pass2.c revision 86512
1215116Sdes/* 257429Smarkm * Copyright (c) 1980, 1986, 1993 357429Smarkm * The Regents of the University of California. All rights reserved. 457429Smarkm * 557429Smarkm * Redistribution and use in source and binary forms, with or without 657429Smarkm * modification, are permitted provided that the following conditions 757429Smarkm * are met: 857429Smarkm * 1. Redistributions of source code must retain the above copyright 960573Skris * notice, this list of conditions and the following disclaimer. 1065668Skris * 2. Redistributions in binary form must reproduce the above copyright 1165668Skris * notice, this list of conditions and the following disclaimer in the 1265668Skris * documentation and/or other materials provided with the distribution. 1365668Skris * 3. All advertising materials mentioning features or use of this software 1465668Skris * must display the following acknowledgement: 1565668Skris * This product includes software developed by the University of 1660573Skris * California, Berkeley and its contributors. 1792559Sdes * 4. Neither the name of the University nor the names of its contributors 1865668Skris * may be used to endorse or promote products derived from this software 1965668Skris * without specific prior written permission. 2065668Skris * 2165668Skris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2265668Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2365668Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2465668Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2565668Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2665668Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2765668Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2865668Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2965668Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3065668Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3165668Skris * SUCH DAMAGE. 3265668Skris */ 3365668Skris 3465668Skris#ifndef lint 3565668Skris#if 0 3665668Skrisstatic const char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95"; 3765668Skris#endif 3865668Skrisstatic const char rcsid[] = 3965668Skris "$FreeBSD: head/sbin/fsck_ffs/pass2.c 86512 2001-11-17 22:46:36Z iedowse $"; 4057429Smarkm#endif /* not lint */ 4157429Smarkm 4257429Smarkm#include <sys/param.h> 4357429Smarkm 44162856Sdes#include <ufs/ufs/dinode.h> 45162856Sdes#include <ufs/ufs/dir.h> 46162856Sdes#include <ufs/ffs/fs.h> 47162856Sdes 48162856Sdes#include <err.h> 49162856Sdes#include <string.h> 50162856Sdes 51162856Sdes#include "fsck.h" 52162856Sdes 53162856Sdes#define MINDIRSIZE (sizeof (struct dirtemplate)) 54162856Sdes 55162856Sdesstatic int blksort __P((const void *, const void *)); 56204917Sdesstatic int pass2check __P((struct inodesc *)); 57162856Sdes 58162856Sdesvoid 59162856Sdespass2() 60162856Sdes{ 61162856Sdes register struct dinode *dp; 62162856Sdes register struct inoinfo **inpp, *inp; 63162856Sdes struct inoinfo **inpend; 64162856Sdes struct inodesc curino; 65181111Sdes struct dinode dino; 66162856Sdes char pathbuf[MAXPATHLEN + 1]; 6757429Smarkm 6876262Sgreen switch (inoinfo(ROOTINO)->ino_state) { 6976262Sgreen 7057429Smarkm case USTATE: 7176262Sgreen pfatal("ROOT INODE UNALLOCATED"); 7276262Sgreen if (reply("ALLOCATE") == 0) { 73162856Sdes ckfini(0); 7457429Smarkm exit(EEXIT); 7557429Smarkm } 7676262Sgreen if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 7765668Skris errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 7865668Skris break; 7992559Sdes 8065668Skris case DCLEAR: 8192559Sdes pfatal("DUPS/BAD IN ROOT INODE"); 8257429Smarkm if (reply("REALLOCATE")) { 8357429Smarkm freeino(ROOTINO); 8457429Smarkm if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 8557429Smarkm errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 8657429Smarkm break; 8792559Sdes } 8857429Smarkm if (reply("CONTINUE") == 0) { 8957429Smarkm ckfini(0); 9057429Smarkm exit(EEXIT); 9192559Sdes } 9257429Smarkm break; 93137019Sdes 9457429Smarkm case FSTATE: 9557429Smarkm case FCLEAR: 9657429Smarkm pfatal("ROOT INODE NOT DIRECTORY"); 9792559Sdes if (reply("REALLOCATE")) { 9857429Smarkm freeino(ROOTINO); 9976262Sgreen if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 10057429Smarkm errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 10157429Smarkm break; 10292559Sdes } 10357429Smarkm if (reply("FIX") == 0) { 10457429Smarkm ckfini(0); 10557429Smarkm exit(EEXIT); 10657429Smarkm } 10757429Smarkm dp = ginode(ROOTINO); 10857429Smarkm dp->di_mode &= ~IFMT; 10957429Smarkm dp->di_mode |= IFDIR; 11057429Smarkm inodirty(); 11160573Skris break; 11260573Skris 11360573Skris case DSTATE: 11457429Smarkm break; 11557429Smarkm 116162856Sdes default: 117215116Sdes errx(EEXIT, "BAD STATE %d FOR ROOT INODE", 11892559Sdes inoinfo(ROOTINO)->ino_state); 119162856Sdes } 120215116Sdes inoinfo(ROOTINO)->ino_state = DFOUND; 121162856Sdes if (newinofmt) { 122162856Sdes inoinfo(WINO)->ino_state = FSTATE; 12357429Smarkm inoinfo(WINO)->ino_type = DT_WHT; 124162856Sdes } 125162856Sdes /* 126162856Sdes * Sort the directory list into disk block order. 127162856Sdes */ 12857429Smarkm qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort); 12957429Smarkm /* 13057429Smarkm * Check the integrity of each directory. 13157429Smarkm */ 13257429Smarkm memset(&curino, 0, sizeof(struct inodesc)); 13357429Smarkm curino.id_type = DATA; 13457429Smarkm curino.id_func = pass2check; 13557429Smarkm dp = &dino; 13692559Sdes inpend = &inpsort[inplast]; 13792559Sdes for (inpp = inpsort; inpp < inpend; inpp++) { 13892559Sdes if (got_siginfo) { 13992559Sdes printf("%s: phase 2: dir %d of %d (%d%%)\n", cdevname, 14092559Sdes inpp - inpsort, inplast, (inpp - inpsort) * 100 / 141149753Sdes inplast); 142149753Sdes got_siginfo = 0; 143149753Sdes } 14492559Sdes inp = *inpp; 14592559Sdes if (inp->i_isize == 0) 14692559Sdes continue; 14792559Sdes if (inp->i_isize < MINDIRSIZE) { 14892559Sdes direrror(inp->i_number, "DIRECTORY TOO SHORT"); 14992559Sdes inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ); 15092559Sdes if (reply("FIX") == 1) { 15192559Sdes dp = ginode(inp->i_number); 15292559Sdes dp->di_size = inp->i_isize; 15392559Sdes inodirty(); 15492559Sdes dp = &dino; 155162856Sdes } 15692559Sdes } else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) { 15792559Sdes getpathname(pathbuf, inp->i_number, inp->i_number); 15892559Sdes if (usedsoftdep) 15992559Sdes pfatal("%s %s: LENGTH %d NOT MULTIPLE OF %d", 16092559Sdes "DIRECTORY", pathbuf, inp->i_isize, 16192559Sdes DIRBLKSIZ); 16292559Sdes else 16376262Sgreen pwarn("%s %s: LENGTH %d NOT MULTIPLE OF %d", 16498941Sdes "DIRECTORY", pathbuf, inp->i_isize, 16576262Sgreen DIRBLKSIZ); 16692559Sdes if (preen) 16792559Sdes printf(" (ADJUSTED)\n"); 16876262Sgreen inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ); 169181111Sdes if (preen || reply("ADJUST") == 1) { 170181111Sdes dp = ginode(inp->i_number); 171181111Sdes dp->di_size = roundup(inp->i_isize, DIRBLKSIZ); 172181111Sdes inodirty(); 17392559Sdes dp = &dino; 17457429Smarkm } 17560573Skris } 176157019Sdes memset(&dino, 0, sizeof(struct dinode)); 17760573Skris dino.di_mode = IFDIR; 17860573Skris dp->di_size = inp->i_isize; 17992559Sdes memmove(&dp->di_db[0], &inp->i_blks[0], (size_t)inp->i_numblks); 180137019Sdes curino.id_number = inp->i_number; 181157019Sdes curino.id_parent = inp->i_parent; 18260573Skris (void)ckinode(dp, &curino); 18360573Skris } 18492559Sdes /* 18592559Sdes * Now that the parents of all directories have been found, 186157019Sdes * make another pass to verify the value of `..' 18760573Skris */ 18860573Skris for (inpp = inpsort; inpp < inpend; inpp++) { 18960573Skris inp = *inpp; 19060573Skris if (inp->i_parent == 0 || inp->i_isize == 0) 19160573Skris continue; 19257429Smarkm if (inoinfo(inp->i_parent)->ino_state == DFOUND && 193157019Sdes inoinfo(inp->i_number)->ino_state == DSTATE) 194157019Sdes inoinfo(inp->i_number)->ino_state = DFOUND; 195157019Sdes if (inp->i_dotdot == inp->i_parent || 196157019Sdes inp->i_dotdot == (ino_t)-1) 197157019Sdes continue; 198157019Sdes if (inp->i_dotdot == 0) { 199157019Sdes inp->i_dotdot = inp->i_parent; 200157019Sdes fileerror(inp->i_parent, inp->i_number, "MISSING '..'"); 201157019Sdes if (reply("FIX") == 0) 202157019Sdes continue; 203157019Sdes (void)makeentry(inp->i_number, inp->i_parent, ".."); 204162856Sdes inoinfo(inp->i_parent)->ino_linkcnt--; 205157019Sdes continue; 206157019Sdes } 207157019Sdes fileerror(inp->i_parent, inp->i_number, 208157019Sdes "BAD INODE NUMBER FOR '..'"); 209157019Sdes if (reply("FIX") == 0) 210157019Sdes continue; 211157019Sdes inoinfo(inp->i_dotdot)->ino_linkcnt++; 212157019Sdes inoinfo(inp->i_parent)->ino_linkcnt--; 213157019Sdes inp->i_dotdot = inp->i_parent; 214157019Sdes (void)changeino(inp->i_number, "..", inp->i_parent); 215157019Sdes } 216157019Sdes /* 217157019Sdes * Mark all the directories that can be found from the root. 218157019Sdes */ 219157019Sdes propagate(); 22060573Skris} 22160573Skris 22260573Skrisstatic int 22392559Sdespass2check(idesc) 22469587Sgreen struct inodesc *idesc; 225181111Sdes{ 22660573Skris register struct direct *dirp = idesc->id_dirp; 22760573Skris register struct inoinfo *inp; 22876262Sgreen int n, entrysize, ret = 0; 22976262Sgreen struct dinode *dp; 23076262Sgreen char *errmsg; 23176262Sgreen struct direct proto; 232204917Sdes char namebuf[MAXPATHLEN + 1]; 233204917Sdes char pathbuf[MAXPATHLEN + 1]; 234204917Sdes 235204917Sdes /* 236204917Sdes * If converting, set directory entry type. 237204917Sdes */ 23860573Skris if (doinglevel2 && dirp->d_ino > 0 && dirp->d_ino < maxino) { 23960573Skris dirp->d_type = inoinfo(dirp->d_ino)->ino_type; 24060573Skris ret |= ALTERED; 24160573Skris } 24260573Skris /* 24360573Skris * check for "." 24469587Sgreen */ 245181111Sdes if (idesc->id_entryno != 0) 246124207Sdes goto chk1; 247181111Sdes if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 24874500Sgreen if (dirp->d_ino != idesc->id_number) { 24969587Sgreen direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 25069587Sgreen dirp->d_ino = idesc->id_number; 25169587Sgreen if (reply("FIX") == 1) 25269587Sgreen ret |= ALTERED; 25369587Sgreen } 25469587Sgreen if (newinofmt && dirp->d_type != DT_DIR) { 25569587Sgreen direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'"); 25669587Sgreen dirp->d_type = DT_DIR; 25769587Sgreen if (reply("FIX") == 1) 25860573Skris ret |= ALTERED; 25960573Skris } 26060573Skris goto chk1; 26157429Smarkm } 26257429Smarkm direrror(idesc->id_number, "MISSING '.'"); 26357429Smarkm proto.d_ino = idesc->id_number; 26492559Sdes if (newinofmt) 26560573Skris proto.d_type = DT_DIR; 26699063Sdes else 26757429Smarkm proto.d_type = 0; 268137019Sdes proto.d_namlen = 1; 269137019Sdes (void)strcpy(proto.d_name, "."); 27057429Smarkm# if BYTE_ORDER == LITTLE_ENDIAN 27157429Smarkm if (!newinofmt) { 27257429Smarkm u_char tmp; 27357429Smarkm 27457429Smarkm tmp = proto.d_type; 275162856Sdes proto.d_type = proto.d_namlen; 27657429Smarkm proto.d_namlen = tmp; 27792559Sdes } 27857429Smarkm# endif 27957429Smarkm entrysize = DIRSIZ(0, &proto); 28057429Smarkm if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 28192559Sdes pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 28257429Smarkm dirp->d_name); 283137019Sdes } else if (dirp->d_reclen < entrysize) { 28457429Smarkm pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 28557429Smarkm } else if (dirp->d_reclen < 2 * entrysize) { 286137019Sdes proto.d_reclen = dirp->d_reclen; 28757429Smarkm memmove(dirp, &proto, (size_t)entrysize); 28857429Smarkm if (reply("FIX") == 1) 28999063Sdes ret |= ALTERED; 29099063Sdes } else { 29199063Sdes n = dirp->d_reclen - entrysize; 292162856Sdes proto.d_reclen = entrysize; 293162856Sdes memmove(dirp, &proto, (size_t)entrysize); 294120489Sjoe idesc->id_entryno++; 29569587Sgreen inoinfo(dirp->d_ino)->ino_linkcnt--; 29657429Smarkm dirp = (struct direct *)((char *)(dirp) + entrysize); 29792559Sdes memset(dirp, 0, (size_t)n); 29857429Smarkm dirp->d_reclen = n; 29992559Sdes if (reply("FIX") == 1) 300162856Sdes ret |= ALTERED; 30157429Smarkm } 30257429Smarkmchk1: 30360573Skris if (idesc->id_entryno > 1) 304192595Sdes goto chk2; 30592559Sdes inp = getinoinfo(idesc->id_number); 30692559Sdes proto.d_ino = inp->i_parent; 30792559Sdes if (newinofmt) 308181111Sdes proto.d_type = DT_DIR; 30957429Smarkm else 31057429Smarkm proto.d_type = 0; 31160573Skris proto.d_namlen = 2; 31260573Skris (void)strcpy(proto.d_name, ".."); 31360573Skris# if BYTE_ORDER == LITTLE_ENDIAN 31460573Skris if (!newinofmt) { 31560573Skris u_char tmp; 31657429Smarkm 317124207Sdes tmp = proto.d_type; 31860573Skris proto.d_type = proto.d_namlen; 31960573Skris proto.d_namlen = tmp; 32092559Sdes } 32192559Sdes# endif 32292559Sdes entrysize = DIRSIZ(0, &proto); 323157019Sdes if (idesc->id_entryno == 0) { 324181111Sdes n = DIRSIZ(0, dirp); 325181111Sdes if (dirp->d_reclen < n + entrysize) 32665668Skris goto chk2; 327157019Sdes proto.d_reclen = dirp->d_reclen - n; 328181111Sdes dirp->d_reclen = n; 329181111Sdes idesc->id_entryno++; 330204917Sdes inoinfo(dirp->d_ino)->ino_linkcnt--; 331204917Sdes dirp = (struct direct *)((char *)(dirp) + n); 332204917Sdes memset(dirp, 0, (size_t)proto.d_reclen); 333215116Sdes dirp->d_reclen = proto.d_reclen; 334204917Sdes } 335181111Sdes if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { 33657429Smarkm inp->i_dotdot = dirp->d_ino; 33792559Sdes if (newinofmt && dirp->d_type != DT_DIR) { 33857429Smarkm direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'"); 33992559Sdes dirp->d_type = DT_DIR; 34092559Sdes if (reply("FIX") == 1) 34192559Sdes ret |= ALTERED; 34292559Sdes } 343137019Sdes goto chk2; 344137019Sdes } 34592559Sdes if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { 34692559Sdes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 34792559Sdes pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 34892559Sdes dirp->d_name); 34992559Sdes inp->i_dotdot = (ino_t)-1; 35092559Sdes } else if (dirp->d_reclen < entrysize) { 35192559Sdes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 35292559Sdes pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 35392559Sdes inp->i_dotdot = (ino_t)-1; 35492559Sdes } else if (inp->i_parent != 0) { 35592559Sdes /* 35692559Sdes * We know the parent, so fix now. 35792559Sdes */ 35860573Skris inp->i_dotdot = inp->i_parent; 35992559Sdes fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 36060573Skris proto.d_reclen = dirp->d_reclen; 36192559Sdes memmove(dirp, &proto, (size_t)entrysize); 36292559Sdes if (reply("FIX") == 1) 36392559Sdes ret |= ALTERED; 36492559Sdes } 36592559Sdes idesc->id_entryno++; 36692559Sdes if (dirp->d_ino != 0) 36792559Sdes inoinfo(dirp->d_ino)->ino_linkcnt--; 36892559Sdes return (ret|KEEPON); 36992559Sdeschk2: 37060573Skris if (dirp->d_ino == 0) 37157429Smarkm return (ret|KEEPON); 37260573Skris if (dirp->d_namlen <= 2 && 37392559Sdes dirp->d_name[0] == '.' && 37460573Skris idesc->id_entryno >= 2) { 37557429Smarkm if (dirp->d_namlen == 1) { 376204917Sdes direrror(idesc->id_number, "EXTRA '.' ENTRY"); 377204917Sdes dirp->d_ino = 0; 37892559Sdes if (reply("FIX") == 1) 37992559Sdes ret |= ALTERED; 38092559Sdes return (KEEPON | ret); 38192559Sdes } 38292559Sdes if (dirp->d_name[1] == '.') { 38360573Skris direrror(idesc->id_number, "EXTRA '..' ENTRY"); 38457429Smarkm dirp->d_ino = 0; 38560573Skris if (reply("FIX") == 1) 38660573Skris ret |= ALTERED; 38792559Sdes return (KEEPON | ret); 38860573Skris } 38992559Sdes } 390137019Sdes idesc->id_entryno++; 391181111Sdes n = 0; 39276262Sgreen if (dirp->d_ino > maxino) { 39392559Sdes fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE"); 39492559Sdes n = reply("REMOVE"); 39592559Sdes } else if (newinofmt && 396137019Sdes ((dirp->d_ino == WINO && dirp->d_type != DT_WHT) || 39792559Sdes (dirp->d_ino != WINO && dirp->d_type == DT_WHT))) { 39892559Sdes fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY"); 39992559Sdes dirp->d_ino = WINO; 400124207Sdes dirp->d_type = DT_WHT; 40176262Sgreen if (reply("FIX") == 1) 40276262Sgreen ret |= ALTERED; 40360573Skris } else { 40460573Skrisagain: 40560573Skris switch (inoinfo(dirp->d_ino)->ino_state) { 40660573Skris case USTATE: 40760573Skris if (idesc->id_entryno <= 2) 40860573Skris break; 40960573Skris fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED"); 41060573Skris n = reply("REMOVE"); 41160573Skris break; 41260573Skris 413192595Sdes case DCLEAR: 414192595Sdes case FCLEAR: 415192595Sdes if (idesc->id_entryno <= 2) 416192595Sdes break; 417181111Sdes if (inoinfo(dirp->d_ino)->ino_state == FCLEAR) 418181111Sdes errmsg = "DUP/BAD"; 419181111Sdes else if (!preen && !usedsoftdep) 420181111Sdes errmsg = "ZERO LENGTH DIRECTORY"; 421181111Sdes else { 422181111Sdes n = 1; 423181111Sdes break; 424181111Sdes } 425181111Sdes fileerror(idesc->id_number, dirp->d_ino, errmsg); 42692559Sdes if ((n = reply("REMOVE")) == 1) 42792559Sdes break; 42857429Smarkm dp = ginode(dirp->d_ino); 42957429Smarkm inoinfo(dirp->d_ino)->ino_state = 43092559Sdes (dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE; 43192559Sdes inoinfo(dirp->d_ino)->ino_linkcnt = dp->di_nlink; 43292559Sdes goto again; 433137019Sdes 43492559Sdes case DSTATE: 43592559Sdes if (inoinfo(idesc->id_number)->ino_state == DFOUND) 43692559Sdes inoinfo(dirp->d_ino)->ino_state = DFOUND; 43792559Sdes /* fall through */ 43892559Sdes 43992559Sdes case DFOUND: 44057429Smarkm inp = getinoinfo(dirp->d_ino); 44192559Sdes if (inp->i_parent != 0 && idesc->id_entryno > 2) { 44292559Sdes getpathname(pathbuf, idesc->id_number, 44392559Sdes idesc->id_number); 44492559Sdes getpathname(namebuf, dirp->d_ino, dirp->d_ino); 44592559Sdes pwarn("%s%s%s %s %s\n", pathbuf, 44692559Sdes (strcmp(pathbuf, "/") == 0 ? "" : "/"), 447137019Sdes dirp->d_name, 44892559Sdes "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", 44992559Sdes namebuf); 45092559Sdes if (cursnapshot != 0) 45192559Sdes break; 45292559Sdes if (preen) { 45392559Sdes printf(" (REMOVED)\n"); 45492559Sdes n = 1; 45592559Sdes break; 45692559Sdes } 45792559Sdes if ((n = reply("REMOVE")) == 1) 45892559Sdes break; 45992559Sdes } 460137019Sdes if (idesc->id_entryno > 2) 46192559Sdes inp->i_parent = idesc->id_number; 46292559Sdes /* fall through */ 46392559Sdes 46492559Sdes case FSTATE: 46592559Sdes if (newinofmt && 46692559Sdes dirp->d_type != inoinfo(dirp->d_ino)->ino_type) { 46792559Sdes fileerror(idesc->id_number, dirp->d_ino, 46892559Sdes "BAD TYPE VALUE"); 46992559Sdes dirp->d_type = inoinfo(dirp->d_ino)->ino_type; 47092559Sdes if (reply("FIX") == 1) 47192559Sdes ret |= ALTERED; 47292559Sdes } 47392559Sdes inoinfo(dirp->d_ino)->ino_linkcnt--; 47492559Sdes break; 47592559Sdes 47692559Sdes default: 47792559Sdes errx(EEXIT, "BAD STATE %d FOR INODE I=%d", 47892559Sdes inoinfo(dirp->d_ino)->ino_state, dirp->d_ino); 47992559Sdes } 48092559Sdes } 48192559Sdes if (n == 0) 48292559Sdes return (ret|KEEPON); 48392559Sdes dirp->d_ino = 0; 48492559Sdes return (ret|KEEPON|ALTERED); 48592559Sdes} 48692559Sdes 48792559Sdes/* 48892559Sdes * Routine to sort disk blocks. 48992559Sdes */ 49092559Sdesstatic int 49192559Sdesblksort(arg1, arg2) 49292559Sdes const void *arg1, *arg2; 49392559Sdes{ 49492559Sdes 495113911Sdes return ((*(struct inoinfo **)arg1)->i_blks[0] - 49692559Sdes (*(struct inoinfo **)arg2)->i_blks[0]); 49792559Sdes} 49892559Sdes