dir.c revision 23675
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> 447585Sbde#include <stdio.h> 451558Srgrimes#include <stdlib.h> 4623675Speter#include <err.h> 471558Srgrimes#include <string.h> 4823675Speter 491558Srgrimes#include "fsck.h" 501558Srgrimes 511558Srgrimeschar *lfname = "lost+found"; 521558Srgrimesint lfmode = 01777; 531558Srgrimesstruct dirtemplate emptydir = { 0, DIRBLKSIZ }; 541558Srgrimesstruct dirtemplate dirhead = { 551558Srgrimes 0, 12, DT_DIR, 1, ".", 561558Srgrimes 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 571558Srgrimes}; 581558Srgrimesstruct odirtemplate odirhead = { 591558Srgrimes 0, 12, 1, ".", 601558Srgrimes 0, DIRBLKSIZ - 12, 2, ".." 611558Srgrimes}; 621558Srgrimes 6323675Speterstatic int chgino __P((struct inodesc *)); 6423675Speterstatic int dircheck __P((struct inodesc *, struct direct *)); 6523675Speterstatic int expanddir __P((struct dinode *dp, char *name)); 6623675Speterstatic void freedir __P((ino_t ino, ino_t parent)); 6723675Speterstatic struct direct *fsck_readdir __P((struct inodesc *)); 6823675Speterstatic struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size)); 6923675Speterstatic int lftempname __P((char *bufp, ino_t ino)); 7023675Speterstatic int mkentry __P((struct inodesc *)); 711558Srgrimes 721558Srgrimes/* 731558Srgrimes * Propagate connected state through the tree. 741558Srgrimes */ 757585Sbdevoid 761558Srgrimespropagate() 771558Srgrimes{ 781558Srgrimes register struct inoinfo **inpp, *inp; 791558Srgrimes struct inoinfo **inpend; 801558Srgrimes long change; 811558Srgrimes 821558Srgrimes inpend = &inpsort[inplast]; 831558Srgrimes do { 841558Srgrimes change = 0; 851558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 861558Srgrimes inp = *inpp; 871558Srgrimes if (inp->i_parent == 0) 881558Srgrimes continue; 891558Srgrimes if (statemap[inp->i_parent] == DFOUND && 901558Srgrimes statemap[inp->i_number] == DSTATE) { 911558Srgrimes statemap[inp->i_number] = DFOUND; 921558Srgrimes change++; 931558Srgrimes } 941558Srgrimes } 951558Srgrimes } while (change > 0); 961558Srgrimes} 971558Srgrimes 981558Srgrimes/* 991558Srgrimes * Scan each entry in a directory block. 1001558Srgrimes */ 1017585Sbdeint 1021558Srgrimesdirscan(idesc) 1031558Srgrimes register struct inodesc *idesc; 1041558Srgrimes{ 1051558Srgrimes register struct direct *dp; 1061558Srgrimes register struct bufarea *bp; 1071558Srgrimes int dsize, n; 1081558Srgrimes long blksiz; 1091558Srgrimes char dbuf[DIRBLKSIZ]; 1101558Srgrimes 1111558Srgrimes if (idesc->id_type != DATA) 11223675Speter errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 1131558Srgrimes if (idesc->id_entryno == 0 && 1141558Srgrimes (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 1151558Srgrimes idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 1161558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1171558Srgrimes if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 1181558Srgrimes idesc->id_filesize -= blksiz; 1191558Srgrimes return (SKIP); 1201558Srgrimes } 1211558Srgrimes idesc->id_loc = 0; 1221558Srgrimes for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 1231558Srgrimes dsize = dp->d_reclen; 12423675Speter memmove(dbuf, dp, (size_t)dsize); 1251558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1261558Srgrimes if (!newinofmt) { 1271558Srgrimes struct direct *tdp = (struct direct *)dbuf; 1281558Srgrimes u_char tmp; 1291558Srgrimes 1301558Srgrimes tmp = tdp->d_namlen; 1311558Srgrimes tdp->d_namlen = tdp->d_type; 1321558Srgrimes tdp->d_type = tmp; 1331558Srgrimes } 1341558Srgrimes# endif 1351558Srgrimes idesc->id_dirp = (struct direct *)dbuf; 1361558Srgrimes if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 1371558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1381558Srgrimes if (!newinofmt && !doinglevel2) { 1391558Srgrimes struct direct *tdp; 1401558Srgrimes u_char tmp; 1411558Srgrimes 1421558Srgrimes tdp = (struct direct *)dbuf; 1431558Srgrimes tmp = tdp->d_namlen; 1441558Srgrimes tdp->d_namlen = tdp->d_type; 1451558Srgrimes tdp->d_type = tmp; 1461558Srgrimes } 1471558Srgrimes# endif 1481558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 14923675Speter memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 1501558Srgrimes (size_t)dsize); 1511558Srgrimes dirty(bp); 1521558Srgrimes sbdirty(); 1531558Srgrimes } 1548871Srgrimes if (n & STOP) 1551558Srgrimes return (n); 1561558Srgrimes } 1571558Srgrimes return (idesc->id_filesize > 0 ? KEEPON : STOP); 1581558Srgrimes} 1591558Srgrimes 1601558Srgrimes/* 1611558Srgrimes * get next entry in a directory. 1621558Srgrimes */ 16323675Speterstatic struct direct * 1641558Srgrimesfsck_readdir(idesc) 1651558Srgrimes register struct inodesc *idesc; 1661558Srgrimes{ 1671558Srgrimes register struct direct *dp, *ndp; 1681558Srgrimes register struct bufarea *bp; 1691558Srgrimes long size, blksiz, fix, dploc; 1701558Srgrimes 1711558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1721558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1731558Srgrimes if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 1741558Srgrimes idesc->id_loc < blksiz) { 1751558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1761558Srgrimes if (dircheck(idesc, dp)) 1771558Srgrimes goto dpok; 17823675Speter if (idesc->id_fix == IGNORE) 17923675Speter return (0); 1801558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1811558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1821558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1831558Srgrimes dp->d_reclen = DIRBLKSIZ; 1841558Srgrimes dp->d_ino = 0; 1851558Srgrimes dp->d_type = 0; 1861558Srgrimes dp->d_namlen = 0; 1871558Srgrimes dp->d_name[0] = '\0'; 1881558Srgrimes if (fix) 1891558Srgrimes dirty(bp); 1901558Srgrimes idesc->id_loc += DIRBLKSIZ; 1911558Srgrimes idesc->id_filesize -= DIRBLKSIZ; 1921558Srgrimes return (dp); 1931558Srgrimes } 1941558Srgrimesdpok: 1951558Srgrimes if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 1961558Srgrimes return NULL; 1971558Srgrimes dploc = idesc->id_loc; 1981558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 1991558Srgrimes idesc->id_loc += dp->d_reclen; 2001558Srgrimes idesc->id_filesize -= dp->d_reclen; 2011558Srgrimes if ((idesc->id_loc % DIRBLKSIZ) == 0) 2021558Srgrimes return (dp); 2031558Srgrimes ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 2041558Srgrimes if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 2051558Srgrimes dircheck(idesc, ndp) == 0) { 2061558Srgrimes size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 2071558Srgrimes idesc->id_loc += size; 2081558Srgrimes idesc->id_filesize -= size; 20923675Speter if (idesc->id_fix == IGNORE) 21023675Speter return (0); 2111558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 2121558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 2131558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2141558Srgrimes dp->d_reclen += size; 2151558Srgrimes if (fix) 2161558Srgrimes dirty(bp); 2171558Srgrimes } 2181558Srgrimes return (dp); 2191558Srgrimes} 2201558Srgrimes 2211558Srgrimes/* 2221558Srgrimes * Verify that a directory entry is valid. 2231558Srgrimes * This is a superset of the checks made in the kernel. 2241558Srgrimes */ 22523675Speterstatic int 2261558Srgrimesdircheck(idesc, dp) 2271558Srgrimes struct inodesc *idesc; 2281558Srgrimes register struct direct *dp; 2291558Srgrimes{ 2301558Srgrimes register int size; 2311558Srgrimes register char *cp; 2321558Srgrimes u_char namlen, type; 2331558Srgrimes int spaceleft; 2341558Srgrimes 23523675Speter spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 23623675Speter if (dp->d_ino >= maxino || 23723675Speter 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{ 3071558Srgrimes register struct dinode *dp; 3081558Srgrimes 3091558Srgrimes dp = ginode(idesc->id_number); 3101558Srgrimes if (dp->di_nlink == lcnt) { 3111558Srgrimes if (linkup(idesc->id_number, (ino_t)0) == 0) 3121558Srgrimes clri(idesc, "UNREF", 0); 3131558Srgrimes } else { 3141558Srgrimes pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 3151558Srgrimes ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 3161558Srgrimes pinode(idesc->id_number); 3171558Srgrimes printf(" COUNT %d SHOULD BE %d", 3181558Srgrimes dp->di_nlink, dp->di_nlink - lcnt); 3191558Srgrimes if (preen) { 3201558Srgrimes if (lcnt < 0) { 3211558Srgrimes printf("\n"); 3221558Srgrimes pfatal("LINK COUNT INCREASING"); 3231558Srgrimes } 3241558Srgrimes 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); 4101558Srgrimes if (preen && dp->di_size == 0) 4111558Srgrimes return (0); 4121558Srgrimes if (preen) 4131558Srgrimes printf(" (RECONNECTED)\n"); 4141558Srgrimes else 4151558Srgrimes if (reply("RECONNECT") == 0) 4161558Srgrimes return (0); 4171558Srgrimes if (lfdir == 0) { 4181558Srgrimes dp = ginode(ROOTINO); 4191558Srgrimes idesc.id_name = lfname; 4201558Srgrimes idesc.id_type = DATA; 4211558Srgrimes idesc.id_func = findino; 4221558Srgrimes idesc.id_number = ROOTINO; 4231558Srgrimes if ((ckinode(dp, &idesc) & FOUND) != 0) { 4241558Srgrimes lfdir = idesc.id_parent; 4251558Srgrimes } else { 4261558Srgrimes pwarn("NO lost+found DIRECTORY"); 4271558Srgrimes if (preen || reply("CREATE")) { 4281558Srgrimes lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 4291558Srgrimes if (lfdir != 0) { 4301558Srgrimes if (makeentry(ROOTINO, lfdir, lfname) != 0) { 4311558Srgrimes if (preen) 4321558Srgrimes printf(" (CREATED)\n"); 4331558Srgrimes } else { 4341558Srgrimes freedir(lfdir, ROOTINO); 4351558Srgrimes lfdir = 0; 4361558Srgrimes if (preen) 4371558Srgrimes printf("\n"); 4381558Srgrimes } 4391558Srgrimes } 4401558Srgrimes } 4411558Srgrimes } 4421558Srgrimes if (lfdir == 0) { 4431558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 4441558Srgrimes printf("\n\n"); 4451558Srgrimes return (0); 4461558Srgrimes } 4471558Srgrimes } 4481558Srgrimes dp = ginode(lfdir); 4491558Srgrimes if ((dp->di_mode & IFMT) != IFDIR) { 4501558Srgrimes pfatal("lost+found IS NOT A DIRECTORY"); 4511558Srgrimes if (reply("REALLOCATE") == 0) 4521558Srgrimes return (0); 4531558Srgrimes oldlfdir = lfdir; 4541558Srgrimes if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 4551558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4561558Srgrimes return (0); 4571558Srgrimes } 4581558Srgrimes if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 4591558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4601558Srgrimes return (0); 4611558Srgrimes } 4621558Srgrimes inodirty(); 4631558Srgrimes idesc.id_type = ADDR; 4641558Srgrimes idesc.id_func = pass4check; 4651558Srgrimes idesc.id_number = oldlfdir; 4661558Srgrimes adjust(&idesc, lncntp[oldlfdir] + 1); 4671558Srgrimes lncntp[oldlfdir] = 0; 4681558Srgrimes dp = ginode(lfdir); 4691558Srgrimes } 4701558Srgrimes if (statemap[lfdir] != DFOUND) { 4711558Srgrimes pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 4721558Srgrimes return (0); 4731558Srgrimes } 4741558Srgrimes (void)lftempname(tempname, orphan); 4751558Srgrimes if (makeentry(lfdir, orphan, tempname) == 0) { 4761558Srgrimes pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 4771558Srgrimes printf("\n\n"); 4781558Srgrimes return (0); 4791558Srgrimes } 4801558Srgrimes lncntp[orphan]--; 4811558Srgrimes if (lostdir) { 4821558Srgrimes if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 4831558Srgrimes parentdir != (ino_t)-1) 4841558Srgrimes (void)makeentry(orphan, lfdir, ".."); 4851558Srgrimes dp = ginode(lfdir); 4861558Srgrimes dp->di_nlink++; 4871558Srgrimes inodirty(); 4881558Srgrimes lncntp[lfdir]++; 4891558Srgrimes pwarn("DIR I=%lu CONNECTED. ", orphan); 49015699Snate if (parentdir != (ino_t)-1) { 4911558Srgrimes printf("PARENT WAS I=%lu\n", parentdir); 49215699Snate /* 49315699Snate * The parent directory, because of the ordering 49415699Snate * guarantees, has had the link count incremented 49515699Snate * for the child, but no entry was made. This 49615699Snate * fixes the parent link count so that fsck does 49715699Snate * not need to be rerun. 49815699Snate */ 49915699Snate lncntp[parentdir]++; 50015699Snate 50115699Snate } 5021558Srgrimes if (preen == 0) 5031558Srgrimes printf("\n"); 5041558Srgrimes } 5051558Srgrimes return (1); 5061558Srgrimes} 5071558Srgrimes 5081558Srgrimes/* 5091558Srgrimes * fix an entry in a directory. 5101558Srgrimes */ 5117585Sbdeint 5121558Srgrimeschangeino(dir, name, newnum) 5131558Srgrimes ino_t dir; 5141558Srgrimes char *name; 5151558Srgrimes ino_t newnum; 5161558Srgrimes{ 5171558Srgrimes struct inodesc idesc; 5181558Srgrimes 51923675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5201558Srgrimes idesc.id_type = DATA; 5211558Srgrimes idesc.id_func = chgino; 5221558Srgrimes idesc.id_number = dir; 5231558Srgrimes idesc.id_fix = DONTKNOW; 5241558Srgrimes idesc.id_name = name; 5251558Srgrimes idesc.id_parent = newnum; /* new value for name */ 5261558Srgrimes return (ckinode(ginode(dir), &idesc)); 5271558Srgrimes} 5281558Srgrimes 5291558Srgrimes/* 5301558Srgrimes * make an entry in a directory 5311558Srgrimes */ 5327585Sbdeint 5331558Srgrimesmakeentry(parent, ino, name) 5341558Srgrimes ino_t parent, ino; 5351558Srgrimes char *name; 5361558Srgrimes{ 5371558Srgrimes struct dinode *dp; 5381558Srgrimes struct inodesc idesc; 5391558Srgrimes char pathbuf[MAXPATHLEN + 1]; 5408871Srgrimes 5411558Srgrimes if (parent < ROOTINO || parent >= maxino || 5421558Srgrimes ino < ROOTINO || ino >= maxino) 5431558Srgrimes return (0); 54423675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5451558Srgrimes idesc.id_type = DATA; 5461558Srgrimes idesc.id_func = mkentry; 5471558Srgrimes idesc.id_number = parent; 5481558Srgrimes idesc.id_parent = ino; /* this is the inode to enter */ 5491558Srgrimes idesc.id_fix = DONTKNOW; 5501558Srgrimes idesc.id_name = name; 5511558Srgrimes dp = ginode(parent); 5521558Srgrimes if (dp->di_size % DIRBLKSIZ) { 5531558Srgrimes dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 5541558Srgrimes inodirty(); 5551558Srgrimes } 5561558Srgrimes if ((ckinode(dp, &idesc) & ALTERED) != 0) 5571558Srgrimes return (1); 5581558Srgrimes getpathname(pathbuf, parent, parent); 5591558Srgrimes dp = ginode(parent); 5601558Srgrimes if (expanddir(dp, pathbuf) == 0) 5611558Srgrimes return (0); 5621558Srgrimes return (ckinode(dp, &idesc) & ALTERED); 5631558Srgrimes} 5641558Srgrimes 5651558Srgrimes/* 5661558Srgrimes * Attempt to expand the size of a directory 5671558Srgrimes */ 56823675Speterstatic int 5691558Srgrimesexpanddir(dp, name) 5701558Srgrimes register struct dinode *dp; 5711558Srgrimes char *name; 5721558Srgrimes{ 57323675Speter ufs_daddr_t lastbn, newblk; 5741558Srgrimes register struct bufarea *bp; 5751558Srgrimes char *cp, firstblk[DIRBLKSIZ]; 5761558Srgrimes 5771558Srgrimes lastbn = lblkno(&sblock, dp->di_size); 5781558Srgrimes if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 5791558Srgrimes return (0); 5801558Srgrimes if ((newblk = allocblk(sblock.fs_frag)) == 0) 5811558Srgrimes return (0); 5821558Srgrimes dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 5831558Srgrimes dp->di_db[lastbn] = newblk; 5841558Srgrimes dp->di_size += sblock.fs_bsize; 5851558Srgrimes dp->di_blocks += btodb(sblock.fs_bsize); 5861558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 5871558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 5881558Srgrimes if (bp->b_errs) 5891558Srgrimes goto bad; 59023675Speter memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 5911558Srgrimes bp = getdirblk(newblk, sblock.fs_bsize); 5921558Srgrimes if (bp->b_errs) 5931558Srgrimes goto bad; 59423675Speter memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 5951558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 5961558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_bsize]; 5971558Srgrimes cp += DIRBLKSIZ) 59823675Speter memmove(cp, &emptydir, sizeof emptydir); 5991558Srgrimes dirty(bp); 6001558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 6011558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 6021558Srgrimes if (bp->b_errs) 6031558Srgrimes goto bad; 60423675Speter memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 6051558Srgrimes pwarn("NO SPACE LEFT IN %s", name); 6061558Srgrimes if (preen) 6071558Srgrimes printf(" (EXPANDED)\n"); 6081558Srgrimes else if (reply("EXPAND") == 0) 6091558Srgrimes goto bad; 6101558Srgrimes dirty(bp); 6111558Srgrimes inodirty(); 6121558Srgrimes return (1); 6131558Srgrimesbad: 6141558Srgrimes dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 6151558Srgrimes dp->di_db[lastbn + 1] = 0; 6161558Srgrimes dp->di_size -= sblock.fs_bsize; 6171558Srgrimes dp->di_blocks -= btodb(sblock.fs_bsize); 6181558Srgrimes freeblk(newblk, sblock.fs_frag); 6191558Srgrimes return (0); 6201558Srgrimes} 6211558Srgrimes 6221558Srgrimes/* 6231558Srgrimes * allocate a new directory 6241558Srgrimes */ 6257586Sbdeino_t 6261558Srgrimesallocdir(parent, request, mode) 6271558Srgrimes ino_t parent, request; 6281558Srgrimes int mode; 6291558Srgrimes{ 6301558Srgrimes ino_t ino; 6311558Srgrimes char *cp; 6321558Srgrimes struct dinode *dp; 6331558Srgrimes register struct bufarea *bp; 6341558Srgrimes struct dirtemplate *dirp; 6351558Srgrimes 6361558Srgrimes ino = allocino(request, IFDIR|mode); 6371558Srgrimes if (newinofmt) 6381558Srgrimes dirp = &dirhead; 6391558Srgrimes else 6401558Srgrimes dirp = (struct dirtemplate *)&odirhead; 6411558Srgrimes dirp->dot_ino = ino; 6421558Srgrimes dirp->dotdot_ino = parent; 6431558Srgrimes dp = ginode(ino); 6441558Srgrimes bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 6451558Srgrimes if (bp->b_errs) { 6461558Srgrimes freeino(ino); 6471558Srgrimes return (0); 6481558Srgrimes } 64923675Speter memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 6501558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6511558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_fsize]; 6521558Srgrimes cp += DIRBLKSIZ) 65323675Speter memmove(cp, &emptydir, sizeof emptydir); 6541558Srgrimes dirty(bp); 6551558Srgrimes dp->di_nlink = 2; 6561558Srgrimes inodirty(); 6571558Srgrimes if (ino == ROOTINO) { 6581558Srgrimes lncntp[ino] = dp->di_nlink; 6591558Srgrimes cacheino(dp, ino); 6601558Srgrimes return(ino); 6611558Srgrimes } 6621558Srgrimes if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 6631558Srgrimes freeino(ino); 6641558Srgrimes return (0); 6651558Srgrimes } 6661558Srgrimes cacheino(dp, ino); 6671558Srgrimes statemap[ino] = statemap[parent]; 6681558Srgrimes if (statemap[ino] == DSTATE) { 6691558Srgrimes lncntp[ino] = dp->di_nlink; 6701558Srgrimes lncntp[parent]++; 6711558Srgrimes } 6721558Srgrimes dp = ginode(parent); 6731558Srgrimes dp->di_nlink++; 6741558Srgrimes inodirty(); 6751558Srgrimes return (ino); 6761558Srgrimes} 6771558Srgrimes 6781558Srgrimes/* 6791558Srgrimes * free a directory inode 6801558Srgrimes */ 6817585Sbdestatic void 6821558Srgrimesfreedir(ino, parent) 6831558Srgrimes ino_t ino, parent; 6841558Srgrimes{ 6851558Srgrimes struct dinode *dp; 6861558Srgrimes 6871558Srgrimes if (ino != parent) { 6881558Srgrimes dp = ginode(parent); 6891558Srgrimes dp->di_nlink--; 6901558Srgrimes inodirty(); 6911558Srgrimes } 6921558Srgrimes freeino(ino); 6931558Srgrimes} 6941558Srgrimes 6951558Srgrimes/* 6961558Srgrimes * generate a temporary name for the lost+found directory. 6971558Srgrimes */ 69823675Speterstatic int 6991558Srgrimeslftempname(bufp, ino) 7001558Srgrimes char *bufp; 7011558Srgrimes ino_t ino; 7021558Srgrimes{ 7031558Srgrimes register ino_t in; 7041558Srgrimes register char *cp; 7051558Srgrimes int namlen; 7061558Srgrimes 7071558Srgrimes cp = bufp + 2; 7081558Srgrimes for (in = maxino; in > 0; in /= 10) 7091558Srgrimes cp++; 7101558Srgrimes *--cp = 0; 7111558Srgrimes namlen = cp - bufp; 7121558Srgrimes in = ino; 7131558Srgrimes while (cp > bufp) { 7141558Srgrimes *--cp = (in % 10) + '0'; 7151558Srgrimes in /= 10; 7161558Srgrimes } 7171558Srgrimes *cp = '#'; 7181558Srgrimes return (namlen); 7191558Srgrimes} 7201558Srgrimes 7211558Srgrimes/* 7221558Srgrimes * Get a directory block. 7231558Srgrimes * Insure that it is held until another is requested. 7241558Srgrimes */ 72523675Speterstatic struct bufarea * 7261558Srgrimesgetdirblk(blkno, size) 72723675Speter ufs_daddr_t blkno; 7281558Srgrimes long size; 7291558Srgrimes{ 7301558Srgrimes 7311558Srgrimes if (pdirbp != 0) 7321558Srgrimes pdirbp->b_flags &= ~B_INUSE; 7331558Srgrimes pdirbp = getdatablk(blkno, size); 7341558Srgrimes return (pdirbp); 7351558Srgrimes} 736