From: Alan Cox Date: Fri, 17 Jun 2016 22:30:50 +0000 (+0100) Subject: fsck: move to a cut of the same fsck used for Standalone X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=03cd2aed0cda44855495c85b74ea1224fb72bad8;p=FUZIX.git fsck: move to a cut of the same fsck used for Standalone The goal being eventually to be able to use this fsck in both standalone and application cases. --- diff --git a/Applications/util/fsck.c b/Applications/util/fsck.c index 8ded14f9..72acab2c 100644 --- a/Applications/util/fsck.c +++ b/Applications/util/fsck.c @@ -1,269 +1,127 @@ -/************************************************** -UZI (Unix Z80 Implementation) Utilities: fsck.c - 21.09.99 corrected daread, ckdir - HP - 06.05.01 adapted to work under uzi - HP -***************************************************/ - #include +#include #include #include -#include -#include +#include #include +#include +#include "fsck.h" #define MAXDEPTH 20 /* Maximum depth of directory tree to search */ /* This checks a filesystem */ -int dev; -struct _uzifilesys filsys; +/* WARNING: This is a test version. Take a copy of the file system first. -#define SMOUNTED 12472 + To fsck a file system it must be unmounted. To fsck the root fs boot with + the root fs read only, fsck, sync, reboot + + TODO: change the bitmap to use bits to save memory. 64K blocks is then 8K + of RAM which should mean we can fsck a full sized fs ok + */ -typedef uint16_t blkno_t; +int dev = 0; +struct filesys superblock; +int swizzling = 0; /* Wrongendian ? */ +long offset; +int dev_fd; +int dev_offset; char *bitmap; int16_t *linkmap; - char *daread(uint16_t blk); -int yes(void); - -struct dinode { - uint16_t i_mode; - uint16_t i_nlink; - uint16_t i_uid; - uint16_t i_gid; - off_t i_size; - uint32_t i_atime; /* Breaks in 2038 */ - uint32_t i_mtime; /* Need to hide some extra bits ? */ - uint32_t i_ctime; /* 24 bytes */ - blkno_t i_addr[20]; -}; /* Exactly 64 bytes long! */ +void dwrite(uint16_t blk, char *addr); +void iread(uint16_t ino, struct dinode *buf); +void iwrite(uint16_t ino, struct dinode *buf); +void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum); +void ckdir(uint16_t inum, uint16_t pnum, char *name); +void dirread(struct dinode *ino, uint16_t j, struct direct *dentry); +void dirwrite(struct dinode *ino, uint16_t j, struct direct *dentry); +void mkentry(uint16_t inum); +blkno_t getblkno(struct dinode *ino, blkno_t num); +blkno_t blk_alloc0(struct filesys *filesys); + +void pass1(void); +void pass2(void); +void pass3(void); +void pass4(void); +void pass5(void); -/* Internal version */ -struct _uzidirent { - uint16_t d_ino; - char d_name[30]; -}; - -#define ROOTINODE 1 - - -char *daread(uint16_t blk) -{ - static char da_buf[512]; - - lseek(dev, blk * 512L, 0); - if (read(dev, da_buf, 512) != 512) { - fprintf(stderr, "Read of block %d failed.\n", blk); - exit(-1); - } - - return da_buf; -} - - -void dwrite(uint16_t blk, char *addr) +int yes(void) { - - lseek(dev, blk * 512L, 0); - if (write(dev, addr, 512) != 512) - fprintf(stderr, "Write of block %d failed %d.\n", blk, errno); - /*sync();*/ + printf("YESYES!\n"); + return 1; } -/* - * Getblkno gets a pointer index, and a number of a block in the file. - * It returns the number of the block on the disk. A value of zero - * means an unallocated block. - */ - -blkno_t getblkno(struct dinode *ino, blkno_t num) +int main(int argc, char **argv) { - blkno_t indb; - blkno_t dindb; - blkno_t *buf; + char *buf; + char *op; - if (num < 18) { /* Direct block */ - return (ino->i_addr[num]); + if(argc != 2){ + fprintf(stderr, "syntax: fsck [devfile][:offset]\n"); + return 1; } - if (num < 256 + 18) { /* Single indirect */ - indb = ino->i_addr[18]; - if (indb == 0) - return (0); - buf = (blkno_t *) daread(indb); - return (buf[num - 18]); + + op = strchr(argv[1], ':'); + if (op) { + *op++ = 0; + offset = atol(op); } - /* Double indirect */ - indb = ino->i_addr[19]; - if (indb == 0) - return (0); - - buf = (blkno_t *) daread(indb); - - dindb = buf[(num - (18 + 256)) >> 8]; - buf = (blkno_t *) daread(dindb); - return (buf[(num - (18 + 256)) & 0x00ff]); -} - - -/* - * Setblkno sets the given block number of the given file to the given - * disk block number, possibly creating or modifiying the indirect blocks. - * A return of zero means there were no blocks available to create an - * indirect block. This should never happen in fsck. - */ - -void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum) -{ - blkno_t indb; - blkno_t dindb; - blkno_t *buf; - - if (num < 18) { /* Direct block */ - ino->i_addr[num] = dnum; - } else if (num < 256 + 18) { /* Single indirect */ - indb = ino->i_addr[18]; - if (indb == 0) { - fprintf(stderr, "Missing indirect block"); - exit(-1); - } - - buf = (blkno_t *) daread(indb); - buf[num - 18] = dnum; - dwrite(indb, (char *) buf); - } else { /* Double indirect */ - indb = ino->i_addr[19]; - if (indb == 0) { - fprintf(stderr, "Missing indirect block"); - exit(-1); - } - - buf = (blkno_t *) daread(indb); - dindb = buf[(num - (18 + 256)) >> 8]; - if (dindb == 0) { - fprintf(stderr, "Missing indirect block"); - exit(-1); - } - - buf = (blkno_t *) daread(dindb); - buf[(num - (18 + 256)) & 0x00ff] = num; - dwrite(indb, (char *) buf); + if(fd_open(argv[1])){ + printf("Cannot open file\n"); + return -1; } -} + buf = daread(1); + bcopy(buf, (char *) &superblock, sizeof(struct filesys)); -/* - * blk_alloc0 allocates an unused block. - * A returned block number of zero means no more blocks. - */ - -/*--- was blk_alloc ---*/ - -blkno_t blk_alloc0(struct _uzifilesys *filsys) -{ - blkno_t newno; - blkno_t *buf; - int16_t j; - - newno = filsys->s_free[--filsys->s_nfree]; - if (!newno) { - ++filsys->s_nfree; - return (0); + /* Verify the fsize and isize parameters */ + if (superblock.s_mounted == SMOUNTED_WRONGENDIAN) { + swizzling = 1; + printf("Checking file system with reversed byte order.\n"); } - /* See if we must refill the s_free array */ - - if (!filsys->s_nfree) { - buf = (blkno_t *) daread(newno); - filsys->s_nfree = buf[0]; - for (j = 0; j < 50; j++) { - filsys->s_free[j] = buf[j + 1]; - } + if (swizzle16(superblock.s_mounted) != SMOUNTED) { + printf("Device %d has invalid magic number %d. Fix? ", dev, superblock.s_mounted); + if (!yes()) + exit(-1); + superblock.s_mounted = swizzle16(SMOUNTED); + dwrite((blkno_t) 1, (char *) &superblock); } + printf("Device %d has fsize = %d and isize = %d. Continue? ", + dev, swizzle16(superblock.s_fsize), swizzle16(superblock.s_isize)); + if (!yes()) + exit(-1); - --filsys->s_tfree; + bitmap = calloc(swizzle16(superblock.s_fsize), sizeof(char)); + linkmap = (int16_t *) calloc(8 * swizzle16(superblock.s_isize), sizeof(int16_t)); - if (newno < filsys->s_isize || newno >= filsys->s_fsize) { - printf("Free list is corrupt. Did you rebuild it?\n"); - return (0); + if (!bitmap || !linkmap) { + fprintf(stderr, "Not enough memory.\n"); + exit(-1); } - dwrite((blkno_t) 1, (char *) filsys); - return (newno); -} + printf("Pass 1: Checking inodes...\n"); + pass1(); + printf("Pass 2: Rebuilding free list...\n"); + pass2(); -void iread(uint16_t ino, struct dinode *buf) -{ - struct dinode *addr; - - addr = (struct dinode *) daread((ino >> 3) + 2); - bcopy((char *) &addr[ino & 7], (char *) buf, sizeof(struct dinode)); -} - - -void iwrite(uint16_t ino, struct dinode *buf) -{ - struct dinode *addr; - - addr = (struct dinode *) daread((ino >> 3) + 2); - bcopy((char *) buf, (char *) &addr[ino & 7], sizeof(struct dinode)); - dwrite((ino >> 3) + 2, (char *) addr); -} - - -void dirread(struct dinode *ino, uint16_t j, struct _uzidirent *dentry) -{ - blkno_t blkno; - char *buf; - - blkno = getblkno(ino, (blkno_t) j / 16); - if (blkno == 0) { - fprintf(stderr, "Missing block in directory"); - exit(-1); - } - buf = daread(blkno); - bcopy(buf + 32 * (j % 16), (char *) dentry, 32); -} - - -void dirwrite(struct dinode *ino, uint16_t j, struct _uzidirent *dentry) -{ - blkno_t blkno; - char *buf; + printf("Pass 3: Checking block allocation...\n"); + pass3(); - blkno = getblkno(ino, (blkno_t) j / 32); - if (blkno == 0) { - fprintf(stderr, "Missing block in directory"); - exit(-1); - } - buf = daread(blkno); - bcopy((char *) dentry, buf + 32 * (j % 16), 32); - dwrite(blkno, buf); -} + printf("Pass 4: Checking directory entries...\n"); + pass4(); -/* This makes an entry in "lost+found" for inode n */ + printf("Pass 5: Checking link counts...\n"); + pass5(); -void mkentry(uint16_t inum) -{ - struct dinode rootino; - struct _uzidirent dentry; - uint16_t d; + printf("Done.\n"); - iread(ROOTINODE, &rootino); - for (d = 0; d < rootino.i_size/32; ++d) { - dirread(&rootino, d, &dentry); - if (dentry.d_ino == 0 && dentry.d_name[0] == '\0') { - dentry.d_ino = inum; - sprintf(dentry.d_name, "l+f%d", inum); - dirwrite(&rootino, d, &dentry); - return; - } - } - printf("Sorry... No empty slots in root directory.\n"); + exit(0); } @@ -284,108 +142,109 @@ void pass1(void) icount = 0; - for (n = ROOTINODE; n < 8 * (filsys.s_isize - 2); ++n) { - iread(n, &ino); - linkmap[n] = -1; - if (ino.i_mode == 0) - continue; - - mode = ino.i_mode & S_IFMT; - - /* FIXME: named pipes ? */ - /* Check mode */ - if (mode != S_IFREG && mode != S_IFDIR && mode != S_IFBLK && mode != S_IFCHR) { - printf("Inode %d with mode 0%o is not of correct type. Zap? ", - n, ino.i_mode); - if (yes()) { - ino.i_mode = 0; - ino.i_nlink = 0; - iwrite(n, &ino); - continue; - } - } - linkmap[n] = 0; - ++icount; - /* Check size */ - - if (ino.i_size < 0) { - printf("Inode %d offset is negative with value of %ld. Fix? ", - n, ino.i_size); - if (yes()) { - ino.i_size = 0; - iwrite(n, &ino); - } - } - /* Check blocks and build free block map */ - if (mode == S_IFREG || mode == S_IFDIR) { - /* Check singly indirect blocks */ - - for (b = 18; b < 20; ++b) { - if (ino.i_addr[b] != 0 && (ino.i_addr[b] < filsys.s_isize || - ino.i_addr[b] >= filsys.s_fsize)) { - printf("Inode %d singly ind. blk %d out of range, val = %u. Zap? ", - n, b, ino.i_addr[b]); - if (yes()) { - ino.i_addr[b] = 0; - iwrite(n, &ino); - } - } - if (ino.i_addr[b] != 0 && ino.i_size < 18*512) { - printf("Inode %d singly ind. blk %d past end of file, val = %u. Zap? ", - n, b, ino.i_addr[b]); - if (yes()) { - ino.i_addr[b] = 0; - iwrite(n, &ino); - } - } - if (ino.i_addr[b] != 0) - bitmap[ino.i_addr[b]] = 1; - } - - /* Check the double indirect blocks */ - if (ino.i_addr[19] != 0) { - buf = (blkno_t *) daread(ino.i_addr[19]); - for (b = 0; b < 256; ++b) { - if (buf[b] != 0 && (buf[b] < filsys.s_isize || - buf[b] >= filsys.s_fsize)) { - printf("Inode %d doubly ind. blk %d is ", n, b); - printf("out of range, val = %u. Zap? ", buf[b]); - /* 1.4.98 - line split. HFB */ - if (yes()) { - buf[b] = 0; - dwrite(b, (char *) buf); - } - } - if (buf[b] != 0) - bitmap[buf[b]] = 1; - } - } - /* Check the rest */ - for (bno = 0; bno <= ino.i_size >> 9; ++bno) { - b = getblkno(&ino, bno); - - if (b != 0 && (b < filsys.s_isize || b >= filsys.s_fsize)) { - printf("Inode %d block %d out of range, val = %u. Zap? ", - n, bno, b); - if (yes()) { - setblkno(&ino, bno, 0); - iwrite(n, &ino); - } - } - if (b != 0) - bitmap[b] = 1; - } - } + for (n = ROOTINODE; n < 8 * (swizzle16(superblock.s_isize) - 2); ++n) { + iread(n, &ino); + linkmap[n] = -1; + if (ino.i_mode == 0) + continue; + + mode = swizzle16(ino.i_mode) & F_MASK; + /* FIXME: named pipes.. */ + + /* Check mode */ + if (mode != F_REG && mode != F_DIR && mode != F_BDEV && mode != F_CDEV) { + printf("Inode %d with mode 0%o is not of correct type. Zap? ", + n, swizzle16(ino.i_mode)); + if (yes()) { + ino.i_mode = 0; + ino.i_nlink = 0; + iwrite(n, &ino); + continue; + } + } + linkmap[n] = 0; + ++icount; + /* Check size */ + + if (swizzle32(ino.i_size) < 0) { + printf("Inode %d offset is negative with value of %ld. Fix? ", + n, (long)swizzle32(ino.i_size)); + if (yes()) { + ino.i_size = 0; + iwrite(n, &ino); + } + } + /* Check blocks and build free block map */ + if (mode == F_REG || mode == F_DIR) { + /* Check singly indirect blocks */ + + for (b = 18; b < 20; ++b) { + if (ino.i_addr[b] != 0 && + (swizzle16(ino.i_addr[b]) < swizzle16(superblock.s_isize) || + swizzle16(ino.i_addr[b]) >= swizzle16(superblock.s_fsize))) { + printf("Inode %d singly ind. blk %d out of range, val = %u. Zap? ", + n, b, swizzle16(ino.i_addr[b])); + if (yes()) { + ino.i_addr[b] = 0; + iwrite(n, &ino); + } + } + if (ino.i_addr[b] != 0 && swizzle32(ino.i_size) < 18*512) { + printf("Inode %d singly ind. blk %d past end of file, val = %u. Zap? ", + n, b, swizzle16(ino.i_addr[b])); + if (yes()) { + ino.i_addr[b] = 0; + iwrite(n, &ino); + } + } + if (ino.i_addr[b] != 0) + bitmap[swizzle16(ino.i_addr[b])] = 1; + } + + /* Check the double indirect blocks */ + if (ino.i_addr[19] != 0) { + buf = (blkno_t *) daread(swizzle16(ino.i_addr[19])); + for (b = 0; b < 256; ++b) { + if (buf[b] != 0 && (swizzle16(buf[b]) < swizzle16(superblock.s_isize) || + swizzle16(buf[b]) >= swizzle16(superblock.s_fsize))) { + printf("Inode %d doubly ind. blk %d is ", n, b); + printf("out of range, val = %u. Zap? ", swizzle16(buf[b])); + /* 1.4.98 - line split. HFB */ + if (yes()) { + buf[b] = 0; + dwrite(b, (char *) buf); + } + } + if (buf[b] != 0) + bitmap[swizzle16(buf[b])] = 1; + } + } + /* Check the rest */ + for (bno = 0; bno <= swizzle32(ino.i_size)/512; ++bno) { + b = getblkno(&ino, bno); + + if (b != 0 && (b < swizzle16(superblock.s_isize) || b >= swizzle16(superblock.s_fsize))) { + printf("Inode %d block %d out of range, val = %u. Zap? ", + n, bno, b); + if (yes()) { + setblkno(&ino, bno, 0); + iwrite(n, &ino); + } + } + if (b != 0) + bitmap[b] = 1; + } + } } - /* Fix free inode count in super block */ - if (filsys.s_tinode != 8 * (filsys.s_isize - 2) - ROOTINODE - icount) { - printf("Free inode count in super block is %u, should be %u. Fix? ", - filsys.s_tinode, 8 * (filsys.s_isize - 2) - ROOTINODE - icount); - - if (yes()) { - filsys.s_tinode = 8 * (filsys.s_isize - 2) - ROOTINODE - icount; - dwrite((blkno_t) 1, (char *) &filsys); - } + /* Fix free inode count in superblock block */ + if (swizzle16(superblock.s_tinode) != 8 * (swizzle16(superblock.s_isize) - 2) - ROOTINODE - icount) { + printf("Free inode count in superblock block is %u, should be %u. Fix? ", + swizzle16(superblock.s_tinode), 8 * (swizzle16(superblock.s_isize) - 2) - ROOTINODE - icount); + + if (yes()) { + superblock.s_tinode = swizzle16(8 * (swizzle16(superblock.s_isize) - 2) - ROOTINODE - icount); + dwrite((blkno_t) 1, (char *) &superblock); + } } } @@ -396,38 +255,41 @@ void pass2(void) { blkno_t j; blkno_t oldtfree; + int s; printf("Rebuild free list? "); if (!yes()) - return; + return; - oldtfree = filsys.s_tfree; + oldtfree = swizzle16(superblock.s_tfree); - /* Initialize the super-block */ + /* Initialize the superblock-block */ - filsys.s_ninode = 0; - filsys.s_nfree = 1; - filsys.s_free[0] = 0; - filsys.s_tfree = 0; + superblock.s_ninode = 0; + superblock.s_nfree = swizzle16(1); + superblock.s_free[0] = 0; + superblock.s_tfree = 0; /* Free each block, building the free list */ - for (j = filsys.s_fsize - 1; j >= filsys.s_isize; --j) { - if (bitmap[j] == 0) { - if (filsys.s_nfree == 50) { - dwrite(j, (char *) &filsys.s_nfree); - filsys.s_nfree = 0; - } - ++filsys.s_tfree; - filsys.s_free[(filsys.s_nfree)++] = j; - } + for (j = swizzle16(superblock.s_fsize) - 1; j >= swizzle16(superblock.s_isize); --j) { + if (bitmap[j] == 0) { + if (swizzle16(superblock.s_nfree) == 50) { + dwrite(j, (char *) &superblock.s_nfree); + superblock.s_nfree = 0; + } + superblock.s_tfree = swizzle16(swizzle16(superblock.s_tfree)+1); + s = swizzle16(superblock.s_nfree); + superblock.s_free[s++] = swizzle16(j); + superblock.s_nfree = swizzle16(s); + } } - dwrite((blkno_t) 1, (char *) &filsys); + dwrite((blkno_t) 1, (char *) &superblock); - if (oldtfree != filsys.s_tfree) - printf("During free list regeneration s_tfree was changed to %d from %d.\n", - filsys.s_tfree, oldtfree); + if (oldtfree != swizzle16(superblock.s_tfree)) + printf("During free list regeneration s_tfree was changed to %d from %d.\n", + swizzle16(superblock.s_tfree), oldtfree); } @@ -442,61 +304,62 @@ void pass3(void) blkno_t b; blkno_t bno; blkno_t newno; + /*--- was blk_alloc ---*/ + + for (b = swizzle16(superblock.s_isize); b < swizzle16(superblock.s_fsize); ++b) + bitmap[b] = 0; + + for (n = ROOTINODE; n < 8 * (swizzle16(superblock.s_isize) - 2); ++n) { + iread(n, &ino); + + mode = swizzle16(ino.i_mode) & F_MASK; + if (mode != F_REG && mode != F_DIR) + continue; + + /* Check singly indirect blocks */ + + for (b = 18; b < 20; ++b) { + if (ino.i_addr[b] != 0) { + if (bitmap[swizzle16(ino.i_addr[b])] != 0) { + printf("Indirect block %d in inode %u value %u multiply allocated. Fix? ", + b, n, swizzle16(ino.i_addr[b])); + if (yes()) { + newno = blk_alloc0(&superblock); + if (newno == 0) + printf("Sorry... No more free blocks.\n"); + else { + dwrite(newno, daread(swizzle16(ino.i_addr[b]))); + ino.i_addr[b] = swizzle16(newno); + iwrite(n, &ino); + } + } + } else + bitmap[swizzle16(ino.i_addr[b])] = 1; + } + } - for (b = filsys.s_isize; b < filsys.s_fsize; ++b) - bitmap[b] = 0; - - for (n = ROOTINODE; n < 8 * (filsys.s_isize - 2); ++n) { - iread(n, &ino); - - mode = ino.i_mode & S_IFMT; - if (mode != S_IFREG && mode != S_IFDIR) - continue; - - /* Check singly indirect blocks */ - - for (b = 18; b < 20; ++b) { - if (ino.i_addr[b] != 0) { - if (bitmap[ino.i_addr[b]] != 0) { - printf("Indirect block %d in inode %u value %u multiply allocated. Fix? ", - b, n, ino.i_addr[b]); - if (yes()) { - newno = blk_alloc0(&filsys); - if (newno == 0) - printf("Sorry... No more free blocks.\n"); - else { - dwrite(newno, daread(ino.i_addr[b])); - ino.i_addr[b] = newno; - iwrite(n, &ino); - } - } - } else - bitmap[ino.i_addr[b]] = 1; - } - } - - /* Check the rest */ - for (bno = 0; bno <= ino.i_size >> 9; ++bno) { - b = getblkno(&ino, bno); - - if (b != 0) { - if (bitmap[b] != 0) { - printf("Block %d in inode %u value %u multiply allocated. Fix? ", - bno, n, b); - if (yes()) { - newno = blk_alloc0(&filsys); - if (newno == 0) - printf("Sorry... No more free blocks.\n"); - else { - dwrite(newno, daread(b)); - setblkno(&ino, bno, newno); - iwrite(n, &ino); - } - } - } else - bitmap[b] = 1; - } - } + /* Check the rest */ + for (bno = 0; bno <= swizzle32(ino.i_size)/512; ++bno) { + b = getblkno(&ino, bno); + + if (b != 0) { + if (bitmap[b] != 0) { + printf("Block %d in inode %u value %u multiply allocated. Fix? ", + bno, n, b); + if (yes()) { + newno = blk_alloc0(&superblock); + if (newno == 0) + printf("Sorry... No more free blocks.\n"); + else { + dwrite(newno, daread(b)); + setblkno(&ino, bno, newno); + iwrite(n, &ino); + } + } + } else + bitmap[b] = 1; + } + } } @@ -504,125 +367,123 @@ void pass3(void) int depth; +/* + * Pass 4 traverses the directory tree, fixing bad directory entries + * and finding the actual number of references to each inode. + */ + +void pass4(void) +{ + depth = 0; + linkmap[ROOTINODE] = 1; + ckdir(ROOTINODE, ROOTINODE, "/"); + if (depth != 0) + panic("Inconsistent depth"); +} + /* This recursively checks the directories */ void ckdir(uint16_t inum, uint16_t pnum, char *name) { struct dinode ino; - struct _uzidirent dentry; + struct direct dentry; uint16_t j; int c; int nentries; - static char ename[150]; + char ename[150]; iread(inum, &ino); - if ((ino.i_mode & S_IFMT) != S_IFDIR) - return; + if ((swizzle16(ino.i_mode) & F_MASK) != F_DIR) + return; ++depth; - if (ino.i_size % 32 != 0) { - printf("Directory inode %d has improper length. Fix? "); - if (yes()) { - ino.i_size &= (~0x1f); - iwrite(inum, &ino); - } + if (swizzle32(ino.i_size) % 32 != 0) { + printf("Directory inode %d has improper length. Fix? ", inum); + if (yes()) { + ino.i_size = swizzle32(swizzle32(ino.i_size) & ~0x1f); + iwrite(inum, &ino); + } } - nentries = ino.i_size/32; + nentries = swizzle32(ino.i_size)/32; for (j = 0; j < nentries; ++j) { - dirread(&ino, j, &dentry); + dirread(&ino, j, &dentry); -#if 1 /* cleanup entry - HP */ +#if 1 /**HP**/ { - int i; - - for (i = 0; i < 30; ++i) if (dentry.d_name[i] == '\0') break; - for ( ; i < 30; ++i) dentry.d_name[i] = '\0'; - dirwrite(&ino, j, &dentry); + int i; + + for (i = 0; i < 30; ++i) if (dentry.d_name[i] == '\0') break; + for ( ; i < 30; ++i) dentry.d_name[i] = '\0'; + dirwrite(&ino, j, &dentry); } #endif + if (dentry.d_ino == 0) + continue; + + if (swizzle16(dentry.d_ino) < ROOTINODE || + swizzle16(dentry.d_ino) >= 8 * swizzle16(superblock.s_isize)) { + printf("Directory entry %s%-1.14s has out-of-range inode %u. Zap? ", + name, dentry.d_name, swizzle16(dentry.d_ino)); + if (yes()) { + dentry.d_ino = 0; + dentry.d_name[0] = '\0'; + dirwrite(&ino, j, &dentry); + continue; + } + } + if (dentry.d_ino && linkmap[swizzle16(dentry.d_ino)] == -1) { + printf("Directory entry %s%-1.14s points to bogus inode %u. Zap? ", + name, dentry.d_name, swizzle16(dentry.d_ino)); + if (yes()) { + dentry.d_ino = 0; + dentry.d_name[0] = '\0'; + dirwrite(&ino, j, &dentry); + continue; + } + } + ++linkmap[swizzle16(dentry.d_ino)]; + + for (c = 0; c < 30 && dentry.d_name[c]; ++c) { + if (dentry.d_name[c] == '/') { + printf("Directory entry %s%-1.30s contains slash. Fix? ", + name, dentry.d_name); + if (yes()) { + dentry.d_name[c] = 'X'; + dirwrite(&ino, j, &dentry); + } + } + } - if (dentry.d_ino == 0) - continue; - - if (dentry.d_ino < ROOTINODE || dentry.d_ino >= 8 * filsys.s_isize) { - printf("Directory entry %s%-1.30s has out-of-range inode %u. Zap? ", - name, dentry.d_name, dentry.d_ino); - if (yes()) { - dentry.d_ino = 0; - dentry.d_name[0] = '\0'; - dirwrite(&ino, j, &dentry); - continue; - } - } - if (dentry.d_ino && linkmap[dentry.d_ino] == -1) { - printf("Directory entry %s%-1.30s points to bogus inode %u. Zap? ", - name, dentry.d_name, dentry.d_ino); - if (yes()) { - dentry.d_ino = 0; - dentry.d_name[0] = '\0'; - dirwrite(&ino, j, &dentry); - continue; - } - } - ++linkmap[dentry.d_ino]; - - for (c = 0; c < 14 && dentry.d_name[c]; ++c) { - if (dentry.d_name[c] == '/') { - printf("Directory entry %s%-1.30s contains slash. Fix? ", - name, dentry.d_name); - if (yes()) { - dentry.d_name[c] = 'X'; - dirwrite(&ino, j, &dentry); - } - } - } - - if (strncmp(dentry.d_name, ".", 14) == 0 && dentry.d_ino != inum) { - printf("\".\" entry %s%-1.30s points to wrong place. Fix? ", - name, dentry.d_name); - if (yes()) { - dentry.d_ino = inum; - dirwrite(&ino, j, &dentry); - } - } - if (strncmp(dentry.d_name, "..", 14) == 0 && dentry.d_ino != pnum) { - printf("\"..\" entry %s%-1.30s points to wrong place. Fix? ", - name, dentry.d_name); - if (yes()) { - dentry.d_ino = pnum; - dirwrite(&ino, j, &dentry); - } - } - if (dentry.d_ino != pnum && dentry.d_ino != inum && depth < MAXDEPTH) { - strcpy(ename, name); - strcat(ename, dentry.d_name); - strcat(ename, "/"); - ckdir(dentry.d_ino, inum, ename); - } + if (strncmp(dentry.d_name, ".", 30) == 0 && swizzle16(dentry.d_ino) != inum) { + printf("Dot entry %s%-1.30s points to wrong place. Fix? ", + name, dentry.d_name); + if (yes()) { + dentry.d_ino = swizzle16(inum); + dirwrite(&ino, j, &dentry); + } + } + if (strncmp(dentry.d_name, "..", 30) == 0 && swizzle16(dentry.d_ino) != pnum) { + printf("DotDot entry %s%-1.30s points to wrong place. Fix? ", + name, dentry.d_name); + if (yes()) { + dentry.d_ino = swizzle16(pnum); + dirwrite(&ino, j, &dentry); + } + } + if (swizzle16(dentry.d_ino) != pnum && + swizzle16(dentry.d_ino) != inum && depth < MAXDEPTH) { + strcpy(ename, name); + strcat(ename, dentry.d_name); + strcat(ename, "/"); + ckdir(swizzle16(dentry.d_ino), inum, ename); + } } --depth; } -/* - * Pass 4 traverses the directory tree, fixing bad directory entries - * and finding the actual number of references to each inode. - */ - -void pass4(void) -{ - depth = 0; - linkmap[ROOTINODE] = 1; - ckdir(ROOTINODE, ROOTINODE, "/"); - if (depth != 0) { - fprintf(stderr, "Inconsistent depth"); - exit(-1); - } -} - - /* Pass 5 compares the link counts found in pass 4 with the inodes. */ @@ -631,169 +492,343 @@ void pass5(void) uint16_t n; struct dinode ino; - for (n = ROOTINODE; n < 8 * (filsys.s_isize - 2); ++n) { - iread(n, &ino); + for (n = ROOTINODE; n < 8 * (swizzle16(superblock.s_isize) - 2); ++n) { + iread(n, &ino); - if (ino.i_mode == 0) { - if (linkmap[n] != -1) { - fprintf(stderr, "Inconsistent linkmap"); - exit(-1); - } - continue; - } + if (ino.i_mode == 0) { + if (linkmap[n] != -1) + panic("Inconsistent linkmap"); + continue; + } - if (linkmap[n] == -1 && ino.i_mode != 0) { - fprintf(stderr, "Inconsistent linkmap"); - exit(-1); - } + if (linkmap[n] == -1 && ino.i_mode != 0) + panic("Inconsistent linkmap"); - if (linkmap[n] > 0 && ino.i_nlink != linkmap[n]) { - printf("Inode %d has link count %d should be %d. Fix? ", - n, ino.i_nlink, linkmap[n]); - if (yes()) { - ino.i_nlink = linkmap[n]; - iwrite(n, &ino); - } - } + if (linkmap[n] > 0 && swizzle16(ino.i_nlink) != linkmap[n]) { + printf("Inode %d has link count %d should be %d. Fix? ", + n, swizzle16(ino.i_nlink), linkmap[n]); + if (yes()) { + ino.i_nlink = swizzle16(linkmap[n]); + iwrite(n, &ino); + } + } - if (linkmap[n] == 0) { - if ((ino.i_mode & S_IFMT) == S_IFBLK || - (ino.i_mode & S_IFMT) == S_IFCHR || - (ino.i_size == 0)) { - printf("Useless inode %d with mode 0%o has become detached. Link count is %d. Zap? ", - n, ino.i_mode, ino.i_nlink); - if (yes()) { - ino.i_nlink = 0; - ino.i_mode = 0; - iwrite(n, &ino); - ++filsys.s_tinode; - dwrite((blkno_t) 1, (char *) &filsys); - } - } else { + if (linkmap[n] == 0) { + if ((swizzle16(ino.i_mode) & F_MASK) == F_BDEV || + (swizzle16(ino.i_mode) & F_MASK) == F_CDEV || + (ino.i_size == 0)) { + printf("Useless inode %d with mode 0%o has become detached. Link count is %d. Zap? ", + n, swizzle16(ino.i_mode), swizzle16(ino.i_nlink)); + if (yes()) { + ino.i_nlink = 0; + ino.i_mode = 0; + iwrite(n, &ino); + superblock.s_tinode = + swizzle16(swizzle16(superblock.s_tinode) + 1); + dwrite((blkno_t) 1, (char *) &superblock); + } + } else { #if 0 - printf("Inode %d has become detached. Link count is %d. Fix? ", - n, ino.i_nlink); - if (yes()) { - ino.i_nlink = 1; - iwrite(n, &ino); - mkentry(n); - } + printf("Inode %d has become detached. Link count is %d. Fix? ", + n, swizzle16(ino.i_nlink)); + if (yes()) { + ino.i_nlink = 1; + iwrite(n, &ino); + mkentry(n); + } #else - printf("Inode %d has become detached. Link count is %d. ", - n, ino.i_nlink); - if (ino.i_nlink == 0) - printf("Zap? "); - else - printf("Fix? "); - if (yes()) { - if (ino.i_nlink == 0) { - ino.i_nlink = 0; - ino.i_mode = 0; - iwrite(n, &ino); - ++filsys.s_tinode; - dwrite((blkno_t) 1, (char *) &filsys); - } else { - ino.i_nlink = 1; - iwrite(n, &ino); - mkentry(n); - } - } + printf("Inode %d has become detached. Link count is %d. ", + n, swizzle16(ino.i_nlink)); + if (ino.i_nlink == 0) + printf("Zap? "); + else + printf("Fix? "); + if (yes()) { + if (ino.i_nlink == 0) { + ino.i_nlink = 0; + ino.i_mode = 0; + iwrite(n, &ino); + superblock.s_tinode = + swizzle16(swizzle16(superblock.s_tinode) + 1); + dwrite((blkno_t) 1, (char *) &superblock); + } else { + ino.i_nlink = swizzle16(1); + iwrite(n, &ino); + mkentry(n); + } + } #endif - } - } - + } + } + } } +/* This makes an entry in "lost+found" for inode n */ +void mkentry(uint16_t inum) +{ + struct dinode rootino; + struct direct dentry; + uint16_t d; -int yes(void) + iread(ROOTINODE, &rootino); + for (d = 0; d < swizzle32(rootino.i_size)/32; ++d) { + dirread(&rootino, d, &dentry); + if (dentry.d_ino == 0 && dentry.d_name[0] == '\0') { + dentry.d_ino = swizzle16(inum); + sprintf(dentry.d_name, "l+f%d", inum); + dirwrite(&rootino, d, &dentry); + return; + } + } + printf("Sorry... No empty slots in root directory.\n"); +} + +/* Beginning of fsck1.c */ + +/* + * Getblkno gets a pointer index, and a number of a block in the file. + * It returns the number of the block on the disk. A value of zero + * means an unallocated block. + */ + +blkno_t getblkno(struct dinode *ino, blkno_t num) { - char line[20]; - /*int fgets(); -- HP */ + blkno_t indb; + blkno_t dindb; + blkno_t *buf; - fflush(stdout); + if (num < 18) { /* Direct block */ + return swizzle16(ino->i_addr[num]); + } + if (num < 256 + 18) { /* Single indirect */ + indb = swizzle16(ino->i_addr[18]); + if (indb == 0) + return (0); + buf = (blkno_t *) daread(indb); + return swizzle16(buf[num - 18]); + } + /* Double indirect */ + indb = swizzle16(ino->i_addr[19]); + if (indb == 0) + return (0); - if (!fgets(line, sizeof(line), stdin) || (*line != 'y' && *line != 'Y')) - return (0); + buf = (blkno_t *) daread(indb); + + dindb = swizzle16(buf[(num - (18 + 256)) >> 8]); + buf = (blkno_t *) daread(dindb); - return (1); + return swizzle16(buf[(num - (18 + 256)) & 0x00ff]); } -main(int argc, char *argv[]) +/* + * Setblkno sets the given block number of the given file to the given + * disk block number, possibly creating or modifiying the indirect blocks. + * A return of zero means there were no blocks available to create an + * indirect block. This should never happen in fsck. + */ + +void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum) { - char *buf; - struct stat statbuf; + blkno_t indb; + blkno_t dindb; + blkno_t *buf; + /*-- char *zerobuf();--*/ - if (argc != 2) { - fprintf(stderr, "usage: fsck device\n"); - exit(-1); - } - if (stat(argv[1], &statbuf) != 0) { - fprintf(stderr, "fsck: can't stat %s\n", argv[1]); - exit(-1); + if (num < 18) { /* Direct block */ + ino->i_addr[num] = swizzle16(dnum); + } else if (num < 256 + 18) { /* Single indirect */ + indb = swizzle16(ino->i_addr[18]); + if (indb == 0) + panic("Missing indirect block"); + + buf = (blkno_t *) daread(indb); + buf[num - 18] = swizzle16(dnum); + dwrite(indb, (char *) buf); + } else { /* Double indirect */ + indb = swizzle16(ino->i_addr[19]); + if (indb == 0) + panic("Missing indirect block"); + + buf = (blkno_t *) daread(indb); + dindb = swizzle16(buf[(num - (18 + 256)) >> 8]); + if (dindb == 0) + panic("Missing indirect block"); + + buf = (blkno_t *) daread(dindb); + buf[(num - (18 + 256)) & 0x00ff] = swizzle16(num); + dwrite(indb, (char *) buf); } - - if ((statbuf.st_mode & S_IFMT) != S_IFBLK) { - fprintf(stderr, "fsck: %s is not a valid device\n", argv[1]); - exit(-1); +} + + +/* + * blk_alloc0 allocates an unused block. + * A returned block number of zero means no more blocks. + */ + +/*--- was blk_alloc ---*/ + +blkno_t blk_alloc0(struct filesys *filesys) +{ + blkno_t newno; + blkno_t *buf; + int16_t j; + + filesys->s_nfree = swizzle16(swizzle16(filesys->s_nfree) - 1); + newno = swizzle16(filesys->s_free[--filesys->s_nfree]); + if (!newno) { + filesys->s_nfree = swizzle16(swizzle16(filesys->s_nfree) + 1); + return (0); } - dev = open(argv[1], O_RDWR); - if (dev < 0) { - fprintf(stderr, "fsck: can't open device %s\n", argv[1]); - exit(-1); + /* See if we must refill the s_free array */ + + if (!filesys->s_nfree) { + buf = (blkno_t *) daread(newno); + filesys->s_nfree = buf[0]; + for (j = 0; j < 50; j++) { + filesys->s_free[j] = buf[j + 1]; + } } - /* Read in the super block. */ + filesys->s_tfree = swizzle16(swizzle16(filesys->s_tfree) - 1); - buf = daread(1); - bcopy(buf, (char *) &filsys, sizeof(struct _uzifilesys)); + if (newno < swizzle16(filesys->s_isize) || newno >= swizzle16(filesys->s_fsize)) { + printf("Free list is corrupt. Did you rebuild it?\n"); + return (0); + } + dwrite((blkno_t) 1, (char *) filesys); + return (newno); +} - /* Verify the fsize and isize parameters */ - if (filsys.s_mounted != SMOUNTED) { - printf("Device %s has invalid magic number %d. Fix? ", - argv[1], filsys.s_mounted); - if (!yes()) - exit(-1); - filsys.s_mounted = SMOUNTED; - dwrite((blkno_t) 1, (char *) &filsys); +char *daread(uint16_t blk) +{ + static char da_buf[512]; + if (lseek(dev_fd, offset + blk * 512L, 0) == -1) { + perror("lseek"); + exit(1); } - printf("Device %s has fsize = %d and isize = %d. Continue? ", - argv[1], filsys.s_fsize, filsys.s_isize); - if (!yes()) - exit(-1); + if(read(dev_fd, da_buf, 512) != 512) { + perror("read"); + exit(1); + } + return da_buf; +} - bitmap = calloc(filsys.s_fsize, sizeof(char)); - linkmap = (int16_t *) calloc(8 * filsys.s_isize, sizeof(int16_t)); - if (!bitmap || !linkmap) { - fprintf(stderr, "Not enough memory.\n"); - exit(-1); +void dwrite(uint16_t blk, char *addr) +{ + if (lseek(dev_fd, offset + blk * 512L, 0) == -1) { + perror("lseek"); + exit(1); + } + if(write(dev_fd, addr, 512) != 512) { + perror("write"); + exit(1); } +} - printf("Pass 1: Checking inodes...\n"); - pass1(); - printf("Pass 2: Rebuilding free list...\n"); - pass2(); +void iread(uint16_t ino, struct dinode *buf) +{ + struct dinode *addr; - printf("Pass 3: Checking block allocation...\n"); - pass3(); + addr = (struct dinode *) daread((ino >> 3) + 2); + bcopy((char *) &addr[ino & 7], (char *) buf, sizeof(struct dinode)); +} - printf("Pass 4: Checking directory entries...\n"); - pass4(); - printf("Pass 5: Checking link counts...\n"); - pass5(); +void iwrite(uint16_t ino, struct dinode *buf) +{ + struct dinode *addr; - sync(); - printf("Done.\n"); + addr = (struct dinode *) daread((ino >> 3) + 2); + bcopy((char *) buf, (char *) &addr[ino & 7], sizeof(struct dinode)); + dwrite((ino >> 3) + 2, (char *) addr); +} - return 0; + +void dirread(struct dinode *ino, uint16_t j, struct direct *dentry) +{ + blkno_t blkno; + char *buf; + + blkno = getblkno(ino, (blkno_t) j / 16); + if (blkno == 0) + panic("Missing block in directory"); + buf = daread(blkno); + bcopy(buf + 32 * (j % 16), (char *) dentry, 32); } + +void dirwrite(struct dinode *ino, uint16_t j, struct direct *dentry) +{ + blkno_t blkno; + char *buf; + + blkno = getblkno(ino, (blkno_t) j / 16); + if (blkno == 0) + panic("Missing block in directory"); + buf = daread(blkno); + bcopy((char *) dentry, buf + 32 * (j % 16), 32); + dwrite(blkno, buf); +} + +int fd_open(char *name) +{ + char *namecopy, *sd; + int bias = 0; + + namecopy = strdup(name); + sd = index(namecopy, ':'); + if (sd) { + *sd = 0; + sd++; + bias = atoi(sd); + } + + printf("Opening %s (offset %d)\n", namecopy, bias); + dev_offset = bias; + dev_fd = open(namecopy, O_RDWR | O_CREAT, 0666); + free(namecopy); + + if (dev_fd < 0) + return -1; + /* printf("fd=%d, dev_offset = %d\n", dev_fd, dev_offset); */ + return 0; +} + + +void panic(char *s) +{ + fprintf(stderr, "panic: %s\n", s); + exit(1); +} + +uint16_t swizzle16(uint32_t v) +{ + int top = v & 0xFFFF0000UL; + if (top && top != 0xFFFF0000) { + fprintf(stderr, "swizzle16 given a 32bit input\n"); + exit(1); + } + if (swizzling) + return (v & 0xFF) << 8 | ((v & 0xFF00) >> 8); + else + return v; +} + +uint32_t swizzle32(uint32_t v) +{ + if (!swizzling) + return v; + + return (v & 0xFF) << 24 | (v & 0xFF00) << 8 | (v & 0xFF0000) >> 8 | + (v & 0xFF000000) >> 24; +} diff --git a/Applications/util/fsck.h b/Applications/util/fsck.h new file mode 100644 index 00000000..0e71b5ce --- /dev/null +++ b/Applications/util/fsck.h @@ -0,0 +1,57 @@ +#define __UZIFS_DOT_H__ + +#define ROOTINODE 1 +#define SMOUNTED 12742 /* Magic number to specify mounted filesystem */ +#define SMOUNTED_WRONGENDIAN 50737 /* byteflipped */ + +extern int dev_fd; +extern int dev_offset; +int fd_open(char *name); +void panic(char *s); + +extern uint16_t swizzle16(uint32_t v); +extern uint32_t swizzle32(uint32_t v); +extern int swizzling; + +struct direct { + uint16_t d_ino; + char d_name[30]; +}; + +typedef uint16_t blkno_t; /* Can have 65536 512-byte blocks in filesystem */ + +struct dinode { + uint16_t i_mode; + uint16_t i_nlink; + uint16_t i_uid; + uint16_t i_gid; + uint32_t i_size; + uint32_t i_atime; + uint32_t i_mtime; + uint32_t i_ctime; + blkno_t i_addr[20]; +}; /* Exactly 64 bytes long! */ + +#define F_REG 0100000 +#define F_DIR 040000 +#define F_PIPE 010000 +#define F_BDEV 060000 +#define F_CDEV 020000 + +#define F_MASK 0170000 + +struct filesys { + uint16_t s_mounted; + uint16_t s_isize; + uint16_t s_fsize; + int16_t s_nfree; + blkno_t s_free[50]; + int16_t s_ninode; + uint16_t s_inode[50]; + uint8_t s_fmod; + uint8_t s_timeh; /* top bits of time */ + uint32_t s_time; + blkno_t s_tfree; + uint16_t s_tinode; + uint16_t s_mntpt; +};