summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-rw-r--r--sbin/fsck_ffs/dir.c109
-rw-r--r--sbin/fsck_ffs/fsck.h1
-rw-r--r--sbin/fsck_ffs/fsck_ffs.87
-rw-r--r--sbin/fsck_ffs/globs.c1
-rw-r--r--sbin/fsck_ffs/main.c6
5 files changed, 104 insertions, 20 deletions
diff --git a/sbin/fsck_ffs/dir.c b/sbin/fsck_ffs/dir.c
index 6043497..8efbabd 100644
--- a/sbin/fsck_ffs/dir.c
+++ b/sbin/fsck_ffs/dir.c
@@ -145,14 +145,23 @@ fsck_readdir(struct inodesc *idesc)
struct direct *dp, *ndp;
struct bufarea *bp;
long size, blksiz, fix, dploc;
+ int dc;
blksiz = idesc->id_numfrags * sblock.fs_fsize;
bp = getdirblk(idesc->id_blkno, blksiz);
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 ((dc = dircheck(idesc, dp)) > 0) {
+ if (dc == 2) {
+ /*
+ * dircheck() cleared unused directory space.
+ * Mark the buffer as dirty to write it out.
+ */
+ dirty(bp);
+ }
goto dpok;
+ }
if (idesc->id_fix == IGNORE)
return (0);
fix = dofix(idesc, "DIRECTORY CORRUPTED");
@@ -179,19 +188,26 @@ dpok:
if ((idesc->id_loc % DIRBLKSIZ) == 0)
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) {
- size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
- idesc->id_loc += size;
- idesc->id_filesize -= size;
- if (idesc->id_fix == IGNORE)
- return (0);
- fix = dofix(idesc, "DIRECTORY CORRUPTED");
- bp = getdirblk(idesc->id_blkno, blksiz);
- dp = (struct direct *)(bp->b_un.b_buf + dploc);
- dp->d_reclen += size;
- if (fix)
+ if (idesc->id_loc < blksiz && idesc->id_filesize > 0) {
+ if ((dc = dircheck(idesc, ndp)) == 0) {
+ size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
+ idesc->id_loc += size;
+ idesc->id_filesize -= size;
+ if (idesc->id_fix == IGNORE)
+ return (0);
+ fix = dofix(idesc, "DIRECTORY CORRUPTED");
+ bp = getdirblk(idesc->id_blkno, blksiz);
+ dp = (struct direct *)(bp->b_un.b_buf + dploc);
+ dp->d_reclen += size;
+ if (fix)
+ dirty(bp);
+ } else if (dc == 2) {
+ /*
+ * dircheck() cleared unused directory space.
+ * Mark the buffer as dirty to write it out.
+ */
dirty(bp);
+ }
}
return (dp);
}
@@ -199,6 +215,11 @@ dpok:
/*
* Verify that a directory entry is valid.
* This is a superset of the checks made in the kernel.
+ * Also optionally clears padding and unused directory space.
+ *
+ * Returns 0 if the entry is bad, 1 if the entry is good and no changes
+ * were made, and 2 if the entry is good but modified to clear out padding
+ * and unused space and needs to be written back to disk.
*/
static int
dircheck(struct inodesc *idesc, struct direct *dp)
@@ -207,15 +228,39 @@ dircheck(struct inodesc *idesc, struct direct *dp)
char *cp;
u_char type;
u_int8_t namlen;
- int spaceleft;
+ int spaceleft, modified, unused;
+ modified = 0;
spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
if (dp->d_reclen == 0 ||
dp->d_reclen > spaceleft ||
- (dp->d_reclen & 0x3) != 0)
+ (dp->d_reclen & (DIR_ROUNDUP - 1)) != 0)
goto bad;
- if (dp->d_ino == 0)
- return (1);
+ if (dp->d_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) {
+ 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;
+ }
size = DIRSIZ(0, dp);
namlen = dp->d_namlen;
type = dp->d_type;
@@ -229,7 +274,37 @@ dircheck(struct inodesc *idesc, struct direct *dp)
goto bad;
if (*cp != '\0')
goto bad;
+
+good:
+ if (zflag && fswritefd >= 0) {
+ /*
+ * Clear unused directory entry space, including the d_name
+ * padding.
+ */
+ /* First figure the number of pad bytes. */
+ unused = roundup2(namlen + 1, DIR_ROUNDUP) - (namlen + 1);
+
+ /* Add in the free space to the end of the record. */
+ unused += dp->d_reclen - DIRSIZ(0, dp);
+
+ /*
+ * Now clear out the unused space, keeping track if we actually
+ * changed anything.
+ */
+ for (cp = &dp->d_name[namlen + 1]; unused > 0; unused--, cp++) {
+ if (*cp != '\0') {
+ *cp = '\0';
+ modified = 1;
+ }
+ }
+
+ if (modified) {
+ return 2;
+ }
+ }
+
return (1);
+
bad:
if (debug)
printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n",
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index 12f863a..065048e 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -310,6 +310,7 @@ extern ufs2_daddr_t bflag; /* location of alternate super block */
extern int debug; /* output debugging info */
extern int Eflag; /* delete empty data blocks */
extern int Zflag; /* zero empty data blocks */
+extern int zflag; /* zero unused directory space */
extern int inoopt; /* trim out unused inodes */
extern char ckclean; /* only do work if not cleanly unmounted */
extern int cvtlevel; /* convert to newer file system format */
diff --git a/sbin/fsck_ffs/fsck_ffs.8 b/sbin/fsck_ffs/fsck_ffs.8
index fa6f7d9..b0c2ebb 100644
--- a/sbin/fsck_ffs/fsck_ffs.8
+++ b/sbin/fsck_ffs/fsck_ffs.8
@@ -29,7 +29,7 @@
.\" @(#)fsck.8 8.4 (Berkeley) 5/9/95
.\" $FreeBSD$
.\"
-.Dd January 13, 2018
+.Dd May 3, 2019
.Dt FSCK_FFS 8
.Os
.Sh NAME
@@ -38,7 +38,7 @@
.Nd file system consistency check and interactive repair
.Sh SYNOPSIS
.Nm
-.Op Fl BCdEFfnpRrSyZ
+.Op Fl BCdEFfnpRrSyZz
.Op Fl b Ar block
.Op Fl c Ar level
.Op Fl m Ar mode
@@ -301,6 +301,9 @@ If both
and
.Fl Z
are specified, blocks are first zeroed and then erased.
+.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 --git a/sbin/fsck_ffs/globs.c b/sbin/fsck_ffs/globs.c
index a642249..64edb12 100644
--- a/sbin/fsck_ffs/globs.c
+++ b/sbin/fsck_ffs/globs.c
@@ -82,6 +82,7 @@ ufs2_daddr_t bflag; /* location of alternate super block */
int debug; /* output debugging info */
int Eflag; /* delete empty data blocks */
int Zflag; /* zero empty data blocks */
+int zflag; /* zero unused directory space */
int inoopt; /* trim out unused inodes */
char ckclean; /* only do work if not cleanly unmounted */
int cvtlevel; /* convert to newer file system format */
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index 98cdafd..2449401 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -86,7 +86,7 @@ main(int argc, char *argv[])
sync();
skipclean = 1;
inoopt = 0;
- while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:npRrSyZ")) != -1) {
+ while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:npRrSyZz")) != -1) {
switch (ch) {
case 'b':
skipclean = 0;
@@ -163,6 +163,10 @@ main(int argc, char *argv[])
Zflag++;
break;
+ case 'z':
+ zflag++;
+ break;
+
default:
usage();
}
OpenPOWER on IntegriCloud