#include #include #include #include #include #define nil NULL typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; char *argv0 = "tp"; u8 boot[512]; typedef struct { char name[32]; u16 mode; u8 uid, gid; u8 unused; u8 s1; u16 s2; u32 mtime; u16 addr; u8 unused2[16]; u16 chk; } Dirent; Dirent dir[496]; u8 *files[496]; int dirsz; int changed; #define SZ(d) ((d->s1<<16)|d->s2) #define NBLK(sz) (((sz)+511)/512) void usage(void) { fprintf(stderr, "%s filename [rtx] [files ...]\n", argv0); exit(1); } void readtape(FILE *f) { fread(boot, 1, 512, f); fread(dir, 1, dirsz*sizeof(Dirent), f); int sz; u8 **fp = files; for(Dirent *d = dir; d < &dir[dirsz]; d++, fp++) { if(d->name[0] == '\0') continue; fseek(f, d->addr*512, 0); *fp = malloc(sz = SZ(d)); fread(*fp, 1, sz, f); } } void writetape(FILE *f) { fwrite(boot, 1, 512, f); fwrite(dir, 1, dirsz*sizeof(Dirent), f); u8 **fp = files; for(Dirent *d = dir; d < &dir[dirsz]; d++, fp++) { if(d->name[0] == '\0') continue; fseek(f, d->addr*512, 0); fwrite(*fp, 1, SZ(d), f); } } void table(void) { for(Dirent *d = dir; d < &dir[dirsz]; d++) { if(d->name[0] == '\0') continue; u16 s = 0; for(u16 *w = (u16*)d; w < (u16*)(d+1); w++) s += *w; printf("%.32s\t%06o %o %o\t%d\t(%d) %u\t%06o %06o %06o\n", d->name, d->mode, d->uid, d->gid, SZ(d), NBLK(SZ(d)), d->mtime, d->addr, d->chk, s); } } void extract(void) { FILE *f; char name[33]; name[32] = '\0'; u8 **fp = files; for(Dirent *d = dir; d < &dir[dirsz]; d++, fp++) { if(d->name[0] == '\0') continue; memcpy(name, d->name, 32); f = fopen(name, "wb"); if(f == nil) { fprintf(stderr, "couldn't open %s\n", name); } else { fwrite(*fp, 1, SZ(d), f); fclose(f); } } } void addfile(char *path) { printf("add file %s\n", path); Dirent *d; u8 **fp = files; for(d = dir; d < &dir[dirsz]; d++, fp++) if(d->name[0] == '\0') goto found; fprintf(stderr, "directory full\n"); return; found: FILE *f = fopen(path, "rb"); if(f == nil) { fprintf(stderr, "can't open file %s\n", path); return; } fseek(f, 0, 2); int sz = ftell(f); fseek(f, 0, 0); *fp = malloc(sz); fread(*fp, 1, sz, f); fclose(f); strncpy(d->name, path, 32); // TMP d->mode = 0644; d->uid = 3; d->gid = 1; d->s1 = sz>>16; d->s2 = sz; d->mtime = time(NULL); changed = 1; } void recalc(void) { int block = dirsz/8 + 1; printf("first %o\n", block); for(Dirent *d = dir; d < &dir[dirsz]; d++) { if(d->name[0] == '\0') continue; d->addr = block; block += NBLK(SZ(d)); u16 s = 0; for(u16 *w = (u16*)d; w < &d->chk; w++) s += *w; d->chk = -s; } printf("last %o\n", block); } int main(int argc, char *argv[]) { FILE *f; char key = 't'; char *filename; assert(sizeof(Dirent) == 64); argv++; argc--; if(argc < 2) usage(); filename = *argv++; argc--; f = fopen(filename, "rb"); if(f == nil) { fprintf(stderr, "can't open file %s\n", filename); return 1; } int m = 0; // 1 for magtape dirsz = m ? 496 : 192; readtape(f); key = **argv++; argc--; switch(key) { case 't': table(); break; case 'x': extract(); break; case 'r': while(argc--) addfile(*argv++); break; } fclose(f); if(changed) { recalc(); f = fopen(filename, "wb"); if(f == nil) { fprintf(stderr, "can't open file %s\n", filename); return 1; } writetape(f); fclose(f); } return 0; }