missing fsbtodb!
[unix-history] / usr / src / sbin / fsck / dir.c
index 2082201..56dc498 100644 (file)
@@ -1,6 +1,12 @@
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
 #ifndef lint
 #ifndef lint
-static char version[] = "@(#)dir.c     3.5 (Berkeley) %G%";
-#endif
+static char sccsid[] = "@(#)dir.c      5.4 (Berkeley) %G%";
+#endif not lint
 
 #include <sys/param.h>
 #include <sys/inode.h>
 
 #include <sys/param.h>
 #include <sys/inode.h>
@@ -15,8 +21,10 @@ static char version[] = "@(#)dir.c   3.5 (Berkeley) %G%";
 char   *endpathname = &pathname[BUFSIZ - 2];
 char   *lfname = "lost+found";
 struct dirtemplate emptydir = { 0, DIRBLKSIZ };
 char   *endpathname = &pathname[BUFSIZ - 2];
 char   *lfname = "lost+found";
 struct dirtemplate emptydir = { 0, DIRBLKSIZ };
+struct dirtemplate dirhead = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".." };
 
 DIRECT *fsck_readdir();
 
 DIRECT *fsck_readdir();
+BUFAREA        *getdirblk();
 
 descend(parentino, inumber)
        struct inodesc *parentino;
 
 descend(parentino, inumber)
        struct inodesc *parentino;
@@ -42,24 +50,41 @@ descend(parentino, inumber)
                if (reply("FIX") == 1)
                        inodirty();
        }
                if (reply("FIX") == 1)
                        inodirty();
        }
+       if ((dp->di_size & (DIRBLKSIZ - 1)) != 0) {
+               pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d",
+                       pathname, dp->di_size, DIRBLKSIZ);
+               dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
+               if (preen)
+                       printf(" (ADJUSTED)\n");
+               if (preen || reply("ADJUST") == 1)
+                       inodirty();
+       }
        curino.id_type = DATA;
        curino.id_func = parentino->id_func;
        curino.id_parent = parentino->id_number;
        curino.id_number = inumber;
        curino.id_type = DATA;
        curino.id_func = parentino->id_func;
        curino.id_parent = parentino->id_number;
        curino.id_number = inumber;
-       curino.id_filesize = dp->di_size;
        (void)ckinode(dp, &curino);
        (void)ckinode(dp, &curino);
