import pdisk utility from Eryk Vershen: trunk
authordbj <dbj@NetBSD.org>
Tue, 09 Jul 2002 05:49:02 +0000
branchtrunk
changeset 99481 8e7e17b2e034
parent 99480 e0da36515013
child 99482 a5f4eb22bcbc
import pdisk utility from Eryk Vershen: http://cantaforda.com/cfcl/eryk/linux/pdisk/index.html this is the utility provided by mklinux and osX to manipulate the Apple Partition map.
dist/pdisk/ATA_media.c
dist/pdisk/ATA_media.h
dist/pdisk/DoSCSICommand.c
dist/pdisk/DoSCSICommand.h
dist/pdisk/HISTORY
dist/pdisk/MacSCSICommand.h
dist/pdisk/README
dist/pdisk/SCSI_media.c
dist/pdisk/SCSI_media.h
dist/pdisk/bitfield.c
dist/pdisk/bitfield.h
dist/pdisk/convert.c
dist/pdisk/convert.h
dist/pdisk/cvt_pt.c
dist/pdisk/deblock_media.c
dist/pdisk/deblock_media.h
dist/pdisk/dpme.h
dist/pdisk/dump.c
dist/pdisk/dump.h
dist/pdisk/errors.c
dist/pdisk/errors.h
dist/pdisk/file_media.c
dist/pdisk/file_media.h
dist/pdisk/hfs_misc.c
dist/pdisk/hfs_misc.h
dist/pdisk/io.c
dist/pdisk/io.h
dist/pdisk/layout_dump.c
dist/pdisk/layout_dump.h
dist/pdisk/makefile
dist/pdisk/media.c
dist/pdisk/media.h
dist/pdisk/partition_map.c
dist/pdisk/partition_map.h
dist/pdisk/pathname.c
dist/pdisk/pathname.h
dist/pdisk/pdisk.8
dist/pdisk/pdisk.c
dist/pdisk/pdisk.h
dist/pdisk/pdisk.html
dist/pdisk/pdisk.r
dist/pdisk/util.c
dist/pdisk/util.h
dist/pdisk/validate.c
dist/pdisk/validate.h
dist/pdisk/version.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/ATA_media.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,1239 @@
+/*
+ * ATA_media.c -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+// for printf()
+#include <stdio.h>
+// for malloc() & free()
+#include <stdlib.h>
+#include <ATA.h>
+// for SCSI command structures
+#include "MacSCSICommand.h"
+#include "ATA_media.h"
+#include "util.h"
+
+
+/*
+ * Defines
+ */
+#define RESULT_OFFSET(type) \
+    ((sizeof(type) == 1) ? 3 : ((sizeof(type) == 2) ? 1 : 0))
+#define TBTrapTableAddress(trapNum) (((trapNum & 0x03FF) << 2) + 0xE00)
+#define SWAP_SHORTS(x)  ((((x) & 0xFFFF) << 16) | (((x) >> 16) & 0xFFFF))
+#define LBA_CAPABLE 0x0200
+
+
+/*
+ * Types
+ */
+typedef struct ATA_info *ATA_INFO;
+
+struct ATA_info {
+    long	    lba;
+    long	    heads;
+    long	    sectors;
+};
+
+typedef struct ATA_media *ATA_MEDIA;
+
+struct ATA_media {
+    struct media    m;
+    long            id;
+    struct ATA_info info;
+};
+
+struct ATA_manager {
+    long        exists;
+    long        kind;
+    struct {
+	char    major;
+	char    minor;
+    } version;
+    short       busCount;
+    long	*bus_list;
+};
+
+typedef struct ATA_media_iterator *ATA_MEDIA_ITERATOR;
+
+struct ATA_media_iterator {
+    struct media_iterator   m;
+    long                    bus_index;
+    long                    bus;
+    long                    id;
+};
+
+struct ATA_identify_drive_info {        /* word */
+    unsigned short  config_bits;        /*  0 */
+    unsigned short  num_cylinders;      /*  1 */
+    unsigned short  reserved2;          /*  2 */
+    unsigned short  num_heads;          /*  3 */
+    unsigned short  bytes_per_track;    /*  4 */
+    unsigned short  bytes_per_sector;   /*  5 */
+    unsigned short  sectors_per_track;  /*  6 */
+    unsigned short  vendor7[3];         /*  7-9 */
+    char            serial_number[20];  /* 10-19 */
+    unsigned short  buffer_type;        /* 20 */
+    unsigned short  buffer_size;        /* 21 */
+    unsigned short  num_of_ecc_bytes;   /* 22 */
+    char            firmware_rev[8];    /* 23-26 */
+    char            model_number[40];   /* 27-46 */
+    unsigned short  word47;             /* 47 */
+    unsigned short  double_word_io;     /* 48 */
+    unsigned short  capabilities;       /* 49 */
+    unsigned short  reserved50;         /* 50 */
+    unsigned short  pio_timing;         /* 51 */
+    unsigned short  dma_timing;         /* 52 */
+    unsigned short  current_is_valid;   /* 53 */
+    unsigned short  cur_cylinders;      /* 54 */
+    unsigned short  cur_heads;          /* 55 */
+    unsigned short  cur_sec_per_track;  /* 56 */
+    unsigned long   total_sectors;      /* 57-58 */
+    unsigned short  multiple_sectors;   /* 59 */
+    unsigned long   lba_sectors;        /* 60-61 */
+    unsigned short  singleword_dma;     /* 62 */
+    unsigned short  multiword_dma;      /* 63 */
+    unsigned short  reserved64[64];     /* 64-127 */
+    unsigned short  vendor128[32];      /* 128-159 */
+    unsigned short  reserved160[96];    /* 160-255 */
+};
+
+struct ATAPI_identify_drive_info {      /* word */
+    unsigned short  config_bits;        /*  0 */
+    unsigned short  retired1[9];        /*  1-9 */
+    char            serial_number[20];  /* 10-19 */
+    unsigned short  retired20[3];       /* 20-22 */
+    char            firmware_rev[8];    /* 23-26 */
+    char            model_number[40];   /* 27-46 */
+    unsigned short  retired47[2];       /* 47-48 */
+    unsigned short  capabilities;       /* 49 */
+    unsigned short  reserved50;         /* 50 */
+    unsigned short  pio_timing;         /* 51 */
+    unsigned short  dma_timing;         /* 52 */
+    unsigned short  current_is_valid;   /* 53 */
+    unsigned short  retired54[8];       /* 54-61 */
+    unsigned short  singleword_dma;     /* 62 */
+    unsigned short  multiword_dma;      /* 63 */
+    unsigned short  pio_transfer;       /* 64 */
+    unsigned short  min_cycle_time;     /* 65 */
+    unsigned short  rec_cycle_time;     /* 66 */
+    unsigned short  min_wo_flow;        /* 67 */
+    unsigned short  min_with_flow;      /* 68 */
+    unsigned short  reserved69[2];      /* 69-70 */
+    unsigned short  release_over;       /* 71 */
+    unsigned short  release_service;    /* 72 */
+    unsigned short  major_rev;          /* 73 */
+    unsigned short  minor_rev;          /* 74 */
+    unsigned short  reserved75[53];     /* 75-127 */
+    unsigned short  vendor128[32];      /* 128-159 */
+    unsigned short  reserved160[96];    /* 160-255 */
+};
+
+/* Identifies the bus protocol type. */
+enum {
+    kDevUnknown     =   0,
+    kDevATA         =   1,
+    kDevATAPI       =   2,
+    kDevPCMCIA      =   3
+};
+
+
+/*
+ * Global Constants
+ */
+enum {
+    kNoDevice = 0x00FF,
+    kATAtimeout = 3000,
+    kATAcmdATAPIPacket          = 0x00A0                        /* ATAPI packet command */
+};
+
+
+/*
+ * Global Variables
+ */
+static long ata_inited = 0;
+static struct ATA_manager ata_mgr;
+
+/*
+ * Forward declarations
+ */
+int ATAManagerPresent(void);
+int ATAHardwarePresent(void);
+pascal SInt16 ataManager(ataPB *pb);
+void ata_init(void);
+ATA_MEDIA new_ata_media(void);
+long read_ata_media(MEDIA m, long long offset, unsigned long count, void *address);
+long write_ata_media(MEDIA m, long long offset, unsigned long count, void *address);
+long close_ata_media(MEDIA m);
+long os_reload_ata_media(MEDIA m);
+long compute_id(long bus, long device);
+pascal SInt16 ataManager(ataPB *pb);
+int ATA_ReadBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address);
+int ATA_WriteBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address);
+long get_info(long id, struct ATA_identify_drive_info *ip);
+long get_pi_info(long id, struct ATAPI_identify_drive_info *ip);
+long is_atapi(long id);
+long read_atapi_media(MEDIA m, long long offset, unsigned long count, void *address);
+long write_atapi_media(MEDIA m, long long offset, unsigned long count, void *address);
+int ATAPI_ReadBlock(UInt32 deviceID, UInt32 block_size, UInt32 block, UInt8 *address);
+int ATAPI_TestUnitReady(UInt32 deviceID);
+int ATAPI_ReadCapacity(UInt32 deviceID, unsigned long *block_size, unsigned long *blocks);
+ATA_MEDIA_ITERATOR new_ata_iterator(void);
+void reset_ata_iterator(MEDIA_ITERATOR m);
+char *step_ata_iterator(MEDIA_ITERATOR m);
+void delete_ata_iterator(MEDIA_ITERATOR m);
+int ata_bus_present(int num);
+
+
+/*
+ * Routines
+ */
+#if GENERATINGPOWERPC
+pascal SInt16
+ataManager(ataPB *pb)
+{
+    #ifdef applec
+	#if sizeof(SInt16) > 4
+	    #error "Result types larger than 4 bytes are not supported."
+	#endif
+    #endif
+    long    private_result;
+
+    private_result = CallUniversalProc(
+	*(UniversalProcPtr*)TBTrapTableAddress(0xAAF1),
+	kPascalStackBased
+	 | RESULT_SIZE(SIZE_CODE(sizeof(SInt16)))
+	 | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(pb))),
+	pb);
+    return *(((SInt16*)&private_result) + RESULT_OFFSET(SInt16));
+}
+#endif
+
+
+int
+ATAHardwarePresent(void)
+{
+    UInt16  configFlags;
+
+    // Hardware configuration flags
+    configFlags = LMGetHWCfgFlags();
+    
+    return ((configFlags & 0x0080) != 0);
+}
+
+
+int
+ATAManagerPresent(void)
+{
+    if (ATAHardwarePresent()) {
+	return (TrapAvailable(kATATrap));
+    } else {
+	return 0;
+    }
+}
+
+void
+ata_init(void)
+{
+    ataMgrInquiry   pb;
+    OSErr           status;
+    int i;
+    int j;
+
+    if (ata_inited != 0) {
+	return;
+    }
+    ata_inited = 1;
+    
+    if (ATAManagerPresent() == 0) {
+	ata_mgr.exists = 0;
+	return;
+    }
+
+    ata_mgr.exists = 1;
+    ata_mgr.kind = allocate_media_kind();
+
+    clear_memory((void *)&pb, sizeof(pb));
+    
+    pb.ataPBFunctionCode =  kATAMgrManagerInquiry;
+    pb.ataPBVers =          kATAPBVers1;
+
+    status = ataManager((ataPB*) &pb );
+    
+    if (status != noErr) {
+	ata_mgr.exists = 0;
+	return;
+    }
+    ata_mgr.version.major = pb.ataMgrVersion.majorRev;
+    ata_mgr.version.minor = pb.ataMgrVersion.minorAndBugRev >> 4;
+    ata_mgr.busCount = pb.ataBusCnt;
+
+    ata_mgr.bus_list = (long *) calloc(ata_mgr.busCount, sizeof(long));
+    if (ata_mgr.bus_list == 0) {
+	ata_mgr.busCount = 0;
+    } else {
+	for (i = 0, j = 0; j < ata_mgr.busCount; i++) {
+	    if (ata_bus_present(i)) {
+		ata_mgr.bus_list[j] = i;
+		j++;
+	    }
+	}
+    }
+}
+
+
+int
+ata_bus_present(int num)
+{
+    ataBusInquiry   pb;
+    OSErr           status;
+
+    clear_memory((void *)&pb, sizeof(pb));
+    
+    pb.ataPBFunctionCode =  kATAMgrBusInquiry;
+    pb.ataPBVers =          kATAPBVers1;
+    pb.ataPBDeviceID =	    num;
+
+    status = ataManager((ataPB*) &pb );
+    
+    if (status == noErr) {
+	return 1;
+    } else {
+	//printf("status = %d\n", status);
+	return 0;
+    }
+}
+
+
+ATA_MEDIA
+new_ata_media(void)
+{
+    return (ATA_MEDIA) new_media(sizeof(struct ATA_media));
+}
+
+
+#pragma mark -
+
+
+long
+compute_id(long bus, long device)
+{
+    long id;
+    int i;
+    
+    id = -1;
+    for (i = 0; i < ata_mgr.busCount; i++) {
+	if (bus == ata_mgr.bus_list[i]) {
+	    break;
+	}
+    }
+    if (i >= ata_mgr.busCount) {
+	/* bad bus id */
+    } else if (ata_mgr.version.major < 3) {
+	if (device != 0) {
+	    /* bad device id */
+	} else {
+	    id = bus & 0xFF;
+	}
+    } else {
+	if (device < 0 || device > 1) {
+	    /* bad device id */
+	} else {
+	    id = ((device & 0xFF) << 8) | (bus & 0xFF);
+	}
+    }
+    return id;
+}
+
+
+static long
+get_info(long id, struct ATA_identify_drive_info *ip)
+{
+    ataIdentify     pb;
+    ataDevConfiguration pb2;
+    OSErr           status;
+    long            rtn_value;
+    long            atapi;
+
+    if (sizeof(struct ATA_identify_drive_info) < 512) {
+	return 0;
+    }
+    clear_memory((void *)ip, sizeof(struct ATA_identify_drive_info));
+
+    clear_memory((void *)&pb, sizeof(pb));
+    pb.ataPBFunctionCode    =   kATAMgrDriveIdentify;
+    pb.ataPBVers            =   kATAPBVers1;
+    pb.ataPBDeviceID        =   id;
+    pb.ataPBFlags           =   mATAFlagIORead | mATAFlagByteSwap;
+    pb.ataPBTimeOut         =   kATAtimeout;
+    pb.ataPBBuffer          =   (void*) ip;
+    
+    status = ataManager((ataPB*) &pb );
+
+    if (status != noErr) {
+	//printf("get info status = %d\n", status);
+	rtn_value = 0;
+    } else {
+	ip->total_sectors = SWAP_SHORTS(ip->total_sectors);
+	ip->lba_sectors = SWAP_SHORTS(ip->lba_sectors);
+	rtn_value = 1;
+    }
+    return rtn_value;
+}
+
+
+static long
+is_atapi(long id)
+{
+    ataDevConfiguration pb;
+    OSErr           status;
+    long            atapi;
+
+    atapi = 0;
+    if (ata_mgr.version.major >= 2) {
+	clear_memory((void *)&pb, sizeof(pb));
+	pb.ataPBFunctionCode    =   kATAMgrGetDrvConfiguration;
+	pb.ataPBVers            =   kATAPBVers2;
+	pb.ataPBDeviceID        =   id;
+	pb.ataPBTimeOut     =   kATAtimeout;
+	
+	status = ataManager((ataPB*) &pb );
+	if (status != noErr) {
+	    //printf("is atatpi status = %d\n", status);
+	} else if (pb.ataDeviceType == kDevATAPI) {
+	    atapi = 1;
+	    /* the drive can be asleep or something in which case this doesn't work */
+	    /* how do we do reads */
+	}
+    }
+    return atapi;
+}
+
+
+MEDIA
+open_ata_as_media(long bus, long device)
+{
+    ATA_MEDIA   a;
+    long        id;
+    struct ATA_identify_drive_info  info;
+    unsigned char *buf;
+    unsigned long total;
+    
+    if (ata_inited == 0) {
+	ata_init();
+    }
+    
+    if (ata_mgr.exists == 0) {
+	//printf("ATA manager does not exist\n");
+	return 0;
+    }
+
+    id = compute_id(bus, device);
+
+    if (id < 0) {
+    	return 0;
+
+    } else if (is_atapi(id)) {
+	a = (ATA_MEDIA) open_atapi_as_media(bus, device);
+
+    } else {
+	a = 0;
+	if (get_info(id, &info) != 0) {
+	    a = new_ata_media();
+	    if (a != 0) {
+		a->m.kind = ata_mgr.kind;
+		if ((info.capabilities & LBA_CAPABLE) != 0) {
+		    total = info.lba_sectors;
+		    a->info.lba = 1;
+		    a->info.heads = 0;
+		    a->info.sectors = 0;
+		} else {
+		    /* Only CHS - Cylinder Head Sector addressing */
+		    total = info.total_sectors;
+		    a->info.lba = 0;
+		    a->info.heads = info.cur_heads;
+		    a->info.sectors = info.cur_sec_per_track;
+		}
+		{ /* XXX this should be a loop in a subroutine */
+		    buf = malloc(2048);
+		    if (ATA_ReadBlock(id, &a->info, 512, 0, buf)) {
+			a->m.grain = 512;
+		    } else if (ATA_ReadBlock(id, &a->info, 1024, 0, buf)) {
+			a->m.grain = 1024;
+		    } else if (ATA_ReadBlock(id, &a->info, 2048, 0, buf)) {
+			a->m.grain = 2048;
+		    } else {
+			a->m.grain = 512; /* XXX should really return failure here */
+		    }
+		    free(buf);
+		}
+		if (total == 0) {
+		    a->m.size_in_bytes = ((long long)1000) * a->m.grain; /* XXX not right */
+		} else {
+		    a->m.size_in_bytes = ((long long)total) * a->m.grain;
+		}
+		a->m.do_read = read_ata_media;
+		a->m.do_write = write_ata_media;
+		a->m.do_close = close_ata_media;
+		a->m.do_os_reload = os_reload_ata_media;
+		a->id = id;
+	    }
+	} else {
+	    printf("ATA - couldn't get info\n");
+	}
+    }
+    return (MEDIA) a;
+}
+
+
+long
+read_ata_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+    ATA_MEDIA a;
+    ataIOPB pb;
+    OSErr       status;
+    long rtn_value;
+    long block;
+    long block_count;
+    long block_size;
+    unsigned char *buffer;
+    int i;
+    
+    a = (ATA_MEDIA) m;
+    rtn_value = 0;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != ata_mgr.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else if (count <= 0 || count % a->m.grain != 0) {
+	/* can't handle size */
+    } else if (offset < 0 || offset % a->m.grain != 0) {
+	/* can't handle offset */
+    } else if (offset + count > a->m.size_in_bytes) {
+	/* check for offset (and offset+count) too large */
+    } else {
+	/* do a read on the physical device */
+	block_size = a->m.grain;
+	block = offset / block_size;
+	block_count = count / block_size;
+	buffer = address;
+	rtn_value = 1;
+	for (i = 0; i < block_count; i++) {
+	    if (ATA_ReadBlock(a->id, &a->info, block_size, block, buffer) == 0) {
+		rtn_value = 0;
+		break;
+	    }
+	    buffer += block_size;
+	    block += 1;
+	}
+    }
+    return rtn_value;
+}
+
+
+long
+write_ata_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+    ATA_MEDIA a;
+    long rtn_value;
+    long block;
+    long block_count;
+    long block_size;
+    unsigned char *buffer;
+    int i;
+    
+    a = (ATA_MEDIA) m;
+    rtn_value = 0;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != ata_mgr.kind) {
+	/* XXX need to error here - this is an internal problem */
+    } else if (count <= 0 || count % a->m.grain != 0) {
+	/* can't handle size */
+    } else if (offset < 0 || offset % a->m.grain != 0) {
+	/* can't handle offset */
+    } else if (offset + count > a->m.size_in_bytes) {
+	/* check for offset (and offset+count) too large */
+    } else {
+	/* do a write on the physical device */
+	block_size = a->m.grain;
+	block = offset / block_size;
+	block_count = count / block_size;
+	buffer = address;
+	rtn_value = 1;
+	for (i = 0; i < block_count; i++) {
+	    if (ATA_WriteBlock(a->id, &a->info, block_size, block, buffer) == 0) {
+		rtn_value = 0;
+		break;
+	    }
+	    buffer += block_size;
+	    block += 1;
+	}
+    }
+    return rtn_value;
+}
+
+
+long
+close_ata_media(MEDIA m)
+{
+    ATA_MEDIA a;
+    
+    a = (ATA_MEDIA) m;
+    if (a == 0) {
+	return 0;
+    } else if (a->m.kind != ata_mgr.kind) {
+	/* XXX need to error here - this is an internal problem */
+	return 0;
+    }
+    /* XXX nothing to do - I think? */
+    return 1;
+}
+
+
+long
+os_reload_ata_media(MEDIA m)
+{
+    printf("Reboot your system so the partition table will be reread.\n");
+    return 1;
+}
+
+
+int
+ATA_ReadBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address)
+{
+    ataIOPB     pb;
+    OSErr       status;
+    long        slave;
+    long	lba, cyl, head, sector;
+
+    clear_memory((void *)&pb, sizeof(pb));
+    pb.ataPBFunctionCode    =   kATAMgrExecIO;
+    pb.ataPBVers            =   kATAPBVers1;
+    pb.ataPBDeviceID        =   deviceID;
+    pb.ataPBFlags           =   mATAFlagTFRead | mATAFlagIORead ;
+    pb.ataPBTimeOut         =   kATAtimeout;
+    
+    pb.ataPBLogicalBlockSize =  block_size;
+    pb.ataPBBuffer          =   address;
+    pb.ataPBByteCount = block_size;
+    if (info->lba) {
+    	lba = 0x40;
+    	sector = block & 0xFF;
+    	head = (block >> 24) & 0xF;
+    	cyl = (block >> 8) & 0xFFFF;
+    } else {
+    	lba = 0x00;
+	sector = (block % info->sectors) + 1;
+	cyl = block / info->sectors;
+	head = cyl % info->heads;
+	cyl = cyl / info->heads;
+    }
+
+    pb.ataPBTaskFile.ataTFCount = 1;
+    pb.ataPBTaskFile.ataTFSector = sector;
+    pb.ataPBTaskFile.ataTFCylinder = cyl;
+    if (deviceID & 0x0FF00) {
+	slave = 0x10;
+    } else {
+	slave = 0x0;
+    }
+			      /* std | L/C  | Drive | head */
+    pb.ataPBTaskFile.ataTFSDH = 0xA0 | lba | slave | head;
+    pb.ataPBTaskFile.ataTFCommand = kATAcmdRead;
+
+    status = ataManager((ataPB*) &pb );
+    if (status != noErr) {
+	/* failure */
+	//printf(" ATA read status = %d\n", status);
+	return 0;
+    } else {
+	return 1;
+    }
+}
+
+
+int
+ATA_WriteBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address)
+{
+    ataIOPB     pb;
+    OSErr       status;
+    long        slave;
+    long	lba, cyl, head, sector;
+
+    clear_memory((void *)&pb, sizeof(pb));
+    pb.ataPBFunctionCode    =   kATAMgrExecIO;
+    pb.ataPBVers            =   kATAPBVers1;
+    pb.ataPBDeviceID        =   deviceID;
+    pb.ataPBFlags           =   mATAFlagTFRead | mATAFlagIOWrite ;
+    pb.ataPBTimeOut         =   kATAtimeout;
+    
+    pb.ataPBLogicalBlockSize =  block_size;
+    pb.ataPBBuffer          =   address;
+    pb.ataPBByteCount = block_size;
+    if (info->lba) {
+    	lba = 0x40;
+    	sector = block & 0xFF;
+    	head = (block >> 24) & 0xF;
+    	cyl = (block >> 8) & 0xFFFF;
+    } else {
+    	lba = 0x00;
+	sector = (block % info->sectors) + 1;
+	cyl = block / info->sectors;
+	head = cyl % info->heads;
+	cyl = cyl / info->heads;
+    }
+    pb.ataPBTaskFile.ataTFCount = 1;
+    pb.ataPBTaskFile.ataTFSector = sector;
+    pb.ataPBTaskFile.ataTFCylinder = cyl;
+    if (deviceID & 0x0FF00) {
+	slave = 0x10;
+    } else {
+	slave = 0x0;
+    }
+			      /* std | L/C  | Drive | head */
+    pb.ataPBTaskFile.ataTFSDH = 0xA0 | lba | slave | head;
+    pb.ataPBTaskFile.ataTFCommand = kATAcmdWrite;
+
+    status = ataManager((ataPB*) &pb );
+    if (status != noErr) {
+	/* failure */
+	return 0;
+    } else {
+	return 1;
+    }
+}
+
+
+#pragma mark -
+
+
+/*
+ * ATAPI stuff
+ */
+static long
+get_pi_info(long id, struct ATAPI_identify_drive_info *ip)
+{
+    ataIdentify     pb;
+    OSErr           status;
+    long            rtn_value;
+
+    if (sizeof(struct ATAPI_identify_drive_info) < 512) {
+	return 0;
+    }
+    clear_memory((void *)ip, sizeof(struct ATAPI_identify_drive_info));
+
+    clear_memory((void *)&pb, sizeof(pb));
+    pb.ataPBFunctionCode    =   kATAMgrDriveIdentify;
+    pb.ataPBVers            =   kATAPBVers1;
+    pb.ataPBDeviceID        =   id;
+    pb.ataPBFlags           =   mATAFlagIORead | mATAFlagByteSwap | mATAFlagProtocol1;
+    pb.ataPBTimeOut         =   kATAtimeout;
+    pb.ataPBBuffer          =   (void*) ip;
+    
+    status = ataManager((ataPB*) &pb );
+
+    if (status != noErr) {
+	//printf("get pi info status = %d\n", status);
+	rtn_value = 0;
+    } else {
+	rtn_value = 1;
+    }
+    return rtn_value;
+}
+
+
+MEDIA
+open_atapi_as_media(long bus, long device)
+{
+    ATA_MEDIA   a;
+    long        id;
+    struct ATAPI_identify_drive_info    info;
+    unsigned char *buf;
+    unsigned long block_size;
+    unsigned long blocks;   
+    
+    if (ata_inited == 0) {
+	ata_init();
+    }
+    
+    if (ata_mgr.exists == 0) {
+	return 0;
+    }
+
+    id = compute_id(bus, device);
+
+    if (!is_atapi(id)) {
+	a = 0;
+
+    } else {
+	a = 0;
+	if (get_pi_info(id, &info) != 0
+		&& (info.capabilities & LBA_CAPABLE) != 0) {
+	    if (ATAPI_TestUnitReady(id) != 0) {
+		a = new_ata_media();
+		if (a != 0) {
+		    a->m.kind = ata_mgr.kind;
+		    if (ATAPI_ReadCapacity(id, &block_size, &blocks) == 0) {
+			block_size = 2048;
+			blocks = 1000;
+		    }
+		    a->m.grain = block_size;
+		    a->m.size_in_bytes = ((long long)blocks) * a->m.grain;
+		    a->m.do_read = read_atapi_media;
+		    a->m.do_write = write_atapi_media;
+		    a->m.do_close = close_ata_media;
+		    a->m.do_os_reload = os_reload_ata_media;
+		    a->id = id;
+		}
+	    } else {
+		printf("ATAPI - unit not ready\n");
+	    }
+	} else {
+	    printf("ATAPI - couldn't get info or not LBA capable\n");
+	}
+    }
+    return (MEDIA) a;
+}
+
+
+long
+read_atapi_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+    ATA_MEDIA a;
+    ataIOPB pb;
+    OSErr       status;
+    long rtn_value;
+    long block;
+    long block_count;
+    long block_size;
+    unsigned char *buffer;
+    int i;
+    
+    a = (ATA_MEDIA) m;
+    rtn_value = 0;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != ata_mgr.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else if (count <= 0 || count % a->m.grain != 0) {
+	/* can't handle size */
+    } else if (offset < 0 || offset % a->m.grain != 0) {
+	/* can't handle offset */
+    } else if (offset + count > a->m.size_in_bytes) {
+	/* check for offset (and offset+count) too large */
+    } else {
+	/* XXX do a read on the physical device */
+	block_size = a->m.grain;
+	block = offset / block_size;
+	block_count = count / block_size;
+	buffer = address;
+	rtn_value = 1;
+	for (i = 0; i < block_count; i++) {
+	    if (ATAPI_ReadBlock(a->id, block_size, block, buffer) == 0) {
+		rtn_value = 0;
+		break;
+	    }
+	    buffer += block_size;
+	    block += 1;
+	}
+    }
+    return rtn_value;
+}
+
+
+long
+write_atapi_media(MEDIA m, long long offset, unsigned long count, void *address)
+{   
+    return 0;
+}
+
+
+int
+ATAPI_ReadBlock(UInt32 deviceID, UInt32 block_size, UInt32 block, UInt8 *address)
+{
+    ataIOPB         pb;
+    OSErr           status;
+    long            slave;
+    ATAPICmdPacket  cmdPacket;
+    SCSI_10_Byte_Command *gRead;
+    long count;
+
+    clear_memory((void *)&pb, sizeof(pb));
+    pb.ataPBFunctionCode    =   kATAMgrExecIO;
+    pb.ataPBVers            =   kATAPBVers1;
+    pb.ataPBDeviceID        =   deviceID;
+    pb.ataPBFlags           =   mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1;
+    pb.ataPBTimeOut         =   kATAtimeout;
+    
+    pb.ataPBBuffer          =   address;
+    pb.ataPBByteCount = block_size;
+    pb.ataPBTaskFile.ataTFCylinder = block_size;
+    if (deviceID & 0x0FF00) {
+	slave = 0x10;
+    } else {
+	slave = 0x0;
+    }
+			      /* std | L/C  | Drive | head */
+    pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave;
+    pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket;
+    pb.ataPBPacketPtr = &cmdPacket;
+    
+    cmdPacket.atapiPacketSize = 16;
+    clear_memory((void *)&cmdPacket.atapiCommandByte, 16);
+    gRead = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0];
+
+    gRead->opcode = kScsiCmdRead10;
+
+    gRead->lbn4 = (block >> 24) & 0xFF;
+    gRead->lbn3 = (block >> 16) & 0xFF;
+    gRead->lbn2 = (block >> 8) & 0xFF;
+    gRead->lbn1 = block & 0xFF;
+
+    count = 1;
+    gRead->len2 = (count >> 8) & 0xFF;
+    gRead->len1 = count & 0xFF;
+
+
+    status = ataManager((ataPB*) &pb );
+    if (status != noErr) {
+	/* failure */
+	//printf("ATAPI read status = %d\n", status);
+	return 0;
+    } else {
+	return 1;
+    }
+}
+
+
+int
+ATAPI_TestUnitReady(UInt32 deviceID)
+{
+    ataIOPB         pb;
+    OSErr           status;
+    long            slave;
+    ATAPICmdPacket  cmdPacket;
+    SCSI_10_Byte_Command *gTestUnit;
+
+    clear_memory((void *)&pb, sizeof(pb));
+    pb.ataPBFunctionCode    =   kATAMgrExecIO;
+    pb.ataPBVers            =   kATAPBVers1;
+    pb.ataPBDeviceID        =   deviceID;
+    pb.ataPBFlags           =   mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1;
+    pb.ataPBTimeOut         =   kATAtimeout;
+    
+    if (deviceID & 0x0FF00) {
+	slave = 0x10;
+    } else {
+	slave = 0x0;
+    }
+			      /* std | L/C  | Drive | head */
+    pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave;
+    pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket;
+    pb.ataPBPacketPtr = &cmdPacket;
+    
+    cmdPacket.atapiPacketSize = 16;
+    clear_memory((void *)&cmdPacket.atapiCommandByte, 16);
+    gTestUnit = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0];
+
+    gTestUnit->opcode = kScsiCmdTestUnitReady;
+
+
+    status = ataManager((ataPB*) &pb );
+    if (status != noErr) {
+	/* failure */
+	//printf("ATAPI test unit ready status = %d\n", status);
+	return 0;
+    } else {
+	return 1;
+    }
+}
+
+
+int
+ATAPI_ReadCapacity(UInt32 deviceID, unsigned long *block_size, unsigned long *blocks)
+{
+    ataIOPB         pb;
+    OSErr           status;
+    long            slave;
+    ATAPICmdPacket  cmdPacket;
+    SCSI_10_Byte_Command *gReadCap;
+    struct read_cap_data {
+	long    addr;
+	long    size;
+    } rcd;
+
+    clear_memory((void *)&pb, sizeof(pb));
+    pb.ataPBFunctionCode    =   kATAMgrExecIO;
+    pb.ataPBVers            =   kATAPBVers1;
+    pb.ataPBDeviceID        =   deviceID;
+    pb.ataPBFlags           =   mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1;
+    pb.ataPBTimeOut         =   kATAtimeout;
+    
+    pb.ataPBBuffer          =   (unsigned char *)&rcd;
+    pb.ataPBByteCount = 8;
+    pb.ataPBTaskFile.ataTFCylinder = 8;
+    if (deviceID & 0x0FF00) {
+	slave = 0x10;
+    } else {
+	slave = 0x0;
+    }
+			      /* std | L/C  | Drive | head */
+    pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave;
+    pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket;
+    pb.ataPBPacketPtr = &cmdPacket;
+    
+    cmdPacket.atapiPacketSize = 16;
+    clear_memory((void *)&cmdPacket.atapiCommandByte, 16);
+    gReadCap = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0];
+
+    gReadCap->opcode = kScsiCmdReadCapacity;
+
+
+    status = ataManager((ataPB*) &pb );
+    if (status != noErr) {
+	/* failure */
+	//printf("ATAPI read capacity status = %d\n", status);
+	return 0;
+    } else {
+	*blocks = rcd.addr;
+	*block_size = rcd.size;
+	return 1;
+    }
+}
+
+
+MEDIA
+ATA_FindDevice(long dRefNum)
+{
+    ataDrvrRegister pb;
+    OSErr       status;
+
+    if (ATAManagerPresent()) {
+	clear_memory((void *)&pb, sizeof(pb));
+	
+	pb.ataPBFunctionCode    =   kATAMgrFindDriverRefnum;
+	pb.ataPBVers            =   kATAPBVers1;
+	pb.ataPBDeviceID        =   0xFFFF;
+	pb.ataPBTimeOut         =   kATAtimeout;
+	
+	pb.ataDeviceNextID = 1;     
+	do {
+	    status = ataManager((ataPB*) &pb);
+	    
+	    if (status != noErr) {
+		break;
+	    } else if (pb.ataDrvrRefNum == dRefNum
+		    && pb.ataPBDeviceID != kNoDevice) {
+		return open_ata_as_media(pb.ataPBDeviceID & 0xFF,
+			(pb.ataPBDeviceID >> 8) & 0xFF);
+	    } else {
+		pb.ataPBDeviceID = pb.ataDeviceNextID;
+	    }
+	} while (pb.ataPBDeviceID != kNoDevice);
+    }
+    return 0;
+}
+
+
+#pragma mark -
+
+
+ATA_MEDIA_ITERATOR
+new_ata_iterator(void)
+{
+    return (ATA_MEDIA_ITERATOR) new_media_iterator(sizeof(struct ATA_media_iterator));
+}
+
+
+MEDIA_ITERATOR
+create_ata_iterator(void)
+{
+    ATA_MEDIA_ITERATOR a;
+    
+    if (ata_inited == 0) {
+	ata_init();
+    }
+    
+    if (ata_mgr.exists == 0) {
+	return 0;
+    }
+
+    a = new_ata_iterator();
+    if (a != 0) {
+	a->m.kind = ata_mgr.kind;
+	a->m.state = kInit;
+	a->m.do_reset = reset_ata_iterator;
+	a->m.do_step = step_ata_iterator;
+	a->m.do_delete = delete_ata_iterator;
+	a->bus_index = 0;
+	a->bus = 0;
+	a->id = 0;
+    }
+
+    return (MEDIA_ITERATOR) a;
+}
+
+
+void
+reset_ata_iterator(MEDIA_ITERATOR m)
+{
+    ATA_MEDIA_ITERATOR a;
+    
+    a = (ATA_MEDIA_ITERATOR) m;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != ata_mgr.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else if (a->m.state != kInit) {
+	a->m.state = kReset;
+    }
+}
+
+
+char *
+step_ata_iterator(MEDIA_ITERATOR m)
+{
+    ATA_MEDIA_ITERATOR a;
+    char *result;
+    
+    a = (ATA_MEDIA_ITERATOR) m;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != ata_mgr.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else {
+	switch (a->m.state) {
+	case kInit:
+	    /* find # of buses (done in ata_init) */
+	    a->m.state = kReset;
+	    /* fall through to reset */
+	case kReset:
+	    a->bus_index = 0 /* low bus id */;
+	    a->bus = ata_mgr.bus_list[a->bus_index];
+	    a->id = 0 /* low device id */;
+	    a->m.state = kIterating;
+	    /* fall through to iterate */
+	case kIterating:
+	    while (1) {
+		if (a->bus_index >= ata_mgr.busCount/* max bus id */) {
+		    break;
+		}
+		if (a->id > 1 /*max id for bus */) {
+		    a->bus_index += 1;
+		    a->bus = ata_mgr.bus_list[a->bus_index];
+		    a->id = 0 /* low device id */;
+		    continue;   /* try again */
+		}
+		if (a->bus > 9) {
+		    // insure that name creation works
+		    break;
+		}
+		/* generate result */
+		result = (char *) malloc(20);
+		if (result != NULL) {
+		    sprintf(result, "/dev/ata%c.%c", '0'+a->bus, '0'+a->id);
+		}
+
+		a->id += 1; /* next id */
+		return result;
+	    }
+	    a->m.state = kEnd;
+	    /* fall through to end */
+	case kEnd:
+	default:
+	    break;
+	}
+    }
+    return 0 /* no entry */;
+}
+
+
+void
+delete_ata_iterator(MEDIA_ITERATOR m)
+{
+    return;
+}
+
+
+#pragma mark -
+
+
+#ifdef notdef
+MEDIA
+open_linux_ata_as_media(long index)
+{
+    long bus;
+    long id;
+    long i;
+    
+    i = index / 2;
+    if (i >= ata_mgr.busCount) {
+	// set bogus id
+	bus = 0;
+	id = 2;
+    } else {
+	bus = ata_mgr.bus_list[index / 2];
+	id = index % 2;
+    }
+
+    return open_ata_as_media(bus, id);
+}
+
+#else
+
+MEDIA
+open_linux_ata_as_media(long index)
+{
+    long bus;
+    long id;
+    
+    bus = index / 2;
+    id = index % 2;
+
+    return open_ata_as_media(bus, id);
+}
+#endif
+
+
+char *
+linux_ata_name(long bus, long id)
+{
+    char *result;
+
+    if (bus >= 13) {
+	// a bus >= 13 would be a bogus character
+	return NULL;
+    }
+    result = (char *) malloc(20);
+    if (result != NULL) {
+    	/* name is hda, hdb, hdc, hdd, ...
+    	 * in order (0,0)  (0,1)  (1,0)  (1,1) ...
+    	 */
+	sprintf(result, "/dev/hd%c", 'a' + (bus*2 + id));
+    }
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/ATA_media.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,64 @@
+/*
+ * ATA_media.h -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __ATA_media__
+#define __ATA_media__
+
+#include "media.h"
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+
+
+/*
+ * Forward declarations
+ */
+MEDIA ATA_FindDevice(long dRefNum);
+MEDIA open_ata_as_media(long bus, long device);
+MEDIA open_atapi_as_media(long bus, long device);
+MEDIA_ITERATOR create_ata_iterator(void);
+MEDIA open_linux_ata_as_media(long index);
+char *linux_ata_name(long bus, long id);
+
+#endif /* __ATA_media__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/DoSCSICommand.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,649 @@
+/*
+ * DoScsiCommand.c
+ *
+ * This is the common entry to the original and asynchronous SCSI Manager calls:
+ * if the asynchronous SCSI Manager is requested, it calls it. Otherwise, it
+ * calls the original SCSI Manager and executes Request Sense if necessary.
+ *
+ * This function returns "autosense" in the SCSI_Sense_Data area. This will
+ * be formatted in the senseMessage string.
+ */
+
+/*
+ * Copyright 1992, 1993, 1997, 1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include "DoScsiCommand.h"
+#include "util.h"
+
+
+//
+// Defines
+//
+#define kSCSICommandTimeout     (5 * 1000L)         /* Five seconds             */
+/*
+ * This is the maximum number of times we try to grab the SCSI Bus
+ */
+#define kMaxSCSIRetries         40                  /* 10 seconds, 4 times/sec  */
+/*
+ * This test is TRUE if the SCSI bus status indicates "busy" (which is the case
+ * if either the BSY or SEL bit is set).
+ */
+#ifndef kScsiStatBSY
+#define kScsiStatBSY            (1 << 6)
+#endif
+#ifndef kScsiStatSEL
+#define kScsiStatSEL            (1 << 1)
+#endif
+#define ScsiBusBusy()       ((SCSIStat() & (kScsiStatBSY | kScsiStatSEL)) != 0)
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+int             gSCSIHiBusID;
+SCSIExecIOPB    *gSCSIExecIOPBPtr;
+UInt32          gSCSIExecIOPBPtrLen;
+
+
+//
+// Forward declarations
+//
+UInt16 GetCommandLength(const SCSI_CommandPtr cmdPtr);
+Boolean IsVirtualMemoryRunning(void);
+
+OSErr OriginalSCSI(
+    DeviceIdent             scsiDevice,
+    const SCSI_CommandPtr   scsiCommand,
+    UInt8                   scsiCommandLen,
+    Ptr                     dataBuffer,
+    ByteCount               dataLength,
+    UInt32                  scsiFlags,
+    ByteCount               *actualTransferCount,
+    UInt8                   *scsiStatusByte
+);
+
+OSErr DoOriginalSCSICommand(
+    DeviceIdent             scsiDevice,
+    const SCSI_CommandPtr   theSCSICommand,
+    unsigned short          cmdBlockLength,
+    Ptr                     dataBuffer,
+    ByteCount               dataLength,
+    UInt32                  scsiFlags,
+    ByteCount               *actualTransferCount,
+    SCSI_Sense_Data         *sensePtr
+);
+
+
+//
+// Routines
+//
+
+/*
+ * This returns TRUE if the command failed with "Illegal Request." We need this
+ * so we can ignore LogSense or ReadDefectData if the device doesn't support
+ * these functions.
+ */
+Boolean
+IsIllegalRequest(
+    OSErr                   scsiStatus,
+    const SCSI_Sense_Data   *senseDataPtr
+    )
+{
+    Boolean                 result;
+#define SENSE   (*senseDataPtr)
+
+    result = FALSE;
+    if (scsiStatus == scsiNonZeroStatus
+     && (SENSE.senseKey & kScsiSenseKeyMask) == kScsiSenseIllegalReq
+     && SENSE.additionalSenseLength >= 4) {
+	switch ((SENSE.additionalSenseCode << 8) | SENSE.additionalSenseQualifier) {
+	case 0x0000:
+	case 0x2000:
+	case 0x2022:    /* Obsolete */
+	result = TRUE;
+	break;
+	default:
+	break;
+	}
+    }
+    return (result);
+#undef SENSE
+}
+
+
+/*
+ * This returns TRUE if the command failed with Device Not Ready (No Media Present)
+ */
+Boolean
+IsNoMedia(
+    OSErr                   scsiStatus,
+    const SCSI_Sense_Data   *senseDataPtr
+    )
+{
+    Boolean                 result;
+#define SENSE   (*senseDataPtr)
+
+    result = FALSE;
+    if (scsiStatus == scsiNonZeroStatus
+     && (SENSE.senseKey & kScsiSenseKeyMask) == kScsiSenseNotReady
+     && SENSE.additionalSenseLength >= 4) {
+	switch ((SENSE.additionalSenseCode << 8) | SENSE.additionalSenseQualifier) {
+	case 0x0000:
+	case 0x3A00:
+	result = TRUE;
+	break;
+	default:
+	break;
+	}
+    }
+    return (result);
+#undef SENSE
+}
+
+
+/*
+ * Do one SCSI Command. If the device returns Check Condition, issue Request Sense
+ * (original SCSI Manager only) and interpret the sense data. The original SCSI
+ * command status is in SCB.status. If it is statusErr or scsiNonZeroStatus,
+ * the sense data is in SCB.sense and the Request Sense status is in
+ * SCB.requestSenseStatus.
+ *
+ * If sensePtr[0] is non-zero, there is a message.
+ */
+OSErr
+DoSCSICommand(
+    DeviceIdent             scsiDevice,
+    ConstStr255Param        currentAction,
+    const SCSI_CommandPtr   callerSCSICommand,
+    Ptr                     dataBuffer,
+    ByteCount               dataLength,
+    UInt32                  scsiFlags,
+    ByteCount               *actualTransferCount,
+    SCSI_Sense_Data         *sensePtr,
+    StringPtr               senseMessage
+    )
+{
+    OSErr                   status;
+    SCSI_Command            theSCSICommand;
+    unsigned short          cmdBlockLength;
+	
+//      SpinSpinner(&gCurrentInfoPtr->spinnerRecord);
+//      ShowProgressAction(currentAction);
+    /*
+     * Store the LUN information in the command block - this is needed
+     * for devices that only examine the command block for LUN values.
+     * (On SCSI-II, the asynchronous SCSI Manager also includes the
+     * LUN in the identify message).
+     */
+    theSCSICommand = *callerSCSICommand;
+    theSCSICommand.scsi[1] &= ~0xE0;
+    theSCSICommand.scsi[1] |= (scsiDevice.LUN & 0x03) << 5;
+    cmdBlockLength = GetCommandLength(&theSCSICommand);
+    if (senseMessage != NULL)
+	senseMessage[0] = 0;
+    if (sensePtr != NULL)
+	sensePtr->errorCode = 0;
+    if (scsiDevice.bus == kOriginalSCSIBusAdaptor) {
+	status = DoOriginalSCSICommand(
+	    scsiDevice,
+	    &theSCSICommand,
+	    cmdBlockLength,
+	    dataBuffer,
+	    dataLength,
+	    scsiFlags,
+	    actualTransferCount,
+	    sensePtr
+	    );
+    }
+    else {
+	clear_memory(gSCSIExecIOPBPtr, gSCSIExecIOPBPtrLen);
+#define PB  (*gSCSIExecIOPBPtr)
+	PB.scsiPBLength = gSCSIExecIOPBPtrLen;
+	PB.scsiFunctionCode = SCSIExecIO;
+	PB.scsiDevice = scsiDevice;
+	PB.scsiTimeout = kSCSICommandTimeout;
+	/*
+	 * Fiddle the flags so they're the least disruptive possible.
+	 */
+	PB.scsiFlags = scsiFlags | (scsiSIMQNoFreeze | scsiDontDisconnect);
+	if (sensePtr != NULL) {
+	PB.scsiSensePtr = (UInt8 *) sensePtr;
+	PB.scsiSenseLength = sizeof *sensePtr;
+	}
+	BlockMoveData(&theSCSICommand, &PB.scsiCDB.cdbBytes[0], cmdBlockLength);
+	PB.scsiCDBLength = cmdBlockLength;
+	if (dataBuffer != NULL) {
+	PB.scsiDataPtr = (UInt8 *) dataBuffer;
+	PB.scsiDataLength = dataLength;
+	PB.scsiDataType = scsiDataBuffer;
+	PB.scsiTransferType = scsiTransferPolled;
+	}
+	status = SCSIAction((SCSI_PB *) &PB);
+	if (status == noErr)
+	status = PB.scsiResult;
+	if (status == scsiSelectTimeout)
+	status = scsiDeviceNotThere;
+	if (actualTransferCount != NULL) {
+	/*
+	 * Make sure that the actual transfer count does not exceed
+	 * the allocation count (some devices spit extra data at us!)
+	 */
+	*actualTransferCount = dataLength - PB.scsiDataResidual;
+	if (*actualTransferCount > dataLength)
+	    *actualTransferCount = dataLength;
+	}
+#undef PB
+    }
+    if (status == scsiNonZeroStatus
+     && sensePtr != NULL
+     && sensePtr->errorCode != 0
+     && senseMessage != NULL) {
+//          FormatSenseMessage(sensePtr, senseMessage);
+//          ShowProgressAction(senseMessage);
+    }
+    return (status);
+}
+
+
+/*
+ * Do a command with autosense using the original SCSI manager.
+ */
+OSErr
+DoOriginalSCSICommand(
+    DeviceIdent             scsiDevice,
+    const SCSI_CommandPtr   theSCSICommand,
+    unsigned short          cmdBlockLength,
+    Ptr                     dataBuffer,
+    ByteCount               dataLength,
+    UInt32                  scsiFlags,
+    ByteCount               *actualTransferCount,
+    SCSI_Sense_Data         *sensePtr
+    )
+{
+    OSErr                   status;
+    UInt8                   scsiStatusByte;
+    SCSI_Command            scsiStatusCommand;
+
+    status = OriginalSCSI(
+	    scsiDevice,
+	    theSCSICommand,
+	    cmdBlockLength,
+	    dataBuffer,
+	    dataLength,
+	    scsiFlags,
+	    actualTransferCount,
+	    &scsiStatusByte
+	);
+    if (status == scsiNonZeroStatus
+     && scsiStatusByte == kScsiStatusCheckCondition
+     && sensePtr != NULL) {
+	CLEAR(scsiStatusCommand);
+	CLEAR(*sensePtr);
+	scsiStatusCommand.scsi6.opcode = kScsiCmdRequestSense;
+	scsiStatusCommand.scsi[1] |= (scsiDevice.LUN & 0x03) << 5;
+	scsiStatusCommand.scsi6.len = sizeof *sensePtr;
+	status = OriginalSCSI(
+	    scsiDevice,
+	    &scsiStatusCommand,
+	    sizeof scsiStatusCommand.scsi6,
+	    (Ptr) sensePtr,
+	    sizeof *sensePtr,
+	    scsiDirectionIn,
+	    NULL,
+	    &scsiStatusByte
+	    );
+	if (status != noErr && status != scsiDataRunError) {
+#ifdef notdef
+	if (gDebugOnError && scsiStatusByte != kScsiStatusCheckCondition) {
+	    Str255          work;
+
+	    pstrcpy(work, "\pAutosense failed ");
+	    AppendSigned(work, status);
+	    AppendChar(work, ' ');
+	    AppendHexLeadingZeros(work, scsiStatusByte, 2);
+	    DebugStr(work);
+	}
+#endif
+	sensePtr->errorCode = 0;
+	status = scsiAutosenseFailed;
+	}
+	else {
+	status = scsiNonZeroStatus;
+	}
+    }
+    return (status);
+}
+
+
+OSErr
+OriginalSCSI(
+    DeviceIdent             scsiDevice,
+    const SCSI_CommandPtr   scsiCommand,
+    UInt8                   scsiCommandLen,
+    Ptr                     dataBuffer,
+    ByteCount               dataLength,
+    UInt32                  scsiFlags,
+    ByteCount               *actualTransferCount,
+    UInt8                   *scsiStatusBytePtr
+    )
+{
+    OSErr                   status;             /* Final status             */
+    OSErr                   completionStatus;   /* Status from ScsiComplete */
+    short                   totalTries;         /* Get/Select retries       */
+    short                   getTries;           /* Get retries              */
+    short                   iCount;             /* Bus free counter         */
+    unsigned long           watchdog;           /* Timeout after this       */
+    unsigned long           myTransferCount;    /* Gets TIB loop counter    */
+    short                   scsiStatusByte;     /* Gets SCSIComplete result */
+    short                   scsiMsgByte;        /* Gets SCSIComplete result */
+    Boolean                 bufferHoldFlag;
+    /*
+     * The TIB has the following format:
+     *  [0] scInc   user buffer         transferQuantum or transferSize
+     *  [1] scAdd   &theTransferCount   1
+     *  [2] scLoop  -> tib[0]           transferSize / transferQuantum
+     *  [3] scStop
+     * The intent of this is to return, in actualTransferCount, the number
+     * of times we cycled through the tib[] loop. This will be the actual
+     * transfer count if transferQuantum equals one, or the number of
+     * "blocks" if transferQuantum is the length of one sector.
+     */
+    SCSIInstr               tib[4];             /* Current TIB              */
+
+    status = noErr;
+    bufferHoldFlag = FALSE;
+    scsiStatusByte = 0xFF;
+    scsiMsgByte = 0xFF;
+    myTransferCount = 0;
+    /*
+     * If there is a data transfer, setup the tib.
+     */
+    if (dataBuffer != NULL) {
+	tib[0].scOpcode = scInc;
+	tib[0].scParam1 = (unsigned long) dataBuffer;
+	tib[0].scParam2 = 1;
+	tib[1].scOpcode = scAdd;
+	tib[1].scParam1 = (unsigned long) &myTransferCount;
+	tib[1].scParam2 = 1;
+	tib[2].scOpcode = scLoop;
+	tib[2].scParam1 = (-2 * sizeof (SCSIInstr));
+	tib[2].scParam2 = dataLength / tib[0].scParam2;
+	tib[3].scOpcode = scStop;
+	tib[3].scParam1 = 0;
+	tib[3].scParam2 = 0;
+    }
+    if (IsVirtualMemoryRunning() && dataBuffer != NULL) {
+	/*
+	 * Lock down the user buffer, if any. In a real-world application
+	 * or driver, this would be done before calling the SCSI interface.
+	 */
+#ifdef notdef
+	FailOSErr(
+	HoldMemory(dataBuffer, dataLength),
+	"\pCan't lock data buffer in physical memory"
+	);
+#else
+	HoldMemory(dataBuffer, dataLength);
+#endif
+	bufferHoldFlag = TRUE;
+    }
+    /*
+     * Arbitrate for the scsi bus.  This will fail if some other device is
+     * accessing the bus at this time (which is unlikely).
+     *
+     *** Do not set breakpoints or call any functions that may require device
+     *** I/O (such as display code that accesses font resources between
+     *** SCSIGet and SCSIComplete,
+     *
+     */
+    for (totalTries = 0; totalTries < kMaxSCSIRetries; totalTries++) {
+	for (getTries = 0; getTries < 4; getTries++) {
+	    /*
+	     * Wait for the bus to go free.
+	     */
+	    watchdog = TickCount() + 300;       /* 5 second timeout         */
+	    while (ScsiBusBusy()) {
+		if (/*gStopNow || StopNow() ||*/ TickCount() > watchdog) {
+		    status = scsiBusy;
+		    goto exit;
+		}
+	    }
+	    /*
+	     * The bus is free, try to grab it
+	     */
+	    for (iCount = 0; iCount < 4; iCount++) {
+		if ((status = SCSIGet()) == noErr)
+		    break;
+	    }
+	    if (status == noErr) {
+		break;                          /* Success: we have the bus */
+	    }
+	    /*
+	     * The bus became busy again. Try to wait for it to go free.
+	     */
+	    for (iCount = 0;
+		/*gStopNow == FALSE && StopNow() == FALSE &&*/ iCount < 100 && ScsiBusBusy();
+		iCount++)
+		;
+	} /* The getTries loop */
+	if (status != noErr) {
+	    /*
+	     * The SCSI Manager thinks the bus is not busy and not selected,
+	     * but "someone" has set its internal semaphore that signals
+	     * that the SCSI Manager itself is busy. The application will have
+	     * to handle this problem. (We tried getTries * 4 times).
+	     */
+	    status = scsiBusy;
+	    goto exit;
+	}
+	/*
+	 * We now own the SCSI bus. Try to select the device.
+	 */
+	if ((status = SCSISelect(scsiDevice.targetID)) != noErr) {
+	    switch (status) {
+	    /*
+	     * We get scBadParmsErr if we try to arbitrate for the initiator.
+	     */
+	    case scBadParmsErr: status = scsiTIDInvalid;        break;
+	    case scCommErr:     status = scsiDeviceNotThere;    break;
+	    case scArbNBErr:    status = scsiBusy;              break;
+	    case scSequenceErr: status = scsiRequestInvalid;    break;
+	    }
+	    goto exit;
+	}
+	/*
+	 * From this point on, we must exit through SCSIComplete() even if an
+	 * error is detected. Send a command to the selected device. There are
+	 * several failure modes, including an illegal command (such as a
+	 * write to a read-only device). If the command failed because of
+	 * "device busy", we will try it again.
+	 */
+	status = SCSICmd((Ptr) scsiCommand, scsiCommandLen);
+	if (status != noErr) {
+	    switch (status) {
+	    case scCommErr:     status = scsiCommandTimeout;    break;
+	    case scPhaseErr:    status = scsiSequenceFailed;    break;
+	    }
+	}
+	if (status == noErr && dataBuffer != NULL) {
+	    /*
+	     * This command requires a data transfer.
+	     */
+	    if (scsiFlags == scsiDirectionOut) {
+		status = SCSIWrite((Ptr) tib);
+	    } else {
+		status = SCSIRead((Ptr) tib);
+	    }
+	    switch (status) {
+	    case scCommErr:     status = scsiCommandTimeout;        break;
+	    case scBadParmsErr: status = scsiRequestInvalid;        break;
+	    case scPhaseErr:    status = noErr; /* Don't care */    break;
+	    case scCompareErr:                  /* Can't happen */  break;
+	    }
+	}
+	/*
+	 * SCSIComplete "runs" the bus-phase algorithm until the bitter end,
+	 * returning the status and command-completion message bytes..
+	 */
+	completionStatus = SCSIComplete(
+	    &scsiStatusByte,
+	    &scsiMsgByte,
+	    5 * 60L
+	    );
+	if (status == noErr && completionStatus != noErr) {
+	    switch (completionStatus) {
+	    case scCommErr:         status = scsiCommandTimeout;    break;
+	    case scPhaseErr:        status = scsiSequenceFailed;    break;
+	    case scComplPhaseErr:   status = scsiSequenceFailed;    break;
+	    }
+	}
+	if (completionStatus == noErr && scsiStatusByte == kScsiStatusBusy) {
+	    /*
+	     * ScsiComplete is happy. If the device is busy,
+	     * pause for 1/4 second and try again.
+	     */
+	    watchdog = TickCount() + 15;
+	    while (TickCount() < watchdog)
+		;
+	    continue;               /* Do next totalTries attempt       */
+	}
+	/*
+	 * This is the normal exit (success) or final failure exit.
+	 */
+	break;
+    } /* totalTries loop */
+exit:
+
+    if (bufferHoldFlag) {
+	(void) UnholdMemory(dataBuffer, dataLength);
+    }
+    /*
+     * Return the number of bytes transferred to the caller. If the caller
+     * supplied an actual count and the count is no greater than the maximum,
+     * ignore any phase errors.
+     */
+    if (actualTransferCount != NULL) {
+	*actualTransferCount = myTransferCount;
+	if (*actualTransferCount > dataLength) {
+	    *actualTransferCount = dataLength;
+	}
+    }
+    /*
+     * Also, there is a bug in the combination of System 7.0.1 and the 53C96
+     * that may cause the real SCSI Status Byte to be in the Message byte.
+     */
+    if (scsiStatusByte == kScsiStatusGood
+	    && scsiMsgByte == kScsiStatusCheckCondition) {
+	scsiStatusByte = kScsiStatusCheckCondition;
+    }
+    if (status == noErr) {
+	switch (scsiStatusByte) {
+	case kScsiStatusGood:                               break;
+	case kScsiStatusBusy:   status = scsiBusy;          break;
+	case 0xFF:              status = scsiProvideFail;   break;
+	default:                status = scsiNonZeroStatus; break;
+	}
+    }
+    if (status == noErr
+	    && (scsiFlags & scsiDirectionMask) != scsiDirectionNone
+	    && myTransferCount != dataLength) {
+	status = scsiDataRunError;
+    }        
+    if (scsiStatusBytePtr != NULL) {
+	*scsiStatusBytePtr = scsiStatusByte;
+    }
+    return (status);
+}
+
+
+UInt16
+GetCommandLength(
+    const SCSI_CommandPtr   cmdPtr
+    )
+{
+    unsigned short          result;
+    /*
+     * Look at the "group code" in the command operation. Return zero
+     * error for the reserved (3, 4) and vendor-specific command (6, 7)
+     * command groups. Otherwise, set the command length from the group code
+     * value as specified in the SCSI-II spec.
+     */
+    switch (cmdPtr->scsi6.opcode & 0xE0) {
+    case (0 << 5):  result = 6;     break;
+    case (1 << 5):
+    case (2 << 5):  result = 10;    break;
+    case (5 << 5):  result = 12;    break;
+    default:        result = 0;     break;
+    }
+    return (result);
+}
+
+
+Boolean
+IsVirtualMemoryRunning(void)
+{
+    OSErr                       status;
+    long                        response;
+    
+    status = Gestalt(gestaltVMAttr, &response);
+    /*
+     * VM is active iff Gestalt succeeded and the response is appropriate.
+     */
+    return (status == noErr && ((response & (1 << gestaltVMPresent)) != 0));
+}
+
+
+void
+AllocatePB()
+{
+    OSErr           status;
+    SCSIBusInquiryPB    busInquiryPB;
+#define PB          (busInquiryPB)
+
+    if (gSCSIExecIOPBPtr == NULL) {
+	CLEAR(PB);
+	PB.scsiPBLength = sizeof PB;
+	PB.scsiFunctionCode = SCSIBusInquiry;
+	PB.scsiDevice.bus = 0xFF;       /* Get info about the XPT */
+	status = SCSIAction((SCSI_PB *) &PB);
+	if (status == noErr)
+	    status = PB.scsiResult;
+	if (PB.scsiHiBusID == 0xFF) {
+	    gSCSIHiBusID = -1;
+	} else {
+	    gSCSIHiBusID = PB.scsiHiBusID;
+	}
+	gSCSIExecIOPBPtrLen = PB.scsiMaxIOpbSize;
+	if (gSCSIExecIOPBPtrLen != 0)
+	    gSCSIExecIOPBPtr = (SCSIExecIOPB *) NewPtrClear(gSCSIExecIOPBPtrLen);
+    }
+#undef PB
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/DoSCSICommand.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,130 @@
+/*
+ * DoScsiCommand.h -
+ *
+ * Modifed by Eryk Vershen
+ * from an original by Martin Minow
+ */
+
+/*
+ * Copyright 1993-1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __DoScsiCommand__
+#define __DoScsiCommand__
+
+#include <SCSI.h>
+#include "MacSCSICommand.h"
+
+
+/*
+ * Defines
+ */
+#ifndef EXTERN
+#define EXTERN              extern
+#endif
+
+#ifndef TRUE
+#define TRUE                1
+#define FALSE               0
+#endif
+
+#ifndef NULL
+#define NULL                0
+#endif
+
+#define kOriginalSCSIBusAdaptor (0xFF)
+
+#define SameSCSIDevice(a, b) ((*((UInt32 *) &a)) == (*((UInt32 *) &b)))
+
+/*
+ * Cheap 'n dirty memory clear routine.
+ */
+#define CLEAR(dst)          clear_memory((void *) &dst, sizeof dst)
+
+
+/*
+ * Types
+ */
+#if !defined(__NewTypesDefined__)
+#define __NewTypesDefined__
+typedef signed char     SInt8;
+typedef signed short    SInt16;
+typedef signed long     SInt32;
+typedef unsigned char   UInt8;
+typedef unsigned short  UInt16;
+typedef unsigned long   UInt32;
+typedef unsigned long   ItemCount;
+typedef unsigned long   ByteCount;
+#endif
+
+
+/*
+ * Global Constants
+ */
+enum {
+    bit0 = (1 << 0),
+    bit1 = (1 << 1),
+    bit2 = (1 << 2),
+    bit3 = (1 << 3),
+    bit4 = (1 << 4),
+    bit5 = (1 << 5),
+    bit6 = (1 << 6),
+    bit7 = (1 << 7)
+};
+
+
+/*
+ * Global Variables
+ */
+EXTERN int				gSCSIHiBusID;
+EXTERN SCSIExecIOPB     *gSCSIExecIOPBPtr;
+EXTERN UInt32           gSCSIExecIOPBPtrLen;
+
+
+/*
+ * Forward declarations
+ */
+void AllocatePB();
+Boolean IsIllegalRequest(OSErr scsiStatus, const SCSI_Sense_Data *senseDataPtr);
+Boolean IsNoMedia(OSErr scsiStatus, const SCSI_Sense_Data *senseDataPtr);
+/*
+ * All SCSI Commands come here.
+ *  if scsiDevice.busID == kOriginalSCSIBusAdaptor, IM-IV SCSI will be called.
+ *  scsiFlags should be scsiDirectionNone, scsiDirectionIn, or scsiDirectionOut
+ *  actualTransferCount may be NULL if you don't care.
+ *  Both old and new SCSI return SCSI Manager 4.3 errors.
+ *
+ * DoSCSICommand throws really serious errors, but returns SCSI errors such
+ * as dataRunError and scsiDeviceNotThere.
+ */
+OSErr DoSCSICommand(
+	DeviceIdent             scsiDevice,
+	ConstStr255Param        currentAction,
+	const SCSI_CommandPtr   callerSCSICommand,
+	Ptr                     dataBuffer,
+	ByteCount               dataLength,
+	UInt32                  scsiFlags,
+	ByteCount               *actualTransferCount,
+	SCSI_Sense_Data         *sensePtr,
+	StringPtr               senseMessage
+);
+
+
+#endif /* __DoScsiCommand__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/HISTORY	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,68 @@
+A short history of pdisk
+------------------------
+11/1996 -	Spent a week to create a minimal partitioner
+		that reads maps, initializes maps, can add and delete partitions.
+		Released as version 0.1 to MkLinux team
+		
+12/1996 -	Spent three weeks adding more commands, writing
+		documentation, fixing bugs and making it prettier.
+		Released version 0.2 to Gilbert
+		Fixed a few more bugs.
+		Released as version 0.3
+		
+01/1997 -	Spent two weeks creating MacOS version and fixing
+		a few more bugs.
+		Released as version 0.4
+		
+03/1997 - 	Spent an evening adding device driver deletion
+		and a couple of flags to private version.
+		
+07/1997 - 	Some one else ported it to Rhapsody.
+		Spent a couple of weeks adding variable block
+		size support to Rhapsody version.
+		Took the time to stop using rich man's source code control
+		(multiple copies) in linux/mac and put sources under RCS.
+		Folded linux/mac version changes into Rhapsody and
+		brought some of the Rhapsody changes into linux/mac
+		
+09/1997 -	Fixed bugs in MacOS version of variable block size.
+		Added new dump routines.
+		Added case-insensitive string matching.
+		Released one copy of version 0.5a3 source internally.
+
+10/1997 -	Wrote MacOS documentation
+		Minor fixes
+
+11/1997 -	A few more fixes
+		Released as version 0.5
+
+12/1997 -	Integrated new media abstraction
+		(includes support for ATA and ATAPI on MacOS)
+
+01/1998 -	Added media iterators (to fix grunge in dump.c)
+		Added os_reload_media (to get rid of ioctl's in write_partition_map)
+		Added rename partition command ('n' in edit mode)
+		Added /dev/hd? and /dev/scd? to MkLinux list all disks
+		Added 68k target to CW project
+
+02/1998 -	Released version 0.6
+		Added support for ATA/IDE disks without LBA capability
+		Fixed bug - create partition with unmodified size failed
+		Added support for new (DR3) MkLinux names - show MkLinux
+		name when displaying under another name and allow the
+		MkLinux name to be used on input.
+		Released version 0.7
+
+02-04/2000 -	Clean up sources - fix naming, delete old email addresses
+		Added support for display of Mac volume names
+		Added cvt_pt target (for LinuxPPC team)
+		Fix block 0 display to show logical offset of drivers
+		Require confimation of quit without write
+		Fix iteration to not complain about missing devices
+		Warn when creating/writing a map with more than 15 entries
+		Make initial window larger in Mac version
+		Fix ATA support to scan buses correctly
+		Fix linux names (in MacOS) to work right when many devices
+		Change so WORM devices are considered 'CDs'
+
+05/2000 - 	Released version 0.8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/MacSCSICommand.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,420 @@
+/*
+    File:       MacSCSICommand.h
+
+    Contains:   SCSI specific definitions.
+
+    Written by: Martin Minow
+
+*/
+
+/*
+ * Copyright 1995, 1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+/*
+ * Scsi-specific definitions.
+ */
+#ifndef __MacSCSICommand__
+#define __MacSCSICommand__
+
+/*
+ * The 6-byte commands are used for most simple
+ * I/O requests.
+ */
+struct SCSI_6_Byte_Command {                /* Six-byte command         */
+    unsigned char       opcode;             /*  0                       */
+    unsigned char       lbn3;               /*  1 lbn in low 5          */
+    unsigned char       lbn2;               /*  2                       */
+    unsigned char       lbn1;               /*  3                       */
+    unsigned char       len;                /*  4                       */
+    unsigned char       ctrl;               /*  5                       */
+};
+typedef struct SCSI_6_Byte_Command SCSI_6_Byte_Command;
+
+struct SCSI_10_Byte_Command {               /* Ten-byte command         */
+    unsigned char       opcode;             /*  0                       */
+    unsigned char       lun;                /*  1                       */
+    unsigned char       lbn4;               /*  2                       */
+    unsigned char       lbn3;               /*  3                       */
+    unsigned char       lbn2;               /*  4                       */
+    unsigned char       lbn1;               /*  5                       */
+    unsigned char       pad;                /*  6                       */
+    unsigned char       len2;               /*  7                       */
+    unsigned char       len1;               /*  8                       */
+    unsigned char       ctrl;               /*  9                       */
+};
+typedef struct SCSI_10_Byte_Command SCSI_10_Byte_Command;
+
+struct SCSI_12_Byte_Command {               /* Twelve-byte command      */
+    unsigned char       opcode;             /*  0                       */
+    unsigned char       lun;                /*  1                       */
+    unsigned char       lbn4;               /*  2                       */
+    unsigned char       lbn3;               /*  3                       */
+    unsigned char       lbn2;               /*  4                       */
+    unsigned char       lbn1;               /*  5                       */
+    unsigned char       len4;               /*  6                       */
+    unsigned char       len3;               /*  7                       */
+    unsigned char       len2;               /*  8                       */
+    unsigned char       len1;               /*  9                       */
+    unsigned char       pad;                /* 10                       */
+    unsigned char       ctrl;               /* 11                       */
+};
+typedef struct SCSI_12_Byte_Command SCSI_12_Byte_Command;
+
+/*
+ * This union defines all scsi commands.
+ */
+union SCSI_Command {
+    SCSI_6_Byte_Command     scsi6;
+    SCSI_10_Byte_Command    scsi10;
+    SCSI_12_Byte_Command    scsi12;
+    unsigned char           scsi[12];
+};
+typedef union SCSI_Command SCSI_Command, *SCSI_CommandPtr;
+
+/*
+ * Returned by a read-capacity command.
+ */
+struct SCSI_Capacity_Data {
+    unsigned char       lbn4;               /* Number                   */
+    unsigned char       lbn3;               /*  of                      */
+    unsigned char       lbn2;               /*   logical                */
+    unsigned char       lbn1;               /*    blocks                */
+    unsigned char       len4;               /* Length                   */
+    unsigned char       len3;               /*  of each                 */
+    unsigned char       len2;               /*   logical block          */
+    unsigned char       len1;               /*    in bytes              */
+};
+typedef struct SCSI_Capacity_Data SCSI_Capacity_Data;
+
+struct SCSI_Inquiry_Data {                  /* Inquiry returns this     */
+    unsigned char       devType;            /*  0 Device type,          */
+    unsigned char       devTypeMod;         /*  1 Device type modifier  */
+    unsigned char       version;            /*  2 ISO/ECMA/ANSI version */
+    unsigned char       format;             /*  3 Response data format  */
+    unsigned char       length;             /*  4 Additional Length     */
+    unsigned char       reserved5;          /*  5 Reserved              */
+    unsigned char       reserved6;          /*  6 Reserved              */
+    unsigned char       flags;              /*  7 Capability flags      */
+    unsigned char       vendor[8];          /*  8-15 Vendor-specific    */
+    unsigned char       product[16];        /* 16-31 Product id         */
+    unsigned char       revision[4];        /* 32-35 Product revision   */
+    unsigned char       vendorSpecific[20]; /* 36-55 Vendor stuff       */
+    unsigned char       moreReserved[40];   /* 56-95 Reserved           */
+};
+typedef struct SCSI_Inquiry_Data SCSI_Inquiry_Data;
+
+/*
+ * This bit may be set in SCSI_Inquiry_Data.devTypeMod
+ */
+enum {
+    kScsiInquiryRMB = 0x80                  /* Removable medium if set  */
+};
+/*
+ * These bits may be set in SCSI_Inquiry_Data.flags
+ */
+enum {
+    kScsiInquiryRelAdr  = 0x80,             /* Has relative addressing  */
+    kScsiInquiryWBus32  = 0x40,             /* Wide (32-bit) transfers  */
+    kScsiInquiryWBus16  = 0x20,             /* Wide (16-bit) transfers  */
+    kScsiInquirySync    = 0x10,             /* Synchronous transfers    */
+    kScsiInquiryLinked  = 0x08,             /* Linked commands ok       */
+    kScsiInquiryReserved = 0x04,
+    kScsiInquiryCmdQue  = 0x02,             /* Tagged cmd queuing ok    */
+    kScsiInquirySftRe   = 0x01              /* Soft reset alternative   */
+};
+
+/*
+ * These bits may be set in SCSI_Inquiry_Data.devType
+ */
+enum {
+    kScsiDevTypeDirect                  = 0,
+    kScsiDevTypeSequential,
+    kScsiDevTypePrinter,
+    kScsiDevTypeProcessor,
+    kScsiDevTypeWorm,                       /* Write-once, read mult    */
+    kScsiDevTypeCDROM,
+    kScsiDevTypeScanner,
+    kScsiDevTypeOptical,
+    kScsiDevTypeChanger,
+    kScsiDevTypeComm,
+    kScsiDevTypeGraphicArts0A,
+    kScsiDevTypeGraphicArts0B,
+    kScsiDevTypeFirstReserved,              /* Reserved sequence start  */
+    kScsiDevTypeUnknownOrMissing        = 0x1F,
+    kScsiDevTypeMask                    = 0x1F
+};
+/*
+ * These are device type qualifiers. We need them to distinguish between "unknown"
+ * and "missing" devices.
+ */
+enum {
+    kScsiDevTypeQualifierConnected      = 0x00, /* Exists and is connected      */
+    kScsiDevTypeQualifierNotConnected   = 0x20, /* Logical unit exists          */
+    kScsiDevTypeQualifierReserved       = 0x40,
+    kScsiDevTypeQualifierMissing        = 0x60, /* No such logical unit         */
+    kScsiDevTypeQualifierVendorSpecific = 0x80, /* Other bits are unspecified   */
+    kScsiDevTypeQualifierMask           = 0xE0
+};
+#define kScsiDevTypeMissing \
+    (kScsiDevTypeUnknownOrMissing | kScsiDevTypeQualifierMissing)
+
+/*
+ * This is the data that is returned after a GetExtendedStatus
+ * request. The errorCode gives a general indication of the error,
+ * which may be qualified by the additionalSenseCode and
+ * additionalSenseQualifier fields. These may be device (vendor)
+ * specific values, however. The info[] field contains additional
+ * information. For a media error, it contains the failing
+ * logical block number (most-significant byte first).
+ */
+struct SCSI_Sense_Data {                /* Request Sense result         */
+    unsigned char       errorCode;      /*  0   Class code, valid lbn   */
+    unsigned char       segmentNumber;  /*  1   Segment number          */
+    unsigned char       senseKey;       /*  2   Sense key and flags     */
+    unsigned char       info[4];
+    unsigned char       additionalSenseLength;
+    unsigned char       reservedForCopy[4];
+    unsigned char       additionalSenseCode;
+    unsigned char       additionalSenseQualifier;   
+    unsigned char       fruCode;        /* Field replacable unit code   */
+    unsigned char       senseKeySpecific[2];
+    unsigned char       additional[101];
+};
+typedef struct SCSI_Sense_Data SCSI_Sense_Data;
+/*
+ * The high-bit of errorCode signals whether there is a logical
+ * block. The low value signals whether there is a valid sense
+ */
+#define kScsiSenseHasLBN            0x80    /* Logical block number set */
+#define kScsiSenseInfoValid         0x70    /* Is sense key valid?      */
+#define kScsiSenseInfoMask          0x70    /* Mask for sense info      */
+/*
+ * These bits may be set in the sense key
+ */
+#define kScsiSenseKeyMask           0x0F
+#define kScsiSenseILI               0x20    /* Illegal logical Length   */
+#define kScsiSenseEOM               0x40    /* End of media             */
+#define kScsiSenseFileMark          0x80    /* End of file mark         */
+
+/*
+ * SCSI sense codes. (Returned after request sense).
+ */
+#define  kScsiSenseNone             0x00    /* No error                 */
+#define  kScsiSenseRecoveredErr     0x01    /* Warning                  */
+#define  kScsiSenseNotReady         0x02    /* Device not ready         */
+#define  kScsiSenseMediumErr        0x03    /* Device medium error      */
+#define  kScsiSenseHardwareErr      0x04    /* Device hardware error    */
+#define  kScsiSenseIllegalReq       0x05    /* Illegal request for dev. */
+#define  kScsiSenseUnitAtn          0x06    /* Unit attention (not err) */
+#define  kScsiSenseDataProtect      0x07    /* Data protection          */
+#define  kScsiSenseBlankCheck       0x08    /* Tape-specific error      */
+#define  kScsiSenseVendorSpecific   0x09    /* Vendor-specific error    */
+#define  kScsiSenseCopyAborted      0x0a    /* Copy request cancelled   */
+#define  kScsiSenseAbortedCmd       0x0b    /* Initiator aborted cmd.   */
+#define  kScsiSenseEqual            0x0c    /* Comparison equal         */
+#define  kScsiSenseVolumeOverflow   0x0d    /* Write past end mark      */
+#define  kScsiSenseMiscompare       0x0e    /* Comparison failed        */
+#define  kScsiSenseCurrentErr       0x70
+#define  kScsiSenseDeferredErr      0x71
+
+/*
+ * Mode sense parameter header
+ */
+struct SCSI_ModeParamHeader {
+    unsigned char       modeDataLength;
+    unsigned char       mediumType;
+    unsigned char       deviceSpecific;
+    unsigned char       blockDescriptorLength;
+};
+typedef struct SCSI_ModeParamHeader SCSI_ModeParamHeader;
+
+struct SCSI_ModeParamBlockDescriptor {
+    unsigned char       densityCode;
+    unsigned char       numberOfBlocks[3];
+    unsigned char       reserved;
+    unsigned char       blockLength[3];
+};
+typedef struct SCSI_ModeParamBlockDescriptor SCSI_ModeParamBlockDescriptor;
+
+union SCSI_ModeParamPage {
+    unsigned char       data[1];
+    struct {
+	unsigned char   code;
+	unsigned char   length;
+    } page;
+};
+typedef union SCSI_ModeParamPage SCSI_ModeParamPage;
+
+/*
+ * LogSense parameter header
+ */
+struct SCSI_LogSenseParamHeader {
+    unsigned char       pageCode;
+    unsigned char       reserved;
+    unsigned char       pageLength[2];
+};
+typedef struct SCSI_LogSenseParamHeader SCSI_LogSenseParamHeader;
+
+/*
+ * Log parameter pages are variable-length with a fixed length header.
+ */
+union SCSI_LogSenseParamPage {
+    unsigned char       data[1];
+    struct {
+	unsigned char   parameterCode[2];
+	unsigned char   flags;
+	unsigned char   parameterLength;
+    } page;
+};
+typedef union SCSI_LogSenseParamPage SCSI_LogSenseParamPage;
+
+/*
+ * SCSI command status (from status phase)
+ */
+#define  kScsiStatusGood            0x00    /* Normal completion        */
+#define  kScsiStatusCheckCondition  0x02    /* Need GetExtendedStatus   */
+#define  kScsiStatusConditionMet    0x04
+#define  kScsiStatusBusy            0x08    /* Device busy (self-test?) */
+#define  kScsiStatusIntermediate    0x10    /* Intermediate status      */
+#define  kScsiStatusResConflict     0x18    /* Reservation conflict     */
+#define  kScsiStatusQueueFull       0x28    /* Target can't do command  */
+#define  kScsiStatusReservedMask    0x3e    /* Vendor specific?         */
+
+/*
+ * SCSI command codes. Commands defined as ...6, ...10, ...12, are
+ * six-byte, ten-byte, and twelve-byte variants of the indicated command.
+ */
+/*
+ * These commands are supported for all devices.
+ */
+#define kScsiCmdChangeDefinition    0x40
+#define kScsiCmdCompare             0x39
+#define kScsiCmdCopy                0x18
+#define kScsiCmdCopyAndVerify       0x3a
+#define kScsiCmdInquiry             0x12
+#define kScsiCmdLogSelect           0x4c
+#define kScsiCmdLogSense            0x4d
+#define kScsiCmdModeSelect10        0x55
+#define kScsiCmdModeSelect6         0x15
+#define kScsiCmdModeSense10         0x5a
+#define kScsiCmdModeSense6          0x1a
+#define kScsiCmdReadBuffer          0x3c
+#define kScsiCmdRecvDiagResult      0x1c
+#define kScsiCmdRequestSense        0x03
+#define kScsiCmdSendDiagnostic      0x1d
+#define kScsiCmdTestUnitReady       0x00
+#define kScsiCmdWriteBuffer         0x3b
+
+/*
+ * These commands are supported by direct-access devices only.
+ */
+#define kScsiCmdFormatUnit          0x04
+#define kSCSICmdCopy                0x18
+#define kSCSICmdCopyAndVerify       0x3a
+#define kScsiCmdLockUnlockCache     0x36
+#define kScsiCmdPrefetch            0x34
+#define kScsiCmdPreventAllowRemoval 0x1e
+#define kScsiCmdRead6               0x08
+#define kScsiCmdRead10              0x28
+#define kScsiCmdReadCapacity        0x25
+#define kScsiCmdReadDefectData      0x37
+#define kScsiCmdReadLong            0x3e
+#define kScsiCmdReassignBlocks      0x07
+#define kScsiCmdRelease             0x17
+#define kScsiCmdReserve             0x16
+#define kScsiCmdRezeroUnit          0x01
+#define kScsiCmdSearchDataEql       0x31
+#define kScsiCmdSearchDataHigh      0x30
+#define kScsiCmdSearchDataLow       0x32
+#define kScsiCmdSeek6               0x0b
+#define kScsiCmdSeek10              0x2b
+#define kScsiCmdSetLimits           0x33
+#define kScsiCmdStartStopUnit       0x1b
+#define kScsiCmdSynchronizeCache    0x35
+#define kScsiCmdVerify              0x2f
+#define kScsiCmdWrite6              0x0a
+#define kScsiCmdWrite10             0x2a
+#define kScsiCmdWriteAndVerify      0x2e
+#define kScsiCmdWriteLong           0x3f
+#define kScsiCmdWriteSame           0x41
+
+/*
+ * These commands are supported by sequential devices.
+ */
+#define kScsiCmdRewind              0x01
+#define kScsiCmdWriteFilemarks      0x10
+#define kScsiCmdSpace               0x11
+#define kScsiCmdLoadUnload          0x1B
+/*
+ * ANSI SCSI-II for CD-ROM devices.
+ */
+#define kScsiCmdReadCDTableOfContents   0x43
+
+/*
+ * Message codes (for Msg In and Msg Out phases).
+ */
+#define kScsiMsgAbort               0x06
+#define kScsiMsgAbortTag            0x0d
+#define kScsiMsgBusDeviceReset      0x0c
+#define kScsiMsgClearQueue          0x0e
+#define kScsiMsgCmdComplete         0x00
+#define kScsiMsgDisconnect          0x04
+#define kScsiMsgIdentify            0x80
+#define kScsiMsgIgnoreWideResdue    0x23
+#define kScsiMsgInitiateRecovery    0x0f
+#define kScsiMsgInitiatorDetectedErr 0x05
+#define kScsiMsgLinkedCmdComplete   0x0a
+#define kScsiMsgLinkedCmdCompleteFlag 0x0b
+#define kScsiMsgParityErr           0x09
+#define kScsiMsgRejectMsg           0x07
+#define kScsiMsgModifyDataPtr       0x00 /* Extended msg        */
+#define kScsiMsgNop                 0x08
+#define kScsiMsgHeadOfQueueTag      0x21 /* Two byte msg        */
+#define kScsiMsgOrderedQueueTag     0x22 /* Two byte msg        */
+#define kScsiMsgSimpleQueueTag      0x20 /* Two byte msg        */
+#define kScsiMsgReleaseRecovery     0x10
+#define kScsiMsgRestorePointers     0x03
+#define kScsiMsgSaveDataPointers    0x02
+#define kScsiMsgSyncXferReq         0x01 /* Extended msg        */
+#define kScsiMsgWideDataXferReq     0x03 /* Extended msg        */
+#define kScsiMsgTerminateIOP        0x11
+#define kScsiMsgExtended            0x01
+#define kScsiMsgEnableDisconnectMask 0x40
+
+#define kScsiMsgTwoByte             0x20
+#define kScsiMsgTwoByteMin          0x20
+#define kScsiMsgTwoByteMax          0x2f
+
+/*
+ * Default timeout times for SCSI commands (times are in Msec).
+ */
+#define kScsiNormalCompletionTime   (500L)          /* 1/2 second               */
+/*
+ * Dratted DAT tape.
+ */
+#define kScsiDATCompletionTime      (60L * 1000L);  /* One minute               */
+/*
+ * Yes, we do allow 90 seconds for spin-up of those dratted tape drives.
+ */
+#define kScsiSpinUpCompletionTime   (90L * 1000L)
+
+
+#endif /* __MacSCSICommand__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/README	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,147 @@
+Product name:	pdisk
+Version:	0.8
+Ship date:	16 May 2000
+Company name:	n/a
+Author name:	Eryk Vershen
+
+Description:	A low-level Apple partition table editor for Linux.
+		A MacOS version exists for "standalone" use.
+
+What's New:	Clean up sources - fix naming, delete old email addresses
+		Added support for display of Mac volume names
+		Added cvt_pt target (for LinuxPPC team)
+		Fix block 0 display to show logical offset of drivers
+		Require confimation of quit without write
+		Fix iteration to not complain about missing devices
+		Warn when creating/writing a map with more than 15 entries
+		Make initial window larger in Mac version
+		Fix ATA support to scan buses correctly
+		Fix linux names (in MacOS) to work right when many devices
+		Change so WORM devices are considered 'CDs'
+
+Last time:	Added support for ATA/IDE disks without LBA capability
+		Fixed bug - create partition with unmodified size failed
+		Added support for new (DR3) MkLinux names - show MkLinux
+		name when displaying under another name and allow the
+		MkLinux name to be used on input.
+
+Requirements:	Linux PPC - just run the binary
+		MacOS - Distributed binaries for PowerPC or 68000
+			I haven't tried it except on 7.6.1 and 8.0
+
+Price:		Free
+
+Legalese:	
+    Modifications copyright 2000 by Eryk Vershen
+    
+    Copyright 1996,1997,1998 by Apple Computer, Inc.
+    All Rights Reserved 
+
+    Permission to use, copy, modify, and distribute this software and 
+    its documentation for any purpose and without fee is hereby granted, 
+    provided that the above copyright notice appears in all copies and 
+    that both the copyright notice and this permission notice appear in 
+    supporting documentation. 
+
+    APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+    INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+    FOR A PARTICULAR PURPOSE. 
+
+    IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+    CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+    LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+    NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+    WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+
+
+Contact Info:	You can send mail to the author. There is  no guarantee of
+		a response, but it is your best hope of getting a bug fixed
+		or a feature added.
+
+
+Other info:
+
+
+READ the html file or the man page.
+
+
+Finding out about apple partitioning
+------------------------------------
+The best curently available documentation on the Apple disk partitioning scheme
+is "Technote 1189: The Monster Disk Drive Technote".  This release is not
+completely in sync with that technote.  Maybe next time.
+		
+
+Building the macintosh application
+----------------------------------
+I have only built this under Code Warrior Pro.  The project file is included.
+Thanks to Martin Minow for the SCSI support code.
+
+
+Some notes on the apple partitioning
+------------------------------------
+The apple disk partitioning scheme was developed in 1986. It attempted to
+be forward thinking as it was intended to handle drives of sizes up to several
+hundred megabytes.  There was a design document, but like most such documents
+it was neither complete nor unambiguous.
+
+While the original intent was to handle various block sizes, in practice
+most devices use a partitioning block size of 512 bytes.
+Since the various address fields are 32 bits unsigned this means the format
+can handle disks up to 2 Terabytes in size.  (32bits + 9 bits = 41 bits)
+Because the format was designed around SCSI, there is no knowledge of
+cylinders or heads, all block address are in absolute sector form.
+A correct map should describe every block on the disk except for block zero.
+
+An aside on CDROMs.  Most old apple CDROMs have incorrect data in block zero.
+Since the HFS file-system could only handle 512 byte blocks, apple drives had
+a special mode where they would do deblocking (i.e. converting 2k blocks
+into four 512byte blocks and accepting 512byte block addresses.)  The partition
+maps laid down on these disks are for the deblocked form.  In many cases the
+partition maps they contain have only the minimum number of fields correct.
+At least one CDROM I have seen doesn't even contain a partition map at all,
+but is simply an HFS volume.
+Bootable CD-ROMs have even stranger partition maps since two are laid down:
+one at 2K offsets and one at 512-byte offsets.  If you notice that these
+overlap then you begin to get an idea of how wierd these maps can be.
+Apple refers to this "technique" as ghost partitioning.
+
+The documentation in Inside Macintosh is only partially correct.
+The boot-arguments field was left out.  A/UX used the boot arguments field
+for something that was called the bzb (block zero block - don't ask me why).
+This structure evolved over the course of A/UX.  I have recapitulated this
+in the dpme.h header file.
+
+
+Making a disk with Apple & Intel partitioning
+---------------------------------------------
+Don't cringe. I know it is an awful hack, but sometimes...
+While I don't recommend doing this, it can be useful.
+The procedure below is what we did.
+
+The intel map can contain NO MORE THAN FOUR PRIMARY PARTITIONS.
+You can't have any extended or logical partitions.  (Well, you might get it
+to work but I wouldn't want to try it.)  The disk will NOT BE INTEL BOOTABLE.
+
+1) Use pdisk to initialize an apple partition map.  Don't add any partitions
+   yet, just write the map out and quit.
+
+2) Use fdisk to create the primary partitions.  Go into the expert 'x' menu
+   in fdisk and print out the table with the sector addresses.  Write the
+   start and lengths down some where.  Write the table out.
+
+3) Use pdisk again.  Shrink the partition map down, if necessary, so it
+   does not overlap any intel partition.  Create an apple partition for each
+   intel partition using the start and length value you got from fdisk.
+   Write out the map and quit.
+
+At present file systems are not compatible between Linux & MkLinux, but you
+can tar stuff into these partitions and tar them out on another machine.
+
+
+
+Good luck,
+
+-eryk vershen
+ software mechanic
+ eryk@cfcl.com
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/SCSI_media.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,1108 @@
+/*
+ * SCSI_media.c -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+// for printf() & sprintf()
+#include <stdio.h>
+// for malloc() & free()
+#include <stdlib.h>
+#include "DoSCSICommand.h"
+#include "SCSI_media.h"
+#include "util.h"
+
+
+/*
+ * Defines
+ */
+#define DriverRefNumToSCSI(x)  ((signed short) (~(x) - 32))
+
+
+/*
+ * Types
+ */
+typedef struct SCSI_media *SCSI_MEDIA;
+
+struct SCSI_media {
+    struct media    m;
+    long            bus;
+    long            id;
+};
+
+struct bus_entry {
+    long    bus;
+    long    sort_value;
+    long    max_id;
+    long    master_id;
+};
+
+struct SCSI_manager {
+    long        exists;
+    long        kind;
+    long        bus_count;
+    struct bus_entry *bus_list;
+};
+
+typedef struct SCSI_media_iterator *SCSI_MEDIA_ITERATOR;
+
+struct SCSI_media_iterator {
+    struct media_iterator   m;
+    long                    bus_index;
+    long                    bus;
+    long                    id;
+};
+
+struct linux_order_cache {
+    struct cache_item *first;
+    struct cache_item *last;
+    long next_disk;
+    long next_cdrom;
+    long loaded;
+};
+
+struct cache_item {
+    struct cache_item *next;
+    long bus;
+    long id;
+    long value;
+    long is_cdrom;
+    long unsure;
+};
+
+
+/*
+ * Global Constants
+ */
+enum {
+    kNoDevice = 0x00FF
+};
+
+enum {
+    kRequiredSCSIinquiryLength = 36
+};
+
+
+/*
+ * Global Variables
+ */
+static long scsi_inited = 0;
+static struct SCSI_manager scsi_mgr;
+static struct linux_order_cache linux_order;
+
+
+/*
+ * Forward declarations
+ */
+int AsyncSCSIPresent(void);
+void scsi_init(void);
+SCSI_MEDIA new_scsi_media(void);
+long read_scsi_media(MEDIA m, long long offset, unsigned long count, void *address);
+long write_scsi_media(MEDIA m, long long offset, unsigned long count, void *address);
+long close_scsi_media(MEDIA m);
+long os_reload_scsi_media(MEDIA m);
+long compute_id(long bus, long device);
+int SCSI_ReadBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address);
+int SCSI_WriteBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address);
+int DoTestUnitReady(UInt8 targetID, int bus);
+int DoReadCapacity(UInt32 id, UInt32 bus, UInt32 *blockCount, UInt32 *blockSize);
+SCSI_MEDIA_ITERATOR new_scsi_iterator(void);
+void reset_scsi_iterator(MEDIA_ITERATOR m);
+char *step_scsi_iterator(MEDIA_ITERATOR m);
+void delete_scsi_iterator(MEDIA_ITERATOR m);
+void fill_bus_entry(struct bus_entry *entry, long bus);
+/*long get_bus_sort_value(long bus);*/
+int bus_entry_compare(const void* a, const void* b);
+int DoInquiry(UInt32 id, UInt32 bus, UInt32 *devType);
+void probe_all(void);
+void probe_scsi_device(long bus, long id, int unsure);
+long lookup_scsi_device(long bus, long id, int *is_cdrom, int *unsure);
+long lookup_scsi_index(long index, int is_cdrom, long *bus, long *id);
+void add_to_cache(long bus, long id, int is_cdrom, int unsure);
+void init_linux_cache(void);
+void clear_linux_cache(void);
+void mark_linux_cache_loaded(void);
+int linux_cache_loaded(void);
+
+
+/*
+ * Routines
+ */
+int
+AsyncSCSIPresent(void)
+{
+    return (TrapAvailable(_SCSIAtomic));
+}
+
+
+void
+scsi_init(void)
+{
+    int i;
+    int old_scsi;
+    
+    if (scsi_inited != 0) {
+	return;
+    }
+    scsi_inited = 1;
+    
+    scsi_mgr.exists = 1;
+    scsi_mgr.kind = allocate_media_kind();
+
+    if (AsyncSCSIPresent()) {
+	AllocatePB();
+
+	scsi_mgr.bus_count = gSCSIHiBusID + 1;
+	old_scsi = 0;
+    } else {
+	scsi_mgr.bus_count = 1;
+	old_scsi = 1;
+    }
+    
+    scsi_mgr.bus_list = (struct bus_entry *)
+	    calloc(scsi_mgr.bus_count, sizeof(struct bus_entry));
+	    
+    if (scsi_mgr.bus_list == 0) {
+	scsi_mgr.bus_count = 0;
+    } else {
+	for (i = 0; i < scsi_mgr.bus_count; i++) {
+	    if (old_scsi) {
+		scsi_mgr.bus_list[i].bus = 0xFF;
+	    } else {
+		scsi_mgr.bus_list[i].bus = i;
+	    }
+	    fill_bus_entry(&scsi_mgr.bus_list[i], i);
+	}
+	qsort((void *)scsi_mgr.bus_list,    /* address of array */
+		scsi_mgr.bus_count,         /* number of elements */
+		sizeof(struct bus_entry),   /* size of element */
+		bus_entry_compare);         /* element comparison routine */
+    }
+    
+    init_linux_cache();
+}
+
+void
+fill_bus_entry(struct bus_entry *entry, long bus)
+{
+    OSErr           status;
+    SCSIBusInquiryPB    pb;
+    long len;
+    long result;
+    long x, y;
+
+    if (!AsyncSCSIPresent()) {
+    	entry->sort_value = 0;
+	entry->max_id = 7;
+	entry->master_id = 7;
+	return;
+    }
+    len = sizeof(SCSIBusInquiryPB);
+    clear_memory((Ptr) &pb, len);
+    pb.scsiPBLength = len;
+    pb.scsiFunctionCode = SCSIBusInquiry;
+    pb.scsiDevice.bus = bus;
+    status = SCSIAction((SCSI_PB *) &pb);
+    if (status != noErr) {
+	result = 6;
+    } else {
+	switch (pb.scsiHBAslotType) {
+	case scsiMotherboardBus:    x = 0; break;
+	case scsiPDSBus:            x = 1; break;
+	case scsiNuBus:             x = 2; break;
+	case scsiPCIBus:            x = 3; break;
+	case scsiFireWireBridgeBus: x = 4; break;
+	case scsiPCMCIABus:         x = 5; break;
+	default:                    x = 7 + pb.scsiHBAslotType; break;
+	};
+	
+	switch (pb.scsiFeatureFlags & scsiBusInternalExternalMask) {
+	case scsiBusInternal:                   y = 0; break;
+	case scsiBusInternalExternal:           y = 1; break;
+	case scsiBusExternal:                   y = 2; break;
+	default:
+	case scsiBusInternalExternalUnknown:    y = 3; break;
+	};
+	result = x * 4 + y;
+    }
+    entry->sort_value = result;
+    entry->max_id = pb.scsiMaxLUN;
+    entry->master_id = pb.scsiInitiatorID;
+}
+
+
+int
+bus_entry_compare(const void* a, const void* b)
+{
+    long result;
+    
+    const struct bus_entry *x = (const struct bus_entry *) a;
+    const struct bus_entry *y = (const struct bus_entry *) b;
+    
+    result = x->sort_value - y->sort_value;
+    if (result == 0) {
+	result = x->bus - y->bus;
+    }
+    return result;
+}
+
+
+SCSI_MEDIA
+new_scsi_media(void)
+{
+    return (SCSI_MEDIA) new_media(sizeof(struct SCSI_media));
+}
+
+
+MEDIA
+open_old_scsi_as_media(long device)
+{
+    return open_scsi_as_media(kOriginalSCSIBusAdaptor, device);
+}
+
+
+MEDIA
+open_scsi_as_media(long bus, long device)
+{
+    SCSI_MEDIA  a;
+    UInt32 blockCount;
+    UInt32 blockSize;
+    
+    if (scsi_inited == 0) {
+	scsi_init();
+    }
+    
+    if (scsi_mgr.exists == 0) {
+	return 0;
+    }
+
+    a = 0;
+    if (DoTestUnitReady(device, bus) > 0) {
+	if (DoReadCapacity(device, bus, &blockCount, &blockSize) != 0) {
+	    a = new_scsi_media();
+	    if (a != 0) {
+		a->m.kind = scsi_mgr.kind;
+		a->m.grain = blockSize;
+		a->m.size_in_bytes = ((long long)blockCount) * blockSize;
+		a->m.do_read = read_scsi_media;
+		a->m.do_write = write_scsi_media;
+		a->m.do_close = close_scsi_media;
+		a->m.do_os_reload = os_reload_scsi_media;
+		a->bus = bus;
+		a->id = device;
+	    }
+	}
+    }
+    return (MEDIA) a;
+}
+
+
+long
+read_scsi_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+    SCSI_MEDIA a;
+    long rtn_value;
+    long block;
+    long block_count;
+    long block_size;
+    unsigned char *buffer;
+    int i;
+    
+    block = (long) offset;
+//printf("scsi %d count %d\n", block, count);
+    a = (SCSI_MEDIA) m;
+    rtn_value = 0;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != scsi_mgr.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else if (count <= 0 || count % a->m.grain != 0) {
+	/* can't handle size */
+    } else if (offset < 0 || offset % a->m.grain != 0) {
+	/* can't handle offset */
+    } else if (offset + count > a->m.size_in_bytes) {
+	/* check for offset (and offset+count) too large */
+    } else {
+	/* XXX do a read on the physical device */
+	block_size = a->m.grain;
+	block = offset / block_size;
+	block_count = count / block_size;
+	buffer = address;
+	rtn_value = 1;
+	for (i = 0; i < block_count; i++) {
+	    if (SCSI_ReadBlock(a->id, a->bus, block_size, block, buffer) == 0) {
+		rtn_value = 0;
+		break;
+	    }
+	    buffer += block_size;
+	    block += 1;
+	}
+    }
+    return rtn_value;
+}
+
+
+long
+write_scsi_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+    SCSI_MEDIA a;
+    long rtn_value;
+    long block;
+    long block_count;
+    long block_size;
+    unsigned char *buffer;
+    int i;
+    
+    a = (SCSI_MEDIA) m;
+    rtn_value = 0;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != scsi_mgr.kind) {
+	/* XXX need to error here - this is an internal problem */
+    } else if (count <= 0 || count % a->m.grain != 0) {
+	/* can't handle size */
+    } else if (offset < 0 || offset % a->m.grain != 0) {
+	/* can't handle offset */
+    } else if (offset + count > a->m.size_in_bytes) {
+	/* check for offset (and offset+count) too large */
+    } else {
+	/* XXX do a write on the physical device */
+	block_size = a->m.grain;
+	block = offset / block_size;
+	block_count = count / block_size;
+	buffer = address;
+	rtn_value = 1;
+	for (i = 0; i < block_count; i++) {
+	    if (SCSI_WriteBlock(a->id, a->bus, block_size, block, buffer) == 0) {
+		rtn_value = 0;
+		break;
+	    }
+	    buffer += block_size;
+	    block += 1;
+	}
+    }
+    return rtn_value;
+}
+
+
+long
+close_scsi_media(MEDIA m)
+{
+    SCSI_MEDIA a;
+    
+    a = (SCSI_MEDIA) m;
+    if (a == 0) {
+	return 0;
+    } else if (a->m.kind != scsi_mgr.kind) {
+	/* XXX need to error here - this is an internal problem */
+	return 0;
+    }
+    /* XXX nothing to do - I think? */
+    return 1;
+}
+
+
+long
+os_reload_scsi_media(MEDIA m)
+{
+    printf("Reboot your system so the partition table will be reread.\n");
+    return 1;
+}
+
+
+#pragma mark -
+
+
+int
+DoTestUnitReady(UInt8 targetID, int bus)
+{
+    OSErr                   status;
+    Str255                  errorText;
+    char*       msg;
+    static const SCSI_6_Byte_Command gTestUnitReadyCommand = {
+	kScsiCmdTestUnitReady, 0, 0, 0, 0, 0
+    };
+    SCSI_Sense_Data         senseData;
+    DeviceIdent scsiDevice;
+    int rtn_value;
+
+    scsiDevice.diReserved = 0;
+    scsiDevice.bus = bus;
+    scsiDevice.targetID = targetID;
+    scsiDevice.LUN = 0;
+
+    status = DoSCSICommand(
+		scsiDevice,
+		"\pTest Unit Ready",
+		(SCSI_CommandPtr) &gTestUnitReadyCommand,
+		NULL,
+		0,
+		scsiDirectionNone,
+		NULL,
+		&senseData,
+		errorText
+		);
+    if (status == scsiNonZeroStatus) {
+	rtn_value = -1;
+    } else if (status != noErr) {
+	rtn_value = 0;
+    } else {
+	rtn_value = 1;
+    }
+    return rtn_value;
+}
+
+
+int
+SCSI_ReadBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address)
+{
+    OSErr                   status;
+    Str255                  errorText;
+    char*       msg;
+    static SCSI_10_Byte_Command gReadCommand = {
+	kScsiCmdRead10, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    SCSI_Sense_Data         senseData;
+    DeviceIdent scsiDevice;
+    int rtn_value;
+    long count;
+
+//printf("scsi read %d:%d block %d size %d\n", bus, id, block, block_size);
+    scsiDevice.diReserved = 0;
+    scsiDevice.bus = bus;
+    scsiDevice.targetID = id;
+    scsiDevice.LUN = 0;
+
+    gReadCommand.lbn4 = (block >> 24) & 0xFF;
+    gReadCommand.lbn3 = (block >> 16) & 0xFF;
+    gReadCommand.lbn2 = (block >> 8) & 0xFF;
+    gReadCommand.lbn1 = block & 0xFF;
+
+    count = 1;
+    gReadCommand.len2 = (count >> 8) & 0xFF;
+    gReadCommand.len1 = count & 0xFF;
+
+    status = DoSCSICommand(
+		scsiDevice,
+		"\pRead",
+		(SCSI_CommandPtr) &gReadCommand,
+		(Ptr) address,
+		count * block_size,
+		scsiDirectionIn,
+		NULL,
+		&senseData,
+		errorText
+	);
+    if (status == noErr) {
+	rtn_value = 1;
+    } else {
+	rtn_value = 0;
+    }
+    return rtn_value;
+}
+
+
+int
+SCSI_WriteBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address)
+{
+    OSErr                   status;
+    Str255                  errorText;
+    char*       msg;
+    static SCSI_10_Byte_Command gWriteCommand = {
+	kScsiCmdWrite10, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    SCSI_Sense_Data         senseData;
+    DeviceIdent scsiDevice;
+    int rtn_value;
+    long count;
+
+    scsiDevice.diReserved = 0;
+    scsiDevice.bus = bus;
+    scsiDevice.targetID = id;
+    scsiDevice.LUN = 0;
+
+    gWriteCommand.lbn4 = (block >> 24) & 0xFF;
+    gWriteCommand.lbn3 = (block >> 16) & 0xFF;
+    gWriteCommand.lbn2 = (block >> 8) & 0xFF;
+    gWriteCommand.lbn1 = block & 0xFF;
+
+    count = 1;
+    gWriteCommand.len2 = (count >> 8) & 0xFF;
+    gWriteCommand.len1 = count & 0xFF;
+
+    status = DoSCSICommand(
+		scsiDevice,
+		"\pWrite",
+		(SCSI_CommandPtr) &gWriteCommand,
+		(Ptr) address,
+		count * block_size,
+		scsiDirectionOut,
+		NULL,
+		&senseData,
+		errorText
+	);
+    if (status == noErr) {
+	rtn_value = 1;
+    } else {
+	rtn_value = 0;
+    }
+    return rtn_value;
+}
+
+
+int
+DoReadCapacity(UInt32 id, UInt32 bus, UInt32 *blockCount, UInt32 *blockSize)
+{
+    OSErr       status;
+    Str255      errorText;
+    static const SCSI_10_Byte_Command gCapacityCommand = {
+	kScsiCmdReadCapacity, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    SCSI_Sense_Data senseData;
+    DeviceIdent     scsiDevice;
+    SCSI_Capacity_Data  capacityData;
+    UInt32      temp;
+    int rtn_value;
+
+    scsiDevice.diReserved = 0;
+    scsiDevice.bus = bus;
+    scsiDevice.targetID = id;
+    scsiDevice.LUN = 0;
+
+    CLEAR(capacityData);
+
+    status = DoSCSICommand(
+		scsiDevice,
+		"\pRead Capacity",
+		(SCSI_CommandPtr) &gCapacityCommand,
+		(Ptr) &capacityData,
+		sizeof (SCSI_Capacity_Data),
+		scsiDirectionIn,
+		NULL,
+		&senseData,
+		errorText
+		);
+
+    if (status == noErr) {
+	temp = capacityData.lbn4;
+	temp = (temp << 8) | capacityData.lbn3;
+	temp = (temp << 8) | capacityData.lbn2;
+	temp = (temp << 8) | capacityData.lbn1;
+	*blockCount = temp;
+
+	temp = capacityData.len4;
+	temp = (temp << 8) | capacityData.len3;
+	temp = (temp << 8) | capacityData.len2;
+	temp = (temp << 8) | capacityData.len1;
+	*blockSize = temp;
+
+	rtn_value = 1;
+    } else {
+	rtn_value = 0;
+    }
+    return rtn_value;
+}
+
+
+int
+DoInquiry(UInt32 id, UInt32 bus, UInt32 *devType)
+{
+    OSErr       status;
+    Str255      errorText;
+    static const SCSI_6_Byte_Command gInquiryCommand = {
+	kScsiCmdInquiry, 0, 0, 0, kRequiredSCSIinquiryLength, 0
+    };
+    SCSI_Sense_Data senseData;
+    DeviceIdent     scsiDevice;
+    SCSI_Inquiry_Data  inquiryData;
+    UInt32      temp;
+    int rtn_value;
+
+    scsiDevice.diReserved = 0;
+    scsiDevice.bus = bus;
+    scsiDevice.targetID = id;
+    scsiDevice.LUN = 0;
+
+    CLEAR(inquiryData);
+
+    status = DoSCSICommand(
+		scsiDevice,
+		"\pInquiry",
+		(SCSI_CommandPtr) &gInquiryCommand,
+		(Ptr) &inquiryData,
+		kRequiredSCSIinquiryLength,
+		scsiDirectionIn,
+		NULL,
+		&senseData,
+		errorText
+		);
+
+    if (status == noErr) {
+	*devType = inquiryData.devType & kScsiDevTypeMask;
+	rtn_value = 1;
+    } else {
+	rtn_value = 0;
+    }
+    return rtn_value;
+}
+
+
+MEDIA
+SCSI_FindDevice(long dRefNum)
+{
+    SCSIDriverPB            pb;
+    OSErr                   status;
+    short                   targetID;
+    
+    status = nsvErr;
+    if (AsyncSCSIPresent()) {
+	clear_memory((Ptr) &pb, sizeof pb);
+	
+	pb.scsiPBLength = sizeof (SCSIDriverPB);
+	pb.scsiCompletion = NULL;
+	pb.scsiFlags = 0;
+	pb.scsiFunctionCode = SCSILookupRefNumXref;
+	pb.scsiDevice.bus = kNoDevice;  /* was *((long *) &pb.scsiDevice) = 0xFFFFFFFFL; */
+	
+	do {
+	    status = SCSIAction((SCSI_PB *) &pb);
+	    
+	    if (status != noErr) {
+		break;
+	    } else if (pb.scsiDriver == dRefNum
+		    && pb.scsiDevice.bus != kNoDevice) {
+		return open_scsi_as_media(pb.scsiDevice.bus, pb.scsiDevice.targetID);
+
+	    } else {
+		pb.scsiDevice = pb.scsiNextDevice;
+	    }
+	}
+	while (pb.scsiDevice.bus != kNoDevice);
+    }
+    if (status == nsvErr) {
+	/*
+	 * The asynchronous SCSI Manager is missing or the
+	 * driver didn't register with the SCSI Manager.*/
+	targetID = DriverRefNumToSCSI(dRefNum);
+	if (targetID >= 0 && targetID <= 6) {
+	    return open_old_scsi_as_media(targetID);
+	}
+    }
+     return 0;
+}
+
+
+#pragma mark -
+
+
+SCSI_MEDIA_ITERATOR
+new_scsi_iterator(void)
+{
+    return (SCSI_MEDIA_ITERATOR) new_media_iterator(sizeof(struct SCSI_media_iterator));
+}
+
+
+MEDIA_ITERATOR
+create_scsi_iterator(void)
+{
+    SCSI_MEDIA_ITERATOR a;
+    
+    if (scsi_inited == 0) {
+	scsi_init();
+    }
+    
+    if (scsi_mgr.exists == 0) {
+	return 0;
+    }
+
+    a = new_scsi_iterator();
+    if (a != 0) {
+	a->m.kind = scsi_mgr.kind;
+	a->m.state = kInit;
+	a->m.do_reset = reset_scsi_iterator;
+	a->m.do_step = step_scsi_iterator;
+	a->m.do_delete = delete_scsi_iterator;
+	a->bus_index = 0;
+	a->bus = 0;
+	a->id = 0;
+    }
+
+    return (MEDIA_ITERATOR) a;
+}
+
+
+void
+reset_scsi_iterator(MEDIA_ITERATOR m)
+{
+    SCSI_MEDIA_ITERATOR a;
+    
+    a = (SCSI_MEDIA_ITERATOR) m;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != scsi_mgr.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else if (a->m.state != kInit) {
+	a->m.state = kReset;
+    }
+}
+
+
+char *
+step_scsi_iterator(MEDIA_ITERATOR m)
+{
+    SCSI_MEDIA_ITERATOR a;
+    char *result;
+    
+    a = (SCSI_MEDIA_ITERATOR) m;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != scsi_mgr.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else {
+	switch (a->m.state) {
+	case kInit:
+	    /* find # of buses - done in AllocatePB() out of scsi_init() */
+	    a->m.state = kReset;
+	    /* fall through to reset */
+	case kReset:
+	    a->bus_index = 0 /* first bus id */;
+	    a->bus = scsi_mgr.bus_list[a->bus_index].bus;
+	    a->id = 0 /* first device id */;
+	    a->m.state = kIterating;
+	    clear_linux_cache();
+	    /* fall through to iterate */
+	case kIterating:
+	    while (1) {
+		if (a->bus_index >= scsi_mgr.bus_count /* max bus id */) {
+		    break;
+		}
+		if (a->id == scsi_mgr.bus_list[a->bus_index].master_id) {
+		    /* next id */
+		    a->id += 1;
+		}
+		if (a->id > scsi_mgr.bus_list[a->bus_index].max_id) {
+		    a->bus_index += 1;
+		    a->bus = scsi_mgr.bus_list[a->bus_index].bus;
+		    a->id = 0 /* first device id */;
+		    continue;   /* try again */
+		}
+		/* generate result */
+		result = (char *) malloc(20);
+		if (result != NULL) {
+		    if (a->bus == 0xFF) {
+			sprintf(result, "/dev/scsi%c", '0'+a->id);
+			probe_scsi_device(a->bus, a->id, 1);
+		    } else {
+			// insure bus number in range
+			if (a->bus > 9) {
+			    free(result);
+			    result = NULL;
+			    break;
+			}
+			sprintf(result, "/dev/scsi%c.%c", '0'+a->bus, '0'+a->id);
+			/* only probe out of iterate; so always added in order. */
+			probe_scsi_device(a->bus, a->id, 0);
+		    }
+		}
+
+		a->id += 1; /* next id */
+		return result;
+	    }
+	    a->m.state = kEnd;
+	    /* fall through to end */
+	case kEnd:
+	    mark_linux_cache_loaded();
+	default:
+	    break;
+	}
+    }
+    return 0 /* no entry */;
+}
+
+
+void
+delete_scsi_iterator(MEDIA_ITERATOR m)
+{
+    return;
+}
+
+
+#pragma mark -
+
+
+MEDIA
+open_linux_scsi_as_media(long index, int is_cdrom)
+{
+    MEDIA m;
+    long bus;
+    long id;
+    
+    if (lookup_scsi_index(index, is_cdrom, &bus, &id) > 0) {
+	m = open_scsi_as_media(bus, id);
+    } else {
+	m = 0;
+    }
+    
+    return m;
+}
+
+
+char *
+linux_old_scsi_name(long id)
+{
+    linux_scsi_name(kOriginalSCSIBusAdaptor, id);
+}
+
+
+char *
+linux_scsi_name(long bus, long id)
+{
+    char *result = 0;
+    long value;
+    int is_cdrom;
+    int unsure;
+    char *suffix;
+
+    /* name is sda, sdb, sdc, ...
+     * in order by buses and ids, but only count responding devices ...
+     */
+    if ((value = lookup_scsi_device(bus, id, &is_cdrom, &unsure)) >= 0) {
+	result = (char *) malloc(20);
+	if (result != NULL) {
+	    if (unsure) {
+		suffix = " ?";
+	    } else {
+		suffix = "";
+	    }
+	    if (is_cdrom) {
+		if (value > 9) {
+		    // too many CD's, give up
+		    free(result); result = NULL;
+		} else {
+		    sprintf(result, "/dev/scd%c%s", '0' + value, suffix);
+		}
+	    } else {
+		if (value < 26) {
+		    sprintf(result, "/dev/sd%c%s", 'a' + value, suffix);
+		} else {
+		    sprintf(result, "/dev/sd%c%c%s",
+			    'a' + value / 26, 'a' + value % 26, suffix);
+		}
+	    }
+	}
+    }
+    return result;
+}
+
+
+void
+probe_all(void)
+{
+    MEDIA_ITERATOR iter;
+    char *name;
+
+    iter = create_scsi_iterator();
+    if (iter == 0) {
+	return;
+    }
+
+    printf("finding devices ");
+    fflush(stdout);
+    while ((name = step_media_iterator(iter)) != 0) {
+    	/* step does the probe for us */
+	printf(".");
+	fflush(stdout);
+	free(name);
+    }
+    delete_media_iterator(iter);
+    printf("\n");
+    fflush(stdout);
+}
+
+
+void
+probe_scsi_device(long bus, long id, int unsure)
+{
+    UInt32 devType;
+    
+    if (DoInquiry(id, bus, &devType)) {
+    	if (devType == kScsiDevTypeDirect
+    		|| devType == kScsiDevTypeOptical) {
+    	    add_to_cache(bus, id, 0, unsure);
+    	} else if (devType == kScsiDevTypeCDROM
+		|| devType == kScsiDevTypeWorm) {
+    	    add_to_cache(bus, id, 1, unsure);
+    	}
+    }
+}
+
+
+long
+lookup_scsi_device(long bus, long id, int *is_cdrom, int *unsure)
+{
+    /* walk down list looking for bus and id ?
+     *
+     * only probe out of iterate (so always add in order)
+     * reset list if we reset the iterate
+     */
+    struct cache_item *item;
+    struct cache_item *next;
+    long result = -1;
+    int count = 0;
+    
+    if (scsi_inited == 0) {
+	scsi_init();
+    }
+
+    while (1) {
+    	count++;
+	for (item = linux_order.first; item != NULL; item = item->next) {
+	    if (item->bus == bus && item->id == id) {
+		result = item->value;
+		*is_cdrom = item->is_cdrom;
+		*unsure = item->unsure;
+		break;
+	    }
+	}
+	if (count < 2 && result < 0) {
+	    probe_all();
+	} else {
+	    break;
+	}
+    };
+
+    return result;
+}
+
+
+/*
+ * This has the same structure as lookup_scsi_device() except we are
+ * matching on the value & type rather than the bus & id.
+ */
+long
+lookup_scsi_index(long index, int is_cdrom, long *bus, long *id)
+{
+    struct cache_item *item;
+    struct cache_item *next;
+    long result = 0;
+    int count = 0;
+    
+    if (scsi_inited == 0) {
+	scsi_init();
+    }
+
+    while (1) {
+    	count++;
+	for (item = linux_order.first; item != NULL; item = item->next) {
+	    if (item->value == index && item->is_cdrom == is_cdrom
+		    && item->unsure == 0) {
+		result = 1;
+		*bus = item->bus;
+		*id = item->id;
+		break;
+	    }
+	}
+	if (count < 2 && result == 0 && !linux_cache_loaded()) {
+	    probe_all();
+	} else {
+	    break;
+	}
+    };
+
+    return result;
+}
+
+
+void
+add_to_cache(long bus, long id, int is_cdrom, int unsure)
+{
+    struct cache_item *item;
+    
+    item = malloc(sizeof(struct cache_item));
+    if (item == NULL) {
+	return;
+    } else {
+	item->bus = bus;
+	item->id = id;
+	item->is_cdrom = is_cdrom;
+	item->unsure = unsure;
+	if (is_cdrom) {
+	    item->value = linux_order.next_cdrom;
+	    linux_order.next_cdrom++;
+	} else {
+	    item->value = linux_order.next_disk;
+	    linux_order.next_disk++;
+	}
+	item->next = 0;
+    }
+    if (linux_order.first == NULL) {
+	linux_order.first = item;
+	linux_order.last = item;
+    } else {
+	linux_order.last->next = item;
+	linux_order.last = item;
+    }
+}
+
+
+void
+init_linux_cache(void)
+{
+    linux_order.first = NULL;
+    clear_linux_cache();
+}
+
+
+void
+clear_linux_cache(void)
+{
+    struct cache_item *item;
+    struct cache_item *next;
+    
+    for (item = linux_order.first; item != NULL; item = next) {
+	next = item->next;
+	free(item);
+    }
+    /* back to starting value */
+    linux_order.first = NULL;
+    linux_order.last = NULL;
+    linux_order.next_disk = 0;
+    linux_order.next_cdrom = 0;
+    linux_order.loaded = 0;
+}
+
+
+void
+mark_linux_cache_loaded(void)
+{
+    linux_order.loaded = 1;
+}
+
+
+int
+linux_cache_loaded(void)
+{
+    return linux_order.loaded;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/SCSI_media.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,65 @@
+/*
+ * SCSI_media.h -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __SCSI_media__
+#define __SCSI_media__
+
+#include "media.h"
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+
+
+/*
+ * Forward declarations
+ */
+MEDIA SCSI_FindDevice(long dRefNum);
+MEDIA open_old_scsi_as_media(long device);
+MEDIA open_scsi_as_media(long bus, long device);
+MEDIA_ITERATOR create_scsi_iterator(void);
+MEDIA open_linux_scsi_as_media(long index, int is_cdrom);
+char *linux_scsi_name(long bus, long id);
+char *linux_old_scsi_name(long id);
+
+#endif /* __SCSI_media__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/bitfield.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,101 @@
+//
+// bitfield.c - extract and set bit fields
+//
+// Written by Eryk Vershen
+//
+// See comments in bitfield.h
+//
+
+/*
+ * Copyright 1996, 1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include "bitfield.h"
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+const unsigned long masks[] = {
+    0x00000000,
+    0x00000001, 0x00000003, 0x00000007, 0x0000000F,
+    0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
+    0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
+    0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
+    0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
+    0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
+    0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
+    0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
+};
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+
+
+//
+// Routines
+//
+unsigned long
+bitfield_set(unsigned long *bf, int base, int length, unsigned long value)
+{
+    unsigned long t;
+    unsigned long m;
+    int s;
+
+    // compute shift & mask, coerce value to correct number of bits,
+    // zap the old bits and stuff the new value
+    // return the masked value in case someone wants it.
+    s = (base + 1) - length;
+    m = masks[length];
+    t = value & m;
+    *bf = (*bf & ~(m << s)) | (t << s);
+    return t;
+}
+
+
+unsigned long
+bitfield_get(unsigned long bf, int base, int length)
+{
+    unsigned long m;
+    int s;
+
+    // compute shift & mask
+    // return the correct number of bits (shifted to low end)
+    s = (base + 1) - length;
+    m = masks[length];
+    return ((bf >> s) & m);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/bitfield.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,72 @@
+//
+// bitfield.h - extract and set bit fields
+//
+// Written by Eryk Vershen
+//
+// Bitfields are not particularly transportable between big and little
+// endian machines.  Big endian machines lay out bitfields starting
+// from the most significant bit of the (one, two or four byte) number,
+// whereas little endian machines lay out bitfields starting from the
+// least signifcant bit.
+//
+// These routines were written to support some bitfields in a disk
+// data structure (partition map) whose original definition was on
+// a big-endian machine.
+//
+// They only work on 32-bit values because I didn't need 16-bit support.
+// The bits in the long word are numbered from 0 (least significant) to
+// 31 (most significant).
+//
+
+/*
+ * Copyright 1996,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __bitfield__
+#define __bitfield__
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+unsigned long bitfield_set(unsigned long *bf, int base, int length, unsigned long value);
+unsigned long bitfield_get(unsigned long bf, int base, int length);
+
+#endif /* __bitfield__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/convert.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,204 @@
+//
+// convert.c - Little-endian conversion
+//
+// Written by Eryk Vershen
+//
+// See comments in convert.h
+//
+
+/*
+ * Copyright 1996,1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifdef __linux__
+#include <endian.h>
+#else
+#define LITTLE_ENDIAN 1234
+#define BIG_ENDIAN 4321
+#define BYTE_ORDER 4321
+//#define BYTE_ORDER 1234
+#endif
+
+#include "convert.h"
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+void reverse2(u8 *bytes);
+void reverse4(u8 *bytes);
+
+
+//
+// Routines
+//
+int
+convert_dpme(DPME *data, int to_cpu_form)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+    // Since we will toss the block if the signature doesn't match
+    // we don't need to check the signature down here.
+    reverse2((u8 *)&data->dpme_signature);
+    reverse2((u8 *)&data->dpme_reserved_1);
+    reverse4((u8 *)&data->dpme_map_entries);
+    reverse4((u8 *)&data->dpme_pblock_start);
+    reverse4((u8 *)&data->dpme_pblocks);
+    reverse4((u8 *)&data->dpme_lblock_start);
+    reverse4((u8 *)&data->dpme_lblocks);
+    reverse4((u8 *)&data->dpme_flags);
+    reverse4((u8 *)&data->dpme_boot_block);
+    reverse4((u8 *)&data->dpme_boot_bytes);
+    reverse4((u8 *)&data->dpme_load_addr);
+    reverse4((u8 *)&data->dpme_load_addr_2);
+    reverse4((u8 *)&data->dpme_goto_addr);
+    reverse4((u8 *)&data->dpme_goto_addr_2);
+    reverse4((u8 *)&data->dpme_checksum);
+    convert_bzb((BZB *)data->dpme_bzb, to_cpu_form);
+#endif
+    return 0;
+}
+
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+int
+convert_bzb(BZB *data, int to_cpu_form)
+{
+    // Since the data here varies according to the type of partition we
+    // do not want to convert willy-nilly. We use the flag to determine
+    // whether to check for the signature before or after we flip the bytes.
+    if (to_cpu_form) {
+	reverse4((u8 *)&data->bzb_magic);
+	if (data->bzb_magic != BZBMAGIC) {
+	    reverse4((u8 *)&data->bzb_magic);
+	    if (data->bzb_magic != BZBMAGIC) {
+		return 0;
+	    }
+	}
+    } else {
+	if (data->bzb_magic != BZBMAGIC) {
+	    return 0;
+	}
+	reverse4((u8 *)&data->bzb_magic);
+    }
+    reverse2((u8 *)&data->bzb_inode);
+    reverse4((u8 *)&data->bzb_flags);
+    reverse4((u8 *)&data->bzb_tmade);
+    reverse4((u8 *)&data->bzb_tmount);
+    reverse4((u8 *)&data->bzb_tumount);
+    return 0;
+}
+#endif
+
+
+int
+convert_block0(Block0 *data, int to_cpu_form)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+    DDMap *m;
+    u16 count;
+    int i;
+
+    // Since this data is optional we do not want to convert willy-nilly.
+    // We use the flag to determine whether to check for the signature
+    // before or after we flip the bytes and to determine which form of
+    // the count to use.
+    if (to_cpu_form) {
+	reverse2((u8 *)&data->sbSig);
+	if (data->sbSig != BLOCK0_SIGNATURE) {
+	    reverse2((u8 *)&data->sbSig);
+	    if (data->sbSig != BLOCK0_SIGNATURE) {
+		return 0;
+	    }
+	}
+    } else {
+	if (data->sbSig != BLOCK0_SIGNATURE) {
+	    return 0;
+	}
+	reverse2((u8 *)&data->sbSig);
+    }
+    reverse2((u8 *)&data->sbBlkSize);
+    reverse4((u8 *)&data->sbBlkCount);
+    reverse2((u8 *)&data->sbDevType);
+    reverse2((u8 *)&data->sbDevId);
+    reverse4((u8 *)&data->sbData);
+    if (to_cpu_form) {
+	reverse2((u8 *)&data->sbDrvrCount);
+	count = data->sbDrvrCount;
+    } else {
+	count = data->sbDrvrCount;
+	reverse2((u8 *)&data->sbDrvrCount);
+    }
+
+    if (count > 0) {
+	m = (DDMap *) data->sbMap;
+	for (i = 0; i < count; i++) {
+	    reverse4((u8 *)&m[i].ddBlock);
+	    reverse2((u8 *)&m[i].ddSize);
+	    reverse2((u8 *)&m[i].ddType);
+	}
+    }
+#endif
+    return 0;
+}
+
+
+void
+reverse2(u8 *bytes)
+{
+    u8 t;
+
+    t = *bytes;
+    *bytes = bytes[1];
+    bytes[1] = t;
+}
+
+
+void
+reverse4(u8 *bytes)
+{
+    u8 t;
+
+    t = *bytes;
+    *bytes = bytes[3];
+    bytes[3] = t;
+    t = bytes[1];
+    bytes[1] = bytes[2];
+    bytes[2] = t;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/convert.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,65 @@
+//
+// convert.h - Little-endian conversion
+//
+// Written by Eryk Vershen
+//
+// The approach taken to conversion is fairly simply.
+// Keep the in-memory copy in the machine's normal form and
+// Convert as necessary when reading and writing.
+//
+
+/*
+ * Copyright 1996,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __convert__
+#define __convert__
+
+#include "dpme.h"
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+int convert_block0(Block0 *data, int to_cpu_form);
+int convert_bzb(BZB *data, int to_cpu_form);
+int convert_dpme(DPME *data, int to_cpu_form);
+
+#endif /* __convert__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/cvt_pt.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,208 @@
+/*
+ * cvt_pt.c
+ *
+ *	Covert partition type.	$Revision: 1.1.1.1 $
+ *
+ *	Copyright (c)  1999, Eryk Vershen
+ * 
+ * History:
+ * $Log: cvt_pt.c,v $
+ * Revision 1.1.1.1  2002/07/09 05:49:05  dbj
+ * import pdisk utility from Eryk Vershen:
+ *   http://cantaforda.com/cfcl/eryk/linux/pdisk/index.html
+ * this is the utility provided by mklinux and osX to manipulate
+ * the Apple Partition map.
+ *
+ * Revision 1.2  2000/05/16 13:56:11  eryk
+ * Minor fixes
+ *
+ * Revision 1.1  2000/02/13 22:04:08  eryk
+ * Initial revision
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "partition_map.h"
+#include "errors.h"
+
+
+/*
+ * Defines / Constants
+ */
+#define CFLAG_DEFAULT	0
+#define DFLAG_DEFAULT	0
+#define HFLAG_DEFAULT	0
+#define INTERACT_DEFAULT	0
+#define RFLAG_DEFAULT	0
+
+
+/*
+ * Structs / Types
+ */
+
+
+/*
+ * Global variables
+ */
+int hflag = HFLAG_DEFAULT;	/* show help */
+int dflag = DFLAG_DEFAULT;	/* turn on debugging commands and printout */
+int rflag = RFLAG_DEFAULT;	/* open device read Only */
+int interactive = INTERACT_DEFAULT;
+int cflag = CFLAG_DEFAULT;	/* compute device size */
+
+
+/*
+ * Forward declarations
+ */
+void process(char *filename);
+
+
+/*
+ * Start here ...
+ */
+int
+main(int argc, char **argv)
+{
+    register int i;
+#ifdef notdef
+    register int c;
+    extern char *optarg;	/* pointer to argument */
+    extern int optind;		/* next argv index */
+    extern int opterr;		/* who does error messages */
+    extern int optopt;		/* char that caused the error */
+    int getopt_error;		/* getopt choked */
+    char option_error[100];	/* buffer for error message */
+    char *arg_option = 0;
+    int bool_option = 0;
+#else
+    int optind = 1;
+#endif
+
+    init_program_name(argv);
+
+#ifdef notdef
+    opterr = 0;	/* tell getopt to be quiet */
+
+    /*
+     * Changes to getopt's last argument should
+     * be reflected in the string printed by the
+     * usage() function.
+     */
+    while ((c = getopt(argc, argv, "a:b")) != EOF) {
+	if (c == '?') {
+	    getopt_error = 1;
+	    c = optopt;
+	} else {
+	    getopt_error = 0;
+	}
+
+	switch (c) {
+	case 'a':
+	    if (getopt_error) {
+		usage("missing argument");
+	    } else {
+		arg_option = optarg;
+	    }
+	    break;
+	case 'b':
+	    bool_option = 1;
+	    break;
+	default:
+	    sprintf(option_error, "no such option as -%c", c);
+	    usage(option_error);
+	}
+    }
+#endif
+
+    if (optind >= argc) {
+	usage("no file argument");
+    }
+    for (i = optind ; i < argc; i++) {
+	process(argv[i]);
+    }
+    return 0;
+}
+
+
+int
+trim_num(char *s)
+{
+    char *t;
+    int n;
+
+    for (t = s; *t; t++) {
+    }
+
+    for (t--; t >= s; t--) {
+        if (!isdigit(*t)) {
+            t++;
+            if (*t) {
+                n = atoi(t);
+                *t = 0;
+            } else {
+                n = -1;
+            }
+            return n;
+        }
+    }
+
+    return -1;
+}
+
+/*
+ * The operation to apply to each file ...
+ */
+void
+process(char *filename)
+{
+    char *s;
+    int index;
+    partition_map_header *map;
+    int valid_file;
+    partition_map * entry;
+
+    //printf("Processing %s\n", filename);
+
+    // 1)       strip off number from end of filename
+    s = strdup(filename);
+    index = trim_num(s);
+
+    if (index < 0) {
+        fatal(-1, "%s does not end in a number", filename);
+    }
+
+    // 2)       open prefix of filename as partition map
+    map = open_partition_map(s, &valid_file, 0);
+    if (!valid_file) {
+        fatal(-1, "%s does not have a partition map", s);
+        return;
+    }
+
+    // 3)       verify the type for the partition;
+
+    if (map->writeable == 0) {
+	fatal(-1, "The map is not writeable");
+        return;
+    }
+
+    // 4) find partition and change it
+    entry = find_entry_by_disk_address(index, map);
+    if (entry == NULL) {
+	fatal(-1, "No such partition");
+    } else if (strcmp(entry->data->dpme_type, kHFSType) != 0) {
+	fatal(-1, "Can't convert a partition with type %s",
+		entry->data->dpme_type);
+    } else {
+	// 4a)       modify the type
+	strncpy(entry->data->dpme_type, kUnixType, DPISTRLEN);
+	
+	// 5)       and write back.
+	write_partition_map(map);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/deblock_media.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,334 @@
+/*
+ * deblock_media.c -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+// for malloc() & free()
+#include <stdlib.h>
+// for memcpy()
+#include <string.h>
+
+#include "deblock_media.h"
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+typedef struct deblock_media *DEBLOCK_MEDIA;
+
+struct deblock_media {
+    struct media    m;
+    long            need_filtering;
+    MEDIA           next_media;
+    unsigned long   next_block_size;
+    unsigned char   *buffer;
+};
+
+struct deblock_globals {
+    long        exists;
+    long        kind;
+};
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+static long deblock_inited = 0;
+static struct deblock_globals deblock_info;
+
+/*
+ * Forward declarations
+ */
+void deblock_init(void);
+DEBLOCK_MEDIA new_deblock_media(void);
+long read_deblock_media(MEDIA m, long long offset, unsigned long count, void *address);
+long write_deblock_media(MEDIA m, long long offset, unsigned long count, void *address);
+long close_deblock_media(MEDIA m);
+long os_reload_deblock_media(MEDIA m);
+
+
+/*
+ * Routines
+ */
+void
+deblock_init(void)
+{
+    if (deblock_inited != 0) {
+	return;
+    }
+    deblock_inited = 1;
+    
+    deblock_info.kind = allocate_media_kind();
+}
+
+
+DEBLOCK_MEDIA
+new_deblock_media(void)
+{
+    return (DEBLOCK_MEDIA) new_media(sizeof(struct deblock_media));
+}
+
+
+MEDIA
+open_deblock_media(long new_block_size, MEDIA m)
+{
+    DEBLOCK_MEDIA   a;
+    unsigned long   block_size;
+    
+    if (deblock_inited == 0) {
+	deblock_init();
+    }
+    
+    a = 0;
+    if (m != 0) {
+	block_size = media_granularity(m);
+
+	if (new_block_size == block_size) {
+	    return m;
+
+	} else if (new_block_size > block_size) {
+	    if ((new_block_size % block_size) == 0) {
+		/* no filtering necessary */
+		a = new_deblock_media();
+		if (a != 0) {
+		    a->need_filtering = 0;
+		    a->next_block_size = block_size;
+		    a->buffer = 0;
+		}
+	    } else {
+		/* too hard to bother with */
+	    }
+	} else /* new_block_size < block_size */ {
+	    if ((block_size % new_block_size) == 0) {
+		/* block & unblock */
+		a = new_deblock_media();
+		if (a != 0) {
+		    a->need_filtering = 1;
+		    a->next_block_size = block_size;
+		    a->buffer = malloc(block_size);
+		}
+	    } else {
+		/* too hard to bother with */
+	    }
+	}
+	if (a != 0) {
+	    a->m.kind = deblock_info.kind;
+	    a->m.grain = new_block_size;
+	    a->m.size_in_bytes = media_total_size(m);
+	    a->m.do_read = read_deblock_media;
+	    a->m.do_write = write_deblock_media;
+	    a->m.do_close = close_deblock_media;
+	    a->m.do_os_reload = os_reload_deblock_media;
+	    a->next_media = m;
+	}
+    }
+    return (MEDIA) a;
+}
+
+
+long
+read_deblock_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+    DEBLOCK_MEDIA a;
+    long rtn_value;
+    unsigned long next_size;
+    unsigned long partial_offset;
+    unsigned long partial_count;
+    long long cur_offset;
+    unsigned long remainder;
+    unsigned char *addr;
+
+    a = (DEBLOCK_MEDIA) m;
+    rtn_value = 0;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != deblock_info.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else if (count <= 0 || count % a->m.grain != 0) {
+	/* can't handle size */
+    } else if (offset < 0 || offset % a->m.grain != 0) {
+	/* can't handle offset */
+    } else if (a->need_filtering == 0) {
+	rtn_value = read_media(a->next_media, offset, count, address);
+    } else {
+	next_size = a->next_block_size;
+	addr = address;
+	cur_offset = offset;
+	remainder = count;
+	rtn_value = 1;
+
+	/* read partial */
+	partial_offset = cur_offset % next_size;
+	if (partial_offset != 0) {
+	    partial_count = next_size - partial_offset;
+	    if (partial_count > remainder) {
+		partial_count = remainder;
+	    }
+	    rtn_value = read_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
+	    if (rtn_value != 0) {
+		memcpy (addr, a->buffer + partial_offset, partial_count);
+		addr += partial_count;
+		cur_offset += partial_count;
+		remainder -= partial_count;
+	    }
+	}
+	/* read fulls as long as needed */
+	if (rtn_value != 0 && remainder > next_size) {
+	    partial_count = remainder - (remainder % next_size);
+	    rtn_value = read_media(a->next_media, cur_offset, partial_count, addr);
+	    addr += partial_count;
+	    cur_offset += partial_count;
+	    remainder -= partial_count;
+	}
+	/* read partial */
+	if (rtn_value != 0 && remainder > 0) {
+	    partial_count = remainder;
+	    rtn_value = read_media(a->next_media, cur_offset, next_size, a->buffer);
+	    if (rtn_value != 0) {
+		memcpy (addr, a->buffer, partial_count);
+	    }
+	}
+    }
+    return rtn_value;
+}
+
+
+long
+write_deblock_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+    DEBLOCK_MEDIA a;
+    long rtn_value;
+    unsigned long next_size;
+    unsigned long partial_offset;
+    unsigned long partial_count;
+    long long cur_offset;
+    unsigned long remainder;
+    unsigned char *addr;
+    
+    a = (DEBLOCK_MEDIA) m;
+    rtn_value = 0;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != deblock_info.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else if (count <= 0 || count % a->m.grain != 0) {
+	/* can't handle size */
+    } else if (offset < 0 || offset % a->m.grain != 0) {
+	/* can't handle offset */
+    } else if (a->need_filtering == 0) {
+	rtn_value = write_media(a->next_media, offset, count, address);
+    } else {
+	next_size = a->next_block_size;
+	addr = address;
+	cur_offset = offset;
+	remainder = count;
+	rtn_value = 1;
+
+	/* write partial */
+	partial_offset = cur_offset % next_size;
+	if (partial_offset != 0) {
+	    partial_count = next_size - partial_offset;
+	    if (partial_count > remainder) {
+		partial_count = remainder;
+	    }
+	    rtn_value = read_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
+	    if (rtn_value != 0) {
+		memcpy (a->buffer + partial_offset, addr, partial_count);
+		rtn_value = write_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
+		addr += partial_count;
+		cur_offset += partial_count;
+		remainder -= partial_count;
+	    }
+	}
+	/* write fulls as long as needed */
+	if (rtn_value != 0 && remainder > next_size) {
+	    partial_count = remainder - (remainder % next_size);
+	    rtn_value = write_media(a->next_media, cur_offset, partial_count, addr);
+	    addr += partial_count;
+	    cur_offset += partial_count;
+	    remainder -= partial_count;
+	}
+	/* write partial */
+	if (rtn_value != 0 && remainder > 0) {
+	    partial_count = remainder;
+	    rtn_value = read_media(a->next_media, cur_offset, next_size, a->buffer);
+	    if (rtn_value != 0) {
+		memcpy (a->buffer, addr, partial_count);
+		rtn_value = write_media(a->next_media, cur_offset, next_size, a->buffer);
+	    }
+	}
+    }
+    /* recompute size to handle file media */
+    a->m.size_in_bytes = media_total_size(a->next_media);
+    return rtn_value;
+}
+
+
+long
+close_deblock_media(MEDIA m)
+{
+    DEBLOCK_MEDIA a;
+    
+    a = (DEBLOCK_MEDIA) m;
+    if (a == 0) {
+	return 0;
+    } else if (a->m.kind != deblock_info.kind) {
+	/* XXX need to error here - this is an internal problem */
+	return 0;
+    }
+    
+    close_media(a->next_media);
+    free(a->buffer);
+    return 1;
+}
+
+
+long
+os_reload_deblock_media(MEDIA m)
+{
+    DEBLOCK_MEDIA a;
+    
+    a = (DEBLOCK_MEDIA) m;
+    if (a == 0) {
+	return 0;
+    } else if (a->m.kind != deblock_info.kind) {
+	/* XXX need to error here - this is an internal problem */
+	return 0;
+    }
+    
+    os_reload_media(a->next_media);
+    return 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/deblock_media.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,59 @@
+/*
+ * deblock_media.h -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __deblock_media__
+#define __deblock_media__
+
+#include "media.h"
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+
+
+/*
+ * Forward declarations
+ */
+MEDIA open_deblock_media(long new_block_size, MEDIA m);
+
+#endif /* __deblock_media__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/dpme.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,219 @@
+//
+// dpme.h - Disk Partition Map Entry (dpme)
+//
+// Written by Eryk Vershen
+//
+// This file describes structures and values related to the standard
+// Apple SCSI disk partitioning scheme.
+//
+// Each entry is (and shall remain) 512 bytes long.
+//
+// For more information see:
+//	"Inside Macintosh: Devices" pages 3-12 to 3-15.
+//	"Inside Macintosh - Volume V" pages V-576 to V-582
+//	"Inside Macintosh - Volume IV" page IV-292
+//
+// There is a kernel file with much of the same info (under different names):
+//	/usr/src/mklinux-1.0DR2/osfmk/src/mach_kernel/ppc/POWERMAC/mac_label.h
+//
+
+/*
+ * Copyright 1996 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+#ifndef __dpme__
+#define __dpme__
+
+#include "bitfield.h"
+
+//
+// Defines
+//
+#define	BLOCK0_SIGNATURE	0x4552	/* i.e. 'ER' */
+
+#define	DPISTRLEN	32
+#define	DPME_SIGNATURE	0x504D		/* i.e. 'PM' */
+
+// A/UX only stuff (tradition!)
+#define	dpme_bzb	dpme_boot_args
+#define	BZBMAGIC 0xABADBABE	/* BZB magic number */
+#define	FST	((u8) 0x1)	/* standard UNIX FS */
+#define	FSTEFS	((u8) 0x2)	/* Autorecovery FS */
+#define	FSTSFS	((u8) 0x3)	/* Swap FS */
+
+
+//
+// Types
+//
+typedef	unsigned char	u8;
+typedef	unsigned short	u16;
+typedef	unsigned long	u32;
+
+
+// Physical block zero of the disk has this format
+struct Block0 {
+    u16 	sbSig;		/* unique value for SCSI block 0 */
+    u16 	sbBlkSize;	/* block size of device */
+    u32 	sbBlkCount;	/* number of blocks on device */
+    u16 	sbDevType;	/* device type */
+    u16 	sbDevId;	/* device id */
+    u32 	sbData;		/* not used */
+    u16 	sbDrvrCount;	/* driver descriptor count */
+    u16 	sbMap[247];	/* descriptor map */
+};
+typedef struct Block0 Block0;
+
+// Where &sbMap[0] is actually an array DDMap[sbDrvrCount]
+// kludge to get around alignment junk
+struct DDMap {
+    u32 	ddBlock;	/* 1st driver's starting block (in sbBlkSize blocks!) */
+    u16 	ddSize;		/* size of 1st driver (512-byte blks) */
+    u16 	ddType;		/* system type (1 for Mac+) */
+};
+typedef struct DDMap DDMap;
+
+
+// Each partition map entry (blocks 1 through n) has this format
+struct dpme {
+    u16     dpme_signature          ;
+    u16     dpme_reserved_1         ;
+    u32     dpme_map_entries        ;
+    u32     dpme_pblock_start       ;
+    u32     dpme_pblocks            ;
+    char    dpme_name[DPISTRLEN]    ;  /* name of partition */
+    char    dpme_type[DPISTRLEN]    ;  /* type of partition */
+    u32     dpme_lblock_start       ;
+    u32     dpme_lblocks            ;
+    u32     dpme_flags;
+#if 0
+    u32     dpme_reserved_2    : 23 ;  /* Bit 9 through 31.        */
+    u32     dpme_os_specific_1 :  1 ;  /* Bit 8.                   */
+    u32     dpme_os_specific_2 :  1 ;  /* Bit 7.                   */
+    u32     dpme_os_pic_code   :  1 ;  /* Bit 6.                   */
+    u32     dpme_writable      :  1 ;  /* Bit 5.                   */
+    u32     dpme_readable      :  1 ;  /* Bit 4.                   */
+    u32     dpme_bootable      :  1 ;  /* Bit 3.                   */
+    u32     dpme_in_use        :  1 ;  /* Bit 2.                   */
+    u32     dpme_allocated     :  1 ;  /* Bit 1.                   */
+    u32     dpme_valid         :  1 ;  /* Bit 0.                   */
+#endif
+    u32     dpme_boot_block         ;
+    u32     dpme_boot_bytes         ;
+    u8     *dpme_load_addr          ;
+    u8     *dpme_load_addr_2        ;
+    u8     *dpme_goto_addr          ;
+    u8     *dpme_goto_addr_2        ;
+    u32     dpme_checksum           ;
+    char    dpme_process_id[16]     ;
+    u32     dpme_boot_args[32]      ;
+    u32     dpme_reserved_3[62]     ;
+};
+typedef struct dpme DPME;
+
+#define	dpme_diskdriver_set(p, v)	bitfield_set(&p->dpme_flags, 9, 1, v)
+#define	dpme_chainable_set(p, v)	bitfield_set(&p->dpme_flags, 8, 1, v)
+
+#define	dpme_os_specific_1_set(p, v)	bitfield_set(&p->dpme_flags, 8, 1, v)
+#define	dpme_os_specific_2_set(p, v)	bitfield_set(&p->dpme_flags, 7, 1, v)
+#define	dpme_os_pic_code_set(p, v)	bitfield_set(&p->dpme_flags, 6, 1, v)
+#define	dpme_writable_set(p, v)		bitfield_set(&p->dpme_flags, 5, 1, v)
+#define	dpme_readable_set(p, v)		bitfield_set(&p->dpme_flags, 4, 1, v)
+#define	dpme_bootable_set(p, v)		bitfield_set(&p->dpme_flags, 3, 1, v)
+#define	dpme_in_use_set(p, v)		bitfield_set(&p->dpme_flags, 2, 1, v)
+#define	dpme_allocated_set(p, v)	bitfield_set(&p->dpme_flags, 1, 1, v)
+#define	dpme_valid_set(p, v)		bitfield_set(&p->dpme_flags, 0, 1, v)
+
+#define	dpme_diskdriver_get(p)		bitfield_get(p->dpme_flags, 9, 1)
+#define	dpme_chainable_get(p)		bitfield_get(p->dpme_flags, 8, 1)
+
+#define	dpme_os_specific_1_get(p)	bitfield_get(p->dpme_flags, 8, 1)
+#define	dpme_os_specific_2_get(p)	bitfield_get(p->dpme_flags, 7, 1)
+#define	dpme_os_pic_code_get(p)		bitfield_get(p->dpme_flags, 6, 1)
+#define	dpme_writable_get(p)		bitfield_get(p->dpme_flags, 5, 1)
+#define	dpme_readable_get(p)		bitfield_get(p->dpme_flags, 4, 1)
+#define	dpme_bootable_get(p)		bitfield_get(p->dpme_flags, 3, 1)
+#define	dpme_in_use_get(p)		bitfield_get(p->dpme_flags, 2, 1)
+#define	dpme_allocated_get(p)		bitfield_get(p->dpme_flags, 1, 1)
+#define	dpme_valid_get(p)		bitfield_get(p->dpme_flags, 0, 1)
+
+
+// A/UX only data structures (sentimental reasons?)
+
+// Alternate block map (aka bad block remaping) [Never really used]
+struct abm		/* altblk map info stored in bzb */
+{
+    u32  abm_size;	/* size of map in bytes */
+    u32  abm_ents;	/* number of used entries */
+    u32  abm_start;	/* start of altblk map */
+};
+typedef	struct abm ABM;
+
+// BZB (Block Zero Block, but I can't remember the etymology)
+// Where &dpme_boot_args[0] is actually the address of a struct bzb
+// kludge to get around alignment junk
+struct	bzb			/* block zero block format */
+{
+    u32  bzb_magic;		/* magic number */
+    u8   bzb_cluster;		/* Autorecovery cluster grouping */
+    u8   bzb_type;		/* FS type */
+    u16  bzb_inode;		/* bad block inode number */
+    u32  bzb_flags;
+#if 0
+    u16  bzb_root:1,		/* FS is a root FS */
+	 bzb_usr:1,		/* FS is a usr FS */
+	 bzb_crit:1,		/* FS is a critical FS */
+	 bzb_rsrvd:8,		/* reserved for later use */
+	 bzb_slice:5;		/* slice number to associate with plus one */
+    u16  bzb_filler;		/* pad bitfield to 32 bits */
+#endif
+    u32  bzb_tmade;		/* time of FS creation */
+    u32  bzb_tmount;		/* time of last mount */
+    u32  bzb_tumount;		/* time of last umount */
+    ABM  bzb_abm;		/* altblk map info */
+    u32  bzb_fill2[7];		/* for expansion of ABM (ha!ha!) */
+    u8   bzb_mount_point[64];	/* default mount point name */
+};
+typedef	struct bzb	BZB;
+
+#define	bzb_root_set(p, v)		bitfield_set(&p->bzb_flags, 31, 1, v)
+#define	bzb_usr_set(p, v)		bitfield_set(&p->bzb_flags, 30, 1, v)
+#define	bzb_crit_set(p, v)		bitfield_set(&p->bzb_flags, 29, 1, v)
+#define	bzb_slice_set(p, v)		bitfield_set(&p->bzb_flags, 20, 5, v)
+
+#define	bzb_root_get(p)			bitfield_get(p->bzb_flags, 31, 1)
+#define	bzb_usr_get(p)			bitfield_get(p->bzb_flags, 30, 1)
+#define	bzb_crit_get(p)			bitfield_get(p->bzb_flags, 29, 1)
+#define	bzb_slice_get(p)		bitfield_get(p->bzb_flags, 20, 5)
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+
+#endif /* __dpme__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/dump.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,917 @@
+//
+// dump.c - dumping partition maps
+//
+// Written by Eryk Vershen
+//
+
+/*
+ * Copyright 1996,1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+// for *printf()
+#include <stdio.h>
+
+// for malloc() & free()
+#ifndef __linux__
+#include <stdlib.h>
+//#include <unistd.h>
+#else
+#include <malloc.h>
+#endif
+
+// for strcmp()
+#include <string.h>
+// for O_RDONLY
+#include <fcntl.h>
+// for errno
+#include <errno.h>
+
+#include "dump.h"
+#include "pathname.h"
+#include "io.h"
+#include "errors.h"
+
+
+//
+// Defines
+//
+#if DPISTRLEN != 32
+#error Change in strlen in partition entries! Fix constants
+#endif
+
+#define get_align_long(x)	(*(x))
+
+
+//
+// Types
+//
+typedef struct names {
+    char *abbr;
+    char *full;
+} NAMES;
+
+#ifdef __unix__
+typedef unsigned long OSType;
+#endif
+
+typedef struct PatchDescriptor {
+    OSType		patchSig;
+    unsigned short	majorVers;
+    unsigned short	minorVers;
+    unsigned long	flags;
+    unsigned long	patchOffset;
+    unsigned long	patchSize;
+    unsigned long	patchCRC;
+    unsigned long	patchDescriptorLen;
+    unsigned char	patchName[33];
+    unsigned char	patchVendor[1];
+} PatchDescriptor;
+typedef PatchDescriptor * PatchDescriptorPtr;
+
+typedef struct PatchList {
+    unsigned short numPatchBlocks;	// number of disk blocks to hold the patch list
+    unsigned short numPatches;		// number of patches in list
+    PatchDescriptor thePatch[1];
+} PatchList;
+typedef PatchList *PatchListPtr;
+
+
+//
+// Global Constants
+//
+NAMES plist[] = {
+    {"Drvr", "Apple_Driver"},
+    {"Drv4", "Apple_Driver43"},
+    {"Free", "Apple_Free"},
+    {"Patc", "Apple_Patches"},
+    {" HFS", "Apple_HFS"},
+    {" MFS", "Apple_MFS"},
+    {"PDOS", "Apple_PRODOS"},
+    {"junk", "Apple_Scratch"},
+    {"unix", "Apple_UNIX_SVR2"},
+    {" map", "Apple_partition_map"},
+    {0,	0},
+};
+
+const char * kStringEmpty	= "";
+const char * kStringNot		= " not";
+
+
+//
+// Global Variables
+//
+int aflag = AFLAG_DEFAULT;	/* abbreviate partition types */
+int pflag = PFLAG_DEFAULT;	/* show physical limits of partition */
+int fflag = FFLAG_DEFAULT;	/* show HFS volume names */
+
+
+//
+// Forward declarations
+//
+void adjust_value_and_compute_prefix(double *value, int *prefix);
+void dump_block_zero(partition_map_header *map);
+void dump_partition_entry(partition_map *entry, int type_length, int name_length, int digits);
+int get_max_base_or_length(partition_map_header *map);
+int get_max_name_string_length(partition_map_header *map);
+int get_max_type_string_length(partition_map_header *map);
+int strnlen(char *s, int n);
+
+
+//
+// Routines
+//
+int
+dump(char *name)
+{
+    partition_map_header *map;
+    int junk;
+
+    map = open_partition_map(name, &junk, 0);
+    if (map == NULL) {
+	//error(-1, "No partition map in '%s'", name);
+	return 0;
+    }
+
+    dump_partition_map(map, 1);
+
+    close_partition_map(map);
+    
+    return 1;
+}
+
+
+void
+dump_block_zero(partition_map_header *map)
+{
+    Block0 *p;
+    DDMap *m;
+    int i;
+    double value;
+    int prefix;
+    long t;
+
+    p = map->misc;
+    if (p->sbSig != BLOCK0_SIGNATURE) {
+	return;
+    }
+
+    value = ((double)p->sbBlkCount) * p->sbBlkSize;
+    adjust_value_and_compute_prefix(&value, &prefix);
+    printf("\nDevice block size=%u, Number of Blocks=%lu (%1.1f%c)\n",
+	    p->sbBlkSize, p->sbBlkCount, value, prefix);
+
+    printf("DeviceType=0x%x, DeviceId=0x%x\n",
+	    p->sbDevType, p->sbDevId);
+    if (p->sbDrvrCount > 0) {
+	printf("Drivers-\n");
+	m = (DDMap *) p->sbMap;
+	for (i = 0; i < p->sbDrvrCount; i++) {
+	    printf("%u: %3u @ %lu, ", i+1,
+		    m[i].ddSize, get_align_long(&m[i].ddBlock));
+	    if (map->logical_block != p->sbBlkSize) {
+		t = (m[i].ddSize * p->sbBlkSize) / map->logical_block;
+		printf("(%lu@", t);
+		t = (get_align_long(&m[i].ddBlock) * p->sbBlkSize)
+			/ map->logical_block;
+		printf("%lu)  ", t);
+	    }
+	    printf("type=0x%x\n", m[i].ddType);
+	}
+    }
+    printf("\n");
+}
+
+
+void
+dump_partition_map(partition_map_header *map, int disk_order)
+{
+    partition_map * entry;
+    int max_type_length;
+    int max_name_length;
+    int digits;
+    char *alternate;
+
+    if (map == NULL) {
+	bad_input("No partition map exists");
+	return;
+    }
+    alternate = get_linux_name(map->name);
+    if (alternate) {
+	printf("\nPartition map (with %d byte blocks) on '%s' (%s)\n",
+		map->logical_block, map->name, alternate);
+	free(alternate);
+    } else {
+	printf("\nPartition map (with %d byte blocks) on '%s'\n",
+		map->logical_block, map->name);
+    }
+
+    digits = number_of_digits(get_max_base_or_length(map));
+    if (digits < 6) {
+	digits = 6;
+    }
+    if (aflag) {
+	max_type_length = 4;
+    } else {
+	max_type_length = get_max_type_string_length(map);
+	if (max_type_length < 4) {
+	    max_type_length = 4;
+	}
+    }
+    max_name_length = get_max_name_string_length(map);
+    if (max_name_length < 6) {
+	max_name_length = 6;
+    }
+    printf(" #: %*s %-*s %*s   %-*s ( size )\n",
+	    max_type_length, "type",
+	    max_name_length, "name",
+	    digits, "length", digits, "base");
+
+    if (disk_order) {
+	for (entry = map->disk_order; entry != NULL;
+		entry = entry->next_on_disk) {
+
+	    dump_partition_entry(entry, max_type_length, max_name_length, digits);
+	}
+    } else {
+	for (entry = map->base_order; entry != NULL;
+		entry = entry->next_by_base) {
+
+	    dump_partition_entry(entry, max_type_length, max_name_length, digits);
+	}
+    }
+    dump_block_zero(map);
+}
+
+
+void
+dump_partition_entry(partition_map *entry, int type_length, int name_length, int digits)
+{
+    partition_map_header *map;
+    int j;
+    DPME *p;
+    char *s;
+    u32 size;
+    double bytes;
+    int driver;
+    // int kind;
+    char *buf;
+
+    map = entry->the_map;
+    p = entry->data;
+    driver = entry->contains_driver? '*': ' ';
+    if (aflag) {
+	s = "????";
+	for (j = 0; plist[j].abbr != 0; j++) {
+	    if (strcmp(p->dpme_type, plist[j].full) == 0) {
+		s = plist[j].abbr;
+		break;
+	    }
+	}
+	printf("%2ld: %.4s", entry->disk_address, s);
+    } else {
+	printf("%2ld: %*.32s", entry->disk_address, type_length, p->dpme_type);
+    }
+
+    buf = (char *) malloc(name_length+1);
+    if (entry->HFS_name == NULL || fflag == 0) {
+	strncpy(buf, p->dpme_name, name_length);
+	buf[name_length] = 0;
+    } else {
+	sprintf(buf, "\"%s\"", entry->HFS_name);
+    }
+    printf("%c%-*.32s ", driver, name_length, buf);
+    free(buf);
+    /*
+    switch (entry->HFS_kind) {
+    case kHFS_std:	kind = 'h'; break;
+    case kHFS_embed:	kind = 'e'; break;
+    case kHFS_plus:	kind = '+'; break;
+    default:
+    case kHFS_not:	kind = ' '; break;
+    }
+    printf("%c ", kind);
+    */
+
+    if (pflag) {
+	printf("%*lu ", digits, p->dpme_pblocks);
+	size = p->dpme_pblocks;
+    } else if (p->dpme_lblocks + p->dpme_lblock_start != p->dpme_pblocks) {
+	printf("%*lu+", digits, p->dpme_lblocks);
+	size = p->dpme_lblocks;
+    } else if (p->dpme_lblock_start != 0) {
+	printf("%*lu ", digits, p->dpme_lblocks);
+	size = p->dpme_lblocks;
+    } else {
+	printf("%*lu ", digits, p->dpme_pblocks);
+	size = p->dpme_pblocks;
+    }
+    if (pflag || p->dpme_lblock_start == 0) {
+	printf("@ %-*lu", digits, p->dpme_pblock_start);
+    } else {
+	printf("@~%-*lu", digits, p->dpme_pblock_start + p->dpme_lblock_start);
+    }
+    
+    bytes = ((double)size) * map->logical_block;
+    adjust_value_and_compute_prefix(&bytes, &j);
+    if (j != ' ' && j != 'K') {
+	printf(" (%#5.1f%c)", bytes, j);
+    }
+
+#if 0
+    // Old A/UX fields that no one pays attention to anymore.
+    bp = (BZB *) (p->dpme_bzb);
+    j = -1;
+    if (bp->bzb_magic == BZBMAGIC) {
+	switch (bp->bzb_type) {
+	case FSTEFS:
+	    s = "EFS";
+	    break;
+	case FSTSFS:
+	    s = "SFS";
+	    j = 1;
+	    break;
+	case FST:
+	default:
+	    if (bzb_root_get(bp) != 0) {
+		if (bzb_usr_get(bp) != 0) {
+		    s = "RUFS";
+		} else {
+		    s = "RFS";
+		}
+		j = 0;
+	    } else if (bzb_usr_get(bp) != 0) {
+		s = "UFS";
+		j = 2;
+	    } else {
+		s = "FS";
+	    }
+	    break;
+	}
+	if (bzb_slice_get(bp) != 0) {
+	    printf(" s%1d %4s", bzb_slice_get(bp)-1, s);
+	} else if (j >= 0) {
+	    printf(" S%1d %4s", j, s);
+	} else {
+	    printf("    %4s", s);
+	}
+	if (bzb_crit_get(bp) != 0) {
+	    printf(" K%1d", bp->bzb_cluster);
+	} else if (j < 0) {
+	    printf("   ");
+	} else {
+	    printf(" k%1d", bp->bzb_cluster);
+	}
+	if (bp->bzb_mount_point[0] != 0) {
+	    printf("  %.64s", bp->bzb_mount_point);
+	}
+    }
+#endif
+    printf("\n");
+}
+
+
+void
+list_all_disks()
+{
+    MEDIA_ITERATOR iter;
+    MEDIA m;
+    DPME * data;
+    char *name;
+    long mark;
+
+    data = (DPME *) malloc(PBLOCK_SIZE);
+    if (data == NULL) {
+	error(errno, "can't allocate memory for try buffer");
+	return;
+    }
+    
+    for (iter = first_media_kind(&mark); iter != 0; iter = next_media_kind(&mark)) {
+
+    	while ((name = step_media_iterator(iter)) != 0) {
+
+	    if ((m = open_pathname_as_media(name, O_RDONLY)) == 0) {
+#if defined(__linux__) || defined(__unix__)
+		error(errno, "can't open file '%s'", name);
+#endif
+	    } else {
+		close_media(m);
+
+		dump(name);
+	    }
+	    free(name);
+	}
+
+	delete_media_iterator(iter);
+    }
+
+    free(data);
+}
+
+
+void
+show_data_structures(partition_map_header *map)
+{
+    Block0 *zp;
+    DDMap *m;
+    int i;
+    int j;
+    partition_map * entry;
+    DPME *p;
+    BZB *bp;
+    char *s;
+
+    if (map == NULL) {
+	printf("No partition map exists\n");
+	return;
+    }
+    printf("Header:\n");
+    printf("map %d blocks out of %d,  media %lu blocks (%d byte blocks)\n",
+	    map->blocks_in_map, map->maximum_in_map,
+	    map->media_size, map->logical_block);
+    printf("Map is%s writeable", (map->writeable)?kStringEmpty:kStringNot);
+    printf(", but%s changed", (map->changed)?kStringEmpty:kStringNot);
+    printf(" and has%s been written\n", (map->written)?kStringEmpty:kStringNot);
+    printf("\n");
+
+    if (map->misc == NULL) {
+	printf("No block zero\n");
+    } else {
+	zp = map->misc;
+
+	printf("Block0:\n");
+	printf("signature 0x%x", zp->sbSig);
+	if (zp->sbSig == BLOCK0_SIGNATURE) {
+	    printf("\n");
+	} else {
+	    printf(" should be 0x%x\n", BLOCK0_SIGNATURE);
+	}
+	printf("Block size=%u, Number of Blocks=%lu\n",
+		zp->sbBlkSize, zp->sbBlkCount);
+	printf("DeviceType=0x%x, DeviceId=0x%x, sbData=0x%lx\n",
+		zp->sbDevType, zp->sbDevId, zp->sbData);
+	if (zp->sbDrvrCount == 0) {
+	    printf("No drivers\n");
+	} else {
+	    printf("%u driver%s-\n", zp->sbDrvrCount,
+		    (zp->sbDrvrCount>1)?"s":kStringEmpty);
+	    m = (DDMap *) zp->sbMap;
+	    for (i = 0; i < zp->sbDrvrCount; i++) {
+            printf("%u: @ %lu for %u, type=0x%x\n", i+1, 
+		   get_align_long(&m[i].ddBlock),
+		   m[i].ddSize, m[i].ddType);
+	    }
+	}
+    }
+    printf("\n");
+
+/*
+u32     dpme_boot_args[32]      ;
+u32     dpme_reserved_3[62]     ;
+*/
+    printf(" #:                 type  length   base    "
+	    "flags        (logical)\n");
+    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
+	p = entry->data;
+	printf("%2ld: %20.32s ",
+		entry->disk_address, p->dpme_type);
+	printf("%7lu @ %-7lu ", p->dpme_pblocks, p->dpme_pblock_start);
+	printf("%c%c%c%c%c%c%c%c%c%c%c%c ",
+		(dpme_valid_get(p))?'V':'.',
+		(dpme_allocated_get(p))?'A':'.',
+		(dpme_in_use_get(p))?'I':'.',
+		(dpme_bootable_get(p))?'B':'.',
+		(dpme_readable_get(p))?'R':'.',
+		(dpme_writable_get(p))?'W':'.',
+		(dpme_os_pic_code_get(p))?'P':'.',
+		(dpme_os_specific_2_get(p))?'2':'.',
+		(dpme_chainable_get(p))?'C':'.',
+		(dpme_diskdriver_get(p))?'D':'.',
+		(bitfield_get(p->dpme_flags, 30, 1))?'M':'.',
+		(bitfield_get(p->dpme_flags, 31, 1))?'X':'.');
+	if (p->dpme_lblock_start != 0 || p->dpme_pblocks != p->dpme_lblocks) {
+	    printf("(%lu @ %lu)", p->dpme_lblocks, p->dpme_lblock_start);
+	}
+	printf("\n");
+    }
+    printf("\n");
+    printf(" #:  booter   bytes      load_address      "
+	    "goto_address checksum processor\n");
+    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
+	p = entry->data;
+	printf("%2ld: ", entry->disk_address);
+	printf("%7lu ", p->dpme_boot_block);
+	printf("%7lu ", p->dpme_boot_bytes);
+	printf("%8lx ", (u32)p->dpme_load_addr);
+	printf("%8lx ", (u32)p->dpme_load_addr_2);
+	printf("%8lx ", (u32)p->dpme_goto_addr);
+	printf("%8lx ", (u32)p->dpme_goto_addr_2);
+	printf("%8lx ", p->dpme_checksum);
+	printf("%.32s", p->dpme_process_id);
+	printf("\n");
+    }
+    printf("\n");
+/*
+xx: cccc RU *dd s...
+*/
+    printf(" #: type RU *slice mount_point (A/UX only fields)\n");
+    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
+	p = entry->data;
+	printf("%2ld: ", entry->disk_address);
+
+	bp = (BZB *) (p->dpme_bzb);
+	j = -1;
+	if (bp->bzb_magic == BZBMAGIC) {
+	    switch (bp->bzb_type) {
+	    case FSTEFS:
+		s = "esch";
+		break;
+	    case FSTSFS:
+		s = "swap";
+		j = 1;
+		break;
+	    case FST:
+	    default:
+		s = "fsys";
+		if (bzb_root_get(bp) != 0) {
+		    j = 0;
+		} else if (bzb_usr_get(bp) != 0) {
+		    j = 2;
+		}
+		break;
+	    }
+	    printf("%4s ", s);
+	    printf("%c%c ",
+		    (bzb_root_get(bp))?'R':' ',
+		    (bzb_usr_get(bp))?'U':' ');
+	    if (bzb_slice_get(bp) != 0) {
+		printf("  %2ld", bzb_slice_get(bp)-1);
+	    } else if (j >= 0) {
+		printf(" *%2d", j);
+	    } else {
+		printf("    ");
+	    }
+	    if (bp->bzb_mount_point[0] != 0) {
+		printf(" %.64s", bp->bzb_mount_point);
+	    }
+	}
+	printf("\n");
+    }
+}
+
+
+void
+full_dump_partition_entry(partition_map_header *map, int index)
+{
+    partition_map * cur;
+    DPME *p;
+    int i;
+    u32 t;
+
+    cur = find_entry_by_disk_address(index, map);
+    if (cur == NULL) {
+	printf("No such partition\n");
+	return;
+    }
+    
+    p = cur->data;
+    printf("             signature: 0x%x\n", p->dpme_signature);
+    printf("             reserved1: 0x%x\n", p->dpme_reserved_1);
+    printf(" number of map entries: %ld\n", p->dpme_map_entries);
+    printf("        physical start: %10lu  length: %10lu\n", p->dpme_pblock_start, p->dpme_pblocks);
+    printf("         logical start: %10lu  length: %10lu\n", p->dpme_lblock_start, p->dpme_lblocks);
+
+    printf("                 flags: 0x%lx\n", (u32)p->dpme_flags);
+    printf("                        ");
+    if (dpme_valid_get(p)) printf("valid ");
+    if (dpme_allocated_get(p)) printf("alloc ");
+    if (dpme_in_use_get(p)) printf("in-use ");
+    if (dpme_bootable_get(p)) printf("boot ");
+    if (dpme_readable_get(p)) printf("read ");
+    if (dpme_writable_get(p)) printf("write ");
+    if (dpme_os_pic_code_get(p)) printf("pic ");
+    t = p->dpme_flags >> 7;
+    for (i = 7; i <= 31; i++) {
+    	if (t & 0x1) {
+    	    printf("%d ", i);
+    	}
+    	t = t >> 1;
+    }
+    printf("\n");
+
+    printf("                  name: '%.32s'\n", p->dpme_name);
+    printf("                  type: '%.32s'\n", p->dpme_type);
+
+    printf("      boot start block: %10lu\n", p->dpme_boot_block);
+    printf("boot length (in bytes): %10lu\n", p->dpme_boot_bytes);
+    printf("          load address: 0x%08lx  0x%08lx\n",
+		(u32)p->dpme_load_addr, (u32)p->dpme_load_addr_2);
+    printf("         start address: 0x%08lx  0x%08lx\n", 
+		(u32)p->dpme_goto_addr, (u32)p->dpme_goto_addr_2);
+    printf("              checksum: 0x%08lx\n", p->dpme_checksum);
+    printf("             processor: '%.32s'\n", p->dpme_process_id);
+    printf("boot args field -");
+    dump_block((unsigned char *)p->dpme_boot_args, 32*4);
+    printf("dpme_reserved_3 -");
+    dump_block((unsigned char *)p->dpme_reserved_3, 62*4);
+}
+
+
+void
+dump_block(unsigned char *addr, int len)
+{
+    int i;
+    int j;
+    int limit1;
+    int limit;
+#define LINE_LEN 16
+#define UNIT_LEN  4
+#define OTHER_LEN  8
+
+    for (i = 0; i < len; i = limit) {
+    	limit1 = i + LINE_LEN;
+    	if (limit1 > len) {
+    	    limit = len;
+    	} else {
+    	    limit = limit1;
+    	}
+	printf("\n%03x: ", i);
+    	for (j = i; j < limit1; j++) {
+	    if (j % UNIT_LEN == 0) {
+		printf(" ");
+	    }
+	    if (j < limit) {
+		printf("%02x", addr[j]);
+	    } else {
+		printf("  ");
+	    }
+    	}
+	printf(" ");
+    	for (j = i; j < limit; j++) {
+	    if (j % OTHER_LEN == 0) {
+		printf(" ");
+	    }
+    	    if (addr[j] < ' ') {
+    	    	printf(".");
+    	    } else {
+    	    	printf("%c", addr[j]);
+    	    }
+    	}
+    }
+    printf("\n");
+}
+
+void
+full_dump_block_zero(partition_map_header *map)
+{
+    Block0 *zp;
+    DDMap *m;
+    int i;
+
+    if (map == NULL) {
+	printf("No partition map exists\n");
+	return;
+    }
+
+    if (map->misc == NULL) {
+	printf("No block zero\n");
+	return;
+    }
+    zp = map->misc;
+
+    printf("             signature: 0x%x\n", zp->sbSig);
+    printf("       size of a block: %d\n", zp->sbBlkSize);
+    printf("      number of blocks: %ld\n", zp->sbBlkCount);
+    printf("           device type: 0x%x\n", zp->sbDevType);
+    printf("             device id: 0x%x\n", zp->sbDevId);
+    printf("                  data: 0x%lx\n", zp->sbData);
+    printf("          driver count: %d\n", zp->sbDrvrCount);
+    m = (DDMap *) zp->sbMap;
+    for (i = 0; &m[i].ddType < &zp->sbMap[247]; i++) {
+    	if (m[i].ddBlock == 0 && m[i].ddSize == 0 && m[i].ddType == 0) {
+    	    break;
+    	}
+	printf("      driver %3u block: %ld\n", i+1, m[i].ddBlock);
+	printf("        size in blocks: %d\n", m[i].ddSize);
+	printf("           driver type: 0x%x\n", m[i].ddType);
+    }
+    printf("remainder of block -");
+    dump_block((unsigned char *)&m[i].ddBlock, (&zp->sbMap[247]-((unsigned short *)&m[i].ddBlock))*2);
+}
+
+
+void
+display_patches(partition_map *entry)
+{
+    long long offset;
+    MEDIA m;
+    static unsigned char *patch_block;
+    PatchListPtr p;
+    PatchDescriptorPtr q;
+    unsigned char *next;
+    unsigned char *s;
+    int i;
+    
+    offset = entry->data->dpme_pblock_start;
+    m = entry->the_map->m;
+    offset = ((long long) entry->data->dpme_pblock_start) * entry->the_map->logical_block;
+    if (patch_block == NULL) {
+	patch_block = (unsigned char *) malloc(PBLOCK_SIZE);
+	if (patch_block == NULL) {
+	    error(errno, "can't allocate memory for patch block buffer");
+	    return;
+	}
+    }
+    if (read_media(m, (long long)offset, PBLOCK_SIZE, (char *)patch_block) == 0) {
+	error(errno, "Can't read patch block");
+	return;
+    }
+    p = (PatchListPtr) patch_block;
+    if (p->numPatchBlocks != 1) {
+	i = p->numPatchBlocks;
+	free(patch_block);
+	patch_block = (unsigned char *) malloc(PBLOCK_SIZE*i);
+	if (patch_block == NULL) {
+	    error(errno, "can't allocate memory for patch blocks buffer");
+	    return;
+	}
+	s = patch_block + PBLOCK_SIZE*i;
+	while (i > 0) {
+	    s -= PBLOCK_SIZE;
+	    i -= 1;
+	    if (read_media(m, offset+i, PBLOCK_SIZE, (char *)s) == 0) {
+		error(errno, "Can't read patch block %d", i);
+		return;
+	    }
+	}
+	p = (PatchListPtr) patch_block;
+    }
+    printf("Patch list (%d entries)\n", p->numPatches);
+    q = p->thePatch;
+    for (i = 0; i < p->numPatches; i++) {
+	printf("%2d signature: '%.4s'\n", i+1, (char *)&q->patchSig);
+	printf("     version: %d.%d\n", q->majorVers, q->minorVers);
+	printf("       flags: 0x%lx\n", q->flags);
+	printf("      offset: %ld\n", q->patchOffset);
+	printf("        size: %ld\n", q->patchSize);
+	printf("         CRC: 0x%lx\n", q->patchCRC);
+	printf("        name: '%.*s'\n", q->patchName[0], &q->patchName[1]);
+	printf("      vendor: '%.*s'\n", q->patchVendor[0], &q->patchVendor[1]);
+	next = ((unsigned char *)q) + q->patchDescriptorLen;
+	s = &q->patchVendor[q->patchVendor[0]+1];
+	if (next > s) {
+	    printf("remainder of entry -");
+	    dump_block(s, next-s);
+	}
+	q = (PatchDescriptorPtr)next;
+    }
+}
+
+int
+strnlen(char *s, int n)
+{
+    int i;
+
+    for (i = 0; i < n; i++) {
+	if (*s == 0) {
+	    break;
+	}
+	s++;
+    }
+    return i;
+}
+
+int
+get_max_type_string_length(partition_map_header *map)
+{
+    partition_map * entry;
+    int max;
+    int length;
+
+    if (map == NULL) {
+	return 0;
+    }
+
+    max = 0;
+
+    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
+	length = strnlen(entry->data->dpme_type, DPISTRLEN);
+	if (length > max) {
+	    max = length;
+	}
+    }
+
+    return max;
+}
+
+int
+get_max_name_string_length(partition_map_header *map)
+{
+    partition_map * entry;
+    int max;
+    int length;
+
+    if (map == NULL) {
+	return 0;
+    }
+
+    max = 0;
+
+    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
+	length = strnlen(entry->data->dpme_name, DPISTRLEN);
+	if (length > max) {
+	    max = length;
+	}
+
+	if (fflag) {
+		if (entry->HFS_name == NULL) {
+		    length = 0;
+		} else {
+		    length = strlen(entry->HFS_name) + 2;
+		}
+		if (length > max) {
+		    max = length;
+		}
+	}
+    }
+
+    return max;
+}
+
+int
+get_max_base_or_length(partition_map_header *map)
+{
+    partition_map * entry;
+    int max;
+
+    if (map == NULL) {
+	return 0;
+    }
+
+    max = 0;
+
+    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
+	if (entry->data->dpme_pblock_start > max) {
+	    max = entry->data->dpme_pblock_start;
+	}
+	if (entry->data->dpme_pblocks > max) {
+	    max = entry->data->dpme_pblocks;
+	}
+	if (entry->data->dpme_lblock_start > max) {
+	    max = entry->data->dpme_lblock_start;
+	}
+	if (entry->data->dpme_lblocks > max) {
+	    max = entry->data->dpme_lblocks;
+	}
+    }
+
+    return max;
+}
+
+void
+adjust_value_and_compute_prefix(double *value, int *prefix)
+{
+    double bytes;
+    int multiplier;
+
+    bytes = *value;
+    if (bytes < 1024.0) {
+	multiplier = ' ';
+    } else {
+	bytes = bytes / 1024.0;
+	if (bytes < 1024.0) {
+	    multiplier = 'K';
+	} else {
+	    bytes = bytes / 1024.0;
+	    if (bytes < 1024.0) {
+		multiplier = 'M';
+	    } else {
+		bytes = bytes / 1024.0;
+		if (bytes < 1024.0) {
+		    multiplier = 'G';
+		} else {
+		    bytes = bytes / 1024.0;
+		    multiplier = 'T';
+		}
+	    }
+	}
+    }
+    *value = bytes;
+    *prefix = multiplier;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/dump.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,72 @@
+//
+// dump.h - dumping partition maps
+//
+// Written by Eryk Vershen
+//
+
+/*
+ * Copyright 1996,1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __dump__
+#define __dump__
+
+#include "partition_map.h"
+
+
+//
+// Defines
+//
+#define AFLAG_DEFAULT	0
+#define PFLAG_DEFAULT	1
+#define FFLAG_DEFAULT	1
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+extern int aflag;
+extern int pflag;
+extern int fflag;
+
+
+//
+// Forward declarations
+//
+void display_patches(partition_map *entry);
+int dump(char *name);
+void dump_block(unsigned char *addr, int len);
+void dump_partition_map(partition_map_header *map, int disk_order);
+void full_dump_partition_entry(partition_map_header *map, int index);
+void full_dump_block_zero(partition_map_header *map);
+void list_all_disks();
+void show_data_structures(partition_map_header *map);
+
+#endif /* __dump__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/errors.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,173 @@
+//
+// errors.c - error & help routines
+//
+// Written by Eryk Vershen
+//
+
+/*
+ * Copyright 1996,1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+// for *printf()
+#include <stdio.h>
+
+// for exit()
+#ifndef __linux__
+#include <stdlib.h>
+#endif
+// for strrchr
+#include <string.h>
+
+// for va_start(), etc.
+#include <stdarg.h>
+
+#include "errors.h"
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+char *program_name;
+#ifdef NeXT
+extern int errno;
+extern int sys_nerr;
+extern const char * const sys_errlist[];
+#endif
+
+
+//
+// Forward declarations
+//
+
+
+//
+// Routines
+//
+void
+init_program_name(char **argv)
+{
+#if defined(__linux__) || defined(__unix__)
+    if ((program_name = strrchr(argv[0], '/')) != (char *)NULL) {
+	program_name++;
+    } else {
+	program_name = argv[0];
+    }
+#else
+    program_name = "pdisk";
+#endif
+}
+
+
+void
+do_help()
+{
+    printf("\t%s [-h|--help]\n", program_name);
+    printf("\t%s [-v|--version]\n", program_name);
+    printf("\t%s [-l|--list [name ...]]\n", program_name);
+    printf("\t%s [-r|--readonly] name ...\n", program_name);
+    printf("\t%s [-i|--interactive]\n", program_name);
+    printf("\t%s name ...\n", program_name);
+/*
+	{"debug",	no_argument,		0,	'd'},
+	{"abbr",	no_argument,		0,	'a'},
+	{"fs",		no_argument,		0,	'f'},
+	{"logical",	no_argument,		0,	kLogicalOption},
+	{"compute_size", no_argument,		0,	'c'},
+*/
+}
+
+
+void
+usage(char *kind)
+{
+    error(-1, "bad usage - %s\n", kind);
+    hflag = 1;
+}
+
+
+//
+// Print a message on standard error and exit with value.
+// Values in the range of system error numbers will add
+// the perror(3) message.
+//
+void
+fatal(int value, char *fmt, ...)
+{
+    va_list ap;
+
+    fprintf(stderr, "%s: ", program_name);
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+
+#if defined(__linux__) || defined(NeXT) || defined(__unix__)
+    if (value > 0 && value < sys_nerr) {
+	fprintf(stderr, "  (%s)\n", sys_errlist[value]);
+    } else {
+	fprintf(stderr, "\n");
+    }
+#else
+    fprintf(stderr, "\n");
+    printf("Processing stopped: Choose 'Quit' from the file menu to quit.\n\n");
+#endif
+    exit(value);
+}
+
+
+//
+// Print a message on standard error.
+// Values in the range of system error numbers will add
+// the perror(3) message.
+//
+void
+error(int value, char *fmt, ...)
+{
+    va_list ap;
+
+    fprintf(stderr, "%s: ", program_name);
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+
+#if defined(__linux__) || defined(NeXT) || defined(__unix__)
+    if (value > 0 && value < sys_nerr) {
+	fprintf(stderr, "  (%s)\n", sys_errlist[value]);
+    } else {
+	fprintf(stderr, "\n");
+    }
+#else
+    fprintf(stderr, "\n");
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/errors.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,62 @@
+//
+// errors.h - error & help routines
+//
+// Written by Eryk Vershen
+//
+
+/*
+ * Copyright 1996 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __errors__
+#define __errors__
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+extern int hflag;
+
+
+//
+// Forward declarations
+//
+void do_help();
+void init_program_name(char **argv);
+void error(int value, char *fmt, ...);
+void fatal(int value, char *fmt, ...);
+void usage(char *kind);
+
+#endif /* __errors__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/file_media.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,574 @@
+/*
+ * file_media.c -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+// for printf()
+#include <stdio.h>
+// for malloc() & free()
+#include <stdlib.h>
+// for lseek(), read(), write(), close()
+#include <unistd.h>
+// for open()
+#include <fcntl.h>
+// for LONG_MAX
+#include <limits.h>
+// for errno
+#include <errno.h>
+
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <sys/stat.h>
+#else
+#ifdef __unix__
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#endif
+#endif
+
+#include "file_media.h"
+#include "errors.h"
+
+
+/*
+ * Defines
+ */
+#ifdef __linux__
+#define LOFF_MAX 9223372036854775807LL
+extern __loff_t llseek __P ((int __fd, __loff_t __offset, int __whence));
+#else
+#define loff_t long
+#define llseek lseek
+#define LOFF_MAX LONG_MAX
+#endif
+
+
+/*
+ * Types
+ */
+typedef struct file_media *FILE_MEDIA;
+
+struct file_media {
+    struct media	m;
+    int			fd;
+    int			regular_file;
+};
+
+struct file_media_globals {
+    long		exists;
+    long		kind;
+};
+
+typedef struct file_media_iterator *FILE_MEDIA_ITERATOR;
+
+struct file_media_iterator {
+    struct media_iterator   m;
+    long		    style;
+    long		    index;
+};
+
+
+/*
+ * Global Constants
+ */
+int potential_block_sizes[] = {
+    1, 512, 1024, 2048,
+    0
+};
+
+enum {
+    kSCSI_Disks = 0,
+    kATA_Devices = 1,
+    kSCSI_CDs = 2,
+    kMaxStyle = 2
+};
+
+
+/*
+ * Global Variables
+ */
+static long file_inited = 0;
+static struct file_media_globals file_info;
+
+/*
+ * Forward declarations
+ */
+int compute_block_size(int fd);
+void file_init(void);
+FILE_MEDIA new_file_media(void);
+long read_file_media(MEDIA m, long long offset, unsigned long count, void *address);
+long write_file_media(MEDIA m, long long offset, unsigned long count, void *address);
+long close_file_media(MEDIA m);
+long os_reload_file_media(MEDIA m);
+FILE_MEDIA_ITERATOR new_file_iterator(void);
+void reset_file_iterator(MEDIA_ITERATOR m);
+char *step_file_iterator(MEDIA_ITERATOR m);
+void delete_file_iterator(MEDIA_ITERATOR m);
+
+
+/*
+ * Routines
+ */
+void
+file_init(void)
+{
+    if (file_inited != 0) {
+	return;
+    }
+    file_inited = 1;
+    
+    file_info.kind = allocate_media_kind();
+}
+
+
+FILE_MEDIA
+new_file_media(void)
+{
+    return (FILE_MEDIA) new_media(sizeof(struct file_media));
+}
+
+
+int
+compute_block_size(int fd)
+{
+    int size;
+    int max_size;
+    loff_t x;
+    long t;
+    int i;
+    char *buffer;
+    
+    max_size = 0;
+    for (i = 0; ; i++) {
+    	size = potential_block_sizes[i];
+    	if (size == 0) {
+	    break;
+    	}
+    	if (max_size < size) {
+	    max_size = size;
+    	}
+    }
+    
+    buffer = malloc(max_size);
+    if (buffer != 0) {
+	for (i = 0; ; i++) {
+	    size = potential_block_sizes[i];
+	    if (size == 0) {
+		break;
+	    }
+	    if ((x = llseek(fd, (loff_t)0, 0)) < 0) {
+		error(errno, "Can't seek on file");
+		break;
+	    }
+	    if ((t = read(fd, buffer, size)) == size) {
+		free(buffer);
+		return size;
+	    }
+	}
+    }
+    return 0;
+}
+
+
+MEDIA
+open_file_as_media(char *file, int oflag)
+{
+    FILE_MEDIA	a;
+    int			fd;
+    loff_t off;
+#if defined(__linux__) || defined(__unix__)
+    struct stat info;
+#endif
+	
+    if (file_inited == 0) {
+	    file_init();
+    }
+    
+    a = 0;
+    fd = open(file, oflag);
+    if (fd >= 0) {
+	a = new_file_media();
+	if (a != 0) {
+	    a->m.kind = file_info.kind;
+	    a->m.grain = compute_block_size(fd);
+	    off = llseek(fd, (loff_t)0, 2);	/* seek to end of media */
+#if !defined(__linux__) && !defined(__unix__)
+	    if (off <= 0) {
+		off = 1; /* XXX not right? */
+	    }
+#endif
+	    //printf("file size = %Ld\n", off);
+	    a->m.size_in_bytes = (long long) off;
+	    a->m.do_read = read_file_media;
+	    a->m.do_write = write_file_media;
+	    a->m.do_close = close_file_media;
+	    a->m.do_os_reload = os_reload_file_media;
+	    a->fd = fd;
+	    a->regular_file = 0;
+#if defined(__linux__) || defined(__unix__)
+	    if (fstat(fd, &info) < 0) {
+		error(errno, "can't stat file '%s'", file);
+	    } else {
+		a->regular_file = S_ISREG(info.st_mode);
+	    }
+#endif
+	} else {
+	    close(fd);
+	}
+    }
+    return (MEDIA) a;
+}
+
+
+long
+read_file_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+    FILE_MEDIA a;
+    long rtn_value;
+    loff_t off;
+    int t;
+
+    a = (FILE_MEDIA) m;
+    rtn_value = 0;
+    if (a == 0) {
+	/* no media */
+	//printf("no media\n");
+    } else if (a->m.kind != file_info.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+	//printf("wrong kind\n");
+    } else if (count <= 0 || count % a->m.grain != 0) {
+	/* can't handle size */
+	//printf("bad size\n");
+    } else if (offset < 0 || offset % a->m.grain != 0) {
+	/* can't handle offset */
+	//printf("bad offset\n");
+    } else if (offset + count > a->m.size_in_bytes && a->m.size_in_bytes != (long long) 0) {
+	/* check for offset (and offset+count) too large */
+	//printf("offset+count too large\n");
+    } else if (offset + count > (long long) LOFF_MAX) {
+	/* check for offset (and offset+count) too large */
+	//printf("offset+count too large 2\n");
+    } else {
+	/* do the read */
+	off = offset;
+	if ((off = llseek(a->fd, off, 0)) >= 0) {
+	    if ((t = read(a->fd, address, count)) == count) {
+		rtn_value = 1;
+	    } else {
+		//printf("read failed\n");
+	    }
+	} else {
+	    //printf("lseek failed\n");
+	}
+    }
+    return rtn_value;
+}
+
+
+long
+write_file_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+    FILE_MEDIA a;
+    long rtn_value;
+    loff_t off;
+    int t;
+	
+    a = (FILE_MEDIA) m;
+    rtn_value = 0;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != file_info.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else if (count <= 0 || count % a->m.grain != 0) {
+	/* can't handle size */
+    } else if (offset < 0 || offset % a->m.grain != 0) {
+	/* can't handle offset */
+    } else if (offset + count > (long long) LOFF_MAX) {
+	/* check for offset (and offset+count) too large */
+    } else {
+	/* do the write  */
+	off = offset;
+	if ((off = llseek(a->fd, off, 0)) >= 0) {
+	    if ((t = write(a->fd, address, count)) == count) {
+		if (off + count > a->m.size_in_bytes) {
+			a->m.size_in_bytes = off + count;
+		}
+		rtn_value = 1;
+	    }
+	}
+    }
+    return rtn_value;
+}
+
+
+long
+close_file_media(MEDIA m)
+{
+    FILE_MEDIA a;
+    
+    a = (FILE_MEDIA) m;
+    if (a == 0) {
+	return 0;
+    } else if (a->m.kind != file_info.kind) {
+	/* XXX need to error here - this is an internal problem */
+	return 0;
+    }
+    
+    close(a->fd);
+    return 1;
+}
+
+
+long
+os_reload_file_media(MEDIA m)
+{
+    FILE_MEDIA a;
+    long rtn_value;
+#if defined(__linux__)
+    int i;
+    int saved_errno;
+#endif
+	
+    a = (FILE_MEDIA) m;
+    rtn_value = 0;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != file_info.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else if (a->regular_file) {
+	/* okay - nothing to do */
+	rtn_value = 1;
+    } else {
+#ifdef __linux__
+	sync();
+	sleep(2);
+	if ((i = ioctl(a->fd, BLKRRPART)) != 0) {
+	    saved_errno = errno;
+	} else {
+	    // some kernel versions (1.2.x) seem to have trouble
+	    // rereading the partition table, but if asked to do it
+	    // twice, the second time works. - biro@yggdrasil.com */
+	    sync();
+	    sleep(2);
+	    if ((i = ioctl(a->fd, BLKRRPART)) != 0) {
+		saved_errno = errno;
+	    }
+	}
+
+	// printf("Syncing disks.\n");
+	sync();
+	sleep(4);		/* for sync() */
+
+	if (i < 0) {
+	    error(saved_errno, "Re-read of partition table failed");
+	    printf("Reboot your system to ensure the "
+		    "partition table is updated.\n");
+	}
+#endif
+	rtn_value = 1;
+    }
+    return rtn_value;
+}
+
+
+#if !defined(__linux__) && !defined(__unix__)
+#pragma mark -
+#endif
+
+
+FILE_MEDIA_ITERATOR
+new_file_iterator(void)
+{
+    return (FILE_MEDIA_ITERATOR) new_media_iterator(sizeof(struct file_media_iterator));
+}
+
+
+MEDIA_ITERATOR
+create_file_iterator(void)
+{
+    FILE_MEDIA_ITERATOR a;
+    
+    if (file_inited == 0) {
+	file_init();
+    }
+    
+    a = new_file_iterator();
+    if (a != 0) {
+	a->m.kind = file_info.kind;
+	a->m.state = kInit;
+	a->m.do_reset = reset_file_iterator;
+	a->m.do_step = step_file_iterator;
+	a->m.do_delete = delete_file_iterator;
+	a->style = 0;
+	a->index = 0;
+    }
+
+    return (MEDIA_ITERATOR) a;
+}
+
+
+void
+reset_file_iterator(MEDIA_ITERATOR m)
+{
+    FILE_MEDIA_ITERATOR a;
+    
+    a = (FILE_MEDIA_ITERATOR) m;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != file_info.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else if (a->m.state != kInit) {
+	a->m.state = kReset;
+    }
+}
+
+
+char *
+step_file_iterator(MEDIA_ITERATOR m)
+{
+    FILE_MEDIA_ITERATOR a;
+    char *result;
+    struct stat info;
+    int	fd;
+    int bump;
+    int value;
+    
+    a = (FILE_MEDIA_ITERATOR) m;
+    if (a == 0) {
+	/* no media */
+    } else if (a->m.kind != file_info.kind) {
+	/* wrong kind - XXX need to error here - this is an internal problem */
+    } else {
+	switch (a->m.state) {
+	case kInit:
+	    a->m.state = kReset;
+	    /* fall through to reset */
+	case kReset:
+	    a->style = 0 /* first style */;
+	    a->index = 0 /* first index */;
+	    a->m.state = kIterating;
+	    /* fall through to iterate */
+	case kIterating:
+	    while (1) {
+		if (a->style > kMaxStyle) {
+		    break;
+		}
+#ifndef notdef
+		/* if old version of mklinux then skip CD drive */
+		if (a->style == kSCSI_Disks && a->index == 3) {
+		    a->index += 1;
+		}
+#endif
+		/* generate result */
+		result = (char *) malloc(20);
+		if (result != NULL) {
+		    /*
+		     * for DR3 we should actually iterate through:
+		     *
+		     *    /dev/sd[a...]    # first missing is end of list
+		     *    /dev/hd[a...]    # may be holes in sequence
+		     *    /dev/scd[0...]   # first missing is end of list
+		     *
+		     * and stop in each group when either a stat of
+		     * the name fails or if an open fails for
+		     * particular reasons.
+		     */
+		    bump = 0;
+		    value = (int) a->index;
+		    switch (a->style) {
+		    case kSCSI_Disks:
+			if (value < 26) {
+			    sprintf(result, "/dev/sd%c", 'a'+value);
+			} else if (value < 676) {
+			    sprintf(result, "/dev/sd%c%c",
+				    'a' + value / 26,
+				    'a' + value % 26);
+			} else {
+			    bump = -1;
+			}
+			break;
+		    case kATA_Devices:
+			if (value < 26) {
+			    sprintf(result, "/dev/hd%c", 'a'+value);
+			} else {
+			    bump = -1;
+			}
+			break;
+		    case kSCSI_CDs:
+			if (value < 10) {
+			    sprintf(result, "/dev/scd%c", '0'+value);
+			} else {
+			    bump = -1;
+			}
+			break;
+		    }
+		    if (bump != 0) {
+			// already set don't even check
+		    } else if (stat(result, &info) < 0) {
+			bump = 1;
+		    } else if ((fd = open(result, O_RDONLY)) >= 0) {
+			close(fd);
+#if defined(__linux__) || defined(__unix__)
+		    } else if (errno == ENXIO || errno == ENODEV) {
+			if (a->style == kATA_Devices) {
+			    bump = -1;
+			} else {
+			    bump = 1;
+			}
+#endif
+		    }
+		    if (bump) {
+			if (bump > 0) {
+			    a->style += 1; /* next style */
+			    a->index = 0; /* first index again */
+			} else {
+			    a->index += 1; /* next index */
+			}
+			free(result);
+			continue;
+		    }
+		}
+
+		a->index += 1; /* next index */
+		return result;
+	    }
+	    a->m.state = kEnd;
+	    /* fall through to end */
+	case kEnd:
+	default:
+	    break;
+	}
+    }
+    return 0 /* no entry */;
+}
+
+
+void
+delete_file_iterator(MEDIA_ITERATOR m)
+{
+    return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/file_media.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,60 @@
+/*
+ * file_media.h -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __file_media__
+#define __file_media__
+
+#include "media.h"
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+
+
+/*
+ * Forward declarations
+ */
+MEDIA open_file_as_media(char *file, int oflag);
+MEDIA_ITERATOR create_file_iterator(void);
+
+#endif /* __file_media__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/hfs_misc.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,253 @@
+//
+// hfs_misc.c - hfs routines
+//
+// Written by Eryk Vershen
+//
+
+/*
+ * Copyright 2000 by Eryk Vershen
+ */
+
+// for *printf()
+#include <stdio.h>
+
+// for malloc(), calloc() & free()
+#ifndef __linux__
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+
+// for strncpy() & strcmp()
+#include <string.h>
+// for O_RDONLY & O_RDWR
+#include <fcntl.h>
+// for errno
+#include <errno.h>
+
+#include "hfs_misc.h"
+#include "partition_map.h"
+#include "convert.h"
+#include "errors.h"
+
+
+//
+// Defines
+//
+#define MDB_OFFSET	2
+#define HFS_SIG		0x4244	/* i.e 'BD' */
+#define HFS_PLUS_SIG	0x482B	/* i.e 'H+' */
+
+#define get_align_long(x)	(*(u32*)(x))
+
+
+//
+// Types
+//
+typedef long long u64;
+
+typedef struct ExtDescriptor {		// extent descriptor
+    u16	xdrStABN;	// first allocation block
+    u16	xdrNumABlks;	// number of allocation blocks
+} ext_descriptor;
+
+typedef struct ExtDataRec {
+    ext_descriptor	ed[3];	// extent data record
+} ext_data_rec;
+
+/*
+ * The crazy "u16 x[2]" stuff here is to get around the fact
+ * that I can't convince the Mac compiler to align on 32 bit
+ * quantities on 16 bit boundaries...
+ */
+struct mdb_record {		// master directory block
+    u16	drSigWord;	// volume signature
+    u16	drCrDate[2];	// date and time of volume creation
+    u16	drLsMod[2];	// date and time of last modification
+    u16	drAtrb;		// volume attributes
+    u16	drNmFls;	// number of files in root directory
+    u16	drVBMSt;	// first block of volume bitmap
+    u16	drAllocPtr;	// start of next allocation search
+    u16	drNmAlBlks;	// number of allocation blocks in volume
+    u32	drAlBlkSiz;	// size (in bytes) of allocation blocks
+    u32	drClpSiz;	// default clump size
+    u16	drAlBlSt;	// first allocation block in volume
+    u16	drNxtCNID[2];	// next unused catalog node ID
+    u16	drFreeBks;	// number of unused allocation blocks
+    char	drVN[28];	// volume name
+    u16	drVolBkUp[2];	// date and time of last backup
+    u16	drVSeqNum;	// volume backup sequence number
+    u16	drWrCnt[2];	// volume write count
+    u16	drXTClpSiz[2];	// clump size for extents overflow file
+    u16	drCTClpSiz[2];	// clump size for catalog file
+    u16	drNmRtDirs;	// number of directories in root directory
+    u32	drFilCnt;	// number of files in volume
+    u32	drDirCnt;	// number of directories in volume
+    u32	drFndrInfo[8];	// information used by the Finder
+#ifdef notdef
+    u16	drVCSize;	// size (in blocks) of volume cache
+    u16	drVBMCSize;	// size (in blocks) of volume bitmap cache
+    u16	drCtlCSize;	// size (in blocks) of common volume cache
+#else
+    u16	drEmbedSigWord;	// type of embedded volume
+    ext_descriptor	drEmbedExtent;	// embedded volume extent
+#endif
+    u16	drXTFlSize[2];	// size of extents overflow file
+    ext_data_rec	drXTExtRec;	// extent record for extents overflow file
+    u16	drCTFlSize[2];	// size of catalog file
+    ext_data_rec	drCTExtRec;	// extent record for catalog file
+};
+
+
+typedef u32 HFSCatalogNodeID;
+
+typedef struct HFSPlusExtentDescriptor {
+    u32 startBlock;
+    u32 blockCount;
+} HFSPlusExtentDescriptor;
+
+typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[ 8];
+
+typedef struct HFSPlusForkData {
+    u64 logicalSize;
+    u32 clumpSize;
+    u32 totalBlocks;
+    HFSPlusExtentRecord extents;
+} HFSPlusForkData;
+
+struct HFSPlusVolumeHeader {
+    u16 signature;
+    u16 version;
+    u32 attributes;
+    u32 lastMountedVersion;
+    u32 reserved;
+    u32 createDate;
+    u32 modifyDate;
+    u32 backupDate;
+    u32 checkedDate;
+    u32 fileCount;
+    u32 folderCount;
+    u32 blockSize;
+    u32 totalBlocks;
+    u32 freeBlocks;
+    u32 nextAllocation;
+    u32 rsrcClumpSize;
+    u32 dataClumpSize;
+    HFSCatalogNodeID nextCatalogID;
+    u32 writeCount;
+    u64 encodingsBitmap;
+    u8 finderInfo[ 32];
+    HFSPlusForkData allocationFile;
+    HFSPlusForkData extentsFile;
+    HFSPlusForkData catalogFile;
+    HFSPlusForkData attributesFile;
+    HFSPlusForkData startupFile;
+} HFSPlusVolumeHeader;
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+u32 embeded_offset(struct mdb_record *mdb, u32 sector);
+int read_partition_block(partition_map *entry, unsigned long num, char *buf);
+
+
+//
+// Routines
+//
+u32
+embeded_offset(struct mdb_record *mdb, u32 sector)
+{
+    u32 e_offset;
+    
+    e_offset = mdb->drAlBlSt + mdb->drEmbedExtent.xdrStABN * (mdb->drAlBlkSiz / 512);
+    
+    return e_offset + sector;
+}
+
+
+char *
+get_HFS_name(partition_map *entry, int *kind)
+{
+    DPME *data;
+    struct mdb_record *mdb;
+    //struct HFSPlusVolumeHeader *mdb2;
+    char *name = NULL;
+    int len;
+    
+    *kind = kHFS_not;
+
+    mdb = (struct mdb_record *) malloc(PBLOCK_SIZE);
+    if (mdb == NULL) {
+	error(errno, "can't allocate memory for MDB");
+	return NULL;
+    }
+
+    data = entry->data;
+    if (strcmp(data->dpme_type, kHFSType) == 0) {
+	if (read_partition_block(entry, 2, (char *)mdb) == 0) {
+	    //error(-1, "Can't read block %d from partition %d", 2, entry->disk_address);
+	    goto not_hfs;
+	}
+	if (mdb->drSigWord == HFS_PLUS_SIG) {
+	    // pure HFS Plus
+	    // printf("%d HFS Plus\n", entry->disk_address);
+	    *kind = kHFS_plus;
+	} else if (mdb->drSigWord != HFS_SIG) {
+	    // not HFS !!!
+	    // printf("%d not HFS\n", entry->disk_address);
+	    *kind = kHFS_not;
+	} else if (mdb->drEmbedSigWord != HFS_PLUS_SIG) {
+	    // HFS
+	    // printf("%d HFS\n", entry->disk_address);
+	    *kind = kHFS_std;
+	    len = mdb->drVN[0];
+	    name = (char *) malloc(len+1);
+	    strncpy(name, &mdb->drVN[1], len);
+	    name[len] = 0;
+	} else {
+	    // embedded HFS plus
+	    // printf("%d embedded HFS Plus\n", entry->disk_address);
+	    *kind = kHFS_embed;
+	    len = mdb->drVN[0];
+	    name = (char *) malloc(len+1);
+	    strncpy(name, &mdb->drVN[1], len);
+	    name[len] = 0;
+	}
+    }
+not_hfs:
+    free(mdb);
+    return name;
+}
+
+// really need a function to read block n from partition m
+
+int
+read_partition_block(partition_map *entry, unsigned long num, char *buf)
+{
+    DPME *data;
+    partition_map_header * map;
+    u32 base;
+    u64 offset;
+    
+    map = entry->the_map;
+    data = entry->data;
+    base = data->dpme_pblock_start;
+
+    if (num >= data->dpme_pblocks) {
+	return 0;
+    }
+    offset = ((long long) base) * map->logical_block + num * 512;
+    
+    return read_media(map->m, offset, 512, (void *)buf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/hfs_misc.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,41 @@
+//
+// hfs_misc.h - hfs routines
+//
+// Written by Eryk Vershen
+//
+
+/*
+ * Copyright 2000 by Eryk Vershen
+ */
+
+#ifndef __hfs_misc__
+#define __hfs_misc__
+
+#include "partition_map.h"
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+char *get_HFS_name(partition_map *entry, int *kind);
+
+#endif /* __hfs_misc__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/io.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,463 @@
+//
+// io.c - simple io and input parsing routines
+//
+// Written by Eryk Vershen
+//
+
+/*
+ * Copyright 1996,1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+// for *printf()
+#include <stdio.h>
+
+// for malloc() & free()
+#if !defined(__linux__)
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+// for strncpy()
+#include <string.h>
+// for va_start(), etc.
+#include <stdarg.h>
+// for errno
+#include <errno.h>
+
+#include "io.h"
+#include "errors.h"
+
+
+//
+// Defines
+//
+#define BAD_DIGIT 17	/* must be greater than any base */
+#define	STRING_CHUNK	16
+#define UNGET_MAX_COUNT 10
+#ifndef __linux__
+#ifndef __unix__
+#define SCSI_FD 8
+#endif
+#ifdef NeXT
+#define loff_t off_t
+#define llseek lseek
+#else
+#define loff_t long
+#define llseek lseek
+#endif
+#endif
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+const long kDefault = -1;
+
+
+//
+// Global Variables
+//
+short unget_buf[UNGET_MAX_COUNT+1];
+int unget_count;
+char io_buffer[MAXIOSIZE];
+
+
+//
+// Forward declarations
+//
+long get_number(int first_char);
+char* get_string(int eos);
+int my_getch();
+void my_ungetch(int c);
+
+
+//
+// Routines
+//
+int
+my_getch()
+{
+    if (unget_count > 0) {
+	return (unget_buf[--unget_count]);
+    } else {
+	return (getc(stdin));
+    }
+}
+
+
+void
+my_ungetch(int c)
+{
+    // In practice there is never more than one character in
+    // the unget_buf, but what's a little overkill among friends?
+
+    if (unget_count < UNGET_MAX_COUNT) {
+	unget_buf[unget_count++] = c;
+    } else {
+	fatal(-1, "Programmer error in my_ungetch().");
+    }
+}
+
+	
+void
+flush_to_newline(int keep_newline)
+{
+    int		c;
+
+    for (;;) {
+	c = my_getch();
+
+	if (c <= 0) {
+	    break;
+	} else if (c == '\n') {
+	    if (keep_newline) {
+		my_ungetch(c);
+	    }
+	    break;
+	} else {
+	    // skip
+	}
+    }
+    return;
+}
+
+
+int
+get_okay(char *prompt, int default_value)
+{
+    int		c;
+
+    flush_to_newline(0);
+    printf(prompt);
+
+    for (;;) {
+	c = my_getch();
+
+	if (c <= 0) {
+	    break;
+	} else if (c == ' ' || c == '\t') {
+	    // skip blanks and tabs
+	} else if (c == '\n') {
+	    my_ungetch(c);
+	    return default_value;
+	} else if (c == 'y' || c == 'Y') {
+	    return 1;
+	} else if (c == 'n' || c == 'N') {
+	    return 0;
+	} else {
+	    flush_to_newline(0);
+	    printf(prompt);
+	}
+    }
+    return -1;
+}
+
+	
+int
+get_command(char *prompt, int promptBeforeGet, int *command)
+{
+    int		c;
+
+    if (promptBeforeGet) {
+	printf(prompt);
+    }	
+    for (;;) {
+	c = my_getch();
+
+	if (c <= 0) {
+	    break;
+	} else if (c == ' ' || c == '\t') {
+	    // skip blanks and tabs
+	} else if (c == '\n') {
+	    printf(prompt);
+	} else {
+	    *command = c;
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+	
+int
+get_number_argument(char *prompt, long *number, long default_value)
+{
+    int c;
+    int result = 0;
+
+    for (;;) {
+	c = my_getch();
+
+	if (c <= 0) {
+	    break;
+	} else if (c == ' ' || c == '\t') {
+	    // skip blanks and tabs
+	} else if (c == '\n') {
+	    if (default_value == kDefault) {
+		printf(prompt);
+	    } else {
+		my_ungetch(c);
+		*number = default_value;
+		result = 1;
+		break;
+	    }
+	} else if ('0' <= c && c <= '9') {
+	    *number = get_number(c);
+	    result = 1;
+	    break;
+	} else {
+	    my_ungetch(c);
+	    *number = 0;
+	    break;
+	}
+    }
+    return result;
+}
+
+
+long
+get_number(int first_char)
+{
+    register int c;
+    int base;
+    int digit;
+    int ret_value;
+
+    if (first_char != '0') {
+	c = first_char;
+	base = 10;
+	digit = BAD_DIGIT;
+    } else if ((c=my_getch()) == 'x' || c == 'X') {
+	c = my_getch();
+	base = 16;
+	digit = BAD_DIGIT;
+    } else {
+	my_ungetch(c);
+	c = first_char;
+	base = 8;
+	digit = 0;
+    }
+    ret_value = 0;
+    for (ret_value = 0; ; c = my_getch()) {
+	if (c >= '0' && c <= '9') {
+	    digit = c - '0';
+	} else if (c >='A' && c <= 'F') {
+	    digit = 10 + (c - 'A');
+	} else if (c >='a' && c <= 'f') {
+	    digit = 10 + (c - 'a');
+	} else {
+	    digit = BAD_DIGIT;
+	}
+	if (digit >= base) {
+	    break;
+	}
+	ret_value = ret_value * base + digit;
+    }
+    my_ungetch(c);
+    return(ret_value);
+}
+
+	
+int
+get_string_argument(char *prompt, char **string, int reprompt)
+{
+    int c;
+    int result = 0;
+
+    for (;;) {
+	c = my_getch();
+
+	if (c <= 0) {
+	    break;
+	} else if (c == ' ' || c == '\t') {
+	    // skip blanks and tabs
+	} else if (c == '\n') {
+	    if (reprompt) {
+		printf(prompt);
+	    } else {
+		my_ungetch(c);
+		*string = NULL;
+		break;
+	    }
+	} else if (c == '"' || c == '\'') {
+	    *string = get_string(c);
+	    result = 1;
+	    break;
+	} else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
+		|| (c == '-' || c == '/' || c == '.' || c == ':')) {
+	    my_ungetch(c);
+	    *string = get_string(' ');
+	    result = 1;
+	    break;
+	} else {
+	    my_ungetch(c);
+	    *string = NULL;
+	    break;
+	}
+    }
+    return result;
+}
+
+
+char *
+get_string(int eos)
+{
+    int c;
+    char *s;
+    char *ret_value;
+    char *limit;
+    int length;
+
+    ret_value = (char *) malloc(STRING_CHUNK);
+    if (ret_value == NULL) {
+	error(errno, "can't allocate memory for string buffer");
+	return NULL;
+    }
+    length = STRING_CHUNK;
+    limit = ret_value + length;
+
+    c = my_getch();
+    for (s = ret_value; ; c = my_getch()) {
+	if (s >= limit) {
+	    // expand string
+	    limit = (char *) malloc(length+STRING_CHUNK);
+	    if (limit == NULL) {
+		error(errno, "can't allocate memory for string buffer");
+		ret_value[length-1] = 0;
+		break;
+	    }
+	    strncpy(limit, ret_value, length);
+	    free(ret_value);
+	    s = limit + (s - ret_value);
+	    ret_value = limit;
+	    length += STRING_CHUNK;
+	    limit = ret_value + length;
+	}
+	if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) {
+	    *s++ = 0;
+	    break;
+	} else if (c == '\n') {
+	    *s++ = 0;
+	    my_ungetch(c);
+	    break;
+	} else {
+	    *s++ = c;
+	}
+    }
+    return(ret_value);
+}
+
+
+unsigned long
+get_multiplier(long divisor)
+{
+    int c;
+    unsigned long result;
+    unsigned long extra;
+
+    c = my_getch();
+
+    extra = 1;
+    if (c <= 0 || divisor <= 0) {
+	result = 0;
+    } else if (c == 't' || c == 'T') {
+	result = 1024*1024;
+	extra = 1024*1024;
+    } else if (c == 'g' || c == 'G') {
+	result = 1024*1024*1024;
+    } else if (c == 'm' || c == 'M') {
+	result = 1024*1024;
+    } else if (c == 'k' || c == 'K') {
+	result = 1024;
+    } else {
+	my_ungetch(c);
+	result = 1;
+    }
+    if (result > 1) {
+	if (extra > 1) {
+	    result /= divisor;
+	    if (result >= 4096) {
+		/* overflow -> 20bits + >12bits */
+		result = 0;
+	    } else {
+		result *= extra;
+	    }
+	} else if (result >= divisor) {
+	    result /= divisor;
+	} else {
+	    result = 1;
+	}
+    }
+    return result;
+}
+
+
+int
+get_partition_modifier(void)
+{
+    int c;
+    int result;
+
+    result = 0;
+
+    c = my_getch();
+
+    if (c == 'p' || c == 'P') {
+    	result = 1;
+    } else if (c > 0) {
+	my_ungetch(c);
+    }
+    return result;
+}
+
+
+int
+number_of_digits(unsigned long value)
+{
+    int j;
+
+    j = 1;
+    while (value > 9) {
+	j++;
+	value = value / 10;
+    }
+    return j;
+}
+
+
+//
+// Print a message on standard error & flush the input.
+//
+void
+bad_input(char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fprintf(stderr, "\n");
+    flush_to_newline(1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/io.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,67 @@
+//
+// io.h - simple io and input parsing routines
+//
+// Written by Eryk Vershen
+//
+
+/*
+ * Copyright 1996,1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __io__
+#define __io__
+
+
+//
+// Defines
+//
+#define MAXIOSIZE	2048
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+extern const long kDefault;
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+void bad_input(char *fmt, ...);
+void flush_to_newline(int keep_newline);
+int get_command(char *prompt, int promptBeforeGet, int *command);
+unsigned long get_multiplier(long divisor);
+int get_number_argument(char *prompt, long *number, long default_value);
+int get_okay(char *prompt, int default_value);
+int get_partition_modifier(void);
+int get_string_argument(char *prompt, char **string, int reprompt);
+int number_of_digits(unsigned long value);
+
+#endif /* __io__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/layout_dump.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,180 @@
+/*
+ * layout_dump.c -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1996,1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+// for printf()
+#include <stdio.h>
+// for strlen()
+#include <string.h>
+#include "layout_dump.h"
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+
+
+/*
+ * Global Constants
+ */
+unsigned char bitmasks[] = {
+    0x01, 0x03, 0x07, 0x0F,
+    0x1F, 0x3F, 0x7F, 0xFF
+};
+
+
+/*
+ * Global Variables
+ */
+
+
+/*
+ * Forward declarations
+ */
+
+
+/*
+ * Routines
+ */
+void
+dump_using_layout(void *buffer, layout *desc)
+{
+    layout *entry;
+    int byte_length;
+    long    value;
+    int max_name;
+    int i;
+    
+    max_name = 0;
+    for (entry = desc; entry->format != kEnd; entry++) {
+	value = strlen(entry->name);
+	if (value > max_name) {
+	    max_name = value;
+	}
+    }
+    
+    
+    for (entry = desc; entry->format != kEnd; entry++) {
+
+	if (entry->format != kBit) {
+	    printf("%*s: ", max_name, entry->name);
+	
+	    byte_length = entry->bit_length / 8;
+	    
+	    if (entry->bit_offset != 0 || (entry->bit_length % 8) != 0) {
+		printf("entry %d, can't handle bitfields yet.\n", entry - desc);
+		continue;
+	    }
+	    
+	    value = 0;
+	    for (i = entry->byte_offset; byte_length > 0;i++) {
+		value = value << 8;
+		value |= ((unsigned char *)buffer)[i];
+		byte_length--;
+	    }
+	} else {
+	    if (entry->bit_offset < 0 || entry->bit_offset > 8) {
+		printf("entry %d, bad bit offset (%d).\n", entry - desc, entry->bit_offset);
+		continue;
+	    } else if (entry->bit_length <= 0 
+		    || entry->bit_length > (entry->bit_offset + 1)) {
+		printf("entry %d, bad bit length (%d,%d).\n", entry - desc,
+			entry->bit_offset, entry->bit_length);
+		continue;
+	    }
+	    value = (((unsigned char *)buffer)[entry->byte_offset]
+		    & bitmasks[entry->bit_offset])
+		    >> ((entry->bit_offset + 1) - entry->bit_length);
+	}
+	
+	switch (entry->format) {
+	case kHex:
+	    printf("0x%x\n", value);
+	    break;
+	case kDec:
+	    byte_length = entry->bit_length / 8;
+	    switch (byte_length) {
+	    case 4: printf("%d\n", (signed long)value); break;
+	    case 2: printf("%d\n", (signed short)value); break;
+	    case 1: printf("%d\n", (signed char)value); break;
+	    }
+	    break;
+	case kUns:
+	    byte_length = entry->bit_length / 8;
+	    switch (byte_length) {
+	    case 4: printf("%u\n", (unsigned long)value); break;
+	    case 2: printf("%u\n", (unsigned short)value); break;
+	    case 1: printf("%u\n", (unsigned char)value); break;
+	    }
+	    break;
+	case kBit:
+	    if (value) {
+		printf("%*s  %s\n", max_name, "", entry->name);
+	    }
+	    break;
+	default:
+	    printf("entry %d, unknown format (%d).\n", entry - desc, entry->format);
+	    break;
+	}
+    }
+}
+
+
+void
+DumpRawBuffer(unsigned char *bufferPtr, int length )
+{
+	register int            i;
+	int                     lineStart;
+	int                     lineLength;
+	short                   c;
+
+#define kLineSize   16
+	for (lineStart = 0; lineStart < length; lineStart += lineLength) {
+	    lineLength = kLineSize;
+	    if (lineStart + lineLength > length)
+		lineLength = length - lineStart;
+	    printf("%03x %3d:", lineStart, lineStart);
+	    for (i = 0; i < lineLength; i++)
+		printf(" %02x", bufferPtr[lineStart + i] & 0xFF);
+	    for (; i < kLineSize; i++)
+		printf("   ");
+	    printf("  ");
+	    for (i = 0; i < lineLength; i++) {
+		c = bufferPtr[lineStart + i] & 0xFF;
+		if (c > ' ' && c < '~')
+		    printf("%c", c);
+		else {
+		    printf(".");
+		}
+	    }
+	    printf("\n");
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/layout_dump.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,78 @@
+/*
+ * layout_dump.h -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __layout_dump__
+#define __layout_dump__
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+enum {
+    kEnd,
+    kHex,
+    kDec,
+    kUns,
+    kBit
+};
+
+typedef struct {
+    short   byte_offset;
+    short   bit_offset;
+    short   bit_length;
+    short   format;
+    char    *name;
+} layout;
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+
+
+/*
+ * Forward declarations
+ */
+
+
+/*
+ * Routines
+ */
+void dump_using_layout(void *buffer, layout *desc);
+void DumpRawBuffer(unsigned char *bufferPtr, int length);
+
+#endif /* __layout_dump__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/makefile	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,212 @@
+#
+# Makefile for pdisk
+#
+
+MAN_PAGE= \
+	pdisk.8
+
+MAC_DOC= \
+	pdisk.html
+
+DOCS= \
+	HISTORY \
+	README \
+	$(MAN_PAGE) \
+	$(MAC_DOC)
+
+SERVER_README = \
+	dist.README
+
+SERVER_MESSAGE = \
+	dist.message
+
+DOCS_INTERNAL= \
+	HISTORY.ALL \
+	HOWTO.DISTRIBUTE \
+	To_do_list \
+	command-language
+
+SUPPORT= \
+	make_filename \
+	make_depend \
+	make_tags \
+	checkin_files \
+	MPWcompare \
+	name_latest \
+	next_release
+
+MAC_SOURCE= \
+	ATA_media.c \
+	ATA_media.h \
+	DoSCSICommand.c \
+	DoSCSICommand.h \
+	MacSCSICommand.h \
+	SCSI_media.c \
+	SCSI_media.h \
+	pdisk.r
+
+UNIX_SOURCE= \
+	bitfield.c \
+	bitfield.h \
+	convert.c \
+	convert.h \
+	cvt_pt.c \
+	deblock_media.c \
+	deblock_media.h \
+	dpme.h \
+	dump.c \
+	dump.h \
+	errors.c \
+	errors.h \
+	file_media.c \
+	file_media.h \
+	hfs_misc.c \
+	hfs_misc.h \
+	io.c \
+	io.h \
+	layout_dump.c \
+	layout_dump.h \
+	makefile \
+	media.c \
+	media.h \
+	partition_map.c \
+	partition_map.h \
+	pathname.c \
+	pathname.h \
+	pdisk.c \
+	pdisk.h \
+	util.c \
+	util.h \
+	validate.c \
+	validate.h \
+	version.h
+
+COMMON_OBJECTS = \
+	partition_map.o \
+	bitfield.o \
+	convert.o \
+	deblock_media.o \
+	file_media.o \
+	errors.o \
+	hfs_misc.o \
+	io.o \
+	media.o \
+	pathname.o \
+	util.o
+
+UNIX_OBJECTS = \
+	pdisk.o \
+	dump.o \
+	$(COMMON_OBJECTS) \
+	validate.o
+
+CVT_OBJECTS = \
+	cvt_pt.o \
+	$(COMMON_OBJECTS)
+
+
+
+ALL_FILES= $(DOCS) $(DOCS_INTERNAL) $(SUPPORT) $(MAC_SOURCE) $(UNIX_SOURCE)
+
+UNIX_BINARIES= \
+	pdisk \
+	cvt_pt
+
+#
+# these names have '__' in place of ' ' to avoid quoting nightmares 
+#
+MAC_PROJECT= \
+	pdisk.mac.bin \
+	pdisk.mac__Data/CW__Settings.stm.bin \
+	pdisk.mac__Data/pdisk.tdm.bin \
+	pdisk.mac__Data/pdisk__68k.tdm.bin
+
+# Constructed under MacOS using CodeWarrior from MAC_PROJECT & sources
+MAC_BINARY= \
+	pdisk.hqx
+
+MAC_68KBINARY= \
+	pdisk_68k.hqx
+
+
+CFLAGS = -Wall
+DIST_TAR_FLAGS = cvf
+
+
+all: $(UNIX_BINARIES)
+
+pdisk: $(UNIX_OBJECTS)
+	cc -o pdisk $(UNIX_OBJECTS)
+
+cvt_pt: $(CVT_OBJECTS)
+	cc -o cvt_pt $(CVT_OBJECTS)
+
+tags:	$(MAC_SOURCE) $(UNIX_SOURCE)
+	ctags $(MAC_SOURCE) $(UNIX_SOURCE)
+
+clean:
+	rm -f *.o $(UNIX_BINARIES) list.src
+
+clobber:	clean
+	rm -f $(ALL_FILES) $(MAC_BINARY) $(MAC_68KBINARY) tags
+
+# note the sed to reinsert the spaces in the Mac names
+list.src: $(MAC_SOURCE) $(DOCS) $(UNIX_SOURCE) $(MAC_PROJECT)
+	echo $(MAC_SOURCE) $(DOCS) $(UNIX_SOURCE) $(MAC_PROJECT) |\
+	tr ' ' '\n' | sed -e 's/__/ /g' -e 's,^,pdisk/,' >list.src
+
+#
+# this depends on this source directory being named 'pdisk'
+#
+distribution: list.src
+	cd ..; tar $(DIST_TAR_FLAGS) pdisk/dist/pdisk.src.tar.`date +%Y%m%d` --files-from pdisk/list.src
+	tar $(DIST_TAR_FLAGS) dist/pdisk.bin.tar.`date +%Y%m%d` $(UNIX_BINARIES) $(MAN_PAGE)
+	cp -f $(MAC_DOC) dist/$(MAC_DOC).`date +%Y%m%d`
+	cp -f $(MAC_BINARY) dist/$(MAC_BINARY).`date +%Y%m%d`
+	cp -f $(MAC_68KBINARY) dist/$(MAC_68KBINARY).`date +%Y%m%d`
+
+checkin:
+	./checkin_files $(ALL_FILES)
+
+checkout:	$(ALL_FILES)
+
+diff:
+	rcsdiff $(ALL_FILES) 2>&1
+
+name:
+	./name_latest $(ALL_FILES)
+
+#
+# in lieu of a real dependency generator
+#
+convert.h:	dpme.h
+deblock_media.h:	media.h
+dpme.h:	bitfield.h
+dump.h:	partition_map.h hfs_misc.h
+file_media.h:	media.h
+partition_map.h:	dpme.h media.h
+pathname.h:	media.h
+validate.h:	partition_map.h
+
+bitfield.o:	bitfield.c bitfield.h
+convert.o:	convert.c convert.h
+deblock_media.o:	deblock_media.c deblock_media.h
+dump.o:		dump.c dump.h pathname.h io.h errors.h
+errors.o:	errors.c errors.h
+file_media.o:	file_media.c file_media.h errors.h
+io.o:		io.c io.h errors.h
+layout_dump.o:	layout_dump.c layout_dump.h
+media.o:	media.c media.h
+partition_map.o:	partition_map.c partition_map.h pathname.h deblock_media.h io.h convert.h util.h errors.h
+pathname.o:	pathname.c pathname.h file_media.h
+pdisk.o:	pdisk.c pdisk.h io.h partition_map.h pathname.h errors.h dump.h validate.h version.h util.h
+util.o:		util.c version.h util.h
+validate.o:	validate.c validate.h deblock_media.h pathname.h convert.h io.h errors.h
+
+
+#
+# fake dependencies used only by list.src {for $(MAC_PROJECT)}
+#
+pdisk.mac__Data/CW__Settings.stm.bin:
+pdisk.mac__Data/pdisk.tdm.bin:
+pdisk.mac__Data/pdisk__68k.tdm.bin:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/media.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,228 @@
+/*
+ * media.c -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+// for printf()
+#include <stdio.h>
+// for malloc() & free()
+#include <stdlib.h>
+
+#include "media.h"
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+static long media_kind = 0;
+
+/*
+ * Forward declarations
+ */
+
+
+/*
+ * Routines
+ */
+long
+allocate_media_kind(void)
+{
+    media_kind++;
+    return media_kind;
+}
+
+
+MEDIA
+new_media(long size)
+{
+    return (MEDIA) malloc(size);
+}
+
+
+void
+delete_media(MEDIA m)
+{
+    if (m == 0) {
+	return;
+    }
+    free(m);
+}
+
+
+unsigned long
+media_granularity(MEDIA m)
+{
+    if (m == 0) {
+	return 0;
+    } else {
+	return m->grain;
+    }
+}
+
+
+long long
+media_total_size(MEDIA m)
+{
+    if (m == 0) {
+	return 0;
+    } else {
+	return m->size_in_bytes;
+    }
+}
+
+
+long
+read_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+    long result;
+    
+    if (m != 0 && m->do_read != 0) {
+	//printf("media: read type %d, offset %Ld, count %d\n\t", m->kind, offset, count);
+	result = (*m->do_read)(m, offset, count, address);
+	//printf(" - returns %d\n", result);
+	return result;
+    } else {
+	return 0;
+    }
+}
+
+
+long
+write_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+    long result;
+    
+    if (m != 0 && m->do_write != 0) {
+	//printf("media: write type %d, offset %Ld, count %d\n\t", m->kind, offset, count);
+	result = (*m->do_write)(m, offset, count, address);
+	//printf(" - returns %d\n", result);
+	return result;
+    } else {
+	return 0;
+    }
+}
+
+
+void
+close_media(MEDIA m)
+{
+    if (m == 0) {
+	return;
+    }
+    if (m->kind != 0) {
+	if (m->do_close != 0) {
+	    (*m->do_close)(m);
+	}
+	m->kind = 0;
+	delete_media(m);
+    }
+}
+
+
+void
+os_reload_media(MEDIA m)
+{
+    if (m != 0 && m->do_os_reload != 0) {
+	(*m->do_os_reload)(m);
+    }
+}
+
+
+#if !defined(__linux__) && !defined(__unix__)
+#pragma mark -
+#endif
+
+
+
+MEDIA_ITERATOR
+new_media_iterator(long size)
+{
+    return (MEDIA_ITERATOR) malloc(size);
+}
+
+
+void
+private_delete_media_iterator(MEDIA_ITERATOR m)
+{
+    if (m == 0) {
+	return;
+    }
+    free(m);
+}
+
+
+void
+reset_media_iterator(MEDIA_ITERATOR m)
+{
+    if (m != 0 && m->do_reset != 0) {
+	(*m->do_reset)(m);
+    }
+}
+
+
+char *
+step_media_iterator(MEDIA_ITERATOR m)
+{
+    char *result;
+    
+    if (m != 0 && m->do_step != 0) {
+	result = (*m->do_step)(m);
+    } else {
+	result = 0;
+    }
+    return result;
+}
+
+
+void
+delete_media_iterator(MEDIA_ITERATOR m)
+{
+    if (m == 0) {
+	return;
+    }
+    if (m->kind != 0) {
+	if (m->do_delete != 0) {
+	    (*m->do_delete)(m);
+	}
+	m->kind = 0;
+	private_delete_media_iterator(m);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/media.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,139 @@
+/*
+ * media.h -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __media__
+#define __media__
+
+
+/*
+ * Media is an abstraction of a disk device.
+ *
+ * A media object has the following visible attributes:
+ *
+ *      a granularity       (e.g. 512, 1024, 1, etc.)
+ *      a total size in bytes 
+ *
+ *  And the following operations are available:
+ *
+ *      open
+ *      read @ byte offset for size in bytes
+ *      write @ byte offset for size in bytes
+ *      close
+ *
+ * XXX Should really split public media interface from "protected" interface.
+ */
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+/* those whose use media objects need just the pointer type */
+typedef struct media *MEDIA;
+
+/* those who define media objects need the struct and internal routine types */
+typedef long (*media_read)(MEDIA m, long long offset, unsigned long count, void *address);
+typedef long (*media_write)(MEDIA m, long long offset, unsigned long count, void *address);
+typedef long (*media_close)(MEDIA m);
+typedef long (*media_os_reload)(MEDIA m);
+
+struct media {
+    long            kind;           /* kind of media - SCSI, IDE, etc. */
+    unsigned long   grain;          /* granularity (offset & size) */
+    long long       size_in_bytes;  /* offset granularity */
+    media_read      do_read;        /* device specific routines */
+    media_write     do_write;
+    media_close     do_close;
+    media_os_reload do_os_reload;
+				    /* specific media kinds will add extra info */
+};
+
+/* those whose use media object iterators need just the pointer type */
+typedef struct media_iterator *MEDIA_ITERATOR;
+
+/* those who define media object iterators need the struct and internal routine types */
+typedef void (*media_iterator_reset)(MEDIA_ITERATOR m);
+typedef char* (*media_iterator_step)(MEDIA_ITERATOR m);
+typedef void (*media_iterator_delete)(MEDIA_ITERATOR m);
+
+typedef enum {
+    kInit,
+    kReset,
+    kIterating,
+    kEnd
+} media_iterator_state;
+
+struct media_iterator {
+    long                    kind;           /* kind of media - SCSI, IDE, etc. */
+    media_iterator_state    state;          /* init, reset, iterating, at_end */
+    media_iterator_reset    do_reset;       /* device specific routines */
+    media_iterator_step     do_step;
+    media_iterator_delete   do_delete;
+					    /* specific media kinds will add extra info */
+};
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+
+
+/*
+ * Forward declarations
+ */
+/* those whose use media objects need these routines */
+unsigned long media_granularity(MEDIA m);
+long long media_total_size(MEDIA m);
+long read_media(MEDIA m, long long offset, unsigned long count, void *address);
+long write_media(MEDIA m, long long offset, unsigned long count, void *address);
+void close_media(MEDIA m);
+void os_reload_media(MEDIA m);
+
+/* those who define media objects need these routines also */
+long allocate_media_kind(void);
+MEDIA new_media(long size);
+void delete_media(MEDIA m);
+
+/* those whose use media object iterators need these routines */
+void reset_media_iterator(MEDIA_ITERATOR m);
+char *step_media_iterator(MEDIA_ITERATOR m);
+void delete_media_iterator(MEDIA_ITERATOR m);
+
+/* those who define media object iterators need these routines also */
+MEDIA_ITERATOR new_media_iterator(long size);
+void private_delete_media_iterator(MEDIA_ITERATOR m);
+
+#endif /* __media__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/partition_map.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,1319 @@
+//
+// partition_map.c - partition map routines
+//
+// Written by Eryk Vershen
+//
+
+/*
+ * Copyright 1996,1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+// for *printf()
+#include <stdio.h>
+
+// for malloc(), calloc() & free()
+#ifndef __linux__
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+
+// for strncpy() & strcmp()
+#include <string.h>
+// for O_RDONLY & O_RDWR
+#include <fcntl.h>
+// for errno
+#include <errno.h>
+
+#include "partition_map.h"
+#include "pathname.h"
+#include "hfs_misc.h"
+#include "deblock_media.h"
+#include "io.h"
+#include "convert.h"
+#include "util.h"
+#include "errors.h"
+
+
+//
+// Defines
+//
+#define APPLE_HFS_FLAGS_VALUE	0x4000037f
+#define get_align_long(x)	(*(x))
+#define put_align_long(y, x)	((*(x)) = (y))
+// #define TEST_COMPUTE
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+const char * kFreeType	= "Apple_Free";
+const char * kMapType	= "Apple_partition_map";
+const char * kUnixType	= "Apple_UNIX_SVR2";
+const char * kHFSType	= "Apple_HFS";
+const char * kPatchType	= "Apple_Patches";
+
+const char * kFreeName	= "Extra";
+
+enum add_action {
+    kReplace = 0,
+    kAdd = 1,
+    kSplit = 2
+};
+
+//
+// Global Variables
+//
+extern int cflag;
+
+
+//
+// Forward declarations
+//
+int add_data_to_map(struct dpme *data, long index, partition_map_header *map);
+int coerce_block0(partition_map_header *map);
+int contains_driver(partition_map *entry);
+void combine_entry(partition_map *entry);
+long compute_device_size(partition_map_header *map, partition_map_header *oldmap);
+DPME* create_data(const char *name, const char *dptype, u32 base, u32 length);
+void delete_entry(partition_map *entry);
+char *get_HFS_name(partition_map *entry, int *kind);
+void insert_in_base_order(partition_map *entry);
+void insert_in_disk_order(partition_map *entry);
+int read_block(partition_map_header *map, unsigned long num, char *buf);
+int read_partition_map(partition_map_header *map);
+void remove_driver(partition_map *entry);
+void remove_from_disk_order(partition_map *entry);
+void renumber_disk_addresses(partition_map_header *map);
+void sync_device_size(partition_map_header *map);
+int write_block(partition_map_header *map, unsigned long num, char *buf);
+
+
+//
+// Routines
+//
+partition_map_header *
+open_partition_map(char *name, int *valid_file, int ask_logical_size)
+{
+    MEDIA m;
+    partition_map_header * map;
+    int writeable;
+    int size;
+
+    m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR);
+    if (m == 0) {
+	m = open_pathname_as_media(name, O_RDONLY);
+	if (m == 0) {
+	    error(errno, "can't open file '%s'", name);
+	    *valid_file = 0;
+	    return NULL;
+	} else {
+	    writeable = 0;
+	}
+    } else {
+	writeable = 1;
+    }
+    *valid_file = 1;
+
+    map = (partition_map_header *) malloc(sizeof(partition_map_header));
+    if (map == NULL) {
+	error(errno, "can't allocate memory for open partition map");
+	close_media(m);
+	return NULL;
+    }
+    map->name = name;
+    map->writeable = (rflag)?0:writeable;
+    map->changed = 0;
+    map->written = 0;
+    map->disk_order = NULL;
+    map->base_order = NULL;
+
+    map->physical_block = media_granularity(m);	/* preflight */
+    m = open_deblock_media(PBLOCK_SIZE, m);
+    map->m = m;
+    map->misc = (Block0 *) malloc(PBLOCK_SIZE);
+    if (map->misc == NULL) {
+	error(errno, "can't allocate memory for block zero buffer");
+	close_media(map->m);
+	free(map);
+	return NULL;
+    } else if (read_media(map->m, (long long) 0, PBLOCK_SIZE, (char *)map->misc) == 0
+	    || convert_block0(map->misc, 1)
+	    || coerce_block0(map)) {
+	// if I can't read block 0 I might as well give up
+	error(-1, "Can't read block 0 from '%s'", name);
+	close_partition_map(map);
+	return NULL;
+    }
+    map->physical_block = map->misc->sbBlkSize;
+    //printf("physical block size is %d\n", map->physical_block);
+
+    if (ask_logical_size && interactive) {
+	size = PBLOCK_SIZE;
+	printf("A logical block is %d bytes: ", size);
+	flush_to_newline(0);
+	get_number_argument("what should be the logical block size? ",
+		(long *)&size, size);
+	size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
+	if (size < PBLOCK_SIZE) {
+	    size = PBLOCK_SIZE;
+	}
+	map->logical_block = size;
+    } else {
+	map->logical_block = PBLOCK_SIZE;
+    }
+    if (map->logical_block > MAXIOSIZE) {
+	map->logical_block = MAXIOSIZE;
+    }
+    if (map->logical_block > map->physical_block) {
+	map->physical_block = map->logical_block;
+    }
+    map->blocks_in_map = 0;
+    map->maximum_in_map = -1;
+    map->media_size = compute_device_size(map, map);
+    sync_device_size(map);
+
+    if (read_partition_map(map) < 0) {
+	// some sort of failure reading the map
+    } else {
+	// got it!
+	;
+	return map;
+    }
+    close_partition_map(map);
+    return NULL;
+}
+
+
+void
+close_partition_map(partition_map_header *map)
+{
+    partition_map * entry;
+    partition_map * next;
+
+    if (map == NULL) {
+	return;
+    }
+
+    free(map->misc);
+
+    for (entry = map->disk_order; entry != NULL; entry = next) {
+	next = entry->next_on_disk;
+	free(entry->data);
+	free(entry->HFS_name);
+	free(entry);
+    }
+    close_media(map->m);
+    free(map);
+}
+
+
+int
+read_partition_map(partition_map_header *map)
+{
+    DPME *data;
+    u32 limit;
+    int index;
+    int old_logical;
+    double d;
+
+//printf("called read_partition_map\n");
+//printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
+    data = (DPME *) malloc(PBLOCK_SIZE);
+    if (data == NULL) {
+	error(errno, "can't allocate memory for disk buffers");
+	return -1;
+    }
+
+    if (read_block(map, 1, (char *)data) == 0) {
+	error(-1, "Can't read block 1 from '%s'", map->name);
+	free(data);
+	return -1;
+    } else if (convert_dpme(data, 1)
+	    || data->dpme_signature != DPME_SIGNATURE) {
+	old_logical = map->logical_block;
+	map->logical_block = 512;
+	while (map->logical_block <= map->physical_block) {
+	    if (read_block(map, 1, (char *)data) == 0) {
+		error(-1, "Can't read block 1 from '%s'", map->name);
+		free(data);
+		return -1;
+	    } else if (convert_dpme(data, 1) == 0
+		    && data->dpme_signature == DPME_SIGNATURE) {
+		d = map->media_size;
+		map->media_size =  (d * old_logical) / map->logical_block;
+		break;
+	    }
+	    map->logical_block *= 2;
+	}
+	if (map->logical_block > map->physical_block) {
+	    error(-1, "No valid block 1 on '%s'", map->name);
+	    free(data);
+	    return -1;
+	}
+    }
+//printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block);
+
+    limit = data->dpme_map_entries;
+    index = 1;
+    while (1) {
+	if (add_data_to_map(data, index, map) == 0) {
+	    free(data);
+	    return -1;
+	}
+
+	if (index >= limit) {
+	    break;
+	} else {
+	    index++;
+	}
+
+	data = (DPME *) malloc(PBLOCK_SIZE);
+	if (data == NULL) {
+	    error(errno, "can't allocate memory for disk buffers");
+	    return -1;
+	}
+
+	if (read_block(map, index, (char *)data) == 0) {
+	    error(-1, "Can't read block %u from '%s'", index, map->name);
+	    free(data);
+	    return -1;
+	} else if (convert_dpme(data, 1)
+		|| (data->dpme_signature != DPME_SIGNATURE && dflag == 0)
+		|| (data->dpme_map_entries != limit && dflag == 0)) {
+	    error(-1, "Bad data in block %u from '%s'", index, map->name);
+	    free(data);
+	    return -1;
+	}
+    }
+    return 0;
+}
+
+
+void
+write_partition_map(partition_map_header *map)
+{
+    MEDIA m;
+    char *block;
+    partition_map * entry;
+    int i = 0;
+    int result;
+
+    m = map->m;
+    if (map->misc != NULL) {
+	convert_block0(map->misc, 0);
+	result = write_block(map, 0, (char *)map->misc);
+	convert_block0(map->misc, 1);
+    } else {
+	block = (char *) calloc(1, PBLOCK_SIZE);
+	if (block != NULL) {
+	    result = write_block(map, 0, block);
+	    free(block);
+	}
+    }
+    if (result == 0) {
+	error(errno, "Unable to write block zero");
+    }
+    for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) {
+	convert_dpme(entry->data, 0);
+	result = write_block(map, entry->disk_address, (char *)entry->data);
+	convert_dpme(entry->data, 1);
+	i = entry->disk_address;
+	if (result == 0) {
+	    error(errno, "Unable to write block %d", i);
+	}
+    }
+	// zap the block after the map (if possible) to get around a bug.
+    if (map->maximum_in_map > 0 &&  i < map->maximum_in_map) {
+	i += 1;
+	block = (char *) malloc(PBLOCK_SIZE);
+	if (block != NULL) {
+	    if (read_block(map, i, block)) {
+		block[0] = 0;
+		write_block(map, i, block);
+	    }
+	    free(block);
+	}
+    }
+    if (interactive)
+	printf("The partition table has been altered!\n\n");
+
+    os_reload_media(map->m);
+}
+
+
+int
+add_data_to_map(struct dpme *data, long index, partition_map_header *map)
+{
+    partition_map *entry;
+
+//printf("add data %d to map\n", index);
+    entry = (partition_map *) malloc(sizeof(partition_map));
+    if (entry == NULL) {
+	error(errno, "can't allocate memory for map entries");
+	return 0;
+    }
+    entry->next_on_disk = NULL;
+    entry->prev_on_disk = NULL;
+    entry->next_by_base = NULL;
+    entry->prev_by_base = NULL;
+    entry->disk_address = index;
+    entry->the_map = map;
+    entry->data = data;
+    entry->contains_driver = contains_driver(entry);
+    entry->HFS_name = get_HFS_name(entry, &entry->HFS_kind);
+
+    insert_in_disk_order(entry);
+    insert_in_base_order(entry);
+
+    map->blocks_in_map++;
+    if (map->maximum_in_map < 0) {
+	if (istrncmp(data->dpme_type, kMapType, DPISTRLEN) == 0) {
+	    map->maximum_in_map = data->dpme_pblocks;
+	}
+    }
+
+    return 1;
+}
+
+
+partition_map_header *
+init_partition_map(char *name, partition_map_header* oldmap)
+{
+    partition_map_header *map;
+
+    if (oldmap != NULL) {
+	printf("map already exists\n");
+	if (get_okay("do you want to reinit? [n/y]: ", 0) != 1) {
+	    return oldmap;
+	}
+    }
+
+    map = create_partition_map(name, oldmap);
+    if (map == NULL) {
+	return oldmap;
+    }
+    close_partition_map(oldmap);
+
+    add_partition_to_map("Apple", kMapType,
+	    1, (map->media_size <= 128? 2: 63), map);
+    return map;
+}
+
+
+partition_map_header *
+create_partition_map(char *name, partition_map_header *oldmap)
+{
+    MEDIA m;
+    partition_map_header * map;
+    DPME *data;
+    unsigned long default_number;
+    unsigned long number;
+    int size;
+    unsigned long multiple;
+
+    m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR);
+    if (m == 0) {
+	error(errno, "can't open file '%s' for %sing", name,
+		(rflag)?"read":"writ");
+	return NULL;
+    }
+
+    map = (partition_map_header *) malloc(sizeof(partition_map_header));
+    if (map == NULL) {
+	error(errno, "can't allocate memory for open partition map");
+	close_media(m);
+	return NULL;
+    }
+    map->name = name;
+    map->writeable = (rflag)?0:1;
+    map->changed = 1;
+    map->disk_order = NULL;
+    map->base_order = NULL;
+
+    if (oldmap != NULL) {
+	size = oldmap->physical_block;
+    } else {
+	size = media_granularity(m);
+    }
+    m = open_deblock_media(PBLOCK_SIZE, m);
+    map->m = m;
+    if (interactive) {
+	printf("A physical block is %d bytes: ", size);
+	flush_to_newline(0);
+	get_number_argument("what should be the physical block size? ",
+		(long *)&size, size);
+	size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
+	if (size < PBLOCK_SIZE) {
+	    size = PBLOCK_SIZE;
+	}
+    }
+    if (map->physical_block > MAXIOSIZE) {
+	map->physical_block = MAXIOSIZE;
+    }
+    map->physical_block = size;
+    // printf("block size is %d\n", map->physical_block);
+
+    if (oldmap != NULL) {
+	size = oldmap->logical_block;
+    } else {
+	size = PBLOCK_SIZE;
+    }
+    if (interactive) {
+	printf("A logical block is %d bytes: ", size);
+	flush_to_newline(0);
+	get_number_argument("what should be the logical block size? ",
+		(long *)&size, size);
+	size = (size / PBLOCK_SIZE) * PBLOCK_SIZE;
+	if (size < PBLOCK_SIZE) {
+	    size = PBLOCK_SIZE;
+	}
+    }
+    if (size > map->physical_block) {
+	size = map->physical_block;
+    }
+    map->logical_block = size;
+
+    map->blocks_in_map = 0;
+    map->maximum_in_map = -1;
+
+    number = compute_device_size(map, oldmap);
+    if (interactive) {
+	printf("size of 'device' is %lu blocks (%d byte blocks): ",
+		number, map->logical_block);
+	default_number = number;
+	flush_to_newline(0);
+	do {
+	    if (get_number_argument("what should be the size? ", 
+		    (long *)&number, default_number) == 0) {
+		printf("Not a number\n");
+		flush_to_newline(1);
+		number = 0;
+	    } else {
+		multiple = get_multiplier(map->logical_block);
+		if (multiple == 0) {
+		    printf("Bad multiplier\n");
+		    number = 0;
+		} else if (multiple != 1) {
+		    if (0xFFFFFFFF/multiple < number) {
+			printf("Number too large\n");
+			number = 0;
+		    } else {
+			number *= multiple;
+		    }
+		}
+	    }
+	    default_number = kDefault;
+	} while (number == 0);
+
+	if (number < 4) {
+	    number = 4;
+	}
+	printf("new size of 'device' is %lu blocks (%d byte blocks)\n",
+		number, map->logical_block);
+    }
+    map->media_size = number;
+
+    map->misc = (Block0 *) calloc(1, PBLOCK_SIZE);
+    if (map->misc == NULL) {
+	error(errno, "can't allocate memory for block zero buffer");
+    } else {
+	// got it!
+	coerce_block0(map);
+	sync_device_size(map);
+	
+	data = (DPME *) calloc(1, PBLOCK_SIZE);
+	if (data == NULL) {
+	    error(errno, "can't allocate memory for disk buffers");
+	} else {
+	    // set data into entry
+	    data->dpme_signature = DPME_SIGNATURE;
+	    data->dpme_map_entries = 1;
+	    data->dpme_pblock_start = 1;
+	    data->dpme_pblocks = map->media_size - 1;
+	    strncpy(data->dpme_name, kFreeName, DPISTRLEN);
+	    strncpy(data->dpme_type, kFreeType, DPISTRLEN);
+	    data->dpme_lblock_start = 0;
+	    data->dpme_lblocks = data->dpme_pblocks;
+	    dpme_writable_set(data, 1);
+	    dpme_readable_set(data, 1);
+	    dpme_bootable_set(data, 0);
+	    dpme_in_use_set(data, 0);
+	    dpme_allocated_set(data, 0);
+	    dpme_valid_set(data, 1);
+
+	    if (add_data_to_map(data, 1, map) == 0) {
+		free(data);
+	    } else {
+		return map;
+	    }
+	}
+    }
+    close_partition_map(map);
+    return NULL;
+}
+
+
+int
+coerce_block0(partition_map_header *map)
+{
+    Block0 *p;
+
+    p = map->misc;
+    if (p == NULL) {
+	return 1;
+    }
+    if (p->sbSig != BLOCK0_SIGNATURE) {
+	p->sbSig = BLOCK0_SIGNATURE;
+	if (map->physical_block == 1) {
+	    p->sbBlkSize = PBLOCK_SIZE;
+	} else {
+	    p->sbBlkSize = map->physical_block;
+	}
+	p->sbBlkCount = 0;
+	p->sbDevType = 0;
+	p->sbDevId = 0;
+	p->sbData = 0;
+	p->sbDrvrCount = 0;
+    }
+    return 0;	// we do this simply to make it easier to call this function
+}
+
+
+int
+add_partition_to_map(const char *name, const char *dptype, u32 base, u32 length,
+	partition_map_header *map)
+{
+    partition_map * cur;
+    DPME *data;
+    enum add_action act;
+    int limit;
+    u32 adjusted_base = 0;
+    u32 adjusted_length = 0;
+    u32 new_base = 0;
+    u32 new_length = 0;
+
+	// find a block that starts includes base and length
+    cur = map->base_order;
+    while (cur != NULL) {
+	if (cur->data->dpme_pblock_start <= base 
+		&& (base + length) <=
+		    (cur->data->dpme_pblock_start + cur->data->dpme_pblocks)) {
+	    break;
+	} else {
+	    cur = cur->next_by_base;
+	}
+    }
+	// if it is not Extra then punt
+    if (cur == NULL
+	    || istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
+	printf("requested base and length is not "
+		"within an existing free partition\n");
+	return 0;
+    }
+	// figure out what to do and sizes
+    data = cur->data;
+    if (data->dpme_pblock_start == base) {
+	// replace or add
+	if (data->dpme_pblocks == length) {
+	    act = kReplace;
+	} else {
+	    act = kAdd;
+	    adjusted_base = base + length;
+	    adjusted_length = data->dpme_pblocks - length;
+	}
+    } else {
+	// split or add
+	if (data->dpme_pblock_start + data->dpme_pblocks == base + length) {
+	    act = kAdd;
+	    adjusted_base = data->dpme_pblock_start;
+	    adjusted_length = base - adjusted_base;
+	} else {
+	    act = kSplit;
+	    new_base = data->dpme_pblock_start;
+	    new_length = base - new_base;
+	    adjusted_base = base + length;
+	    adjusted_length = data->dpme_pblocks - (length + new_length);
+	}
+    }
+	// if the map will overflow then punt
+    if (map->maximum_in_map < 0) {
+	limit = map->media_size;
+    } else {
+	limit = map->maximum_in_map;
+    }
+    if (map->blocks_in_map + act > limit) {
+	printf("the map is not big enough\n");
+	return 0;
+    }
+
+    data = create_data(name, dptype, base, length);
+    if (data == NULL) {
+	return 0;
+    }
+    if (act == kReplace) {
+	free(cur->data);
+	cur->data = data;
+    } else {
+	    // adjust this block's size
+	cur->data->dpme_pblock_start = adjusted_base;
+	cur->data->dpme_pblocks = adjusted_length;
+	cur->data->dpme_lblocks = adjusted_length;
+	    // insert new with block address equal to this one
+	if (add_data_to_map(data, cur->disk_address, map) == 0) {
+	    free(data);
+	} else if (act == kSplit) {
+	    data = create_data(kFreeName, kFreeType, new_base, new_length);
+	    if (data != NULL) {
+		    // insert new with block address equal to this one
+		if (add_data_to_map(data, cur->disk_address, map) == 0) {
+		    free(data);
+		}
+	    }
+	}
+    }
+	// renumber disk addresses
+    renumber_disk_addresses(map);
+	// mark changed
+    map->changed = 1;
+    return 1;
+}
+
+
+DPME *
+create_data(const char *name, const char *dptype, u32 base, u32 length)
+{
+    DPME *data;
+
+    data = (DPME *) calloc(1, PBLOCK_SIZE);
+    if (data == NULL) {
+	error(errno, "can't allocate memory for disk buffers");
+    } else {
+	// set data into entry
+	data->dpme_signature = DPME_SIGNATURE;
+	data->dpme_map_entries = 1;
+	data->dpme_pblock_start = base;
+	data->dpme_pblocks = length;
+	strncpy(data->dpme_name, name, DPISTRLEN);
+	strncpy(data->dpme_type, dptype, DPISTRLEN);
+	data->dpme_lblock_start = 0;
+	data->dpme_lblocks = data->dpme_pblocks;
+	if (strcmp(data->dpme_type, kHFSType) == 0) { /* XXX this is gross, fix it! */
+	    data->dpme_flags = APPLE_HFS_FLAGS_VALUE;
+	}
+	else {
+	    dpme_writable_set(data, 1);
+	    dpme_readable_set(data, 1);
+	    dpme_bootable_set(data, 0);
+	    dpme_in_use_set(data, 0);
+	    dpme_allocated_set(data, 1);
+	    dpme_valid_set(data, 1);
+	}
+    }
+    return data;
+}
+
+
+void
+renumber_disk_addresses(partition_map_header *map)
+{
+    partition_map * cur;
+    long index;
+
+	// reset disk addresses
+    cur = map->disk_order;
+    index = 1;
+    while (cur != NULL) {
+	cur->disk_address = index++;
+	cur->data->dpme_map_entries = map->blocks_in_map;
+	cur = cur->next_on_disk;
+    }
+}
+
+
+long
+compute_device_size(partition_map_header *map, partition_map_header *oldmap)
+{
+#ifdef TEST_COMPUTE
+    unsigned long length;
+    struct hd_geometry geometry;
+    struct stat info;
+    loff_t pos;
+#endif
+    char* data;
+    unsigned long l, r, x = 0;
+    long long size;
+    int valid = 0;
+#ifdef TEST_COMPUTE
+    int fd;
+
+    fd = map->fd->fd;
+    printf("\n");
+    if (fstat(fd, &info) < 0) {
+	printf("stat of device failed\n");
+    } else {
+	printf("stat: mode = 0%o, type=%s\n", info.st_mode, 
+		(S_ISREG(info.st_mode)? "Regular":
+		(S_ISBLK(info.st_mode)?"Block":"Other")));
+	printf("size = %d, blocks = %d\n",
+		info.st_size, info.st_size/map->logical_block);
+    }
+
+    if (ioctl(fd, BLKGETSIZE, &length) < 0) {
+	printf("get device size failed\n");
+    } else {
+	printf("BLKGETSIZE:size in blocks = %u\n", length);
+    }
+
+    if (ioctl(fd, HDIO_GETGEO, &geometry) < 0) {
+	printf("get device geometry failed\n");
+    } else {
+	printf("HDIO_GETGEO: heads=%d, sectors=%d, cylinders=%d, start=%d,  total=%d\n",
+		geometry.heads, geometry.sectors,
+		geometry.cylinders, geometry.start,
+		geometry.heads*geometry.sectors*geometry.cylinders);
+    }
+
+    if ((pos = llseek(fd, (loff_t)0, SEEK_END)) < 0) {
+	printf("llseek to end of device failed\n");
+    } else if ((pos = llseek(fd, (loff_t)0, SEEK_CUR)) < 0) {
+	printf("llseek to end of device failed on second try\n");
+    } else {
+	printf("llseek: pos = %d, blocks=%d\n", pos, pos/map->logical_block);
+    }
+#endif
+
+    if (cflag == 0 && oldmap != NULL && oldmap->misc->sbBlkCount != 0) {
+	return (oldmap->misc->sbBlkCount
+		* (oldmap->physical_block / map->logical_block));
+    }
+
+    size = media_total_size(map->m);
+    if (size != 0) {
+    	return (long)(size / map->logical_block);
+    }
+ 
+    // else case
+ 
+    data = (char *) malloc(PBLOCK_SIZE);
+    if (data == NULL) {
+	error(errno, "can't allocate memory for try buffer");
+	x = 0;
+    } else {
+	// double till off end
+	l = 0;
+	r = 1024;
+	while (read_block(map, r, data) != 0) {
+	    l = r;
+	    if (r <= 1024) {
+		r = r * 1024;
+	    } else {
+		r = r * 2;
+	    }
+	    if (r >= 0x80000000) {
+		r = 0xFFFFFFFE;
+		break;
+	    }
+	}
+	// binary search for end
+	while (l <= r) {
+	    x = (r - l) / 2 + l;
+	    if ((valid = read_block(map, x, data)) != 0) {
+		l = x + 1;
+	    } else {
+		if (x > 0) {
+		    r = x - 1;
+		} else {
+		    break;
+		}
+	    }
+	}
+	if (valid != 0) {
+	    x = x + 1;
+	}
+	// printf("size in blocks = %d\n", x);
+	free(data);
+    }
+
+    return x;
+}
+
+
+void
+sync_device_size(partition_map_header *map)
+{
+    Block0 *p;
+    unsigned long size;
+    double d;
+
+    p = map->misc;
+    if (p == NULL) {
+	return;
+    }
+    d = map->media_size;
+    size = (d * map->logical_block) / map->physical_block;
+    if (p->sbBlkCount != size) {
+	p->sbBlkCount = size;
+    }
+}
+
+
+void
+delete_partition_from_map(partition_map *entry)
+{
+    partition_map_header *map;
+    DPME *data;
+
+    if (istrncmp(entry->data->dpme_type, kMapType, DPISTRLEN) == 0) {
+	printf("Can't delete entry for the map itself\n");
+	return;
+    }
+    if (entry->contains_driver) {
+	printf("This program can't install drivers\n");
+	if (get_okay("are you sure you want to delete this driver? [n/y]: ", 0) != 1) {
+	    return;
+	}
+    }
+    data = create_data(kFreeName, kFreeType,
+	    entry->data->dpme_pblock_start, entry->data->dpme_pblocks);
+    if (data == NULL) {
+	return;
+    }
+    if (entry->contains_driver) {
+    	remove_driver(entry);	// update block0 if necessary
+    }
+    free(entry->data);
+    free(entry->HFS_name);
+    entry->HFS_kind = kHFS_not;
+    entry->HFS_name = 0;
+    entry->data = data;
+    combine_entry(entry);
+    map = entry->the_map;
+    renumber_disk_addresses(map);
+    map->changed = 1;
+}
+
+
+int
+contains_driver(partition_map *entry)
+{
+    partition_map_header *map;
+    Block0 *p;
+    DDMap *m;
+    int i;
+    int f;
+    u32 start;
+
+    map = entry->the_map;
+    p = map->misc;
+    if (p == NULL) {
+	return 0;
+    }
+    if (p->sbSig != BLOCK0_SIGNATURE) {
+	return 0;
+    }
+    if (map->logical_block > p->sbBlkSize) {
+	return 0;
+    } else {
+	f = p->sbBlkSize / map->logical_block;
+    }
+    if (p->sbDrvrCount > 0) {
+	m = (DDMap *) p->sbMap;
+	for (i = 0; i < p->sbDrvrCount; i++) {
+	    start = get_align_long(&m[i].ddBlock);
+	    if (entry->data->dpme_pblock_start <= f*start
+		    && f*(start + m[i].ddSize)
+			<= (entry->data->dpme_pblock_start
+			+ entry->data->dpme_pblocks)) {
+		return 1;
+	    }
+	}
+    }
+    return 0;
+}
+
+
+void
+combine_entry(partition_map *entry)
+{
+    partition_map *p;
+    u32 end;
+
+    if (entry == NULL
+	    || istrncmp(entry->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
+	return;
+    }
+    if (entry->next_by_base != NULL) {
+	p = entry->next_by_base;
+	if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
+	    // next is not free
+	} else if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks
+		!= p->data->dpme_pblock_start) {
+	    // next is not contiguous (XXX this is bad)
+	    printf("next entry is not contiguous\n");
+	    // start is already minimum
+	    // new end is maximum of two ends
+	    end = p->data->dpme_pblock_start + p->data->dpme_pblocks;
+	    if (end > entry->data->dpme_pblock_start + entry->data->dpme_pblocks) {
+	    	entry->data->dpme_pblocks = end - entry->data->dpme_pblock_start;
+	    }
+	    entry->data->dpme_lblocks = entry->data->dpme_pblocks;
+	    delete_entry(p);
+	} else {
+	    entry->data->dpme_pblocks += p->data->dpme_pblocks;
+	    entry->data->dpme_lblocks = entry->data->dpme_pblocks;
+	    delete_entry(p);
+	}
+    }
+    if (entry->prev_by_base != NULL) {
+	p = entry->prev_by_base;
+	if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
+	    // previous is not free
+	} else if (p->data->dpme_pblock_start + p->data->dpme_pblocks
+		!= entry->data->dpme_pblock_start) {
+	    // previous is not contiguous (XXX this is bad)
+	    printf("previous entry is not contiguous\n");
+	    // new end is maximum of two ends
+	    end = p->data->dpme_pblock_start + p->data->dpme_pblocks;
+	    if (end < entry->data->dpme_pblock_start + entry->data->dpme_pblocks) {
+		end = entry->data->dpme_pblock_start + entry->data->dpme_pblocks;
+	    }
+	    entry->data->dpme_pblocks = end - p->data->dpme_pblock_start;
+	    // new start is previous entry's start
+	    entry->data->dpme_pblock_start = p->data->dpme_pblock_start;
+	    entry->data->dpme_lblocks = entry->data->dpme_pblocks;
+	    delete_entry(p);
+	} else {
+	    entry->data->dpme_pblock_start = p->data->dpme_pblock_start;
+	    entry->data->dpme_pblocks += p->data->dpme_pblocks;
+	    entry->data->dpme_lblocks = entry->data->dpme_pblocks;
+	    delete_entry(p);
+	}
+    }
+    entry->contains_driver = contains_driver(entry);
+}
+
+
+void
+delete_entry(partition_map *entry)
+{
+    partition_map_header *map;
+    partition_map *p;
+
+    map = entry->the_map;
+    map->blocks_in_map--;
+
+    remove_from_disk_order(entry);
+
+    p = entry->next_by_base;
+    if (map->base_order == entry) {
+	map->base_order = p;
+    }
+    if (p != NULL) {
+	p->prev_by_base = entry->prev_by_base;
+    }
+    if (entry->prev_by_base != NULL) {
+	entry->prev_by_base->next_by_base = p;
+    }
+
+    free(entry->data);
+    free(entry->HFS_name);
+    free(entry);
+}
+
+
+partition_map *
+find_entry_by_disk_address(long index, partition_map_header *map)
+{
+    partition_map * cur;
+
+    cur = map->disk_order;
+    while (cur != NULL) {
+	if (cur->disk_address == index) {
+	    break;
+	}
+	cur = cur->next_on_disk;
+    }
+    return cur;
+}
+
+
+partition_map *
+find_entry_by_type(const char *type_name, partition_map_header *map)
+{
+    partition_map * cur;
+
+    cur = map->base_order;
+    while (cur != NULL) {
+	if (istrncmp(cur->data->dpme_type, type_name, DPISTRLEN) == 0) {
+	    break;
+	}
+	cur = cur->next_by_base;
+    }
+    return cur;
+}
+
+
+void
+move_entry_in_map(long old_index, long index, partition_map_header *map)
+{
+    partition_map * cur;
+
+    cur = find_entry_by_disk_address(old_index, map);
+    if (cur == NULL) {
+	printf("No such partition\n");
+    } else {
+	remove_from_disk_order(cur);
+	cur->disk_address = index;
+	insert_in_disk_order(cur);
+	renumber_disk_addresses(map);
+	map->changed = 1;
+    }
+}
+
+
+void
+remove_from_disk_order(partition_map *entry)
+{
+    partition_map_header *map;
+    partition_map *p;
+
+    map = entry->the_map;
+    p = entry->next_on_disk;
+    if (map->disk_order == entry) {
+	map->disk_order = p;
+    }
+    if (p != NULL) {
+	p->prev_on_disk = entry->prev_on_disk;
+    }
+    if (entry->prev_on_disk != NULL) {
+	entry->prev_on_disk->next_on_disk = p;
+    }
+    entry->next_on_disk = NULL;
+    entry->prev_on_disk = NULL;
+}
+
+
+void
+insert_in_disk_order(partition_map *entry)
+{
+    partition_map_header *map;
+    partition_map * cur;
+
+    // find position in disk list & insert
+    map = entry->the_map;
+    cur = map->disk_order;
+    if (cur == NULL || entry->disk_address <= cur->disk_address) {
+	map->disk_order = entry;
+	entry->next_on_disk = cur;
+	if (cur != NULL) {
+	    cur->prev_on_disk = entry;
+	}
+	entry->prev_on_disk = NULL;
+    } else {
+	for (cur = map->disk_order; cur != NULL; cur = cur->next_on_disk) {
+	    if (cur->disk_address <= entry->disk_address
+		    && (cur->next_on_disk == NULL
+		    || entry->disk_address <= cur->next_on_disk->disk_address)) {
+		entry->next_on_disk = cur->next_on_disk;
+		cur->next_on_disk = entry;
+		entry->prev_on_disk = cur;
+		if (entry->next_on_disk != NULL) {
+		    entry->next_on_disk->prev_on_disk = entry;
+		}
+		break;
+	    }
+	}
+    }
+}
+
+
+void
+insert_in_base_order(partition_map *entry)
+{
+    partition_map_header *map;
+    partition_map * cur;
+
+    // find position in base list & insert
+    map = entry->the_map;
+    cur = map->base_order;
+    if (cur == NULL
+	    || entry->data->dpme_pblock_start <= cur->data->dpme_pblock_start) {
+	map->base_order = entry;
+	entry->next_by_base = cur;
+	if (cur != NULL) {
+	    cur->prev_by_base = entry;
+	}
+	entry->prev_by_base = NULL;
+    } else {
+	for (cur = map->base_order; cur != NULL; cur = cur->next_by_base) {
+	    if (cur->data->dpme_pblock_start <= entry->data->dpme_pblock_start
+		    && (cur->next_by_base == NULL
+		    || entry->data->dpme_pblock_start
+			<= cur->next_by_base->data->dpme_pblock_start)) {
+		entry->next_by_base = cur->next_by_base;
+		cur->next_by_base = entry;
+		entry->prev_by_base = cur;
+		if (entry->next_by_base != NULL) {
+		    entry->next_by_base->prev_by_base = entry;
+		}
+		break;
+	    }
+	}
+    }
+}
+
+
+void
+resize_map(long new_size, partition_map_header *map)
+{
+    partition_map * entry;
+    partition_map * next;
+    int incr;
+
+    // find map entry
+    entry = find_entry_by_type(kMapType, map);
+
+    if (entry == NULL) {
+	printf("Couldn't find entry for map!\n");
+	return;
+    }
+    next = entry->next_by_base;
+
+	// same size
+    if (new_size == entry->data->dpme_pblocks) {
+	// do nothing
+	return;
+    }
+
+	// make it smaller
+    if (new_size < entry->data->dpme_pblocks) {
+	if (next == NULL
+		|| istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
+	    incr = 1;
+	} else {
+	    incr = 0;
+	}
+	if (new_size < map->blocks_in_map + incr) {
+	    printf("New size would be too small\n");
+	    return;
+	}
+	goto doit;
+    }
+
+	// make it larger
+    if (next == NULL
+	    || istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) {
+	printf("No free space to expand into\n");
+	return;
+    }
+    if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks
+	    != next->data->dpme_pblock_start) {
+	printf("No contiguous free space to expand into\n");
+	return;
+    }
+    if (new_size > entry->data->dpme_pblocks + next->data->dpme_pblocks) {
+	printf("No enough free space\n");
+	return;
+    }
+doit:
+    entry->data->dpme_type[0] = 0;
+    delete_partition_from_map(entry);
+    add_partition_to_map("Apple", kMapType, 1, new_size, map);
+    map->maximum_in_map = new_size;
+}
+
+
+void
+remove_driver(partition_map *entry)
+{
+    partition_map_header *map;
+    Block0 *p;
+    DDMap *m;
+    int i;
+    int j;
+    int f;
+    u32 start;
+
+    map = entry->the_map;
+    p = map->misc;
+    if (p == NULL) {
+	return;
+    }
+    if (p->sbSig != BLOCK0_SIGNATURE) {
+	return;
+    }
+    if (map->logical_block > p->sbBlkSize) {
+	/* this is not supposed to happen, but let's just ignore it. */
+	return;
+    } else {
+	/*
+	 * compute the factor to convert the block numbers in block0
+	 * into partition map block numbers.
+	 */
+	f = p->sbBlkSize / map->logical_block;
+    }
+    if (p->sbDrvrCount > 0) {
+	m = (DDMap *) p->sbMap;
+	for (i = 0; i < p->sbDrvrCount; i++) {
+	    start = get_align_long(&m[i].ddBlock);
+
+	    /* zap the driver if it is wholly contained in the partition */
+	    if (entry->data->dpme_pblock_start <= f*start
+		    && f*(start + m[i].ddSize)
+			<= (entry->data->dpme_pblock_start
+			+ entry->data->dpme_pblocks)) {
+		// delete this driver
+		// by copying down later ones and zapping the last
+		for (j = i+1; j < p->sbDrvrCount; j++, i++) {
+		   put_align_long(get_align_long(&m[j].ddBlock), &m[i].ddBlock);
+		   m[i].ddSize = m[j].ddSize;
+		   m[i].ddType = m[j].ddType;
+		}
+	        put_align_long(0, &m[i].ddBlock);
+		m[i].ddSize = 0;
+		m[i].ddType = 0;
+		p->sbDrvrCount -= 1;
+		return; /* XXX if we continue we will delete other drivers? */
+	    }
+	}
+    }
+}
+
+int
+read_block(partition_map_header *map, unsigned long num, char *buf)
+{
+//printf("read block %d\n", num);
+    return read_media(map->m, ((long long) num) * map->logical_block,
+    		PBLOCK_SIZE, (void *)buf);
+}
+
+
+int
+write_block(partition_map_header *map, unsigned long num, char *buf)
+{
+    return write_media(map->m, ((long long) num) * map->logical_block,
+    		PBLOCK_SIZE, (void *)buf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/partition_map.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,119 @@
+//
+// partition_map.h - partition map routines
+//
+// Written by Eryk Vershen
+//
+
+/*
+ * Copyright 1996,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __partition_map__
+#define __partition_map__
+
+#include "dpme.h"
+#include "media.h"
+
+
+//
+// Defines
+//
+#define	PBLOCK_SIZE	512
+#define	MAX_LINUX_MAP	15
+
+
+//
+// Types
+//
+struct partition_map_header {
+    MEDIA m;
+    char *name;
+    struct partition_map * disk_order;
+    struct partition_map * base_order;
+    Block0 *misc;
+    int writeable;
+    int changed;
+    int written;
+    int physical_block;		// must be == sbBlockSize
+    int logical_block;		// must be <= physical_block
+    int blocks_in_map;
+    int maximum_in_map;
+    unsigned long media_size;	// in logical_blocks
+};
+typedef struct partition_map_header partition_map_header;
+
+struct partition_map {
+    struct partition_map * next_on_disk;
+    struct partition_map * prev_on_disk;
+    struct partition_map * next_by_base;
+    struct partition_map * prev_by_base;
+    long disk_address;
+    struct partition_map_header * the_map;
+    int contains_driver;
+    DPME *data;
+    int HFS_kind;
+    char *HFS_name;
+};
+typedef struct partition_map partition_map;
+
+/* Identifies the HFS kind. */
+enum {
+    kHFS_not       =   0,	// ' '
+    kHFS_std       =   1,	// 'h'
+    kHFS_embed     =   2,	// 'e'
+    kHFS_plus      =   3	// '+'
+};
+
+
+//
+// Global Constants
+//
+extern const char * kFreeType;
+extern const char * kMapType;
+extern const char * kUnixType;
+extern const char * kHFSType;
+extern const char * kFreeName;
+extern const char * kPatchType;
+
+
+//
+// Global Variables
+//
+extern int rflag;
+extern int interactive;
+extern int dflag;
+
+
+//
+// Forward declarations
+//
+int add_partition_to_map(const char *name, const char *dptype, u32 base, u32 length, partition_map_header *map);
+void close_partition_map(partition_map_header *map);
+partition_map_header* create_partition_map(char *name, partition_map_header *oldmap);
+void delete_partition_from_map(partition_map *entry);
+partition_map* find_entry_by_disk_address(long index, partition_map_header *map);
+partition_map* find_entry_by_type(const char *type_name, partition_map_header *map);
+partition_map_header* init_partition_map(char *name, partition_map_header* oldmap);
+void move_entry_in_map(long old_index, long index, partition_map_header *map);
+partition_map_header* open_partition_map(char *name, int *valid_file, int ask_logical_size);
+void resize_map(long new_size, partition_map_header *map);
+void write_partition_map(partition_map_header *map);
+
+#endif /* __partition_map__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/pathname.c	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,247 @@
+/*
+ * pathname.c -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+// for strncmp()
+#include <string.h>
+
+#include "pathname.h"
+#include "file_media.h"
+
+#if !defined(__linux__) && !defined(__unix__)
+#include "SCSI_media.h"
+#include "ATA_media.h"
+#endif
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+
+
+/*
+ * Forward declarations
+ */
+
+
+/*
+ * Routines
+ */
+
+/*
+ * Note that open_pathname_as_media() and get_linux_name() have almost
+ * identical structures.  If one changes the other must also!
+ */
+MEDIA
+open_pathname_as_media(char *path, int oflag)
+{
+    MEDIA	m = 0;
+#if !defined(__linux__) && !defined(__unix__)
+    long	id;
+    long	bus;
+	
+    if (strncmp("/dev/", path, 5) == 0) {
+	if (strncmp("/dev/scsi", path, 9) == 0) {
+	    if (path[9] >= '0' && path[9] <= '7' && path[10] == 0) {
+		// scsi[0-7]
+		id = path[9] - '0';
+		m = open_old_scsi_as_media(id);
+	    } else if (path[9] >= '0' && path[9] <= '7' && path[10] == '.'
+		    && path[11] >= '0' && path[11] <= '7' && path[12] == 0) {
+		// scsi[0-7].[0-7]
+		id = path[11] - '0';
+		bus = path[9] - '0';
+		m = open_scsi_as_media(bus, id);
+	    }
+	} else if (strncmp("/dev/ata", path, 8) == 0
+		|| strncmp("/dev/ide", path, 8) == 0) {
+	    if (path[8] >= '0' && path[8] <= '7' && path[9] == 0) {
+		// ata[0-7], ide[0-7]
+		bus = path[8] - '0';
+		m = open_ata_as_media(bus, 0);
+	    } else if (path[8] >= '0' && path[8] <= '7' && path[9] == '.'
+		    && path[10] >= '0' && path[10] <= '1' && path[11] == 0) {
+		// ata[0-7].[0-1], ide[0-7].[0-1]
+		id = path[10] - '0';
+		bus = path[8] - '0';
+		m = open_ata_as_media(bus, id);
+	    }
+	} else if (strncmp("/dev/sd", path, 7) == 0) {
+	    if (path[7] >= 'a' && path[7] <= 'z' && path[8] == 0) {
+		// sd[a-z]
+		id = path[7] - 'a';
+		m = open_linux_scsi_as_media(id, 0);
+	    } else if (path[7] >= 'a' && path[7] <= 'z' && path[8] == '.'
+		    && path[9] >= 'a' && path[9] <= 'z' && path[10] == 0) {
+		// sd[a-z][a-z]
+		bus = path[7] - 'a';
+		id = path[9] - 'a';
+		id += bus * 26;
+		m = open_linux_scsi_as_media(id, 0);
+	    }
+	} else if (strncmp("/dev/scd", path, 8) == 0) {
+	    if (path[8] >= '0' && path[8] <= '9' && path[9] == 0) {
+		// scd[0-9]
+		id = path[8] - '0';
+		m = open_linux_scsi_as_media(id, 1);
+	    }
+	} else if (strncmp("/dev/hd", path, 7) == 0) {
+	    if (path[7] >= 'a' && path[7] <= 'z' && path[8] == 0) {
+		// hd[a-z]
+		id = path[7] - 'a';
+		m = open_linux_ata_as_media(id);
+	    }
+	}
+    } else
+#endif
+
+    {
+	m = open_file_as_media(path, oflag);
+    }
+    return m;
+}
+
+
+char *
+get_linux_name(char *path)
+{
+    char	*result = 0;
+#if !defined(__linux__) && !defined(__unix__)
+    long	id;
+    long	bus;
+
+    if (strncmp("/dev/", path, 5) == 0) {
+	if (strncmp("/dev/scsi", path, 9) == 0) {
+	    if (path[9] >= '0' && path[9] <= '7' && path[10] == 0) {
+		/* old scsi */
+		// scsi[0-7]
+		id = path[9] - '0';
+		result = linux_old_scsi_name(id);
+	    } else if (path[9] >= '0' && path[9] <= '7' && path[10] == '.'
+		    && path[11] >= '0' && path[11] <= '7' && path[12] == 0) {
+		/* new scsi */
+		// scsi[0-7].[0-7]
+		id = path[11] - '0';
+		bus = path[9] - '0';
+		result = linux_scsi_name(bus, id);
+	    }
+	} else if (strncmp("/dev/ata", path, 8) == 0
+		|| strncmp("/dev/ide", path, 8) == 0) {
+	    if (path[8] >= '0' && path[8] <= '7' && path[9] == 0) {
+		/* ata/ide - master device */
+		// ata[0-7], ide[0-7]
+		bus = path[8] - '0';
+		result = linux_ata_name(bus, 0);
+	    } else if (path[8] >= '0' && path[8] <= '7' && path[9] == '.'
+		    && path[10] >= '0' && path[10] <= '1' && path[11] == 0) {
+		/* ata/ide */
+		// ata[0-7].[0-1], ide[0-7].[0-1]
+		id = path[10] - '0';
+		bus = path[8] - '0';
+		result = linux_ata_name(bus, id);
+	    }
+	}
+    }
+#endif
+    
+    return result;
+}
+
+
+MEDIA_ITERATOR
+first_media_kind(long *state)
+{
+    *state = 0;
+    return next_media_kind(state);
+}
+
+
+MEDIA_ITERATOR
+next_media_kind(long *state)
+{
+    MEDIA_ITERATOR result;
+    long index;
+
+    result = 0;
+    index = *state;
+
+    switch (index) {
+    case 0:
+#if defined(__linux__) || defined(__unix__)
+	result = create_file_iterator();
+#endif
+	index = 1;
+	if (result != 0) {
+		break;
+	}
+	/* fall through to next interface */
+
+    case 1:
+#if !defined(__linux__) && !defined(__unix__)
+	result = create_ata_iterator();
+#endif
+	index = 2;
+	if (result != 0) {
+		break;
+	}
+	/* fall through to next interface */
+
+    case 2:
+#if !defined(__linux__) && !defined(__unix__)
+	result = create_scsi_iterator();
+#endif
+	index = 3;
+	if (result != 0) {
+		break;
+	}
+	/* fall through to next interface */
+
+    case 3:
+    default:
+	break;
+    }
+ 
+    *state = index;
+    return result;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/pathname.h	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,62 @@
+/*
+ * pathname.h -
+ *
+ * Written by Eryk Vershen
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __pathname__
+#define __pathname__
+
+#include "media.h"
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+
+
+/*
+ * Forward declarations
+ */
+MEDIA open_pathname_as_media(char *path, int oflag);
+MEDIA_ITERATOR first_media_kind(long *state);
+MEDIA_ITERATOR next_media_kind(long *state);
+char *get_linux_name(char *name);
+
+#endif /* __pathname__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/pdisk/pdisk.8	Tue Jul 09 05:49:02 2002 +0000
@@ -0,0 +1,222 @@
+.TH PDISK 8 "16 May 2000" "LinuxPPC" "Linux Programmer's Manual"
+.SH NAME
+pdisk \- Apple partition table editor for Linux
+.SH SYNOPSIS
+.B pdisk
+.B "[\-h|\--help]"
+.br
+.B pdisk
+.B "[\-i|\--interactive]"
+.br
+.B pdisk
+.B "[\-l|\--list [name ...]]"
+.br
+.B pdisk
+device ...
+.br
+.B pdisk
+.B "[\-v|\--version] [\-r|\--readonly] [\-abbr] [\--logical] [\-c|\--compute_size] [\-p|\--pname] [\-d|\--debug]"
+.SH DESCRIPTION
+.B pdisk
+is a menu driven program which partitions disks using the standard Apple
+disk partitioning scheme described in "Inside Macintosh: Devices".
+It does not support the intel/dos partitioning scheme supported by 
+.BR fdisk .
+The
+.I device
+is usually one of the following:
+
+.nf
+.RS
+/dev/sda
+/dev/sdb
+/dev/sdc
+/dev/sdd
+/dev/sde
+/dev/sdf
+/dev/sdg
+/dev/hda
+/dev/hdb
+/dev/hdc
+/dev/hdd
+
+.RE
+.fi
+In standard Linux /dev/sda is the first hard disk on the SCSI bus (i.e. the
+one with the lowest id), /dev/sdb is the second hard disk, and so on.
+The
+.I partition
+is a
+.I device
+name followed by a partition number.
+The partition number is the index (starting from one) of the partition
+map entry in the partition map.
+For example,
+.B /dev/sda2
+is the partition described by the second entry in the partiton map on /dev/sda.
+
+.SH OPTIONS
+.TP
+.B \-v | \--version
+Prints version number of the
+.B pdisk
+program.
+.TP
+.B \-h | \--help
+Prints a rather lame set of help messages for the
+.B pdisk
+program.
+.TP
+.B \-i | \--interactive
+Causes
+.B pdisk
+to go into an interactive mode similar to the MacOS version of the program.
+.TP
+.B \-l | \--list
+If no
+.IR name s
+are present then lists the partition tables for
+.BR /dev/sda ,
+.BR /dev/sdb ,
+etc. ,
+.BR /dev/hda ,
+.BR /dev/hdb ,
+etc. , and
+.BR /dev/scd0 ,
+.BR /dev/scd1 ,
+etc..
+Otherwise, lists the partition tables for the specified
+.IR name s.
+.TP
+.B \-r | \--readonly
+Prevents
+.B pdisk
+from writing to the device.
+.TP
+.B \-c | \--compute_size
+Causes
+.B pdisk
+to always ignore the device size listed in the partition table
+and compute the device size by other means.
+.TP
+.B \-p | \--pname
+Since the default behaviour of
+.B pdisk
+is to show the Mac volume name, this flag forces
+.B pdisk
+to show the partition name instead.
+.TP
+.B \-d | \--debug
+Turns on debugging.  Doesn't add that much output, but does add
+a new command 'x' to the editing commands that accesses an
+eclectic bunch of undocumented functionality.
+.SH "Editing Partition Tables"
+An argument which is simply the name of a
+.I device
+indicates that
+.B pdisk
+should edit the partition table of that device.
+
+The current top level editing commands are:
+
+.nf
+.RS
+h    command help
+p    print the partition table
+P    (print ordered by base address)
+i    initialize partition map
+s    change size of partition map
+c    create new partition