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 * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 30114589Sobrien#if 0 311558Srgrimes#ifndef lint 3223675Speterstatic const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; 33114589Sobrien#endif /* not lint */ 3441477Sjulian#endif 35114589Sobrien#include <sys/cdefs.h> 36114589Sobrien__FBSDID("$FreeBSD$"); 371558Srgrimes 381558Srgrimes#include <sys/param.h> 3941474Sjulian#include <sys/time.h> 4074556Smckusick#include <sys/sysctl.h> 4123675Speter 421558Srgrimes#include <ufs/ufs/dinode.h> 431558Srgrimes#include <ufs/ufs/dir.h> 441558Srgrimes#include <ufs/ffs/fs.h> 4523796Sbde 4623675Speter#include <err.h> 471558Srgrimes#include <string.h> 4823675Speter 491558Srgrimes#include "fsck.h" 501558Srgrimes 51100935Sphkconst char *lfname = "lost+found"; 52121258Siedowseint lfmode = 0700; 5374556Smckusickstruct dirtemplate emptydir = { 5474556Smckusick 0, DIRBLKSIZ, DT_UNKNOWN, 0, "", 5574556Smckusick 0, 0, DT_UNKNOWN, 0, "" 5674556Smckusick}; 571558Srgrimesstruct dirtemplate dirhead = { 581558Srgrimes 0, 12, DT_DIR, 1, ".", 591558Srgrimes 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 601558Srgrimes}; 611558Srgrimesstruct odirtemplate odirhead = { 621558Srgrimes 0, 12, 1, ".", 631558Srgrimes 0, DIRBLKSIZ - 12, 2, ".." 641558Srgrimes}; 651558Srgrimes 6692839Simpstatic int chgino(struct inodesc *); 6792839Simpstatic int dircheck(struct inodesc *, struct direct *); 6898542Smckusickstatic int expanddir(union dinode *dp, char *name); 6992839Simpstatic void freedir(ino_t ino, ino_t parent); 7092839Simpstatic struct direct *fsck_readdir(struct inodesc *); 7198542Smckusickstatic struct bufarea *getdirblk(ufs2_daddr_t blkno, long size); 7292839Simpstatic int lftempname(char *bufp, ino_t ino); 7392839Simpstatic int mkentry(struct inodesc *); 741558Srgrimes 751558Srgrimes/* 761558Srgrimes * Propagate connected state through the tree. 771558Srgrimes */ 787585Sbdevoid 7992839Simppropagate(void) 801558Srgrimes{ 8192806Sobrien struct inoinfo **inpp, *inp; 821558Srgrimes struct inoinfo **inpend; 831558Srgrimes long change; 841558Srgrimes 851558Srgrimes inpend = &inpsort[inplast]; 861558Srgrimes do { 871558Srgrimes change = 0; 881558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 891558Srgrimes inp = *inpp; 901558Srgrimes if (inp->i_parent == 0) 911558Srgrimes continue; 9241474Sjulian if (inoinfo(inp->i_parent)->ino_state == DFOUND && 93136281Struckman INO_IS_DUNFOUND(inp->i_number)) { 9441474Sjulian inoinfo(inp->i_number)->ino_state = DFOUND; 951558Srgrimes change++; 961558Srgrimes } 971558Srgrimes } 981558Srgrimes } while (change > 0); 991558Srgrimes} 1001558Srgrimes 1011558Srgrimes/* 1021558Srgrimes * Scan each entry in a directory block. 1031558Srgrimes */ 1047585Sbdeint 10592839Simpdirscan(struct inodesc *idesc) 1061558Srgrimes{ 10792806Sobrien struct direct *dp; 10892806Sobrien struct bufarea *bp; 10974556Smckusick u_int dsize, n; 1101558Srgrimes long blksiz; 1111558Srgrimes char dbuf[DIRBLKSIZ]; 1121558Srgrimes 1131558Srgrimes if (idesc->id_type != DATA) 11423675Speter errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 1151558Srgrimes if (idesc->id_entryno == 0 && 1161558Srgrimes (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 1171558Srgrimes idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 1181558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1191558Srgrimes if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 1201558Srgrimes idesc->id_filesize -= blksiz; 1211558Srgrimes return (SKIP); 1221558Srgrimes } 1231558Srgrimes idesc->id_loc = 0; 1241558Srgrimes for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 1251558Srgrimes dsize = dp->d_reclen; 12641474Sjulian if (dsize > sizeof(dbuf)) 12741474Sjulian dsize = sizeof(dbuf); 12823675Speter memmove(dbuf, dp, (size_t)dsize); 1291558Srgrimes idesc->id_dirp = (struct direct *)dbuf; 1301558Srgrimes if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 1311558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 13223675Speter memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 1331558Srgrimes (size_t)dsize); 1341558Srgrimes dirty(bp); 1351558Srgrimes sbdirty(); 1361558Srgrimes } 1378871Srgrimes if (n & STOP) 1381558Srgrimes return (n); 1391558Srgrimes } 1401558Srgrimes return (idesc->id_filesize > 0 ? KEEPON : STOP); 1411558Srgrimes} 1421558Srgrimes 1431558Srgrimes/* 1441558Srgrimes * get next entry in a directory. 1451558Srgrimes */ 14623675Speterstatic struct direct * 14792839Simpfsck_readdir(struct inodesc *idesc) 1481558Srgrimes{ 14992806Sobrien struct direct *dp, *ndp; 15092806Sobrien struct bufarea *bp; 1511558Srgrimes long size, blksiz, fix, dploc; 1521558Srgrimes 1531558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1541558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1551558Srgrimes if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 1561558Srgrimes idesc->id_loc < blksiz) { 1571558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1581558Srgrimes if (dircheck(idesc, dp)) 1591558Srgrimes goto dpok; 16023675Speter if (idesc->id_fix == IGNORE) 16123675Speter return (0); 1621558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1631558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1641558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1651558Srgrimes dp->d_reclen = DIRBLKSIZ; 1661558Srgrimes dp->d_ino = 0; 1671558Srgrimes dp->d_type = 0; 1681558Srgrimes dp->d_namlen = 0; 1691558Srgrimes dp->d_name[0] = '\0'; 1701558Srgrimes if (fix) 1711558Srgrimes dirty(bp); 1721558Srgrimes idesc->id_loc += DIRBLKSIZ; 1731558Srgrimes idesc->id_filesize -= DIRBLKSIZ; 1741558Srgrimes return (dp); 1751558Srgrimes } 1761558Srgrimesdpok: 1771558Srgrimes if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 1781558Srgrimes return NULL; 1791558Srgrimes dploc = idesc->id_loc; 1801558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 1811558Srgrimes idesc->id_loc += dp->d_reclen; 1821558Srgrimes idesc->id_filesize -= dp->d_reclen; 1831558Srgrimes if ((idesc->id_loc % DIRBLKSIZ) == 0) 1841558Srgrimes return (dp); 1851558Srgrimes ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1861558Srgrimes if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 1871558Srgrimes dircheck(idesc, ndp) == 0) { 1881558Srgrimes size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 1891558Srgrimes idesc->id_loc += size; 1901558Srgrimes idesc->id_filesize -= size; 19123675Speter if (idesc->id_fix == IGNORE) 19223675Speter return (0); 1931558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1941558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1951558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 1961558Srgrimes dp->d_reclen += size; 1971558Srgrimes if (fix) 1981558Srgrimes dirty(bp); 1991558Srgrimes } 2001558Srgrimes return (dp); 2011558Srgrimes} 2021558Srgrimes 2031558Srgrimes/* 2041558Srgrimes * Verify that a directory entry is valid. 2051558Srgrimes * This is a superset of the checks made in the kernel. 2061558Srgrimes */ 20723675Speterstatic int 20892839Simpdircheck(struct inodesc *idesc, struct direct *dp) 2091558Srgrimes{ 210114589Sobrien size_t size; 21192806Sobrien char *cp; 212114589Sobrien u_char type; 213225338Sdelphij u_int8_t namlen; 2141558Srgrimes int spaceleft; 2151558Srgrimes 21623675Speter spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 21741474Sjulian if (dp->d_reclen == 0 || 21823675Speter dp->d_reclen > spaceleft || 21923675Speter (dp->d_reclen & 0x3) != 0) 22062668Smckusick goto bad; 22123675Speter if (dp->d_ino == 0) 22223675Speter return (1); 22396483Sphk size = DIRSIZ(0, dp); 22496483Sphk namlen = dp->d_namlen; 22596483Sphk type = dp->d_type; 22623675Speter if (dp->d_reclen < size || 22723675Speter idesc->id_filesize < size || 228225338Sdelphij namlen == 0 || 22923675Speter type > 15) 23062668Smckusick goto bad; 23123675Speter for (cp = dp->d_name, size = 0; size < namlen; size++) 23223675Speter if (*cp == '\0' || (*cp++ == '/')) 23362668Smckusick goto bad; 23423675Speter if (*cp != '\0') 23562668Smckusick goto bad; 23623675Speter return (1); 23762668Smckusickbad: 23862668Smckusick if (debug) 23962668Smckusick printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n", 24062668Smckusick dp->d_ino, dp->d_reclen, dp->d_namlen, dp->d_type, 24162668Smckusick dp->d_name); 24262668Smckusick return (0); 2431558Srgrimes} 2441558Srgrimes 2457585Sbdevoid 246100935Sphkdirerror(ino_t ino, const char *errmesg) 2471558Srgrimes{ 2481558Srgrimes 2491558Srgrimes fileerror(ino, ino, errmesg); 2501558Srgrimes} 2511558Srgrimes 2527585Sbdevoid 253100935Sphkfileerror(ino_t cwd, ino_t ino, const char *errmesg) 2541558Srgrimes{ 25598542Smckusick union dinode *dp; 2561558Srgrimes char pathbuf[MAXPATHLEN + 1]; 2571558Srgrimes 2581558Srgrimes pwarn("%s ", errmesg); 2591558Srgrimes pinode(ino); 2601558Srgrimes printf("\n"); 2611558Srgrimes getpathname(pathbuf, cwd, ino); 2621558Srgrimes if (ino < ROOTINO || ino > maxino) { 2631558Srgrimes pfatal("NAME=%s\n", pathbuf); 2641558Srgrimes return; 2651558Srgrimes } 2661558Srgrimes dp = ginode(ino); 2671558Srgrimes if (ftypeok(dp)) 2681558Srgrimes pfatal("%s=%s\n", 26998542Smckusick (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE", 27098542Smckusick pathbuf); 2711558Srgrimes else 2721558Srgrimes pfatal("NAME=%s\n", pathbuf); 2731558Srgrimes} 2741558Srgrimes 2757585Sbdevoid 27692839Simpadjust(struct inodesc *idesc, int lcnt) 2771558Srgrimes{ 27898542Smckusick union dinode *dp; 27941474Sjulian int saveresolved; 2801558Srgrimes 2811558Srgrimes dp = ginode(idesc->id_number); 28298542Smckusick if (DIP(dp, di_nlink) == lcnt) { 28341474Sjulian /* 28441474Sjulian * If we have not hit any unresolved problems, are running 285102231Strhodes * in preen mode, and are on a file system using soft updates, 28641474Sjulian * then just toss any partially allocated files. 28741474Sjulian */ 28874556Smckusick if (resolved && (preen || bkgrdflag) && usedsoftdep) { 28941474Sjulian clri(idesc, "UNREF", 1); 29041474Sjulian return; 29141474Sjulian } else { 29241474Sjulian /* 293102231Strhodes * The file system can be marked clean even if 29441474Sjulian * a file is not linked up, but is cleared. 29541474Sjulian * Hence, resolved should not be cleared when 29641474Sjulian * linkup is answered no, but clri is answered yes. 29741474Sjulian */ 29841474Sjulian saveresolved = resolved; 29941474Sjulian if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) { 30041474Sjulian resolved = saveresolved; 30141474Sjulian clri(idesc, "UNREF", 0); 30241474Sjulian return; 30341474Sjulian } 30441474Sjulian /* 30541474Sjulian * Account for the new reference created by linkup(). 30641474Sjulian */ 30741474Sjulian dp = ginode(idesc->id_number); 30841474Sjulian lcnt--; 30941474Sjulian } 31041474Sjulian } 31141474Sjulian if (lcnt != 0) { 3121558Srgrimes pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 31398542Smckusick ((DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE")); 3141558Srgrimes pinode(idesc->id_number); 3151558Srgrimes printf(" COUNT %d SHOULD BE %d", 31698542Smckusick DIP(dp, di_nlink), DIP(dp, di_nlink) - lcnt); 31734266Sjulian if (preen || usedsoftdep) { 3181558Srgrimes if (lcnt < 0) { 3191558Srgrimes printf("\n"); 3201558Srgrimes pfatal("LINK COUNT INCREASING"); 3211558Srgrimes } 32234266Sjulian if (preen) 32334266Sjulian printf(" (ADJUSTED)\n"); 3241558Srgrimes } 3251558Srgrimes if (preen || reply("ADJUST") == 1) { 32674556Smckusick if (bkgrdflag == 0) { 327134589Sscottl DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - lcnt); 32874556Smckusick inodirty(); 32974556Smckusick } else { 33074556Smckusick cmd.value = idesc->id_number; 33174556Smckusick cmd.size = -lcnt; 33274556Smckusick if (debug) 333100935Sphk printf("adjrefcnt ino %ld amt %lld\n", 334100935Sphk (long)cmd.value, 335100935Sphk (long long)cmd.size); 33674556Smckusick if (sysctl(adjrefcnt, MIBSIZE, 0, 0, 33774556Smckusick &cmd, sizeof cmd) == -1) 33874556Smckusick rwerror("ADJUST INODE", cmd.value); 33974556Smckusick } 3401558Srgrimes } 3411558Srgrimes } 3421558Srgrimes} 3431558Srgrimes 34423675Speterstatic int 34592839Simpmkentry(struct inodesc *idesc) 3461558Srgrimes{ 34792806Sobrien struct direct *dirp = idesc->id_dirp; 3481558Srgrimes struct direct newent; 3491558Srgrimes int newlen, oldlen; 3501558Srgrimes 3511558Srgrimes newent.d_namlen = strlen(idesc->id_name); 3521558Srgrimes newlen = DIRSIZ(0, &newent); 3531558Srgrimes if (dirp->d_ino != 0) 3541558Srgrimes oldlen = DIRSIZ(0, dirp); 3551558Srgrimes else 3561558Srgrimes oldlen = 0; 3571558Srgrimes if (dirp->d_reclen - oldlen < newlen) 3581558Srgrimes return (KEEPON); 3591558Srgrimes newent.d_reclen = dirp->d_reclen - oldlen; 3601558Srgrimes dirp->d_reclen = oldlen; 3611558Srgrimes dirp = (struct direct *)(((char *)dirp) + oldlen); 3621558Srgrimes dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 36323675Speter dirp->d_reclen = newent.d_reclen; 36496483Sphk dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 36523675Speter dirp->d_namlen = newent.d_namlen; 36623675Speter memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 3671558Srgrimes return (ALTERED|STOP); 3681558Srgrimes} 3691558Srgrimes 37023675Speterstatic int 37192839Simpchgino(struct inodesc *idesc) 3721558Srgrimes{ 37392806Sobrien struct direct *dirp = idesc->id_dirp; 3741558Srgrimes 37523675Speter if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 3761558Srgrimes return (KEEPON); 3771558Srgrimes dirp->d_ino = idesc->id_parent; 37896483Sphk dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 3791558Srgrimes return (ALTERED|STOP); 3801558Srgrimes} 3811558Srgrimes 3827585Sbdeint 38392839Simplinkup(ino_t orphan, ino_t parentdir, char *name) 3841558Srgrimes{ 38598542Smckusick union dinode *dp; 3861558Srgrimes int lostdir; 3871558Srgrimes ino_t oldlfdir; 3881558Srgrimes struct inodesc idesc; 3891558Srgrimes char tempname[BUFSIZ]; 3901558Srgrimes 39123675Speter memset(&idesc, 0, sizeof(struct inodesc)); 3921558Srgrimes dp = ginode(orphan); 39398542Smckusick lostdir = (DIP(dp, di_mode) & IFMT) == IFDIR; 3941558Srgrimes pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 3951558Srgrimes pinode(orphan); 39698542Smckusick if (preen && DIP(dp, di_size) == 0) 3971558Srgrimes return (0); 39874556Smckusick if (cursnapshot != 0) { 39974556Smckusick pfatal("FILE LINKUP IN SNAPSHOT"); 40074556Smckusick return (0); 40174556Smckusick } 4021558Srgrimes if (preen) 4031558Srgrimes printf(" (RECONNECTED)\n"); 4041558Srgrimes else 4051558Srgrimes if (reply("RECONNECT") == 0) 4061558Srgrimes return (0); 4071558Srgrimes if (lfdir == 0) { 4081558Srgrimes dp = ginode(ROOTINO); 409100935Sphk idesc.id_name = strdup(lfname); 4101558Srgrimes idesc.id_type = DATA; 4111558Srgrimes idesc.id_func = findino; 4121558Srgrimes idesc.id_number = ROOTINO; 4131558Srgrimes if ((ckinode(dp, &idesc) & FOUND) != 0) { 4141558Srgrimes lfdir = idesc.id_parent; 4151558Srgrimes } else { 4161558Srgrimes pwarn("NO lost+found DIRECTORY"); 4171558Srgrimes if (preen || reply("CREATE")) { 4181558Srgrimes lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 4191558Srgrimes if (lfdir != 0) { 4201558Srgrimes if (makeentry(ROOTINO, lfdir, lfname) != 0) { 42141474Sjulian numdirs++; 4221558Srgrimes if (preen) 4231558Srgrimes printf(" (CREATED)\n"); 4241558Srgrimes } else { 4251558Srgrimes freedir(lfdir, ROOTINO); 4261558Srgrimes lfdir = 0; 4271558Srgrimes if (preen) 4281558Srgrimes printf("\n"); 4291558Srgrimes } 4301558Srgrimes } 4311558Srgrimes } 4321558Srgrimes } 4331558Srgrimes if (lfdir == 0) { 4341558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 4351558Srgrimes printf("\n\n"); 4361558Srgrimes return (0); 4371558Srgrimes } 4381558Srgrimes } 4391558Srgrimes dp = ginode(lfdir); 44098542Smckusick if ((DIP(dp, di_mode) & IFMT) != IFDIR) { 4411558Srgrimes pfatal("lost+found IS NOT A DIRECTORY"); 4421558Srgrimes if (reply("REALLOCATE") == 0) 4431558Srgrimes return (0); 4441558Srgrimes oldlfdir = lfdir; 4451558Srgrimes if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 4461558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4471558Srgrimes return (0); 4481558Srgrimes } 4491558Srgrimes if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 4501558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4511558Srgrimes return (0); 4521558Srgrimes } 4531558Srgrimes inodirty(); 4541558Srgrimes idesc.id_type = ADDR; 4551558Srgrimes idesc.id_func = pass4check; 4561558Srgrimes idesc.id_number = oldlfdir; 45741474Sjulian adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1); 45841474Sjulian inoinfo(oldlfdir)->ino_linkcnt = 0; 4591558Srgrimes dp = ginode(lfdir); 4601558Srgrimes } 46141474Sjulian if (inoinfo(lfdir)->ino_state != DFOUND) { 4621558Srgrimes pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 4631558Srgrimes return (0); 4641558Srgrimes } 4651558Srgrimes (void)lftempname(tempname, orphan); 46641474Sjulian if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) { 4671558Srgrimes pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 4681558Srgrimes printf("\n\n"); 4691558Srgrimes return (0); 4701558Srgrimes } 47141474Sjulian inoinfo(orphan)->ino_linkcnt--; 4721558Srgrimes if (lostdir) { 4731558Srgrimes if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 4741558Srgrimes parentdir != (ino_t)-1) 4751558Srgrimes (void)makeentry(orphan, lfdir, ".."); 4761558Srgrimes dp = ginode(lfdir); 477134589Sscottl DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1); 4781558Srgrimes inodirty(); 47941474Sjulian inoinfo(lfdir)->ino_linkcnt++; 48086514Siedowse pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan); 48115699Snate if (parentdir != (ino_t)-1) { 48237236Sbde printf("PARENT WAS I=%lu\n", (u_long)parentdir); 48341477Sjulian /* 48441477Sjulian * The parent directory, because of the ordering 48541477Sjulian * guarantees, has had the link count incremented 48641477Sjulian * for the child, but no entry was made. This 48741477Sjulian * fixes the parent link count so that fsck does 48841477Sjulian * not need to be rerun. 48941477Sjulian */ 49041474Sjulian inoinfo(parentdir)->ino_linkcnt++; 49115699Snate } 4921558Srgrimes if (preen == 0) 4931558Srgrimes printf("\n"); 4941558Srgrimes } 4951558Srgrimes return (1); 4961558Srgrimes} 4971558Srgrimes 4981558Srgrimes/* 4991558Srgrimes * fix an entry in a directory. 5001558Srgrimes */ 5017585Sbdeint 502100935Sphkchangeino(ino_t dir, const char *name, ino_t newnum) 5031558Srgrimes{ 5041558Srgrimes struct inodesc idesc; 5051558Srgrimes 50623675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5071558Srgrimes idesc.id_type = DATA; 5081558Srgrimes idesc.id_func = chgino; 5091558Srgrimes idesc.id_number = dir; 5101558Srgrimes idesc.id_fix = DONTKNOW; 511100935Sphk idesc.id_name = strdup(name); 5121558Srgrimes idesc.id_parent = newnum; /* new value for name */ 5131558Srgrimes return (ckinode(ginode(dir), &idesc)); 5141558Srgrimes} 5151558Srgrimes 5161558Srgrimes/* 5171558Srgrimes * make an entry in a directory 5181558Srgrimes */ 5197585Sbdeint 520100935Sphkmakeentry(ino_t parent, ino_t ino, const char *name) 5211558Srgrimes{ 52298542Smckusick union dinode *dp; 5231558Srgrimes struct inodesc idesc; 5241558Srgrimes char pathbuf[MAXPATHLEN + 1]; 5258871Srgrimes 5261558Srgrimes if (parent < ROOTINO || parent >= maxino || 5271558Srgrimes ino < ROOTINO || ino >= maxino) 5281558Srgrimes return (0); 52923675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5301558Srgrimes idesc.id_type = DATA; 5311558Srgrimes idesc.id_func = mkentry; 5321558Srgrimes idesc.id_number = parent; 5331558Srgrimes idesc.id_parent = ino; /* this is the inode to enter */ 5341558Srgrimes idesc.id_fix = DONTKNOW; 535100935Sphk idesc.id_name = strdup(name); 5361558Srgrimes dp = ginode(parent); 53798542Smckusick if (DIP(dp, di_size) % DIRBLKSIZ) { 538134589Sscottl DIP_SET(dp, di_size, roundup(DIP(dp, di_size), DIRBLKSIZ)); 5391558Srgrimes inodirty(); 5401558Srgrimes } 5411558Srgrimes if ((ckinode(dp, &idesc) & ALTERED) != 0) 5421558Srgrimes return (1); 5431558Srgrimes getpathname(pathbuf, parent, parent); 5441558Srgrimes dp = ginode(parent); 5451558Srgrimes if (expanddir(dp, pathbuf) == 0) 5461558Srgrimes return (0); 5471558Srgrimes return (ckinode(dp, &idesc) & ALTERED); 5481558Srgrimes} 5491558Srgrimes 5501558Srgrimes/* 5511558Srgrimes * Attempt to expand the size of a directory 5521558Srgrimes */ 55323675Speterstatic int 55498542Smckusickexpanddir(union dinode *dp, char *name) 5551558Srgrimes{ 55698542Smckusick ufs2_daddr_t lastbn, newblk; 55792806Sobrien struct bufarea *bp; 5581558Srgrimes char *cp, firstblk[DIRBLKSIZ]; 5591558Srgrimes 56098542Smckusick lastbn = lblkno(&sblock, DIP(dp, di_size)); 56198542Smckusick if (lastbn >= NDADDR - 1 || DIP(dp, di_db[lastbn]) == 0 || 56298542Smckusick DIP(dp, di_size) == 0) 5631558Srgrimes return (0); 5641558Srgrimes if ((newblk = allocblk(sblock.fs_frag)) == 0) 5651558Srgrimes return (0); 566134589Sscottl DIP_SET(dp, di_db[lastbn + 1], DIP(dp, di_db[lastbn])); 567134589Sscottl DIP_SET(dp, di_db[lastbn], newblk); 568134589Sscottl DIP_SET(dp, di_size, DIP(dp, di_size) + sblock.fs_bsize); 569134589Sscottl DIP_SET(dp, di_blocks, DIP(dp, di_blocks) + btodb(sblock.fs_bsize)); 57098542Smckusick bp = getdirblk(DIP(dp, di_db[lastbn + 1]), 57198542Smckusick sblksize(&sblock, DIP(dp, di_size), lastbn + 1)); 5721558Srgrimes if (bp->b_errs) 5731558Srgrimes goto bad; 57423675Speter memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 5751558Srgrimes bp = getdirblk(newblk, sblock.fs_bsize); 5761558Srgrimes if (bp->b_errs) 5771558Srgrimes goto bad; 57823675Speter memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 5791558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 5801558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_bsize]; 5811558Srgrimes cp += DIRBLKSIZ) 58223675Speter memmove(cp, &emptydir, sizeof emptydir); 5831558Srgrimes dirty(bp); 58498542Smckusick bp = getdirblk(DIP(dp, di_db[lastbn + 1]), 58598542Smckusick sblksize(&sblock, DIP(dp, di_size), lastbn + 1)); 5861558Srgrimes if (bp->b_errs) 5871558Srgrimes goto bad; 58823675Speter memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 5891558Srgrimes pwarn("NO SPACE LEFT IN %s", name); 5901558Srgrimes if (preen) 5911558Srgrimes printf(" (EXPANDED)\n"); 5921558Srgrimes else if (reply("EXPAND") == 0) 5931558Srgrimes goto bad; 5941558Srgrimes dirty(bp); 5951558Srgrimes inodirty(); 5961558Srgrimes return (1); 5971558Srgrimesbad: 598134589Sscottl DIP_SET(dp, di_db[lastbn], DIP(dp, di_db[lastbn + 1])); 599134589Sscottl DIP_SET(dp, di_db[lastbn + 1], 0); 600134589Sscottl DIP_SET(dp, di_size, DIP(dp, di_size) - sblock.fs_bsize); 601134589Sscottl DIP_SET(dp, di_blocks, DIP(dp, di_blocks) - btodb(sblock.fs_bsize)); 6021558Srgrimes freeblk(newblk, sblock.fs_frag); 6031558Srgrimes return (0); 6041558Srgrimes} 6051558Srgrimes 6061558Srgrimes/* 6071558Srgrimes * allocate a new directory 6081558Srgrimes */ 6097586Sbdeino_t 61092839Simpallocdir(ino_t parent, ino_t request, int mode) 6111558Srgrimes{ 6121558Srgrimes ino_t ino; 6131558Srgrimes char *cp; 61498542Smckusick union dinode *dp; 61563810Smckusick struct bufarea *bp; 61663810Smckusick struct inoinfo *inp; 6171558Srgrimes struct dirtemplate *dirp; 6181558Srgrimes 6191558Srgrimes ino = allocino(request, IFDIR|mode); 62096483Sphk dirp = &dirhead; 6211558Srgrimes dirp->dot_ino = ino; 6221558Srgrimes dirp->dotdot_ino = parent; 6231558Srgrimes dp = ginode(ino); 62498542Smckusick bp = getdirblk(DIP(dp, di_db[0]), sblock.fs_fsize); 6251558Srgrimes if (bp->b_errs) { 6261558Srgrimes freeino(ino); 6271558Srgrimes return (0); 6281558Srgrimes } 62923675Speter memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 6301558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6311558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_fsize]; 6321558Srgrimes cp += DIRBLKSIZ) 63323675Speter memmove(cp, &emptydir, sizeof emptydir); 6341558Srgrimes dirty(bp); 635134589Sscottl DIP_SET(dp, di_nlink, 2); 6361558Srgrimes inodirty(); 6371558Srgrimes if (ino == ROOTINO) { 63898542Smckusick inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink); 6391558Srgrimes cacheino(dp, ino); 6401558Srgrimes return(ino); 6411558Srgrimes } 642136281Struckman if (!INO_IS_DVALID(parent)) { 6431558Srgrimes freeino(ino); 6441558Srgrimes return (0); 6451558Srgrimes } 6461558Srgrimes cacheino(dp, ino); 64763810Smckusick inp = getinoinfo(ino); 64863810Smckusick inp->i_parent = parent; 64963810Smckusick inp->i_dotdot = parent; 65041474Sjulian inoinfo(ino)->ino_state = inoinfo(parent)->ino_state; 65141474Sjulian if (inoinfo(ino)->ino_state == DSTATE) { 65298542Smckusick inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink); 65341474Sjulian inoinfo(parent)->ino_linkcnt++; 6541558Srgrimes } 6551558Srgrimes dp = ginode(parent); 656134589Sscottl DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1); 6571558Srgrimes inodirty(); 6581558Srgrimes return (ino); 6591558Srgrimes} 6601558Srgrimes 6611558Srgrimes/* 6621558Srgrimes * free a directory inode 6631558Srgrimes */ 6647585Sbdestatic void 66592839Simpfreedir(ino_t ino, ino_t parent) 6661558Srgrimes{ 66798542Smckusick union dinode *dp; 6681558Srgrimes 6691558Srgrimes if (ino != parent) { 6701558Srgrimes dp = ginode(parent); 671134589Sscottl DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - 1); 6721558Srgrimes inodirty(); 6731558Srgrimes } 6741558Srgrimes freeino(ino); 6751558Srgrimes} 6761558Srgrimes 6771558Srgrimes/* 6781558Srgrimes * generate a temporary name for the lost+found directory. 6791558Srgrimes */ 68023675Speterstatic int 68192839Simplftempname(char *bufp, ino_t ino) 6821558Srgrimes{ 68392806Sobrien ino_t in; 68492806Sobrien char *cp; 6851558Srgrimes int namlen; 6861558Srgrimes 6871558Srgrimes cp = bufp + 2; 6881558Srgrimes for (in = maxino; in > 0; in /= 10) 6891558Srgrimes cp++; 6901558Srgrimes *--cp = 0; 6911558Srgrimes namlen = cp - bufp; 6921558Srgrimes in = ino; 6931558Srgrimes while (cp > bufp) { 6941558Srgrimes *--cp = (in % 10) + '0'; 6951558Srgrimes in /= 10; 6961558Srgrimes } 6971558Srgrimes *cp = '#'; 6981558Srgrimes return (namlen); 6991558Srgrimes} 7001558Srgrimes 7011558Srgrimes/* 7021558Srgrimes * Get a directory block. 7031558Srgrimes * Insure that it is held until another is requested. 7041558Srgrimes */ 70523675Speterstatic struct bufarea * 70698542Smckusickgetdirblk(ufs2_daddr_t blkno, long size) 7071558Srgrimes{ 7081558Srgrimes 7091558Srgrimes if (pdirbp != 0) 7101558Srgrimes pdirbp->b_flags &= ~B_INUSE; 711249788Smckusick pdirbp = getdatablk(blkno, size, BT_DIRDATA); 7121558Srgrimes return (pdirbp); 7131558Srgrimes} 714