+       if (curino.id_entryno < 2) {
+               direrr(inumber, "NULL DIRECTORY");
+               if (reply("REMOVE") == 1)
+                       statemap[inumber] = DCLEAR;
+       }
 }
 
 dirscan(idesc)
        register struct inodesc *idesc;
 {
        register DIRECT *dp;
 }
 
 dirscan(idesc)
        register struct inodesc *idesc;
 {
        register DIRECT *dp;
+       register BUFAREA *bp;
        int dsize, n;
        long blksiz;
        char dbuf[DIRBLKSIZ];
 
        if (idesc->id_type != DATA)
                errexit("wrong type to dirscan %d\n", idesc->id_type);
        int dsize, n;
        long blksiz;
        char dbuf[DIRBLKSIZ];
 
        if (idesc->id_type != DATA)
                errexit("wrong type to dirscan %d\n", idesc->id_type);
+       if (idesc->id_entryno == 0 &&
+           (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
+               idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
        blksiz = idesc->id_numfrags * sblock.fs_fsize;
        if (outrange(idesc->id_blkno, idesc->id_numfrags)) {
                idesc->id_filesize -= blksiz;
        blksiz = idesc->id_numfrags * sblock.fs_fsize;
        if (outrange(idesc->id_blkno, idesc->id_numfrags)) {
                idesc->id_filesize -= blksiz;
@@ -71,12 +96,10 @@ dirscan(idesc)
                bcopy((char *)dp, dbuf, dsize);
                idesc->id_dirp = (DIRECT *)dbuf;
                if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
                bcopy((char *)dp, dbuf, dsize);
                idesc->id_dirp = (DIRECT *)dbuf;
                if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
-                       if (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) {
-                               bcopy(dbuf, (char *)dp, dsize);
-                               dirty(&fileblk);
-                               sbdirty();
-                       } else
-                               n &= ~ALTERED;
+                       bp = getdirblk(idesc->id_blkno, blksiz);
+                       bcopy(dbuf, (char *)dp, dsize);
+                       dirty(bp);
+                       sbdirty();
                }
                if (n & STOP) 
                        return (n);
                }
                if (n & STOP) 
                        return (n);
@@ -92,16 +115,14 @@ fsck_readdir(idesc)
        register struct inodesc *idesc;
 {
        register DIRECT *dp, *ndp;
        register struct inodesc *idesc;
 {
        register DIRECT *dp, *ndp;
+       register BUFAREA *bp;
        long size, blksiz;
 
        blksiz = idesc->id_numfrags * sblock.fs_fsize;
        long size, blksiz;
 
        blksiz = idesc->id_numfrags * sblock.fs_fsize;
-       if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) {
-               idesc->id_filesize -= blksiz - idesc->id_loc;
-               return NULL;
-       }
+       bp = getdirblk(idesc->id_blkno, blksiz);
        if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
            idesc->id_loc < blksiz) {
        if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
            idesc->id_loc < blksiz) {
-               dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
+               dp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc);
                if (dircheck(idesc, dp))
                        goto dpok;
                idesc->id_loc += DIRBLKSIZ;
                if (dircheck(idesc, dp))
                        goto dpok;
                idesc->id_loc += DIRBLKSIZ;
@@ -111,18 +132,18 @@ fsck_readdir(idesc)
                dp->d_namlen = 0;
                dp->d_name[0] = '\0';
                if (dofix(idesc, "DIRECTORY CORRUPTED"))
                dp->d_namlen = 0;
                dp->d_name[0] = '\0';
                if (dofix(idesc, "DIRECTORY CORRUPTED"))
-                       dirty(&fileblk);
+                       dirty(bp);
                return (dp);
        }
 dpok:
        if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
                return NULL;
                return (dp);
        }
 dpok:
        if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
                return NULL;
-       dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
+       dp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc);
        idesc->id_loc += dp->d_reclen;
        idesc->id_filesize -= dp->d_reclen;
        if ((idesc->id_loc % DIRBLKSIZ) == 0)
                return (dp);
        idesc->id_loc += dp->d_reclen;
        idesc->id_filesize -= dp->d_reclen;
        if ((idesc->id_loc % DIRBLKSIZ) == 0)
                return (dp);
-       ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
+       ndp = (DIRECT *)(bp->b_un.b_buf + idesc->id_loc);
        if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
            dircheck(idesc, ndp) == 0) {
                size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
        if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
            dircheck(idesc, ndp) == 0) {
                size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
@@ -130,7 +151,7 @@ dpok:
                idesc->id_loc += size;
                idesc->id_filesize -= size;
                if (dofix(idesc, "DIRECTORY CORRUPTED"))
                idesc->id_loc += size;
                idesc->id_filesize -= size;
                if (dofix(idesc, "DIRECTORY CORRUPTED"))
-                       dirty(&fileblk);
+                       dirty(bp);
        }
        return (dp);
 }
        }
        return (dp);
 }
@@ -237,21 +258,20 @@ mkentry(idesc)
        dirp = (struct direct *)(((char *)dirp) + oldlen);
        dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
        dirp->d_reclen = newent.d_reclen;
        dirp = (struct direct *)(((char *)dirp) + oldlen);
        dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
        dirp->d_reclen = newent.d_reclen;
-       dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent);
+       dirp->d_namlen = strlen(idesc->id_name);
+       bcopy(idesc->id_name, dirp->d_name, dirp->d_namlen + 1);
        return (ALTERED|STOP);
 }
 
        return (ALTERED|STOP);
 }
 
-chgdd(idesc)
+chgino(idesc)
        struct inodesc *idesc;
 {
        register DIRECT *dirp = idesc->id_dirp;
 
        struct inodesc *idesc;
 {
        register DIRECT *dirp = idesc->id_dirp;
 
-       if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
-       dirp->d_name[2] == 0) {
-               dirp->d_ino = lfdir;
-               return (ALTERED|STOP);
-       }
-       return (KEEPON);
+       if (bcmp(dirp->d_name, idesc->id_name, dirp->d_namlen + 1))
+               return (KEEPON);
+       dirp->d_ino = idesc->id_parent;;
+       return (ALTERED|STOP);
 }
 
 linkup(orphan, pdir)
 }
 
 linkup(orphan, pdir)
