diff options
Diffstat (limited to 'sbin/fsck_ffs/pass3.c')
-rw-r--r-- | sbin/fsck_ffs/pass3.c | 71 |
1 files changed, 55 insertions, 16 deletions
diff --git a/sbin/fsck_ffs/pass3.c b/sbin/fsck_ffs/pass3.c index 6524a11..6320755 100644 --- a/sbin/fsck_ffs/pass3.c +++ b/sbin/fsck_ffs/pass3.c @@ -32,45 +32,84 @@ */ #ifndef lint -#if 0 static const char sccsid[] = "@(#)pass3.c 8.2 (Berkeley) 4/27/95"; -#endif -static const char rcsid[] = - "$Id$"; #endif /* not lint */ #include <sys/param.h> +#include <sys/time.h> #include <ufs/ufs/dinode.h> +#include <ufs/ufs/dir.h> +#include <ufs/ffs/fs.h> + +#include <string.h> #include "fsck.h" void pass3() { - register struct inoinfo **inpp, *inp; + struct inoinfo *inp; + int loopcnt, inpindex, state; ino_t orphan; - int loopcnt; + struct inodesc idesc; + char namebuf[MAXNAMLEN+1]; - for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) { - inp = *inpp; + for (inpindex = inplast - 1; inpindex >= 0; inpindex--) { + inp = inpsort[inpindex]; + state = inoinfo(inp->i_number)->ino_state; if (inp->i_number == ROOTINO || - !(inp->i_parent == 0 || statemap[inp->i_number] == DSTATE)) + (inp->i_parent != 0 && state != DSTATE)) + continue; + if (state == DCLEAR) continue; - if (statemap[inp->i_number] == DCLEAR) + /* + * If we are running with soft updates and we come + * across unreferenced directories, we just leave + * them in DSTATE which will cause them to be pitched + * in pass 4. + */ + if (preen && resolved && usedsoftdep && state == DSTATE) { + if (inp->i_dotdot >= ROOTINO) + inoinfo(inp->i_dotdot)->ino_linkcnt++; continue; + } for (loopcnt = 0; ; loopcnt++) { orphan = inp->i_number; if (inp->i_parent == 0 || - statemap[inp->i_parent] != DSTATE || - loopcnt > numdirs) + inoinfo(inp->i_parent)->ino_state != DSTATE || + loopcnt > countdirs) break; inp = getinoinfo(inp->i_parent); } - (void)linkup(orphan, inp->i_dotdot); - inp->i_parent = inp->i_dotdot = lfdir; - lncntp[lfdir]--; - statemap[orphan] = DFOUND; + if (loopcnt <= countdirs) { + if (linkup(orphan, inp->i_dotdot, NULL)) { + inp->i_parent = inp->i_dotdot = lfdir; + inoinfo(lfdir)->ino_linkcnt--; + } + inoinfo(orphan)->ino_state = DFOUND; + propagate(); + continue; + } + pfatal("ORPHANED DIRECTORY LOOP DETECTED I=%lu", orphan); + if (reply("RECONNECT") == 0) + continue; + memset(&idesc, 0, sizeof(struct inodesc)); + idesc.id_type = DATA; + idesc.id_number = inp->i_parent; + idesc.id_parent = orphan; + idesc.id_func = findname; + idesc.id_name = namebuf; + if ((ckinode(ginode(inp->i_parent), &idesc) & FOUND) == 0) + pfatal("COULD NOT FIND NAME IN PARENT DIRECTORY"); + if (linkup(orphan, inp->i_parent, namebuf)) { + idesc.id_func = clearentry; + if (ckinode(ginode(inp->i_parent), &idesc) & FOUND) + inoinfo(orphan)->ino_linkcnt++; + inp->i_parent = inp->i_dotdot = lfdir; + inoinfo(lfdir)->ino_linkcnt--; + } + inoinfo(orphan)->ino_state = DFOUND; propagate(); } } |