From 76231a67e0831bfe4296f4a18d781551175bafb3 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Wed, 28 Jul 2021 23:02:18 -0400 Subject: [PATCH] prodos: can handle .dsk and .po images now interleave is a pain --- utils/prodos-utils/prodos.c | 58 +++--- utils/prodos-utils/prodos.h | 44 ++++- utils/prodos-utils/prodos_dump.c | 226 ++++++++++++++-------- utils/prodos-utils/prodos_read.c | 59 +++++- utils/prodos-utils/prodos_volume_bitmap.c | 26 ++- 5 files changed, 290 insertions(+), 123 deletions(-) diff --git a/utils/prodos-utils/prodos.c b/utils/prodos-utils/prodos.c index 32c3e780..c77a3cda 100644 --- a/utils/prodos-utils/prodos.c +++ b/utils/prodos-utils/prodos.c @@ -22,14 +22,16 @@ static unsigned char get_low_byte(int value) { } /* Read volume directory into a buffer */ -static int prodos_read_voldir(int fd, struct voldir_t *voldir) { +static int prodos_read_voldir(int fd, struct voldir_t *voldir, int interleave) { int result; unsigned char voldir_buffer[PRODOS_BYTES_PER_BLOCK]; - /* read in VOLDIR */ + voldir->interleave=interleave; + + /* read in VOLDIR KEY Block*/ voldir->fd=fd; - result=prodos_read_block(voldir,voldir_buffer,PRODOS_VOLDIR_BLOCK); + result=prodos_read_block(voldir,voldir_buffer,PRODOS_VOLDIR_KEY_BLOCK); if (result<0) { fprintf(stderr,"Error reading VOLDIR\n"); @@ -56,18 +58,24 @@ static int prodos_read_voldir(int fd, struct voldir_t *voldir) { voldir->min_version=voldir_buffer[0x21]; voldir->access=voldir_buffer[0x22]; voldir->entry_length=voldir_buffer[0x23]; + + if (voldir->entry_length!=PRODOS_FILE_DESC_LEN) { + printf("Error! Unexpected desc len %d\n", + voldir->entry_length); + } + voldir->entries_per_block=voldir_buffer[0x24]; voldir->file_count=voldir_buffer[0x25]|(voldir_buffer[0x26]<<8); voldir->bit_map_pointer=voldir_buffer[0x27]|(voldir_buffer[0x28]<<8); voldir->total_blocks=voldir_buffer[0x29]|(voldir_buffer[0x2A]<<8); - + voldir->next_block=voldir_buffer[0x2]|(voldir_buffer[0x3]<<8); return 0; } /* Checks if "filename" exists */ - /* returns entry/track/sector */ + /* returns entry/block */ static int prodos_check_file_exists(int fd, char *filename, int file_deleted) { @@ -79,9 +87,10 @@ static int prodos_check_file_exists(int fd, struct voldir_t voldir; unsigned char catalog_buffer[PRODOS_BYTES_PER_BLOCK]; - /* read the VOLDIR into buffer */ - prodos_read_voldir(fd,&voldir); #if 0 + /* read the VOLDIR into buffer */ + prodos_read_voldir(fd,&voldir,interleave); + /* FIXME: we have a function for this */ /* get the catalog track and sector from the VTOC */ catalog_track=voldir[VTOC_CATALOG_T]; @@ -133,12 +142,13 @@ repeat_catalog: return -1; } -static int prodos_free_sector(struct voldir_t *voldir,int fd,int track,int sector) { +static int prodos_free_block(struct voldir_t *voldir,int block) { int result; - /* mark as free in VTOC */ - prodos_voldir_free_sector(voldir,track,sector); + /* mark as free using VOLDIR */ + result=prodos_voldir_free_block(voldir,block); + #if 0 /* write modified VTOC back out */ lseek(fd,DISK_OFFSET(PRODOS_VOLDIR_TRACK,PRODOS_VOLDIR_BLOCK),SEEK_SET); @@ -148,6 +158,7 @@ static int prodos_free_sector(struct voldir_t *voldir,int fd,int track,int secto fprintf(stderr,"Error on I/O\n"); } #endif + return 0; } @@ -916,6 +927,7 @@ int main(int argc, char **argv) { char image[BUFSIZ]; unsigned char type='b'; int dos_fd=0,i; + int interleave=PRODOS_INTERLEAVE_PRODOS; int command,catalog_entry; char temp_string[BUFSIZ]; @@ -944,16 +956,6 @@ int main(int argc, char **argv) { length=strtol(optarg,&endptr,0); if (debug) fprintf(stderr,"Length=%d\n",address); break; -#if 0 - case 't': - track=strtol(optarg,&endptr,0); - if (debug) fprintf(stderr,"Track=%d\n",address); - break; - case 's': - sector=strtol(optarg,&endptr,0); - if (debug) fprintf(stderr,"Sector=%d\n",address); - break; -#endif case 'v': display_help(argv[0],1); return 0; @@ -980,7 +982,19 @@ int main(int argc, char **argv) { fprintf(stderr,"Error opening disk_image: %s\n",image); return -1; } - prodos_read_voldir(dos_fd,&voldir); + + if (debug) { + printf("checking extension: %s\n",&image[strlen(image)-4]); + } + + if (strlen(image)>4) { + if (!strncmp(&image[strlen(image)-4],".dsk",4)) { + if (debug) printf("Detected DOS33\n"); + interleave=PRODOS_INTERLEAVE_DOS33; + } + } + + prodos_read_voldir(dos_fd,&voldir,interleave); /* Move to next argument */ optind++; @@ -1057,7 +1071,7 @@ int main(int argc, char **argv) { break; case COMMAND_CATALOG: - prodos_read_voldir(dos_fd,&voldir); + prodos_read_voldir(dos_fd,&voldir,interleave); prodos_catalog(dos_fd,&voldir); break; diff --git a/utils/prodos-utils/prodos.h b/utils/prodos-utils/prodos.h index 91644ff1..2e2408bd 100644 --- a/utils/prodos-utils/prodos.h +++ b/utils/prodos-utils/prodos.h @@ -5,11 +5,25 @@ #define BLOCKS_PER_TRACK 0x8 #define PRODOS_BYTES_PER_BLOCK 0x200 -#define PRODOS_VOLDIR_TRACK 0x0 -#define PRODOS_VOLDIR_BLOCK 2 +#define PRODOS_INTERLEAVE_PRODOS 0x0 +#define PRODOS_INTERLEAVE_DOS33 0x1 + + +#define PRODOS_VOLDIR_KEY_BLOCK 0x02 // key block + +#define PRODOS_FILE_DESC_LEN 0x27 + +#define PRODOS_FILE_DELETED 0x00 +#define PRODOS_FILE_SEEDLING 0x01 +#define PRODOS_FILE_SAPLING 0x02 +#define PRODOS_FILE_TREE 0x03 +#define PRODOS_FILE_SUBDIR 0x0d +#define PRODOS_FILE_SUBDIR_HDR 0x0e +#define PRODOS_FILE_VOLUME_HDR 0x0f struct voldir_t { int fd; + int interleave; unsigned char storage_type; unsigned char name_length; unsigned char version; @@ -17,6 +31,7 @@ struct voldir_t { unsigned char access; unsigned char entry_length; unsigned char entries_per_block; + unsigned short next_block; unsigned short file_count; unsigned short bit_map_pointer; unsigned short total_blocks; @@ -24,6 +39,23 @@ struct voldir_t { unsigned int creation_time; }; +struct file_entry_t { + unsigned char storage_type; + unsigned char name_length; + unsigned char file_name[16]; + unsigned char file_type; + unsigned short key_pointer; + unsigned short blocks_used; + int eof; + int creation_time; + unsigned char version; + unsigned char min_version; + unsigned char access; + unsigned short aux_type; + int last_mod; + unsigned short header_pointer; +}; + /* CATALOG_VALUES */ #define CATALOG_NEXT_T 0x01 #define CATALOG_NEXT_S 0x02 @@ -61,11 +93,11 @@ struct voldir_t { /* prodos_volume_bitmap.c */ int prodos_voldir_free_space(struct voldir_t *voldir); -void prodos_voldir_free_sector(struct voldir_t *voldir, int track, int sector); -void prodos_voldir_reserve_sector(struct voldir_t *voldir, int track, int sector); +int prodos_voldir_free_block(struct voldir_t *voldir, int block); +int prodos_voldir_reserve_block(struct voldir_t *voldir, int block); void prodos_voldir_dump_bitmap(struct voldir_t *voldir); -int prodos_voldir_find_free_sector(struct voldir_t *voldir, - int *found_track, int *found_sector); +int prodos_voldir_find_free_block(struct voldir_t *voldir, + int *found_block); /* prodos_catalog.c */ unsigned char prodos_char_to_type(char type, int lock); diff --git a/utils/prodos-utils/prodos_dump.c b/utils/prodos-utils/prodos_dump.c index ba512a64..52135017 100644 --- a/utils/prodos-utils/prodos_dump.c +++ b/utils/prodos-utils/prodos_dump.c @@ -52,6 +52,96 @@ static void prodos_print_access(int access) { if (access&0x1) printf("VOLDIR_READ "); } + + +static void prodos_print_storage_type(int type) { + + switch(type) { + + case PRODOS_FILE_DELETED: + printf("Deleted\n"); + break; + case PRODOS_FILE_SEEDLING: + printf("Seedling\n"); + break; + case PRODOS_FILE_SAPLING: + printf("Sapling\n"); + break; + case PRODOS_FILE_TREE: + printf("Tree\n"); + break; + case PRODOS_FILE_SUBDIR: + printf("Subdir\n"); + break; + case PRODOS_FILE_SUBDIR_HDR: + printf("Subdir Header\n"); + break; + case PRODOS_FILE_VOLUME_HDR: + printf("Volume Header\n"); + break; + default: + printf("Unknown\n"); + break; + } +} + +static void prodos_print_file_type(int type) { + + switch(type) { + case 0x00: + printf("Typeless\n"); + break; + case 0x01: + printf("BAD: Bad Blocks\n"); + break; + case 0x04: + printf("TXT: ASCII Text\n"); + break; + case 0x06: + printf("BIN: Binary\n"); + break; + case 0x0f: + printf("DIR: Directory\n"); + break; + case 0x19: + printf("ADB: AppleWorks Database\n"); + break; + case 0x1A: + printf("AWP: AppleWorks Word Processing\n"); + break; + case 0x1B: + printf("ASP: AppleWorks Spreadsheet\n"); + break; + case 0xEF: + printf("PAS: PASCAL\n"); + break; + case 0xF0: + printf("CMD: Command\n"); + break; + case 0xF1: case 0xF2: case 0xF3: case 0xF4: + case 0xF5: case 0xF6: case 0xF7: case 0xF8: + printf("User defined %x\n",type); + break; + case 0xFC: + printf("BAS: Applesoft BASIC\n"); + break; + case 0xFD: + printf("VAR: Applesoft variables\n"); + break; + case 0xFE: + printf("REL: Relocatable Object\n"); + break; + case 0xFF: + printf("SYS: ProDOS system\n"); + break; + + default: + printf("Unknown\n"); + break; + } +} + + static void dump_voldir(struct voldir_t *voldir) { unsigned char volume_name[16]; @@ -88,104 +178,82 @@ static void dump_voldir(struct voldir_t *voldir) { int prodos_dump(struct voldir_t *voldir, int fd) { - int num_tracks,catalog_t,catalog_s,file,ts_t,ts_s,ts_total; - int track,sector; + int catalog_block,catalog_offset,file; int i; int deleted=0; char temp_string[BUFSIZ]; - unsigned char tslist[PRODOS_BYTES_PER_BLOCK]; unsigned char catalog_buffer[PRODOS_BYTES_PER_BLOCK]; + unsigned char file_desc[PRODOS_FILE_DESC_LEN]; int result; + struct file_entry_t file_entry; dump_voldir(voldir); prodos_voldir_dump_bitmap(voldir); + catalog_block=PRODOS_VOLDIR_KEY_BLOCK; + catalog_offset=1; /* skip the header */ + + while(1) { + + result=prodos_read_block(voldir,catalog_buffer,catalog_block); + if (result<0) fprintf(stderr,"Error on I/O\n"); + + // dump_block(catalog_buffer); + + for(file=catalog_offset; + fileentries_per_block;file++) { + + memcpy(file_desc, + catalog_buffer+4+file*PRODOS_FILE_DESC_LEN, + PRODOS_FILE_DESC_LEN); + + file_entry.storage_type=(file_desc[0]>>4)&0xf; + file_entry.name_length=file_desc[0]&0xf; + memcpy(&file_entry.file_name[0],&file_desc[1], + file_entry.name_length); + file_entry.file_name[file_entry.name_length]=0; + + if (file_entry.storage_type==PRODOS_FILE_DELETED) continue; + + printf("\n\n"); + printf("FILE %d: %s\n",file,file_entry.file_name); + printf("\t"); + prodos_print_storage_type(file_entry.storage_type); + + printf("\t"); + file_entry.file_type=file_desc[0x10]; + prodos_print_file_type(file_entry.file_type); + #if 0 -repeat_catalog: - printf("\nCatalog Sector $%02X/$%02x\n",catalog_t,catalog_s); - lseek(fd,DISK_OFFSET(catalog_t,catalog_s),SEEK_SET); - result=read(fd,catalog_buffer,PRODOS_BYTES_PER_BLOCK); +struct file_entry_t { + unsigned char file_type; + unsigned short key_pointer; + unsigned short blocks_used; + int eof; + int creation_time; + unsigned char version; + unsigned char min_version; + unsigned char access; + unsigned short aux_type; + int last_mod; + unsigned short header_pointer; +}; +#endif - printf("\tNext track/sector $%02X/$%02X (found at offsets $%02X/$%02X\n", - catalog_buffer[CATALOG_NEXT_T],catalog_buffer[CATALOG_NEXT_S], - CATALOG_NEXT_T,CATALOG_NEXT_S); - - dump_block(catalog_buffer); - - for(file=0;file<7;file++) { - printf("\n\n"); - - ts_t=catalog_buffer[(CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_TS_LIST_T))]; - ts_s=catalog_buffer[(CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_TS_LIST_S))]; - - printf("%i+$%02X/$%02X - ",file,catalog_t,catalog_s); - deleted=0; - - if (ts_t==0xff) { - printf("**DELETED** "); - deleted=1; - ts_t=catalog_buffer[(CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_NAME+0x1e))]; } - if (ts_t==0x00) { - printf("UNUSED!\n"); - goto continue_dump; - } - - dos33_filename_to_ascii(temp_string, - catalog_buffer+(CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_NAME)),30); - - for(i=0;i0x7f? - "YES":"NO"); - printf("\tType = %c\n", - dos33_file_type(catalog_buffer[CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE)+FILE_TYPE])); - printf("\tSize in sectors = %i\n", - catalog_buffer[CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_SIZE_L)]+ - (catalog_buffer[CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_SIZE_H)]<<8)); - -repeat_tsl: - printf("\tT/S List $%02X/$%02X:\n",ts_t,ts_s); - if (deleted) goto continue_dump; - lseek(fd,DISK_OFFSET(ts_t,ts_s),SEEK_SET); - result=read(fd,&tslist,PRODOS_BYTES_PER_BLOCK); - - for(i=0;i 0xb */ +static int dos_interleave[16]= { +// 0,7,14,6,13,5,12,4,11,3,10,2,9,1,8,15, + 0,14,13,12,11,10,9,8,7,6,5,4,3,2,1,15, +}; + /* 0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15 */ + + /* ?? 0 7 14 6 13 5 12 4 11 3 10 2 9 1 8 15 */ + int prodos_read_block(struct voldir_t *voldir, unsigned char *block, int blocknum) { - int result; + int result=0; + int track,sector1,sector2; - /* Note, we need to handle interleave, etc */ - /* For now assume it's linear */ + if (voldir->interleave==PRODOS_INTERLEAVE_PRODOS) { - /* Seek to VOLDIR */ - lseek(voldir->fd,blocknum*PRODOS_BYTES_PER_BLOCK,SEEK_SET); - result=read(voldir->fd,block,PRODOS_BYTES_PER_BLOCK); + /* Seek to VOLDIR */ + lseek(voldir->fd,blocknum*PRODOS_BYTES_PER_BLOCK,SEEK_SET); + result=read(voldir->fd,block,PRODOS_BYTES_PER_BLOCK); - if (resultinterleave==PRODOS_INTERLEAVE_DOS33) { + if (debug) printf("DOS33! reading %d\n",blocknum); + track=blocknum&(~0xf); + sector1=dos_interleave[(blocknum&0xf)*2]; + sector2=dos_interleave[(blocknum&0xf)*2+1]; + + if (debug) printf("Seeking to %x\n",(track+sector1)*256); + lseek(voldir->fd,(track+sector1)*256,SEEK_SET); + result=read(voldir->fd,block,PRODOS_BYTES_PER_BLOCK/2); + + if (resultfd,(track+sector2)*256,SEEK_SET); + result=read(voldir->fd,block+256,PRODOS_BYTES_PER_BLOCK/2); + + if (result