|
|
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.