dir.c revision 34266
11592Srgrimes/* 21592Srgrimes * Copyright (c) 1980, 1986, 1993 31592Srgrimes * The Regents of the University of California. All rights reserved. 41592Srgrimes * 51592Srgrimes * Redistribution and use in source and binary forms, with or without 61592Srgrimes * modification, are permitted provided that the following conditions 71592Srgrimes * are met: 81592Srgrimes * 1. Redistributions of source code must retain the above copyright 91592Srgrimes * notice, this list of conditions and the following disclaimer. 101592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111592Srgrimes * notice, this list of conditions and the following disclaimer in the 121592Srgrimes * documentation and/or other materials provided with the distribution. 131592Srgrimes * 3. All advertising materials mentioning features or use of this software 141592Srgrimes * must display the following acknowledgement: 151592Srgrimes * This product includes software developed by the University of 161592Srgrimes * California, Berkeley and its contributors. 171592Srgrimes * 4. Neither the name of the University nor the names of its contributors 181592Srgrimes * may be used to endorse or promote products derived from this software 191592Srgrimes * without specific prior written permission. 201592Srgrimes * 211592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311592Srgrimes * SUCH DAMAGE. 3218471Swosch */ 3324191Simp 341592Srgrimes#ifndef lint 351592Srgrimesstatic const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; 361592Srgrimes#endif /* not lint */ 371592Srgrimes 381592Srgrimes#include <sys/param.h> 391592Srgrimes#include <sys/time.h> 401592Srgrimes 411592Srgrimes#include <ufs/ufs/dinode.h> 421592Srgrimes#include <ufs/ufs/dir.h> 431592Srgrimes#include <ufs/ffs/fs.h> 441592Srgrimes 451592Srgrimes#include <err.h> 461592Srgrimes#include <string.h> 471592Srgrimes 481592Srgrimes#include "fsck.h" 491592Srgrimes 501592Srgrimeschar *lfname = "lost+found"; 511592Srgrimesint lfmode = 01777; 521592Srgrimesstruct dirtemplate emptydir = { 0, DIRBLKSIZ }; 531592Srgrimesstruct dirtemplate dirhead = { 541592Srgrimes 0, 12, DT_DIR, 1, ".", 551592Srgrimes 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 561592Srgrimes}; 571592Srgrimesstruct odirtemplate odirhead = { 581592Srgrimes 0, 12, 1, ".", 591592Srgrimes 0, DIRBLKSIZ - 12, 2, ".." 601592Srgrimes}; 611592Srgrimes 621592Srgrimesstatic int chgino __P((struct inodesc *)); 631592Srgrimesstatic int dircheck __P((struct inodesc *, struct direct *)); 641592Srgrimesstatic int expanddir __P((struct dinode *dp, char *name)); 651592Srgrimesstatic void freedir __P((ino_t ino, ino_t parent)); 6611486Sdgstatic struct direct *fsck_readdir __P((struct inodesc *)); 671592Srgrimesstatic struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size)); 681592Srgrimesstatic int lftempname __P((char *bufp, ino_t ino)); 691592Srgrimesstatic int mkentry __P((struct inodesc *)); 701592Srgrimes 711592Srgrimes/* 721592Srgrimes * Propagate connected state through the tree. 731592Srgrimes */ 741592Srgrimesvoid 751592Srgrimespropagate() 761592Srgrimes{ 771592Srgrimes register struct inoinfo **inpp, *inp; 781592Srgrimes struct inoinfo **inpend; 791592Srgrimes long change; 801592Srgrimes 811592Srgrimes inpend = &inpsort[inplast]; 821592Srgrimes do { 831592Srgrimes change = 0; 8414024Smarkm for (inpp = inpsort; inpp < inpend; inpp++) { 851592Srgrimes inp = *inpp; 861592Srgrimes if (inp->i_parent == 0) 871592Srgrimes continue; 881592Srgrimes if (statemap[inp->i_parent] == DFOUND && 891592Srgrimes statemap[inp->i_number] == DSTATE) { 901592Srgrimes statemap[inp->i_number] = DFOUND; 911592Srgrimes change++; 921592Srgrimes } 931592Srgrimes } 941592Srgrimes } while (change > 0); 9511486Sdg} 961592Srgrimes 9711486Sdg/* 981592Srgrimes * Scan each entry in a directory block. 991592Srgrimes */ 1001592Srgrimesint 1011592Srgrimesdirscan(idesc) 1021592Srgrimes register struct inodesc *idesc; 1031592Srgrimes{ 1041592Srgrimes register struct direct *dp; 1051592Srgrimes register struct bufarea *bp; 1061592Srgrimes int dsize, n; 10711486Sdg long blksiz; 1081592Srgrimes char dbuf[DIRBLKSIZ]; 1091592Srgrimes 1101592Srgrimes if (idesc->id_type != DATA) 1111592Srgrimes errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 1121592Srgrimes if (idesc->id_entryno == 0 && 1131592Srgrimes (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 1141592Srgrimes idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 1151592Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1161592Srgrimes if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 1171592Srgrimes idesc->id_filesize -= blksiz; 1181592Srgrimes return (SKIP); 1191592Srgrimes } 1201592Srgrimes idesc->id_loc = 0; 1211592Srgrimes for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 1221592Srgrimes dsize = dp->d_reclen; 1231592Srgrimes memmove(dbuf, dp, (size_t)dsize); 1241592Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1251592Srgrimes if (!newinofmt) { 1261592Srgrimes struct direct *tdp = (struct direct *)dbuf; 1271592Srgrimes u_char tmp; 1281592Srgrimes 1291592Srgrimes tmp = tdp->d_namlen; 1301592Srgrimes tdp->d_namlen = tdp->d_type; 1311592Srgrimes tdp->d_type = tmp; 1321592Srgrimes } 1331592Srgrimes# endif 1341592Srgrimes idesc->id_dirp = (struct direct *)dbuf; 1351592Srgrimes if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 1361592Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1371592Srgrimes if (!newinofmt && !doinglevel2) { 13811486Sdg struct direct *tdp; 13911486Sdg u_char tmp; 14011486Sdg 1411592Srgrimes tdp = (struct direct *)dbuf; 1421592Srgrimes tmp = tdp->d_namlen; 1431592Srgrimes tdp->d_namlen = tdp->d_type; 1441592Srgrimes tdp->d_type = tmp; 1451592Srgrimes } 1461592Srgrimes# endif 1471592Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1481592Srgrimes memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 1491592Srgrimes (size_t)dsize); 1501592Srgrimes dirty(bp); 1511592Srgrimes sbdirty(); 1521592Srgrimes } 1531592Srgrimes if (n & STOP) 1541592Srgrimes return (n); 1551592Srgrimes } 1561592Srgrimes return (idesc->id_filesize > 0 ? KEEPON : STOP); 1571592Srgrimes} 1581592Srgrimes 1591592Srgrimes/* 1601592Srgrimes * get next entry in a directory. 1611592Srgrimes */ 1621592Srgrimesstatic struct direct * 1631592Srgrimesfsck_readdir(idesc) 1641592Srgrimes register struct inodesc *idesc; 1651592Srgrimes{ 1661592Srgrimes register struct direct *dp, *ndp; 1671592Srgrimes register struct bufarea *bp; 1681592Srgrimes long size, blksiz, fix, dploc; 1691592Srgrimes 1701592Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1711592Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1721592Srgrimes if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 1731592Srgrimes idesc->id_loc < blksiz) { 1741592Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1751592Srgrimes if (dircheck(idesc, dp)) 1761592Srgrimes goto dpok; 1771592Srgrimes if (idesc->id_fix == IGNORE) 1781592Srgrimes return (0); 1791592Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1801592Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1811592Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1821592Srgrimes dp->d_reclen = DIRBLKSIZ; 1831592Srgrimes dp->d_ino = 0; 1841592Srgrimes dp->d_type = 0; 1851592Srgrimes dp->d_namlen = 0; 18611486Sdg dp->d_name[0] = '\0'; 18711486Sdg if (fix) 18811486Sdg dirty(bp); 1891592Srgrimes idesc->id_loc += DIRBLKSIZ; 1901592Srgrimes idesc->id_filesize -= DIRBLKSIZ; 1911592Srgrimes return (dp); 19211486Sdg } 1931592Srgrimesdpok: 1941592Srgrimes if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 1951592Srgrimes return NULL; 1961592Srgrimes dploc = idesc->id_loc; 1971592Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 1981592Srgrimes idesc->id_loc += dp->d_reclen; 1991592Srgrimes idesc->id_filesize -= dp->d_reclen; 2001592Srgrimes if ((idesc->id_loc % DIRBLKSIZ) == 0) 2011592Srgrimes return (dp); 2021592Srgrimes ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 2031592Srgrimes if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 2041592Srgrimes dircheck(idesc, ndp) == 0) { 2051592Srgrimes size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 2061592Srgrimes idesc->id_loc += size; 2071592Srgrimes idesc->id_filesize -= size; 2081592Srgrimes if (idesc->id_fix == IGNORE) 2091592Srgrimes return (0); 2101592Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 2111592Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 2121592Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2131592Srgrimes dp->d_reclen += size; 2141592Srgrimes if (fix) 2151592Srgrimes dirty(bp); 2161592Srgrimes } 2171592Srgrimes return (dp); 2181592Srgrimes} 2191592Srgrimes 2201592Srgrimes/* 2211592Srgrimes * Verify that a directory entry is valid. 2221592Srgrimes * This is a superset of the checks made in the kernel. 2231592Srgrimes */ 2241592Srgrimesstatic int 2251592Srgrimesdircheck(idesc, dp) 2261592Srgrimes struct inodesc *idesc; 2271592Srgrimes register struct direct *dp; 2281592Srgrimes{ 22924191Simp register int size; 23024191Simp register char *cp; 23124191Simp u_char namlen, type; 23224191Simp int spaceleft; 23324191Simp 23424191Simp spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 2351592Srgrimes if (dp->d_ino >= maxino || 2361592Srgrimes dp->d_reclen == 0 || 2371592Srgrimes dp->d_reclen > spaceleft || 2381592Srgrimes (dp->d_reclen & 0x3) != 0) 2391592Srgrimes return (0); 2401592Srgrimes if (dp->d_ino == 0) 2411592Srgrimes return (1); 2421592Srgrimes size = DIRSIZ(!newinofmt, dp); 2431592Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 2441592Srgrimes if (!newinofmt) { 2451592Srgrimes type = dp->d_namlen; 2461592Srgrimes namlen = dp->d_type; 2471592Srgrimes } else { 2481592Srgrimes namlen = dp->d_namlen; 2491592Srgrimes type = dp->d_type; 2501592Srgrimes } 2511592Srgrimes# else 2521592Srgrimes namlen = dp->d_namlen; 2531592Srgrimes type = dp->d_type; 2541592Srgrimes# endif 2551592Srgrimes if (dp->d_reclen < size || 2561592Srgrimes idesc->id_filesize < size || 25722455Simp namlen > MAXNAMLEN || 25822455Simp type > 15) 2591592Srgrimes return (0); 2601592Srgrimes for (cp = dp->d_name, size = 0; size < namlen; size++) 2611592Srgrimes if (*cp == '\0' || (*cp++ == '/')) 2621592Srgrimes return (0); 2631592Srgrimes if (*cp != '\0') 2641592Srgrimes return (0); 2651592Srgrimes return (1); 2661592Srgrimes} 26722455Simp 26822455Simpvoid 26922455Simpdirerror(ino, errmesg) 27022455Simp ino_t ino; 27122455Simp char *errmesg; 27222455Simp{ 27322455Simp 27422455Simp fileerror(ino, ino, errmesg); 27522455Simp} 27622455Simp 27722455Simpvoid 27822455Simpfileerror(cwd, ino, errmesg) 2791592Srgrimes ino_t cwd, ino; 2801592Srgrimes char *errmesg; 2811592Srgrimes{ 2821592Srgrimes register struct dinode *dp; 2831592Srgrimes char pathbuf[MAXPATHLEN + 1]; 2841592Srgrimes 2851592Srgrimes pwarn("%s ", errmesg); 2861592Srgrimes pinode(ino); 2871592Srgrimes printf("\n"); 2881592Srgrimes getpathname(pathbuf, cwd, ino); 2891592Srgrimes if (ino < ROOTINO || ino > maxino) { 2901592Srgrimes pfatal("NAME=%s\n", pathbuf); 2911592Srgrimes return; 2921592Srgrimes } 2931592Srgrimes dp = ginode(ino); 2941592Srgrimes if (ftypeok(dp)) 2951592Srgrimes pfatal("%s=%s\n", 2961592Srgrimes (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 2971592Srgrimes else 2981592Srgrimes pfatal("NAME=%s\n", pathbuf); 2991592Srgrimes} 3001592Srgrimes 3011592Srgrimesvoid 3021592Srgrimesadjust(idesc, lcnt) 3031592Srgrimes register struct inodesc *idesc; 3041592Srgrimes int lcnt; 3051592Srgrimes{ 3061592Srgrimes register struct dinode *dp; 3071592Srgrimes 3081592Srgrimes dp = ginode(idesc->id_number); 30912575Snate if (dp->di_nlink == lcnt) { 3102076Sguido if (linkup(idesc->id_number, (ino_t)0) == 0) 3112076Sguido clri(idesc, "UNREF", 0); 3122076Sguido } else { 3132076Sguido pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 3141592Srgrimes ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 3151592Srgrimes pinode(idesc->id_number); 3161592Srgrimes printf(" COUNT %d SHOULD BE %d", 3171592Srgrimes dp->di_nlink, dp->di_nlink - lcnt); 3181592Srgrimes if (preen || usedsoftdep) { 3191592Srgrimes if (lcnt < 0) { 3201592Srgrimes printf("\n"); 3211592Srgrimes pfatal("LINK COUNT INCREASING"); 3221592Srgrimes } 3231592Srgrimes if (preen) 3241592Srgrimes printf(" (ADJUSTED)\n"); 3251592Srgrimes } 3261592Srgrimes if (preen || reply("ADJUST") == 1) { 3271592Srgrimes dp->di_nlink -= lcnt; 3281592Srgrimes inodirty(); 3291592Srgrimes } 3301592Srgrimes } 3311592Srgrimes} 3321592Srgrimes 3331592Srgrimesstatic int 3341592Srgrimesmkentry(idesc) 3351592Srgrimes struct inodesc *idesc; 3361592Srgrimes{ 3371592Srgrimes register struct direct *dirp = idesc->id_dirp; 3381592Srgrimes struct direct newent; 3391592Srgrimes int newlen, oldlen; 3401592Srgrimes 3411592Srgrimes newent.d_namlen = strlen(idesc->id_name); 3421592Srgrimes newlen = DIRSIZ(0, &newent); 3431592Srgrimes if (dirp->d_ino != 0) 3441592Srgrimes oldlen = DIRSIZ(0, dirp); 3451592Srgrimes else 3461592Srgrimes oldlen = 0; 3471592Srgrimes if (dirp->d_reclen - oldlen < newlen) 3481592Srgrimes return (KEEPON); 3491592Srgrimes newent.d_reclen = dirp->d_reclen - oldlen; 3501592Srgrimes dirp->d_reclen = oldlen; 3511592Srgrimes dirp = (struct direct *)(((char *)dirp) + oldlen); 3521592Srgrimes dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 3531592Srgrimes dirp->d_reclen = newent.d_reclen; 3541592Srgrimes if (newinofmt) 3551592Srgrimes dirp->d_type = typemap[idesc->id_parent]; 3561592Srgrimes else 3571592Srgrimes dirp->d_type = 0; 3581592Srgrimes dirp->d_namlen = newent.d_namlen; 3591592Srgrimes memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 3601592Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 3611592Srgrimes /* 3621592Srgrimes * If the entry was split, dirscan() will only reverse the byte 3631592Srgrimes * order of the original entry, and not the new one, before 3641592Srgrimes * writing it back out. So, we reverse the byte order here if 3651592Srgrimes * necessary. 3661592Srgrimes */ 3671592Srgrimes if (oldlen != 0 && !newinofmt && !doinglevel2) { 3681592Srgrimes u_char tmp; 3691592Srgrimes 3701592Srgrimes tmp = dirp->d_namlen; 3711592Srgrimes dirp->d_namlen = dirp->d_type; 3721592Srgrimes dirp->d_type = tmp; 3731592Srgrimes } 3741592Srgrimes# endif 3751592Srgrimes return (ALTERED|STOP); 3761592Srgrimes} 3771592Srgrimes 3781592Srgrimesstatic int 3791592Srgrimeschgino(idesc) 3801592Srgrimes struct inodesc *idesc; 3811592Srgrimes{ 3821592Srgrimes register struct direct *dirp = idesc->id_dirp; 3831592Srgrimes 3841592Srgrimes if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 3851592Srgrimes return (KEEPON); 3861592Srgrimes dirp->d_ino = idesc->id_parent; 3871592Srgrimes if (newinofmt) 3881592Srgrimes dirp->d_type = typemap[idesc->id_parent]; 3891592Srgrimes else 3901592Srgrimes dirp->d_type = 0; 3911592Srgrimes return (ALTERED|STOP); 3921592Srgrimes} 3931592Srgrimes 3941592Srgrimesint 3951592Srgrimeslinkup(orphan, parentdir) 3961592Srgrimes ino_t orphan; 3971592Srgrimes ino_t parentdir; 3981592Srgrimes{ 3991592Srgrimes register struct dinode *dp; 4001592Srgrimes int lostdir; 4011592Srgrimes ino_t oldlfdir; 4021592Srgrimes struct inodesc idesc; 4031592Srgrimes char tempname[BUFSIZ]; 4041592Srgrimes 4051592Srgrimes memset(&idesc, 0, sizeof(struct inodesc)); 4061592Srgrimes dp = ginode(orphan); 4071592Srgrimes lostdir = (dp->di_mode & IFMT) == IFDIR; 4081592Srgrimes pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 4091592Srgrimes pinode(orphan); 4101592Srgrimes if ((preen || usedsoftdep) && dp->di_size == 0) 4111592Srgrimes return (0); 4121592Srgrimes if (preen) 4131592Srgrimes printf(" (RECONNECTED)\n"); 4141592Srgrimes else 4151592Srgrimes if (reply("RECONNECT") == 0) 4161592Srgrimes return (0); 4171592Srgrimes if (parentdir != 0) 4181592Srgrimes lncntp[parentdir]++; 4191592Srgrimes if (lfdir == 0) { 4201592Srgrimes dp = ginode(ROOTINO); 4211592Srgrimes idesc.id_name = lfname; 4221592Srgrimes idesc.id_type = DATA; 4231592Srgrimes idesc.id_func = findino; 4241592Srgrimes idesc.id_number = ROOTINO; 4251592Srgrimes if ((ckinode(dp, &idesc) & FOUND) != 0) { 4261592Srgrimes lfdir = idesc.id_parent; 4271592Srgrimes } else { 4281592Srgrimes pwarn("NO lost+found DIRECTORY"); 4291592Srgrimes if (preen || reply("CREATE")) { 4301592Srgrimes lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 4311592Srgrimes if (lfdir != 0) { 4321592Srgrimes if (makeentry(ROOTINO, lfdir, lfname) != 0) { 4331592Srgrimes if (preen) 4341592Srgrimes printf(" (CREATED)\n"); 4351592Srgrimes } else { 4361592Srgrimes freedir(lfdir, ROOTINO); 4371592Srgrimes lfdir = 0; 4381592Srgrimes if (preen) 4391592Srgrimes printf("\n"); 4401592Srgrimes } 4411592Srgrimes } 4421592Srgrimes } 4431592Srgrimes } 4441592Srgrimes if (lfdir == 0) { 4451592Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 4461592Srgrimes printf("\n\n"); 4471592Srgrimes return (0); 4481592Srgrimes } 4491592Srgrimes } 4501592Srgrimes dp = ginode(lfdir); 4511592Srgrimes if ((dp->di_mode & IFMT) != IFDIR) { 4521592Srgrimes pfatal("lost+found IS NOT A DIRECTORY"); 4531592Srgrimes if (reply("REALLOCATE") == 0) 4541592Srgrimes return (0); 4551592Srgrimes oldlfdir = lfdir; 4561592Srgrimes if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 4571592Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4581592Srgrimes return (0); 4591592Srgrimes } 4601592Srgrimes if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 4611592Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4621592Srgrimes return (0); 4631592Srgrimes } 4641592Srgrimes inodirty(); 4651592Srgrimes idesc.id_type = ADDR; 4661592Srgrimes idesc.id_func = pass4check; 4671592Srgrimes idesc.id_number = oldlfdir; 4681592Srgrimes adjust(&idesc, lncntp[oldlfdir] + 1); 4691592Srgrimes lncntp[oldlfdir] = 0; 4701592Srgrimes dp = ginode(lfdir); 4711592Srgrimes } 4721592Srgrimes if (statemap[lfdir] != DFOUND) { 4731592Srgrimes pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 4741592Srgrimes return (0); 4751592Srgrimes } 4761592Srgrimes (void)lftempname(tempname, orphan); 4771592Srgrimes if (makeentry(lfdir, orphan, tempname) == 0) { 4781592Srgrimes pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 4791592Srgrimes printf("\n\n"); 4801592Srgrimes return (0); 4811592Srgrimes } 4821592Srgrimes lncntp[orphan]--; 4831592Srgrimes if (lostdir) { 4841592Srgrimes if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 4851592Srgrimes parentdir != (ino_t)-1) 4861592Srgrimes (void)makeentry(orphan, lfdir, ".."); 4871592Srgrimes dp = ginode(lfdir); 4881592Srgrimes dp->di_nlink++; 4891592Srgrimes inodirty(); 4901592Srgrimes lncntp[lfdir]++; 4911592Srgrimes pwarn("DIR I=%lu CONNECTED. ", orphan); 4921592Srgrimes if (parentdir != (ino_t)-1) { 4931592Srgrimes printf("PARENT WAS I=%lu\n", parentdir); 4941592Srgrimes /* 4951592Srgrimes * The parent directory, because of the ordering 4961592Srgrimes * guarantees, has had the link count incremented 4971592Srgrimes * for the child, but no entry was made. This 4981592Srgrimes * fixes the parent link count so that fsck does 4991592Srgrimes * not need to be rerun. 5001592Srgrimes */ 5011592Srgrimes lncntp[parentdir]++; 5021592Srgrimes 5031592Srgrimes } 5041592Srgrimes if (preen == 0) 5051592Srgrimes printf("\n"); 5061592Srgrimes } 5071592Srgrimes return (1); 5081592Srgrimes} 5091592Srgrimes 5101592Srgrimes/* 5111592Srgrimes * fix an entry in a directory. 5121592Srgrimes */ 5131592Srgrimesint 5141592Srgrimeschangeino(dir, name, newnum) 5151592Srgrimes ino_t dir; 5161592Srgrimes char *name; 5171592Srgrimes ino_t newnum; 5181592Srgrimes{ 5191592Srgrimes struct inodesc idesc; 5201592Srgrimes 5211592Srgrimes memset(&idesc, 0, sizeof(struct inodesc)); 5221592Srgrimes idesc.id_type = DATA; 5231592Srgrimes idesc.id_func = chgino; 5241592Srgrimes idesc.id_number = dir; 5251592Srgrimes idesc.id_fix = DONTKNOW; 5261592Srgrimes idesc.id_name = name; 5271592Srgrimes idesc.id_parent = newnum; /* new value for name */ 5281592Srgrimes return (ckinode(ginode(dir), &idesc)); 5291592Srgrimes} 5301592Srgrimes 5311592Srgrimes/* 5321592Srgrimes * make an entry in a directory 5331592Srgrimes */ 5341592Srgrimesint 5351592Srgrimesmakeentry(parent, ino, name) 5361592Srgrimes ino_t parent, ino; 5371592Srgrimes char *name; 5381592Srgrimes{ 5391592Srgrimes struct dinode *dp; 5401592Srgrimes struct inodesc idesc; 5411592Srgrimes char pathbuf[MAXPATHLEN + 1]; 5421592Srgrimes 5431592Srgrimes if (parent < ROOTINO || parent >= maxino || 5441592Srgrimes ino < ROOTINO || ino >= maxino) 5451592Srgrimes return (0); 5461592Srgrimes memset(&idesc, 0, sizeof(struct inodesc)); 5471592Srgrimes idesc.id_type = DATA; 5481592Srgrimes idesc.id_func = mkentry; 5491592Srgrimes idesc.id_number = parent; 5501592Srgrimes idesc.id_parent = ino; /* this is the inode to enter */ 5511592Srgrimes idesc.id_fix = DONTKNOW; 5521592Srgrimes idesc.id_name = name; 5531592Srgrimes dp = ginode(parent); 5541592Srgrimes if (dp->di_size % DIRBLKSIZ) { 5551592Srgrimes dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 5561592Srgrimes inodirty(); 5571592Srgrimes } 5581592Srgrimes if ((ckinode(dp, &idesc) & ALTERED) != 0) 5591592Srgrimes return (1); 5601592Srgrimes getpathname(pathbuf, parent, parent); 5611592Srgrimes dp = ginode(parent); 5621592Srgrimes if (expanddir(dp, pathbuf) == 0) 5631592Srgrimes return (0); 5641592Srgrimes return (ckinode(dp, &idesc) & ALTERED); 5651592Srgrimes} 5661592Srgrimes 5671592Srgrimes/* 5681592Srgrimes * Attempt to expand the size of a directory 5691592Srgrimes */ 5701592Srgrimesstatic int 5711592Srgrimesexpanddir(dp, name) 5721592Srgrimes register struct dinode *dp; 5731592Srgrimes char *name; 5741592Srgrimes{ 5751592Srgrimes ufs_daddr_t lastbn, newblk; 5761592Srgrimes register struct bufarea *bp; 5771592Srgrimes char *cp, firstblk[DIRBLKSIZ]; 5781592Srgrimes 5791592Srgrimes lastbn = lblkno(&sblock, dp->di_size); 5801592Srgrimes if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 5811592Srgrimes return (0); 5821592Srgrimes if ((newblk = allocblk(sblock.fs_frag)) == 0) 5831592Srgrimes return (0); 5841592Srgrimes dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 5851592Srgrimes dp->di_db[lastbn] = newblk; 5861592Srgrimes dp->di_size += sblock.fs_bsize; 5871592Srgrimes dp->di_blocks += btodb(sblock.fs_bsize); 5881592Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 5891592Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 5901592Srgrimes if (bp->b_errs) 5911592Srgrimes goto bad; 5921592Srgrimes memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 5931592Srgrimes bp = getdirblk(newblk, sblock.fs_bsize); 5941592Srgrimes if (bp->b_errs) 59512434Speter goto bad; 59612434Speter memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 5971592Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 5981592Srgrimes cp < &bp->b_un.b_buf[sblock.fs_bsize]; 5991592Srgrimes cp += DIRBLKSIZ) 6001592Srgrimes memmove(cp, &emptydir, sizeof emptydir); 6011592Srgrimes dirty(bp); 6021592Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 6031592Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 6041592Srgrimes if (bp->b_errs) 6051592Srgrimes goto bad; 6061592Srgrimes memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 6071592Srgrimes pwarn("NO SPACE LEFT IN %s", name); 6081592Srgrimes if (preen) 6091592Srgrimes printf(" (EXPANDED)\n"); 6101592Srgrimes else if (reply("EXPAND") == 0) 6111592Srgrimes goto bad; 6121592Srgrimes dirty(bp); 6131592Srgrimes inodirty(); 6141592Srgrimes return (1); 6151592Srgrimesbad: 6161592Srgrimes dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 6171592Srgrimes dp->di_db[lastbn + 1] = 0; 6181592Srgrimes dp->di_size -= sblock.fs_bsize; 6191592Srgrimes dp->di_blocks -= btodb(sblock.fs_bsize); 6201592Srgrimes freeblk(newblk, sblock.fs_frag); 6211592Srgrimes return (0); 6221592Srgrimes} 6231592Srgrimes 6241592Srgrimes/* 6251592Srgrimes * allocate a new directory 6261592Srgrimes */ 6271592Srgrimesino_t 6281592Srgrimesallocdir(parent, request, mode) 6291592Srgrimes ino_t parent, request; 6301592Srgrimes int mode; 6311592Srgrimes{ 6321592Srgrimes ino_t ino; 6331592Srgrimes char *cp; 6341592Srgrimes struct dinode *dp; 6351592Srgrimes register struct bufarea *bp; 6361592Srgrimes struct dirtemplate *dirp; 6371592Srgrimes 6381592Srgrimes ino = allocino(request, IFDIR|mode); 6391592Srgrimes if (newinofmt) 6401592Srgrimes dirp = &dirhead; 6411592Srgrimes else 6421592Srgrimes dirp = (struct dirtemplate *)&odirhead; 6431592Srgrimes dirp->dot_ino = ino; 6441592Srgrimes dirp->dotdot_ino = parent; 6451592Srgrimes dp = ginode(ino); 6461592Srgrimes bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 6471592Srgrimes if (bp->b_errs) { 6481592Srgrimes freeino(ino); 6491592Srgrimes return (0); 6501592Srgrimes } 6511592Srgrimes memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 6521592Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6531592Srgrimes cp < &bp->b_un.b_buf[sblock.fs_fsize]; 6541592Srgrimes cp += DIRBLKSIZ) 6551592Srgrimes memmove(cp, &emptydir, sizeof emptydir); 6561592Srgrimes dirty(bp); 6571592Srgrimes dp->di_nlink = 2; 6581592Srgrimes inodirty(); 6591592Srgrimes if (ino == ROOTINO) { 6601592Srgrimes lncntp[ino] = dp->di_nlink; 6611592Srgrimes cacheino(dp, ino); 6621592Srgrimes return(ino); 6631592Srgrimes } 6641592Srgrimes if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 6651592Srgrimes freeino(ino); 6661592Srgrimes return (0); 6671592Srgrimes } 6681592Srgrimes cacheino(dp, ino); 6691592Srgrimes statemap[ino] = statemap[parent]; 6701592Srgrimes if (statemap[ino] == DSTATE) { 6711592Srgrimes lncntp[ino] = dp->di_nlink; 6721592Srgrimes lncntp[parent]++; 6731592Srgrimes } 6741592Srgrimes dp = ginode(parent); 6751592Srgrimes dp->di_nlink++; 6761592Srgrimes inodirty(); 6771592Srgrimes return (ino); 6781592Srgrimes} 6791592Srgrimes 6801592Srgrimes/* 6811592Srgrimes * free a directory inode 6821592Srgrimes */ 6831592Srgrimesstatic void 6841592Srgrimesfreedir(ino, parent) 6851592Srgrimes ino_t ino, parent; 6861592Srgrimes{ 6871592Srgrimes struct dinode *dp; 6881592Srgrimes 6891592Srgrimes if (ino != parent) { 6901592Srgrimes dp = ginode(parent); 6911592Srgrimes dp->di_nlink--; 6921592Srgrimes inodirty(); 6931592Srgrimes } 6941592Srgrimes freeino(ino); 6951592Srgrimes} 69613881Smarkm 6971592Srgrimes/* 6981592Srgrimes * generate a temporary name for the lost+found directory. 6991592Srgrimes */ 7001592Srgrimesstatic int 7011592Srgrimeslftempname(bufp, ino) 7021592Srgrimes char *bufp; 7031592Srgrimes ino_t ino; 70418449Spst{ 7051592Srgrimes register ino_t in; 7061592Srgrimes register char *cp; 7071592Srgrimes int namlen; 7081592Srgrimes 7091592Srgrimes cp = bufp + 2; 7101592Srgrimes for (in = maxino; in > 0; in /= 10) 7111592Srgrimes cp++; 7121592Srgrimes *--cp = 0; 7131592Srgrimes namlen = cp - bufp; 7141592Srgrimes in = ino; 7151592Srgrimes while (cp > bufp) { 7161592Srgrimes *--cp = (in % 10) + '0'; 7171592Srgrimes in /= 10; 7181592Srgrimes } 7191592Srgrimes *cp = '#'; 7208870Srgrimes return (namlen); 7211592Srgrimes} 7221592Srgrimes 7231592Srgrimes/* 7241592Srgrimes * Get a directory block. 7251592Srgrimes * Insure that it is held until another is requested. 7261592Srgrimes */ 7271592Srgrimesstatic struct bufarea * 7281592Srgrimesgetdirblk(blkno, size) 7291592Srgrimes ufs_daddr_t blkno; 73011486Sdg long size; 7311592Srgrimes{ 73211486Sdg 7331592Srgrimes if (pdirbp != 0) 7341592Srgrimes pdirbp->b_flags &= ~B_INUSE; 7351592Srgrimes pdirbp = getdatablk(blkno, size); 7361592Srgrimes return (pdirbp); 7371592Srgrimes} 7381592Srgrimes