prodos: catalog works

This commit is contained in:
Vince Weaver 2021-07-29 22:04:08 -04:00
parent 18a286dc0d
commit 67814b316d
2 changed files with 183 additions and 160 deletions

View File

@ -21,6 +21,12 @@
#define PRODOS_FILE_SUBDIR_HDR 0x0e #define PRODOS_FILE_SUBDIR_HDR 0x0e
#define PRODOS_FILE_VOLUME_HDR 0x0f #define PRODOS_FILE_VOLUME_HDR 0x0f
#define PRODOS_TYPE_TXT 0x04
#define PRODOS_TYPE_BIN 0x06
#define PRODOS_TYPE_BAS 0xFC
#define PRODOS_TYPE_VAR 0xFD
#define PRODOS_TYPE_SYS 0xFF
struct voldir_t { struct voldir_t {
int fd; int fd;
int interleave; int interleave;

View File

@ -7,194 +7,209 @@
static int debug=0; static int debug=0;
unsigned char prodos_file_type(int value) {
unsigned char result;
switch(value&0x7f) {
case 0x0: result='T'; break;
case 0x1: result='I'; break;
case 0x2: result='A'; break;
case 0x4: result='B'; break;
case 0x8: result='S'; break;
case 0x10: result='R'; break;
case 0x20: result='N'; break;
case 0x40: result='L'; break;
default: result='?'; break;
}
return result;
}
unsigned char prodos_char_to_type(char type, int lock) {
unsigned char result=0,temp_type;
#if 0
temp_type=type;
/* Covert to upper case */
if (temp_type>='a') temp_type=temp_type-0x20;
switch(temp_type) {
case 'T': result=0x0; break;
case 'I': result=0x1; break;
case 'A': result=0x2; break;
case 'B': result=0x4; break;
case 'S': result=0x8; break;
case 'R': result=0x10; break;
case 'N': result=0x20; break;
case 'L': result=0x40; break;
default: result=0x0;
}
if (lock) result|=0x80;
#endif
return result;
}
/* prodos filenames have top bit set on ascii chars */
/* and are padded with spaces */
char *prodos_filename_to_ascii(char *dest,unsigned char *src,int len) {
int i=0,last_nonspace=0;
for(i=0;i<len;i++) if (src[i]!=0xA0) last_nonspace=i;
for(i=0;i<last_nonspace+1;i++) {
dest[i]=src[i]^0x80; /* toggle top bit */
}
dest[i]='\0';
return dest;
}
/* Get a T/S value from a Catalog Sector */
static int prodos_get_catalog_ts(struct voldir_t *voldir) {
// return TS_TO_INT(voldir[VTOC_CATALOG_T],voldir[VTOC_CATALOG_S]);
return 0;
}
/* returns the next valid catalog entry */ /* returns the next valid catalog entry */
/* after the one passed in */ /* after the one passed in */
static int prodos_find_next_file(int catalog_tsf,struct voldir_t *voldir) {
int catalog_track,catalog_sector,catalog_file; /* inode = block<<8|entry */
int file_track,i;
int result;
unsigned char sector_buffer[PRODOS_BYTES_PER_BLOCK];
catalog_file=catalog_tsf>>16; static int prodos_find_next_file(int inode, struct voldir_t *voldir) {
catalog_track=(catalog_tsf>>8)&0xff;
catalog_sector=(catalog_tsf&0xff);
if (debug) { int result,catalog_block,catalog_offset;
fprintf(stderr,"CATALOG FIND NEXT, " unsigned char catalog_buffer[PRODOS_BYTES_PER_BLOCK];
"CURRENT FILE=%X TRACK=%X SECTOR=%X\n", int storage_type,file;
catalog_file,catalog_track,catalog_sector);
}
#if 0
catalog_loop:
/* Read in Catalog Sector */ catalog_block=inode>>8;
lseek(fd,DISK_OFFSET(catalog_track,catalog_sector),SEEK_SET); catalog_offset=inode&0xff;
result=read(fd,sector_buffer,PRODOS_BYTES_PER_BLOCK);
catalog_offset++;
while(1) {
/* Read in Sector */
result=prodos_read_block(voldir,catalog_buffer,catalog_block);
if (result<0) { if (result<0) {
fprintf(stderr,"Error on I/O %s\n",strerror(errno)); fprintf(stderr,"Error on I/O\n");
return -1; return -1;
} }
i=catalog_file; for(file=catalog_offset;
while(i<7) { file<voldir->entries_per_block;file++) {
file_track=sector_buffer[CATALOG_FILE_LIST+ storage_type=(catalog_buffer[4+file*PRODOS_FILE_DESC_LEN]>>4)&0xf;
(i*CATALOG_ENTRY_SIZE)];
/* 0xff means file deleted */ if (storage_type!=PRODOS_FILE_DELETED) {
/* 0x0 means empty */
if (debug) { return (catalog_block<<8)|file;
if (file_track==0xff) fprintf(stderr,"\tFILE %d DELETED\n",i); }
if (file_track==0x00) fprintf(stderr,"\tFILE %d UNALLOCATED\n",i);
} }
if ((file_track!=0xff) && (file_track!=0x0)) { catalog_offset=0;
if (debug) fprintf(stderr,"\tFOUND FILE %X TRACK $%X SECTOR $%X\n",i,catalog_track,catalog_sector); catalog_block=catalog_buffer[2]|
return ((i<<16)+(catalog_track<<8)+catalog_sector); (catalog_buffer[3]<<8);
} if (catalog_block==0) break;
i++;
} }
catalog_track=sector_buffer[CATALOG_NEXT_T];
catalog_sector=sector_buffer[CATALOG_NEXT_S];
if (debug) fprintf(stderr,"\tTRYING NEXT SECTOR T=$%X S=$%X\n",
catalog_track,catalog_sector);
/* FIXME: this wouldn't happen on 140k disks */
/* but who knows if you're doing something fancy? */
if ((catalog_track<0) || (catalog_track>40)) {
return -1;
}
if (catalog_sector!=0) {
catalog_file=0;
goto catalog_loop;
}
#endif
return -1; return -1;
} }
static int prodos_print_file_info(int fd,int catalog_tsf) { int prodos_populate_filedesc(unsigned char *file_desc,
struct file_entry_t *file_entry) {
int catalog_track,catalog_sector,catalog_file,i; file_entry->storage_type=(file_desc[0]>>4)&0xf;
char temp_string[BUFSIZ]; file_entry->name_length=file_desc[0]&0xf;
int result; memcpy(&file_entry->file_name[0],&file_desc[1],
unsigned char sector_buffer[PRODOS_BYTES_PER_BLOCK]; file_entry->name_length);
file_entry->file_name[file_entry->name_length]=0;
catalog_file=catalog_tsf>>16; file_entry->file_type=file_desc[0x10];
catalog_track=(catalog_tsf>>8)&0xff; file_entry->key_pointer=file_desc[0x11]|file_desc[0x12]<<8;
catalog_sector=(catalog_tsf&0xff); file_entry->blocks_used=file_desc[0x13]|file_desc[0x14]<<8;
file_entry->eof=file_desc[0x15]|file_desc[0x16]<<8|
file_desc[0x17]<<16;
file_entry->creation_time=(file_desc[0x18]<<16)|
(file_desc[0x19]<<24)|
(file_desc[0x1a]<<0)|
(file_desc[0x1b]<<8);
file_entry->version=file_desc[0x1c];
file_entry->min_version=file_desc[0x1d];
file_entry->access=file_desc[0x1e];
file_entry->aux_type=file_desc[0x1f]|file_desc[0x20]<<8;
file_entry->last_mod=(file_desc[0x21]<<16)|
(file_desc[0x22]<<24)|
(file_desc[0x23]<<0)|
(file_desc[0x24]<<8);
file_entry->header_pointer=file_desc[0x25]|file_desc[0x26]<<8;
if (debug) fprintf(stderr,"CATALOG FILE=%X TRACK=%X SECTOR=%X\n", return 0;
catalog_file,catalog_track,catalog_sector); }
#if 0
/* Read in Catalog Sector */
lseek(fd,DISK_OFFSET(catalog_track,catalog_sector),SEEK_SET);
result=read(fd,sector_buffer,PRODOS_BYTES_PER_BLOCK);
if (sector_buffer[CATALOG_FILE_LIST+(catalog_file*CATALOG_ENTRY_SIZE)+FILE_TYPE]>0x7f) { static int prodos_print_short_filetype(int type) {
printf("*");
} switch(type) {
else { case 0x01: printf("BAD"); break; /* Bad Blocks */
printf(" "); case 0x04: printf("TXT"); break; /* ASCII Text */
case 0x06: printf("BIN"); break; /* Binary */
case 0x0f: printf("DIR"); break; /* Directory */
case 0x19: printf("ADB"); break; /* Appleworks Database */
case 0x1A: printf("AWP"); break; /* Appleworks Word Processing */
case 0x1B: printf("ASP"); break; /* AppleWorks Spreadsheet */
case 0xEF: printf("PAS"); break; /* PASCAL */
case 0xF0: printf("CMD"); break; /* Command */
case 0xF1: case 0xF2: case 0xF3: case 0xF4:
case 0xF5: case 0xF6: case 0xF7: case 0xF8:
printf("USR"); break;
case 0xFC: printf("BAS"); break; /* Applesoft BASIC */
case 0xFD: printf("VAR"); break; /* Applesoft variables */
case 0xFE: printf("REL"); break; /* Relocatable Object */
case 0xFF: printf("SYS"); break; /* ProDOS system */
default:
case 0x00: printf("???"); break;
} }
printf("%c",prodos_file_type(sector_buffer[CATALOG_FILE_LIST+(catalog_file*CATALOG_ENTRY_SIZE)+FILE_TYPE]));
printf(" ");
printf("%.3i ",sector_buffer[CATALOG_FILE_LIST+(catalog_file*CATALOG_ENTRY_SIZE+FILE_SIZE_L)]+
(sector_buffer[CATALOG_FILE_LIST+(catalog_file*CATALOG_ENTRY_SIZE+FILE_SIZE_H)]<<8));
prodos_filename_to_ascii(temp_string,sector_buffer+(CATALOG_FILE_LIST+ return 0;
(catalog_file*CATALOG_ENTRY_SIZE+FILE_NAME)),30); }
for(i=0;i<strlen(temp_string);i++) { static unsigned char prodos_capital_month_names[12][4]={
if (temp_string[i]<0x20) { "JAN","FEB","MAR","APR","MAY","JUN",
printf("^%c",temp_string[i]+0x40); "JUL","AUG","SEP","OCT","NOV","DEC",
} };
else {
printf("%c",temp_string[i]); static int prodos_text_timestamp(int t, unsigned char *timestamp) {
int year,month,day,hour,minute;
year=(t>>25)&0x7f;
month=(t>>21)&0xf;
day=(t>>16)&0x1f;
hour=(t>>8)&0x1f;
minute=t&0x3f;
sprintf((char *)timestamp,"%2d-%s-%02d %2d:%02d",
day,prodos_capital_month_names[month-1],year,hour,minute);
timestamp[16]=0;
return 0;
}
static int prodos_print_file_info(int inode, struct voldir_t *voldir) {
int result,catalog_block,catalog_offset;
unsigned char catalog_buffer[PRODOS_BYTES_PER_BLOCK];
unsigned char file_desc[PRODOS_FILE_DESC_LEN];
struct file_entry_t file_entry;
unsigned char timestamp[17];
catalog_block=inode>>8;
catalog_offset=inode&0xff;
/* Read in Sector */
result=prodos_read_block(voldir,catalog_buffer,catalog_block);
if (result<0) {
fprintf(stderr,"Error on I/O\n");
return -1;
} }
memcpy(file_desc,
catalog_buffer+4+catalog_offset*PRODOS_FILE_DESC_LEN,
PRODOS_FILE_DESC_LEN);
prodos_populate_filedesc(file_desc,&file_entry);
/* name */
printf(" %-16s",file_entry.file_name);
/* type */
prodos_print_short_filetype(file_entry.file_type);
/* blocks used */
printf("%8d ",file_entry.blocks_used);
/* modified timestamp */
prodos_text_timestamp(file_entry.last_mod,timestamp);
printf("%s ",timestamp);
/* creation timestamp */
prodos_text_timestamp(file_entry.creation_time,timestamp);
printf("%s ",timestamp);
/* eof */
printf("%8d ",file_entry.eof);
switch(file_entry.file_type) {
// case PRODOS_TYPE_TXT:
// printf("L=$%04X",file_entry.aux_type);
// break;
case PRODOS_TYPE_BIN:
printf("A=$%04X",file_entry.aux_type);
break;
// case PRODOS_TYPE_BAS:
// printf("A=$%04X",file_entry.aux_type);
// break;
// case PRODOS_TYPE_VAR:
// printf("A=$%04X",file_entry.aux_type);
// break;
// case PRODOS_TYPE_SYS:
// printf("A=$%04X",file_entry.aux_type);
// break;
default: break;
} }
printf("\n"); printf("\n");
if (result<0) fprintf(stderr,"Error on I/O\n");
#endif
return 0; return 0;
} }
void prodos_catalog(int dos_fd, struct voldir_t *voldir) { void prodos_catalog(int dos_fd, struct voldir_t *voldir) {
int catalog_block,catalog_offset; int catalog_block,catalog_offset,catalog_inode;
int blocks_free=0; int blocks_free=0;
blocks_free=prodos_voldir_free_space(voldir); blocks_free=prodos_voldir_free_space(voldir);
@ -206,11 +221,13 @@ void prodos_catalog(int dos_fd, struct voldir_t *voldir) {
printf("\n"); printf("\n");
catalog_block=PRODOS_VOLDIR_KEY_BLOCK; catalog_block=PRODOS_VOLDIR_KEY_BLOCK;
catalog_offset=1; /* skip the header */ catalog_offset=0; /* skip the header */
catalog_inode=(catalog_block<<8)|catalog_offset;
while(1) { while(1) {
catalog_offset=prodos_find_next_file(catalog_offset,voldir); catalog_inode=prodos_find_next_file(catalog_inode,voldir);
if (catalog_offset<0) break; if (catalog_inode==-1) break;
prodos_print_file_info(catalog_inode,voldir);
} }
printf("\n"); printf("\n");
@ -218,5 +235,5 @@ void prodos_catalog(int dos_fd, struct voldir_t *voldir) {
printf(" BLOCKS USED: % 3d ",voldir->total_blocks-blocks_free); printf(" BLOCKS USED: % 3d ",voldir->total_blocks-blocks_free);
printf(" TOTAL BLOCKS: % 3d ",voldir->total_blocks); printf(" TOTAL BLOCKS: % 3d ",voldir->total_blocks);
printf("\n"); printf("\n\n");
} }