dos33: fix some issues when copying files off disk image

ran across this when trying to debug a different issue

by default we can only get total sector size from the T/S lists
(which is only a multiple of 256 bytes) but in addition A (basic)
and B (binary) files also tell you the exact length.  So we used that
to truncate to the exact length

Only it turns out some programs (I'm looking at you, cracked version
of WAVY NAVY) intentionally set the file size to be wrong and so
we were truncating things improperly

I think this updated code is a bit more clear.  Hopefully it doesn't
break anything, I need a better test suite.
This commit is contained in:
Vince Weaver 2022-06-09 16:46:17 -04:00
parent db49ead0b6
commit 87f7fc15f5
3 changed files with 86 additions and 18 deletions

View File

@ -455,13 +455,14 @@ static int dos33_load_file(int fd,int fts,char *filename) {
unsigned char sector_buffer[BYTES_PER_SECTOR];
int tsl_pointer=0,output_pointer=0;
int result;
int total_sectors=0,last_output_pointer=0;
/* FIXME! Warn if overwriting file! */
output_fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
if (output_fd<0) {
fprintf(stderr,"Error! could not open %s for local save\n",
filename);
return -1;
return -ERROR_CANNOT_OPEN;
}
catalog_file=fts>>16;
@ -480,7 +481,8 @@ static int dos33_load_file(int fd,int fts,char *filename) {
file_type=dos33_file_type(sector_buffer[CATALOG_FILE_LIST+
(catalog_file*CATALOG_ENTRY_SIZE)+FILE_TYPE]);
// printf("file_type: %c\n",file_type);
if (debug) printf("Using TSL at %02X:%02X\n",tsl_track,tsl_sector);
if (debug) printf("file_type: %c\n",file_type);
keep_saving:
/* Read in TSL Sector */
@ -497,6 +499,8 @@ keep_saving:
if ((data_s==0) && (data_t==0)) {
/* empty */
/* this is complicated, can be a "hole" if in middle */
/* or else ignored if at the end */
}
else {
lseek(fd,DISK_OFFSET(data_t,data_s),SEEK_SET);
@ -508,39 +512,65 @@ keep_saving:
switch(file_type) {
case 'A':
case 'I':
file_size=data_sector[0]+(data_sector[1]<<8)+2;
file_size=data_sector[0]+
(data_sector[1]<<8)+2;
break;
case 'B':
file_size=data_sector[2]+(data_sector[3]<<8)+4;
file_size=data_sector[2]+
(data_sector[3]<<8)+4;
break;
default:
file_size=-1;
}
if (debug) printf("File size = %d\n",file_size);
}
/* write the block read in out to the output file */
lseek(output_fd,output_pointer*BYTES_PER_SECTOR,SEEK_SET);
result=write(output_fd,&data_sector,BYTES_PER_SECTOR);
last_output_pointer=output_pointer+1;
}
output_pointer++;
tsl_pointer++;
}
total_sectors=last_output_pointer;
/* finished with TSL sector, see if we have another */
tsl_track=sector_buffer[TSL_NEXT_TRACK];
tsl_sector=sector_buffer[TSL_NEXT_SECTOR];
// printf("Next track/sector=%d/%d op=%d\n",tsl_track,tsl_sector,
// output_pointer*BYTES_PER_SECTOR);
if ((tsl_track==0) && (tsl_sector==0)) {
}
else goto keep_saving;
else {
if (debug) printf("Next track/sector=%02X:%02X op=%d\n",
tsl_track,tsl_sector,
output_pointer*BYTES_PER_SECTOR);
goto keep_saving;
}
/* Correct the file size */
/* Note: this can cause issues if the original disk image */
/* was doing something extra-clever and intentionally */
/* had a mis-matched file size */
if (file_size>=0) {
// printf("Truncating file size to %d\n",file_size);
result=ftruncate(output_fd,file_size);
if (debug) printf("Total size %d sectors (%d bytes)\n",
total_sectors,total_sectors*BYTES_PER_SECTOR);
/* Tricky, 0...255 will give sectors of 0 */
/* 256...511 will give sectors of 1 */
if (((file_size-1)/256)!=total_sectors-1) {
printf("Warning! Total size %d not within "
"256 bytes of sector total (%d %d)!\n",
file_size,file_size/256,total_sectors);
printf("This could mean your program is trying "
"to be clever. Not truncating.\n");
}
else {
printf("Auto-truncating file size to %d\n",file_size);
result=ftruncate(output_fd,file_size);
}
}
if (result<0) fprintf(stderr,"Error on I/O\n");
@ -828,8 +858,9 @@ static void display_help(char *name, int version_only) {
if (version_only) return;
printf("Usage: %s [-h] [-y] [-x] disk_image COMMAND [options]\n",name);
printf("Usage: %s [-h] [-d] [-y] [-x] disk_image COMMAND [options]\n",name);
printf("\t-h : this help message\n");
printf("\t-d : enable debugging\n");
printf("\t-y : always answer yes for anying warning questions\n");
printf("\t-x : ignore errors (useful for making invalid filenames)\n");
printf("\n");

View File

@ -63,6 +63,7 @@
#define ERROR_NO_SPACE 3
#define ERROR_IMAGE_NOT_FOUND 4
#define ERROR_CATALOG_FULL 5
#define ERROR_CANNOT_OPEN 6
/* dos33_vtoc_bitmap.c */
int dos33_vtoc_free_space(unsigned char *vtoc);

View File

@ -59,7 +59,7 @@ static void dump_vtoc(unsigned char *vtoc) {
int dos33_dump(unsigned char *vtoc, int fd) {
int num_tracks,catalog_t,catalog_s,file,ts_t,ts_s,ts_total;
int track,sector;
int track,sector,type;
int i;
int deleted=0;
char temp_string[BUFSIZ];
@ -67,6 +67,7 @@ int dos33_dump(unsigned char *vtoc, int fd) {
unsigned char catalog_buffer[BYTES_PER_SECTOR];
unsigned char data[BYTES_PER_SECTOR];
int result;
int size_already=0;
/* Read Track 1 Sector 9 */
lseek(fd,DISK_OFFSET(1,9),SEEK_SET);
@ -104,6 +105,7 @@ repeat_catalog:
dump_sector(catalog_buffer);
for(file=0;file<7;file++) {
size_already=0;
printf("\n\n");
ts_t=catalog_buffer[(CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_TS_LIST_T))];
@ -138,28 +140,62 @@ repeat_catalog:
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]));
type=dos33_file_type(catalog_buffer[CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE)+FILE_TYPE]);
printf("\tType = %c\n",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);
/* read first sector to try to get size */
if (type=='B') {
}
if (deleted) goto continue_dump;
repeat_tsl:
/* read T/S list */
lseek(fd,DISK_OFFSET(ts_t,ts_s),SEEK_SET);
result=read(fd,&tslist,BYTES_PER_SECTOR);
/* read data */
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);
else {
if (!size_already) {
/* Read Data */
lseek(fd,DISK_OFFSET(track,sector),SEEK_SET);
result=read(fd,data,BYTES_PER_SECTOR);
if (type=='B') {
printf("\tAddress=$%04X\n",
data[0]|(data[1]<<8));
printf("\tSize=$%04X (%d)\n",
data[2]|(data[3]<<8),
data[2]|(data[3]<<8));
}
else if ((type=='A') || (type=='I')) {
printf("\tSize=$%04X (%d)\n",
data[0]|(data[1]<<8),
data[0]|(data[1]<<8));
}
size_already=1;
printf("\n\tT/S List $%02X/$%02X:\n",ts_t,ts_s);
}
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;
if (!((ts_s==0) && (ts_t==0))) {
printf("\n\tNext T/S List $%02X/$%02X:\n",ts_t,ts_s);
goto repeat_tsl;
}
continue_dump:;
}