pass2.c revision 96483
133965Sjdp/* 278828Sobrien * Copyright (c) 1980, 1986, 1993 3218822Sdim * The Regents of the University of California. All rights reserved. 433965Sjdp * 533965Sjdp * Redistribution and use in source and binary forms, with or without 633965Sjdp * modification, are permitted provided that the following conditions 733965Sjdp * are met: 833965Sjdp * 1. Redistributions of source code must retain the above copyright 933965Sjdp * notice, this list of conditions and the following disclaimer. 1033965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1133965Sjdp * notice, this list of conditions and the following disclaimer in the 1233965Sjdp * documentation and/or other materials provided with the distribution. 1333965Sjdp * 3. All advertising materials mentioning features or use of this software 1433965Sjdp * must display the following acknowledgement: 1533965Sjdp * This product includes software developed by the University of 1633965Sjdp * California, Berkeley and its contributors. 1733965Sjdp * 4. Neither the name of the University nor the names of its contributors 1833965Sjdp * may be used to endorse or promote products derived from this software 1933965Sjdp * without specific prior written permission. 20218822Sdim * 21218822Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2233965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2333965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2433965Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2577298Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26218822Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27218822Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28218822Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29218822Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30218822Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31218822Sdim * SUCH DAMAGE. 32218822Sdim */ 33218822Sdim 34218822Sdim#ifndef lint 35218822Sdim#if 0 36218822Sdimstatic const char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95"; 37218822Sdim#endif 3833965Sjdpstatic const char rcsid[] = 3933965Sjdp "$FreeBSD: head/sbin/fsck_ffs/pass2.c 96483 2002-05-12 23:44:15Z phk $"; 4033965Sjdp#endif /* not lint */ 4133965Sjdp 4233965Sjdp#include <sys/param.h> 4333965Sjdp 4433965Sjdp#include <ufs/ufs/dinode.h> 4533965Sjdp#include <ufs/ufs/dir.h> 4633965Sjdp#include <ufs/ffs/fs.h> 4733965Sjdp 4833965Sjdp#include <err.h> 4989857Sobrien#include <string.h> 5033965Sjdp 5133965Sjdp#include "fsck.h" 5233965Sjdp 5333965Sjdp#define MINDIRSIZE (sizeof (struct dirtemplate)) 5489857Sobrien 5589857Sobrienstatic int blksort(const void *, const void *); 5689857Sobrienstatic int pass2check(struct inodesc *); 5733965Sjdp 5833965Sjdpvoid 5933965Sjdppass2(void) 6033965Sjdp{ 6138889Sjdp struct dinode *dp; 6233965Sjdp struct inoinfo **inpp, *inp; 6338889Sjdp struct inoinfo **inpend; 6433965Sjdp struct inodesc curino; 6533965Sjdp struct dinode dino; 6633965Sjdp char pathbuf[MAXPATHLEN + 1]; 6733965Sjdp 6889857Sobrien switch (inoinfo(ROOTINO)->ino_state) { 6933965Sjdp 70218822Sdim case USTATE: 71218822Sdim pfatal("ROOT INODE UNALLOCATED"); 72218822Sdim if (reply("ALLOCATE") == 0) { 73218822Sdim ckfini(0); 74218822Sdim exit(EEXIT); 75218822Sdim } 76218822Sdim if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 77218822Sdim errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 78218822Sdim break; 79218822Sdim 80218822Sdim case DCLEAR: 81218822Sdim pfatal("DUPS/BAD IN ROOT INODE"); 82218822Sdim if (reply("REALLOCATE")) { 8333965Sjdp freeino(ROOTINO); 8433965Sjdp if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 8577298Sobrien errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 8633965Sjdp break; 8733965Sjdp } 8833965Sjdp if (reply("CONTINUE") == 0) { 8933965Sjdp ckfini(0); 9033965Sjdp exit(EEXIT); 9133965Sjdp } 9233965Sjdp break; 9333965Sjdp 9433965Sjdp case FSTATE: 9533965Sjdp case FCLEAR: 9633965Sjdp pfatal("ROOT INODE NOT DIRECTORY"); 9733965Sjdp if (reply("REALLOCATE")) { 9833965Sjdp freeino(ROOTINO); 9933965Sjdp if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) 10033965Sjdp errx(EEXIT, "CANNOT ALLOCATE ROOT INODE"); 10133965Sjdp break; 10233965Sjdp } 10333965Sjdp if (reply("FIX") == 0) { 10433965Sjdp ckfini(0); 105218822Sdim exit(EEXIT); 106218822Sdim } 107218822Sdim dp = ginode(ROOTINO); 108218822Sdim dp->di_mode &= ~IFMT; 109218822Sdim dp->di_mode |= IFDIR; 110218822Sdim inodirty(); 111218822Sdim break; 112218822Sdim 113218822Sdim case DSTATE: 114218822Sdim break; 115218822Sdim 116218822Sdim default: 117218822Sdim errx(EEXIT, "BAD STATE %d FOR ROOT INODE", 118218822Sdim inoinfo(ROOTINO)->ino_state); 119218822Sdim } 120218822Sdim inoinfo(ROOTINO)->ino_state = DFOUND; 121218822Sdim inoinfo(WINO)->ino_state = FSTATE; 122218822Sdim inoinfo(WINO)->ino_type = DT_WHT; 123218822Sdim /* 124218822Sdim * Sort the directory list into disk block order. 125218822Sdim */ 126104834Sobrien qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort); 12733965Sjdp /* 12833965Sjdp * Check the integrity of each directory. 12933965Sjdp */ 13033965Sjdp memset(&curino, 0, sizeof(struct inodesc)); 13177298Sobrien curino.id_type = DATA; 13277298Sobrien curino.id_func = pass2check; 13333965Sjdp dp = &dino; 13433965Sjdp inpend = &inpsort[inplast]; 13533965Sjdp for (inpp = inpsort; inpp < inpend; inpp++) { 13633965Sjdp if (got_siginfo) { 13760484Sobrien printf("%s: phase 2: dir %d of %d (%d%%)\n", cdevname, 13833965Sjdp inpp - inpsort, (int)inplast, 13933965Sjdp (int)((inpp - inpsort) * 100 / inplast)); 140218822Sdim got_siginfo = 0; 141218822Sdim } 14233965Sjdp inp = *inpp; 14333965Sjdp if (inp->i_isize == 0) 14433965Sjdp continue; 14577298Sobrien if (inp->i_isize < MINDIRSIZE) { 14660484Sobrien direrror(inp->i_number, "DIRECTORY TOO SHORT"); 14760484Sobrien inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ); 14860484Sobrien if (reply("FIX") == 1) { 14933965Sjdp dp = ginode(inp->i_number); 15033965Sjdp dp->di_size = inp->i_isize; 15160484Sobrien inodirty(); 15233965Sjdp dp = &dino; 15333965Sjdp } 154218822Sdim } else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) { 15533965Sjdp getpathname(pathbuf, inp->i_number, inp->i_number); 15633965Sjdp if (usedsoftdep) 15733965Sjdp pfatal("%s %s: LENGTH %d NOT MULTIPLE OF %d", 15833965Sjdp "DIRECTORY", pathbuf, inp->i_isize, 15933965Sjdp DIRBLKSIZ); 16033965Sjdp else 161218822Sdim pwarn("%s %s: LENGTH %d NOT MULTIPLE OF %d", 162218822Sdim "DIRECTORY", pathbuf, inp->i_isize, 16333965Sjdp DIRBLKSIZ); 164218822Sdim if (preen) 165218822Sdim printf(" (ADJUSTED)\n"); 16633965Sjdp inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ); 167218822Sdim if (preen || reply("ADJUST") == 1) { 168218822Sdim dp = ginode(inp->i_number); 169218822Sdim dp->di_size = roundup(inp->i_isize, DIRBLKSIZ); 17033965Sjdp inodirty(); 17133965Sjdp dp = &dino; 17233965Sjdp } 173218822Sdim } 174218822Sdim memset(&dino, 0, sizeof(struct dinode)); 175218822Sdim dino.di_mode = IFDIR; 17633965Sjdp dp->di_size = inp->i_isize; 177218822Sdim memmove(&dp->di_db[0], &inp->i_blks[0], (size_t)inp->i_numblks); 178218822Sdim curino.id_number = inp->i_number; 17960484Sobrien curino.id_parent = inp->i_parent; 18033965Sjdp (void)ckinode(dp, &curino); 181218822Sdim } 182218822Sdim /* 183218822Sdim * Now that the parents of all directories have been found, 184218822Sdim * make another pass to verify the value of `..' 18538889Sjdp */ 18638889Sjdp for (inpp = inpsort; inpp < inpend; inpp++) { 18733965Sjdp inp = *inpp; 18833965Sjdp if (inp->i_parent == 0 || inp->i_isize == 0) 18933965Sjdp continue; 19033965Sjdp if (inoinfo(inp->i_parent)->ino_state == DFOUND && 19133965Sjdp inoinfo(inp->i_number)->ino_state == DSTATE) 192104834Sobrien inoinfo(inp->i_number)->ino_state = DFOUND; 19333965Sjdp if (inp->i_dotdot == inp->i_parent || 19433965Sjdp inp->i_dotdot == (ino_t)-1) 19533965Sjdp continue; 19633965Sjdp if (inp->i_dotdot == 0) { 19733965Sjdp inp->i_dotdot = inp->i_parent; 19877298Sobrien fileerror(inp->i_parent, inp->i_number, "MISSING '..'"); 19933965Sjdp if (reply("FIX") == 0) 20077298Sobrien continue; 20133965Sjdp (void)makeentry(inp->i_number, inp->i_parent, ".."); 20233965Sjdp inoinfo(inp->i_parent)->ino_linkcnt--; 20333965Sjdp continue; 20433965Sjdp } 20533965Sjdp fileerror(inp->i_parent, inp->i_number, 20633965Sjdp "BAD INODE NUMBER FOR '..'"); 20733965Sjdp if (reply("FIX") == 0) 20833965Sjdp continue; 20933965Sjdp inoinfo(inp->i_dotdot)->ino_linkcnt++; 21033965Sjdp inoinfo(inp->i_parent)->ino_linkcnt--; 21133965Sjdp inp->i_dotdot = inp->i_parent; 212218822Sdim (void)changeino(inp->i_number, "..", inp->i_parent); 21333965Sjdp } 21433965Sjdp /* 21533965Sjdp * Mark all the directories that can be found from the root. 21633965Sjdp */ 21733965Sjdp propagate(); 21833965Sjdp} 21933965Sjdp 22033965Sjdpstatic int 22133965Sjdppass2check(struct inodesc *idesc) 22233965Sjdp{ 22333965Sjdp struct direct *dirp = idesc->id_dirp; 22460484Sobrien struct inoinfo *inp; 22560484Sobrien int n, entrysize, ret = 0; 22660484Sobrien struct dinode *dp; 22760484Sobrien char *errmsg; 22833965Sjdp struct direct proto; 22933965Sjdp char namebuf[MAXPATHLEN + 1]; 23033965Sjdp char pathbuf[MAXPATHLEN + 1]; 23133965Sjdp 23233965Sjdp /* 23360484Sobrien * check for "." 23460484Sobrien */ 23577298Sobrien if (idesc->id_entryno != 0) 23677298Sobrien goto chk1; 23777298Sobrien if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 23877298Sobrien if (dirp->d_ino != idesc->id_number) { 23977298Sobrien direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 24033965Sjdp dirp->d_ino = idesc->id_number; 24133965Sjdp if (reply("FIX") == 1) 24233965Sjdp ret |= ALTERED; 24333965Sjdp } 24433965Sjdp if (dirp->d_type != DT_DIR) { 24533965Sjdp direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'"); 24633965Sjdp dirp->d_type = DT_DIR; 24733965Sjdp if (reply("FIX") == 1) 24833965Sjdp ret |= ALTERED; 24933965Sjdp } 25033965Sjdp goto chk1; 25133965Sjdp } 25233965Sjdp direrror(idesc->id_number, "MISSING '.'"); 25333965Sjdp proto.d_ino = idesc->id_number; 254218822Sdim proto.d_type = DT_DIR; 25533965Sjdp proto.d_namlen = 1; 256218822Sdim (void)strcpy(proto.d_name, "."); 25733965Sjdp entrysize = DIRSIZ(0, &proto); 25833965Sjdp if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 25933965Sjdp pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 26033965Sjdp dirp->d_name); 261218822Sdim } else if (dirp->d_reclen < entrysize) { 262218822Sdim pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 263218822Sdim } else if (dirp->d_reclen < 2 * entrysize) { 264218822Sdim proto.d_reclen = dirp->d_reclen; 265218822Sdim memmove(dirp, &proto, (size_t)entrysize); 26633965Sjdp if (reply("FIX") == 1) 267218822Sdim ret |= ALTERED; 26833965Sjdp } else { 26933965Sjdp n = dirp->d_reclen - entrysize; 270218822Sdim proto.d_reclen = entrysize; 27133965Sjdp memmove(dirp, &proto, (size_t)entrysize); 27233965Sjdp idesc->id_entryno++; 27333965Sjdp inoinfo(dirp->d_ino)->ino_linkcnt--; 27433965Sjdp dirp = (struct direct *)((char *)(dirp) + entrysize); 27577298Sobrien memset(dirp, 0, (size_t)n); 27677298Sobrien dirp->d_reclen = n; 27733965Sjdp if (reply("FIX") == 1) 27833965Sjdp ret |= ALTERED; 27933965Sjdp } 28033965Sjdpchk1: 281218822Sdim if (idesc->id_entryno > 1) 28233965Sjdp goto chk2; 28333965Sjdp inp = getinoinfo(idesc->id_number); 28433965Sjdp proto.d_ino = inp->i_parent; 28533965Sjdp proto.d_type = DT_DIR; 28633965Sjdp proto.d_namlen = 2; 287218822Sdim (void)strcpy(proto.d_name, ".."); 28833965Sjdp entrysize = DIRSIZ(0, &proto); 28933965Sjdp if (idesc->id_entryno == 0) { 29077298Sobrien n = DIRSIZ(0, dirp); 29133965Sjdp if (dirp->d_reclen < n + entrysize) 29233965Sjdp goto chk2; 29333965Sjdp proto.d_reclen = dirp->d_reclen - n; 29433965Sjdp dirp->d_reclen = n; 29533965Sjdp idesc->id_entryno++; 29633965Sjdp inoinfo(dirp->d_ino)->ino_linkcnt--; 29733965Sjdp dirp = (struct direct *)((char *)(dirp) + n); 29833965Sjdp memset(dirp, 0, (size_t)proto.d_reclen); 29933965Sjdp dirp->d_reclen = proto.d_reclen; 30033965Sjdp } 301218822Sdim if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { 302218822Sdim inp->i_dotdot = dirp->d_ino; 303218822Sdim if (dirp->d_type != DT_DIR) { 304218822Sdim direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'"); 30533965Sjdp dirp->d_type = DT_DIR; 30677298Sobrien if (reply("FIX") == 1) 30777298Sobrien ret |= ALTERED; 30877298Sobrien } 309218822Sdim goto chk2; 31033965Sjdp } 31177298Sobrien if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { 31277298Sobrien fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 31377298Sobrien pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 31477298Sobrien dirp->d_name); 31577298Sobrien inp->i_dotdot = (ino_t)-1; 31633965Sjdp } else if (dirp->d_reclen < entrysize) { 31777298Sobrien fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 31877298Sobrien pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 31977298Sobrien inp->i_dotdot = (ino_t)-1; 32077298Sobrien } else if (inp->i_parent != 0) { 32177298Sobrien /* 32277298Sobrien * We know the parent, so fix now. 32333965Sjdp */ 32477298Sobrien inp->i_dotdot = inp->i_parent; 32577298Sobrien fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); 32677298Sobrien proto.d_reclen = dirp->d_reclen; 32733965Sjdp memmove(dirp, &proto, (size_t)entrysize); 32877298Sobrien if (reply("FIX") == 1) 32977298Sobrien ret |= ALTERED; 33077298Sobrien } 33177298Sobrien idesc->id_entryno++; 33233965Sjdp if (dirp->d_ino != 0) 33377298Sobrien inoinfo(dirp->d_ino)->ino_linkcnt--; 33477298Sobrien return (ret|KEEPON); 33533965Sjdpchk2: 33633965Sjdp if (dirp->d_ino == 0) 337218822Sdim return (ret|KEEPON); 33877298Sobrien if (dirp->d_namlen <= 2 && 33933965Sjdp dirp->d_name[0] == '.' && 34077298Sobrien idesc->id_entryno >= 2) { 34177298Sobrien if (dirp->d_namlen == 1) { 34277298Sobrien direrror(idesc->id_number, "EXTRA '.' ENTRY"); 34377298Sobrien dirp->d_ino = 0; 34477298Sobrien if (reply("FIX") == 1) 34538889Sjdp ret |= ALTERED; 34677298Sobrien return (KEEPON | ret); 34777298Sobrien } 34877298Sobrien if (dirp->d_name[1] == '.') { 34938889Sjdp direrror(idesc->id_number, "EXTRA '..' ENTRY"); 35077298Sobrien dirp->d_ino = 0; 35177298Sobrien if (reply("FIX") == 1) 35233965Sjdp ret |= ALTERED; 35377298Sobrien return (KEEPON | ret); 35477298Sobrien } 35577298Sobrien } 35677298Sobrien idesc->id_entryno++; 35733965Sjdp n = 0; 35833965Sjdp if (dirp->d_ino > maxino) { 35933965Sjdp fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE"); 36033965Sjdp n = reply("REMOVE"); 36133965Sjdp } else if (((dirp->d_ino == WINO && dirp->d_type != DT_WHT) || 36233965Sjdp (dirp->d_ino != WINO && dirp->d_type == DT_WHT))) { 36333965Sjdp fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY"); 36433965Sjdp dirp->d_ino = WINO; 36533965Sjdp dirp->d_type = DT_WHT; 366168433Skan if (reply("FIX") == 1) 367168433Skan ret |= ALTERED; 368168433Skan } else { 369168433Skanagain: 370168433Skan switch (inoinfo(dirp->d_ino)->ino_state) { 371168433Skan case USTATE: 372168433Skan if (idesc->id_entryno <= 2) 373168433Skan break; 374168433Skan fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED"); 375168433Skan n = reply("REMOVE"); 376168433Skan break; 377168433Skan 378168433Skan case DCLEAR: 379168433Skan case FCLEAR: 380168433Skan if (idesc->id_entryno <= 2) 381168433Skan break; 38233965Sjdp if (inoinfo(dirp->d_ino)->ino_state == FCLEAR) 383218822Sdim errmsg = "DUP/BAD"; 38433965Sjdp else if (!preen && !usedsoftdep) 38533965Sjdp errmsg = "ZERO LENGTH DIRECTORY"; 38633965Sjdp else { 38733965Sjdp n = 1; 38833965Sjdp break; 38933965Sjdp } 39033965Sjdp fileerror(idesc->id_number, dirp->d_ino, errmsg); 39133965Sjdp if ((n = reply("REMOVE")) == 1) 39233965Sjdp break; 39333965Sjdp dp = ginode(dirp->d_ino); 39433965Sjdp inoinfo(dirp->d_ino)->ino_state = 39533965Sjdp (dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE; 39633965Sjdp inoinfo(dirp->d_ino)->ino_linkcnt = dp->di_nlink; 39733965Sjdp goto again; 39833965Sjdp 39933965Sjdp case DSTATE: 40033965Sjdp if (inoinfo(idesc->id_number)->ino_state == DFOUND) 40133965Sjdp inoinfo(dirp->d_ino)->ino_state = DFOUND; 40233965Sjdp /* fall through */ 40333965Sjdp 40433965Sjdp case DFOUND: 40560484Sobrien inp = getinoinfo(dirp->d_ino); 40660484Sobrien if (inp->i_parent != 0 && idesc->id_entryno > 2) { 40760484Sobrien getpathname(pathbuf, idesc->id_number, 40833965Sjdp idesc->id_number); 40933965Sjdp getpathname(namebuf, dirp->d_ino, dirp->d_ino); 41033965Sjdp pwarn("%s%s%s %s %s\n", pathbuf, 41133965Sjdp (strcmp(pathbuf, "/") == 0 ? "" : "/"), 41277298Sobrien dirp->d_name, 41333965Sjdp "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", 41433965Sjdp namebuf); 41538889Sjdp if (cursnapshot != 0) 41638889Sjdp break; 41738889Sjdp if (preen) { 41838889Sjdp printf(" (REMOVED)\n"); 41938889Sjdp n = 1; 42038889Sjdp break; 421130561Sobrien } 422130561Sobrien if ((n = reply("REMOVE")) == 1) 423130561Sobrien break; 424130561Sobrien } 425130561Sobrien if (idesc->id_entryno > 2) 426130561Sobrien inp->i_parent = idesc->id_number; 42733965Sjdp /* fall through */ 42833965Sjdp 42933965Sjdp case FSTATE: 43033965Sjdp if (dirp->d_type != inoinfo(dirp->d_ino)->ino_type) { 43133965Sjdp fileerror(idesc->id_number, dirp->d_ino, 43233965Sjdp "BAD TYPE VALUE"); 43377298Sobrien dirp->d_type = inoinfo(dirp->d_ino)->ino_type; 43433965Sjdp if (reply("FIX") == 1) 43533965Sjdp ret |= ALTERED; 43633965Sjdp } 43733965Sjdp inoinfo(dirp->d_ino)->ino_linkcnt--; 43833965Sjdp break; 43933965Sjdp 44033965Sjdp default: 44133965Sjdp errx(EEXIT, "BAD STATE %d FOR INODE I=%d", 44233965Sjdp inoinfo(dirp->d_ino)->ino_state, dirp->d_ino); 44377298Sobrien } 44477298Sobrien } 44538889Sjdp if (n == 0) 44677298Sobrien return (ret|KEEPON); 44777298Sobrien dirp->d_ino = 0; 44877298Sobrien return (ret|KEEPON|ALTERED); 44977298Sobrien} 45038889Sjdp 451218822Sdim/* 452218822Sdim * Routine to sort disk blocks. 45377298Sobrien */ 45477298Sobrienstatic int 45577298Sobrienblksort(const void *arg1, const void *arg2) 45677298Sobrien{ 45777298Sobrien 45877298Sobrien return ((*(struct inoinfo **)arg1)->i_blks[0] - 45977298Sobrien (*(struct inoinfo **)arg2)->i_blks[0]); 46077298Sobrien} 46138889Sjdp