dir.c revision 41474
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 3523675Speterstatic const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; 361558Srgrimes#endif /* not lint */ 371558Srgrimes 381558Srgrimes#include <sys/param.h> 3941474Sjulian#include <sys/time.h> 4023675Speter 411558Srgrimes#include <ufs/ufs/dinode.h> 421558Srgrimes#include <ufs/ufs/dir.h> 431558Srgrimes#include <ufs/ffs/fs.h> 4423796Sbde 4523675Speter#include <err.h> 461558Srgrimes#include <string.h> 4723675Speter 481558Srgrimes#include "fsck.h" 491558Srgrimes 501558Srgrimeschar *lfname = "lost+found"; 511558Srgrimesint lfmode = 01777; 521558Srgrimesstruct dirtemplate emptydir = { 0, DIRBLKSIZ }; 531558Srgrimesstruct dirtemplate dirhead = { 541558Srgrimes 0, 12, DT_DIR, 1, ".", 551558Srgrimes 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 561558Srgrimes}; 571558Srgrimesstruct odirtemplate odirhead = { 581558Srgrimes 0, 12, 1, ".", 591558Srgrimes 0, DIRBLKSIZ - 12, 2, ".." 601558Srgrimes}; 611558Srgrimes 6223675Speterstatic int chgino __P((struct inodesc *)); 6323675Speterstatic int dircheck __P((struct inodesc *, struct direct *)); 6423675Speterstatic int expanddir __P((struct dinode *dp, char *name)); 6523675Speterstatic void freedir __P((ino_t ino, ino_t parent)); 6623675Speterstatic struct direct *fsck_readdir __P((struct inodesc *)); 6723675Speterstatic struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size)); 6823675Speterstatic int lftempname __P((char *bufp, ino_t ino)); 6923675Speterstatic int mkentry __P((struct inodesc *)); 701558Srgrimes 711558Srgrimes/* 721558Srgrimes * Propagate connected state through the tree. 731558Srgrimes */ 747585Sbdevoid 751558Srgrimespropagate() 761558Srgrimes{ 771558Srgrimes register struct inoinfo **inpp, *inp; 781558Srgrimes struct inoinfo **inpend; 791558Srgrimes long change; 801558Srgrimes 811558Srgrimes inpend = &inpsort[inplast]; 821558Srgrimes do { 831558Srgrimes change = 0; 841558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 851558Srgrimes inp = *inpp; 861558Srgrimes if (inp->i_parent == 0) 871558Srgrimes continue; 8841474Sjulian if (inoinfo(inp->i_parent)->ino_state == DFOUND && 8941474Sjulian inoinfo(inp->i_number)->ino_state == DSTATE) { 9041474Sjulian inoinfo(inp->i_number)->ino_state = DFOUND; 911558Srgrimes change++; 921558Srgrimes } 931558Srgrimes } 941558Srgrimes } while (change > 0); 951558Srgrimes} 961558Srgrimes 971558Srgrimes/* 981558Srgrimes * Scan each entry in a directory block. 991558Srgrimes */ 1007585Sbdeint 1011558Srgrimesdirscan(idesc) 1021558Srgrimes register struct inodesc *idesc; 1031558Srgrimes{ 1041558Srgrimes register struct direct *dp; 1051558Srgrimes register struct bufarea *bp; 1061558Srgrimes int dsize, n; 1071558Srgrimes long blksiz; 1081558Srgrimes char dbuf[DIRBLKSIZ]; 1091558Srgrimes 1101558Srgrimes if (idesc->id_type != DATA) 11123675Speter errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 1121558Srgrimes if (idesc->id_entryno == 0 && 1131558Srgrimes (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 1141558Srgrimes idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 1151558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1161558Srgrimes if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 1171558Srgrimes idesc->id_filesize -= blksiz; 1181558Srgrimes return (SKIP); 1191558Srgrimes } 1201558Srgrimes idesc->id_loc = 0; 1211558Srgrimes for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 1221558Srgrimes dsize = dp->d_reclen; 12341474Sjulian if (dsize > sizeof(dbuf)) 12441474Sjulian dsize = sizeof(dbuf); 12523675Speter memmove(dbuf, dp, (size_t)dsize); 1261558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1271558Srgrimes if (!newinofmt) { 1281558Srgrimes struct direct *tdp = (struct direct *)dbuf; 1291558Srgrimes u_char tmp; 1301558Srgrimes 1311558Srgrimes tmp = tdp->d_namlen; 1321558Srgrimes tdp->d_namlen = tdp->d_type; 1331558Srgrimes tdp->d_type = tmp; 1341558Srgrimes } 1351558Srgrimes# endif 1361558Srgrimes idesc->id_dirp = (struct direct *)dbuf; 1371558Srgrimes if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 1381558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1391558Srgrimes if (!newinofmt && !doinglevel2) { 1401558Srgrimes struct direct *tdp; 1411558Srgrimes u_char tmp; 1421558Srgrimes 1431558Srgrimes tdp = (struct direct *)dbuf; 1441558Srgrimes tmp = tdp->d_namlen; 1451558Srgrimes tdp->d_namlen = tdp->d_type; 1461558Srgrimes tdp->d_type = tmp; 1471558Srgrimes } 1481558Srgrimes# endif 1491558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 15023675Speter memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 1511558Srgrimes (size_t)dsize); 1521558Srgrimes dirty(bp); 1531558Srgrimes sbdirty(); 1541558Srgrimes } 1558871Srgrimes if (n & STOP) 1561558Srgrimes return (n); 1571558Srgrimes } 1581558Srgrimes return (idesc->id_filesize > 0 ? KEEPON : STOP); 1591558Srgrimes} 1601558Srgrimes 1611558Srgrimes/* 1621558Srgrimes * get next entry in a directory. 1631558Srgrimes */ 16423675Speterstatic struct direct * 1651558Srgrimesfsck_readdir(idesc) 1661558Srgrimes register struct inodesc *idesc; 1671558Srgrimes{ 1681558Srgrimes register struct direct *dp, *ndp; 1691558Srgrimes register struct bufarea *bp; 1701558Srgrimes long size, blksiz, fix, dploc; 1711558Srgrimes 1721558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1731558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1741558Srgrimes if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 1751558Srgrimes idesc->id_loc < blksiz) { 1761558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1771558Srgrimes if (dircheck(idesc, dp)) 1781558Srgrimes goto dpok; 17923675Speter if (idesc->id_fix == IGNORE) 18023675Speter return (0); 1811558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1821558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1831558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1841558Srgrimes dp->d_reclen = DIRBLKSIZ; 1851558Srgrimes dp->d_ino = 0; 1861558Srgrimes dp->d_type = 0; 1871558Srgrimes dp->d_namlen = 0; 1881558Srgrimes dp->d_name[0] = '\0'; 1891558Srgrimes if (fix) 1901558Srgrimes dirty(bp); 1911558Srgrimes idesc->id_loc += DIRBLKSIZ; 1921558Srgrimes idesc->id_filesize -= DIRBLKSIZ; 1931558Srgrimes return (dp); 1941558Srgrimes } 1951558Srgrimesdpok: 1961558Srgrimes if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 1971558Srgrimes return NULL; 1981558Srgrimes dploc = idesc->id_loc; 1991558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2001558Srgrimes idesc->id_loc += dp->d_reclen; 2011558Srgrimes idesc->id_filesize -= dp->d_reclen; 2021558Srgrimes if ((idesc->id_loc % DIRBLKSIZ) == 0) 2031558Srgrimes return (dp); 2041558Srgrimes ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 2051558Srgrimes if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 2061558Srgrimes dircheck(idesc, ndp) == 0) { 2071558Srgrimes size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 2081558Srgrimes idesc->id_loc += size; 2091558Srgrimes idesc->id_filesize -= size; 21023675Speter if (idesc->id_fix == IGNORE) 21123675Speter return (0); 2121558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 2131558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 2141558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2151558Srgrimes dp->d_reclen += size; 2161558Srgrimes if (fix) 2171558Srgrimes dirty(bp); 2181558Srgrimes } 2191558Srgrimes return (dp); 2201558Srgrimes} 2211558Srgrimes 2221558Srgrimes/* 2231558Srgrimes * Verify that a directory entry is valid. 2241558Srgrimes * This is a superset of the checks made in the kernel. 2251558Srgrimes */ 22623675Speterstatic int 2271558Srgrimesdircheck(idesc, dp) 2281558Srgrimes struct inodesc *idesc; 2291558Srgrimes register struct direct *dp; 2301558Srgrimes{ 2311558Srgrimes register int size; 2321558Srgrimes register char *cp; 2331558Srgrimes u_char namlen, type; 2341558Srgrimes int spaceleft; 2351558Srgrimes 23623675Speter spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 23741474Sjulian if (dp->d_reclen == 0 || 23823675Speter dp->d_reclen > spaceleft || 23923675Speter (dp->d_reclen & 0x3) != 0) 24023675Speter return (0); 24123675Speter if (dp->d_ino == 0) 24223675Speter return (1); 2431558Srgrimes size = DIRSIZ(!newinofmt, dp); 2441558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 2451558Srgrimes if (!newinofmt) { 2461558Srgrimes type = dp->d_namlen; 2471558Srgrimes namlen = dp->d_type; 2481558Srgrimes } else { 2491558Srgrimes namlen = dp->d_namlen; 2501558Srgrimes type = dp->d_type; 2511558Srgrimes } 2521558Srgrimes# else 2531558Srgrimes namlen = dp->d_namlen; 2541558Srgrimes type = dp->d_type; 2551558Srgrimes# endif 25623675Speter if (dp->d_reclen < size || 25723675Speter idesc->id_filesize < size || 25823675Speter namlen > MAXNAMLEN || 25923675Speter type > 15) 26023675Speter return (0); 26123675Speter for (cp = dp->d_name, size = 0; size < namlen; size++) 26223675Speter if (*cp == '\0' || (*cp++ == '/')) 26323675Speter return (0); 26423675Speter if (*cp != '\0') 26523675Speter return (0); 26623675Speter return (1); 2671558Srgrimes} 2681558Srgrimes 2697585Sbdevoid 2701558Srgrimesdirerror(ino, errmesg) 2711558Srgrimes ino_t ino; 2721558Srgrimes char *errmesg; 2731558Srgrimes{ 2741558Srgrimes 2751558Srgrimes fileerror(ino, ino, errmesg); 2761558Srgrimes} 2771558Srgrimes 2787585Sbdevoid 2791558Srgrimesfileerror(cwd, ino, errmesg) 2801558Srgrimes ino_t cwd, ino; 2811558Srgrimes char *errmesg; 2821558Srgrimes{ 2831558Srgrimes register struct dinode *dp; 2841558Srgrimes char pathbuf[MAXPATHLEN + 1]; 2851558Srgrimes 2861558Srgrimes pwarn("%s ", errmesg); 2871558Srgrimes pinode(ino); 2881558Srgrimes printf("\n"); 2891558Srgrimes getpathname(pathbuf, cwd, ino); 2901558Srgrimes if (ino < ROOTINO || ino > maxino) { 2911558Srgrimes pfatal("NAME=%s\n", pathbuf); 2921558Srgrimes return; 2931558Srgrimes } 2941558Srgrimes dp = ginode(ino); 2951558Srgrimes if (ftypeok(dp)) 2961558Srgrimes pfatal("%s=%s\n", 2971558Srgrimes (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 2981558Srgrimes else 2991558Srgrimes pfatal("NAME=%s\n", pathbuf); 3001558Srgrimes} 3011558Srgrimes 3027585Sbdevoid 3031558Srgrimesadjust(idesc, lcnt) 3041558Srgrimes register struct inodesc *idesc; 30523675Speter int lcnt; 3061558Srgrimes{ 30741474Sjulian struct dinode *dp; 30841474Sjulian int saveresolved; 3091558Srgrimes 3101558Srgrimes dp = ginode(idesc->id_number); 3111558Srgrimes if (dp->di_nlink == lcnt) { 31241474Sjulian /* 31341474Sjulian * If we have not hit any unresolved problems, are running 31441474Sjulian * in preen mode, and are on a filesystem using soft updates, 31541474Sjulian * then just toss any partially allocated files. 31641474Sjulian */ 31741474Sjulian if (resolved && preen && usedsoftdep) { 31841474Sjulian clri(idesc, "UNREF", 1); 31941474Sjulian return; 32041474Sjulian } else { 32141474Sjulian /* 32241474Sjulian * The filesystem can be marked clean even if 32341474Sjulian * a file is not linked up, but is cleared. 32441474Sjulian * Hence, resolved should not be cleared when 32541474Sjulian * linkup is answered no, but clri is answered yes. 32641474Sjulian */ 32741474Sjulian saveresolved = resolved; 32841474Sjulian if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) { 32941474Sjulian resolved = saveresolved; 33041474Sjulian clri(idesc, "UNREF", 0); 33141474Sjulian return; 33241474Sjulian } 33341474Sjulian /* 33441474Sjulian * Account for the new reference created by linkup(). 33541474Sjulian */ 33641474Sjulian dp = ginode(idesc->id_number); 33741474Sjulian lcnt--; 33841474Sjulian } 33941474Sjulian } 34041474Sjulian if (lcnt != 0) { 3411558Srgrimes pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 3421558Srgrimes ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 3431558Srgrimes pinode(idesc->id_number); 3441558Srgrimes printf(" COUNT %d SHOULD BE %d", 3451558Srgrimes dp->di_nlink, dp->di_nlink - lcnt); 34634266Sjulian if (preen || usedsoftdep) { 3471558Srgrimes if (lcnt < 0) { 3481558Srgrimes printf("\n"); 3491558Srgrimes pfatal("LINK COUNT INCREASING"); 3501558Srgrimes } 35134266Sjulian if (preen) 35234266Sjulian printf(" (ADJUSTED)\n"); 3531558Srgrimes } 3541558Srgrimes if (preen || reply("ADJUST") == 1) { 3551558Srgrimes dp->di_nlink -= lcnt; 3561558Srgrimes inodirty(); 3571558Srgrimes } 3581558Srgrimes } 3591558Srgrimes} 3601558Srgrimes 36123675Speterstatic int 3621558Srgrimesmkentry(idesc) 3631558Srgrimes struct inodesc *idesc; 3641558Srgrimes{ 3651558Srgrimes register struct direct *dirp = idesc->id_dirp; 3661558Srgrimes struct direct newent; 3671558Srgrimes int newlen, oldlen; 3681558Srgrimes 3691558Srgrimes newent.d_namlen = strlen(idesc->id_name); 3701558Srgrimes newlen = DIRSIZ(0, &newent); 3711558Srgrimes if (dirp->d_ino != 0) 3721558Srgrimes oldlen = DIRSIZ(0, dirp); 3731558Srgrimes else 3741558Srgrimes oldlen = 0; 3751558Srgrimes if (dirp->d_reclen - oldlen < newlen) 3761558Srgrimes return (KEEPON); 3771558Srgrimes newent.d_reclen = dirp->d_reclen - oldlen; 3781558Srgrimes dirp->d_reclen = oldlen; 3791558Srgrimes dirp = (struct direct *)(((char *)dirp) + oldlen); 3801558Srgrimes dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 38123675Speter dirp->d_reclen = newent.d_reclen; 38223675Speter if (newinofmt) 38341474Sjulian dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 38423675Speter else 38523675Speter dirp->d_type = 0; 38623675Speter dirp->d_namlen = newent.d_namlen; 38723675Speter memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 38823675Speter# if (BYTE_ORDER == LITTLE_ENDIAN) 38923675Speter /* 39023675Speter * If the entry was split, dirscan() will only reverse the byte 39123675Speter * order of the original entry, and not the new one, before 39223675Speter * writing it back out. So, we reverse the byte order here if 39323675Speter * necessary. 39423675Speter */ 39523675Speter if (oldlen != 0 && !newinofmt && !doinglevel2) { 39623675Speter u_char tmp; 39723675Speter 39823675Speter tmp = dirp->d_namlen; 39923675Speter dirp->d_namlen = dirp->d_type; 40023675Speter dirp->d_type = tmp; 40123675Speter } 40223675Speter# endif 4031558Srgrimes return (ALTERED|STOP); 4041558Srgrimes} 4051558Srgrimes 40623675Speterstatic int 4071558Srgrimeschgino(idesc) 4081558Srgrimes struct inodesc *idesc; 4091558Srgrimes{ 4101558Srgrimes register struct direct *dirp = idesc->id_dirp; 4111558Srgrimes 41223675Speter if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 4131558Srgrimes return (KEEPON); 4141558Srgrimes dirp->d_ino = idesc->id_parent; 4151558Srgrimes if (newinofmt) 41641474Sjulian dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 4171558Srgrimes else 4181558Srgrimes dirp->d_type = 0; 4191558Srgrimes return (ALTERED|STOP); 4201558Srgrimes} 4211558Srgrimes 4227585Sbdeint 42341474Sjulianlinkup(orphan, parentdir, name) 4241558Srgrimes ino_t orphan; 4251558Srgrimes ino_t parentdir; 42641474Sjulian char *name; 4271558Srgrimes{ 4281558Srgrimes register struct dinode *dp; 4291558Srgrimes int lostdir; 4301558Srgrimes ino_t oldlfdir; 4311558Srgrimes struct inodesc idesc; 4321558Srgrimes char tempname[BUFSIZ]; 4331558Srgrimes 43423675Speter memset(&idesc, 0, sizeof(struct inodesc)); 4351558Srgrimes dp = ginode(orphan); 4361558Srgrimes lostdir = (dp->di_mode & IFMT) == IFDIR; 4371558Srgrimes pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 4381558Srgrimes pinode(orphan); 43941474Sjulian if (preen && dp->di_size == 0) 4401558Srgrimes return (0); 4411558Srgrimes if (preen) 4421558Srgrimes printf(" (RECONNECTED)\n"); 4431558Srgrimes else 4441558Srgrimes if (reply("RECONNECT") == 0) 4451558Srgrimes return (0); 4461558Srgrimes if (lfdir == 0) { 4471558Srgrimes dp = ginode(ROOTINO); 4481558Srgrimes idesc.id_name = lfname; 4491558Srgrimes idesc.id_type = DATA; 4501558Srgrimes idesc.id_func = findino; 4511558Srgrimes idesc.id_number = ROOTINO; 4521558Srgrimes if ((ckinode(dp, &idesc) & FOUND) != 0) { 4531558Srgrimes lfdir = idesc.id_parent; 4541558Srgrimes } else { 4551558Srgrimes pwarn("NO lost+found DIRECTORY"); 4561558Srgrimes if (preen || reply("CREATE")) { 4571558Srgrimes lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 4581558Srgrimes if (lfdir != 0) { 4591558Srgrimes if (makeentry(ROOTINO, lfdir, lfname) != 0) { 46041474Sjulian numdirs++; 4611558Srgrimes if (preen) 4621558Srgrimes printf(" (CREATED)\n"); 4631558Srgrimes } else { 4641558Srgrimes freedir(lfdir, ROOTINO); 4651558Srgrimes lfdir = 0; 4661558Srgrimes if (preen) 4671558Srgrimes printf("\n"); 4681558Srgrimes } 4691558Srgrimes } 4701558Srgrimes } 4711558Srgrimes } 4721558Srgrimes if (lfdir == 0) { 4731558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 4741558Srgrimes printf("\n\n"); 4751558Srgrimes return (0); 4761558Srgrimes } 4771558Srgrimes } 4781558Srgrimes dp = ginode(lfdir); 4791558Srgrimes if ((dp->di_mode & IFMT) != IFDIR) { 4801558Srgrimes pfatal("lost+found IS NOT A DIRECTORY"); 4811558Srgrimes if (reply("REALLOCATE") == 0) 4821558Srgrimes return (0); 4831558Srgrimes oldlfdir = lfdir; 4841558Srgrimes if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 4851558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4861558Srgrimes return (0); 4871558Srgrimes } 4881558Srgrimes if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 4891558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4901558Srgrimes return (0); 4911558Srgrimes } 4921558Srgrimes inodirty(); 4931558Srgrimes idesc.id_type = ADDR; 4941558Srgrimes idesc.id_func = pass4check; 4951558Srgrimes idesc.id_number = oldlfdir; 49641474Sjulian adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1); 49741474Sjulian inoinfo(oldlfdir)->ino_linkcnt = 0; 4981558Srgrimes dp = ginode(lfdir); 4991558Srgrimes } 50041474Sjulian if (inoinfo(lfdir)->ino_state != DFOUND) { 5011558Srgrimes pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 5021558Srgrimes return (0); 5031558Srgrimes } 5041558Srgrimes (void)lftempname(tempname, orphan); 50541474Sjulian if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) { 5061558Srgrimes pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 5071558Srgrimes printf("\n\n"); 5081558Srgrimes return (0); 5091558Srgrimes } 51041474Sjulian inoinfo(orphan)->ino_linkcnt--; 5111558Srgrimes if (lostdir) { 5121558Srgrimes if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 5131558Srgrimes parentdir != (ino_t)-1) 5141558Srgrimes (void)makeentry(orphan, lfdir, ".."); 5151558Srgrimes dp = ginode(lfdir); 5161558Srgrimes dp->di_nlink++; 5171558Srgrimes inodirty(); 51841474Sjulian inoinfo(lfdir)->ino_linkcnt++; 5191558Srgrimes pwarn("DIR I=%lu CONNECTED. ", orphan); 52015699Snate if (parentdir != (ino_t)-1) { 52137236Sbde printf("PARENT WAS I=%lu\n", (u_long)parentdir); 52241474Sjulian inoinfo(parentdir)->ino_linkcnt++; 52315699Snate } 5241558Srgrimes if (preen == 0) 5251558Srgrimes printf("\n"); 5261558Srgrimes } 5271558Srgrimes return (1); 5281558Srgrimes} 5291558Srgrimes 5301558Srgrimes/* 5311558Srgrimes * fix an entry in a directory. 5321558Srgrimes */ 5337585Sbdeint 5341558Srgrimeschangeino(dir, name, newnum) 5351558Srgrimes ino_t dir; 5361558Srgrimes char *name; 5371558Srgrimes ino_t newnum; 5381558Srgrimes{ 5391558Srgrimes struct inodesc idesc; 5401558Srgrimes 54123675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5421558Srgrimes idesc.id_type = DATA; 5431558Srgrimes idesc.id_func = chgino; 5441558Srgrimes idesc.id_number = dir; 5451558Srgrimes idesc.id_fix = DONTKNOW; 5461558Srgrimes idesc.id_name = name; 5471558Srgrimes idesc.id_parent = newnum; /* new value for name */ 5481558Srgrimes return (ckinode(ginode(dir), &idesc)); 5491558Srgrimes} 5501558Srgrimes 5511558Srgrimes/* 5521558Srgrimes * make an entry in a directory 5531558Srgrimes */ 5547585Sbdeint 5551558Srgrimesmakeentry(parent, ino, name) 5561558Srgrimes ino_t parent, ino; 5571558Srgrimes char *name; 5581558Srgrimes{ 5591558Srgrimes struct dinode *dp; 5601558Srgrimes struct inodesc idesc; 5611558Srgrimes char pathbuf[MAXPATHLEN + 1]; 5628871Srgrimes 5631558Srgrimes if (parent < ROOTINO || parent >= maxino || 5641558Srgrimes ino < ROOTINO || ino >= maxino) 5651558Srgrimes return (0); 56623675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5671558Srgrimes idesc.id_type = DATA; 5681558Srgrimes idesc.id_func = mkentry; 5691558Srgrimes idesc.id_number = parent; 5701558Srgrimes idesc.id_parent = ino; /* this is the inode to enter */ 5711558Srgrimes idesc.id_fix = DONTKNOW; 5721558Srgrimes idesc.id_name = name; 5731558Srgrimes dp = ginode(parent); 5741558Srgrimes if (dp->di_size % DIRBLKSIZ) { 5751558Srgrimes dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 5761558Srgrimes inodirty(); 5771558Srgrimes } 5781558Srgrimes if ((ckinode(dp, &idesc) & ALTERED) != 0) 5791558Srgrimes return (1); 5801558Srgrimes getpathname(pathbuf, parent, parent); 5811558Srgrimes dp = ginode(parent); 5821558Srgrimes if (expanddir(dp, pathbuf) == 0) 5831558Srgrimes return (0); 5841558Srgrimes return (ckinode(dp, &idesc) & ALTERED); 5851558Srgrimes} 5861558Srgrimes 5871558Srgrimes/* 5881558Srgrimes * Attempt to expand the size of a directory 5891558Srgrimes */ 59023675Speterstatic int 5911558Srgrimesexpanddir(dp, name) 5921558Srgrimes register struct dinode *dp; 5931558Srgrimes char *name; 5941558Srgrimes{ 59523675Speter ufs_daddr_t lastbn, newblk; 5961558Srgrimes register struct bufarea *bp; 5971558Srgrimes char *cp, firstblk[DIRBLKSIZ]; 5981558Srgrimes 5991558Srgrimes lastbn = lblkno(&sblock, dp->di_size); 6001558Srgrimes if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 6011558Srgrimes return (0); 6021558Srgrimes if ((newblk = allocblk(sblock.fs_frag)) == 0) 6031558Srgrimes return (0); 6041558Srgrimes dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 6051558Srgrimes dp->di_db[lastbn] = newblk; 6061558Srgrimes dp->di_size += sblock.fs_bsize; 6071558Srgrimes dp->di_blocks += btodb(sblock.fs_bsize); 6081558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 6091558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 6101558Srgrimes if (bp->b_errs) 6111558Srgrimes goto bad; 61223675Speter memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 6131558Srgrimes bp = getdirblk(newblk, sblock.fs_bsize); 6141558Srgrimes if (bp->b_errs) 6151558Srgrimes goto bad; 61623675Speter memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 6171558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6181558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_bsize]; 6191558Srgrimes cp += DIRBLKSIZ) 62023675Speter memmove(cp, &emptydir, sizeof emptydir); 6211558Srgrimes dirty(bp); 6221558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 6231558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 6241558Srgrimes if (bp->b_errs) 6251558Srgrimes goto bad; 62623675Speter memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 6271558Srgrimes pwarn("NO SPACE LEFT IN %s", name); 6281558Srgrimes if (preen) 6291558Srgrimes printf(" (EXPANDED)\n"); 6301558Srgrimes else if (reply("EXPAND") == 0) 6311558Srgrimes goto bad; 6321558Srgrimes dirty(bp); 6331558Srgrimes inodirty(); 6341558Srgrimes return (1); 6351558Srgrimesbad: 6361558Srgrimes dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 6371558Srgrimes dp->di_db[lastbn + 1] = 0; 6381558Srgrimes dp->di_size -= sblock.fs_bsize; 6391558Srgrimes dp->di_blocks -= btodb(sblock.fs_bsize); 6401558Srgrimes freeblk(newblk, sblock.fs_frag); 6411558Srgrimes return (0); 6421558Srgrimes} 6431558Srgrimes 6441558Srgrimes/* 6451558Srgrimes * allocate a new directory 6461558Srgrimes */ 6477586Sbdeino_t 6481558Srgrimesallocdir(parent, request, mode) 6491558Srgrimes ino_t parent, request; 6501558Srgrimes int mode; 6511558Srgrimes{ 6521558Srgrimes ino_t ino; 6531558Srgrimes char *cp; 6541558Srgrimes struct dinode *dp; 6551558Srgrimes register struct bufarea *bp; 6561558Srgrimes struct dirtemplate *dirp; 6571558Srgrimes 6581558Srgrimes ino = allocino(request, IFDIR|mode); 6591558Srgrimes if (newinofmt) 6601558Srgrimes dirp = &dirhead; 6611558Srgrimes else 6621558Srgrimes dirp = (struct dirtemplate *)&odirhead; 6631558Srgrimes dirp->dot_ino = ino; 6641558Srgrimes dirp->dotdot_ino = parent; 6651558Srgrimes dp = ginode(ino); 6661558Srgrimes bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 6671558Srgrimes if (bp->b_errs) { 6681558Srgrimes freeino(ino); 6691558Srgrimes return (0); 6701558Srgrimes } 67123675Speter memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 6721558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6731558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_fsize]; 6741558Srgrimes cp += DIRBLKSIZ) 67523675Speter memmove(cp, &emptydir, sizeof emptydir); 6761558Srgrimes dirty(bp); 6771558Srgrimes dp->di_nlink = 2; 6781558Srgrimes inodirty(); 6791558Srgrimes if (ino == ROOTINO) { 68041474Sjulian inoinfo(ino)->ino_linkcnt = dp->di_nlink; 6811558Srgrimes cacheino(dp, ino); 6821558Srgrimes return(ino); 6831558Srgrimes } 68441474Sjulian if (inoinfo(parent)->ino_state != DSTATE && 68541474Sjulian inoinfo(parent)->ino_state != DFOUND) { 6861558Srgrimes freeino(ino); 6871558Srgrimes return (0); 6881558Srgrimes } 6891558Srgrimes cacheino(dp, ino); 69041474Sjulian inoinfo(ino)->ino_state = inoinfo(parent)->ino_state; 69141474Sjulian if (inoinfo(ino)->ino_state == DSTATE) { 69241474Sjulian inoinfo(ino)->ino_linkcnt = dp->di_nlink; 69341474Sjulian inoinfo(parent)->ino_linkcnt++; 6941558Srgrimes } 6951558Srgrimes dp = ginode(parent); 6961558Srgrimes dp->di_nlink++; 6971558Srgrimes inodirty(); 6981558Srgrimes return (ino); 6991558Srgrimes} 7001558Srgrimes 7011558Srgrimes/* 7021558Srgrimes * free a directory inode 7031558Srgrimes */ 7047585Sbdestatic void 7051558Srgrimesfreedir(ino, parent) 7061558Srgrimes ino_t ino, parent; 7071558Srgrimes{ 7081558Srgrimes struct dinode *dp; 7091558Srgrimes 7101558Srgrimes if (ino != parent) { 7111558Srgrimes dp = ginode(parent); 7121558Srgrimes dp->di_nlink--; 7131558Srgrimes inodirty(); 7141558Srgrimes } 7151558Srgrimes freeino(ino); 7161558Srgrimes} 7171558Srgrimes 7181558Srgrimes/* 7191558Srgrimes * generate a temporary name for the lost+found directory. 7201558Srgrimes */ 72123675Speterstatic int 7221558Srgrimeslftempname(bufp, ino) 7231558Srgrimes char *bufp; 7241558Srgrimes ino_t ino; 7251558Srgrimes{ 7261558Srgrimes register ino_t in; 7271558Srgrimes register char *cp; 7281558Srgrimes int namlen; 7291558Srgrimes 7301558Srgrimes cp = bufp + 2; 7311558Srgrimes for (in = maxino; in > 0; in /= 10) 7321558Srgrimes cp++; 7331558Srgrimes *--cp = 0; 7341558Srgrimes namlen = cp - bufp; 7351558Srgrimes in = ino; 7361558Srgrimes while (cp > bufp) { 7371558Srgrimes *--cp = (in % 10) + '0'; 7381558Srgrimes in /= 10; 7391558Srgrimes } 7401558Srgrimes *cp = '#'; 7411558Srgrimes return (namlen); 7421558Srgrimes} 7431558Srgrimes 7441558Srgrimes/* 7451558Srgrimes * Get a directory block. 7461558Srgrimes * Insure that it is held until another is requested. 7471558Srgrimes */ 74823675Speterstatic struct bufarea * 7491558Srgrimesgetdirblk(blkno, size) 75023675Speter ufs_daddr_t blkno; 7511558Srgrimes long size; 7521558Srgrimes{ 7531558Srgrimes 7541558Srgrimes if (pdirbp != 0) 7551558Srgrimes pdirbp->b_flags &= ~B_INUSE; 7561558Srgrimes pdirbp = getdatablk(blkno, size); 7571558Srgrimes return (pdirbp); 7581558Srgrimes} 759