Module Name: src Committed By: christos Date: Sun May 5 14:59:07 UTC 2019
Modified Files: src/sbin/fsck_ffs: dir.c fsck.h fsck_ffs.8 main.c Log Message: 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". To generate a diff of this commit: cvs rdiff -u -r1.60 -r1.61 src/sbin/fsck_ffs/dir.c cvs rdiff -u -r1.52 -r1.53 src/sbin/fsck_ffs/fsck.h cvs rdiff -u -r1.50 -r1.51 src/sbin/fsck_ffs/fsck_ffs.8 cvs rdiff -u -r1.84 -r1.85 src/sbin/fsck_ffs/main.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sbin/fsck_ffs/dir.c diff -u src/sbin/fsck_ffs/dir.c:1.60 src/sbin/fsck_ffs/dir.c:1.61 --- src/sbin/fsck_ffs/dir.c:1.60 Sun May 5 09:24:19 2019 +++ src/sbin/fsck_ffs/dir.c Sun May 5 10:59:06 2019 @@ -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 @@ struct odirtemplate odirhead = { }; 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 @@ fsck_readdir(struct inodesc *idesc) 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 @@ dpok: 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 @@ dpok: /* * 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 @@ dircheck(struct inodesc *idesc, struct d 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 Index: src/sbin/fsck_ffs/fsck.h diff -u src/sbin/fsck_ffs/fsck.h:1.52 src/sbin/fsck_ffs/fsck.h:1.53 --- src/sbin/fsck_ffs/fsck.h:1.52 Wed Feb 8 13:05:25 2017 +++ src/sbin/fsck_ffs/fsck.h Sun May 5 10:59:06 2019 @@ -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 @@ char yflag; /* assume a yes response * 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 */ Index: src/sbin/fsck_ffs/fsck_ffs.8 diff -u src/sbin/fsck_ffs/fsck_ffs.8:1.50 src/sbin/fsck_ffs/fsck_ffs.8:1.51 --- src/sbin/fsck_ffs/fsck_ffs.8:1.50 Sun Sep 11 00:07:38 2016 +++ src/sbin/fsck_ffs/fsck_ffs.8 Sun May 5 10:59:06 2019 @@ -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 @@ Assume a yes response to all questions a .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: Index: src/sbin/fsck_ffs/main.c diff -u src/sbin/fsck_ffs/main.c:1.84 src/sbin/fsck_ffs/main.c:1.85 --- src/sbin/fsck_ffs/main.c:1.84 Wed Feb 8 11:11:40 2017 +++ src/sbin/fsck_ffs/main.c Sun May 5 10:59:06 2019 @@ -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 @@ __COPYRIGHT("@(#) Copyright (c) 1980, 19 #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 @@ main(int argc, char *argv[]) #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,17 +179,23 @@ main(int argc, char *argv[]) break; #endif - case 'y': - yflag++; - nflag = 0; - break; case 'x': snap_backup = optarg; break; + case 'X': snap_internal = 1; break; + case 'y': + yflag++; + nflag = 0; + break; + + case 'z': + zflag++; + break; + default: usage(); }