dir.c revision 121258
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 34114589Sobrien#if 0 351558Srgrimes#ifndef lint 3623675Speterstatic const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; 37114589Sobrien#endif /* not lint */ 3841477Sjulian#endif 39114589Sobrien#include <sys/cdefs.h> 40114589Sobrien__FBSDID("$FreeBSD: head/sbin/fsck_ffs/dir.c 121258 2003-10-19 21:49:44Z iedowse $"); 411558Srgrimes 421558Srgrimes#include <sys/param.h> 4341474Sjulian#include <sys/time.h> 4474556Smckusick#include <sys/sysctl.h> 4523675Speter 461558Srgrimes#include <ufs/ufs/dinode.h> 471558Srgrimes#include <ufs/ufs/dir.h> 481558Srgrimes#include <ufs/ffs/fs.h> 4923796Sbde 5023675Speter#include <err.h> 511558Srgrimes#include <string.h> 5223675Speter 531558Srgrimes#include "fsck.h" 541558Srgrimes 55100935Sphkconst char *lfname = "lost+found"; 56121258Siedowseint lfmode = 0700; 5774556Smckusickstruct dirtemplate emptydir = { 5874556Smckusick 0, DIRBLKSIZ, DT_UNKNOWN, 0, "", 5974556Smckusick 0, 0, DT_UNKNOWN, 0, "" 6074556Smckusick}; 611558Srgrimesstruct dirtemplate dirhead = { 621558Srgrimes 0, 12, DT_DIR, 1, ".", 631558Srgrimes 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 641558Srgrimes}; 651558Srgrimesstruct odirtemplate odirhead = { 661558Srgrimes 0, 12, 1, ".", 671558Srgrimes 0, DIRBLKSIZ - 12, 2, ".." 681558Srgrimes}; 691558Srgrimes 7092839Simpstatic int chgino(struct inodesc *); 7192839Simpstatic int dircheck(struct inodesc *, struct direct *); 7298542Smckusickstatic int expanddir(union dinode *dp, char *name); 7392839Simpstatic void freedir(ino_t ino, ino_t parent); 7492839Simpstatic struct direct *fsck_readdir(struct inodesc *); 7598542Smckusickstatic struct bufarea *getdirblk(ufs2_daddr_t blkno, long size); 7692839Simpstatic int lftempname(char *bufp, ino_t ino); 7792839Simpstatic int mkentry(struct inodesc *); 781558Srgrimes 791558Srgrimes/* 801558Srgrimes * Propagate connected state through the tree. 811558Srgrimes */ 827585Sbdevoid 8392839Simppropagate(void) 841558Srgrimes{ 8592806Sobrien struct inoinfo **inpp, *inp; 861558Srgrimes struct inoinfo **inpend; 871558Srgrimes long change; 881558Srgrimes 891558Srgrimes inpend = &inpsort[inplast]; 901558Srgrimes do { 911558Srgrimes change = 0; 921558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 931558Srgrimes inp = *inpp; 941558Srgrimes if (inp->i_parent == 0) 951558Srgrimes continue; 9641474Sjulian if (inoinfo(inp->i_parent)->ino_state == DFOUND && 9741474Sjulian inoinfo(inp->i_number)->ino_state == DSTATE) { 9841474Sjulian inoinfo(inp->i_number)->ino_state = DFOUND; 991558Srgrimes change++; 1001558Srgrimes } 1011558Srgrimes } 1021558Srgrimes } while (change > 0); 1031558Srgrimes} 1041558Srgrimes 1051558Srgrimes/* 1061558Srgrimes * Scan each entry in a directory block. 1071558Srgrimes */ 1087585Sbdeint 10992839Simpdirscan(struct inodesc *idesc) 1101558Srgrimes{ 11192806Sobrien struct direct *dp; 11292806Sobrien struct bufarea *bp; 11374556Smckusick u_int dsize, n; 1141558Srgrimes long blksiz; 1151558Srgrimes char dbuf[DIRBLKSIZ]; 1161558Srgrimes 1171558Srgrimes if (idesc->id_type != DATA) 11823675Speter errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 1191558Srgrimes if (idesc->id_entryno == 0 && 1201558Srgrimes (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 1211558Srgrimes idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 1221558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1231558Srgrimes if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 1241558Srgrimes idesc->id_filesize -= blksiz; 1251558Srgrimes return (SKIP); 1261558Srgrimes } 1271558Srgrimes idesc->id_loc = 0; 1281558Srgrimes for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 1291558Srgrimes dsize = dp->d_reclen; 13041474Sjulian if (dsize > sizeof(dbuf)) 13141474Sjulian dsize = sizeof(dbuf); 13223675Speter memmove(dbuf, dp, (size_t)dsize); 1331558Srgrimes idesc->id_dirp = (struct direct *)dbuf; 1341558Srgrimes if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 1351558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 13623675Speter memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 1371558Srgrimes (size_t)dsize); 1381558Srgrimes dirty(bp); 1391558Srgrimes sbdirty(); 1401558Srgrimes } 1418871Srgrimes if (n & STOP) 1421558Srgrimes return (n); 1431558Srgrimes } 1441558Srgrimes return (idesc->id_filesize > 0 ? KEEPON : STOP); 1451558Srgrimes} 1461558Srgrimes 1471558Srgrimes/* 1481558Srgrimes * get next entry in a directory. 1491558Srgrimes */ 15023675Speterstatic struct direct * 15192839Simpfsck_readdir(struct inodesc *idesc) 1521558Srgrimes{ 15392806Sobrien struct direct *dp, *ndp; 15492806Sobrien struct bufarea *bp; 1551558Srgrimes long size, blksiz, fix, dploc; 1561558Srgrimes 1571558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1581558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1591558Srgrimes if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 1601558Srgrimes idesc->id_loc < blksiz) { 1611558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1621558Srgrimes if (dircheck(idesc, dp)) 1631558Srgrimes goto dpok; 16423675Speter if (idesc->id_fix == IGNORE) 16523675Speter return (0); 1661558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1671558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1681558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1691558Srgrimes dp->d_reclen = DIRBLKSIZ; 1701558Srgrimes dp->d_ino = 0; 1711558Srgrimes dp->d_type = 0; 1721558Srgrimes dp->d_namlen = 0; 1731558Srgrimes dp->d_name[0] = '\0'; 1741558Srgrimes if (fix) 1751558Srgrimes dirty(bp); 1761558Srgrimes idesc->id_loc += DIRBLKSIZ; 1771558Srgrimes idesc->id_filesize -= DIRBLKSIZ; 1781558Srgrimes return (dp); 1791558Srgrimes } 1801558Srgrimesdpok: 1811558Srgrimes if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 1821558Srgrimes return NULL; 1831558Srgrimes dploc = idesc->id_loc; 1841558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 1851558Srgrimes idesc->id_loc += dp->d_reclen; 1861558Srgrimes idesc->id_filesize -= dp->d_reclen; 1871558Srgrimes if ((idesc->id_loc % DIRBLKSIZ) == 0) 1881558Srgrimes return (dp); 1891558Srgrimes ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1901558Srgrimes if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 1911558Srgrimes dircheck(idesc, ndp) == 0) { 1921558Srgrimes size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 1931558Srgrimes idesc->id_loc += size; 1941558Srgrimes idesc->id_filesize -= size; 19523675Speter if (idesc->id_fix == IGNORE) 19623675Speter return (0); 1971558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1981558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1991558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2001558Srgrimes dp->d_reclen += size; 2011558Srgrimes if (fix) 2021558Srgrimes dirty(bp); 2031558Srgrimes } 2041558Srgrimes return (dp); 2051558Srgrimes} 2061558Srgrimes 2071558Srgrimes/* 2081558Srgrimes * Verify that a directory entry is valid. 2091558Srgrimes * This is a superset of the checks made in the kernel. 2101558Srgrimes */ 21123675Speterstatic int 21292839Simpdircheck(struct inodesc *idesc, struct direct *dp) 2131558Srgrimes{ 214114589Sobrien size_t size; 21592806Sobrien char *cp; 216114589Sobrien u_char type; 217114589Sobrien u_int namlen; 2181558Srgrimes int spaceleft; 2191558Srgrimes 22023675Speter spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 22141474Sjulian if (dp->d_reclen == 0 || 22223675Speter dp->d_reclen > spaceleft || 22323675Speter (dp->d_reclen & 0x3) != 0) 22462668Smckusick goto bad; 22523675Speter if (dp->d_ino == 0) 22623675Speter return (1); 22796483Sphk size = DIRSIZ(0, dp); 22896483Sphk namlen = dp->d_namlen; 22996483Sphk type = dp->d_type; 23023675Speter if (dp->d_reclen < size || 23123675Speter idesc->id_filesize < size || 23223675Speter namlen > MAXNAMLEN || 23323675Speter type > 15) 23462668Smckusick goto bad; 23523675Speter for (cp = dp->d_name, size = 0; size < namlen; size++) 23623675Speter if (*cp == '\0' || (*cp++ == '/')) 23762668Smckusick goto bad; 23823675Speter if (*cp != '\0') 23962668Smckusick goto bad; 24023675Speter return (1); 24162668Smckusickbad: 24262668Smckusick if (debug) 24362668Smckusick printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n", 24462668Smckusick dp->d_ino, dp->d_reclen, dp->d_namlen, dp->d_type, 24562668Smckusick dp->d_name); 24662668Smckusick return (0); 2471558Srgrimes} 2481558Srgrimes 2497585Sbdevoid 250100935Sphkdirerror(ino_t ino, const char *errmesg) 2511558Srgrimes{ 2521558Srgrimes 2531558Srgrimes fileerror(ino, ino, errmesg); 2541558Srgrimes} 2551558Srgrimes 2567585Sbdevoid 257100935Sphkfileerror(ino_t cwd, ino_t ino, const char *errmesg) 2581558Srgrimes{ 25998542Smckusick union dinode *dp; 2601558Srgrimes char pathbuf[MAXPATHLEN + 1]; 2611558Srgrimes 2621558Srgrimes pwarn("%s ", errmesg); 2631558Srgrimes pinode(ino); 2641558Srgrimes printf("\n"); 2651558Srgrimes getpathname(pathbuf, cwd, ino); 2661558Srgrimes if (ino < ROOTINO || ino > maxino) { 2671558Srgrimes pfatal("NAME=%s\n", pathbuf); 2681558Srgrimes return; 2691558Srgrimes } 2701558Srgrimes dp = ginode(ino); 2711558Srgrimes if (ftypeok(dp)) 2721558Srgrimes pfatal("%s=%s\n", 27398542Smckusick (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE", 27498542Smckusick pathbuf); 2751558Srgrimes else 2761558Srgrimes pfatal("NAME=%s\n", pathbuf); 2771558Srgrimes} 2781558Srgrimes 2797585Sbdevoid 28092839Simpadjust(struct inodesc *idesc, int lcnt) 2811558Srgrimes{ 28298542Smckusick union dinode *dp; 28341474Sjulian int saveresolved; 2841558Srgrimes 2851558Srgrimes dp = ginode(idesc->id_number); 28698542Smckusick if (DIP(dp, di_nlink) == lcnt) { 28741474Sjulian /* 28841474Sjulian * If we have not hit any unresolved problems, are running 289102231Strhodes * in preen mode, and are on a file system using soft updates, 29041474Sjulian * then just toss any partially allocated files. 29141474Sjulian */ 29274556Smckusick if (resolved && (preen || bkgrdflag) && usedsoftdep) { 29341474Sjulian clri(idesc, "UNREF", 1); 29441474Sjulian return; 29541474Sjulian } else { 29641474Sjulian /* 297102231Strhodes * The file system can be marked clean even if 29841474Sjulian * a file is not linked up, but is cleared. 29941474Sjulian * Hence, resolved should not be cleared when 30041474Sjulian * linkup is answered no, but clri is answered yes. 30141474Sjulian */ 30241474Sjulian saveresolved = resolved; 30341474Sjulian if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) { 30441474Sjulian resolved = saveresolved; 30541474Sjulian clri(idesc, "UNREF", 0); 30641474Sjulian return; 30741474Sjulian } 30841474Sjulian /* 30941474Sjulian * Account for the new reference created by linkup(). 31041474Sjulian */ 31141474Sjulian dp = ginode(idesc->id_number); 31241474Sjulian lcnt--; 31341474Sjulian } 31441474Sjulian } 31541474Sjulian if (lcnt != 0) { 3161558Srgrimes pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 31798542Smckusick ((DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE")); 3181558Srgrimes pinode(idesc->id_number); 3191558Srgrimes printf(" COUNT %d SHOULD BE %d", 32098542Smckusick DIP(dp, di_nlink), DIP(dp, di_nlink) - lcnt); 32134266Sjulian if (preen || usedsoftdep) { 3221558Srgrimes if (lcnt < 0) { 3231558Srgrimes printf("\n"); 3241558Srgrimes pfatal("LINK COUNT INCREASING"); 3251558Srgrimes } 32634266Sjulian if (preen) 32734266Sjulian printf(" (ADJUSTED)\n"); 3281558Srgrimes } 3291558Srgrimes if (preen || reply("ADJUST") == 1) { 33074556Smckusick if (bkgrdflag == 0) { 33198542Smckusick DIP(dp, di_nlink) -= lcnt; 33274556Smckusick inodirty(); 33374556Smckusick } else { 33474556Smckusick cmd.value = idesc->id_number; 33574556Smckusick cmd.size = -lcnt; 33674556Smckusick if (debug) 337100935Sphk printf("adjrefcnt ino %ld amt %lld\n", 338100935Sphk (long)cmd.value, 339100935Sphk (long long)cmd.size); 34074556Smckusick if (sysctl(adjrefcnt, MIBSIZE, 0, 0, 34174556Smckusick &cmd, sizeof cmd) == -1) 34274556Smckusick rwerror("ADJUST INODE", cmd.value); 34374556Smckusick } 3441558Srgrimes } 3451558Srgrimes } 3461558Srgrimes} 3471558Srgrimes 34823675Speterstatic int 34992839Simpmkentry(struct inodesc *idesc) 3501558Srgrimes{ 35192806Sobrien struct direct *dirp = idesc->id_dirp; 3521558Srgrimes struct direct newent; 3531558Srgrimes int newlen, oldlen; 3541558Srgrimes 3551558Srgrimes newent.d_namlen = strlen(idesc->id_name); 3561558Srgrimes newlen = DIRSIZ(0, &newent); 3571558Srgrimes if (dirp->d_ino != 0) 3581558Srgrimes oldlen = DIRSIZ(0, dirp); 3591558Srgrimes else 3601558Srgrimes oldlen = 0; 3611558Srgrimes if (dirp->d_reclen - oldlen < newlen) 3621558Srgrimes return (KEEPON); 3631558Srgrimes newent.d_reclen = dirp->d_reclen - oldlen; 3641558Srgrimes dirp->d_reclen = oldlen; 3651558Srgrimes dirp = (struct direct *)(((char *)dirp) + oldlen); 3661558Srgrimes dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 36723675Speter dirp->d_reclen = newent.d_reclen; 36896483Sphk dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 36923675Speter dirp->d_namlen = newent.d_namlen; 37023675Speter memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 3711558Srgrimes return (ALTERED|STOP); 3721558Srgrimes} 3731558Srgrimes 37423675Speterstatic int 37592839Simpchgino(struct inodesc *idesc) 3761558Srgrimes{ 37792806Sobrien struct direct *dirp = idesc->id_dirp; 3781558Srgrimes 37923675Speter if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 3801558Srgrimes return (KEEPON); 3811558Srgrimes dirp->d_ino = idesc->id_parent; 38296483Sphk dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 3831558Srgrimes return (ALTERED|STOP); 3841558Srgrimes} 3851558Srgrimes 3867585Sbdeint 38792839Simplinkup(ino_t orphan, ino_t parentdir, char *name) 3881558Srgrimes{ 38998542Smckusick union dinode *dp; 3901558Srgrimes int lostdir; 3911558Srgrimes ino_t oldlfdir; 3921558Srgrimes struct inodesc idesc; 3931558Srgrimes char tempname[BUFSIZ]; 3941558Srgrimes 39523675Speter memset(&idesc, 0, sizeof(struct inodesc)); 3961558Srgrimes dp = ginode(orphan); 39798542Smckusick lostdir = (DIP(dp, di_mode) & IFMT) == IFDIR; 3981558Srgrimes pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 3991558Srgrimes pinode(orphan); 40098542Smckusick if (preen && DIP(dp, di_size) == 0) 4011558Srgrimes return (0); 40274556Smckusick if (cursnapshot != 0) { 40374556Smckusick pfatal("FILE LINKUP IN SNAPSHOT"); 40474556Smckusick return (0); 40574556Smckusick } 4061558Srgrimes if (preen) 4071558Srgrimes printf(" (RECONNECTED)\n"); 4081558Srgrimes else 4091558Srgrimes if (reply("RECONNECT") == 0) 4101558Srgrimes return (0); 4111558Srgrimes if (lfdir == 0) { 4121558Srgrimes dp = ginode(ROOTINO); 413100935Sphk idesc.id_name = strdup(lfname); 4141558Srgrimes idesc.id_type = DATA; 4151558Srgrimes idesc.id_func = findino; 4161558Srgrimes idesc.id_number = ROOTINO; 4171558Srgrimes if ((ckinode(dp, &idesc) & FOUND) != 0) { 4181558Srgrimes lfdir = idesc.id_parent; 4191558Srgrimes } else { 4201558Srgrimes pwarn("NO lost+found DIRECTORY"); 4211558Srgrimes if (preen || reply("CREATE")) { 4221558Srgrimes lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 4231558Srgrimes if (lfdir != 0) { 4241558Srgrimes if (makeentry(ROOTINO, lfdir, lfname) != 0) { 42541474Sjulian numdirs++; 4261558Srgrimes if (preen) 4271558Srgrimes printf(" (CREATED)\n"); 4281558Srgrimes } else { 4291558Srgrimes freedir(lfdir, ROOTINO); 4301558Srgrimes lfdir = 0; 4311558Srgrimes if (preen) 4321558Srgrimes printf("\n"); 4331558Srgrimes } 4341558Srgrimes } 4351558Srgrimes } 4361558Srgrimes } 4371558Srgrimes if (lfdir == 0) { 4381558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 4391558Srgrimes printf("\n\n"); 4401558Srgrimes return (0); 4411558Srgrimes } 4421558Srgrimes } 4431558Srgrimes dp = ginode(lfdir); 44498542Smckusick if ((DIP(dp, di_mode) & IFMT) != IFDIR) { 4451558Srgrimes pfatal("lost+found IS NOT A DIRECTORY"); 4461558Srgrimes if (reply("REALLOCATE") == 0) 4471558Srgrimes return (0); 4481558Srgrimes oldlfdir = lfdir; 4491558Srgrimes if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 4501558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4511558Srgrimes return (0); 4521558Srgrimes } 4531558Srgrimes if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 4541558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4551558Srgrimes return (0); 4561558Srgrimes } 4571558Srgrimes inodirty(); 4581558Srgrimes idesc.id_type = ADDR; 4591558Srgrimes idesc.id_func = pass4check; 4601558Srgrimes idesc.id_number = oldlfdir; 46141474Sjulian adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1); 46241474Sjulian inoinfo(oldlfdir)->ino_linkcnt = 0; 4631558Srgrimes dp = ginode(lfdir); 4641558Srgrimes } 46541474Sjulian if (inoinfo(lfdir)->ino_state != DFOUND) { 4661558Srgrimes pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 4671558Srgrimes return (0); 4681558Srgrimes } 4691558Srgrimes (void)lftempname(tempname, orphan); 47041474Sjulian if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) { 4711558Srgrimes pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 4721558Srgrimes printf("\n\n"); 4731558Srgrimes return (0); 4741558Srgrimes } 47541474Sjulian inoinfo(orphan)->ino_linkcnt--; 4761558Srgrimes if (lostdir) { 4771558Srgrimes if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 4781558Srgrimes parentdir != (ino_t)-1) 4791558Srgrimes (void)makeentry(orphan, lfdir, ".."); 4801558Srgrimes dp = ginode(lfdir); 48198542Smckusick DIP(dp, di_nlink)++; 4821558Srgrimes inodirty(); 48341474Sjulian inoinfo(lfdir)->ino_linkcnt++; 48486514Siedowse pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan); 48515699Snate if (parentdir != (ino_t)-1) { 48637236Sbde printf("PARENT WAS I=%lu\n", (u_long)parentdir); 48741477Sjulian /* 48841477Sjulian * The parent directory, because of the ordering 48941477Sjulian * guarantees, has had the link count incremented 49041477Sjulian * for the child, but no entry was made. This 49141477Sjulian * fixes the parent link count so that fsck does 49241477Sjulian * not need to be rerun. 49341477Sjulian */ 49441474Sjulian inoinfo(parentdir)->ino_linkcnt++; 49515699Snate } 4961558Srgrimes if (preen == 0) 4971558Srgrimes printf("\n"); 4981558Srgrimes } 4991558Srgrimes return (1); 5001558Srgrimes} 5011558Srgrimes 5021558Srgrimes/* 5031558Srgrimes * fix an entry in a directory. 5041558Srgrimes */ 5057585Sbdeint 506100935Sphkchangeino(ino_t dir, const char *name, ino_t newnum) 5071558Srgrimes{ 5081558Srgrimes struct inodesc idesc; 5091558Srgrimes 51023675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5111558Srgrimes idesc.id_type = DATA; 5121558Srgrimes idesc.id_func = chgino; 5131558Srgrimes idesc.id_number = dir; 5141558Srgrimes idesc.id_fix = DONTKNOW; 515100935Sphk idesc.id_name = strdup(name); 5161558Srgrimes idesc.id_parent = newnum; /* new value for name */ 5171558Srgrimes return (ckinode(ginode(dir), &idesc)); 5181558Srgrimes} 5191558Srgrimes 5201558Srgrimes/* 5211558Srgrimes * make an entry in a directory 5221558Srgrimes */ 5237585Sbdeint 524100935Sphkmakeentry(ino_t parent, ino_t ino, const char *name) 5251558Srgrimes{ 52698542Smckusick union dinode *dp; 5271558Srgrimes struct inodesc idesc; 5281558Srgrimes char pathbuf[MAXPATHLEN + 1]; 5298871Srgrimes 5301558Srgrimes if (parent < ROOTINO || parent >= maxino || 5311558Srgrimes ino < ROOTINO || ino >= maxino) 5321558Srgrimes return (0); 53323675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5341558Srgrimes idesc.id_type = DATA; 5351558Srgrimes idesc.id_func = mkentry; 5361558Srgrimes idesc.id_number = parent; 5371558Srgrimes idesc.id_parent = ino; /* this is the inode to enter */ 5381558Srgrimes idesc.id_fix = DONTKNOW; 539100935Sphk idesc.id_name = strdup(name); 5401558Srgrimes dp = ginode(parent); 54198542Smckusick if (DIP(dp, di_size) % DIRBLKSIZ) { 54298542Smckusick DIP(dp, di_size) = roundup(DIP(dp, di_size), DIRBLKSIZ); 5431558Srgrimes inodirty(); 5441558Srgrimes } 5451558Srgrimes if ((ckinode(dp, &idesc) & ALTERED) != 0) 5461558Srgrimes return (1); 5471558Srgrimes getpathname(pathbuf, parent, parent); 5481558Srgrimes dp = ginode(parent); 5491558Srgrimes if (expanddir(dp, pathbuf) == 0) 5501558Srgrimes return (0); 5511558Srgrimes return (ckinode(dp, &idesc) & ALTERED); 5521558Srgrimes} 5531558Srgrimes 5541558Srgrimes/* 5551558Srgrimes * Attempt to expand the size of a directory 5561558Srgrimes */ 55723675Speterstatic int 55898542Smckusickexpanddir(union dinode *dp, char *name) 5591558Srgrimes{ 56098542Smckusick ufs2_daddr_t lastbn, newblk; 56192806Sobrien struct bufarea *bp; 5621558Srgrimes char *cp, firstblk[DIRBLKSIZ]; 5631558Srgrimes 56498542Smckusick lastbn = lblkno(&sblock, DIP(dp, di_size)); 56598542Smckusick if (lastbn >= NDADDR - 1 || DIP(dp, di_db[lastbn]) == 0 || 56698542Smckusick DIP(dp, di_size) == 0) 5671558Srgrimes return (0); 5681558Srgrimes if ((newblk = allocblk(sblock.fs_frag)) == 0) 5691558Srgrimes return (0); 57098542Smckusick DIP(dp, di_db[lastbn + 1]) = DIP(dp, di_db[lastbn]); 57198542Smckusick DIP(dp, di_db[lastbn]) = newblk; 57298542Smckusick DIP(dp, di_size) += sblock.fs_bsize; 57398542Smckusick DIP(dp, di_blocks) += btodb(sblock.fs_bsize); 57498542Smckusick bp = getdirblk(DIP(dp, di_db[lastbn + 1]), 57598542Smckusick sblksize(&sblock, DIP(dp, di_size), lastbn + 1)); 5761558Srgrimes if (bp->b_errs) 5771558Srgrimes goto bad; 57823675Speter memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 5791558Srgrimes bp = getdirblk(newblk, sblock.fs_bsize); 5801558Srgrimes if (bp->b_errs) 5811558Srgrimes goto bad; 58223675Speter memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 5831558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 5841558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_bsize]; 5851558Srgrimes cp += DIRBLKSIZ) 58623675Speter memmove(cp, &emptydir, sizeof emptydir); 5871558Srgrimes dirty(bp); 58898542Smckusick bp = getdirblk(DIP(dp, di_db[lastbn + 1]), 58998542Smckusick sblksize(&sblock, DIP(dp, di_size), lastbn + 1)); 5901558Srgrimes if (bp->b_errs) 5911558Srgrimes goto bad; 59223675Speter memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 5931558Srgrimes pwarn("NO SPACE LEFT IN %s", name); 5941558Srgrimes if (preen) 5951558Srgrimes printf(" (EXPANDED)\n"); 5961558Srgrimes else if (reply("EXPAND") == 0) 5971558Srgrimes goto bad; 5981558Srgrimes dirty(bp); 5991558Srgrimes inodirty(); 6001558Srgrimes return (1); 6011558Srgrimesbad: 60298542Smckusick DIP(dp, di_db[lastbn]) = DIP(dp, di_db[lastbn + 1]); 60398542Smckusick DIP(dp, di_db[lastbn + 1]) = 0; 60498542Smckusick DIP(dp, di_size) -= sblock.fs_bsize; 60598542Smckusick DIP(dp, di_blocks) -= btodb(sblock.fs_bsize); 6061558Srgrimes freeblk(newblk, sblock.fs_frag); 6071558Srgrimes return (0); 6081558Srgrimes} 6091558Srgrimes 6101558Srgrimes/* 6111558Srgrimes * allocate a new directory 6121558Srgrimes */ 6137586Sbdeino_t 61492839Simpallocdir(ino_t parent, ino_t request, int mode) 6151558Srgrimes{ 6161558Srgrimes ino_t ino; 6171558Srgrimes char *cp; 61898542Smckusick union dinode *dp; 61963810Smckusick struct bufarea *bp; 62063810Smckusick struct inoinfo *inp; 6211558Srgrimes struct dirtemplate *dirp; 6221558Srgrimes 6231558Srgrimes ino = allocino(request, IFDIR|mode); 62496483Sphk dirp = &dirhead; 6251558Srgrimes dirp->dot_ino = ino; 6261558Srgrimes dirp->dotdot_ino = parent; 6271558Srgrimes dp = ginode(ino); 62898542Smckusick bp = getdirblk(DIP(dp, di_db[0]), sblock.fs_fsize); 6291558Srgrimes if (bp->b_errs) { 6301558Srgrimes freeino(ino); 6311558Srgrimes return (0); 6321558Srgrimes } 63323675Speter memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 6341558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6351558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_fsize]; 6361558Srgrimes cp += DIRBLKSIZ) 63723675Speter memmove(cp, &emptydir, sizeof emptydir); 6381558Srgrimes dirty(bp); 63998542Smckusick DIP(dp, di_nlink) = 2; 6401558Srgrimes inodirty(); 6411558Srgrimes if (ino == ROOTINO) { 64298542Smckusick inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink); 6431558Srgrimes cacheino(dp, ino); 6441558Srgrimes return(ino); 6451558Srgrimes } 64641474Sjulian if (inoinfo(parent)->ino_state != DSTATE && 64741474Sjulian inoinfo(parent)->ino_state != DFOUND) { 6481558Srgrimes freeino(ino); 6491558Srgrimes return (0); 6501558Srgrimes } 6511558Srgrimes cacheino(dp, ino); 65263810Smckusick inp = getinoinfo(ino); 65363810Smckusick inp->i_parent = parent; 65463810Smckusick inp->i_dotdot = parent; 65541474Sjulian inoinfo(ino)->ino_state = inoinfo(parent)->ino_state; 65641474Sjulian if (inoinfo(ino)->ino_state == DSTATE) { 65798542Smckusick inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink); 65841474Sjulian inoinfo(parent)->ino_linkcnt++; 6591558Srgrimes } 6601558Srgrimes dp = ginode(parent); 66198542Smckusick DIP(dp, di_nlink)++; 6621558Srgrimes inodirty(); 6631558Srgrimes return (ino); 6641558Srgrimes} 6651558Srgrimes 6661558Srgrimes/* 6671558Srgrimes * free a directory inode 6681558Srgrimes */ 6697585Sbdestatic void 67092839Simpfreedir(ino_t ino, ino_t parent) 6711558Srgrimes{ 67298542Smckusick union dinode *dp; 6731558Srgrimes 6741558Srgrimes if (ino != parent) { 6751558Srgrimes dp = ginode(parent); 67698542Smckusick DIP(dp, di_nlink)--; 6771558Srgrimes inodirty(); 6781558Srgrimes } 6791558Srgrimes freeino(ino); 6801558Srgrimes} 6811558Srgrimes 6821558Srgrimes/* 6831558Srgrimes * generate a temporary name for the lost+found directory. 6841558Srgrimes */ 68523675Speterstatic int 68692839Simplftempname(char *bufp, ino_t ino) 6871558Srgrimes{ 68892806Sobrien ino_t in; 68992806Sobrien char *cp; 6901558Srgrimes int namlen; 6911558Srgrimes 6921558Srgrimes cp = bufp + 2; 6931558Srgrimes for (in = maxino; in > 0; in /= 10) 6941558Srgrimes cp++; 6951558Srgrimes *--cp = 0; 6961558Srgrimes namlen = cp - bufp; 6971558Srgrimes in = ino; 6981558Srgrimes while (cp > bufp) { 6991558Srgrimes *--cp = (in % 10) + '0'; 7001558Srgrimes in /= 10; 7011558Srgrimes } 7021558Srgrimes *cp = '#'; 7031558Srgrimes return (namlen); 7041558Srgrimes} 7051558Srgrimes 7061558Srgrimes/* 7071558Srgrimes * Get a directory block. 7081558Srgrimes * Insure that it is held until another is requested. 7091558Srgrimes */ 71023675Speterstatic struct bufarea * 71198542Smckusickgetdirblk(ufs2_daddr_t blkno, long size) 7121558Srgrimes{ 7131558Srgrimes 7141558Srgrimes if (pdirbp != 0) 7151558Srgrimes pdirbp->b_flags &= ~B_INUSE; 7161558Srgrimes pdirbp = getdatablk(blkno, size); 7171558Srgrimes return (pdirbp); 7181558Srgrimes} 719