dir.c revision 34266
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> 391558Srgrimes#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; 881558Srgrimes if (statemap[inp->i_parent] == DFOUND && 891558Srgrimes statemap[inp->i_number] == DSTATE) { 901558Srgrimes statemap[inp->i_number] = 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; 12323675Speter memmove(dbuf, dp, (size_t)dsize); 1241558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1251558Srgrimes if (!newinofmt) { 1261558Srgrimes struct direct *tdp = (struct direct *)dbuf; 1271558Srgrimes u_char tmp; 1281558Srgrimes 1291558Srgrimes tmp = tdp->d_namlen; 1301558Srgrimes tdp->d_namlen = tdp->d_type; 1311558Srgrimes tdp->d_type = tmp; 1321558Srgrimes } 1331558Srgrimes# endif 1341558Srgrimes idesc->id_dirp = (struct direct *)dbuf; 1351558Srgrimes if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 1361558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1371558Srgrimes if (!newinofmt && !doinglevel2) { 1381558Srgrimes struct direct *tdp; 1391558Srgrimes u_char tmp; 1401558Srgrimes 1411558Srgrimes tdp = (struct direct *)dbuf; 1421558Srgrimes tmp = tdp->d_namlen; 1431558Srgrimes tdp->d_namlen = tdp->d_type; 1441558Srgrimes tdp->d_type = tmp; 1451558Srgrimes } 1461558Srgrimes# endif 1471558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 14823675Speter memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 1491558Srgrimes (size_t)dsize); 1501558Srgrimes dirty(bp); 1511558Srgrimes sbdirty(); 1521558Srgrimes } 1538871Srgrimes if (n & STOP) 1541558Srgrimes return (n); 1551558Srgrimes } 1561558Srgrimes return (idesc->id_filesize > 0 ? KEEPON : STOP); 1571558Srgrimes} 1581558Srgrimes 1591558Srgrimes/* 1601558Srgrimes * get next entry in a directory. 1611558Srgrimes */ 16223675Speterstatic struct direct * 1631558Srgrimesfsck_readdir(idesc) 1641558Srgrimes register struct inodesc *idesc; 1651558Srgrimes{ 1661558Srgrimes register struct direct *dp, *ndp; 1671558Srgrimes register struct bufarea *bp; 1681558Srgrimes long size, blksiz, fix, dploc; 1691558Srgrimes 1701558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1711558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1721558Srgrimes if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 1731558Srgrimes idesc->id_loc < blksiz) { 1741558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1751558Srgrimes if (dircheck(idesc, dp)) 1761558Srgrimes goto dpok; 17723675Speter if (idesc->id_fix == IGNORE) 17823675Speter return (0); 1791558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1801558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1811558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1821558Srgrimes dp->d_reclen = DIRBLKSIZ; 1831558Srgrimes dp->d_ino = 0; 1841558Srgrimes dp->d_type = 0; 1851558Srgrimes dp->d_namlen = 0; 1861558Srgrimes dp->d_name[0] = '\0'; 1871558Srgrimes if (fix) 1881558Srgrimes dirty(bp); 1891558Srgrimes idesc->id_loc += DIRBLKSIZ; 1901558Srgrimes idesc->id_filesize -= DIRBLKSIZ; 1911558Srgrimes return (dp); 1921558Srgrimes } 1931558Srgrimesdpok: 1941558Srgrimes if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 1951558Srgrimes return NULL; 1961558Srgrimes dploc = idesc->id_loc; 1971558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 1981558Srgrimes idesc->id_loc += dp->d_reclen; 1991558Srgrimes idesc->id_filesize -= dp->d_reclen; 2001558Srgrimes if ((idesc->id_loc % DIRBLKSIZ) == 0) 2011558Srgrimes return (dp); 2021558Srgrimes ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 2031558Srgrimes if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 2041558Srgrimes dircheck(idesc, ndp) == 0) { 2051558Srgrimes size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 2061558Srgrimes idesc->id_loc += size; 2071558Srgrimes idesc->id_filesize -= size; 20823675Speter if (idesc->id_fix == IGNORE) 20923675Speter return (0); 2101558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 2111558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 2121558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2131558Srgrimes dp->d_reclen += size; 2141558Srgrimes if (fix) 2151558Srgrimes dirty(bp); 2161558Srgrimes } 2171558Srgrimes return (dp); 2181558Srgrimes} 2191558Srgrimes 2201558Srgrimes/* 2211558Srgrimes * Verify that a directory entry is valid. 2221558Srgrimes * This is a superset of the checks made in the kernel. 2231558Srgrimes */ 22423675Speterstatic int 2251558Srgrimesdircheck(idesc, dp) 2261558Srgrimes struct inodesc *idesc; 2271558Srgrimes register struct direct *dp; 2281558Srgrimes{ 2291558Srgrimes register int size; 2301558Srgrimes register char *cp; 2311558Srgrimes u_char namlen, type; 2321558Srgrimes int spaceleft; 2331558Srgrimes 23423675Speter spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 23523675Speter if (dp->d_ino >= maxino || 23623675Speter dp->d_reclen == 0 || 23723675Speter dp->d_reclen > spaceleft || 23823675Speter (dp->d_reclen & 0x3) != 0) 23923675Speter return (0); 24023675Speter if (dp->d_ino == 0) 24123675Speter return (1); 2421558Srgrimes size = DIRSIZ(!newinofmt, dp); 2431558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 2441558Srgrimes if (!newinofmt) { 2451558Srgrimes type = dp->d_namlen; 2461558Srgrimes namlen = dp->d_type; 2471558Srgrimes } else { 2481558Srgrimes namlen = dp->d_namlen; 2491558Srgrimes type = dp->d_type; 2501558Srgrimes } 2511558Srgrimes# else 2521558Srgrimes namlen = dp->d_namlen; 2531558Srgrimes type = dp->d_type; 2541558Srgrimes# endif 25523675Speter if (dp->d_reclen < size || 25623675Speter idesc->id_filesize < size || 25723675Speter namlen > MAXNAMLEN || 25823675Speter type > 15) 25923675Speter return (0); 26023675Speter for (cp = dp->d_name, size = 0; size < namlen; size++) 26123675Speter if (*cp == '\0' || (*cp++ == '/')) 26223675Speter return (0); 26323675Speter if (*cp != '\0') 26423675Speter return (0); 26523675Speter return (1); 2661558Srgrimes} 2671558Srgrimes 2687585Sbdevoid 2691558Srgrimesdirerror(ino, errmesg) 2701558Srgrimes ino_t ino; 2711558Srgrimes char *errmesg; 2721558Srgrimes{ 2731558Srgrimes 2741558Srgrimes fileerror(ino, ino, errmesg); 2751558Srgrimes} 2761558Srgrimes 2777585Sbdevoid 2781558Srgrimesfileerror(cwd, ino, errmesg) 2791558Srgrimes ino_t cwd, ino; 2801558Srgrimes char *errmesg; 2811558Srgrimes{ 2821558Srgrimes register struct dinode *dp; 2831558Srgrimes char pathbuf[MAXPATHLEN + 1]; 2841558Srgrimes 2851558Srgrimes pwarn("%s ", errmesg); 2861558Srgrimes pinode(ino); 2871558Srgrimes printf("\n"); 2881558Srgrimes getpathname(pathbuf, cwd, ino); 2891558Srgrimes if (ino < ROOTINO || ino > maxino) { 2901558Srgrimes pfatal("NAME=%s\n", pathbuf); 2911558Srgrimes return; 2921558Srgrimes } 2931558Srgrimes dp = ginode(ino); 2941558Srgrimes if (ftypeok(dp)) 2951558Srgrimes pfatal("%s=%s\n", 2961558Srgrimes (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 2971558Srgrimes else 2981558Srgrimes pfatal("NAME=%s\n", pathbuf); 2991558Srgrimes} 3001558Srgrimes 3017585Sbdevoid 3021558Srgrimesadjust(idesc, lcnt) 3031558Srgrimes register struct inodesc *idesc; 30423675Speter int lcnt; 3051558Srgrimes{ 3061558Srgrimes register struct dinode *dp; 3071558Srgrimes 3081558Srgrimes dp = ginode(idesc->id_number); 3091558Srgrimes if (dp->di_nlink == lcnt) { 3101558Srgrimes if (linkup(idesc->id_number, (ino_t)0) == 0) 3111558Srgrimes clri(idesc, "UNREF", 0); 3121558Srgrimes } else { 3131558Srgrimes pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 3141558Srgrimes ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 3151558Srgrimes pinode(idesc->id_number); 3161558Srgrimes printf(" COUNT %d SHOULD BE %d", 3171558Srgrimes dp->di_nlink, dp->di_nlink - lcnt); 31834266Sjulian if (preen || usedsoftdep) { 3191558Srgrimes if (lcnt < 0) { 3201558Srgrimes printf("\n"); 3211558Srgrimes pfatal("LINK COUNT INCREASING"); 3221558Srgrimes } 32334266Sjulian if (preen) 32434266Sjulian printf(" (ADJUSTED)\n"); 3251558Srgrimes } 3261558Srgrimes if (preen || reply("ADJUST") == 1) { 3271558Srgrimes dp->di_nlink -= lcnt; 3281558Srgrimes inodirty(); 3291558Srgrimes } 3301558Srgrimes } 3311558Srgrimes} 3321558Srgrimes 33323675Speterstatic int 3341558Srgrimesmkentry(idesc) 3351558Srgrimes struct inodesc *idesc; 3361558Srgrimes{ 3371558Srgrimes register struct direct *dirp = idesc->id_dirp; 3381558Srgrimes struct direct newent; 3391558Srgrimes int newlen, oldlen; 3401558Srgrimes 3411558Srgrimes newent.d_namlen = strlen(idesc->id_name); 3421558Srgrimes newlen = DIRSIZ(0, &newent); 3431558Srgrimes if (dirp->d_ino != 0) 3441558Srgrimes oldlen = DIRSIZ(0, dirp); 3451558Srgrimes else 3461558Srgrimes oldlen = 0; 3471558Srgrimes if (dirp->d_reclen - oldlen < newlen) 3481558Srgrimes return (KEEPON); 3491558Srgrimes newent.d_reclen = dirp->d_reclen - oldlen; 3501558Srgrimes dirp->d_reclen = oldlen; 3511558Srgrimes dirp = (struct direct *)(((char *)dirp) + oldlen); 3521558Srgrimes dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 35323675Speter dirp->d_reclen = newent.d_reclen; 35423675Speter if (newinofmt) 3551558Srgrimes dirp->d_type = typemap[idesc->id_parent]; 35623675Speter else 35723675Speter dirp->d_type = 0; 35823675Speter dirp->d_namlen = newent.d_namlen; 35923675Speter memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 36023675Speter# if (BYTE_ORDER == LITTLE_ENDIAN) 36123675Speter /* 36223675Speter * If the entry was split, dirscan() will only reverse the byte 36323675Speter * order of the original entry, and not the new one, before 36423675Speter * writing it back out. So, we reverse the byte order here if 36523675Speter * necessary. 36623675Speter */ 36723675Speter if (oldlen != 0 && !newinofmt && !doinglevel2) { 36823675Speter u_char tmp; 36923675Speter 37023675Speter tmp = dirp->d_namlen; 37123675Speter dirp->d_namlen = dirp->d_type; 37223675Speter dirp->d_type = tmp; 37323675Speter } 37423675Speter# endif 3751558Srgrimes return (ALTERED|STOP); 3761558Srgrimes} 3771558Srgrimes 37823675Speterstatic int 3791558Srgrimeschgino(idesc) 3801558Srgrimes struct inodesc *idesc; 3811558Srgrimes{ 3821558Srgrimes register struct direct *dirp = idesc->id_dirp; 3831558Srgrimes 38423675Speter if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 3851558Srgrimes return (KEEPON); 3861558Srgrimes dirp->d_ino = idesc->id_parent; 3871558Srgrimes if (newinofmt) 3881558Srgrimes dirp->d_type = typemap[idesc->id_parent]; 3891558Srgrimes else 3901558Srgrimes dirp->d_type = 0; 3911558Srgrimes return (ALTERED|STOP); 3921558Srgrimes} 3931558Srgrimes 3947585Sbdeint 3951558Srgrimeslinkup(orphan, parentdir) 3961558Srgrimes ino_t orphan; 3971558Srgrimes ino_t parentdir; 3981558Srgrimes{ 3991558Srgrimes register struct dinode *dp; 4001558Srgrimes int lostdir; 4011558Srgrimes ino_t oldlfdir; 4021558Srgrimes struct inodesc idesc; 4031558Srgrimes char tempname[BUFSIZ]; 4041558Srgrimes 40523675Speter memset(&idesc, 0, sizeof(struct inodesc)); 4061558Srgrimes dp = ginode(orphan); 4071558Srgrimes lostdir = (dp->di_mode & IFMT) == IFDIR; 4081558Srgrimes pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 4091558Srgrimes pinode(orphan); 41034266Sjulian if ((preen || usedsoftdep) && dp->di_size == 0) 4111558Srgrimes return (0); 4121558Srgrimes if (preen) 4131558Srgrimes printf(" (RECONNECTED)\n"); 4141558Srgrimes else 4151558Srgrimes if (reply("RECONNECT") == 0) 4161558Srgrimes return (0); 41734266Sjulian if (parentdir != 0) 41834266Sjulian lncntp[parentdir]++; 4191558Srgrimes if (lfdir == 0) { 4201558Srgrimes dp = ginode(ROOTINO); 4211558Srgrimes idesc.id_name = lfname; 4221558Srgrimes idesc.id_type = DATA; 4231558Srgrimes idesc.id_func = findino; 4241558Srgrimes idesc.id_number = ROOTINO; 4251558Srgrimes if ((ckinode(dp, &idesc) & FOUND) != 0) { 4261558Srgrimes lfdir = idesc.id_parent; 4271558Srgrimes } else { 4281558Srgrimes pwarn("NO lost+found DIRECTORY"); 4291558Srgrimes if (preen || reply("CREATE")) { 4301558Srgrimes lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 4311558Srgrimes if (lfdir != 0) { 4321558Srgrimes if (makeentry(ROOTINO, lfdir, lfname) != 0) { 4331558Srgrimes if (preen) 4341558Srgrimes printf(" (CREATED)\n"); 4351558Srgrimes } else { 4361558Srgrimes freedir(lfdir, ROOTINO); 4371558Srgrimes lfdir = 0; 4381558Srgrimes if (preen) 4391558Srgrimes printf("\n"); 4401558Srgrimes } 4411558Srgrimes } 4421558Srgrimes } 4431558Srgrimes } 4441558Srgrimes if (lfdir == 0) { 4451558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 4461558Srgrimes printf("\n\n"); 4471558Srgrimes return (0); 4481558Srgrimes } 4491558Srgrimes } 4501558Srgrimes dp = ginode(lfdir); 4511558Srgrimes if ((dp->di_mode & IFMT) != IFDIR) { 4521558Srgrimes pfatal("lost+found IS NOT A DIRECTORY"); 4531558Srgrimes if (reply("REALLOCATE") == 0) 4541558Srgrimes return (0); 4551558Srgrimes oldlfdir = lfdir; 4561558Srgrimes if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 4571558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4581558Srgrimes return (0); 4591558Srgrimes } 4601558Srgrimes if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 4611558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4621558Srgrimes return (0); 4631558Srgrimes } 4641558Srgrimes inodirty(); 4651558Srgrimes idesc.id_type = ADDR; 4661558Srgrimes idesc.id_func = pass4check; 4671558Srgrimes idesc.id_number = oldlfdir; 4681558Srgrimes adjust(&idesc, lncntp[oldlfdir] + 1); 4691558Srgrimes lncntp[oldlfdir] = 0; 4701558Srgrimes dp = ginode(lfdir); 4711558Srgrimes } 4721558Srgrimes if (statemap[lfdir] != DFOUND) { 4731558Srgrimes pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 4741558Srgrimes return (0); 4751558Srgrimes } 4761558Srgrimes (void)lftempname(tempname, orphan); 4771558Srgrimes if (makeentry(lfdir, orphan, tempname) == 0) { 4781558Srgrimes pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 4791558Srgrimes printf("\n\n"); 4801558Srgrimes return (0); 4811558Srgrimes } 4821558Srgrimes lncntp[orphan]--; 4831558Srgrimes if (lostdir) { 4841558Srgrimes if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 4851558Srgrimes parentdir != (ino_t)-1) 4861558Srgrimes (void)makeentry(orphan, lfdir, ".."); 4871558Srgrimes dp = ginode(lfdir); 4881558Srgrimes dp->di_nlink++; 4891558Srgrimes inodirty(); 4901558Srgrimes lncntp[lfdir]++; 4911558Srgrimes pwarn("DIR I=%lu CONNECTED. ", orphan); 49215699Snate if (parentdir != (ino_t)-1) { 4931558Srgrimes printf("PARENT WAS I=%lu\n", parentdir); 49423796Sbde /* 49515699Snate * The parent directory, because of the ordering 49615699Snate * guarantees, has had the link count incremented 49715699Snate * for the child, but no entry was made. This 49815699Snate * fixes the parent link count so that fsck does 49915699Snate * not need to be rerun. 50015699Snate */ 50115699Snate lncntp[parentdir]++; 50215699Snate 50315699Snate } 5041558Srgrimes if (preen == 0) 5051558Srgrimes printf("\n"); 5061558Srgrimes } 5071558Srgrimes return (1); 5081558Srgrimes} 5091558Srgrimes 5101558Srgrimes/* 5111558Srgrimes * fix an entry in a directory. 5121558Srgrimes */ 5137585Sbdeint 5141558Srgrimeschangeino(dir, name, newnum) 5151558Srgrimes ino_t dir; 5161558Srgrimes char *name; 5171558Srgrimes ino_t newnum; 5181558Srgrimes{ 5191558Srgrimes struct inodesc idesc; 5201558Srgrimes 52123675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5221558Srgrimes idesc.id_type = DATA; 5231558Srgrimes idesc.id_func = chgino; 5241558Srgrimes idesc.id_number = dir; 5251558Srgrimes idesc.id_fix = DONTKNOW; 5261558Srgrimes idesc.id_name = name; 5271558Srgrimes idesc.id_parent = newnum; /* new value for name */ 5281558Srgrimes return (ckinode(ginode(dir), &idesc)); 5291558Srgrimes} 5301558Srgrimes 5311558Srgrimes/* 5321558Srgrimes * make an entry in a directory 5331558Srgrimes */ 5347585Sbdeint 5351558Srgrimesmakeentry(parent, ino, name) 5361558Srgrimes ino_t parent, ino; 5371558Srgrimes char *name; 5381558Srgrimes{ 5391558Srgrimes struct dinode *dp; 5401558Srgrimes struct inodesc idesc; 5411558Srgrimes char pathbuf[MAXPATHLEN + 1]; 5428871Srgrimes 5431558Srgrimes if (parent < ROOTINO || parent >= maxino || 5441558Srgrimes ino < ROOTINO || ino >= maxino) 5451558Srgrimes return (0); 54623675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5471558Srgrimes idesc.id_type = DATA; 5481558Srgrimes idesc.id_func = mkentry; 5491558Srgrimes idesc.id_number = parent; 5501558Srgrimes idesc.id_parent = ino; /* this is the inode to enter */ 5511558Srgrimes idesc.id_fix = DONTKNOW; 5521558Srgrimes idesc.id_name = name; 5531558Srgrimes dp = ginode(parent); 5541558Srgrimes if (dp->di_size % DIRBLKSIZ) { 5551558Srgrimes dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 5561558Srgrimes inodirty(); 5571558Srgrimes } 5581558Srgrimes if ((ckinode(dp, &idesc) & ALTERED) != 0) 5591558Srgrimes return (1); 5601558Srgrimes getpathname(pathbuf, parent, parent); 5611558Srgrimes dp = ginode(parent); 5621558Srgrimes if (expanddir(dp, pathbuf) == 0) 5631558Srgrimes return (0); 5641558Srgrimes return (ckinode(dp, &idesc) & ALTERED); 5651558Srgrimes} 5661558Srgrimes 5671558Srgrimes/* 5681558Srgrimes * Attempt to expand the size of a directory 5691558Srgrimes */ 57023675Speterstatic int 5711558Srgrimesexpanddir(dp, name) 5721558Srgrimes register struct dinode *dp; 5731558Srgrimes char *name; 5741558Srgrimes{ 57523675Speter ufs_daddr_t lastbn, newblk; 5761558Srgrimes register struct bufarea *bp; 5771558Srgrimes char *cp, firstblk[DIRBLKSIZ]; 5781558Srgrimes 5791558Srgrimes lastbn = lblkno(&sblock, dp->di_size); 5801558Srgrimes if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 5811558Srgrimes return (0); 5821558Srgrimes if ((newblk = allocblk(sblock.fs_frag)) == 0) 5831558Srgrimes return (0); 5841558Srgrimes dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 5851558Srgrimes dp->di_db[lastbn] = newblk; 5861558Srgrimes dp->di_size += sblock.fs_bsize; 5871558Srgrimes dp->di_blocks += btodb(sblock.fs_bsize); 5881558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 5891558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 5901558Srgrimes if (bp->b_errs) 5911558Srgrimes goto bad; 59223675Speter memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 5931558Srgrimes bp = getdirblk(newblk, sblock.fs_bsize); 5941558Srgrimes if (bp->b_errs) 5951558Srgrimes goto bad; 59623675Speter memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 5971558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 5981558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_bsize]; 5991558Srgrimes cp += DIRBLKSIZ) 60023675Speter memmove(cp, &emptydir, sizeof emptydir); 6011558Srgrimes dirty(bp); 6021558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 6031558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 6041558Srgrimes if (bp->b_errs) 6051558Srgrimes goto bad; 60623675Speter memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 6071558Srgrimes pwarn("NO SPACE LEFT IN %s", name); 6081558Srgrimes if (preen) 6091558Srgrimes printf(" (EXPANDED)\n"); 6101558Srgrimes else if (reply("EXPAND") == 0) 6111558Srgrimes goto bad; 6121558Srgrimes dirty(bp); 6131558Srgrimes inodirty(); 6141558Srgrimes return (1); 6151558Srgrimesbad: 6161558Srgrimes dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 6171558Srgrimes dp->di_db[lastbn + 1] = 0; 6181558Srgrimes dp->di_size -= sblock.fs_bsize; 6191558Srgrimes dp->di_blocks -= btodb(sblock.fs_bsize); 6201558Srgrimes freeblk(newblk, sblock.fs_frag); 6211558Srgrimes return (0); 6221558Srgrimes} 6231558Srgrimes 6241558Srgrimes/* 6251558Srgrimes * allocate a new directory 6261558Srgrimes */ 6277586Sbdeino_t 6281558Srgrimesallocdir(parent, request, mode) 6291558Srgrimes ino_t parent, request; 6301558Srgrimes int mode; 6311558Srgrimes{ 6321558Srgrimes ino_t ino; 6331558Srgrimes char *cp; 6341558Srgrimes struct dinode *dp; 6351558Srgrimes register struct bufarea *bp; 6361558Srgrimes struct dirtemplate *dirp; 6371558Srgrimes 6381558Srgrimes ino = allocino(request, IFDIR|mode); 6391558Srgrimes if (newinofmt) 6401558Srgrimes dirp = &dirhead; 6411558Srgrimes else 6421558Srgrimes dirp = (struct dirtemplate *)&odirhead; 6431558Srgrimes dirp->dot_ino = ino; 6441558Srgrimes dirp->dotdot_ino = parent; 6451558Srgrimes dp = ginode(ino); 6461558Srgrimes bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 6471558Srgrimes if (bp->b_errs) { 6481558Srgrimes freeino(ino); 6491558Srgrimes return (0); 6501558Srgrimes } 65123675Speter memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 6521558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6531558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_fsize]; 6541558Srgrimes cp += DIRBLKSIZ) 65523675Speter memmove(cp, &emptydir, sizeof emptydir); 6561558Srgrimes dirty(bp); 6571558Srgrimes dp->di_nlink = 2; 6581558Srgrimes inodirty(); 6591558Srgrimes if (ino == ROOTINO) { 6601558Srgrimes lncntp[ino] = dp->di_nlink; 6611558Srgrimes cacheino(dp, ino); 6621558Srgrimes return(ino); 6631558Srgrimes } 6641558Srgrimes if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 6651558Srgrimes freeino(ino); 6661558Srgrimes return (0); 6671558Srgrimes } 6681558Srgrimes cacheino(dp, ino); 6691558Srgrimes statemap[ino] = statemap[parent]; 6701558Srgrimes if (statemap[ino] == DSTATE) { 6711558Srgrimes lncntp[ino] = dp->di_nlink; 6721558Srgrimes lncntp[parent]++; 6731558Srgrimes } 6741558Srgrimes dp = ginode(parent); 6751558Srgrimes dp->di_nlink++; 6761558Srgrimes inodirty(); 6771558Srgrimes return (ino); 6781558Srgrimes} 6791558Srgrimes 6801558Srgrimes/* 6811558Srgrimes * free a directory inode 6821558Srgrimes */ 6837585Sbdestatic void 6841558Srgrimesfreedir(ino, parent) 6851558Srgrimes ino_t ino, parent; 6861558Srgrimes{ 6871558Srgrimes struct dinode *dp; 6881558Srgrimes 6891558Srgrimes if (ino != parent) { 6901558Srgrimes dp = ginode(parent); 6911558Srgrimes dp->di_nlink--; 6921558Srgrimes inodirty(); 6931558Srgrimes } 6941558Srgrimes freeino(ino); 6951558Srgrimes} 6961558Srgrimes 6971558Srgrimes/* 6981558Srgrimes * generate a temporary name for the lost+found directory. 6991558Srgrimes */ 70023675Speterstatic int 7011558Srgrimeslftempname(bufp, ino) 7021558Srgrimes char *bufp; 7031558Srgrimes ino_t ino; 7041558Srgrimes{ 7051558Srgrimes register ino_t in; 7061558Srgrimes register char *cp; 7071558Srgrimes int namlen; 7081558Srgrimes 7091558Srgrimes cp = bufp + 2; 7101558Srgrimes for (in = maxino; in > 0; in /= 10) 7111558Srgrimes cp++; 7121558Srgrimes *--cp = 0; 7131558Srgrimes namlen = cp - bufp; 7141558Srgrimes in = ino; 7151558Srgrimes while (cp > bufp) { 7161558Srgrimes *--cp = (in % 10) + '0'; 7171558Srgrimes in /= 10; 7181558Srgrimes } 7191558Srgrimes *cp = '#'; 7201558Srgrimes return (namlen); 7211558Srgrimes} 7221558Srgrimes 7231558Srgrimes/* 7241558Srgrimes * Get a directory block. 7251558Srgrimes * Insure that it is held until another is requested. 7261558Srgrimes */ 72723675Speterstatic struct bufarea * 7281558Srgrimesgetdirblk(blkno, size) 72923675Speter ufs_daddr_t blkno; 7301558Srgrimes long size; 7311558Srgrimes{ 7321558Srgrimes 7331558Srgrimes if (pdirbp != 0) 7341558Srgrimes pdirbp->b_flags &= ~B_INUSE; 7351558Srgrimes pdirbp = getdatablk(blkno, size); 7361558Srgrimes return (pdirbp); 7371558Srgrimes} 738