dir.c revision 41477
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1980, 1986, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 3541477Sjulian#if 0 3623675Speterstatic const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; 3741477Sjulian#endif 3841477Sjulianstatic const char rcsid[] = 3941477Sjulian "$Id: dir.c,v 1.12 1998/09/23 05:37:35 nate Exp $"; 401558Srgrimes#endif /* not lint */ 411558Srgrimes 421558Srgrimes#include <sys/param.h> 4341474Sjulian#include <sys/time.h> 4423675Speter 451558Srgrimes#include <ufs/ufs/dinode.h> 461558Srgrimes#include <ufs/ufs/dir.h> 471558Srgrimes#include <ufs/ffs/fs.h> 4823796Sbde 4923675Speter#include <err.h> 501558Srgrimes#include <string.h> 5123675Speter 521558Srgrimes#include "fsck.h" 531558Srgrimes 541558Srgrimeschar *lfname = "lost+found"; 551558Srgrimesint lfmode = 01777; 561558Srgrimesstruct dirtemplate emptydir = { 0, DIRBLKSIZ }; 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 6623675Speterstatic int chgino __P((struct inodesc *)); 6723675Speterstatic int dircheck __P((struct inodesc *, struct direct *)); 6823675Speterstatic int expanddir __P((struct dinode *dp, char *name)); 6923675Speterstatic void freedir __P((ino_t ino, ino_t parent)); 7023675Speterstatic struct direct *fsck_readdir __P((struct inodesc *)); 7123675Speterstatic struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size)); 7223675Speterstatic int lftempname __P((char *bufp, ino_t ino)); 7323675Speterstatic int mkentry __P((struct inodesc *)); 741558Srgrimes 751558Srgrimes/* 761558Srgrimes * Propagate connected state through the tree. 771558Srgrimes */ 787585Sbdevoid 791558Srgrimespropagate() 801558Srgrimes{ 811558Srgrimes register 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 && 9341474Sjulian inoinfo(inp->i_number)->ino_state == DSTATE) { 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 1051558Srgrimesdirscan(idesc) 1061558Srgrimes register struct inodesc *idesc; 1071558Srgrimes{ 1081558Srgrimes register struct direct *dp; 1091558Srgrimes register struct bufarea *bp; 1101558Srgrimes int dsize, n; 1111558Srgrimes long blksiz; 1121558Srgrimes char dbuf[DIRBLKSIZ]; 1131558Srgrimes 1141558Srgrimes if (idesc->id_type != DATA) 11523675Speter errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 1161558Srgrimes if (idesc->id_entryno == 0 && 1171558Srgrimes (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 1181558Srgrimes idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 1191558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1201558Srgrimes if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 1211558Srgrimes idesc->id_filesize -= blksiz; 1221558Srgrimes return (SKIP); 1231558Srgrimes } 1241558Srgrimes idesc->id_loc = 0; 1251558Srgrimes for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 1261558Srgrimes dsize = dp->d_reclen; 12741474Sjulian if (dsize > sizeof(dbuf)) 12841474Sjulian dsize = sizeof(dbuf); 12923675Speter memmove(dbuf, dp, (size_t)dsize); 1301558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1311558Srgrimes if (!newinofmt) { 1321558Srgrimes struct direct *tdp = (struct direct *)dbuf; 1331558Srgrimes u_char tmp; 1341558Srgrimes 1351558Srgrimes tmp = tdp->d_namlen; 1361558Srgrimes tdp->d_namlen = tdp->d_type; 1371558Srgrimes tdp->d_type = tmp; 1381558Srgrimes } 1391558Srgrimes# endif 1401558Srgrimes idesc->id_dirp = (struct direct *)dbuf; 1411558Srgrimes if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 1421558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1431558Srgrimes if (!newinofmt && !doinglevel2) { 1441558Srgrimes struct direct *tdp; 1451558Srgrimes u_char tmp; 1461558Srgrimes 1471558Srgrimes tdp = (struct direct *)dbuf; 1481558Srgrimes tmp = tdp->d_namlen; 1491558Srgrimes tdp->d_namlen = tdp->d_type; 1501558Srgrimes tdp->d_type = tmp; 1511558Srgrimes } 1521558Srgrimes# endif 1531558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 15423675Speter memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 1551558Srgrimes (size_t)dsize); 1561558Srgrimes dirty(bp); 1571558Srgrimes sbdirty(); 1581558Srgrimes } 1598871Srgrimes if (n & STOP) 1601558Srgrimes return (n); 1611558Srgrimes } 1621558Srgrimes return (idesc->id_filesize > 0 ? KEEPON : STOP); 1631558Srgrimes} 1641558Srgrimes 1651558Srgrimes/* 1661558Srgrimes * get next entry in a directory. 1671558Srgrimes */ 16823675Speterstatic struct direct * 1691558Srgrimesfsck_readdir(idesc) 1701558Srgrimes register struct inodesc *idesc; 1711558Srgrimes{ 1721558Srgrimes register struct direct *dp, *ndp; 1731558Srgrimes register struct bufarea *bp; 1741558Srgrimes long size, blksiz, fix, dploc; 1751558Srgrimes 1761558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1771558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1781558Srgrimes if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 1791558Srgrimes idesc->id_loc < blksiz) { 1801558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1811558Srgrimes if (dircheck(idesc, dp)) 1821558Srgrimes goto dpok; 18323675Speter if (idesc->id_fix == IGNORE) 18423675Speter return (0); 1851558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1861558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1871558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1881558Srgrimes dp->d_reclen = DIRBLKSIZ; 1891558Srgrimes dp->d_ino = 0; 1901558Srgrimes dp->d_type = 0; 1911558Srgrimes dp->d_namlen = 0; 1921558Srgrimes dp->d_name[0] = '\0'; 1931558Srgrimes if (fix) 1941558Srgrimes dirty(bp); 1951558Srgrimes idesc->id_loc += DIRBLKSIZ; 1961558Srgrimes idesc->id_filesize -= DIRBLKSIZ; 1971558Srgrimes return (dp); 1981558Srgrimes } 1991558Srgrimesdpok: 2001558Srgrimes if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 2011558Srgrimes return NULL; 2021558Srgrimes dploc = idesc->id_loc; 2031558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2041558Srgrimes idesc->id_loc += dp->d_reclen; 2051558Srgrimes idesc->id_filesize -= dp->d_reclen; 2061558Srgrimes if ((idesc->id_loc % DIRBLKSIZ) == 0) 2071558Srgrimes return (dp); 2081558Srgrimes ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 2091558Srgrimes if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 2101558Srgrimes dircheck(idesc, ndp) == 0) { 2111558Srgrimes size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 2121558Srgrimes idesc->id_loc += size; 2131558Srgrimes idesc->id_filesize -= size; 21423675Speter if (idesc->id_fix == IGNORE) 21523675Speter return (0); 2161558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 2171558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 2181558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2191558Srgrimes dp->d_reclen += size; 2201558Srgrimes if (fix) 2211558Srgrimes dirty(bp); 2221558Srgrimes } 2231558Srgrimes return (dp); 2241558Srgrimes} 2251558Srgrimes 2261558Srgrimes/* 2271558Srgrimes * Verify that a directory entry is valid. 2281558Srgrimes * This is a superset of the checks made in the kernel. 2291558Srgrimes */ 23023675Speterstatic int 2311558Srgrimesdircheck(idesc, dp) 2321558Srgrimes struct inodesc *idesc; 2331558Srgrimes register struct direct *dp; 2341558Srgrimes{ 2351558Srgrimes register int size; 2361558Srgrimes register char *cp; 2371558Srgrimes u_char namlen, type; 2381558Srgrimes int spaceleft; 2391558Srgrimes 24023675Speter spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 24141474Sjulian if (dp->d_reclen == 0 || 24223675Speter dp->d_reclen > spaceleft || 24323675Speter (dp->d_reclen & 0x3) != 0) 24423675Speter return (0); 24523675Speter if (dp->d_ino == 0) 24623675Speter return (1); 2471558Srgrimes size = DIRSIZ(!newinofmt, dp); 2481558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 2491558Srgrimes if (!newinofmt) { 2501558Srgrimes type = dp->d_namlen; 2511558Srgrimes namlen = dp->d_type; 2521558Srgrimes } else { 2531558Srgrimes namlen = dp->d_namlen; 2541558Srgrimes type = dp->d_type; 2551558Srgrimes } 2561558Srgrimes# else 2571558Srgrimes namlen = dp->d_namlen; 2581558Srgrimes type = dp->d_type; 2591558Srgrimes# endif 26023675Speter if (dp->d_reclen < size || 26123675Speter idesc->id_filesize < size || 26223675Speter namlen > MAXNAMLEN || 26323675Speter type > 15) 26423675Speter return (0); 26523675Speter for (cp = dp->d_name, size = 0; size < namlen; size++) 26623675Speter if (*cp == '\0' || (*cp++ == '/')) 26723675Speter return (0); 26823675Speter if (*cp != '\0') 26923675Speter return (0); 27023675Speter return (1); 2711558Srgrimes} 2721558Srgrimes 2737585Sbdevoid 2741558Srgrimesdirerror(ino, errmesg) 2751558Srgrimes ino_t ino; 2761558Srgrimes char *errmesg; 2771558Srgrimes{ 2781558Srgrimes 2791558Srgrimes fileerror(ino, ino, errmesg); 2801558Srgrimes} 2811558Srgrimes 2827585Sbdevoid 2831558Srgrimesfileerror(cwd, ino, errmesg) 2841558Srgrimes ino_t cwd, ino; 2851558Srgrimes char *errmesg; 2861558Srgrimes{ 2871558Srgrimes register struct dinode *dp; 2881558Srgrimes char pathbuf[MAXPATHLEN + 1]; 2891558Srgrimes 2901558Srgrimes pwarn("%s ", errmesg); 2911558Srgrimes pinode(ino); 2921558Srgrimes printf("\n"); 2931558Srgrimes getpathname(pathbuf, cwd, ino); 2941558Srgrimes if (ino < ROOTINO || ino > maxino) { 2951558Srgrimes pfatal("NAME=%s\n", pathbuf); 2961558Srgrimes return; 2971558Srgrimes } 2981558Srgrimes dp = ginode(ino); 2991558Srgrimes if (ftypeok(dp)) 3001558Srgrimes pfatal("%s=%s\n", 3011558Srgrimes (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 3021558Srgrimes else 3031558Srgrimes pfatal("NAME=%s\n", pathbuf); 3041558Srgrimes} 3051558Srgrimes 3067585Sbdevoid 3071558Srgrimesadjust(idesc, lcnt) 3081558Srgrimes register struct inodesc *idesc; 30923675Speter int lcnt; 3101558Srgrimes{ 31141474Sjulian struct dinode *dp; 31241474Sjulian int saveresolved; 3131558Srgrimes 3141558Srgrimes dp = ginode(idesc->id_number); 3151558Srgrimes if (dp->di_nlink == lcnt) { 31641474Sjulian /* 31741474Sjulian * If we have not hit any unresolved problems, are running 31841474Sjulian * in preen mode, and are on a filesystem using soft updates, 31941474Sjulian * then just toss any partially allocated files. 32041474Sjulian */ 32141474Sjulian if (resolved && preen && usedsoftdep) { 32241474Sjulian clri(idesc, "UNREF", 1); 32341474Sjulian return; 32441474Sjulian } else { 32541474Sjulian /* 32641474Sjulian * The filesystem can be marked clean even if 32741474Sjulian * a file is not linked up, but is cleared. 32841474Sjulian * Hence, resolved should not be cleared when 32941474Sjulian * linkup is answered no, but clri is answered yes. 33041474Sjulian */ 33141474Sjulian saveresolved = resolved; 33241474Sjulian if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) { 33341474Sjulian resolved = saveresolved; 33441474Sjulian clri(idesc, "UNREF", 0); 33541474Sjulian return; 33641474Sjulian } 33741474Sjulian /* 33841474Sjulian * Account for the new reference created by linkup(). 33941474Sjulian */ 34041474Sjulian dp = ginode(idesc->id_number); 34141474Sjulian lcnt--; 34241474Sjulian } 34341474Sjulian } 34441474Sjulian if (lcnt != 0) { 3451558Srgrimes pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 3461558Srgrimes ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 3471558Srgrimes pinode(idesc->id_number); 3481558Srgrimes printf(" COUNT %d SHOULD BE %d", 3491558Srgrimes dp->di_nlink, dp->di_nlink - lcnt); 35034266Sjulian if (preen || usedsoftdep) { 3511558Srgrimes if (lcnt < 0) { 3521558Srgrimes printf("\n"); 3531558Srgrimes pfatal("LINK COUNT INCREASING"); 3541558Srgrimes } 35534266Sjulian if (preen) 35634266Sjulian printf(" (ADJUSTED)\n"); 3571558Srgrimes } 3581558Srgrimes if (preen || reply("ADJUST") == 1) { 3591558Srgrimes dp->di_nlink -= lcnt; 3601558Srgrimes inodirty(); 3611558Srgrimes } 3621558Srgrimes } 3631558Srgrimes} 3641558Srgrimes 36523675Speterstatic int 3661558Srgrimesmkentry(idesc) 3671558Srgrimes struct inodesc *idesc; 3681558Srgrimes{ 3691558Srgrimes register struct direct *dirp = idesc->id_dirp; 3701558Srgrimes struct direct newent; 3711558Srgrimes int newlen, oldlen; 3721558Srgrimes 3731558Srgrimes newent.d_namlen = strlen(idesc->id_name); 3741558Srgrimes newlen = DIRSIZ(0, &newent); 3751558Srgrimes if (dirp->d_ino != 0) 3761558Srgrimes oldlen = DIRSIZ(0, dirp); 3771558Srgrimes else 3781558Srgrimes oldlen = 0; 3791558Srgrimes if (dirp->d_reclen - oldlen < newlen) 3801558Srgrimes return (KEEPON); 3811558Srgrimes newent.d_reclen = dirp->d_reclen - oldlen; 3821558Srgrimes dirp->d_reclen = oldlen; 3831558Srgrimes dirp = (struct direct *)(((char *)dirp) + oldlen); 3841558Srgrimes dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 38523675Speter dirp->d_reclen = newent.d_reclen; 38623675Speter if (newinofmt) 38741474Sjulian dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 38823675Speter else 38923675Speter dirp->d_type = 0; 39023675Speter dirp->d_namlen = newent.d_namlen; 39123675Speter memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 39223675Speter# if (BYTE_ORDER == LITTLE_ENDIAN) 39323675Speter /* 39423675Speter * If the entry was split, dirscan() will only reverse the byte 39523675Speter * order of the original entry, and not the new one, before 39623675Speter * writing it back out. So, we reverse the byte order here if 39723675Speter * necessary. 39823675Speter */ 39923675Speter if (oldlen != 0 && !newinofmt && !doinglevel2) { 40023675Speter u_char tmp; 40123675Speter 40223675Speter tmp = dirp->d_namlen; 40323675Speter dirp->d_namlen = dirp->d_type; 40423675Speter dirp->d_type = tmp; 40523675Speter } 40623675Speter# endif 4071558Srgrimes return (ALTERED|STOP); 4081558Srgrimes} 4091558Srgrimes 41023675Speterstatic int 4111558Srgrimeschgino(idesc) 4121558Srgrimes struct inodesc *idesc; 4131558Srgrimes{ 4141558Srgrimes register struct direct *dirp = idesc->id_dirp; 4151558Srgrimes 41623675Speter if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 4171558Srgrimes return (KEEPON); 4181558Srgrimes dirp->d_ino = idesc->id_parent; 4191558Srgrimes if (newinofmt) 42041474Sjulian dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 4211558Srgrimes else 4221558Srgrimes dirp->d_type = 0; 4231558Srgrimes return (ALTERED|STOP); 4241558Srgrimes} 4251558Srgrimes 4267585Sbdeint 42741474Sjulianlinkup(orphan, parentdir, name) 4281558Srgrimes ino_t orphan; 4291558Srgrimes ino_t parentdir; 43041474Sjulian char *name; 4311558Srgrimes{ 4321558Srgrimes register struct dinode *dp; 4331558Srgrimes int lostdir; 4341558Srgrimes ino_t oldlfdir; 4351558Srgrimes struct inodesc idesc; 4361558Srgrimes char tempname[BUFSIZ]; 4371558Srgrimes 43823675Speter memset(&idesc, 0, sizeof(struct inodesc)); 4391558Srgrimes dp = ginode(orphan); 4401558Srgrimes lostdir = (dp->di_mode & IFMT) == IFDIR; 4411558Srgrimes pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 4421558Srgrimes pinode(orphan); 44341474Sjulian if (preen && dp->di_size == 0) 4441558Srgrimes return (0); 4451558Srgrimes if (preen) 4461558Srgrimes printf(" (RECONNECTED)\n"); 4471558Srgrimes else 4481558Srgrimes if (reply("RECONNECT") == 0) 4491558Srgrimes return (0); 4501558Srgrimes if (lfdir == 0) { 4511558Srgrimes dp = ginode(ROOTINO); 4521558Srgrimes idesc.id_name = lfname; 4531558Srgrimes idesc.id_type = DATA; 4541558Srgrimes idesc.id_func = findino; 4551558Srgrimes idesc.id_number = ROOTINO; 4561558Srgrimes if ((ckinode(dp, &idesc) & FOUND) != 0) { 4571558Srgrimes lfdir = idesc.id_parent; 4581558Srgrimes } else { 4591558Srgrimes pwarn("NO lost+found DIRECTORY"); 4601558Srgrimes if (preen || reply("CREATE")) { 4611558Srgrimes lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 4621558Srgrimes if (lfdir != 0) { 4631558Srgrimes if (makeentry(ROOTINO, lfdir, lfname) != 0) { 46441474Sjulian numdirs++; 4651558Srgrimes if (preen) 4661558Srgrimes printf(" (CREATED)\n"); 4671558Srgrimes } else { 4681558Srgrimes freedir(lfdir, ROOTINO); 4691558Srgrimes lfdir = 0; 4701558Srgrimes if (preen) 4711558Srgrimes printf("\n"); 4721558Srgrimes } 4731558Srgrimes } 4741558Srgrimes } 4751558Srgrimes } 4761558Srgrimes if (lfdir == 0) { 4771558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 4781558Srgrimes printf("\n\n"); 4791558Srgrimes return (0); 4801558Srgrimes } 4811558Srgrimes } 4821558Srgrimes dp = ginode(lfdir); 4831558Srgrimes if ((dp->di_mode & IFMT) != IFDIR) { 4841558Srgrimes pfatal("lost+found IS NOT A DIRECTORY"); 4851558Srgrimes if (reply("REALLOCATE") == 0) 4861558Srgrimes return (0); 4871558Srgrimes oldlfdir = lfdir; 4881558Srgrimes if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 4891558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4901558Srgrimes return (0); 4911558Srgrimes } 4921558Srgrimes if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 4931558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4941558Srgrimes return (0); 4951558Srgrimes } 4961558Srgrimes inodirty(); 4971558Srgrimes idesc.id_type = ADDR; 4981558Srgrimes idesc.id_func = pass4check; 4991558Srgrimes idesc.id_number = oldlfdir; 50041474Sjulian adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1); 50141474Sjulian inoinfo(oldlfdir)->ino_linkcnt = 0; 5021558Srgrimes dp = ginode(lfdir); 5031558Srgrimes } 50441474Sjulian if (inoinfo(lfdir)->ino_state != DFOUND) { 5051558Srgrimes pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 5061558Srgrimes return (0); 5071558Srgrimes } 5081558Srgrimes (void)lftempname(tempname, orphan); 50941474Sjulian if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) { 5101558Srgrimes pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 5111558Srgrimes printf("\n\n"); 5121558Srgrimes return (0); 5131558Srgrimes } 51441474Sjulian inoinfo(orphan)->ino_linkcnt--; 5151558Srgrimes if (lostdir) { 5161558Srgrimes if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 5171558Srgrimes parentdir != (ino_t)-1) 5181558Srgrimes (void)makeentry(orphan, lfdir, ".."); 5191558Srgrimes dp = ginode(lfdir); 5201558Srgrimes dp->di_nlink++; 5211558Srgrimes inodirty(); 52241474Sjulian inoinfo(lfdir)->ino_linkcnt++; 5231558Srgrimes pwarn("DIR I=%lu CONNECTED. ", orphan); 52415699Snate if (parentdir != (ino_t)-1) { 52537236Sbde printf("PARENT WAS I=%lu\n", (u_long)parentdir); 52641477Sjulian /* 52741477Sjulian * The parent directory, because of the ordering 52841477Sjulian * guarantees, has had the link count incremented 52941477Sjulian * for the child, but no entry was made. This 53041477Sjulian * fixes the parent link count so that fsck does 53141477Sjulian * not need to be rerun. 53241477Sjulian */ 53341474Sjulian inoinfo(parentdir)->ino_linkcnt++; 53415699Snate } 5351558Srgrimes if (preen == 0) 5361558Srgrimes printf("\n"); 5371558Srgrimes } 5381558Srgrimes return (1); 5391558Srgrimes} 5401558Srgrimes 5411558Srgrimes/* 5421558Srgrimes * fix an entry in a directory. 5431558Srgrimes */ 5447585Sbdeint 5451558Srgrimeschangeino(dir, name, newnum) 5461558Srgrimes ino_t dir; 5471558Srgrimes char *name; 5481558Srgrimes ino_t newnum; 5491558Srgrimes{ 5501558Srgrimes struct inodesc idesc; 5511558Srgrimes 55223675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5531558Srgrimes idesc.id_type = DATA; 5541558Srgrimes idesc.id_func = chgino; 5551558Srgrimes idesc.id_number = dir; 5561558Srgrimes idesc.id_fix = DONTKNOW; 5571558Srgrimes idesc.id_name = name; 5581558Srgrimes idesc.id_parent = newnum; /* new value for name */ 5591558Srgrimes return (ckinode(ginode(dir), &idesc)); 5601558Srgrimes} 5611558Srgrimes 5621558Srgrimes/* 5631558Srgrimes * make an entry in a directory 5641558Srgrimes */ 5657585Sbdeint 5661558Srgrimesmakeentry(parent, ino, name) 5671558Srgrimes ino_t parent, ino; 5681558Srgrimes char *name; 5691558Srgrimes{ 5701558Srgrimes struct dinode *dp; 5711558Srgrimes struct inodesc idesc; 5721558Srgrimes char pathbuf[MAXPATHLEN + 1]; 5738871Srgrimes 5741558Srgrimes if (parent < ROOTINO || parent >= maxino || 5751558Srgrimes ino < ROOTINO || ino >= maxino) 5761558Srgrimes return (0); 57723675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5781558Srgrimes idesc.id_type = DATA; 5791558Srgrimes idesc.id_func = mkentry; 5801558Srgrimes idesc.id_number = parent; 5811558Srgrimes idesc.id_parent = ino; /* this is the inode to enter */ 5821558Srgrimes idesc.id_fix = DONTKNOW; 5831558Srgrimes idesc.id_name = name; 5841558Srgrimes dp = ginode(parent); 5851558Srgrimes if (dp->di_size % DIRBLKSIZ) { 5861558Srgrimes dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 5871558Srgrimes inodirty(); 5881558Srgrimes } 5891558Srgrimes if ((ckinode(dp, &idesc) & ALTERED) != 0) 5901558Srgrimes return (1); 5911558Srgrimes getpathname(pathbuf, parent, parent); 5921558Srgrimes dp = ginode(parent); 5931558Srgrimes if (expanddir(dp, pathbuf) == 0) 5941558Srgrimes return (0); 5951558Srgrimes return (ckinode(dp, &idesc) & ALTERED); 5961558Srgrimes} 5971558Srgrimes 5981558Srgrimes/* 5991558Srgrimes * Attempt to expand the size of a directory 6001558Srgrimes */ 60123675Speterstatic int 6021558Srgrimesexpanddir(dp, name) 6031558Srgrimes register struct dinode *dp; 6041558Srgrimes char *name; 6051558Srgrimes{ 60623675Speter ufs_daddr_t lastbn, newblk; 6071558Srgrimes register struct bufarea *bp; 6081558Srgrimes char *cp, firstblk[DIRBLKSIZ]; 6091558Srgrimes 6101558Srgrimes lastbn = lblkno(&sblock, dp->di_size); 6111558Srgrimes if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 6121558Srgrimes return (0); 6131558Srgrimes if ((newblk = allocblk(sblock.fs_frag)) == 0) 6141558Srgrimes return (0); 6151558Srgrimes dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 6161558Srgrimes dp->di_db[lastbn] = newblk; 6171558Srgrimes dp->di_size += sblock.fs_bsize; 6181558Srgrimes dp->di_blocks += btodb(sblock.fs_bsize); 6191558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 6201558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 6211558Srgrimes if (bp->b_errs) 6221558Srgrimes goto bad; 62323675Speter memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 6241558Srgrimes bp = getdirblk(newblk, sblock.fs_bsize); 6251558Srgrimes if (bp->b_errs) 6261558Srgrimes goto bad; 62723675Speter memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 6281558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6291558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_bsize]; 6301558Srgrimes cp += DIRBLKSIZ) 63123675Speter memmove(cp, &emptydir, sizeof emptydir); 6321558Srgrimes dirty(bp); 6331558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 6341558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 6351558Srgrimes if (bp->b_errs) 6361558Srgrimes goto bad; 63723675Speter memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 6381558Srgrimes pwarn("NO SPACE LEFT IN %s", name); 6391558Srgrimes if (preen) 6401558Srgrimes printf(" (EXPANDED)\n"); 6411558Srgrimes else if (reply("EXPAND") == 0) 6421558Srgrimes goto bad; 6431558Srgrimes dirty(bp); 6441558Srgrimes inodirty(); 6451558Srgrimes return (1); 6461558Srgrimesbad: 6471558Srgrimes dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 6481558Srgrimes dp->di_db[lastbn + 1] = 0; 6491558Srgrimes dp->di_size -= sblock.fs_bsize; 6501558Srgrimes dp->di_blocks -= btodb(sblock.fs_bsize); 6511558Srgrimes freeblk(newblk, sblock.fs_frag); 6521558Srgrimes return (0); 6531558Srgrimes} 6541558Srgrimes 6551558Srgrimes/* 6561558Srgrimes * allocate a new directory 6571558Srgrimes */ 6587586Sbdeino_t 6591558Srgrimesallocdir(parent, request, mode) 6601558Srgrimes ino_t parent, request; 6611558Srgrimes int mode; 6621558Srgrimes{ 6631558Srgrimes ino_t ino; 6641558Srgrimes char *cp; 6651558Srgrimes struct dinode *dp; 6661558Srgrimes register struct bufarea *bp; 6671558Srgrimes struct dirtemplate *dirp; 6681558Srgrimes 6691558Srgrimes ino = allocino(request, IFDIR|mode); 6701558Srgrimes if (newinofmt) 6711558Srgrimes dirp = &dirhead; 6721558Srgrimes else 6731558Srgrimes dirp = (struct dirtemplate *)&odirhead; 6741558Srgrimes dirp->dot_ino = ino; 6751558Srgrimes dirp->dotdot_ino = parent; 6761558Srgrimes dp = ginode(ino); 6771558Srgrimes bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 6781558Srgrimes if (bp->b_errs) { 6791558Srgrimes freeino(ino); 6801558Srgrimes return (0); 6811558Srgrimes } 68223675Speter memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 6831558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6841558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_fsize]; 6851558Srgrimes cp += DIRBLKSIZ) 68623675Speter memmove(cp, &emptydir, sizeof emptydir); 6871558Srgrimes dirty(bp); 6881558Srgrimes dp->di_nlink = 2; 6891558Srgrimes inodirty(); 6901558Srgrimes if (ino == ROOTINO) { 69141474Sjulian inoinfo(ino)->ino_linkcnt = dp->di_nlink; 6921558Srgrimes cacheino(dp, ino); 6931558Srgrimes return(ino); 6941558Srgrimes } 69541474Sjulian if (inoinfo(parent)->ino_state != DSTATE && 69641474Sjulian inoinfo(parent)->ino_state != DFOUND) { 6971558Srgrimes freeino(ino); 6981558Srgrimes return (0); 6991558Srgrimes } 7001558Srgrimes cacheino(dp, ino); 70141474Sjulian inoinfo(ino)->ino_state = inoinfo(parent)->ino_state; 70241474Sjulian if (inoinfo(ino)->ino_state == DSTATE) { 70341474Sjulian inoinfo(ino)->ino_linkcnt = dp->di_nlink; 70441474Sjulian inoinfo(parent)->ino_linkcnt++; 7051558Srgrimes } 7061558Srgrimes dp = ginode(parent); 7071558Srgrimes dp->di_nlink++; 7081558Srgrimes inodirty(); 7091558Srgrimes return (ino); 7101558Srgrimes} 7111558Srgrimes 7121558Srgrimes/* 7131558Srgrimes * free a directory inode 7141558Srgrimes */ 7157585Sbdestatic void 7161558Srgrimesfreedir(ino, parent) 7171558Srgrimes ino_t ino, parent; 7181558Srgrimes{ 7191558Srgrimes struct dinode *dp; 7201558Srgrimes 7211558Srgrimes if (ino != parent) { 7221558Srgrimes dp = ginode(parent); 7231558Srgrimes dp->di_nlink--; 7241558Srgrimes inodirty(); 7251558Srgrimes } 7261558Srgrimes freeino(ino); 7271558Srgrimes} 7281558Srgrimes 7291558Srgrimes/* 7301558Srgrimes * generate a temporary name for the lost+found directory. 7311558Srgrimes */ 73223675Speterstatic int 7331558Srgrimeslftempname(bufp, ino) 7341558Srgrimes char *bufp; 7351558Srgrimes ino_t ino; 7361558Srgrimes{ 7371558Srgrimes register ino_t in; 7381558Srgrimes register char *cp; 7391558Srgrimes int namlen; 7401558Srgrimes 7411558Srgrimes cp = bufp + 2; 7421558Srgrimes for (in = maxino; in > 0; in /= 10) 7431558Srgrimes cp++; 7441558Srgrimes *--cp = 0; 7451558Srgrimes namlen = cp - bufp; 7461558Srgrimes in = ino; 7471558Srgrimes while (cp > bufp) { 7481558Srgrimes *--cp = (in % 10) + '0'; 7491558Srgrimes in /= 10; 7501558Srgrimes } 7511558Srgrimes *cp = '#'; 7521558Srgrimes return (namlen); 7531558Srgrimes} 7541558Srgrimes 7551558Srgrimes/* 7561558Srgrimes * Get a directory block. 7571558Srgrimes * Insure that it is held until another is requested. 7581558Srgrimes */ 75923675Speterstatic struct bufarea * 7601558Srgrimesgetdirblk(blkno, size) 76123675Speter ufs_daddr_t blkno; 7621558Srgrimes long size; 7631558Srgrimes{ 7641558Srgrimes 7651558Srgrimes if (pdirbp != 0) 7661558Srgrimes pdirbp->b_flags &= ~B_INUSE; 7671558Srgrimes pdirbp = getdatablk(blkno, size); 7681558Srgrimes return (pdirbp); 7691558Srgrimes} 770