|
|
1.1 ! root 1: /* ! 2: * read a V7 PDP-11 dump tape as a filesystem ! 3: */ ! 4: #include <stdio.h> ! 5: #include <rf.h> ! 6: #include <sys/types.h> ! 7: #include <sys/stat.h> ! 8: #include <errno.h> ! 9: ! 10: /* ! 11: * PDP-11 integers ! 12: */ ! 13: #define p11s(c) ((c)[0]|((c)[1]<<8)) ! 14: #define p11l(c) ((c)[2]|((c)[3]<<8)|((c)[0]<<16)|((c)[1]<<24)) /* wretched FP-11 */ ! 15: #define P11S 2 /* size of PDP-11 short */ ! 16: #define P11L 4 /* size of PDP-11 long */ ! 17: ! 18: /* ! 19: * PDP-11 disk inode offsets ! 20: */ ! 21: ! 22: #define DI_MODE 0 /* (short) */ ! 23: #define DI_NLINK 2 /* (short) */ ! 24: #define DI_UID 4 /* (short) */ ! 25: #define DI_GID 6 /* (short) */ ! 26: #define DI_SIZE 8 /* (long) */ ! 27: #define DI_ADDR 12 /* 40 bytes */ ! 28: #define DI_ATIME 52 /* (long) */ ! 29: #define DI_MTIME 56 /* (long) */ ! 30: #define DI_CTIME 60 /* (long) */ ! 31: #define DILEN 64 ! 32: ! 33: /* ! 34: * PDP-11 directory entry ! 35: */ ! 36: ! 37: #define D_INO 0 /* (short) */ ! 38: #define D_NAME 2 /* 14 characters */ ! 39: #define DNSIZE 14 ! 40: #define DLEN 16 ! 41: ! 42: /* ! 43: * dump records ! 44: */ ! 45: ! 46: #define TBSIZE 512 ! 47: ! 48: #define MAGIC (int)60011 ! 49: ! 50: #define TS_TAPE 1 ! 51: #define TS_INODE 2 ! 52: #define TS_BITS 3 ! 53: #define TS_ADDR 4 ! 54: #define TS_END 5 ! 55: #define TS_CLRI 6 ! 56: ! 57: struct spcl11 { /* header as found on the tape */ ! 58: unsigned char c_type[P11S]; ! 59: unsigned char c_date[P11L]; ! 60: unsigned char c_ddate[P11L]; ! 61: unsigned char c_volume[P11S]; ! 62: unsigned char c_tapea[P11L]; ! 63: unsigned char c_inumber[P11S]; ! 64: unsigned char c_magic[P11S]; ! 65: unsigned char c_checksum[P11S]; ! 66: unsigned char c_dinode[DILEN]; ! 67: unsigned char c_count[P11S]; ! 68: unsigned char c_addr[TBSIZE]; ! 69: }; ! 70: ! 71: struct spcl { /* header we use internally */ ! 72: int c_type; ! 73: int c_inumber; ! 74: unsigned char c_dinode[DILEN]; ! 75: int c_count; ! 76: char c_addr[TBSIZE]; ! 77: }; ! 78: ! 79: /* ! 80: * our data ! 81: */ ! 82: ! 83: typedef unsigned int taddr_t; ! 84: ! 85: #define MAXINO 10000 /* dynamic would be better */ ! 86: static taddr_t iaddr[MAXINO]; /* offset of TS_INODE for this file */ ! 87: ! 88: static int devfd; ! 89: static Rfile *root; ! 90: int fserrno; ! 91: ! 92: struct spcl *getspcl(); ! 93: taddr_t curtblock(); ! 94: Rfile *getino(); ! 95: ! 96: char *malloc(); ! 97: long lseek(); ! 98: ! 99: /* ! 100: * init ! 101: */ ! 102: Rfile * ! 103: fsinit(argc, argv) ! 104: int argc; ! 105: char **argv; ! 106: { ! 107: ! 108: if (argc <= 1) ! 109: rfpanic("no device\n"); ! 110: if ((devfd = open(argv[1], 0)) < 0) ! 111: rfpanic("%s: cannot open\n", argv[1]); ! 112: scantape(); ! 113: if ((root = getino(2)) == NULL) ! 114: rfpanic("no root\n"); ! 115: return (root); ! 116: } ! 117: ! 118: /* ! 119: * look up a file ! 120: */ ! 121: Rfile * ! 122: fswalk(df, name) ! 123: Rfile *df; ! 124: char *name; ! 125: { ! 126: int ino; ! 127: ! 128: if ((ino = dsearch(df, name)) == 0) { ! 129: fserrno = ENOENT; ! 130: return (NULL); ! 131: } ! 132: if (df == root) { /* "." and ".." magic */ ! 133: if (strcmp(name, ".") == 0) ! 134: return (df); ! 135: if (strcmp(name, "..") == 0) { ! 136: fserrno = 0; /* pseudo-error */ ! 137: return (NULL); ! 138: } ! 139: } ! 140: return (getino(ino)); ! 141: } ! 142: ! 143: /* ! 144: * all done with a file ! 145: */ ! 146: fsdone(f) ! 147: Rfile *f; ! 148: { ! 149: free(f->fs); ! 150: free((char *)f); ! 151: return (0); ! 152: } ! 153: ! 154: /* ! 155: * read data ! 156: */ ! 157: int ! 158: fsread(f, off, buf, len) ! 159: register Rfile *f; ! 160: long off; ! 161: char *buf; ! 162: int len; ! 163: { ! 164: char blk[TBSIZE]; ! 165: int rest; ! 166: long bno; ! 167: ! 168: switch (f->mode & S_IFMT) { ! 169: case S_IFREG: ! 170: case S_IFDIR: ! 171: break; ! 172: ! 173: default: ! 174: return (0); ! 175: } ! 176: if (off >= f->size) ! 177: return (0); ! 178: if (off + len > f->size) ! 179: len = f->size - off; ! 180: bno = off / TBSIZE; ! 181: if (getblk(f, bno, blk) == 0) ! 182: return (-1); ! 183: rest = (bno + 1)*TBSIZE - off; ! 184: if (len > rest) ! 185: len = rest; ! 186: memcpy(buf, blk + (off % TBSIZE), len); ! 187: return (len); ! 188: } ! 189: ! 190: /* ! 191: * read a piece of a directory ! 192: * -- cheap out for now: just return one ! 193: */ ! 194: int ! 195: fsdirread(f, off, buf, len, offp) ! 196: register Rfile *f; ! 197: long off; ! 198: char *buf; ! 199: int len; ! 200: long *offp; ! 201: { ! 202: int stlen; ! 203: register unsigned char *de; ! 204: unsigned char blk[TBSIZE]; ! 205: unsigned char one[TBSIZE]; ! 206: int n, ino; ! 207: ! 208: if (off % DLEN) { ! 209: fserrno = EINVAL; ! 210: return (-1); ! 211: } ! 212: stlen = len; ! 213: de = &blk[TBSIZE]; ! 214: for (; off < f->size; de += DLEN, off += DLEN) { ! 215: if (de >= &blk[TBSIZE]) { ! 216: if (getblk(f, off/TBSIZE, blk) == 0) ! 217: break; ! 218: de = &blk[off%TBSIZE]; ! 219: } ! 220: ino = p11s(&de[D_INO]); ! 221: if (ino == 0) ! 222: continue; ! 223: n = sprintf(one, "%d\t%.14s", ino, &de[D_NAME]); ! 224: n++; /* need the NUL too */ ! 225: if (n > len) ! 226: break; ! 227: memcpy(buf, one, n); ! 228: len -= n; ! 229: buf += n; ! 230: } ! 231: *offp = off; ! 232: return (stlen - len); ! 233: } ! 234: ! 235: /* ! 236: * search a directory ! 237: */ ! 238: int ! 239: dsearch(f, name) ! 240: Rfile *f; ! 241: char *name; ! 242: { ! 243: unsigned char dbuf[TBSIZE]; ! 244: register unsigned char *de; ! 245: register int ino; ! 246: register long b, size; ! 247: ! 248: for (b = 0, size = f->size; size > 0; b++, size -= TBSIZE) { ! 249: if (getblk(f, b, dbuf) == 0) ! 250: continue; ! 251: for (de = dbuf; de < &dbuf[TBSIZE]; de += DLEN) { ! 252: ino = p11s(&de[D_INO]); ! 253: if (ino == 0) ! 254: continue; ! 255: if (strncmp(&de[D_NAME], name, DNSIZE) == 0) ! 256: return (ino); ! 257: } ! 258: } ! 259: return (0); ! 260: } ! 261: ! 262: /* ! 263: * retrieve file data ! 264: */ ! 265: Rfile * ! 266: getino(i) ! 267: int i; ! 268: { ! 269: register Rfile *f; ! 270: register struct spcl *sp; ! 271: long nblocks; ! 272: ! 273: if (i >= MAXINO || i < 0 || iaddr[i] == 0) { ! 274: rflog("%d: bad i-number\n", i); ! 275: fserrno = EINVAL; ! 276: return (NULL); ! 277: } ! 278: lseek(devfd, (long)iaddr[i] * TBSIZE, 0); ! 279: if ((sp = getspcl()) == NULL ! 280: || sp->c_type != TS_INODE) { ! 281: rflog("%d: can't find header\n", i); ! 282: fserrno = EIO; ! 283: return (NULL); ! 284: } ! 285: if (sp->c_inumber != i) { ! 286: rflog("%d: found header for %d instead\n", ! 287: i, sp->c_inumber); ! 288: fserrno = EIO; ! 289: return (NULL); ! 290: } ! 291: if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL) { ! 292: rflog("%d: no memory for header\n", i); ! 293: fserrno = ENOMEM; ! 294: return (NULL); ! 295: } ! 296: f->ino = i; ! 297: f->dev = 0; ! 298: f->mode = p11s(&sp->c_dinode[DI_MODE]); /* understood same bits */ ! 299: f->nlink = p11s(&sp->c_dinode[DI_NLINK]); ! 300: f->uid = p11s(&sp->c_dinode[DI_UID]); ! 301: f->gid = p11s(&sp->c_dinode[DI_GID]); ! 302: f->rdev = 0; ! 303: f->size = p11l(&sp->c_dinode[DI_SIZE]); ! 304: f->ta = p11l(&sp->c_dinode[DI_ATIME]); ! 305: f->tm = p11l(&sp->c_dinode[DI_MTIME]); ! 306: f->tc = p11l(&sp->c_dinode[DI_CTIME]); ! 307: nblocks = (f->size + TBSIZE - 1)/TBSIZE; ! 308: if ((f->fs = malloc(nblocks * sizeof(taddr_t))) == NULL) { ! 309: rflog("%d: no mem for %d block addresses\n", i, nblocks); ! 310: fserrno = ENOMEM; ! 311: free((char *)f); ! 312: return (NULL); ! 313: } ! 314: scanfile(sp, (taddr_t *)f->fs, nblocks); ! 315: return (f); ! 316: } ! 317: ! 318: /* ! 319: * read a TBSIZE block from file ! 320: */ ! 321: getblk(f, bno, buf) ! 322: register Rfile *f; ! 323: long bno; ! 324: char *buf; ! 325: { ! 326: ! 327: if (bno * TBSIZE > f->size) { ! 328: fserrno = 0; ! 329: return (0); ! 330: } ! 331: lseek(devfd, (long)((taddr_t *)f->fs)[bno] * TBSIZE, 0); ! 332: if (read(devfd, buf, TBSIZE) != TBSIZE) { ! 333: rflog("%d: bno %ld: errno %d\n", f->ino, bno, errno); ! 334: fserrno = errno; ! 335: return (0); ! 336: } ! 337: return (1); ! 338: } ! 339: ! 340: /* ! 341: * scan the tape, ! 342: * remember where all the file records are ! 343: */ ! 344: ! 345: scantape() ! 346: { ! 347: register struct spcl *sp; ! 348: register int i; ! 349: ! 350: for (;;) { ! 351: if ((sp = getspcl()) == NULL) { ! 352: rflog("unexpected tape EOF\n"); ! 353: return; ! 354: } ! 355: switch (sp->c_type) { ! 356: case TS_END: ! 357: return; ! 358: ! 359: case TS_TAPE: ! 360: continue; ! 361: ! 362: case TS_BITS: ! 363: case TS_CLRI: ! 364: lseek(devfd, (long)sp->c_count * TBSIZE, 1); ! 365: continue; ! 366: ! 367: case TS_ADDR: ! 368: rflog("unexpected TS_ADDR i %d\n", sp->c_inumber); ! 369: continue; ! 370: ! 371: default: ! 372: rflog("ill spcl type %d i %d\n", ! 373: sp->c_type, sp->c_inumber); ! 374: continue; ! 375: ! 376: case TS_INODE: ! 377: i = sp->c_inumber; ! 378: if (i <= 0 || i >= MAXINO) ! 379: rflog("ill TS_FILE i %d\n", i); ! 380: else ! 381: iaddr[i] = curtblock() - 1; ! 382: scanfile(sp, (taddr_t *)NULL, ! 383: (p11l(&sp->c_dinode[DI_SIZE])+TBSIZE-1)/TBSIZE); ! 384: continue; ! 385: } ! 386: } ! 387: } ! 388: ! 389: /* ! 390: * skip lightly through a file, ! 391: * remembering where the blocks are ! 392: * ip is an array of tape addresses; ! 393: * n is the length of the array, if present, ! 394: * which is the same as the number of blocks expected ! 395: * call with the TS_INODE record, ! 396: * since that contains the first list of blocks ! 397: */ ! 398: ! 399: scanfile(sp, ip, n) ! 400: register struct spcl *sp; ! 401: register taddr_t *ip; ! 402: register int n; ! 403: { ! 404: register int i; ! 405: taddr_t tblock; ! 406: ! 407: tblock = curtblock(); ! 408: while (n) { ! 409: for (i = 0; i < sp->c_count; i++) { ! 410: if (sp->c_count == 0) { /* hole */ ! 411: if (ip) ! 412: *ip++ = 0; ! 413: } else { /* real */ ! 414: if (ip) ! 415: *ip++ = tblock; ! 416: tblock++; ! 417: } ! 418: if (--n <= 0) ! 419: break; ! 420: } ! 421: lseek(devfd, (long)tblock*TBSIZE, 0); /* past data */ ! 422: if (n <= 0) ! 423: return; ! 424: /* ! 425: * more: get TS_ADDR ! 426: */ ! 427: if ((sp = getspcl()) == NULL) { ! 428: rflog("unexpected tape EOF\n"); ! 429: return; ! 430: } ! 431: if (sp->c_type != TS_ADDR) { ! 432: rflog("wanted TS_ADDR, got type %d i %d\n", ! 433: sp->c_type, sp->c_inumber); ! 434: unspcl(); ! 435: return; ! 436: } ! 437: tblock++; /* count the header we just read */ ! 438: } ! 439: } ! 440: ! 441: struct spcl * ! 442: getspcl() ! 443: { ! 444: char buf[TBSIZE]; ! 445: static struct spcl s; ! 446: register struct spcl11 *tp; ! 447: int nbad; ! 448: ! 449: nbad = 0; ! 450: tp = (struct spcl11 *)buf; ! 451: for (;;) { ! 452: if (read(devfd, buf, TBSIZE) != TBSIZE) { ! 453: rflog("tape scan read, errno %d\n", errno); ! 454: return (NULL); ! 455: } ! 456: if (p11s(tp->c_magic) != MAGIC) { ! 457: nbad++; ! 458: continue; ! 459: } ! 460: s.c_type = p11s(tp->c_type); ! 461: s.c_inumber = p11s(tp->c_inumber); ! 462: s.c_count = p11s(tp->c_count); ! 463: /* a sanity check or two would go well here */ ! 464: memcpy(s.c_dinode, tp->c_dinode, DILEN); ! 465: memcpy(s.c_addr, tp->c_addr, s.c_count); ! 466: if (nbad) ! 467: rflog("skipped %d to type %d i %d\n", ! 468: nbad, s.c_type, s.c_inumber); ! 469: return (&s); ! 470: } ! 471: } ! 472: ! 473: /* ! 474: * reread the current header: cheap hack ! 475: */ ! 476: unspcl() ! 477: { ! 478: lseek(devfd, (long)-TBSIZE, 1); ! 479: } ! 480: ! 481: taddr_t ! 482: curtblock() ! 483: { ! 484: return (lseek(devfd, 0L, 1)/TBSIZE); ! 485: } ! 486:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.