pass2.c revision 98542
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 98542 2002-06-21 06:18:05Z mckusick $"; 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> 491558Srgrimes#include <string.h> 5023675Speter 511558Srgrimes#include "fsck.h" 521558Srgrimes 531558Srgrimes#define MINDIRSIZE (sizeof (struct dirtemplate)) 541558Srgrimes 5592839Simpstatic int blksort(const void *, const void *); 5692839Simpstatic int pass2check(struct inodesc *); 571558Srgrimes 587585Sbdevoid 5992839Simppass2(void) 601558Srgrimes{ 6198542Smckusick union dinode *dp; 6292806Sobrien struct inoinfo **inpp, *inp; 631558Srgrimes struct inoinfo **inpend; 641558Srgrimes struct inodesc curino; 6598542Smckusick union dinode dino; 6698542Smckusick int i; 671558Srgrimes char pathbuf[MAXPATHLEN + 1]; 681558Srgrimes 6941474Sjulian switch (inoinfo(ROOTINO)->ino_state) { 701558Srgrimes 711558Srgrimes case USTATE: 721558Srgrimes pfatal("ROOT INODE UNALLOCATED"); 7334266Sjulian if (reply("ALLOCATE") == 0) { 7434266Sjulian ckfini(0); 7523675Speter exit(EEXIT); 7634266Sjulian } 771558Srgrimes if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 7823675Speter errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 791558Srgrimes break; 801558Srgrimes 811558Srgrimes case DCLEAR: 821558Srgrimes pfatal("DUPS/BAD IN ROOT INODE"); 831558Srgrimes if (reply("REALLOCATE")) { 841558Srgrimes freeino(ROOTINO); 851558Srgrimes if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 8623675Speter errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 871558Srgrimes break; 881558Srgrimes } 8934266Sjulian if (reply("CONTINUE") == 0) { 9034266Sjulian ckfini(0); 9123675Speter exit(EEXIT); 9234266Sjulian } 931558Srgrimes break; 941558Srgrimes 951558Srgrimes case FSTATE: 961558Srgrimes case FCLEAR: 971558Srgrimes pfatal("ROOT INODE NOT DIRECTORY"); 981558Srgrimes if (reply("REALLOCATE")) { 991558Srgrimes freeino(ROOTINO); 1001558Srgrimes if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 10123675Speter errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 1021558Srgrimes break; 1031558Srgrimes } 10434266Sjulian if (reply("FIX") == 0) { 10534266Sjulian ckfini(0); 10623675Speter exit(EEXIT); 10734266Sjulian } 1081558Srgrimes dp = ginode(ROOTINO); 10998542Smckusick DIP(dp, di_mode) &= ~IFMT; 11098542Smckusick DIP(dp, di_mode) |= IFDIR; 1111558Srgrimes inodirty(); 1121558Srgrimes break; 1131558Srgrimes 1141558Srgrimes case DSTATE: 1151558Srgrimes break; 1161558Srgrimes 1171558Srgrimes default: 11841474Sjulian errx(EEXIT, "BAD STATE %d FOR ROOT INODE", 11941474Sjulian inoinfo(ROOTINO)->ino_state); 1201558Srgrimes } 12141474Sjulian inoinfo(ROOTINO)->ino_state = DFOUND; 12296483Sphk inoinfo(WINO)->ino_state = FSTATE; 12396483Sphk inoinfo(WINO)->ino_type = DT_WHT; 1241558Srgrimes /* 1251558Srgrimes * Sort the directory list into disk block order. 1261558Srgrimes */ 1271558Srgrimes qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort); 1281558Srgrimes /* 1291558Srgrimes * Check the integrity of each directory. 1301558Srgrimes */ 13123675Speter memset(&curino, 0, sizeof(struct inodesc)); 1321558Srgrimes curino.id_type = DATA; 1331558Srgrimes curino.id_func = pass2check; 1341558Srgrimes inpend = &inpsort[inplast]; 1351558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 13670050Siedowse if (got_siginfo) { 13770050Siedowse printf("%s: phase 2: dir %d of %d (%d%%)\n", cdevname, 13886514Siedowse inpp - inpsort, (int)inplast, 13986514Siedowse (int)((inpp - inpsort) * 100 / inplast)); 14070050Siedowse got_siginfo = 0; 14170050Siedowse } 1421558Srgrimes inp = *inpp; 1431558Srgrimes if (inp->i_isize == 0) 1441558Srgrimes continue; 1451558Srgrimes if (inp->i_isize < MINDIRSIZE) { 1461558Srgrimes direrror(inp->i_number, "DIRECTORY TOO SHORT"); 1471558Srgrimes inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ); 1481558Srgrimes if (reply("FIX") == 1) { 1491558Srgrimes dp = ginode(inp->i_number); 15098542Smckusick DIP(dp, di_size) = inp->i_isize; 1511558Srgrimes inodirty(); 1521558Srgrimes } 1531558Srgrimes } else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) { 1541558Srgrimes getpathname(pathbuf, inp->i_number, inp->i_number); 15534266Sjulian if (usedsoftdep) 15634266Sjulian pfatal("%s %s: LENGTH %d NOT MULTIPLE OF %d", 15734266Sjulian "DIRECTORY", pathbuf, inp->i_isize, 15834266Sjulian DIRBLKSIZ); 15934266Sjulian else 16034266Sjulian pwarn("%s %s: LENGTH %d NOT MULTIPLE OF %d", 16134266Sjulian "DIRECTORY", pathbuf, inp->i_isize, 16234266Sjulian DIRBLKSIZ); 1631558Srgrimes if (preen) 1641558Srgrimes printf(" (ADJUSTED)\n"); 1651558Srgrimes inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ); 1661558Srgrimes if (preen || reply("ADJUST") == 1) { 1671558Srgrimes dp = ginode(inp->i_number); 16898542Smckusick DIP(dp, di_size) = 16998542Smckusick roundup(inp->i_isize, DIRBLKSIZ); 1701558Srgrimes inodirty(); 1711558Srgrimes } 1721558Srgrimes } 17398542Smckusick dp = &dino; 17498542Smckusick memset(dp, 0, sizeof(struct ufs2_dinode)); 17598542Smckusick DIP(dp, di_mode) = IFDIR; 17698542Smckusick DIP(dp, di_size) = inp->i_isize; 17798542Smckusick for (i = 0; 17898542Smckusick i < (inp->i_numblks<NDADDR ? inp->i_numblks : NDADDR); 17998542Smckusick i++) 18098542Smckusick DIP(dp, di_db[i]) = inp->i_blks[i]; 18198542Smckusick if (inp->i_numblks > NDADDR) 18298542Smckusick for (i = 0; i < NIADDR; i++) 18398542Smckusick DIP(dp, di_ib[i]) = inp->i_blks[NDADDR + i]; 1841558Srgrimes curino.id_number = inp->i_number; 1851558Srgrimes curino.id_parent = inp->i_parent; 1861558Srgrimes (void)ckinode(dp, &curino); 1871558Srgrimes } 1881558Srgrimes /* 1891558Srgrimes * Now that the parents of all directories have been found, 1901558Srgrimes * make another pass to verify the value of `..' 1911558Srgrimes */ 1921558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 1931558Srgrimes inp = *inpp; 1941558Srgrimes if (inp->i_parent == 0 || inp->i_isize == 0) 1951558Srgrimes continue; 19641474Sjulian if (inoinfo(inp->i_parent)->ino_state == DFOUND && 19741474Sjulian inoinfo(inp->i_number)->ino_state == DSTATE) 19841474Sjulian inoinfo(inp->i_number)->ino_state = DFOUND; 1991558Srgrimes if (inp->i_dotdot == inp->i_parent || 2001558Srgrimes inp->i_dotdot == (ino_t)-1) 2011558Srgrimes continue; 2021558Srgrimes if (inp->i_dotdot == 0) { 2031558Srgrimes inp->i_dotdot = inp->i_parent; 2041558Srgrimes fileerror(inp->i_parent, inp->i_number, "MISSING '..'"); 2051558Srgrimes if (reply("FIX") == 0) 2061558Srgrimes continue; 2071558Srgrimes (void)makeentry(inp->i_number, inp->i_parent, ".."); 20841474Sjulian inoinfo(inp->i_parent)->ino_linkcnt--; 2091558Srgrimes continue; 2101558Srgrimes } 2111558Srgrimes fileerror(inp->i_parent, inp->i_number, 2121558Srgrimes "BAD INODE NUMBER FOR '..'"); 2131558Srgrimes if (reply("FIX") == 0) 2141558Srgrimes continue; 21541474Sjulian inoinfo(inp->i_dotdot)->ino_linkcnt++; 21641474Sjulian inoinfo(inp->i_parent)->ino_linkcnt--; 2171558Srgrimes inp->i_dotdot = inp->i_parent; 2181558Srgrimes (void)changeino(inp->i_number, "..", inp->i_parent); 2191558Srgrimes } 2201558Srgrimes /* 2211558Srgrimes * Mark all the directories that can be found from the root. 2221558Srgrimes */ 2231558Srgrimes propagate(); 2241558Srgrimes} 2251558Srgrimes 22623675Speterstatic int 22792839Simppass2check(struct inodesc *idesc) 2281558Srgrimes{ 22992806Sobrien struct direct *dirp = idesc->id_dirp; 23092806Sobrien struct inoinfo *inp; 2311558Srgrimes int n, entrysize, ret = 0; 23298542Smckusick union dinode *dp; 2331558Srgrimes char *errmsg; 2341558Srgrimes struct direct proto; 2351558Srgrimes char namebuf[MAXPATHLEN + 1]; 2361558Srgrimes char pathbuf[MAXPATHLEN + 1]; 2371558Srgrimes 2381558Srgrimes /* 2391558Srgrimes * check for "." 2401558Srgrimes */ 2411558Srgrimes if (idesc->id_entryno != 0) 2421558Srgrimes goto chk1; 2431558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 2441558Srgrimes if (dirp->d_ino != idesc->id_number) { 2451558Srgrimes direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 2461558Srgrimes dirp->d_ino = idesc->id_number; 2471558Srgrimes if (reply("FIX") == 1) 2481558Srgrimes ret |= ALTERED; 2491558Srgrimes } 25096483Sphk if (dirp->d_type != DT_DIR) { 2511558Srgrimes direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'"); 2521558Srgrimes dirp->d_type = DT_DIR; 2531558Srgrimes if (reply("FIX") == 1) 2541558Srgrimes ret |= ALTERED; 2551558Srgrimes } 2561558Srgrimes goto chk1; 2571558Srgrimes } 2581558Srgrimes direrror(idesc->id_number, "MISSING '.'"); 2591558Srgrimes proto.d_ino = idesc->id_number; 26096483Sphk proto.d_type = DT_DIR; 2611558Srgrimes proto.d_namlen = 1; 2621558Srgrimes (void)strcpy(proto.d_name, "."); 2631558Srgrimes entrysize = DIRSIZ(0, &proto); 2641558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 2651558Srgrimes pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 2661558Srgrimes dirp->d_name); 2671558Srgrimes } else if (dirp->d_reclen < entrysize) { 2681558Srgrimes pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 2691558Srgrimes } else if (dirp->d_reclen < 2 * entrysize) { 2701558Srgrimes proto.d_reclen = dirp->d_reclen; 27123675Speter memmove(dirp, &proto, (size_t)entrysize); 2721558Srgrimes if (reply("FIX") == 1) 2731558Srgrimes ret |= ALTERED; 2741558Srgrimes } else { 2751558Srgrimes n = dirp->d_reclen - entrysize; 2761558Srgrimes proto.d_reclen = entrysize; 27723675Speter memmove(dirp, &proto, (size_t)entrysize); 2781558Srgrimes idesc->id_entryno++; 27941474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 2801558Srgrimes dirp = (struct direct *)((char *)(dirp) + entrysize); 28123675Speter memset(dirp, 0, (size_t)n); 2821558Srgrimes dirp->d_reclen = n; 2831558Srgrimes if (reply("FIX") == 1) 2841558Srgrimes ret |= ALTERED; 2851558Srgrimes } 2861558Srgrimeschk1: 2871558Srgrimes if (idesc->id_entryno > 1) 2881558Srgrimes goto chk2; 2891558Srgrimes inp = getinoinfo(idesc->id_number); 2901558Srgrimes proto.d_ino = inp->i_parent; 29196483Sphk proto.d_type = DT_DIR; 2921558Srgrimes proto.d_namlen = 2; 2931558Srgrimes (void)strcpy(proto.d_name, ".."); 2941558Srgrimes entrysize = DIRSIZ(0, &proto); 2951558Srgrimes if (idesc->id_entryno == 0) { 2961558Srgrimes n = DIRSIZ(0, dirp); 2971558Srgrimes if (dirp->d_reclen < n + entrysize) 2981558Srgrimes goto chk2; 2991558Srgrimes proto.d_reclen = dirp->d_reclen - n; 3001558Srgrimes dirp->d_reclen = n; 3011558Srgrimes idesc->id_entryno++; 30241474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 3031558Srgrimes dirp = (struct direct *)((char *)(dirp) + n); 30423675Speter memset(dirp, 0, (size_t)proto.d_reclen); 3051558Srgrimes dirp->d_reclen = proto.d_reclen; 3061558Srgrimes } 3071558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { 3081558Srgrimes inp->i_dotdot = dirp->d_ino; 30996483Sphk if (dirp->d_type != DT_DIR) { 3101558Srgrimes direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'"); 3111558Srgrimes dirp->d_type = DT_DIR; 3121558Srgrimes if (reply("FIX") == 1) 3131558Srgrimes ret |= ALTERED; 3141558Srgrimes } 3151558Srgrimes goto chk2; 3161558Srgrimes } 3171558Srgrimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { 3181558Srgrimes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 3191558Srgrimes pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 3201558Srgrimes dirp->d_name); 3211558Srgrimes inp->i_dotdot = (ino_t)-1; 3221558Srgrimes } else if (dirp->d_reclen < entrysize) { 3231558Srgrimes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 3241558Srgrimes pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 3251558Srgrimes inp->i_dotdot = (ino_t)-1; 3261558Srgrimes } else if (inp->i_parent != 0) { 3271558Srgrimes /* 3281558Srgrimes * We know the parent, so fix now. 3291558Srgrimes */ 3301558Srgrimes inp->i_dotdot = inp->i_parent; 3311558Srgrimes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 3321558Srgrimes proto.d_reclen = dirp->d_reclen; 33323675Speter memmove(dirp, &proto, (size_t)entrysize); 3341558Srgrimes if (reply("FIX") == 1) 3351558Srgrimes ret |= ALTERED; 3361558Srgrimes } 3371558Srgrimes idesc->id_entryno++; 3381558Srgrimes if (dirp->d_ino != 0) 33941474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 3401558Srgrimes return (ret|KEEPON); 3411558Srgrimeschk2: 3421558Srgrimes if (dirp->d_ino == 0) 3431558Srgrimes return (ret|KEEPON); 3441558Srgrimes if (dirp->d_namlen <= 2 && 3451558Srgrimes dirp->d_name[0] == '.' && 3461558Srgrimes idesc->id_entryno >= 2) { 3471558Srgrimes if (dirp->d_namlen == 1) { 3481558Srgrimes direrror(idesc->id_number, "EXTRA '.' ENTRY"); 3491558Srgrimes dirp->d_ino = 0; 3501558Srgrimes if (reply("FIX") == 1) 3511558Srgrimes ret |= ALTERED; 3521558Srgrimes return (KEEPON | ret); 3531558Srgrimes } 3541558Srgrimes if (dirp->d_name[1] == '.') { 3551558Srgrimes direrror(idesc->id_number, "EXTRA '..' ENTRY"); 3561558Srgrimes dirp->d_ino = 0; 3571558Srgrimes if (reply("FIX") == 1) 3581558Srgrimes ret |= ALTERED; 3591558Srgrimes return (KEEPON | ret); 3601558Srgrimes } 3611558Srgrimes } 3621558Srgrimes idesc->id_entryno++; 3631558Srgrimes n = 0; 3641558Srgrimes if (dirp->d_ino > maxino) { 3651558Srgrimes fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE"); 3661558Srgrimes n = reply("REMOVE"); 36796483Sphk } else if (((dirp->d_ino == WINO && dirp->d_type != DT_WHT) || 36823675Speter (dirp->d_ino != WINO && dirp->d_type == DT_WHT))) { 36923675Speter fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY"); 37023675Speter dirp->d_ino = WINO; 37123675Speter dirp->d_type = DT_WHT; 37223675Speter if (reply("FIX") == 1) 37323675Speter ret |= ALTERED; 3741558Srgrimes } else { 3751558Srgrimesagain: 37641474Sjulian switch (inoinfo(dirp->d_ino)->ino_state) { 3771558Srgrimes case USTATE: 3781558Srgrimes if (idesc->id_entryno <= 2) 3791558Srgrimes break; 3801558Srgrimes fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED"); 3811558Srgrimes n = reply("REMOVE"); 3821558Srgrimes break; 3831558Srgrimes 3841558Srgrimes case DCLEAR: 3851558Srgrimes case FCLEAR: 3861558Srgrimes if (idesc->id_entryno <= 2) 3871558Srgrimes break; 38841474Sjulian if (inoinfo(dirp->d_ino)->ino_state == FCLEAR) 3891558Srgrimes errmsg = "DUP/BAD"; 39034266Sjulian else if (!preen && !usedsoftdep) 3911558Srgrimes errmsg = "ZERO LENGTH DIRECTORY"; 3921558Srgrimes else { 3931558Srgrimes n = 1; 3941558Srgrimes break; 3951558Srgrimes } 3961558Srgrimes fileerror(idesc->id_number, dirp->d_ino, errmsg); 3971558Srgrimes if ((n = reply("REMOVE")) == 1) 3981558Srgrimes break; 3991558Srgrimes dp = ginode(dirp->d_ino); 40041474Sjulian inoinfo(dirp->d_ino)->ino_state = 40198542Smckusick (DIP(dp, di_mode) & IFMT) == IFDIR ? DSTATE : FSTATE; 40298542Smckusick inoinfo(dirp->d_ino)->ino_linkcnt = DIP(dp, di_nlink); 4031558Srgrimes goto again; 4041558Srgrimes 4051558Srgrimes case DSTATE: 40641474Sjulian if (inoinfo(idesc->id_number)->ino_state == DFOUND) 40741474Sjulian inoinfo(dirp->d_ino)->ino_state = DFOUND; 4081558Srgrimes /* fall through */ 4091558Srgrimes 4101558Srgrimes case DFOUND: 4111558Srgrimes inp = getinoinfo(dirp->d_ino); 4121558Srgrimes if (inp->i_parent != 0 && idesc->id_entryno > 2) { 4131558Srgrimes getpathname(pathbuf, idesc->id_number, 4141558Srgrimes idesc->id_number); 4151558Srgrimes getpathname(namebuf, dirp->d_ino, dirp->d_ino); 41686512Siedowse pwarn("%s%s%s %s %s\n", pathbuf, 41786512Siedowse (strcmp(pathbuf, "/") == 0 ? "" : "/"), 41886512Siedowse dirp->d_name, 4191558Srgrimes "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", 4201558Srgrimes namebuf); 42174556Smckusick if (cursnapshot != 0) 42274556Smckusick break; 42334266Sjulian if (preen) { 42434266Sjulian printf(" (REMOVED)\n"); 42541474Sjulian n = 1; 42641474Sjulian break; 42734266Sjulian } 42841474Sjulian if ((n = reply("REMOVE")) == 1) 4291558Srgrimes break; 4301558Srgrimes } 4311558Srgrimes if (idesc->id_entryno > 2) 4321558Srgrimes inp->i_parent = idesc->id_number; 4331558Srgrimes /* fall through */ 4341558Srgrimes 4351558Srgrimes case FSTATE: 43696483Sphk if (dirp->d_type != inoinfo(dirp->d_ino)->ino_type) { 4371558Srgrimes fileerror(idesc->id_number, dirp->d_ino, 4381558Srgrimes "BAD TYPE VALUE"); 43941474Sjulian dirp->d_type = inoinfo(dirp->d_ino)->ino_type; 4401558Srgrimes if (reply("FIX") == 1) 4411558Srgrimes ret |= ALTERED; 4421558Srgrimes } 44341474Sjulian inoinfo(dirp->d_ino)->ino_linkcnt--; 4441558Srgrimes break; 4451558Srgrimes 4461558Srgrimes default: 44723675Speter errx(EEXIT, "BAD STATE %d FOR INODE I=%d", 44841474Sjulian inoinfo(dirp->d_ino)->ino_state, dirp->d_ino); 4491558Srgrimes } 4501558Srgrimes } 4511558Srgrimes if (n == 0) 4521558Srgrimes return (ret|KEEPON); 4531558Srgrimes dirp->d_ino = 0; 4541558Srgrimes return (ret|KEEPON|ALTERED); 4551558Srgrimes} 4561558Srgrimes 4571558Srgrimes/* 4581558Srgrimes * Routine to sort disk blocks. 4591558Srgrimes */ 46023675Speterstatic int 46192839Simpblksort(const void *arg1, const void *arg2) 4621558Srgrimes{ 4631558Srgrimes 46423675Speter return ((*(struct inoinfo **)arg1)->i_blks[0] - 46523675Speter (*(struct inoinfo **)arg2)->i_blks[0]); 4661558Srgrimes} 467