pass2.c revision 176574
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1980, 1986, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 30102411Scharnier#if 0 311558Srgrimes#ifndef lint 3223675Speterstatic const char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95"; 33102411Scharnier#endif /* not lint */ 3441477Sjulian#endif 35102411Scharnier#include <sys/cdefs.h> 36102411Scharnier__FBSDID("$FreeBSD: head/sbin/fsck_ffs/pass2.c 176574 2008-02-26 03:05:48Z delphij $"); 37102411Scharnier 381558Srgrimes#include <sys/param.h> 3923675Speter 401558Srgrimes#include <ufs/ufs/dinode.h> 411558Srgrimes#include <ufs/ufs/dir.h> 4274556Smckusick#include <ufs/ffs/fs.h> 4323799Sbde 4423675Speter#include <err.h> 45101037Smux#include <stdint.h> 461558Srgrimes#include <string.h> 4723675Speter 481558Srgrimes#include "fsck.h" 491558Srgrimes 501558Srgrimes#define MINDIRSIZE (sizeof (struct dirtemplate)) 511558Srgrimes 5292839Simpstatic int blksort(const void *, const void *); 5392839Simpstatic int pass2check(struct inodesc *); 541558Srgrimes 557585Sbdevoid 5692839Simppass2(void) 571558Srgrimes{ 5898542Smckusick union dinode *dp; 5992806Sobrien struct inoinfo **inpp, *inp; 601558Srgrimes struct inoinfo **inpend; 611558Srgrimes struct inodesc curino; 6298542Smckusick union dinode dino; 6398542Smckusick int i; 641558Srgrimes char pathbuf[MAXPATHLEN + 1]; 651558Srgrimes 6641474Sjulian switch (inoinfo(ROOTINO)->ino_state) { 671558Srgrimes 681558Srgrimes case USTATE: 691558Srgrimes pfatal("ROOT INODE UNALLOCATED"); 7034266Sjulian if (reply("ALLOCATE") == 0) { 7134266Sjulian ckfini(0); 7223675Speter exit(EEXIT); 7334266Sjulian } 741558Srgrimes if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 7523675Speter errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 761558Srgrimes break; 771558Srgrimes 781558Srgrimes case DCLEAR: 791558Srgrimes pfatal("DUPS/BAD IN ROOT INODE"); 801558Srgrimes if (reply("REALLOCATE")) { 811558Srgrimes freeino(ROOTINO); 821558Srgrimes if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 8323675Speter errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 841558Srgrimes break; 851558Srgrimes } 8634266Sjulian if (reply("CONTINUE") == 0) { 8734266Sjulian ckfini(0); 8823675Speter exit(EEXIT); 8934266Sjulian } 901558Srgrimes break; 911558Srgrimes 921558Srgrimes case FSTATE: 931558Srgrimes case FCLEAR: 94136281Struckman case FZLINK: 951558Srgrimes pfatal("ROOT INODE NOT DIRECTORY"); 961558Srgrimes if (reply("REALLOCATE")) { 971558Srgrimes freeino(ROOTINO); 981558Srgrimes if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 9923675Speter errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 1001558Srgrimes break; 1011558Srgrimes } 10234266Sjulian if (reply("FIX") == 0) { 10334266Sjulian ckfini(0); 10423675Speter exit(EEXIT); 10534266Sjulian } 1061558Srgrimes dp = ginode(ROOTINO); 107134589Sscottl DIP_SET(dp, di_mode, DIP(dp, di_mode) & ~IFMT); 108134589Sscottl DIP_SET(dp, di_mode, DIP(dp, di_mode) | IFDIR); 1091558Srgrimes inodirty(); 1101558Srgrimes break; 1111558Srgrimes 1121558Srgrimes case DSTATE: 113136281Struckman case DZLINK: 1141558Srgrimes break; 1151558Srgrimes 1161558Srgrimes default: 11741474Sjulian errx(EEXIT, "BAD STATE %d FOR ROOT INODE", 11841474Sjulian inoinfo(ROOTINO)->ino_state); 1191558Srgrimes } 12041474Sjulian inoinfo(ROOTINO)->ino_state = DFOUND; 12196483Sphk inoinfo(WINO)->ino_state = FSTATE; 12296483Sphk inoinfo(WINO)->ino_type = DT_WHT; 1231558Srgrimes /* 1241558Srgrimes * Sort the directory list into disk block order. 1251558Srgrimes */ 1261558Srgrimes qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort); 1271558Srgrimes /* 1281558Srgrimes * Check the integrity of each directory. 1291558Srgrimes */ 13023675Speter memset(&curino, 0, sizeof(struct inodesc)); 1311558Srgrimes curino.id_type = DATA; 1321558Srgrimes curino.id_func = pass2check; 1331558Srgrimes inpend = &inpsort[inplast]; 1341558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 13570050Siedowse if (got_siginfo) { 136101037Smux printf("%s: phase 2: dir %td of %d (%d%%)\n", cdevname, 13786514Siedowse inpp - inpsort, (int)inplast, 13886514Siedowse (int)((inpp - inpsort) * 100 / inplast)); 13970050Siedowse got_siginfo = 0; 14070050Siedowse } 141126345Sscottl if (got_sigalarm) { 142126345Sscottl setproctitle("%s p2 %d%%", cdevname, 143126345Sscottl (int)((inpp - inpsort) * 100 / inplast)); 144126345Sscottl got_sigalarm = 0; 145126345Sscottl } 1461558Srgrimes inp = *inpp; 1471558Srgrimes if (inp->i_isize == 0) 1481558Srgrimes continue; 1491558Srgrimes if (inp->i_isize < MINDIRSIZE) { 1501558Srgrimes direrror(inp->i_number, "DIRECTORY TOO SHORT"); 1511558Srgrimes inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ); 1521558Srgrimes if (reply("FIX") == 1) { 1531558Srgrimes dp = ginode(inp->i_number); 154134589Sscottl DIP_SET(dp, di_size, inp->i_isize); 1551558Srgrimes inodirty(); 1561558Srgrimes } 1571558Srgrimes } else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) { 1581558Srgrimes getpathname(pathbuf, inp->i_number, inp->i_number); 15934266Sjulian if (usedsoftdep) 160101037Smux pfatal("%s %s: LENGTH %jd NOT MULTIPLE OF %d", 161101037Smux "DIRECTORY", pathbuf, 162101037Smux (intmax_t)inp->i_isize, DIRBLKSIZ); 16334266Sjulian else 164101037Smux pwarn("%s %s: LENGTH %jd NOT MULTIPLE OF %d", 165101037Smux "DIRECTORY", pathbuf, 166101037Smux (intmax_t)inp->i_isize, DIRBLKSIZ); 1671558Srgrimes if (preen) 1681558Srgrimes printf(" (ADJUSTED)\n"); 1691558Srgrimes inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ); 1701558Srgrimes if (preen || reply("ADJUST") == 1) { 1711558Srgrimes dp = ginode(inp->i_number); 172134589Sscottl DIP_SET(dp, di_size, 173134589Sscottl roundup(inp->i_isize, DIRBLKSIZ)); 1741558Srgrimes inodirty(); 1751558Srgrimes } 1761558Srgrimes } 17798542Smckusick dp = &dino; 17898542Smckusick memset(dp, 0, sizeof(struct ufs2_dinode)); 179134589Sscottl DIP_SET(dp, di_mode, IFDIR); 180134589Sscottl DIP_SET(dp, di_size, inp->i_isize); 18198542Smckusick for (i = 0; 18298542Smckusick i < (inp->i_numblks<NDADDR ? inp->i_numblks : NDADDR); 18398542Smckusick i++) 184134589Sscottl DIP_SET(dp, di_db[i], inp->i_blks[i]); 18598542Smckusick if (inp->i_numblks > NDADDR) 18698542Smckusick for (i = 0; i < NIADDR; i++) 187134589Sscottl DIP_SET(dp, di_ib[i], inp->i_blks[NDADDR + i]); 1881558Srgrimes curino.id_number = inp->i_number; 1891558Srgrimes curino.id_parent = inp->i_parent; 1901558Srgrimes (void)ckinode(dp, &curino); 1911558Srgrimes } 1921558Srgrimes /* 1931558Srgrimes * Now that the parents of all directories have been found, 1941558Srgrimes * make another pass to verify the value of `..' 1951558Srgrimes */ 1961558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 1971558Srgrimes inp = *inpp; 1981558Srgrimes if (inp->i_parent == 0 || inp->i_isize == 0) 1991558Srgrimes continue; 20041474Sjulian if (inoinfo(inp->i_parent)->ino_state == DFOUND && 201136281Struckman INO_IS_DUNFOUND(inp->i_number)) 20241474Sjulian inoinfo(inp->i_number)->ino_state = DFOUND; 2031558Srgrimes if (inp->i_dotdot == inp->i_parent || 2041558Srgrimes inp->i_dotdot == (ino_t)-1) 2051558Srgrimes continue; 2061558Srgrimes if (inp->i_dotdot == 0) { 2071558Srgrimes inp->i_dotdot = inp->i_parent; 2081558Srgrimes fileerror(inp->i_parent, inp->i_number, "MISSING '..'"); 2091558Srgrimes if (reply("FIX") == 0) 2101558Srgrimes continue; 2111558Srgrimes (void)makeentry(inp->i_number, inp->i_parent, ".."); 21241474Sjulian inoinfo(inp->i_parent)->ino_linkcnt--; 2131558Srgrimes continue; 2141558Srgrimes } 2151558Srgrimes fileerror(inp->i_parent, inp->i_number, 2161558Srgrimes "BAD INODE NUMBER FOR '..'"); 2171558Srgrimes if (reply("FIX") == 0) 2181558Srgrimes continue; 21941474Sjulian inoinfo(inp->i_dotdot)->ino_linkcnt++; 22041474Sjulian inoinfo(inp->i_parent)->ino_linkcnt--; 2211558Srgrimes inp->i_dotdot = inp->i_parent; 2221558Srgrimes (void)changeino(inp->i_number, "..", inp->i_parent); 2231558Srgrimes } 2241558Srgrimes /* 2251558Srgrimes * Mark all the directories that can be found from the root. 2261558Srgrimes */ 2271558Srgrimes propagate(); 2281558Srgrimes} 2291558Srgrimes 23023675Speterstatic int 23192839Simppass2check(struct inodesc *idesc) 2321558Srgrimes{ 23392806Sobrien struct direct *dirp = idesc->id_dirp; 23492806Sobrien struct inoinfo *inp; 2351558Srgrimes int n, entrysize, ret = 0; 23698542Smckusick union dinode *dp; 237100935Sphk const char *errmsg; 2381558Srgrimes struct direct proto; 2391558Srgrimes char namebuf[MAXPATHLEN + 1]; 2401558Srgrimes char pathbuf[MAXPATHLEN + 1]; 2411558Srgrimes 2421558Srgrimes /* 2431558Srgrimes * check for "." 2441558Srgrimes */ 245176574Sdelphij if (dirp->d_ino > maxino) 246176574Sdelphij goto chk2; 2471558Srgrimes if (idesc->id_entryno != 0) 2481558Srgrimes goto chk1; 2491558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 2501558Srgrimes if (dirp->d_ino != idesc->id_number) { 2511558Srgrimes direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 2521558Srgrimes dirp->d_ino = idesc->id_number; 2531558Srgrimes if (reply("FIX") == 1) 2541558Srgrimes ret |= ALTERED; 2551558Srgrimes } 25696483Sphk if (dirp->d_type != DT_DIR) { 2571558Srgrimes direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'"); 2581558Srgrimes dirp->d_type = DT_DIR; 2591558Srgrimes if (reply("FIX") == 1) 2601558Srgrimes ret |= ALTERED; 2611558Srgrimes } 2621558Srgrimes goto chk1; 2631558Srgrimes } 2641558Srgrimes direrror(idesc->id_number, "MISSING '.'"); 2651558Srgrimes proto.d_ino = idesc->id_number; 26696483Sphk proto.d_type = DT_DIR; 2671558Srgrimes proto.d_namlen = 1; 2681558Srgrimes (void)strcpy(proto.d_name, "."); 2691558Srgrimes entrysize = DIRSIZ(0, &proto); 2701558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 2711558Srgrimes pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 2721558Srgrimes dirp->d_name); 2731558Srgrimes } else if (dirp->d_reclen < entrysize) { 2741558Srgrimes pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 2751558Srgrimes } else if (dirp->d_reclen < 2 * entrysize) { 2761558Srgrimes proto.d_reclen = dirp->d_reclen; 27723675Speter memmove(dirp, &proto, (size_t)entrysize); 2781558Srgrimes if (reply("FIX") == 1) 2791558Srgrimes ret |= ALTERED; 2801558Srgrimes } else { 2811558Srgrimes n = dirp->d_reclen - entrysize; 2821558Srgrimes proto.d_reclen = entrysize; 28323675Speter memmove(dirp, &proto, (size_t)entrysize); 2841558Srgrimes idesc->id_entryno++; 28541474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 2861558Srgrimes dirp = (struct direct *)((char *)(dirp) + entrysize); 28723675Speter memset(dirp, 0, (size_t)n); 2881558Srgrimes dirp->d_reclen = n; 2891558Srgrimes if (reply("FIX") == 1) 2901558Srgrimes ret |= ALTERED; 2911558Srgrimes } 2921558Srgrimeschk1: 2931558Srgrimes if (idesc->id_entryno > 1) 2941558Srgrimes goto chk2; 2951558Srgrimes inp = getinoinfo(idesc->id_number); 2961558Srgrimes proto.d_ino = inp->i_parent; 29796483Sphk proto.d_type = DT_DIR; 2981558Srgrimes proto.d_namlen = 2; 2991558Srgrimes (void)strcpy(proto.d_name, ".."); 3001558Srgrimes entrysize = DIRSIZ(0, &proto); 3011558Srgrimes if (idesc->id_entryno == 0) { 3021558Srgrimes n = DIRSIZ(0, dirp); 3031558Srgrimes if (dirp->d_reclen < n + entrysize) 3041558Srgrimes goto chk2; 3051558Srgrimes proto.d_reclen = dirp->d_reclen - n; 3061558Srgrimes dirp->d_reclen = n; 3071558Srgrimes idesc->id_entryno++; 30841474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 3091558Srgrimes dirp = (struct direct *)((char *)(dirp) + n); 31023675Speter memset(dirp, 0, (size_t)proto.d_reclen); 3111558Srgrimes dirp->d_reclen = proto.d_reclen; 3121558Srgrimes } 3131558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { 3141558Srgrimes inp->i_dotdot = dirp->d_ino; 31596483Sphk if (dirp->d_type != DT_DIR) { 3161558Srgrimes direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'"); 3171558Srgrimes dirp->d_type = DT_DIR; 3181558Srgrimes if (reply("FIX") == 1) 3191558Srgrimes ret |= ALTERED; 3201558Srgrimes } 3211558Srgrimes goto chk2; 3221558Srgrimes } 3231558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { 3241558Srgrimes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 3251558Srgrimes pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 3261558Srgrimes dirp->d_name); 3271558Srgrimes inp->i_dotdot = (ino_t)-1; 3281558Srgrimes } else if (dirp->d_reclen < entrysize) { 3291558Srgrimes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 3301558Srgrimes pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 3311558Srgrimes inp->i_dotdot = (ino_t)-1; 3321558Srgrimes } else if (inp->i_parent != 0) { 3331558Srgrimes /* 3341558Srgrimes * We know the parent, so fix now. 3351558Srgrimes */ 3361558Srgrimes inp->i_dotdot = inp->i_parent; 3371558Srgrimes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 3381558Srgrimes proto.d_reclen = dirp->d_reclen; 33923675Speter memmove(dirp, &proto, (size_t)entrysize); 3401558Srgrimes if (reply("FIX") == 1) 3411558Srgrimes ret |= ALTERED; 3421558Srgrimes } 3431558Srgrimes idesc->id_entryno++; 3441558Srgrimes if (dirp->d_ino != 0) 34541474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 3461558Srgrimes return (ret|KEEPON); 3471558Srgrimeschk2: 3481558Srgrimes if (dirp->d_ino == 0) 3491558Srgrimes return (ret|KEEPON); 3501558Srgrimes if (dirp->d_namlen <= 2 && 3511558Srgrimes dirp->d_name[0] == '.' && 3521558Srgrimes idesc->id_entryno >= 2) { 3531558Srgrimes if (dirp->d_namlen == 1) { 3541558Srgrimes direrror(idesc->id_number, "EXTRA '.' ENTRY"); 3551558Srgrimes dirp->d_ino = 0; 3561558Srgrimes if (reply("FIX") == 1) 3571558Srgrimes ret |= ALTERED; 3581558Srgrimes return (KEEPON | ret); 3591558Srgrimes } 3601558Srgrimes if (dirp->d_name[1] == '.') { 3611558Srgrimes direrror(idesc->id_number, "EXTRA '..' ENTRY"); 3621558Srgrimes dirp->d_ino = 0; 3631558Srgrimes if (reply("FIX") == 1) 3641558Srgrimes ret |= ALTERED; 3651558Srgrimes return (KEEPON | ret); 3661558Srgrimes } 3671558Srgrimes } 3681558Srgrimes idesc->id_entryno++; 3691558Srgrimes n = 0; 3701558Srgrimes if (dirp->d_ino > maxino) { 3711558Srgrimes fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE"); 3721558Srgrimes n = reply("REMOVE"); 37396483Sphk } else if (((dirp->d_ino == WINO && dirp->d_type != DT_WHT) || 37423675Speter (dirp->d_ino != WINO && dirp->d_type == DT_WHT))) { 37523675Speter fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY"); 37623675Speter dirp->d_ino = WINO; 37723675Speter dirp->d_type = DT_WHT; 37823675Speter if (reply("FIX") == 1) 37923675Speter ret |= ALTERED; 3801558Srgrimes } else { 3811558Srgrimesagain: 38241474Sjulian switch (inoinfo(dirp->d_ino)->ino_state) { 3831558Srgrimes case USTATE: 3841558Srgrimes if (idesc->id_entryno <= 2) 3851558Srgrimes break; 3861558Srgrimes fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED"); 3871558Srgrimes n = reply("REMOVE"); 3881558Srgrimes break; 3891558Srgrimes 3901558Srgrimes case DCLEAR: 3911558Srgrimes case FCLEAR: 3921558Srgrimes if (idesc->id_entryno <= 2) 3931558Srgrimes break; 39441474Sjulian if (inoinfo(dirp->d_ino)->ino_state == FCLEAR) 3951558Srgrimes errmsg = "DUP/BAD"; 39634266Sjulian else if (!preen && !usedsoftdep) 3971558Srgrimes errmsg = "ZERO LENGTH DIRECTORY"; 3981558Srgrimes else { 3991558Srgrimes n = 1; 4001558Srgrimes break; 4011558Srgrimes } 4021558Srgrimes fileerror(idesc->id_number, dirp->d_ino, errmsg); 4031558Srgrimes if ((n = reply("REMOVE")) == 1) 4041558Srgrimes break; 4051558Srgrimes dp = ginode(dirp->d_ino); 40641474Sjulian inoinfo(dirp->d_ino)->ino_state = 40798542Smckusick (DIP(dp, di_mode) & IFMT) == IFDIR ? DSTATE : FSTATE; 40898542Smckusick inoinfo(dirp->d_ino)->ino_linkcnt = DIP(dp, di_nlink); 4091558Srgrimes goto again; 4101558Srgrimes 4111558Srgrimes case DSTATE: 412136281Struckman case DZLINK: 41341474Sjulian if (inoinfo(idesc->id_number)->ino_state == DFOUND) 41441474Sjulian inoinfo(dirp->d_ino)->ino_state = DFOUND; 415102411Scharnier /* FALLTHROUGH */ 4161558Srgrimes 4171558Srgrimes case DFOUND: 4181558Srgrimes inp = getinoinfo(dirp->d_ino); 4191558Srgrimes if (inp->i_parent != 0 && idesc->id_entryno > 2) { 4201558Srgrimes getpathname(pathbuf, idesc->id_number, 4211558Srgrimes idesc->id_number); 4221558Srgrimes getpathname(namebuf, dirp->d_ino, dirp->d_ino); 42386512Siedowse pwarn("%s%s%s %s %s\n", pathbuf, 42486512Siedowse (strcmp(pathbuf, "/") == 0 ? "" : "/"), 42586512Siedowse dirp->d_name, 4261558Srgrimes "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", 4271558Srgrimes namebuf); 42874556Smckusick if (cursnapshot != 0) 42974556Smckusick break; 43034266Sjulian if (preen) { 43134266Sjulian printf(" (REMOVED)\n"); 43241474Sjulian n = 1; 43341474Sjulian break; 43434266Sjulian } 43541474Sjulian if ((n = reply("REMOVE")) == 1) 4361558Srgrimes break; 4371558Srgrimes } 4381558Srgrimes if (idesc->id_entryno > 2) 4391558Srgrimes inp->i_parent = idesc->id_number; 440102411Scharnier /* FALLTHROUGH */ 4411558Srgrimes 4421558Srgrimes case FSTATE: 443136281Struckman case FZLINK: 44496483Sphk if (dirp->d_type != inoinfo(dirp->d_ino)->ino_type) { 4451558Srgrimes fileerror(idesc->id_number, dirp->d_ino, 4461558Srgrimes "BAD TYPE VALUE"); 44741474Sjulian dirp->d_type = inoinfo(dirp->d_ino)->ino_type; 4481558Srgrimes if (reply("FIX") == 1) 4491558Srgrimes ret |= ALTERED; 4501558Srgrimes } 45141474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 4521558Srgrimes break; 4531558Srgrimes 4541558Srgrimes default: 45523675Speter errx(EEXIT, "BAD STATE %d FOR INODE I=%d", 45641474Sjulian inoinfo(dirp->d_ino)->ino_state, dirp->d_ino); 4571558Srgrimes } 4581558Srgrimes } 4591558Srgrimes if (n == 0) 4601558Srgrimes return (ret|KEEPON); 4611558Srgrimes dirp->d_ino = 0; 4621558Srgrimes return (ret|KEEPON|ALTERED); 4631558Srgrimes} 4641558Srgrimes 4651558Srgrimes/* 4661558Srgrimes * Routine to sort disk blocks. 4671558Srgrimes */ 46823675Speterstatic int 46992839Simpblksort(const void *arg1, const void *arg2) 4701558Srgrimes{ 4711558Srgrimes 472100935Sphk return ((*(struct inoinfo * const *)arg1)->i_blks[0] - 473100935Sphk (*(struct inoinfo * const *)arg2)->i_blks[0]); 4741558Srgrimes} 475