prodos: can handle .dsk and .po images now

interleave is a pain
This commit is contained in:
Vince Weaver 2021-07-28 23:02:18 -04:00
parent b8e0cf5b29
commit 76231a67e0
5 changed files with 290 additions and 123 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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;
file<voldir->entries_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;i<strlen(temp_string);i++) {
if (temp_string[i]<0x20) {
printf("^%c",temp_string[i]+0x40);
}
else {
printf("%c",temp_string[i]);
}
}
printf("\n");
printf("\tLocked = %s\n",
catalog_buffer[CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE)+FILE_TYPE]>0x7f?
"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<ts_total;i++) {
track=tslist[TSL_LIST+(i*TSL_ENTRY_SIZE)];
sector=tslist[TSL_LIST+(i*TSL_ENTRY_SIZE)+1];
if ((track==0) && (sector==0)) printf(".");
else printf("\n\t\t%02X/%02X",track,sector);
}
ts_t=tslist[TSL_NEXT_TRACK];
ts_s=tslist[TSL_NEXT_SECTOR];
if (!((ts_s==0) && (ts_t==0))) goto repeat_tsl;
continue_dump:;
}
catalog_t=catalog_buffer[CATALOG_NEXT_T];
catalog_s=catalog_buffer[CATALOG_NEXT_S];
if (catalog_s!=0) {
file=0;
goto repeat_catalog;
/* move to next */
catalog_block=catalog_buffer[0x2]|(catalog_buffer[0x3]<<8);
if (catalog_block==0) break;
catalog_offset=0;
}
printf("\n");
if (result<0) fprintf(stderr,"Error on I/O\n");
#endif
return 0;
}

View File

@ -11,6 +11,8 @@
#include "prodos.h"
static int debug=0;
#if 0
static int debug=0,ignore_errors=0;
@ -23,22 +25,61 @@ static unsigned char get_low_byte(int value) {
}
#endif
/* we want block 2 -> 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 (result<PRODOS_BYTES_PER_BLOCK) {
fprintf(stderr,"Error reading block %d\n",blocknum);
return -1;
if (result<PRODOS_BYTES_PER_BLOCK) {
fprintf(stderr,"Error reading block %d\n",blocknum);
return -1;
}
}
else if (voldir->interleave==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 (result<PRODOS_BYTES_PER_BLOCK/2) {
fprintf(stderr,"Error reading block %d\n",blocknum);
return -1;
}
lseek(voldir->fd,(track+sector2)*256,SEEK_SET);
result=read(voldir->fd,block+256,PRODOS_BYTES_PER_BLOCK/2);
if (result<PRODOS_BYTES_PER_BLOCK/2) {
fprintf(stderr,"Error reading block %d\n",blocknum);
return -1;
}
}
else {
fprintf(stderr,"ERROR! Unknown interleave!\n");
}
return 0;
}

View File

@ -2,9 +2,6 @@
#include "prodos.h"
/* FIXME: this code assumes that we have 16 sectors pretty much everywhere */
static int ones_lookup[16]={
/* 0x0 = 0000 */ 0,
/* 0x1 = 0001 */ 1,
@ -62,7 +59,7 @@ int prodos_voldir_free_space(struct voldir_t *voldir) {
}
/* free a sector from the sector bitmap */
void prodos_voldir_free_sector(struct voldir_t *voldir, int track, int sector) {
int prodos_voldir_free_block(struct voldir_t *voldir, int block) {
#if 0
/* each bitmap is 32 bits. With 16-sector tracks only first 16 used */
@ -86,7 +83,7 @@ void prodos_voldir_free_sector(struct voldir_t *voldir, int track, int sector) {
}
/* reserve a sector in the sector bitmap */
void prodos_voldir_reserve_sector(struct voldir_t *voldir, int track, int sector) {
int prodos_voldir_reserve_block(struct voldir_t *voldir, int block) {
#if 0
/* each bitmap is 32 bits. With 16-sector tracks only first 16 used */
@ -155,8 +152,8 @@ void prodos_voldir_dump_bitmap(struct voldir_t *voldir) {
/* reserve a sector in the sector bitmap */
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) {
#if 0
int start_track,track_dir,i;
@ -219,7 +216,22 @@ int prodos_voldir_find_free_sector(struct voldir_t *voldir,
return 0;
}
#if 0
/* write modified VTOC back out */
lseek(fd,DISK_OFFSET(PRODOS_VOLDIR_TRACK,PRODOS_VOLDIR_BLOCK),SEEK_SET);
result=write(fd,&voldir,PRODOS_BYTES_PER_BLOCK);
if (result<0) {
fprintf(stderr,"Error on I/O\n");
}
#endif
#endif
/* no room */
return -1;