@@ -260,7 +280,10 @@ linkup(orphan, pdir)
 {
        register DINODE *dp;
        int lostdir, len;
 {
        register DINODE *dp;
        int lostdir, len;
+       ino_t oldlfdir;
        struct inodesc idesc;
        struct inodesc idesc;
+       char tempname[BUFSIZ];
+       extern int pass4check();
 
        bzero((char *)&idesc, sizeof(struct inodesc));
        dp = ginode(orphan);
 
        bzero((char *)&idesc, sizeof(struct inodesc));
        dp = ginode(orphan);
@@ -283,51 +306,83 @@ linkup(orphan, pdir)
                idesc.id_type = DATA;
                idesc.id_func = findino;
                idesc.id_number = ROOTINO;
                idesc.id_type = DATA;
                idesc.id_func = findino;
                idesc.id_number = ROOTINO;
-               idesc.id_filesize = dp->di_size;
-               (void)ckinode(dp, &idesc);
-               lfdir = idesc.id_parent;
-               if (lfdir < ROOTINO || lfdir > imax)
-                       lfdir = 0;
+               if ((ckinode(dp, &idesc) & FOUND) != 0) {
+                       lfdir = idesc.id_parent;
+               } else {
+                       pwarn("NO lost+found DIRECTORY");
+                       if (preen || reply("CREATE")) {
+                               lfdir = allocdir(ROOTINO, 0);
+                               if (lfdir != 0) {
+                                       if (makeentry(ROOTINO, lfdir, lfname) != 0) {
+                                               if (preen)
+                                                       printf(" (CREATED)\n");
+                                       } else {
+                                               freedir(lfdir, ROOTINO);
+                                               lfdir = 0;
+                                               if (preen)
+                                                       printf("\n");
+                                       }
+                               }
+                       }
+               }
                if (lfdir == 0) {
                if (lfdir == 0) {
-                       pfatal("SORRY. NO lost+found DIRECTORY");
+                       pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
                        printf("\n\n");
                        return (0);
                }
        }
        dp = ginode(lfdir);
                        printf("\n\n");
                        return (0);
                }
        }
        dp = ginode(lfdir);
-       if (!DIRCT(dp) || statemap[lfdir] != DFOUND) {
-               pfatal("SORRY. NO lost+found DIRECTORY");
-               printf("\n\n");
-               return (0);
-       }
-       if (dp->di_size % DIRBLKSIZ) {
-               dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
+       if (!DIRCT(dp)) {
+               pfatal("lost+found IS NOT A DIRECTORY");
+               if (reply("REALLOCATE") == 0)
+                       return (0);
+               oldlfdir = lfdir;
+               if ((lfdir = allocdir(ROOTINO, 0)) == 0) {
+                       pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
+                       return (0);
+               }
+               idesc.id_type = DATA;
+               idesc.id_func = chgino;
+               idesc.id_number = ROOTINO;
+               idesc.id_parent = lfdir;        /* new inumber for lost+found */
+               idesc.id_name = lfname;
+               if ((ckinode(ginode(ROOTINO), &idesc) & ALTERED) == 0) {
+                       pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
+                       return (0);
+               }
                inodirty();
                inodirty();
+               idesc.id_type = ADDR;
+               idesc.id_func = pass4check;
+               idesc.id_number = oldlfdir;
+               adjust(&idesc, lncntp[oldlfdir] + 1);
+               lncntp[oldlfdir] = 0;
+               dp = ginode(lfdir);
+       }
+       if (statemap[lfdir] != DFOUND) {
+               pfatal("SORRY. NO lost+found DIRECTORY\n\n");
+               return (0);
        }
        len = strlen(lfname);
        bcopy(lfname, pathp, len + 1);
        pathp += len;
        }
        len = strlen(lfname);
        bcopy(lfname, pathp, len + 1);
        pathp += len;
-       idesc.id_type = DATA;
-       idesc.id_func = mkentry;
-       idesc.id_number = lfdir;
-       idesc.id_filesize = dp->di_size;
-       idesc.id_parent = orphan;       /* this is the inode to enter */
-       idesc.id_fix = DONTKNOW;
-       if (makeentry(dp, &idesc) == 0) {
+       len = lftempname(tempname, orphan);
+       if (makeentry(lfdir, orphan, tempname) == 0) {
                pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
                printf("\n\n");
                return (0);
        }
        lncntp[orphan]--;
        *pathp++ = '/';
                pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
                printf("\n\n");
                return (0);
        }
        lncntp[orphan]--;
        *pathp++ = '/';
