Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sbin/fsck_ffs Add a -z flag to zero out the up to 4 bytes of...



details:   https://anonhg.NetBSD.org/src/rev/df4e62a66133
branches:  trunk
changeset: 451075:df4e62a66133
user:      christos <christos%NetBSD.org@localhost>
date:      Sun May 05 14:59:06 2019 +0000

description:
Add a -z flag to zero out the up to 4 bytes of padding in directory entry
names (including the terminating NUL), as well as directory entries with
extra free space (d->d_reclen > UFS_DIRSIZ(d)).

Inspired from FreeBSD:
    https://svnweb.freebsd.org/base?view=revision&revision=347066

While the kernel has been fixed to deal with the padding bytes (new
kernels will correctly zero out all the padding after the name), it
appears that there is still an issue with directory entries with extra
free space, since a newly created and populated filesystem gets modified
with "fsck_ffs -z".

diffstat:

 sbin/fsck_ffs/dir.c      |  116 +++++++++++++++++++++++++++++++++++++---------
 sbin/fsck_ffs/fsck.h     |    3 +-
 sbin/fsck_ffs/fsck_ffs.8 |    9 ++-
 sbin/fsck_ffs/main.c     |   22 +++++---
 4 files changed, 114 insertions(+), 36 deletions(-)

diffs (283 lines):

diff -r d97a53a9349a -r df4e62a66133 sbin/fsck_ffs/dir.c
--- a/sbin/fsck_ffs/dir.c       Sun May 05 13:24:19 2019 +0000
+++ b/sbin/fsck_ffs/dir.c       Sun May 05 14:59:06 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: dir.c,v 1.60 2019/05/05 13:24:19 christos Exp $        */
+/*     $NetBSD: dir.c,v 1.61 2019/05/05 14:59:06 christos Exp $        */
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)dir.c      8.8 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: dir.c,v 1.60 2019/05/05 13:24:19 christos Exp $");
+__RCSID("$NetBSD: dir.c,v 1.61 2019/05/05 14:59:06 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -85,7 +85,7 @@
 };
 
 static int chgino(struct  inodesc *);
-static int dircheck(struct inodesc *, struct direct *);
+static int dircheck(struct inodesc *, struct direct *, struct bufarea *);
 static int expanddir(union dinode *, char *);
 static void freedir(ino_t, ino_t);
 static struct direct *fsck_readdir(struct inodesc *);
