pass2.c revision 101037
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 * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 3541477Sjulian#if 0 3623675Speterstatic const char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95"; 3741477Sjulian#endif 3841477Sjulianstatic const char rcsid[] = 3950476Speter "$FreeBSD: head/sbin/fsck_ffs/pass2.c 101037 2002-07-31 12:01:14Z mux $"; 401558Srgrimes#endif /* not lint */ 411558Srgrimes 421558Srgrimes#include <sys/param.h> 4323675Speter 441558Srgrimes#include <ufs/ufs/dinode.h> 451558Srgrimes#include <ufs/ufs/dir.h> 4674556Smckusick#include <ufs/ffs/fs.h> 4723799Sbde 4823675Speter#include <err.h> 49101037Smux#include <stdint.h> 501558Srgrimes#include <string.h> 5123675Speter 521558Srgrimes#include "fsck.h" 531558Srgrimes 541558Srgrimes#define MINDIRSIZE (sizeof (struct dirtemplate)) 551558Srgrimes 5692839Simpstatic int blksort(const void *, const void *); 5792839Simpstatic int pass2check(struct inodesc *); 581558Srgrimes 597585Sbdevoid 6092839Simppass2(void) 611558Srgrimes{ 6298542Smckusick union dinode *dp; 6392806Sobrien struct inoinfo **inpp, *inp; 641558Srgrimes struct inoinfo **inpend; 651558Srgrimes struct inodesc curino; 6698542Smckusick union dinode dino; 6798542Smckusick int i; 681558Srgrimes char pathbuf[MAXPATHLEN + 1]; 691558Srgrimes 7041474Sjulian switch (inoinfo(ROOTINO)->ino_state) { 711558Srgrimes 721558Srgrimes case USTATE: 731558Srgrimes pfatal("ROOT INODE UNALLOCATED"); 7434266Sjulian if (reply("ALLOCATE") == 0) { 7534266Sjulian ckfini(0); 7623675Speter exit(EEXIT); 7734266Sjulian } 781558Srgrimes if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 7923675Speter errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 801558Srgrimes break; 811558Srgrimes 821558Srgrimes case DCLEAR: 831558Srgrimes pfatal("DUPS/BAD IN ROOT INODE"); 841558Srgrimes if (reply("REALLOCATE")) { 851558Srgrimes freeino(ROOTINO); 861558Srgrimes if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 8723675Speter errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 881558Srgrimes break; 891558Srgrimes } 9034266Sjulian if (reply("CONTINUE") == 0) { 9134266Sjulian ckfini(0); 9223675Speter exit(EEXIT); 9334266Sjulian } 941558Srgrimes break; 951558Srgrimes 961558Srgrimes case FSTATE: 971558Srgrimes case FCLEAR: 981558Srgrimes pfatal("ROOT INODE NOT DIRECTORY"); 991558Srgrimes if (reply("REALLOCATE")) { 1001558Srgrimes freeino(ROOTINO); 1011558Srgrimes if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 10223675Speter errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 1031558Srgrimes break; 1041558Srgrimes } 10534266Sjulian if (reply("FIX") == 0) { 10634266Sjulian ckfini(0); 10723675Speter exit(EEXIT); 10834266Sjulian } 1091558Srgrimes dp = ginode(ROOTINO); 11098542Smckusick DIP(dp, di_mode) &= ~IFMT; 11198542Smckusick DIP(dp, di_mode) |= IFDIR; 1121558Srgrimes inodirty(); 1131558Srgrimes break; 1141558Srgrimes 1151558Srgrimes case DSTATE: 1161558Srgrimes break; 1171558Srgrimes 1181558Srgrimes default: 11941474Sjulian errx(EEXIT, "BAD STATE %d FOR ROOT INODE", 12041474Sjulian inoinfo(ROOTINO)->ino_state); 1211558Srgrimes } 12241474Sjulian inoinfo(ROOTINO)->ino_state = DFOUND; 12396483Sphk inoinfo(WINO)->ino_state = FSTATE; 12496483Sphk inoinfo(WINO)->ino_type = DT_WHT; 1251558Srgrimes /* 1261558Srgrimes * Sort the directory list into disk block order. 1271558Srgrimes */ 1281558Srgrimes qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort); 1291558Srgrimes /* 1301558Srgrimes * Check the integrity of each directory. 1311558Srgrimes */ 13223675Speter memset(&curino, 0, sizeof(struct inodesc)); 1331558Srgrimes curino.id_type = DATA; 1341558Srgrimes curino.id_func = pass2check; 1351558Srgrimes inpend = &inpsort[inplast]; 1361558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 13770050Siedowse if (got_siginfo) { 138101037Smux printf("%s: phase 2: dir %td of %d (%d%%)\n", cdevname, 13986514Siedowse inpp - inpsort, (int)inplast, 14086514Siedowse (int)((inpp - inpsort) * 100 / inplast)); 14170050Siedowse got_siginfo = 0; 14270050Siedowse } 1431558Srgrimes inp = *inpp; 1441558Srgrimes if (inp->i_isize == 0) 1451558Srgrimes continue; 1461558Srgrimes if (inp->i_isize < MINDIRSIZE) { 1471558Srgrimes direrror(inp->i_number, "DIRECTORY TOO SHORT"); 1481558Srgrimes inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ); 1491558Srgrimes if (reply("FIX") == 1) { 1501558Srgrimes dp = ginode(inp->i_number); 15198542Smckusick DIP(dp, di_size) = inp->i_isize; 1521558Srgrimes inodirty(); 1531558Srgrimes } 1541558Srgrimes } else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) { 1551558Srgrimes getpathname(pathbuf, inp->i_number, inp->i_number); 15634266Sjulian if (usedsoftdep) 157101037Smux pfatal("%s %s: LENGTH %jd NOT MULTIPLE OF %d", 158101037Smux "DIRECTORY", pathbuf, 159101037Smux (intmax_t)inp->i_isize, DIRBLKSIZ); 16034266Sjulian else 161101037Smux pwarn("%s %s: LENGTH %jd NOT MULTIPLE OF %d", 162101037Smux "DIRECTORY", pathbuf, 163101037Smux (intmax_t)inp->i_isize, DIRBLKSIZ); 1641558Srgrimes if (preen) 1651558Srgrimes printf(" (ADJUSTED)\n"); 1661558Srgrimes inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ); 1671558Srgrimes if (preen || reply("ADJUST") == 1) { 1681558Srgrimes dp = ginode(inp->i_number); 16998542Smckusick DIP(dp, di_size) = 17098542Smckusick roundup(inp->i_isize, DIRBLKSIZ); 1711558Srgrimes inodirty(); 1721558Srgrimes } 1731558Srgrimes } 17498542Smckusick dp = &dino; 17598542Smckusick memset(dp, 0, sizeof(struct ufs2_dinode)); 17698542Smckusick DIP(dp, di_mode) = IFDIR; 17798542Smckusick DIP(dp, di_size) = inp->i_isize; 17898542Smckusick for (i = 0; 17998542Smckusick i < (inp->i_numblks<NDADDR ? inp->i_numblks : NDADDR); 18098542Smckusick i++) 18198542Smckusick DIP(dp, di_db[i]) = inp->i_blks[i]; 18298542Smckusick if (inp->i_numblks > NDADDR) 18398542Smckusick for (i = 0; i < NIADDR; i++) 18498542Smckusick DIP(dp, di_ib[i]) = inp->i_blks[NDADDR + i]; 1851558Srgrimes curino.id_number = inp->i_number; 1861558Srgrimes curino.id_parent = inp->i_parent; 1871558Srgrimes (void)ckinode(dp, &curino); 1881558Srgrimes } 1891558Srgrimes /* 1901558Srgrimes * Now that the parents of all directories have been found, 1911558Srgrimes * make another pass to verify the value of `..' 1921558Srgrimes */ 1931558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 1941558Srgrimes inp = *inpp; 1951558Srgrimes if (inp->i_parent == 0 || inp->i_isize == 0) 1961558Srgrimes continue; 19741474Sjulian if (inoinfo(inp->i_parent)->ino_state == DFOUND && 19841474Sjulian inoinfo(inp->i_number)->ino_state == DSTATE) 19941474Sjulian inoinfo(inp->i_number)->ino_state = DFOUND; 2001558Srgrimes if (inp->i_dotdot == inp->i_parent || 2011558Srgrimes inp->i_dotdot == (ino_t)-1) 2021558Srgrimes continue; 2031558Srgrimes if (inp->i_dotdot == 0) { 2041558Srgrimes inp->i_dotdot = inp->i_parent; 2051558Srgrimes fileerror(inp->i_parent, inp->i_number, "MISSING '..'"); 2061558Srgrimes if (reply("FIX") == 0) 2071558Srgrimes continue; 2081558Srgrimes (void)makeentry(inp->i_number, inp->i_parent, ".."); 20941474Sjulian inoinfo(inp->i_parent)->ino_linkcnt--; 2101558Srgrimes continue; 2111558Srgrimes } 2121558Srgrimes fileerror(inp->i_parent, inp->i_number, 2131558Srgrimes "BAD INODE NUMBER FOR '..'"); 2141558Srgrimes if (reply("FIX") == 0) 2151558Srgrimes continue; 21641474Sjulian inoinfo(inp->i_dotdot)->ino_linkcnt++; 21741474Sjulian inoinfo(inp->i_parent)->ino_linkcnt--; 2181558Srgrimes inp->i_dotdot = inp->i_parent; 2191558Srgrimes (void)changeino(inp->i_number, "..", inp->i_parent); 2201558Srgrimes } 2211558Srgrimes /* 2221558Srgrimes * Mark all the directories that can be found from the root. 2231558Srgrimes */ 2241558Srgrimes propagate(); 2251558Srgrimes} 2261558Srgrimes 22723675Speterstatic int 22892839Simppass2check(struct inodesc *idesc) 2291558Srgrimes{ 23092806Sobrien struct direct *dirp = idesc->id_dirp; 23192806Sobrien struct inoinfo *inp; 2321558Srgrimes int n, entrysize, ret = 0; 23398542Smckusick union dinode *dp; 234100935Sphk const char *errmsg; 2351558Srgrimes struct direct proto; 2361558Srgrimes char namebuf[MAXPATHLEN + 1]; 2371558Srgrimes char pathbuf[MAXPATHLEN + 1]; 2381558Srgrimes 2391558Srgrimes /* 2401558Srgrimes * check for "." 2411558Srgrimes */ 2421558Srgrimes if (idesc->id_entryno != 0) 2431558Srgrimes goto chk1; 2441558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 2451558Srgrimes if (dirp->d_ino != idesc->id_number) { 2461558Srgrimes direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 2471558Srgrimes dirp->d_ino = idesc->id_number; 2481558Srgrimes if (reply("FIX") == 1) 2491558Srgrimes ret |= ALTERED; 2501558Srgrimes } 25196483Sphk if (dirp->d_type != DT_DIR) { 2521558Srgrimes direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'"); 2531558Srgrimes dirp->d_type = DT_DIR; 2541558Srgrimes if (reply("FIX") == 1) 2551558Srgrimes ret |= ALTERED; 2561558Srgrimes } 2571558Srgrimes goto chk1; 2581558Srgrimes } 2591558Srgrimes direrror(idesc->id_number, "MISSING '.'"); 2601558Srgrimes proto.d_ino = idesc->id_number; 26196483Sphk proto.d_type = DT_DIR; 2621558Srgrimes proto.d_namlen = 1; 2631558Srgrimes (void)strcpy(proto.d_name, "."); 2641558Srgrimes entrysize = DIRSIZ(0, &proto); 2651558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 2661558Srgrimes pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 2671558Srgrimes dirp->d_name); 2681558Srgrimes } else if (dirp->d_reclen < entrysize) { 2691558Srgrimes pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 2701558Srgrimes } else if (dirp->d_reclen < 2 * entrysize) { 2711558Srgrimes proto.d_reclen = dirp->d_reclen; 27223675Speter memmove(dirp, &proto, (size_t)entrysize); 2731558Srgrimes if (reply("FIX") == 1) 2741558Srgrimes ret |= ALTERED; 2751558Srgrimes } else { 2761558Srgrimes n = dirp->d_reclen - entrysize; 2771558Srgrimes proto.d_reclen = entrysize; 27823675Speter memmove(dirp, &proto, (size_t)entrysize); 2791558Srgrimes idesc->id_entryno++; 28041474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 2811558Srgrimes dirp = (struct direct *)((char *)(dirp) + entrysize); 28223675Speter memset(dirp, 0, (size_t)n); 2831558Srgrimes dirp->d_reclen = n; 2841558Srgrimes if (reply("FIX") == 1) 2851558Srgrimes ret |= ALTERED; 2861558Srgrimes } 2871558Srgrimeschk1: 2881558Srgrimes if (idesc->id_entryno > 1) 2891558Srgrimes goto chk2; 2901558Srgrimes inp = getinoinfo(idesc->id_number); 2911558Srgrimes proto.d_ino = inp->i_parent; 29296483Sphk proto.d_type = DT_DIR; 2931558Srgrimes proto.d_namlen = 2; 2941558Srgrimes (void)strcpy(proto.d_name, ".."); 2951558Srgrimes entrysize = DIRSIZ(0, &proto); 2961558Srgrimes if (idesc->id_entryno == 0) { 2971558Srgrimes n = DIRSIZ(0, dirp); 2981558Srgrimes if (dirp->d_reclen < n + entrysize) 2991558Srgrimes goto chk2; 3001558Srgrimes proto.d_reclen = dirp->d_reclen - n; 3011558Srgrimes dirp->d_reclen = n; 3021558Srgrimes idesc->id_entryno++; 30341474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 3041558Srgrimes dirp = (struct direct *)((char *)(dirp) + n); 30523675Speter memset(dirp, 0, (size_t)proto.d_reclen); 3061558Srgrimes dirp->d_reclen = proto.d_reclen; 3071558Srgrimes } 3081558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { 3091558Srgrimes inp->i_dotdot = dirp->d_ino; 31096483Sphk if (dirp->d_type != DT_DIR) { 3111558Srgrimes direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'"); 3121558Srgrimes dirp->d_type = DT_DIR; 3131558Srgrimes if (reply("FIX") == 1) 3141558Srgrimes ret |= ALTERED; 3151558Srgrimes } 3161558Srgrimes goto chk2; 3171558Srgrimes } 3181558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { 3191558Srgrimes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 3201558Srgrimes pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 3211558Srgrimes dirp->d_name); 3221558Srgrimes inp->i_dotdot = (ino_t)-1; 3231558Srgrimes } else if (dirp->d_reclen < entrysize) { 3241558Srgrimes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 3251558Srgrimes pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 3261558Srgrimes inp->i_dotdot = (ino_t)-1; 3271558Srgrimes } else if (inp->i_parent != 0) { 3281558Srgrimes /* 3291558Srgrimes * We know the parent, so fix now. 3301558Srgrimes */ 3311558Srgrimes inp->i_dotdot = inp->i_parent; 3321558Srgrimes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 3331558Srgrimes proto.d_reclen = dirp->d_reclen; 33423675Speter memmove(dirp, &proto, (size_t)entrysize); 3351558Srgrimes if (reply("FIX") == 1) 3361558Srgrimes ret |= ALTERED; 3371558Srgrimes } 3381558Srgrimes idesc->id_entryno++; 3391558Srgrimes if (dirp->d_ino != 0) 34041474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 3411558Srgrimes return (ret|KEEPON); 3421558Srgrimeschk2: 3431558Srgrimes if (dirp->d_ino == 0) 3441558Srgrimes return (ret|KEEPON); 3451558Srgrimes if (dirp->d_namlen <= 2 && 3461558Srgrimes dirp->d_name[0] == '.' && 3471558Srgrimes idesc->id_entryno >= 2) { 3481558Srgrimes if (dirp->d_namlen == 1) { 3491558Srgrimes direrror(idesc->id_number, "EXTRA '.' ENTRY"); 3501558Srgrimes dirp->d_ino = 0; 3511558Srgrimes if (reply("FIX") == 1) 3521558Srgrimes ret |= ALTERED; 3531558Srgrimes return (KEEPON | ret); 3541558Srgrimes } 3551558Srgrimes if (dirp->d_name[1] == '.') { 3561558Srgrimes direrror(idesc->id_number, "EXTRA '..' ENTRY"); 3571558Srgrimes dirp->d_ino = 0; 3581558Srgrimes if (reply("FIX") == 1) 3591558Srgrimes ret |= ALTERED; 3601558Srgrimes return (KEEPON | ret); 3611558Srgrimes } 3621558Srgrimes } 3631558Srgrimes idesc->id_entryno++; 3641558Srgrimes n = 0; 3651558Srgrimes if (dirp->d_ino > maxino) { 3661558Srgrimes fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE"); 3671558Srgrimes n = reply("REMOVE"); 36896483Sphk } else if (((dirp->d_ino == WINO && dirp->d_type != DT_WHT) || 36923675Speter (dirp->d_ino != WINO && dirp->d_type == DT_WHT))) { 37023675Speter fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY"); 37123675Speter dirp->d_ino = WINO; 37223675Speter dirp->d_type = DT_WHT; 37323675Speter if (reply("FIX") == 1) 37423675Speter ret |= ALTERED; 3751558Srgrimes } else { 3761558Srgrimesagain: 37741474Sjulian switch (inoinfo(dirp->d_ino)->ino_state) { 3781558Srgrimes case USTATE: 3791558Srgrimes if (idesc->id_entryno <= 2) 3801558Srgrimes break; 3811558Srgrimes fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED"); 3821558Srgrimes n = reply("REMOVE"); 3831558Srgrimes break; 3841558Srgrimes 3851558Srgrimes case DCLEAR: 3861558Srgrimes case FCLEAR: 3871558Srgrimes if (idesc->id_entryno <= 2) 3881558Srgrimes break; 38941474Sjulian if (inoinfo(dirp->d_ino)->ino_state == FCLEAR) 3901558Srgrimes errmsg = "DUP/BAD"; 39134266Sjulian else if (!preen && !usedsoftdep) 3921558Srgrimes errmsg = "ZERO LENGTH DIRECTORY"; 3931558Srgrimes else { 3941558Srgrimes n = 1; 3951558Srgrimes break; 3961558Srgrimes } 3971558Srgrimes fileerror(idesc->id_number, dirp->d_ino, errmsg); 3981558Srgrimes if ((n = reply("REMOVE")) == 1) 3991558Srgrimes break; 4001558Srgrimes dp = ginode(dirp->d_ino); 40141474Sjulian inoinfo(dirp->d_ino)->ino_state = 40298542Smckusick (DIP(dp, di_mode) & IFMT) == IFDIR ? DSTATE : FSTATE; 40398542Smckusick inoinfo(dirp->d_ino)->ino_linkcnt = DIP(dp, di_nlink); 4041558Srgrimes goto again; 4051558Srgrimes 4061558Srgrimes case DSTATE: 40741474Sjulian if (inoinfo(idesc->id_number)->ino_state == DFOUND) 40841474Sjulian inoinfo(dirp->d_ino)->ino_state = DFOUND; 4091558Srgrimes /* fall through */ 4101558Srgrimes 4111558Srgrimes case DFOUND: 4121558Srgrimes inp = getinoinfo(dirp->d_ino); 4131558Srgrimes if (inp->i_parent != 0 && idesc->id_entryno > 2) { 4141558Srgrimes getpathname(pathbuf, idesc->id_number, 4151558Srgrimes idesc->id_number); 4161558Srgrimes getpathname(namebuf, dirp->d_ino, dirp->d_ino); 41786512Siedowse pwarn("%s%s%s %s %s\n", pathbuf, 41886512Siedowse (strcmp(pathbuf, "/") == 0 ? "" : "/"), 41986512Siedowse dirp->d_name, 4201558Srgrimes "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", 4211558Srgrimes namebuf); 42274556Smckusick if (cursnapshot != 0) 42374556Smckusick break; 42434266Sjulian if (preen) { 42534266Sjulian printf(" (REMOVED)\n"); 42641474Sjulian n = 1; 42741474Sjulian break; 42834266Sjulian } 42941474Sjulian if ((n = reply("REMOVE")) == 1) 4301558Srgrimes break; 4311558Srgrimes } 4321558Srgrimes if (idesc->id_entryno > 2) 4331558Srgrimes inp->i_parent = idesc->id_number; 4341558Srgrimes /* fall through */ 4351558Srgrimes 4361558Srgrimes case FSTATE: 43796483Sphk if (dirp->d_type != inoinfo(dirp->d_ino)->ino_type) { 4381558Srgrimes fileerror(idesc->id_number, dirp->d_ino, 4391558Srgrimes "BAD TYPE VALUE"); 44041474Sjulian dirp->d_type = inoinfo(dirp->d_ino)->ino_type; 4411558Srgrimes if (reply("FIX") == 1) 4421558Srgrimes ret |= ALTERED; 4431558Srgrimes } 44441474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 4451558Srgrimes break; 4461558Srgrimes 4471558Srgrimes default: 44823675Speter errx(EEXIT, "BAD STATE %d FOR INODE I=%d", 44941474Sjulian inoinfo(dirp->d_ino)->ino_state, dirp->d_ino); 4501558Srgrimes } 4511558Srgrimes } 4521558Srgrimes if (n == 0) 4531558Srgrimes return (ret|KEEPON); 4541558Srgrimes dirp->d_ino = 0; 4551558Srgrimes return (ret|KEEPON|ALTERED); 4561558Srgrimes} 4571558Srgrimes 4581558Srgrimes/* 4591558Srgrimes * Routine to sort disk blocks. 4601558Srgrimes */ 46123675Speterstatic int 46292839Simpblksort(const void *arg1, const void *arg2) 4631558Srgrimes{ 4641558Srgrimes 465100935Sphk return ((*(struct inoinfo * const *)arg1)->i_blks[0] - 466100935Sphk (*(struct inoinfo * const *)arg2)->i_blks[0]); 4671558Srgrimes} 468