diff options
Diffstat (limited to 'sbin')
| -rw-r--r-- | sbin/fsck_ffs/pass2.c | 145 |
1 files changed, 84 insertions, 61 deletions
diff --git a/sbin/fsck_ffs/pass2.c b/sbin/fsck_ffs/pass2.c index 07b4b162047..54dbeb4a7a0 100644 --- a/sbin/fsck_ffs/pass2.c +++ b/sbin/fsck_ffs/pass2.c @@ -1,4 +1,4 @@ -/* $NetBSD: pass2.c,v 1.51 2017/02/08 16:11:40 rin Exp $ */ +/* $NetBSD: pass2.c,v 1.52 2023/03/27 22:53:37 chs Exp $ */ /* * Copyright (c) 1980, 1986, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95"; #else -__RCSID("$NetBSD: pass2.c,v 1.51 2017/02/08 16:11:40 rin Exp $"); +__RCSID("$NetBSD: pass2.c,v 1.52 2023/03/27 22:53:37 chs Exp $"); #endif #endif /* not lint */ @@ -271,11 +271,9 @@ pass2(void) info = inoinfo(inp->i_parent); if (inp->i_dotdot == 0) { inp->i_dotdot = inp->i_parent; - fileerror(inp->i_parent, inp->i_number, "MISSING '..'"); - if (reply("FIX") == 0) { - markclean = 0; - continue; - } + if (debug) + fileerror(inp->i_parent, inp->i_number, + "DEFERRED MISSING '..' FIX"); (void)makeentry(inp->i_number, inp->i_parent, ".."); info->ino_linkcnt--; continue; @@ -331,7 +329,7 @@ pass2check(struct inodesc *idesc) int n, entrysize, ret = 0; union dinode *dp; const char *errmsg; - struct direct proto; + struct direct proto, *newdirp; char namebuf[MAXPATHLEN + 1]; char pathbuf[MAXPATHLEN + 1]; @@ -351,23 +349,22 @@ pass2check(struct inodesc *idesc) if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { if (iswap32(dirp->d_ino) != idesc->id_number) { direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); - dirp->d_ino = iswap32(idesc->id_number); - if (reply("FIX") == 1) + if (reply("FIX") == 1) { + dirp->d_ino = iswap32(idesc->id_number); ret |= ALTERED; - else + } else markclean = 0; } if (newinofmt && dirp->d_type != DT_DIR) { direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'"); - dirp->d_type = DT_DIR; - if (reply("FIX") == 1) + if (reply("FIX") == 1) { + dirp->d_type = DT_DIR; ret |= ALTERED; - else + } else markclean = 0; } goto chk1; } - direrror(idesc->id_number, "MISSING '.'"); proto.d_ino = iswap32(idesc->id_number); if (newinofmt) proto.d_type = DT_DIR; @@ -387,33 +384,33 @@ pass2check(struct inodesc *idesc) proto.d_namlen = tmp; } entrysize = UFS_DIRSIZ(0, &proto, 0); - if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { - pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", - dirp->d_name); - markclean = 0; - } else if (iswap16(dirp->d_reclen) < entrysize) { - pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); - markclean = 0; - } else if (iswap16(dirp->d_reclen) < 2 * entrysize) { + direrror(idesc->id_number, "MISSING '.'"); + errmsg = "ADD '.' ENTRY"; + if (iswap16(dirp->d_reclen) < entrysize + UFS_DIRSIZ(0, dirp, 0)) { + /* Not enough space to add '.', replace first entry with '.' */ + if (dirp->d_ino != 0) { + pwarn("\nFIRST ENTRY IN DIRECTORY CONTAINS %s\n", + dirp->d_name); + errmsg = "REPLACE WITH '.'"; + } + if (reply(errmsg) == 0) + goto chk1; proto.d_reclen = dirp->d_reclen; memmove(dirp, &proto, (size_t)entrysize); - if (reply("FIX") == 1) - ret |= ALTERED; - else - markclean = 0; + ret |= ALTERED; } else { - n = iswap16(dirp->d_reclen) - entrysize; + /* Move over first entry and add '.' entry */ + if (reply(errmsg) == 0) + goto chk1; + newdirp = (struct direct *)((char *)(dirp) + entrysize); + dirp->d_reclen = iswap16(iswap16(dirp->d_reclen) - entrysize); + memmove(newdirp, dirp, iswap16(dirp->d_reclen)); proto.d_reclen = iswap16(entrysize); memmove(dirp, &proto, (size_t)entrysize); idesc->id_entryno++; - inoinfo(iswap32(dirp->d_ino))->ino_linkcnt--; - dirp = (struct direct *)((char *)(dirp) + entrysize); - memset(dirp, 0, (size_t)n); - dirp->d_reclen = iswap16(n); - if (reply("FIX") == 1) - ret |= ALTERED; - else - markclean = 0; + inoinfo(idesc->id_number)->ino_linkcnt--; + dirp = newdirp; + ret |= ALTERED; } chk1: if (idesc->id_entryno > 1) @@ -462,34 +459,60 @@ chk1: } goto chk2; } - if (iswap32(dirp->d_ino) != 0 && strcmp(dirp->d_name, ".") != 0) { - fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); - pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", - dirp->d_name); - inp->i_dotdot = (ino_t)-1; - markclean = 0; - } else if (iswap16(dirp->d_reclen) < entrysize) { - fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); - pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); - inp->i_dotdot = (ino_t)-1; - markclean = 0; - } else if (inp->i_parent != 0) { - /* - * We know the parent, so fix now. - */ - inp->i_dotdot = inp->i_parent; - fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); + fileerror(inp->i_parent != 0 ? inp->i_parent : idesc->id_number, + idesc->id_number, "MISSING '..'"); + errmsg = "ADD '..' ENTRY"; + if (dirp->d_reclen < entrysize + UFS_DIRSIZ(0, dirp, 0)) { + /* No space to add '..', replace second entry with '..' */ + if (dirp->d_ino != 0) { + pfatal("SECOND ENTRY IN DIRECTORY CONTAINS %s\n", + dirp->d_name); + errmsg = "REPLACE WITH '..'"; + } + if (reply(errmsg) == 0) { + inp->i_dotdot = (ino_t)-1; + goto chk2; + } + if (proto.d_ino == 0) { + /* Defer processing until parent known */ + idesc->id_entryno++; + if (debug) + printf("(FIX DEFERRED)\n"); + } + inp->i_dotdot = proto.d_ino; proto.d_reclen = dirp->d_reclen; memmove(dirp, &proto, (size_t)entrysize); - if (reply("FIX") == 1) - ret |= ALTERED; - else - markclean = 0; + ret |= ALTERED; + } else { + /* Move over second entry and add '..' entry */ + if (reply(errmsg) == 0) { + inp->i_dotdot = (ino_t)-1; + goto chk2; + } + if (proto.d_ino == 0) { + /* Defer processing until parent known */ + idesc->id_entryno++; + if (debug) + printf("(FIX DEFERRED)\n"); + } + inp->i_dotdot = proto.d_ino; + if (dirp->d_ino == 0) { + proto.d_reclen = dirp->d_reclen; + memmove(dirp, &proto, (size_t)entrysize); + } else { + newdirp = (struct direct *)((char *)(dirp) + entrysize); + dirp->d_reclen -= entrysize; + memmove(newdirp, dirp, dirp->d_reclen); + proto.d_reclen = entrysize; + memmove(dirp, &proto, (size_t)entrysize); + if (dirp->d_ino != 0) { + idesc->id_entryno++; + inoinfo(dirp->d_ino)->ino_linkcnt--; + } + dirp = newdirp; + } + ret |= ALTERED; } - idesc->id_entryno++; - if (dirp->d_ino != 0) - inoinfo(iswap32(dirp->d_ino))->ino_linkcnt--; - return (ret|KEEPON); chk2: if (dirp->d_ino == 0) return (ret|KEEPON); |
