From e2ba8458a5cfdfacfaf103e7ba97d610afa6c970 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Mon, 29 Aug 2022 16:11:13 -0400 Subject: initial commit --- axelib.c | 546 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 546 insertions(+) create mode 100644 axelib.c (limited to 'axelib.c') diff --git a/axelib.c b/axelib.c new file mode 100644 index 0000000..2b6e66b --- /dev/null +++ b/axelib.c @@ -0,0 +1,546 @@ +#include "axe.h" + +extern int all, total_sec, translate; + +static int atr_offset; + +int load_disk(unsigned char *diskbuf, char *filename) { + FILE *file; + int vtoc_sec; + unsigned char tmpbuf[16]; + char tmp[128]; + + if((file = fopen(filename, "r")) == NULL) { + sprintf(tmp, "load_disk(): %s", filename); + perror(tmp); + exit(1); + } + fread(tmpbuf, 16, 1, file); + atr_offset = 16; + memcpy(diskbuf, tmpbuf, 16); + if((tmpbuf[0] != 0x96) || (tmpbuf[1] != 0x02)) { /* not an atr */ + atr_offset = 0; + rewind(file); + total_sec = 720; + } + + /* do some sanity checking of images: */ + if(atr_offset) { + total_sec = (diskbuf[2] + 256 * diskbuf[3]) >> 3; + if(!total_sec) + total_sec = (diskbuf[6] + 256 * diskbuf[7]) * 8192; + if(total_sec < 720) { + printf("Total sectors (%d) < 720 - aborting\n", total_sec); + exit(1); + } + if(total_sec > 720) { + printf + ("Warning: Total sectors (%d) > 720 - only reading first 720 sectors\n", + total_sec); + } + if((diskbuf[4] + 256 * diskbuf[5]) != 128) { + printf("Fatal: sector size not 128 bytes!\n"); + exit(1); + } + } else { + printf + ("Warning: blindly assuming xfd image is 720 sectors, 128 bytes/sector!\n"); + } + + if((total_sec = fread(diskbuf + atr_offset, 128, 720, file)) < 720) { + printf("Error reading image file, only got %d sectors, aborting\n", total_sec); + perror("fread"); + exit(1); + } + + vtoc_sec = + diskbuf[atr_offset + 128 * 359 + 1] + 256 * diskbuf[atr_offset + + 128 * 359 + 2]; + if(vtoc_sec != 707) + printf + ("Warning: VTOC sector count (%d) not 707, are you sure this is an AtariDOS 2.0 image?\n", + vtoc_sec); + return 0; +} + +int write_disk(unsigned char *diskbuf, char *filename) { + FILE *file; + unsigned char tmpbuf[16]; + + file = fopen(filename, "w"); + memcpy(tmpbuf, diskbuf, 16); + atr_offset = 0; + if((tmpbuf[0] == 0x96) && (tmpbuf[1] == 0x02)) { /* is an atr */ + fwrite(tmpbuf, 16, 1, file); + atr_offset = 16; + } + fwrite(diskbuf + atr_offset, 128, 720, file); + fclose(file); + return 0; +} + + +void usage(char *name) { + printf + ("Usage: %s [options] [-D filename] [-w filename] [-e filename]\n\t\t [-b filename] [-c dirname] [-d sector] disk_image\n\n", + name); + + printf("\t-a\tlist all dir entries, even deleted/empty ones\n"); + printf("\t-l\ttrace & print links for all files on disk\n"); + printf("\t-v\tdump VTOC (sector 360) in decimal, hex, and binary\n"); + printf + ("\t-t\t'tar xf' style - create dir filled with files in image\n"); + printf("\t-u\tUn*x <-> Atari newline/EOL translation\n"); + printf("\t-D\tdelete file from image\n"); + printf("\t-w\twrite file to image\n"); + printf("\t-c\tcreate new image from directory\n"); + printf("\t-x\textract (read) file from image, write to current dir\n"); + printf("\t-b\tcreate blank image called 'filename'\n"); + printf("\t-d\tdump a sector in decimal, hex, and binary\n"); + printf + ("\ndisk_image must be a 720 sector, single density .atr or .xfd image\n"); + printf("\tin Atari DOS 2.0 or compatible format\n"); + printf + ("\nAll UN*X filenames must conform to Atari 8.3 filename.ext format\n"); + printf("\t(though they are NOT treated case-sensitively)\n"); + printf("\nEnjoy!\n\n"); + exit(1); +} + +void print_entry(unsigned char *buf) { +#ifdef DEBUG + static int ents; + int i; +#endif + int s; + unsigned char tmpbuf[32]; + + memcpy(tmpbuf, buf, 16); + tmpbuf[16] = '\0'; +#ifdef DEBUG + printf("successfully read dir. entry #%d\n", ents++); +#endif + if((tmpbuf[0] & 64) || all) { +#ifdef DEBUG + for (i = 0; i < 16; i++) { + printf(" 0x%X", tmpbuf[i]); + } +#endif + total_sec += (s = tmpbuf[1] + 256 * tmpbuf[2]); + printf("%c %s\t%03d\n", (tmpbuf[0] & 32) ? '*' : ' ', tmpbuf + 5, + s); + } +} + +void read_sector(unsigned char *disk, int sector, unsigned char *buf) { + memcpy(buf, disk + (sector - 1) * 128 + atr_offset, 128); +} + +void write_sector(unsigned char *disk, int sector, unsigned char *buf) { + memcpy(disk + (sector - 1) * 128 + atr_offset, buf, 128); +} + +void traverse_file(unsigned char *disk, unsigned char *ent, int action) { + int i, next_sec, data_bytes, curfile; + unsigned char buf[128]; + unsigned char vtoc[128]; + +#ifdef DEBUG + printf("traverse_file called with %s\n", + (action - 1) ? "TF_DELETE" : "TF_PRINT"); +#endif + + if(action == TF_DELETE) + read_sector(disk, 360, vtoc); + + next_sec = ent[3] + 256 * ent[4]; + while(next_sec) { + if(action == TF_DELETE) + mark_free(vtoc, next_sec); + if(action == TF_PRINT) + printf("%d: ", next_sec); + read_sector(disk, next_sec, buf); + data_bytes = buf[127]; + curfile = buf[125] >> 2; + next_sec = buf[126] + 256 * (buf[125] & 3); + if(action == TF_PRINT) + printf("data_bytes=%d filenum=%d next_sec=%d\n", data_bytes, + curfile, next_sec); + } + if(action == TF_DELETE) { + i = (vtoc[3] + 256 * vtoc[4]); +#ifdef DEBUG + printf("deleting file, old vtoc free count=%d", i); +#endif + i += ent[1] + 256 * ent[2]; +#ifdef DEBUG + printf(", new=%d\n", i); +#endif + vtoc[3] = i % 256; + vtoc[4] = i / 256; + write_sector(disk, 360, vtoc); + if(action == TF_DELETE) { + printf("Deleted file, now %d free sectors on image\n", i); + } + } +} + +void dump_file(unsigned char *disk, unsigned char *ent, char *outfile) { +#ifdef DEBUG + int curfile; +#endif + int i, next_sec, data_bytes, total_written = 0; + unsigned char buf[128]; + FILE *out; + +/* fseek(handle,atr_seek(361)+16*filenum,SEEK_SET); + fread(buf,16,1,handle); */ + next_sec = ent[3] + 256 * ent[4]; + out = fopen(outfile, "wb"); +/* #ifdef DEBUG + printf("First sector of filenum %d, ",filenum); + #endif */ + while(next_sec) { +#ifdef DEBUG + printf("%d: ", next_sec); +#endif + read_sector(disk, next_sec, buf); + data_bytes = buf[127]; + next_sec = buf[126] + 256 * (buf[125] & 3); +#ifdef DEBUG + curfile = buf[125] >> 2; + printf("data_bytes=%d filenum=%d next_sec=%d\n", data_bytes, curfile, + next_sec); +#endif + if(translate) + for (i = 0; i <= data_bytes; i++) + if(buf[i] == 0x9b) + buf[i] = '\n'; + fwrite(buf, data_bytes, 1, out); + total_written += data_bytes; + fflush(out); + } + printf("Wrote %d bytes to file %s\n", total_written, outfile); +} + + +int parse_filename(char *filename, char *result) { + int i = 0, j = 0; + char ext[4] = " \0"; + char fn[9] = " \0"; +#ifdef DEBUG + printf("parse_filename called, filename=%s\n", filename); +#endif + if(strlen(filename) > 12) { + printf("filename too long: %s\n", filename); + exit(1); + } +/* if(strlen(strstr(filename,"."))>4) { + printf("extension too long: %s\n",filename); + exit(1); + } */ + while((filename[i]) && (filename[i] != '.')) { + fn[i++] = toupper(filename[i]); + } + if(filename[i] == '.') + while(filename[++i]) { + ext[j++] = toupper(filename[i]); + } + + strcpy(result, fn); + strncat(result, ext, 3); +#ifdef DEBUG + printf("parse_filename exiting, result=%s\n", result); +#endif + return (0); +} + +int make_filename(char *filename, char *result) { + int i = 0, j = 8; + char fn[13] = { '\0' }; + + while((filename[i] && filename[i] != ' ') && (i < 8)) { + fn[i++] = tolower(filename[i]); + } + if(filename[j] != ' ') { + fn[i++] = '.'; + while(filename[j]) { + fn[i++] = tolower(filename[j++]); + } + } +#ifdef DEBUG + printf("made filename %s from %s\n", fn, filename); +#endif + strcpy(result, fn); + return 0; +} + +int make_dir(char *filename) { + char tmp[15] = { '\0' }; + char *p; + + strcpy(tmp, filename); + if(!(p = strrchr(tmp, '.'))) { + strcat(tmp, ".dir"); + } else { + *p = '\0'; + } +#ifdef DEBUG + printf("made dir: %s\n", tmp); +#endif + if(mkdir(tmp, 0777)) { + perror("Can't make directory: "); + exit(1); + } + chdir(tmp); + return 0; +} + +void dump_sector(unsigned char *disk, int sector) { + unsigned char buf[256]; + int i, j, k; + printf("Dump of sector %d in decimal:\n", sector); + read_sector(disk, sector, buf); + for (i = 0; i < 128; i += 16) { + printf("%03d: ", i); + for (j = 0; j < 16; j++) { + printf("%03d ", buf[i + j]); + } + printf("\n"); + } + printf("Dump of sector %d in hex:\n", sector); + for (i = 0; i < 128; i += 16) { + printf("%03x: ", i); + for (j = 0; j < 16; j++) { + printf(" %02x ", buf[i + j]); + } + printf("\n"); + } + printf("Dump of sector %d in binary:\n", sector); + for (i = 0; i < 128; i += 16) { + printf("%03x: ", i); + for (j = 0; j < 16; j++) { + for (k = 7; k > -1; k--) { + if(buf[i + j] & (1 << k)) + printf("1"); + else + printf("0"); + } + printf(" "); + if(j == 7) + printf("\n "); + } + printf("\n"); + } +} + + +/* please, ignore the ugliness of this function:*/ +void write_blank_disk(char *filename) { + unsigned char atr_header[16] = { 0x96, 0x02, 0x80, 0x16, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + unsigned char disk[128 * 720 + 16] = { '\0' }; + int i; + unsigned char vtoc[128] = + { 0x02, 0xc3, 0x02, 0xc3, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f + }; + + for (i = 11; i < 100; i++) + vtoc[i] = 0xff; + vtoc[55] = 0x00; + vtoc[56] = 0x7f; + for (i = 100; i < 128; i++) + vtoc[i] = 0x00; + atr_offset = 16; + memcpy(disk, atr_header, 16); + write_sector(disk, 360, vtoc); + write_disk(disk, filename); + printf("Wrote formatted blank image to %s\n", filename); +} + +static void xlate_eofs(unsigned char *buf, int len) { + int i; + for (i = 0; i < len; i++) + if(buf[i] == '\n') + buf[i] = 0x9b; +} + +void write_file(unsigned char *disk, char *filename) { + unsigned char vtoc[128]; + unsigned char buf[128]; + char fnbuf[15]; +/* unsigned char dentry[16];*/ + unsigned char *dindex; + int i, dentryno, first_sec, secno, next_sec, count = 0, bytes; + FILE *handle; + + printf("Writing %s to image...", filename); + parse_filename(filename, fnbuf); + if((handle = fopen(filename, "r")) == NULL) { + perror("write_file::fopen"); + exit(1); + } +#ifdef DEBUG + printf("write_file: parsed %s as \"%s\"\n", filename, fnbuf); +#endif + if((dentryno = get_dentry(disk)) == -1) { + printf("write_file: no free directory entries on image\n"); + exit(1); + } +#ifdef DEBUG + printf("dentryno=%d\n", dentryno); +#endif + read_sector(disk, 360, vtoc); + if(!(first_sec = secno = get_free_sector(vtoc))) { + printf("write_file: no free sectors in image\n"); + exit(1); + } +#ifdef DEBUG + printf("first_sec=%d\n", first_sec); +#endif + do { + int tmp, eof = 0; + count++; + bytes = fread(buf, 1, 125, handle); + + if(bytes == 125) { + /* test for EOF on handle */ + tmp = fgetc(handle); + if(tmp == EOF) + eof = 1; + else + ungetc(tmp, handle); + } + + if(translate) xlate_eofs(buf, 125); + mark_used(vtoc, secno); + + if(bytes == 125 && !eof) { + /* full sector, not at EOF */ + next_sec = get_free_sector(vtoc); + buf[125] = (dentryno << 2) | (next_sec >> 8); + buf[126] = next_sec & 255; + buf[127] = 125; + write_sector(disk, secno, buf); + secno = next_sec; + } else { + /* partial sector or full sector at EOF */ + buf[125] = dentryno << 2; + buf[126] = 0; + buf[127] = bytes; + write_sector(disk, secno, buf); + next_sec = 0; + } + } while(next_sec); + /* update dentry */ + read_sector(disk, 361 + (dentryno / 8), buf); + dindex = buf + (dentryno % 8) * 16; + dindex[0] = 66; /* taken from a dos 2.0s disk, hope its right */ + dindex[1] = count & 255; + dindex[2] = count / 256; + dindex[3] = first_sec & 255; + dindex[4] = first_sec / 256; + memcpy(dindex + 5, fnbuf, 11); + write_sector(disk, 361 + (dentryno / 8), buf); + /*all thats left to do is update free sector count in vtoc: */ + i = (vtoc[3] + 256 * vtoc[4]) - count; + vtoc[3] = i & 255; + vtoc[4] = i / 256; + write_sector(disk, 360, vtoc); + printf("Wrote %d sectors.\n", count); +} + +int get_dentry(unsigned char *disk) { + int i = 361, j, dentryno = 0, done = 0; + unsigned char buf[128]; + + while(!done) { + read_sector(disk, i, buf); + for (j = 0; j < 128; j += 16) { + if((buf[j] == 0) || (buf[j] & 128)) { + return dentryno; + } + dentryno++; + } + done = (++i == 369); + } + return -1; +} + +int get_free_sector(unsigned char *vtoc) { + int i; + + for (i = 1; i < 720; i++) { /* atari DOS doesn't use sector 720 */ + if(vtoc[vtoc_byte(i)] & vtoc_bit(i)) + return i; + } + + return 0; +} + +int vtoc_byte(int sector) { + return 10 + (sector) / 8; +} + +int vtoc_bit(int sector) { + return 128 >> ((sector) % 8); +} + +void mark_used(unsigned char *vtoc_sector, int sector) { + vtoc_sector[vtoc_byte(sector)] &= ~vtoc_bit(sector); +} + +void mark_free(unsigned char *vtoc_sector, int sector) { + vtoc_sector[vtoc_byte(sector)] |= vtoc_bit(sector); +} + +/*int get_confirm(char *prompt) { + printf("%s[y/N]? ",prompt); + return ((toupper(getc(stdin)))=='Y'); +}*/ + +int check_dir(unsigned char *disk, char *filename) { + int i = 361, j, done = 0, dentryno = 0; + unsigned char buf[128]; + + printf("check_dir: passed %s\n", filename); + while(!done) { + read_sector(disk, i, buf); + for (j = 0; j < 128; j += 16) { + if((strncmp(filename, (char*)(buf + j + 5), 11) == 0)) { + return dentryno; + } + dentryno++; + } + done = (++i == 369); + } + + return -1; +} + +/* these routines suck, and are not actually used any more. + * maybe someday they'll become useful again. + * + int delete_file(unsigned char *disk,char *filename) { + int first_sec,next_sec,i,dentryno; + char fnbuf[15]; + char buf[128]; + char *debuf; + char vtoc[128]; + + printf("delete_file doesn't work yet. passed: %s\n",filename); + parse_filename(filename,fnbuf); + if((dentryno=check_dir(disk,fnbuf))==-1) { + printf("delete_file: file %s not found on image\n",fnbuf); + exit(1); + } + printf("delete_file: would delete %s\n",fnbuf); + read_sector(disk,361+dentryno/8,buf); + read_sector(disk,360,vtoc); + debuf=buf+(dentryno%8)*16; + next_sec=debuf[3]+256*debuf[4]; + traverse_file(disk,debuf,TF_DELETE); + return 0; +} +*/ -- cgit v1.2.3