# /* Read file off of Unix filesystem. * * Filename mode doesn't deal with mounted (i.e. no-root) filesystems; * in such cases, give the name relative to the root of the mounted * filesystem. */ #include #include "../sys/h/wfilsys.h" #include "../sys/h/wino.h" #define DIRSIZ 14 struct dirent { short int d_inum; char d_name[DIRSIZ]; }; #define BLKSIZ 512 #define ROOTBLK 1 #define INOST 2 /* First inode block */ #define NINOBL (BLKSIZ / sizeof(struct inode)) #define FILSIZ 65536 #define SMLSIZ 8 #define INDSIZ (BLKSIZ / sizeof(short unsigned)) #define ROOTINO 1 /* Inum for root directory */ #define NDIRBL (BLKSIZ / sizeof(struct dirent)) struct filsys fisys; struct inode inod; char ibuf[BLKSIZ]; char nobuf[BLKSIZ] = {0}; /* For unassigned blocks */ unsigned short ibbuf[INDSIZ]; char *ffnm, *ofnm; FILE *fsys, *out; int ino = 0, maxino; long iloc, size; unsigned blksiz, eblksz; unsigned nblks, lstblk; int dflg = 0; /* Debug; print entry and value */ int fflg = 0; /* Force read of dir inode */ int main(argc, argv) int argc; char *argv[]; { char *arg; register char *fnm; if (argc < 4) { printf("\nfilex {-d} {-i } {}\n"); exit(1); } argv++; argc--; for (;;) { arg = *argv; if (*arg++ != '-') break; argv++; argc--; switch (*arg) { case 'd': dflg++; break; case 'f': fflg++; break; case 'i': ino = atoi(*argv++); argc--; if (ino < 0) { printf("Bad inode number: %\n", ino); exit(1); } break; default: printf("Bad flag: %c", *arg); exit(1); } } ffnm = *argv++; argc--; fsys = fopen(ffnm, "rb"); if (fsys == NULL) { printf("Error opening input file: '%s'\n", ffnm); exit(1); } ofnm = *argv++; argc--; out = fopen(ofnm, "wb"); if (out == NULL) { printf("Error opening output file: '%s'\n", ofnm); exit(1); } if (ino == 0) { if (argc <= 0) { printf("No inode given, must provide file name\n"); exit(1); } fnm = *argv++; argc--; if (*fnm++ != '/') { printf("File must be rooted, no working dirs\n"); exit(1); } } if (argc > 0) { printf("Unneeded extra arg '%s'\n", *argv); exit(1); } if (fseek(fsys, (ROOTBLK * BLKSIZ), SEEK_SET) != 0) { printf("Root block seek failed\n"); exit(1); } if (fread(((char *) &fisys), sizeof(struct filsys), 1, fsys) != 1) { printf("Root block Read failed\n"); exit(1); } if (dflg) printf("maxino: %d maxblk: %d\n", fisys.s_isize, fisys.s_fsize); maxino = (fisys.s_isize * NINOBL); if (ino == 0) ino = findi(fnm); rdinode(ino); fflush(out); fclose(out); if (blksiz == BLKSIZ) { blksiz = 0; lstblk++; } printf("%d+%d blocks read\n", lstblk, blksiz); } findi(fnm) char *fnm; { register char *cp; char *fend, *dnm; int flen, i; int inum = ROOTINO; flen = strlen(fnm); fend = (fnm + flen); dnm = fnm; i = 0; for (cp = fnm; (cp < fend);) { if (*cp != '/') { if (i++ < DIRSIZ) { cp++; continue; } printf("Directory element '%s' too long\n", dnm); exit(1); } *cp++ = '\0'; inum = rddir(inum, dnm); dnm = cp; i = 0; } inum = rddir(inum, dnm); if (dflg) printf("found file '%s' - %d\n", dnm, inum); return (inum); } /* Only handles directories in 'small' files for the moment. That should * be OK for almost all uses - that allows up to 224 files in a directory. */ rddir(idir, nm) char *nm; { register struct dirent *dp; struct dirent *dirend; char *dnm; unsigned short mode, fmt; unsigned blkno, cblk; int inum; if (dflg) printf("lookup entry '%s' in %d\n", nm, idir); mode = getinode(idir); fmt = (mode & IFMT); if (fmt != IFDIR) { printf("Inode %d is not a directory, cannot extract\n", idir); exit(1); } if ((mode & ILARG) != 0) { printf("Inode %d is large, only small dirs handled\n", idir); exit(1); } for (blkno = 0; (blkno < nblks); blkno++) { if (blkno == lstblk) blksiz = eblksz; cblk = inod.i_addr[blkno]; if (dflg) printf("checking dir block %d-%d, %d entries\n", blkno, cblk, (blksiz / sizeof(struct dirent))); if (cblk != 0) rdblk(&ibuf[0], cblk); dirend = ((struct dirent *) (&ibuf[0] + blksiz)); for (dp = ((struct dirent *) &ibuf[0]); (dp < dirend); dp++) { inum = dp->d_inum; dnm = &dp->d_name[0]; if (dflg > 1) printf("dirent: %d '%.14s'\n", inum, dnm); if (strncmp(nm, dnm, DIRSIZ) != 0) continue; if (inum == 0) continue; if (dflg) printf("found entry '%s' - %d\n", nm, inum); return(inum); } } printf("Directory entry '%s' not found in directory inode %d\n", nm, idir); exit(1); } getinode(inum) { unsigned short mode, fmt; if (dflg) printf("rd inum: %ld\n", inum); if (inum >= maxino) { printf("inode %d large than max inode no %d\n", ino, maxino); exit(1); } iloc = ((INOST * BLKSIZ) + ((inum - 1) * sizeof(struct inode))); if (dflg) printf("iloc: %ld\n", iloc); if (fseek(fsys, iloc, SEEK_SET) != 0) { printf("Inode seek failed\n"); exit(1); } if (fread(((char *) &inod), sizeof(struct inode), 1, fsys) != 1) { printf("Inode read failed\n"); exit(1); } fmt = ((mode = inod.i_mode) & IFMT); if ((mode & IALLOC) == 0) { printf("Inode %d is not allocated, cannot extract\n", inum); exit(1); } if ((fmt == IFCHR) || (fmt == IFBLK)) { printf("Inode %d is a device, cannot extract\n", inum); exit(1); } if (dflg) printf("size: %o-%o\n", inod.i_size0, inod.i_size1); size = ((inod.i_size0 * FILSIZ) + inod.i_size1); nblks = (size / BLKSIZ); blksiz = BLKSIZ; eblksz = (size % BLKSIZ); if (eblksz == 0) eblksz = BLKSIZ; else nblks++; lstblk = (nblks - 1); if ((size > (BLKSIZ * SMLSIZ)) && ((mode & ILARG) == 0)) { printf("Inode %d is small, length %d too long\n", inum, size); exit(1); } if ((size <= (BLKSIZ * SMLSIZ)) && ((mode & ILARG) != 0)) { printf("Inode %d is large, length %d too short\n", inum, size); exit(1); } if (dflg) { printf("mode: %o size: %d\n", mode, size); printf("nblks: %d lstblk: %d eblksz: %d\n", nblks, lstblk, eblksz); } return(mode); } rdinode(inum) { int mode, fmt; mode = getinode(inum); fmt = (mode & IFMT); if ((fmt != 0) && ((fmt == IFDIR) & (fflg == 0))) { printf("Inode %d is not a file, cannot extract\n", ino); exit(1); } if ((mode & ILARG) == 0) rdsmall(fsys, out); else rdlarge(fsys, out); } rdsmall() { unsigned blkno, cblk; for (blkno = 0; (blkno < nblks); blkno++) { if (blkno == lstblk) blksiz = eblksz; cblk = inod.i_addr[blkno]; xferblk(cblk, blkno); } } rdlarge() { unsigned niblks, lstiblk, resiblk, iblkno, ciblk; unsigned blkno, endblk, cblk; register unsigned short *ibp; niblks = (nblks / INDSIZ); lstiblk = niblks; resiblk = (nblks % INDSIZ); if (resiblk == 0) lstiblk--; else niblks++; if (dflg) printf("niblks: %d lstiblk: %d resiblk: %d\n", niblks, lstiblk, resiblk); if (niblks >= 7) { printf("HUGE file (%d iblks) - not supported yet\n", niblks); exit(1); } blkno = 0; for (iblkno = 0; (iblkno < niblks); iblkno++) { ciblk = inod.i_addr[iblkno]; if (dflg) printf("Rd iblock %d - %d\n", iblkno, ciblk); if (ciblk >= fisys.s_fsize) { printf("Indir blk number %d - %d too large\n", iblkno, ciblk); exit(1); } rdblk(((char *) &ibbuf[0]), ciblk); endblk = ((iblkno != lstiblk) ? (blkno + INDSIZ) : resiblk); if (dflg) printf("st blk: %d end blk: %d\n", blkno, endblk); for (ibp = &ibbuf[0]; (blkno < endblk); blkno++) { if (blkno == lstblk) blksiz = eblksz; cblk = *ibp++; xferblk(cblk, blkno); } } } xferblk(cblk, blkno) unsigned cblk, blkno; { char *bloc; if (dflg) printf("Xfer block %d-%d %d\n", blkno, cblk, blksiz); if (cblk >= fisys.s_fsize) { printf("Xfer block number %d - %d too large\n", blkno, cblk); exit(1); } if (cblk != 0) { bloc = &ibuf[0]; rdblk(bloc, cblk); } else bloc = &nobuf[0]; if (fwrite(bloc, sizeof(char), blksiz, out) != blksiz) { printf("Write of block %d failed\n", blkno); exit(1); } } rdblk(bloc, cblk) char *bloc; unsigned cblk; { if (dflg > 1) printf("Read block %d\n", cblk); if (cblk >= fisys.s_fsize) { printf("Read block number %d too large\n", cblk); exit(1); } if (fseek(fsys, (cblk * BLKSIZ), SEEK_SET) != 0) { printf("Read seek to block %d - %d failed\n", cblk); exit(1); } if (fread(bloc, sizeof(char), blksiz, fsys) != blksiz) { printf("Read of block %d failed\n", cblk); exit(1); } }