From david@uow.edu.au Tue Nov 28 10:05:23 CST 2000 Dennis Jenkins writes: >Does anyone have any C/C++ code that can read (write too?!?) files from >a disk image of a prodos disk under win32/linux/dos/anything? I found >some code to do it for dos 3.3, and I'm looking for the prodos >equivalent. I have some code that will (almost) copy all the files from a ProDOS image and make a directory tree on the system on which it is run (eg UNIX). Feel free to adapt this code for your own use. Note that it does not support Tree files. This is just based on the code in Apple's ProDOS Technical Reference Manual for recursively reading a directory. Run it as "protar < image_file". Let me know if you find it useful. prodos.h: /* * Directory pointers */ #define Prev(x) (x[0] + (x[1] << 8)) #define Next(x) (x[2] + (x[3] << 8)) /* * Fields common to vol header, sub dir headers & file entries */ #define Storage_type(x) (x[0] >> 4) #define Name_length(x) (x[0] & 15) #define Active(x) (x[0] != 0) #define File_name(x) (x + 1) #define Creation(x) (x[0x1a] + (x[0x1b] << 8) + (x[0x18] << 16) + (x[0x19] << 24)) #define Version(x) (x[0x1c]) #define Min_version(x) (x[0x1d]) #define Access(x) (x[0x1e]) /* * File entry only */ #define File_type(x) (x[0x10]) #define Key_pointer(x) (x[0x11] + (x[0x12] << 8)) #define Blocks_used(x) (x[0x13] + (x[0x14] << 8)) #define Eof(x) (x[0x15] + (x[0x16] << 8) + (x[0x17] << 16)) #define Aux_type(x) (x[0x1f] + (x[0x20] << 8)) #define Last_mod(x) (x[0x23] + (x[0x24] << 8) + (x[0x21] << 16) + (x[0x22] << 24)) #define Header_pointer(x) (x[0x25] + (x[0x26] << 8)) /* * Vol & sub dir headers */ #define Entry_length(x) (x[0x1f]) #define Entries_per_block(x) (x[0x20]) #define File_count(x) (x[0x21] + (x[0x22] << 8)) /* * Vol header only */ #define Bit_map_pointer(x) (x[0x23] + (x[0x24] << 8)) #define Total_blocks(x) (x[0x25] + (x[0x26] << 8)) /* * Sub dir header only */ #define Parent_entry_number(x) (x[0x25]) #define Parent_entry_length(x) (x[0x26]) #define Parent_pointer(x) (x[0x23] + (x[0x24] << 8)) /* * Date format */ #define year(x) ((x >> 25) & 127) #define month(x) ((x >> 21) & 15) #define day(x) ((x >> 16) & 31) #define hour(x) ((x >> 8) & 31) #define minute(x) (x & 63) /* * Indirect block function */ #define indirect(block,index) (block[index] + (block[index + 256] << 8)) /* * ProDOS constants */ #define PRODOS_BS 512 #define PRODOS_ROOT 2 ------------------------------------------------------------------------------- protar.c: #include #include #include "prodos.h" extern long lseek(); extern char *sprintf(); char err[80], filename[64]; main(argc, argv) int argc; char *argv[]; { ReadDir(PRODOS_ROOT, 0); } ReadDir(blocknum, filelen) unsigned blocknum, filelen; { unsigned char block[PRODOS_BS]; int elen, epb, fc, be, ae; unsigned char *ep; if (lseek(0, (long) (PRODOS_BS * blocknum), 0) == -1L || read(0, (char *) block, PRODOS_BS) == -1) { sprintf(err, "Error reading block %d", blocknum); perror(err); return; } ep = block + 4; if (filelen == 0) { sprintf(filename, "%.*s", Name_length(ep), File_name(ep)); filelen = Name_length(ep); } elen = Entry_length(ep); epb = Entries_per_block(ep); fc = File_count(ep); ep += elen; be = 2; ae = 0; while (ae < fc) { if (Active(ep)) { ProcessEntry(ep, filelen); ++ae; } if (ae < fc) if (be == epb) { if (Next(block) == 0) { fprintf(stderr, "Short Directory. ae = %d fc = %d blocknum = %d\n", ae, fc, blocknum); return; } blocknum = Next(block); if (lseek(0, (long) (PRODOS_BS * blocknum), 0) == -1L || read(0, (char *) block, PRODOS_BS) == -1) { sprintf(err, "Error reading block %d", blocknum); perror(err); return; } be = 1; ep = block + 4; } else { ep += elen; ++be; } } } ProcessEntry(ep, filelen) unsigned char *ep; unsigned filelen; { sprintf(filename + filelen, "/%.*s", Name_length(ep), File_name(ep)); filelen += Name_length(ep) + 1; ProcessFile(ep); if (File_type(ep) == 0x0f) ReadDir(Key_pointer(ep), filelen); filelen -= Name_length(ep) + 1; } unsigned char masterblock[PRODOS_BS], ptrblock[PRODOS_BS], datablock[PRODOS_BS]; ProcessFile(ep) unsigned char *ep; { int fd, len, i; #ifdef DEBUG puts(filename); #else switch (Storage_type(ep)) { case 0: /* Inactive */ break; case 1: /* Seedling */ if ((fd = open(filename, O_WRONLY|O_CREAT, 0777)) < 0) perror(filename); else { len = Eof(ep); if (lseek(0, (long) (PRODOS_BS * Key_pointer(ep)), 0) == -1L || read(0, datablock, len) != len || write(fd, datablock, len) != len || close(fd) == -1) perror(filename); } break; case 2: /* Sapling */ if ((fd = open(filename, O_WRONLY|O_CREAT, 0777)) < 0) perror(filename); else { len = Eof(ep); if (lseek(0, (long) (PRODOS_BS * Key_pointer(ep)), 0) == -1L || read(0, ptrblock, PRODOS_BS) != PRODOS_BS) perror(filename); else { for (i = 0; len >= PRODOS_BS; ++i, len -= PRODOS_BS) if (lseek(0, (long) PRODOS_BS * indirect(ptrblock, i), 0) == -1L || read(0, datablock, PRODOS_BS) != PRODOS_BS || write(fd, datablock, PRODOS_BS) != PRODOS_BS) perror(filename); if (len) if (lseek(0, (long) PRODOS_BS * indirect(ptrblock, i), 0) == -1L || read(0, datablock, len) != len || write(fd, datablock, len) != len) perror(filename); if (close(fd) == -1) perror(filename); } } break; case 3: /* Tree */ break; case 0xd: /* SubDir file entry */ if (mkdir(filename, 0777) == -1) perror(filename); break; case 0xe: /* SubDir header */ break; case 0xf: /* Vol header */ break; default: /* ??? */ fprintf(stderr, "%s: unknown storage_type %x\n", filename, Storage_type(ep)); break; } #endif } -- David Wilson School of IT & CS, Uni of Wollongong, Australia