@@ -251,7 +251,7 @@
        if (idesc->id_loc % dirblksiz == 0 && idesc->id_filesize > 0 &&
            idesc->id_loc < blksiz) {
                dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
-               if (dircheck(idesc, dp))
+               if (dircheck(idesc, dp, bp))
                        goto dpok;
                if (idesc->id_fix == IGNORE)
                        return (0);
@@ -282,7 +282,7 @@
                return (dp);
        ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
        if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
-           dircheck(idesc, ndp) == 0) {
+           dircheck(idesc, ndp, bp) == 0) {
                size = dirblksiz - (idesc->id_loc % dirblksiz);
                idesc->id_loc += size;
                idesc->id_filesize -= size;
@@ -303,24 +303,25 @@
 /*
  * Verify that a directory entry is valid.
  * This is a superset of the checks made in the kernel.
+ * Returns:
+ *     1: good
+ *     0: bad
  */
 static int
-dircheck(struct inodesc *idesc, struct direct *dp)
+dircheck(struct inodesc *idesc, struct direct *dp, struct bufarea *bp) 
 {
-       int size;
+       uint8_t namlen, type;
+       uint16_t reclen;
+       uint32_t ino;
        char *cp;
-       u_char namlen, type;
-       int spaceleft;
+       int size, spaceleft, modified, unused, i;
 
+       modified = 0;
        spaceleft = dirblksiz - (idesc->id_loc % dirblksiz);
-       if (iswap32(dp->d_ino) >= maxino ||
-           dp->d_reclen == 0 ||
-           iswap16(dp->d_reclen) > spaceleft ||
-           (iswap16(dp->d_reclen) & 0x3) != 0) 
-               return (0);
-       if (dp->d_ino == 0)
-               return (1);
-       size = UFS_DIRSIZ(!newinofmt, dp, needswap);
+
+       /* fill in the correct info for our fields */
+       ino = iswap32(dp->d_ino);
+       reclen = iswap16(dp->d_reclen);
        if (!newinofmt && NEEDSWAP) {
                type = dp->d_namlen;
                namlen = dp->d_type;
@@ -328,17 +329,84 @@
                namlen = dp->d_namlen;
                type = dp->d_type;
        }
-       if (iswap16(dp->d_reclen) < size ||
-           idesc->id_filesize < size ||
+
+       if (ino >= maxino ||
+           reclen == 0 || reclen > spaceleft || (reclen & 0x3) != 0)
+               goto bad;
+
+       size = UFS_DIRSIZ(!newinofmt, dp, needswap);
+       if (ino == 0) {
+               /*
+                * Special case of an unused directory entry. Normally
+                * the kernel would coalesce unused space with the previous
+                * entry by extending its d_reclen, but there are situations
+                * (e.g. fsck) where that doesn't occur.
+                * If we're clearing out directory cruft (-z flag), then make
+                * sure this entry gets fully cleared as well.
+                */
+               if (!zflag || fswritefd < 0)
+                       return 1;
+
+               if (dp->d_type != 0) {
+                       dp->d_type = 0;
+                       modified = 1;
+               }
+               if (dp->d_namlen != 0) {
+                       dp->d_namlen = 0;
+                       modified = 1;
+               }
+               if (dp->d_name[0] != '\0') {
+                       dp->d_name[0] = '\0';
+                       modified = 1;
+               }
+               goto good;
+       }
+
+       if (reclen < size || idesc->id_filesize < size ||
            /* namlen > MAXNAMLEN || */
            type > 15)
-               return (0);
-       for (cp = dp->d_name, size = 0; size < namlen; size++)
+               goto bad;
+
+       for (cp = dp->d_name, i = 0; i < namlen; i++)
                if (*cp == '\0' || (*cp++ == '/'))
-                       return (0);
+                       goto bad;
+
        if (*cp != '\0')
-               return (0);
-       return (1);
+               goto bad;
+
+       if (!zflag || fswritefd < 0)
+               return 1;
+good:
+       /*
+        * Clear unused directory entry space, including the d_name
+        * padding.
+        */
+       /* First figure the number of pad bytes. */
+       unused = UFS_NAMEPAD(namlen);
+
+       /* Add in the free space to the end of the record. */
+       unused += iswap16(dp->d_reclen) - size;
+
+       /*
+        * Now clear out the unused space, keeping track if we actually
+        * changed anything.
+        */
+       for (cp = &dp->d_name[namlen]; unused > 0; unused--, cp++) {
+               if (*cp == '\0')
+                       continue;
+               *cp = '\0';
+               modified = 1;
+       }
+
+       /* mark dirty so we update the zeroed space */
+       if (modified)
+               dirty(bp);
+       return 1;
+bad:
+       if (debug)
+               printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n",
+                   ino, reclen, namlen, type, dp->d_name);
+       return 0;
 }
 
 void
diff -r d97a53a9349a -r df4e62a66133 sbin/fsck_ffs/fsck.h
--- a/sbin/fsck_ffs/fsck.h      Sun May 05 13:24:19 2019 +0000
+++ b/sbin/fsck_ffs/fsck.h      Sun May 05 14:59:06 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: fsck.h,v 1.52 2017/02/08 18:05:25 rin Exp $    */
+/*     $NetBSD: fsck.h,v 1.53 2019/05/05 14:59:06 christos Exp $       */
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -276,6 +276,7 @@
 int    Uflag;                  /* resolve user names */
 int    bflag;                  /* location of alternate super block */
 int    debug;                  /* output debugging info */
+int    zflag;                  /* zero unused directory space */
 int    cvtlevel;               /* convert to newer file system format */
 int    doinglevel1;            /* converting to new cylinder group format */
 int    doinglevel2;            /* converting to new inode format */
diff -r d97a53a9349a -r df4e62a66133 sbin/fsck_ffs/fsck_ffs.8
--- a/sbin/fsck_ffs/fsck_ffs.8  Sun May 05 13:24:19 2019 +0000
+++ b/sbin/fsck_ffs/fsck_ffs.8  Sun May 05 14:59:06 2019 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: fsck_ffs.8,v 1.50 2016/09/11 04:07:38 sevan Exp $
+.\"    $NetBSD: fsck_ffs.8,v 1.51 2019/05/05 14:59:06 christos Exp $
 .\"
 .\" Copyright (c) 1980, 1989, 1991, 1993
 .\"    The Regents of the University of California.  All rights reserved.
@@ -29,7 +29,7 @@
 .\"
 .\"    @(#)fsck.8      8.3 (Berkeley) 11/29/94
 .\"
-.Dd September 11, 2016
+.Dd May 4, 2018
 .Dt FSCK_FFS 8
 .Os
 .Sh NAME
@@ -37,7 +37,7 @@
 .Nd Fast File System consistency check and interactive repair
 .Sh SYNOPSIS
 .Nm
-.Op Fl adFfPpqUX
+.Op Fl adFfPpqUXz
 .Op Fl B Ar byteorder
 .Op Fl b Ar block
 .Op Fl c Ar level
@@ -300,6 +300,9 @@
 .Nm ;
 this should be used with great caution as this is a free license
 to continue after essentially unlimited trouble has been encountered.
+.It Fl z
+Clear unused directory space.
+The cleared space includes deleted file names and name padding.
 .El
 .Pp
 Inconsistencies checked are as follows:
diff -r d97a53a9349a -r df4e62a66133 sbin/fsck_ffs/main.c
--- a/sbin/fsck_ffs/main.c      Sun May 05 13:24:19 2019 +0000
+++ b/sbin/fsck_ffs/main.c      Sun May 05 14:59:06 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: main.c,v 1.84 2017/02/08 16:11:40 rin Exp $    */
+/*     $NetBSD: main.c,v 1.85 2019/05/05 14:59:06 christos Exp $       */
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -39,7 +39,7 @@
 #if 0
 static char sccsid[] = "@(#)main.c     8.6 (Berkeley) 5/14/95";
 #else
-__RCSID("$NetBSD: main.c,v 1.84 2017/02/08 16:11:40 rin Exp $");
+__RCSID("$NetBSD: main.c,v 1.85 2019/05/05 14:59:06 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -102,7 +102,7 @@
 #ifndef NO_APPLE_UFS
        isappleufs = 0;
 #endif
-       while ((ch = getopt(argc, argv, "aB:b:c:dFfm:npPqUyx:X")) != -1) {
+       while ((ch = getopt(argc, argv, "aB:b:c:dFfm:npPqUyx:Xz")) != -1) {
                switch (ch) {
 #ifndef NO_APPLE_UFS
                case 'a':
@@ -179,15 +179,21 @@
                        break;
 #endif
 
+               case 'x':
+                       snap_backup = optarg;
+                       break;
+
+               case 'X':
+                       snap_internal = 1;
+                       break;
+
                case 'y':
                        yflag++;
                        nflag = 0;
                        break;
-               case 'x':
-                       snap_backup = optarg;
-                       break;
-               case 'X':
-                       snap_internal = 1;
+
+               case 'z':
+                       zflag++;
                        break;
 
                default:



Home | Main Index | Thread Index | Old Index