dir.c revision 37236
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 3537000Scharnier#if 0 3623675Speterstatic const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; 3737000Scharnier#endif 3837000Scharnierstatic const char rcsid[] = 3937236Sbde "$Id: dir.c,v 1.10 1998/06/15 07:07:10 charnier Exp $"; 401558Srgrimes#endif /* not lint */ 411558Srgrimes 421558Srgrimes#include <sys/param.h> 4323675Speter 441558Srgrimes#include <ufs/ufs/dinode.h> 451558Srgrimes#include <ufs/ufs/dir.h> 461558Srgrimes#include <ufs/ffs/fs.h> 4723796Sbde 4823675Speter#include <err.h> 491558Srgrimes#include <string.h> 5023675Speter 511558Srgrimes#include "fsck.h" 521558Srgrimes 531558Srgrimeschar *lfname = "lost+found"; 541558Srgrimesint lfmode = 01777; 551558Srgrimesstruct dirtemplate emptydir = { 0, DIRBLKSIZ }; 561558Srgrimesstruct dirtemplate dirhead = { 571558Srgrimes 0, 12, DT_DIR, 1, ".", 581558Srgrimes 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 591558Srgrimes}; 601558Srgrimesstruct odirtemplate odirhead = { 611558Srgrimes 0, 12, 1, ".", 621558Srgrimes 0, DIRBLKSIZ - 12, 2, ".." 631558Srgrimes}; 641558Srgrimes 6523675Speterstatic int chgino __P((struct inodesc *)); 6623675Speterstatic int dircheck __P((struct inodesc *, struct direct *)); 6723675Speterstatic int expanddir __P((struct dinode *dp, char *name)); 6823675Speterstatic void freedir __P((ino_t ino, ino_t parent)); 6923675Speterstatic struct direct *fsck_readdir __P((struct inodesc *)); 7023675Speterstatic struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size)); 7123675Speterstatic int lftempname __P((char *bufp, ino_t ino)); 7223675Speterstatic int mkentry __P((struct inodesc *)); 731558Srgrimes 741558Srgrimes/* 751558Srgrimes * Propagate connected state through the tree. 761558Srgrimes */ 777585Sbdevoid 781558Srgrimespropagate() 791558Srgrimes{ 801558Srgrimes register struct inoinfo **inpp, *inp; 811558Srgrimes struct inoinfo **inpend; 821558Srgrimes long change; 831558Srgrimes 841558Srgrimes inpend = &inpsort[inplast]; 851558Srgrimes do { 861558Srgrimes change = 0; 871558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 881558Srgrimes inp = *inpp; 891558Srgrimes if (inp->i_parent == 0) 901558Srgrimes continue; 911558Srgrimes if (statemap[inp->i_parent] == DFOUND && 921558Srgrimes statemap[inp->i_number] == DSTATE) { 931558Srgrimes statemap[inp->i_number] = DFOUND; 941558Srgrimes change++; 951558Srgrimes } 961558Srgrimes } 971558Srgrimes } while (change > 0); 981558Srgrimes} 991558Srgrimes 1001558Srgrimes/* 1011558Srgrimes * Scan each entry in a directory block. 1021558Srgrimes */ 1037585Sbdeint 1041558Srgrimesdirscan(idesc) 1051558Srgrimes register struct inodesc *idesc; 1061558Srgrimes{ 1071558Srgrimes register struct direct *dp; 1081558Srgrimes register struct bufarea *bp; 1091558Srgrimes 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; 12623675Speter memmove(dbuf, dp, (size_t)dsize); 1271558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1281558Srgrimes if (!newinofmt) { 1291558Srgrimes struct direct *tdp = (struct direct *)dbuf; 1301558Srgrimes u_char tmp; 1311558Srgrimes 1321558Srgrimes tmp = tdp->d_namlen; 1331558Srgrimes tdp->d_namlen = tdp->d_type; 1341558Srgrimes tdp->d_type = tmp; 1351558Srgrimes } 1361558Srgrimes# endif 1371558Srgrimes idesc->id_dirp = (struct direct *)dbuf; 1381558Srgrimes if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 1391558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1401558Srgrimes if (!newinofmt && !doinglevel2) { 1411558Srgrimes struct direct *tdp; 1421558Srgrimes u_char tmp; 1431558Srgrimes 1441558Srgrimes tdp = (struct direct *)dbuf; 1451558Srgrimes tmp = tdp->d_namlen; 1461558Srgrimes tdp->d_namlen = tdp->d_type; 1471558Srgrimes tdp->d_type = tmp; 1481558Srgrimes } 1491558Srgrimes# endif 1501558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 15123675Speter memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 1521558Srgrimes (size_t)dsize); 1531558Srgrimes dirty(bp); 1541558Srgrimes sbdirty(); 1551558Srgrimes } 1568871Srgrimes if (n & STOP) 1571558Srgrimes return (n); 1581558Srgrimes } 1591558Srgrimes return (idesc->id_filesize > 0 ? KEEPON : STOP); 1601558Srgrimes} 1611558Srgrimes 1621558Srgrimes/* 1631558Srgrimes * get next entry in a directory. 1641558Srgrimes */ 16523675Speterstatic struct direct * 1661558Srgrimesfsck_readdir(idesc) 1671558Srgrimes register struct inodesc *idesc; 1681558Srgrimes{ 1691558Srgrimes register struct direct *dp, *ndp; 1701558Srgrimes register struct bufarea *bp; 1711558Srgrimes long size, blksiz, fix, dploc; 1721558Srgrimes 1731558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1741558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1751558Srgrimes if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 1761558Srgrimes idesc->id_loc < blksiz) { 1771558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1781558Srgrimes if (dircheck(idesc, dp)) 1791558Srgrimes goto dpok; 18023675Speter if (idesc->id_fix == IGNORE) 18123675Speter return (0); 1821558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1831558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1841558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1851558Srgrimes dp->d_reclen = DIRBLKSIZ; 1861558Srgrimes dp->d_ino = 0; 1871558Srgrimes dp->d_type = 0; 1881558Srgrimes dp->d_namlen = 0; 1891558Srgrimes dp->d_name[0] = '\0'; 1901558Srgrimes if (fix) 1911558Srgrimes dirty(bp); 1921558Srgrimes idesc->id_loc += DIRBLKSIZ; 1931558Srgrimes idesc->id_filesize -= DIRBLKSIZ; 1941558Srgrimes return (dp); 1951558Srgrimes } 1961558Srgrimesdpok: 1971558Srgrimes if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 1981558Srgrimes return NULL; 1991558Srgrimes dploc = idesc->id_loc; 2001558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2011558Srgrimes idesc->id_loc += dp->d_reclen; 2021558Srgrimes idesc->id_filesize -= dp->d_reclen; 2031558Srgrimes if ((idesc->id_loc % DIRBLKSIZ) == 0) 2041558Srgrimes return (dp); 2051558Srgrimes ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 2061558Srgrimes if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 2071558Srgrimes dircheck(idesc, ndp) == 0) { 2081558Srgrimes size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 2091558Srgrimes idesc->id_loc += size; 2101558Srgrimes idesc->id_filesize -= size; 21123675Speter if (idesc->id_fix == IGNORE) 21223675Speter return (0); 2131558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 2141558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 2151558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2161558Srgrimes dp->d_reclen += size; 2171558Srgrimes if (fix) 2181558Srgrimes dirty(bp); 2191558Srgrimes } 2201558Srgrimes return (dp); 2211558Srgrimes} 2221558Srgrimes 2231558Srgrimes/* 2241558Srgrimes * Verify that a directory entry is valid. 2251558Srgrimes * This is a superset of the checks made in the kernel. 2261558Srgrimes */ 22723675Speterstatic int 2281558Srgrimesdircheck(idesc, dp) 2291558Srgrimes struct inodesc *idesc; 2301558Srgrimes register struct direct *dp; 2311558Srgrimes{ 2321558Srgrimes register int size; 2331558Srgrimes register char *cp; 2341558Srgrimes u_char namlen, type; 2351558Srgrimes int spaceleft; 2361558Srgrimes 23723675Speter spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 23823675Speter if (dp->d_ino >= maxino || 23923675Speter dp->d_reclen == 0 || 24023675Speter dp->d_reclen > spaceleft || 24123675Speter (dp->d_reclen & 0x3) != 0) 24223675Speter return (0); 24323675Speter if (dp->d_ino == 0) 24423675Speter return (1); 2451558Srgrimes size = DIRSIZ(!newinofmt, dp); 2461558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 2471558Srgrimes if (!newinofmt) { 2481558Srgrimes type = dp->d_namlen; 2491558Srgrimes namlen = dp->d_type; 2501558Srgrimes } else { 2511558Srgrimes namlen = dp->d_namlen; 2521558Srgrimes type = dp->d_type; 2531558Srgrimes } 2541558Srgrimes# else 2551558Srgrimes namlen = dp->d_namlen; 2561558Srgrimes type = dp->d_type; 2571558Srgrimes# endif 25823675Speter if (dp->d_reclen < size || 25923675Speter idesc->id_filesize < size || 26023675Speter namlen > MAXNAMLEN || 26123675Speter type > 15) 26223675Speter return (0); 26323675Speter for (cp = dp->d_name, size = 0; size < namlen; size++) 26423675Speter if (*cp == '\0' || (*cp++ == '/')) 26523675Speter return (0); 26623675Speter if (*cp != '\0') 26723675Speter return (0); 26823675Speter return (1); 2691558Srgrimes} 2701558Srgrimes 2717585Sbdevoid 2721558Srgrimesdirerror(ino, errmesg) 2731558Srgrimes ino_t ino; 2741558Srgrimes char *errmesg; 2751558Srgrimes{ 2761558Srgrimes 2771558Srgrimes fileerror(ino, ino, errmesg); 2781558Srgrimes} 2791558Srgrimes 2807585Sbdevoid 2811558Srgrimesfileerror(cwd, ino, errmesg) 2821558Srgrimes ino_t cwd, ino; 2831558Srgrimes char *errmesg; 2841558Srgrimes{ 2851558Srgrimes register struct dinode *dp; 2861558Srgrimes char pathbuf[MAXPATHLEN + 1]; 2871558Srgrimes 2881558Srgrimes pwarn("%s ", errmesg); 2891558Srgrimes pinode(ino); 2901558Srgrimes printf("\n"); 2911558Srgrimes getpathname(pathbuf, cwd, ino); 2921558Srgrimes if (ino < ROOTINO || ino > maxino) { 2931558Srgrimes pfatal("NAME=%s\n", pathbuf); 2941558Srgrimes return; 2951558Srgrimes } 2961558Srgrimes dp = ginode(ino); 2971558Srgrimes if (ftypeok(dp)) 2981558Srgrimes pfatal("%s=%s\n", 2991558Srgrimes (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 3001558Srgrimes else 3011558Srgrimes pfatal("NAME=%s\n", pathbuf); 3021558Srgrimes} 3031558Srgrimes 3047585Sbdevoid 3051558Srgrimesadjust(idesc, lcnt) 3061558Srgrimes register struct inodesc *idesc; 30723675Speter int lcnt; 3081558Srgrimes{ 3091558Srgrimes register struct dinode *dp; 3101558Srgrimes 3111558Srgrimes dp = ginode(idesc->id_number); 3121558Srgrimes if (dp->di_nlink == lcnt) { 3131558Srgrimes if (linkup(idesc->id_number, (ino_t)0) == 0) 3141558Srgrimes clri(idesc, "UNREF", 0); 3151558Srgrimes } else { 3161558Srgrimes pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 3171558Srgrimes ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 3181558Srgrimes pinode(idesc->id_number); 3191558Srgrimes printf(" COUNT %d SHOULD BE %d", 3201558Srgrimes dp->di_nlink, dp->di_nlink - lcnt); 32134266Sjulian if (preen || usedsoftdep) { 3221558Srgrimes if (lcnt < 0) { 3231558Srgrimes printf("\n"); 3241558Srgrimes pfatal("LINK COUNT INCREASING"); 3251558Srgrimes } 32634266Sjulian if (preen) 32734266Sjulian printf(" (ADJUSTED)\n"); 3281558Srgrimes } 3291558Srgrimes if (preen || reply("ADJUST") == 1) { 3301558Srgrimes dp->di_nlink -= lcnt; 3311558Srgrimes inodirty(); 3321558Srgrimes } 3331558Srgrimes } 3341558Srgrimes} 3351558Srgrimes 33623675Speterstatic int 3371558Srgrimesmkentry(idesc) 3381558Srgrimes struct inodesc *idesc; 3391558Srgrimes{ 3401558Srgrimes register struct direct *dirp = idesc->id_dirp; 3411558Srgrimes struct direct newent; 3421558Srgrimes int newlen, oldlen; 3431558Srgrimes 3441558Srgrimes newent.d_namlen = strlen(idesc->id_name); 3451558Srgrimes newlen = DIRSIZ(0, &newent); 3461558Srgrimes if (dirp->d_ino != 0) 3471558Srgrimes oldlen = DIRSIZ(0, dirp); 3481558Srgrimes else 3491558Srgrimes oldlen = 0; 3501558Srgrimes if (dirp->d_reclen - oldlen < newlen) 3511558Srgrimes return (KEEPON); 3521558Srgrimes newent.d_reclen = dirp->d_reclen - oldlen; 3531558Srgrimes dirp->d_reclen = oldlen; 3541558Srgrimes dirp = (struct direct *)(((char *)dirp) + oldlen); 3551558Srgrimes dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 35623675Speter dirp->d_reclen = newent.d_reclen; 35723675Speter if (newinofmt) 3581558Srgrimes dirp->d_type = typemap[idesc->id_parent]; 35923675Speter else 36023675Speter dirp->d_type = 0; 36123675Speter dirp->d_namlen = newent.d_namlen; 36223675Speter memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 36323675Speter# if (BYTE_ORDER == LITTLE_ENDIAN) 36423675Speter /* 36523675Speter * If the entry was split, dirscan() will only reverse the byte 36623675Speter * order of the original entry, and not the new one, before 36723675Speter * writing it back out. So, we reverse the byte order here if 36823675Speter * necessary. 36923675Speter */ 37023675Speter if (oldlen != 0 && !newinofmt && !doinglevel2) { 37123675Speter u_char tmp; 37223675Speter 37323675Speter tmp = dirp->d_namlen; 37423675Speter dirp->d_namlen = dirp->d_type; 37523675Speter dirp->d_type = tmp; 37623675Speter } 37723675Speter# endif 3781558Srgrimes return (ALTERED|STOP); 3791558Srgrimes} 3801558Srgrimes 38123675Speterstatic int 3821558Srgrimeschgino(idesc) 3831558Srgrimes struct inodesc *idesc; 3841558Srgrimes{ 3851558Srgrimes register struct direct *dirp = idesc->id_dirp; 3861558Srgrimes 38723675Speter if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 3881558Srgrimes return (KEEPON); 3891558Srgrimes dirp->d_ino = idesc->id_parent; 3901558Srgrimes if (newinofmt) 3911558Srgrimes dirp->d_type = typemap[idesc->id_parent]; 3921558Srgrimes else 3931558Srgrimes dirp->d_type = 0; 3941558Srgrimes return (ALTERED|STOP); 3951558Srgrimes} 3961558Srgrimes 3977585Sbdeint 3981558Srgrimeslinkup(orphan, parentdir) 3991558Srgrimes ino_t orphan; 4001558Srgrimes ino_t parentdir; 4011558Srgrimes{ 4021558Srgrimes register struct dinode *dp; 4031558Srgrimes int lostdir; 4041558Srgrimes ino_t oldlfdir; 4051558Srgrimes struct inodesc idesc; 4061558Srgrimes char tempname[BUFSIZ]; 4071558Srgrimes 40823675Speter memset(&idesc, 0, sizeof(struct inodesc)); 4091558Srgrimes dp = ginode(orphan); 4101558Srgrimes lostdir = (dp->di_mode & IFMT) == IFDIR; 4111558Srgrimes pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 4121558Srgrimes pinode(orphan); 41334266Sjulian if ((preen || usedsoftdep) && dp->di_size == 0) 4141558Srgrimes return (0); 4151558Srgrimes if (preen) 4161558Srgrimes printf(" (RECONNECTED)\n"); 4171558Srgrimes else 4181558Srgrimes if (reply("RECONNECT") == 0) 4191558Srgrimes return (0); 42034266Sjulian if (parentdir != 0) 42134266Sjulian lncntp[parentdir]++; 4221558Srgrimes if (lfdir == 0) { 4231558Srgrimes dp = ginode(ROOTINO); 4241558Srgrimes idesc.id_name = lfname; 4251558Srgrimes idesc.id_type = DATA; 4261558Srgrimes idesc.id_func = findino; 4271558Srgrimes idesc.id_number = ROOTINO; 4281558Srgrimes if ((ckinode(dp, &idesc) & FOUND) != 0) { 4291558Srgrimes lfdir = idesc.id_parent; 4301558Srgrimes } else { 4311558Srgrimes pwarn("NO lost+found DIRECTORY"); 4321558Srgrimes if (preen || reply("CREATE")) { 4331558Srgrimes lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 4341558Srgrimes if (lfdir != 0) { 4351558Srgrimes if (makeentry(ROOTINO, lfdir, lfname) != 0) { 4361558Srgrimes if (preen) 4371558Srgrimes printf(" (CREATED)\n"); 4381558Srgrimes } else { 4391558Srgrimes freedir(lfdir, ROOTINO); 4401558Srgrimes lfdir = 0; 4411558Srgrimes if (preen) 4421558Srgrimes printf("\n"); 4431558Srgrimes } 4441558Srgrimes } 4451558Srgrimes } 4461558Srgrimes } 4471558Srgrimes if (lfdir == 0) { 4481558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 4491558Srgrimes printf("\n\n"); 4501558Srgrimes return (0); 4511558Srgrimes } 4521558Srgrimes } 4531558Srgrimes dp = ginode(lfdir); 4541558Srgrimes if ((dp->di_mode & IFMT) != IFDIR) { 4551558Srgrimes pfatal("lost+found IS NOT A DIRECTORY"); 4561558Srgrimes if (reply("REALLOCATE") == 0) 4571558Srgrimes return (0); 4581558Srgrimes oldlfdir = lfdir; 4591558Srgrimes if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 4601558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4611558Srgrimes return (0); 4621558Srgrimes } 4631558Srgrimes if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 4641558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4651558Srgrimes return (0); 4661558Srgrimes } 4671558Srgrimes inodirty(); 4681558Srgrimes idesc.id_type = ADDR; 4691558Srgrimes idesc.id_func = pass4check; 4701558Srgrimes idesc.id_number = oldlfdir; 4711558Srgrimes adjust(&idesc, lncntp[oldlfdir] + 1); 4721558Srgrimes lncntp[oldlfdir] = 0; 4731558Srgrimes dp = ginode(lfdir); 4741558Srgrimes } 4751558Srgrimes if (statemap[lfdir] != DFOUND) { 4761558Srgrimes pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 4771558Srgrimes return (0); 4781558Srgrimes } 4791558Srgrimes (void)lftempname(tempname, orphan); 4801558Srgrimes if (makeentry(lfdir, orphan, tempname) == 0) { 4811558Srgrimes pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 4821558Srgrimes printf("\n\n"); 4831558Srgrimes return (0); 4841558Srgrimes } 4851558Srgrimes lncntp[orphan]--; 4861558Srgrimes if (lostdir) { 4871558Srgrimes if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 4881558Srgrimes parentdir != (ino_t)-1) 4891558Srgrimes (void)makeentry(orphan, lfdir, ".."); 4901558Srgrimes dp = ginode(lfdir); 4911558Srgrimes dp->di_nlink++; 4921558Srgrimes inodirty(); 4931558Srgrimes lncntp[lfdir]++; 4941558Srgrimes pwarn("DIR I=%lu CONNECTED. ", orphan); 49515699Snate if (parentdir != (ino_t)-1) { 49637236Sbde printf("PARENT WAS I=%lu\n", (u_long)parentdir); 49723796Sbde /* 49815699Snate * The parent directory, because of the ordering 49915699Snate * guarantees, has had the link count incremented 50015699Snate * for the child, but no entry was made. This 50115699Snate * fixes the parent link count so that fsck does 50215699Snate * not need to be rerun. 50315699Snate */ 50415699Snate lncntp[parentdir]++; 50515699Snate 50615699Snate } 5071558Srgrimes if (preen == 0) 5081558Srgrimes printf("\n"); 5091558Srgrimes } 5101558Srgrimes return (1); 5111558Srgrimes} 5121558Srgrimes 5131558Srgrimes/* 5141558Srgrimes * fix an entry in a directory. 5151558Srgrimes */ 5167585Sbdeint 5171558Srgrimeschangeino(dir, name, newnum) 5181558Srgrimes ino_t dir; 5191558Srgrimes char *name; 5201558Srgrimes ino_t newnum; 5211558Srgrimes{ 5221558Srgrimes struct inodesc idesc; 5231558Srgrimes 52423675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5251558Srgrimes idesc.id_type = DATA; 5261558Srgrimes idesc.id_func = chgino; 5271558Srgrimes idesc.id_number = dir; 5281558Srgrimes idesc.id_fix = DONTKNOW; 5291558Srgrimes idesc.id_name = name; 5301558Srgrimes idesc.id_parent = newnum; /* new value for name */ 5311558Srgrimes return (ckinode(ginode(dir), &idesc)); 5321558Srgrimes} 5331558Srgrimes 5341558Srgrimes/* 5351558Srgrimes * make an entry in a directory 5361558Srgrimes */ 5377585Sbdeint 5381558Srgrimesmakeentry(parent, ino, name) 5391558Srgrimes ino_t parent, ino; 5401558Srgrimes char *name; 5411558Srgrimes{ 5421558Srgrimes struct dinode *dp; 5431558Srgrimes struct inodesc idesc; 5441558Srgrimes char pathbuf[MAXPATHLEN + 1]; 5458871Srgrimes 5461558Srgrimes if (parent < ROOTINO || parent >= maxino || 5471558Srgrimes ino < ROOTINO || ino >= maxino) 5481558Srgrimes return (0); 54923675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5501558Srgrimes idesc.id_type = DATA; 5511558Srgrimes idesc.id_func = mkentry; 5521558Srgrimes idesc.id_number = parent; 5531558Srgrimes idesc.id_parent = ino; /* this is the inode to enter */ 5541558Srgrimes idesc.id_fix = DONTKNOW; 5551558Srgrimes idesc.id_name = name; 5561558Srgrimes dp = ginode(parent); 5571558Srgrimes if (dp->di_size % DIRBLKSIZ) { 5581558Srgrimes dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 5591558Srgrimes inodirty(); 5601558Srgrimes } 5611558Srgrimes if ((ckinode(dp, &idesc) & ALTERED) != 0) 5621558Srgrimes return (1); 5631558Srgrimes getpathname(pathbuf, parent, parent); 5641558Srgrimes dp = ginode(parent); 5651558Srgrimes if (expanddir(dp, pathbuf) == 0) 5661558Srgrimes return (0); 5671558Srgrimes return (ckinode(dp, &idesc) & ALTERED); 5681558Srgrimes} 5691558Srgrimes 5701558Srgrimes/* 5711558Srgrimes * Attempt to expand the size of a directory 5721558Srgrimes */ 57323675Speterstatic int 5741558Srgrimesexpanddir(dp, name) 5751558Srgrimes register struct dinode *dp; 5761558Srgrimes char *name; 5771558Srgrimes{ 57823675Speter ufs_daddr_t lastbn, newblk; 5791558Srgrimes register struct bufarea *bp; 5801558Srgrimes char *cp, firstblk[DIRBLKSIZ]; 5811558Srgrimes 5821558Srgrimes lastbn = lblkno(&sblock, dp->di_size); 5831558Srgrimes if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 5841558Srgrimes return (0); 5851558Srgrimes if ((newblk = allocblk(sblock.fs_frag)) == 0) 5861558Srgrimes return (0); 5871558Srgrimes dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 5881558Srgrimes dp->di_db[lastbn] = newblk; 5891558Srgrimes dp->di_size += sblock.fs_bsize; 5901558Srgrimes dp->di_blocks += btodb(sblock.fs_bsize); 5911558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 5921558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 5931558Srgrimes if (bp->b_errs) 5941558Srgrimes goto bad; 59523675Speter memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 5961558Srgrimes bp = getdirblk(newblk, sblock.fs_bsize); 5971558Srgrimes if (bp->b_errs) 5981558Srgrimes goto bad; 59923675Speter memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 6001558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6011558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_bsize]; 6021558Srgrimes cp += DIRBLKSIZ) 60323675Speter memmove(cp, &emptydir, sizeof emptydir); 6041558Srgrimes dirty(bp); 6051558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 6061558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 6071558Srgrimes if (bp->b_errs) 6081558Srgrimes goto bad; 60923675Speter memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 6101558Srgrimes pwarn("NO SPACE LEFT IN %s", name); 6111558Srgrimes if (preen) 6121558Srgrimes printf(" (EXPANDED)\n"); 6131558Srgrimes else if (reply("EXPAND") == 0) 6141558Srgrimes goto bad; 6151558Srgrimes dirty(bp); 6161558Srgrimes inodirty(); 6171558Srgrimes return (1); 6181558Srgrimesbad: 6191558Srgrimes dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 6201558Srgrimes dp->di_db[lastbn + 1] = 0; 6211558Srgrimes dp->di_size -= sblock.fs_bsize; 6221558Srgrimes dp->di_blocks -= btodb(sblock.fs_bsize); 6231558Srgrimes freeblk(newblk, sblock.fs_frag); 6241558Srgrimes return (0); 6251558Srgrimes} 6261558Srgrimes 6271558Srgrimes/* 6281558Srgrimes * allocate a new directory 6291558Srgrimes */ 6307586Sbdeino_t 6311558Srgrimesallocdir(parent, request, mode) 6321558Srgrimes ino_t parent, request; 6331558Srgrimes int mode; 6341558Srgrimes{ 6351558Srgrimes ino_t ino; 6361558Srgrimes char *cp; 6371558Srgrimes struct dinode *dp; 6381558Srgrimes register struct bufarea *bp; 6391558Srgrimes struct dirtemplate *dirp; 6401558Srgrimes 6411558Srgrimes ino = allocino(request, IFDIR|mode); 6421558Srgrimes if (newinofmt) 6431558Srgrimes dirp = &dirhead; 6441558Srgrimes else 6451558Srgrimes dirp = (struct dirtemplate *)&odirhead; 6461558Srgrimes dirp->dot_ino = ino; 6471558Srgrimes dirp->dotdot_ino = parent; 6481558Srgrimes dp = ginode(ino); 6491558Srgrimes bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 6501558Srgrimes if (bp->b_errs) { 6511558Srgrimes freeino(ino); 6521558Srgrimes return (0); 6531558Srgrimes } 65423675Speter memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 6551558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6561558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_fsize]; 6571558Srgrimes cp += DIRBLKSIZ) 65823675Speter memmove(cp, &emptydir, sizeof emptydir); 6591558Srgrimes dirty(bp); 6601558Srgrimes dp->di_nlink = 2; 6611558Srgrimes inodirty(); 6621558Srgrimes if (ino == ROOTINO) { 6631558Srgrimes lncntp[ino] = dp->di_nlink; 6641558Srgrimes cacheino(dp, ino); 6651558Srgrimes return(ino); 6661558Srgrimes } 6671558Srgrimes if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 6681558Srgrimes freeino(ino); 6691558Srgrimes return (0); 6701558Srgrimes } 6711558Srgrimes cacheino(dp, ino); 6721558Srgrimes statemap[ino] = statemap[parent]; 6731558Srgrimes if (statemap[ino] == DSTATE) { 6741558Srgrimes lncntp[ino] = dp->di_nlink; 6751558Srgrimes lncntp[parent]++; 6761558Srgrimes } 6771558Srgrimes dp = ginode(parent); 6781558Srgrimes dp->di_nlink++; 6791558Srgrimes inodirty(); 6801558Srgrimes return (ino); 6811558Srgrimes} 6821558Srgrimes 6831558Srgrimes/* 6841558Srgrimes * free a directory inode 6851558Srgrimes */ 6867585Sbdestatic void 6871558Srgrimesfreedir(ino, parent) 6881558Srgrimes ino_t ino, parent; 6891558Srgrimes{ 6901558Srgrimes struct dinode *dp; 6911558Srgrimes 6921558Srgrimes if (ino != parent) { 6931558Srgrimes dp = ginode(parent); 6941558Srgrimes dp->di_nlink--; 6951558Srgrimes inodirty(); 6961558Srgrimes } 6971558Srgrimes freeino(ino); 6981558Srgrimes} 6991558Srgrimes 7001558Srgrimes/* 7011558Srgrimes * generate a temporary name for the lost+found directory. 7021558Srgrimes */ 70323675Speterstatic int 7041558Srgrimeslftempname(bufp, ino) 7051558Srgrimes char *bufp; 7061558Srgrimes ino_t ino; 7071558Srgrimes{ 7081558Srgrimes register ino_t in; 7091558Srgrimes register char *cp; 7101558Srgrimes int namlen; 7111558Srgrimes 7121558Srgrimes cp = bufp + 2; 7131558Srgrimes for (in = maxino; in > 0; in /= 10) 7141558Srgrimes cp++; 7151558Srgrimes *--cp = 0; 7161558Srgrimes namlen = cp - bufp; 7171558Srgrimes in = ino; 7181558Srgrimes while (cp > bufp) { 7191558Srgrimes *--cp = (in % 10) + '0'; 7201558Srgrimes in /= 10; 7211558Srgrimes } 7221558Srgrimes *cp = '#'; 7231558Srgrimes return (namlen); 7241558Srgrimes} 7251558Srgrimes 7261558Srgrimes/* 7271558Srgrimes * Get a directory block. 7281558Srgrimes * Insure that it is held until another is requested. 7291558Srgrimes */ 73023675Speterstatic struct bufarea * 7311558Srgrimesgetdirblk(blkno, size) 73223675Speter ufs_daddr_t blkno; 7331558Srgrimes long size; 7341558Srgrimes{ 7351558Srgrimes 7361558Srgrimes if (pdirbp != 0) 7371558Srgrimes pdirbp->b_flags &= ~B_INUSE; 7381558Srgrimes pdirbp = getdatablk(blkno, size); 7391558Srgrimes return (pdirbp); 7401558Srgrimes} 741