/* * read an old (V6 and before) PDP-11 Unix filesystem * quick, cheap hack; runs only on VAXes */ /* * miscellaneous filesystem definitions * some are magic numbers here */ #include <stdio.h> #include <sys/types.h> #include <sys/inode.h> #include <sys/dir.h> /* hack: pdp11 dirs == vax dirs */ #define BLSIZE 512 /* * v6 disk inode */ #define V6NADDR 8 struct v6dinode { short flags; unsigned char nlinks; unsigned char uid; unsigned char gid; unsigned char hisize; unsigned short losize; unsigned short addr[V6NADDR]; unsigned short atime[2]; /* pdp-11 order */ unsigned short mtime[2]; /* pdp-11 order */ }; /* * type part of mode */ #define V6FMT 0160000 #define V6IFREG 0100000 #define V6IFDIR 0140000 #define V6IFCHR 0120000 #define V6IFBLK 0160000 #define V6MODE 07777 #define V6LARGE 010000 #define V6SUPERB 1 #define V6ROOT 1 /* root inode */ /* * local file data */ typedef struct Fsfile { long addr[V6NADDR]; int large; } Fsfile; #define fsp(f) ((Fsfile *)((f)->fs)) #include "rf.h" #include <errno.h> #include <libc.h> int fserrno; static int devfd; static Rfile *root; /* * init: * open the device */ Rfile * fsinit(argc, argv) int argc; char **argv; { register Rfile *f; char *passwd, *group; if (argc <= 1) rfpanic("no device specified\n"); if ((devfd = open(argv[1], 0)) < 0) rfpanic("%s: cannot open\n", argv[1]); if (argc > 2) passwd = argv[2]; else passwd = "/etc/passwd"; if (argc > 3) group = argv[3]; else group = "/etc/group"; rfuidmap = rfmkidmap(passwd, (Namemap *)0); rfgidmap = rfmkidmap(group, (Namemap *)0); /* never mind the super-block */ if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL) rfpanic("no mem for root\n"); if ((f->fs = malloc(sizeof(Fsfile))) == NULL) rfpanic("no mem for root\n"); f->ino = V6ROOT; fsstat(f); root = f; return (f); } /* * access a file */ Rfile * fswalk(df, name) Rfile *df; char *name; { register Rfile *f; int ino; if ((ino = dsearch(df, name)) == 0) { fserrno = ENOENT; return (NULL); } if (df == root) { /* "." and ".." magic */ if (strcmp(name, ".") == 0) return (df); if (strcmp(name, "..") == 0) { fserrno = 0; /* pseudo-error: popped out of root */ return (NULL); } } if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL) { fserrno = ENOMEM; return (NULL); } if ((f->fs = malloc(sizeof(Fsfile))) == NULL) { free((char *)f); fserrno = ENOMEM; return (NULL); } f->ino = ino; fsstat(f); return (f); } /* * discard a file reference */ int fsdone(f) Rfile *f; { free(f->fs); free((char *)f); return (0); } /* * return file status */ int fsstat(f) Rfile *f; { getino(f); return (0); } /* * read data */ int fsread(f, off, buf, len) register Rfile *f; long off; char *buf; int len; { char blk[BLSIZE]; int rest; daddr_t bno; switch (f->mode & IFMT) { case IFREG: case IFDIR: break; default: return (0); } if (off >= f->size) return (0); if (off + len > f->size) len = f->size - off; bno = off / BLSIZE; if (getlblk(f, bno, blk) == 0) return (-1); rest = (bno + 1)*BLSIZE - off; if (len > rest) len = rest; memcpy(buf, blk + (off % BLSIZE), len); return (len); } /* * read a piece of a directory * -- cheap out for now: just return one */ int fsdirread(f, off, buf, len, offp) register Rfile *f; long off; char *buf; int len; long *offp; { int stlen; register struct direct *de; char blk[BLSIZE]; char one[BLSIZE]; int n; if (off % sizeof(struct direct)) { fserrno = EINVAL; return (-1); } stlen = len; de = (struct direct *)&blk[BLSIZE]; for (; off < f->size; de++, off += sizeof(struct direct)) { if (de >= (struct direct *)&blk[BLSIZE]) { if (getlblk(f, off/BLSIZE, blk) == 0) break; de = (struct direct *)&blk[off%BLSIZE]; } if (de->d_ino == 0) continue; n = sprintf(one, "%d\t%.14s", de->d_ino, de->d_name); n++; /* need the NUL too */ if (n > len) break; memcpy(buf, one, n); len -= n; buf += n; } *offp = off; return (stlen - len); } /* * fetch an i-node * -- no sanity check for now * -- magic inode-to-disk-block stuff here */ #define LINOPB (BLSIZE/sizeof(struct v6dinode)) int getino(f) register Rfile *f; { char buf[BLSIZE]; register struct v6dinode *dp; register int ioff; register int i; int mode; ioff = f->ino - 1; lseek(devfd, (long)BLSIZE*(ioff/LINOPB + V6SUPERB + 1), 0); if (read(devfd, buf, BLSIZE) != BLSIZE) { /* print error */ return (0); } dp = ((struct v6dinode *)buf) + (ioff%LINOPB); switch (dp->flags & V6FMT) { case V6IFREG: mode = IFREG; break; case V6IFDIR: mode = IFDIR; break; case V6IFCHR: mode = IFCHR; break; case V6IFBLK: mode = IFBLK; break; default: return (0); /* unalloc or illegal */ } for (i = 0; i < V6NADDR; i++) fsp(f)->addr[i] = dp->addr[i]; f->dev = 0; /* all the same device */ f->rdev = fsp(f)->addr[0]; f->mode = mode | (dp->flags & V6MODE); fsp(f)->large = (dp->flags & V6LARGE) != 0; f->nlink = dp->nlinks; f->uid = dp->uid; f->gid = dp->gid; f->size = (dp->hisize << 16) + dp->losize; f->tm = (dp->mtime[0]<<16) + dp->mtime[1]; f->ta = (dp->atime[0]<<16) + dp->atime[1]; f->tc = f->tm; return (1); } /* * look up a file */ #define LNDPB (BLSIZE/sizeof(struct direct)) int dsearch(f, name) Rfile *f; char *name; { struct direct dbuf[LNDPB]; register struct direct *de; register int i; register long b, size; for (b = 0, size = f->size; size > 0; b++, size -= BLSIZE) { if (getlblk(f, b, (char *)dbuf) == 0) continue; for (i = 0, de = dbuf; i < LNDPB; i++, de++) { if (de->d_ino == 0) continue; if (strncmp(de->d_name, name, DIRSIZ) == 0) return (de->d_ino); } } return (0); } /* * read a block from a file */ daddr_t bmap(); getlblk(f, bno, buf) Rfile *f; daddr_t bno; char *buf; { daddr_t dbno; if ((dbno = bmap(f, bno)) == 0) { memset(buf, 0, BLSIZE); return (1); } lseek(devfd, dbno*BLSIZE, 0); if (read(devfd, buf, BLSIZE) != BLSIZE) { fserrno = errno; return (0); } return (1); } /* * logical to physical block * only singly-indirect files for now */ #define LNINDIR (BLSIZE/sizeof(unsigned short)) daddr_t bmap(f, bno) register Rfile *f; daddr_t bno; { unsigned short indbuf[LNINDIR]; if (fsp(f)->large == 0) { if (bno < V6NADDR) return (fsp(f)->addr[bno]); return (0); } if (bno < V6NADDR*LNINDIR) { lseek(devfd, fsp(f)->addr[bno/LNINDIR]*BLSIZE, 0); if (read(devfd, (char *)indbuf, BLSIZE) != BLSIZE) return (0); return (indbuf[bno%LNINDIR]); } return (0); }