-       pathp += lftempname(pathp, orphan);
+       bcopy(tempname, pathp, len + 1);
+       pathp += len;
        if (lostdir) {
                dp = ginode(orphan);
                idesc.id_type = DATA;
        if (lostdir) {
                dp = ginode(orphan);
                idesc.id_type = DATA;
-               idesc.id_func = chgdd;
+               idesc.id_func = chgino;
                idesc.id_number = orphan;
                idesc.id_number = orphan;
-               idesc.id_filesize = dp->di_size;
                idesc.id_fix = DONTKNOW;
                idesc.id_fix = DONTKNOW;
+               idesc.id_name = "..";
+               idesc.id_parent = lfdir;        /* new value for ".." */
                (void)ckinode(dp, &idesc);
                dp = ginode(lfdir);
                dp->di_nlink++;
                (void)ckinode(dp, &idesc);
                dp = ginode(lfdir);
                dp->di_nlink++;
@@ -344,17 +399,32 @@ linkup(orphan, pdir)
 /*
  * make an entry in a directory
  */
 /*
  * make an entry in a directory
  */
-makeentry(dp, idesc)
-       DINODE *dp;
-       struct inodesc *idesc;
+makeentry(parent, ino, name)
+       ino_t parent, ino;
+       char *name;
 {
 {
+       DINODE *dp;
+       struct inodesc idesc;
        
        
-       if ((ckinode(dp, idesc) & ALTERED) != 0)
+       if (parent < ROOTINO || parent >= imax || ino < ROOTINO || ino >= imax)
+               return (0);
+       bzero(&idesc, sizeof(struct inodesc));
+       idesc.id_type = DATA;
+       idesc.id_func = mkentry;
+       idesc.id_number = parent;
+       idesc.id_parent = ino;  /* this is the inode to enter */
+       idesc.id_fix = DONTKNOW;
+       idesc.id_name = name;
+       dp = ginode(parent);
+       if (dp->di_size % DIRBLKSIZ) {
+               dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
+               inodirty();
+       }
+       if ((ckinode(dp, &idesc) & ALTERED) != 0)
                return (1);
        if (expanddir(dp) == 0)
                return (0);
                return (1);
        if (expanddir(dp) == 0)
                return (0);
-       idesc->id_filesize = dp->di_size;
-       return (ckinode(dp, idesc) & ALTERED);
+       return (ckinode(dp, &idesc) & ALTERED);
 }
 
 /*
 }
 
 /*
@@ -364,6 +434,7 @@ expanddir(dp)
        register DINODE *dp;
 {
        daddr_t lastbn, newblk;
        register DINODE *dp;
 {
        daddr_t lastbn, newblk;
+       register BUFAREA *bp;
        char *cp, firstblk[DIRBLKSIZ];
 
        lastbn = lblkno(&sblock, dp->di_size);
        char *cp, firstblk[DIRBLKSIZ];
 
        lastbn = lblkno(&sblock, dp->di_size);
@@ -375,28 +446,31 @@ expanddir(dp)
        dp->di_db[lastbn] = newblk;
        dp->di_size += sblock.fs_bsize;
        dp->di_blocks += btodb(sblock.fs_bsize);
        dp->di_db[lastbn] = newblk;
        dp->di_size += sblock.fs_bsize;
        dp->di_blocks += btodb(sblock.fs_bsize);
-       if (getblk(&fileblk, dp->di_db[lastbn + 1],
-           dblksize(&sblock, dp, lastbn + 1)) == NULL)
+       bp = getdirblk(dp->di_db[lastbn + 1],
+               dblksize(&sblock, dp, lastbn + 1));
+       if (bp->b_errs != NULL)
                goto bad;
                goto bad;
-       bcopy(dirblk.b_buf, firstblk, DIRBLKSIZ);
-       if (getblk(&fileblk, newblk, sblock.fs_bsize) == NULL)
+       bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
+       bp = getdirblk(newblk, sblock.fs_bsize);
+       if (bp->b_errs != NULL)
                goto bad;
                goto bad;
-       bcopy(firstblk, dirblk.b_buf, DIRBLKSIZ);
-       for (cp = &dirblk.b_buf[DIRBLKSIZ];
-            cp < &dirblk.b_buf[sblock.fs_bsize];
+       bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
+       for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
+            cp < &bp->b_un.b_buf[sblock.fs_bsize];
             cp += DIRBLKSIZ)
                bcopy((char *)&emptydir, cp, sizeof emptydir);
             cp += DIRBLKSIZ)
                bcopy((char *)&emptydir, cp, sizeof emptydir);
-       dirty(&fileblk);
-       if (getblk(&fileblk, dp->di_db[lastbn + 1],
-           dblksize(&sblock, dp, lastbn + 1)) == NULL)
+       dirty(bp);
+       bp = getdirblk(dp->di_db[lastbn + 1],
+               dblksize(&sblock, dp, lastbn + 1));
+       if (bp->b_errs != NULL)
                goto bad;
                goto bad;
-       bcopy((char *)&emptydir, dirblk.b_buf, sizeof emptydir);
+       bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir);
        pwarn("NO SPACE LEFT IN %s", pathname);
        if (preen)
                printf(" (EXPANDED)\n");
        else if (reply("EXPAND") == 0)
                goto bad;
        pwarn("NO SPACE LEFT IN %s", pathname);
        if (preen)
                printf(" (EXPANDED)\n");
        else if (reply("EXPAND") == 0)
                goto bad;
-       dirty(&fileblk);
+       dirty(bp);
        inodirty();
        return (1);
 bad:
        inodirty();
        return (1);
 bad:
@@ -408,6 +482,69 @@ bad:
        return (0);
 }
 
        return (0);
 }
 
+/*
+ * allocate a new directory
+ */
+allocdir(parent, request)
+       ino_t parent, request;
+{
+       ino_t ino;
+       char *cp;
+       DINODE *dp;
+       register BUFAREA *bp;
+
+       ino = allocino(request, IFDIR|0755);
+       dirhead.dot_ino = ino;
+       dirhead.dotdot_ino = parent;
+       dp = ginode(ino);
+       bp = getdirblk(dp->di_db[0], sblock.fs_fsize);
+       if (bp->b_errs != NULL) {
+               freeino(ino);
+               return (0);
+       }
+       bcopy((char *)&dirhead, bp->b_un.b_buf, sizeof dirhead);
+       for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
+            cp < &bp->b_un.b_buf[sblock.fs_fsize];
+            cp += DIRBLKSIZ)
+               bcopy((char *)&emptydir, cp, sizeof emptydir);
+       dirty(bp);
+       dp->di_nlink = 2;
+       inodirty();
+       if (ino == ROOTINO) {
+               lncntp[ino] = dp->di_nlink;
+               return(ino);
+       }
+       if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
+               freeino(ino);
+               return (0);
+       }
+       statemap[ino] = statemap[parent];
+       if (statemap[ino] == DSTATE) {
+               lncntp[ino] = dp->di_nlink;
+               lncntp[parent]++;
+       }
+       dp = ginode(parent);
+       dp->di_nlink++;
+       inodirty();
+       return (ino);
+}
+
+/*
+ * free a directory inode
+ */
+freedir(ino, parent)
+       ino_t ino, parent;
+{
+       DINODE *dp;
+
+       if (ino != parent) {
+               dp = ginode(parent);
+               dp->di_nlink--;
+               inodirty();
+       }
+       freeino(ino);
+}
+
 /*
  * generate a temporary name for the lost+found directory.
  */
 /*
  * generate a temporary name for the lost+found directory.
  */
@@ -432,3 +569,20 @@ lftempname(bufp, ino)
        *cp = '#';
        return (namlen);
 }
        *cp = '#';
        return (namlen);
 }
+
+/*
+ * Get a directory block.
+ * Insure that it is held until another is requested.
+ */
+BUFAREA *
+getdirblk(blkno, size)
+       daddr_t blkno;
+       long size;
+{
+       static BUFAREA *pbp = 0;
+
+       if (pbp != 0)
+               pbp->b_flags &= ~B_INUSE;
+       pbp = getdatablk(blkno, size);
+       return (pbp);
+}