#include #include #define FALSE (0) #define TRUE (!FALSE) /* Force stdin into binary mode if running cygwin */ #ifdef __CYGWIN__ #include #include void stdin_setup() { if (setmode(0,O_BINARY)==EOF) { fprintf(stderr,"\nImage read error.\n"); exit(1); } } #else void stdin_setup() {} #endif #define TOTAL_DISK_BLOCKS (8*2*80) #define SECTOR_SIZE (0x200) #define DISK_SIZE (TOTAL_DISK_BLOCKS * SECTOR_SIZE) #define DIR_ENTRY_SIZE (12) unsigned char disk[DISK_SIZE]; void check_bounds(int block) { if (block < 0 || block >= DISK_SIZE) { fprintf(stderr,"\nImage file error. Block %4x\n",(int)block); exit(1); } } int tolong(int offset) { unsigned int l = 0; int i; check_bounds(l+3); for (i=0;i<4;i++) { l= (l<<8)| disk[offset+i]; } return l; } struct tds_file { int first_file_block; int current_file_block; int offset_in_current_file_block; int data_blocks_remaining; }; void init_fb(struct tds_file * f, int file_block) { check_bounds(file_block); f->first_file_block = file_block; f->current_file_block = file_block; f -> data_blocks_remaining=tolong(file_block+32); f -> offset_in_current_file_block = 36; } int get_next_sector (struct tds_file *f) { /* The count of valid blocks in the current file block is at offset 32 of the * file block. * The individual data sectors of the file start at offset 36. * If we have to chain to further file blocks, the pointer to the * next one is at offset 12, otherwise the long here is -1 */ int next_sector; if ((f -> data_blocks_remaining)<=0) if((disk[(f -> current_file_block)+12] & 0xff) == 0xff) return (-1); else { f -> current_file_block = tolong((f -> current_file_block)+12)*SECTOR_SIZE; check_bounds(f -> current_file_block); f -> data_blocks_remaining=tolong(f->current_file_block+32); f -> offset_in_current_file_block = 36; } next_sector = tolong(f -> current_file_block + f -> offset_in_current_file_block)*SECTOR_SIZE; check_bounds(next_sector); f -> offset_in_current_file_block += 4; f -> data_blocks_remaining -= 1; return next_sector; } void write_error() { fprintf(stderr,"\nFile write error\n"); exit(1); } void usage(char * n) { fprintf(stderr, "Usage: %s [-d] < image\n" "\t-d\twrite out files in the image\n",n); exit(1); } main(int argc, char * argv[]) { struct tds_file root, current; int write_files; char * prog_name = argc>0?argv[0]:"tdsfs"; /* Parse arguments */ write_files = FALSE; while (--argc > 0) { argv++; if (strlen(*argv) != 2 || **argv != '-') usage(prog_name); switch ((*argv)[1]) { case 'd': write_files = TRUE; break; default: usage(prog_name); break; } } /* Set stdin to binary mode if appropriate and read in the image */ stdin_setup(); if(fread(disk,1,DISK_SIZE,stdin)!=DISK_SIZE) { fprintf(stderr,"\nImage read error.\n"); exit(1); } /* The root block is half way into the disk. The long at offset 24 points * to a file block for the root directory. The long at offset 28 seems to * point to some sort of free block bitmap */ init_fb(&root, tolong((TOTAL_DISK_BLOCKS/2)*SECTOR_SIZE + 24)*SECTOR_SIZE); /* Read the root directory */ { int offset_in_current_root_sector = 0; int current_root_sector; while ((current_root_sector=get_next_sector(&root))>=0) { while ( offset_in_current_root_sector + DIR_ENTRY_SIZE < SECTOR_SIZE) { int name = tolong(current_root_sector+offset_in_current_root_sector+4); int fb_file = tolong(current_root_sector+offset_in_current_root_sector+8) * SECTOR_SIZE; int current_sector; if (name > 0 && fb_file >=0 && fb_file < DISK_SIZE) { char fname[24]; FILE * out; init_fb(¤t, fb_file); snprintf(fname,23,"%d", name); if (write_files && !(out = fopen(fname,"wb"))) { write_error(); } while ((current_sector=get_next_sector(¤t))>=0) if (write_files && fwrite(&disk[current_sector],1,SECTOR_SIZE,out)!=SECTOR_SIZE) write_error(); if (write_files && fclose(out)) write_error(); } offset_in_current_root_sector += DIR_ENTRY_SIZE; } offset_in_current_root_sector = 0; } } }