dir.c revision 92806
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 3541477Sjulian#if 0 3623675Speterstatic const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; 3741477Sjulian#endif 3841477Sjulianstatic const char rcsid[] = 3950476Speter "$FreeBSD: head/sbin/fsck_ffs/dir.c 92806 2002-03-20 17:55:10Z obrien $"; 401558Srgrimes#endif /* not lint */ 411558Srgrimes 421558Srgrimes#include <sys/param.h> 4341474Sjulian#include <sys/time.h> 4474556Smckusick#include <sys/sysctl.h> 4523675Speter 461558Srgrimes#include <ufs/ufs/dinode.h> 471558Srgrimes#include <ufs/ufs/dir.h> 481558Srgrimes#include <ufs/ffs/fs.h> 4923796Sbde 5023675Speter#include <err.h> 511558Srgrimes#include <string.h> 5223675Speter 531558Srgrimes#include "fsck.h" 541558Srgrimes 551558Srgrimeschar *lfname = "lost+found"; 561558Srgrimesint lfmode = 01777; 5774556Smckusickstruct dirtemplate emptydir = { 5874556Smckusick 0, DIRBLKSIZ, DT_UNKNOWN, 0, "", 5974556Smckusick 0, 0, DT_UNKNOWN, 0, "" 6074556Smckusick}; 611558Srgrimesstruct dirtemplate dirhead = { 621558Srgrimes 0, 12, DT_DIR, 1, ".", 631558Srgrimes 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 641558Srgrimes}; 651558Srgrimesstruct odirtemplate odirhead = { 661558Srgrimes 0, 12, 1, ".", 671558Srgrimes 0, DIRBLKSIZ - 12, 2, ".." 681558Srgrimes}; 691558Srgrimes 7023675Speterstatic int chgino __P((struct inodesc *)); 7123675Speterstatic int dircheck __P((struct inodesc *, struct direct *)); 7223675Speterstatic int expanddir __P((struct dinode *dp, char *name)); 7323675Speterstatic void freedir __P((ino_t ino, ino_t parent)); 7423675Speterstatic struct direct *fsck_readdir __P((struct inodesc *)); 7523675Speterstatic struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size)); 7623675Speterstatic int lftempname __P((char *bufp, ino_t ino)); 7723675Speterstatic int mkentry __P((struct inodesc *)); 781558Srgrimes 791558Srgrimes/* 801558Srgrimes * Propagate connected state through the tree. 811558Srgrimes */ 827585Sbdevoid 831558Srgrimespropagate() 841558Srgrimes{ 8592806Sobrien struct inoinfo **inpp, *inp; 861558Srgrimes struct inoinfo **inpend; 871558Srgrimes long change; 881558Srgrimes 891558Srgrimes inpend = &inpsort[inplast]; 901558Srgrimes do { 911558Srgrimes change = 0; 921558Srgrimes for (inpp = inpsort; inpp < inpend; inpp++) { 931558Srgrimes inp = *inpp; 941558Srgrimes if (inp->i_parent == 0) 951558Srgrimes continue; 9641474Sjulian if (inoinfo(inp->i_parent)->ino_state == DFOUND && 9741474Sjulian inoinfo(inp->i_number)->ino_state == DSTATE) { 9841474Sjulian inoinfo(inp->i_number)->ino_state = DFOUND; 991558Srgrimes change++; 1001558Srgrimes } 1011558Srgrimes } 1021558Srgrimes } while (change > 0); 1031558Srgrimes} 1041558Srgrimes 1051558Srgrimes/* 1061558Srgrimes * Scan each entry in a directory block. 1071558Srgrimes */ 1087585Sbdeint 1091558Srgrimesdirscan(idesc) 11092806Sobrien struct inodesc *idesc; 1111558Srgrimes{ 11292806Sobrien struct direct *dp; 11392806Sobrien struct bufarea *bp; 11474556Smckusick u_int dsize, n; 1151558Srgrimes long blksiz; 1161558Srgrimes char dbuf[DIRBLKSIZ]; 1171558Srgrimes 1181558Srgrimes if (idesc->id_type != DATA) 11923675Speter errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 1201558Srgrimes if (idesc->id_entryno == 0 && 1211558Srgrimes (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 1221558Srgrimes idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 1231558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1241558Srgrimes if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 1251558Srgrimes idesc->id_filesize -= blksiz; 1261558Srgrimes return (SKIP); 1271558Srgrimes } 1281558Srgrimes idesc->id_loc = 0; 1291558Srgrimes for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 1301558Srgrimes dsize = dp->d_reclen; 13141474Sjulian if (dsize > sizeof(dbuf)) 13241474Sjulian dsize = sizeof(dbuf); 13323675Speter memmove(dbuf, dp, (size_t)dsize); 1341558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1351558Srgrimes if (!newinofmt) { 1361558Srgrimes struct direct *tdp = (struct direct *)dbuf; 1371558Srgrimes u_char tmp; 1381558Srgrimes 1391558Srgrimes tmp = tdp->d_namlen; 1401558Srgrimes tdp->d_namlen = tdp->d_type; 1411558Srgrimes tdp->d_type = tmp; 1421558Srgrimes } 1431558Srgrimes# endif 1441558Srgrimes idesc->id_dirp = (struct direct *)dbuf; 1451558Srgrimes if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 1461558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 1471558Srgrimes if (!newinofmt && !doinglevel2) { 1481558Srgrimes struct direct *tdp; 1491558Srgrimes u_char tmp; 1501558Srgrimes 1511558Srgrimes tdp = (struct direct *)dbuf; 1521558Srgrimes tmp = tdp->d_namlen; 1531558Srgrimes tdp->d_namlen = tdp->d_type; 1541558Srgrimes tdp->d_type = tmp; 1551558Srgrimes } 1561558Srgrimes# endif 1571558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 15823675Speter memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 1591558Srgrimes (size_t)dsize); 1601558Srgrimes dirty(bp); 1611558Srgrimes sbdirty(); 1621558Srgrimes } 1638871Srgrimes if (n & STOP) 1641558Srgrimes return (n); 1651558Srgrimes } 1661558Srgrimes return (idesc->id_filesize > 0 ? KEEPON : STOP); 1671558Srgrimes} 1681558Srgrimes 1691558Srgrimes/* 1701558Srgrimes * get next entry in a directory. 1711558Srgrimes */ 17223675Speterstatic struct direct * 1731558Srgrimesfsck_readdir(idesc) 17492806Sobrien struct inodesc *idesc; 1751558Srgrimes{ 17692806Sobrien struct direct *dp, *ndp; 17792806Sobrien struct bufarea *bp; 1781558Srgrimes long size, blksiz, fix, dploc; 1791558Srgrimes 1801558Srgrimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1811558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1821558Srgrimes if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 1831558Srgrimes idesc->id_loc < blksiz) { 1841558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1851558Srgrimes if (dircheck(idesc, dp)) 1861558Srgrimes goto dpok; 18723675Speter if (idesc->id_fix == IGNORE) 18823675Speter return (0); 1891558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1901558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 1911558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1921558Srgrimes dp->d_reclen = DIRBLKSIZ; 1931558Srgrimes dp->d_ino = 0; 1941558Srgrimes dp->d_type = 0; 1951558Srgrimes dp->d_namlen = 0; 1961558Srgrimes dp->d_name[0] = '\0'; 1971558Srgrimes if (fix) 1981558Srgrimes dirty(bp); 1991558Srgrimes idesc->id_loc += DIRBLKSIZ; 2001558Srgrimes idesc->id_filesize -= DIRBLKSIZ; 2011558Srgrimes return (dp); 2021558Srgrimes } 2031558Srgrimesdpok: 2041558Srgrimes if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 2051558Srgrimes return NULL; 2061558Srgrimes dploc = idesc->id_loc; 2071558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2081558Srgrimes idesc->id_loc += dp->d_reclen; 2091558Srgrimes idesc->id_filesize -= dp->d_reclen; 2101558Srgrimes if ((idesc->id_loc % DIRBLKSIZ) == 0) 2111558Srgrimes return (dp); 2121558Srgrimes ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 2131558Srgrimes if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 2141558Srgrimes dircheck(idesc, ndp) == 0) { 2151558Srgrimes size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 2161558Srgrimes idesc->id_loc += size; 2171558Srgrimes idesc->id_filesize -= size; 21823675Speter if (idesc->id_fix == IGNORE) 21923675Speter return (0); 2201558Srgrimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 2211558Srgrimes bp = getdirblk(idesc->id_blkno, blksiz); 2221558Srgrimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 2231558Srgrimes dp->d_reclen += size; 2241558Srgrimes if (fix) 2251558Srgrimes dirty(bp); 2261558Srgrimes } 2271558Srgrimes return (dp); 2281558Srgrimes} 2291558Srgrimes 2301558Srgrimes/* 2311558Srgrimes * Verify that a directory entry is valid. 2321558Srgrimes * This is a superset of the checks made in the kernel. 2331558Srgrimes */ 23423675Speterstatic int 2351558Srgrimesdircheck(idesc, dp) 2361558Srgrimes struct inodesc *idesc; 23792806Sobrien struct direct *dp; 2381558Srgrimes{ 23992806Sobrien int size; 24092806Sobrien char *cp; 2411558Srgrimes u_char namlen, type; 2421558Srgrimes int spaceleft; 2431558Srgrimes 24423675Speter spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 24541474Sjulian if (dp->d_reclen == 0 || 24623675Speter dp->d_reclen > spaceleft || 24723675Speter (dp->d_reclen & 0x3) != 0) 24862668Smckusick goto bad; 24923675Speter if (dp->d_ino == 0) 25023675Speter return (1); 2511558Srgrimes size = DIRSIZ(!newinofmt, dp); 2521558Srgrimes# if (BYTE_ORDER == LITTLE_ENDIAN) 2531558Srgrimes if (!newinofmt) { 2541558Srgrimes type = dp->d_namlen; 2551558Srgrimes namlen = dp->d_type; 2561558Srgrimes } else { 2571558Srgrimes namlen = dp->d_namlen; 2581558Srgrimes type = dp->d_type; 2591558Srgrimes } 2601558Srgrimes# else 2611558Srgrimes namlen = dp->d_namlen; 2621558Srgrimes type = dp->d_type; 2631558Srgrimes# endif 26423675Speter if (dp->d_reclen < size || 26523675Speter idesc->id_filesize < size || 26623675Speter namlen > MAXNAMLEN || 26723675Speter type > 15) 26862668Smckusick goto bad; 26923675Speter for (cp = dp->d_name, size = 0; size < namlen; size++) 27023675Speter if (*cp == '\0' || (*cp++ == '/')) 27162668Smckusick goto bad; 27223675Speter if (*cp != '\0') 27362668Smckusick goto bad; 27423675Speter return (1); 27562668Smckusickbad: 27662668Smckusick if (debug) 27762668Smckusick printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n", 27862668Smckusick dp->d_ino, dp->d_reclen, dp->d_namlen, dp->d_type, 27962668Smckusick dp->d_name); 28062668Smckusick return (0); 2811558Srgrimes} 2821558Srgrimes 2837585Sbdevoid 2841558Srgrimesdirerror(ino, errmesg) 2851558Srgrimes ino_t ino; 2861558Srgrimes char *errmesg; 2871558Srgrimes{ 2881558Srgrimes 2891558Srgrimes fileerror(ino, ino, errmesg); 2901558Srgrimes} 2911558Srgrimes 2927585Sbdevoid 2931558Srgrimesfileerror(cwd, ino, errmesg) 2941558Srgrimes ino_t cwd, ino; 2951558Srgrimes char *errmesg; 2961558Srgrimes{ 29792806Sobrien struct dinode *dp; 2981558Srgrimes char pathbuf[MAXPATHLEN + 1]; 2991558Srgrimes 3001558Srgrimes pwarn("%s ", errmesg); 3011558Srgrimes pinode(ino); 3021558Srgrimes printf("\n"); 3031558Srgrimes getpathname(pathbuf, cwd, ino); 3041558Srgrimes if (ino < ROOTINO || ino > maxino) { 3051558Srgrimes pfatal("NAME=%s\n", pathbuf); 3061558Srgrimes return; 3071558Srgrimes } 3081558Srgrimes dp = ginode(ino); 3091558Srgrimes if (ftypeok(dp)) 3101558Srgrimes pfatal("%s=%s\n", 3111558Srgrimes (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 3121558Srgrimes else 3131558Srgrimes pfatal("NAME=%s\n", pathbuf); 3141558Srgrimes} 3151558Srgrimes 3167585Sbdevoid 3171558Srgrimesadjust(idesc, lcnt) 31892806Sobrien struct inodesc *idesc; 31923675Speter int lcnt; 3201558Srgrimes{ 32141474Sjulian struct dinode *dp; 32241474Sjulian int saveresolved; 3231558Srgrimes 3241558Srgrimes dp = ginode(idesc->id_number); 3251558Srgrimes if (dp->di_nlink == lcnt) { 32641474Sjulian /* 32741474Sjulian * If we have not hit any unresolved problems, are running 32841474Sjulian * in preen mode, and are on a filesystem using soft updates, 32941474Sjulian * then just toss any partially allocated files. 33041474Sjulian */ 33174556Smckusick if (resolved && (preen || bkgrdflag) && usedsoftdep) { 33241474Sjulian clri(idesc, "UNREF", 1); 33341474Sjulian return; 33441474Sjulian } else { 33541474Sjulian /* 33641474Sjulian * The filesystem can be marked clean even if 33741474Sjulian * a file is not linked up, but is cleared. 33841474Sjulian * Hence, resolved should not be cleared when 33941474Sjulian * linkup is answered no, but clri is answered yes. 34041474Sjulian */ 34141474Sjulian saveresolved = resolved; 34241474Sjulian if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) { 34341474Sjulian resolved = saveresolved; 34441474Sjulian clri(idesc, "UNREF", 0); 34541474Sjulian return; 34641474Sjulian } 34741474Sjulian /* 34841474Sjulian * Account for the new reference created by linkup(). 34941474Sjulian */ 35041474Sjulian dp = ginode(idesc->id_number); 35141474Sjulian lcnt--; 35241474Sjulian } 35341474Sjulian } 35441474Sjulian if (lcnt != 0) { 3551558Srgrimes pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 3561558Srgrimes ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 3571558Srgrimes pinode(idesc->id_number); 3581558Srgrimes printf(" COUNT %d SHOULD BE %d", 3591558Srgrimes dp->di_nlink, dp->di_nlink - lcnt); 36034266Sjulian if (preen || usedsoftdep) { 3611558Srgrimes if (lcnt < 0) { 3621558Srgrimes printf("\n"); 3631558Srgrimes pfatal("LINK COUNT INCREASING"); 3641558Srgrimes } 36534266Sjulian if (preen) 36634266Sjulian printf(" (ADJUSTED)\n"); 3671558Srgrimes } 3681558Srgrimes if (preen || reply("ADJUST") == 1) { 36974556Smckusick if (bkgrdflag == 0) { 37074556Smckusick dp->di_nlink -= lcnt; 37174556Smckusick inodirty(); 37274556Smckusick } else { 37374556Smckusick cmd.value = idesc->id_number; 37474556Smckusick cmd.size = -lcnt; 37574556Smckusick if (debug) 37686514Siedowse printf("adjrefcnt ino %ld amt %ld\n", 37774556Smckusick (long)cmd.value, cmd.size); 37874556Smckusick if (sysctl(adjrefcnt, MIBSIZE, 0, 0, 37974556Smckusick &cmd, sizeof cmd) == -1) 38074556Smckusick rwerror("ADJUST INODE", cmd.value); 38174556Smckusick } 3821558Srgrimes } 3831558Srgrimes } 3841558Srgrimes} 3851558Srgrimes 38623675Speterstatic int 3871558Srgrimesmkentry(idesc) 3881558Srgrimes struct inodesc *idesc; 3891558Srgrimes{ 39092806Sobrien struct direct *dirp = idesc->id_dirp; 3911558Srgrimes struct direct newent; 3921558Srgrimes int newlen, oldlen; 3931558Srgrimes 3941558Srgrimes newent.d_namlen = strlen(idesc->id_name); 3951558Srgrimes newlen = DIRSIZ(0, &newent); 3961558Srgrimes if (dirp->d_ino != 0) 3971558Srgrimes oldlen = DIRSIZ(0, dirp); 3981558Srgrimes else 3991558Srgrimes oldlen = 0; 4001558Srgrimes if (dirp->d_reclen - oldlen < newlen) 4011558Srgrimes return (KEEPON); 4021558Srgrimes newent.d_reclen = dirp->d_reclen - oldlen; 4031558Srgrimes dirp->d_reclen = oldlen; 4041558Srgrimes dirp = (struct direct *)(((char *)dirp) + oldlen); 4051558Srgrimes dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 40623675Speter dirp->d_reclen = newent.d_reclen; 40723675Speter if (newinofmt) 40841474Sjulian dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 40923675Speter else 41023675Speter dirp->d_type = 0; 41123675Speter dirp->d_namlen = newent.d_namlen; 41223675Speter memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 41323675Speter# if (BYTE_ORDER == LITTLE_ENDIAN) 41423675Speter /* 41523675Speter * If the entry was split, dirscan() will only reverse the byte 41623675Speter * order of the original entry, and not the new one, before 41723675Speter * writing it back out. So, we reverse the byte order here if 41823675Speter * necessary. 41923675Speter */ 42023675Speter if (oldlen != 0 && !newinofmt && !doinglevel2) { 42123675Speter u_char tmp; 42223675Speter 42323675Speter tmp = dirp->d_namlen; 42423675Speter dirp->d_namlen = dirp->d_type; 42523675Speter dirp->d_type = tmp; 42623675Speter } 42723675Speter# endif 4281558Srgrimes return (ALTERED|STOP); 4291558Srgrimes} 4301558Srgrimes 43123675Speterstatic int 4321558Srgrimeschgino(idesc) 4331558Srgrimes struct inodesc *idesc; 4341558Srgrimes{ 43592806Sobrien struct direct *dirp = idesc->id_dirp; 4361558Srgrimes 43723675Speter if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 4381558Srgrimes return (KEEPON); 4391558Srgrimes dirp->d_ino = idesc->id_parent; 4401558Srgrimes if (newinofmt) 44141474Sjulian dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 4421558Srgrimes else 4431558Srgrimes dirp->d_type = 0; 4441558Srgrimes return (ALTERED|STOP); 4451558Srgrimes} 4461558Srgrimes 4477585Sbdeint 44841474Sjulianlinkup(orphan, parentdir, name) 4491558Srgrimes ino_t orphan; 4501558Srgrimes ino_t parentdir; 45141474Sjulian char *name; 4521558Srgrimes{ 45392806Sobrien struct dinode *dp; 4541558Srgrimes int lostdir; 4551558Srgrimes ino_t oldlfdir; 4561558Srgrimes struct inodesc idesc; 4571558Srgrimes char tempname[BUFSIZ]; 4581558Srgrimes 45923675Speter memset(&idesc, 0, sizeof(struct inodesc)); 4601558Srgrimes dp = ginode(orphan); 4611558Srgrimes lostdir = (dp->di_mode & IFMT) == IFDIR; 4621558Srgrimes pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 4631558Srgrimes pinode(orphan); 46441474Sjulian if (preen && dp->di_size == 0) 4651558Srgrimes return (0); 46674556Smckusick if (cursnapshot != 0) { 46774556Smckusick pfatal("FILE LINKUP IN SNAPSHOT"); 46874556Smckusick return (0); 46974556Smckusick } 4701558Srgrimes if (preen) 4711558Srgrimes printf(" (RECONNECTED)\n"); 4721558Srgrimes else 4731558Srgrimes if (reply("RECONNECT") == 0) 4741558Srgrimes return (0); 4751558Srgrimes if (lfdir == 0) { 4761558Srgrimes dp = ginode(ROOTINO); 4771558Srgrimes idesc.id_name = lfname; 4781558Srgrimes idesc.id_type = DATA; 4791558Srgrimes idesc.id_func = findino; 4801558Srgrimes idesc.id_number = ROOTINO; 4811558Srgrimes if ((ckinode(dp, &idesc) & FOUND) != 0) { 4821558Srgrimes lfdir = idesc.id_parent; 4831558Srgrimes } else { 4841558Srgrimes pwarn("NO lost+found DIRECTORY"); 4851558Srgrimes if (preen || reply("CREATE")) { 4861558Srgrimes lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 4871558Srgrimes if (lfdir != 0) { 4881558Srgrimes if (makeentry(ROOTINO, lfdir, lfname) != 0) { 48941474Sjulian numdirs++; 4901558Srgrimes if (preen) 4911558Srgrimes printf(" (CREATED)\n"); 4921558Srgrimes } else { 4931558Srgrimes freedir(lfdir, ROOTINO); 4941558Srgrimes lfdir = 0; 4951558Srgrimes if (preen) 4961558Srgrimes printf("\n"); 4971558Srgrimes } 4981558Srgrimes } 4991558Srgrimes } 5001558Srgrimes } 5011558Srgrimes if (lfdir == 0) { 5021558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 5031558Srgrimes printf("\n\n"); 5041558Srgrimes return (0); 5051558Srgrimes } 5061558Srgrimes } 5071558Srgrimes dp = ginode(lfdir); 5081558Srgrimes if ((dp->di_mode & IFMT) != IFDIR) { 5091558Srgrimes pfatal("lost+found IS NOT A DIRECTORY"); 5101558Srgrimes if (reply("REALLOCATE") == 0) 5111558Srgrimes return (0); 5121558Srgrimes oldlfdir = lfdir; 5131558Srgrimes if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 5141558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 5151558Srgrimes return (0); 5161558Srgrimes } 5171558Srgrimes if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 5181558Srgrimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 5191558Srgrimes return (0); 5201558Srgrimes } 5211558Srgrimes inodirty(); 5221558Srgrimes idesc.id_type = ADDR; 5231558Srgrimes idesc.id_func = pass4check; 5241558Srgrimes idesc.id_number = oldlfdir; 52541474Sjulian adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1); 52641474Sjulian inoinfo(oldlfdir)->ino_linkcnt = 0; 5271558Srgrimes dp = ginode(lfdir); 5281558Srgrimes } 52941474Sjulian if (inoinfo(lfdir)->ino_state != DFOUND) { 5301558Srgrimes pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 5311558Srgrimes return (0); 5321558Srgrimes } 5331558Srgrimes (void)lftempname(tempname, orphan); 53441474Sjulian if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) { 5351558Srgrimes pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 5361558Srgrimes printf("\n\n"); 5371558Srgrimes return (0); 5381558Srgrimes } 53941474Sjulian inoinfo(orphan)->ino_linkcnt--; 5401558Srgrimes if (lostdir) { 5411558Srgrimes if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 5421558Srgrimes parentdir != (ino_t)-1) 5431558Srgrimes (void)makeentry(orphan, lfdir, ".."); 5441558Srgrimes dp = ginode(lfdir); 5451558Srgrimes dp->di_nlink++; 5461558Srgrimes inodirty(); 54741474Sjulian inoinfo(lfdir)->ino_linkcnt++; 54886514Siedowse pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan); 54915699Snate if (parentdir != (ino_t)-1) { 55037236Sbde printf("PARENT WAS I=%lu\n", (u_long)parentdir); 55141477Sjulian /* 55241477Sjulian * The parent directory, because of the ordering 55341477Sjulian * guarantees, has had the link count incremented 55441477Sjulian * for the child, but no entry was made. This 55541477Sjulian * fixes the parent link count so that fsck does 55641477Sjulian * not need to be rerun. 55741477Sjulian */ 55841474Sjulian inoinfo(parentdir)->ino_linkcnt++; 55915699Snate } 5601558Srgrimes if (preen == 0) 5611558Srgrimes printf("\n"); 5621558Srgrimes } 5631558Srgrimes return (1); 5641558Srgrimes} 5651558Srgrimes 5661558Srgrimes/* 5671558Srgrimes * fix an entry in a directory. 5681558Srgrimes */ 5697585Sbdeint 5701558Srgrimeschangeino(dir, name, newnum) 5711558Srgrimes ino_t dir; 5721558Srgrimes char *name; 5731558Srgrimes ino_t newnum; 5741558Srgrimes{ 5751558Srgrimes struct inodesc idesc; 5761558Srgrimes 57723675Speter memset(&idesc, 0, sizeof(struct inodesc)); 5781558Srgrimes idesc.id_type = DATA; 5791558Srgrimes idesc.id_func = chgino; 5801558Srgrimes idesc.id_number = dir; 5811558Srgrimes idesc.id_fix = DONTKNOW; 5821558Srgrimes idesc.id_name = name; 5831558Srgrimes idesc.id_parent = newnum; /* new value for name */ 5841558Srgrimes return (ckinode(ginode(dir), &idesc)); 5851558Srgrimes} 5861558Srgrimes 5871558Srgrimes/* 5881558Srgrimes * make an entry in a directory 5891558Srgrimes */ 5907585Sbdeint 5911558Srgrimesmakeentry(parent, ino, name) 5921558Srgrimes ino_t parent, ino; 5931558Srgrimes char *name; 5941558Srgrimes{ 5951558Srgrimes struct dinode *dp; 5961558Srgrimes struct inodesc idesc; 5971558Srgrimes char pathbuf[MAXPATHLEN + 1]; 5988871Srgrimes 5991558Srgrimes if (parent < ROOTINO || parent >= maxino || 6001558Srgrimes ino < ROOTINO || ino >= maxino) 6011558Srgrimes return (0); 60223675Speter memset(&idesc, 0, sizeof(struct inodesc)); 6031558Srgrimes idesc.id_type = DATA; 6041558Srgrimes idesc.id_func = mkentry; 6051558Srgrimes idesc.id_number = parent; 6061558Srgrimes idesc.id_parent = ino; /* this is the inode to enter */ 6071558Srgrimes idesc.id_fix = DONTKNOW; 6081558Srgrimes idesc.id_name = name; 6091558Srgrimes dp = ginode(parent); 6101558Srgrimes if (dp->di_size % DIRBLKSIZ) { 6111558Srgrimes dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 6121558Srgrimes inodirty(); 6131558Srgrimes } 6141558Srgrimes if ((ckinode(dp, &idesc) & ALTERED) != 0) 6151558Srgrimes return (1); 6161558Srgrimes getpathname(pathbuf, parent, parent); 6171558Srgrimes dp = ginode(parent); 6181558Srgrimes if (expanddir(dp, pathbuf) == 0) 6191558Srgrimes return (0); 6201558Srgrimes return (ckinode(dp, &idesc) & ALTERED); 6211558Srgrimes} 6221558Srgrimes 6231558Srgrimes/* 6241558Srgrimes * Attempt to expand the size of a directory 6251558Srgrimes */ 62623675Speterstatic int 6271558Srgrimesexpanddir(dp, name) 62892806Sobrien struct dinode *dp; 6291558Srgrimes char *name; 6301558Srgrimes{ 63123675Speter ufs_daddr_t lastbn, newblk; 63292806Sobrien struct bufarea *bp; 6331558Srgrimes char *cp, firstblk[DIRBLKSIZ]; 6341558Srgrimes 6351558Srgrimes lastbn = lblkno(&sblock, dp->di_size); 6361558Srgrimes if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 6371558Srgrimes return (0); 6381558Srgrimes if ((newblk = allocblk(sblock.fs_frag)) == 0) 6391558Srgrimes return (0); 6401558Srgrimes dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 6411558Srgrimes dp->di_db[lastbn] = newblk; 6421558Srgrimes dp->di_size += sblock.fs_bsize; 6431558Srgrimes dp->di_blocks += btodb(sblock.fs_bsize); 6441558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 6451558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 6461558Srgrimes if (bp->b_errs) 6471558Srgrimes goto bad; 64823675Speter memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 6491558Srgrimes bp = getdirblk(newblk, sblock.fs_bsize); 6501558Srgrimes if (bp->b_errs) 6511558Srgrimes goto bad; 65223675Speter memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 6531558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 6541558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_bsize]; 6551558Srgrimes cp += DIRBLKSIZ) 65623675Speter memmove(cp, &emptydir, sizeof emptydir); 6571558Srgrimes dirty(bp); 6581558Srgrimes bp = getdirblk(dp->di_db[lastbn + 1], 6591558Srgrimes (long)dblksize(&sblock, dp, lastbn + 1)); 6601558Srgrimes if (bp->b_errs) 6611558Srgrimes goto bad; 66223675Speter memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 6631558Srgrimes pwarn("NO SPACE LEFT IN %s", name); 6641558Srgrimes if (preen) 6651558Srgrimes printf(" (EXPANDED)\n"); 6661558Srgrimes else if (reply("EXPAND") == 0) 6671558Srgrimes goto bad; 6681558Srgrimes dirty(bp); 6691558Srgrimes inodirty(); 6701558Srgrimes return (1); 6711558Srgrimesbad: 6721558Srgrimes dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 6731558Srgrimes dp->di_db[lastbn + 1] = 0; 6741558Srgrimes dp->di_size -= sblock.fs_bsize; 6751558Srgrimes dp->di_blocks -= btodb(sblock.fs_bsize); 6761558Srgrimes freeblk(newblk, sblock.fs_frag); 6771558Srgrimes return (0); 6781558Srgrimes} 6791558Srgrimes 6801558Srgrimes/* 6811558Srgrimes * allocate a new directory 6821558Srgrimes */ 6837586Sbdeino_t 6841558Srgrimesallocdir(parent, request, mode) 6851558Srgrimes ino_t parent, request; 6861558Srgrimes int mode; 6871558Srgrimes{ 6881558Srgrimes ino_t ino; 6891558Srgrimes char *cp; 6901558Srgrimes struct dinode *dp; 69163810Smckusick struct bufarea *bp; 69263810Smckusick struct inoinfo *inp; 6931558Srgrimes struct dirtemplate *dirp; 6941558Srgrimes 6951558Srgrimes ino = allocino(request, IFDIR|mode); 6961558Srgrimes if (newinofmt) 6971558Srgrimes dirp = &dirhead; 6981558Srgrimes else 6991558Srgrimes dirp = (struct dirtemplate *)&odirhead; 7001558Srgrimes dirp->dot_ino = ino; 7011558Srgrimes dirp->dotdot_ino = parent; 7021558Srgrimes dp = ginode(ino); 7031558Srgrimes bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 7041558Srgrimes if (bp->b_errs) { 7051558Srgrimes freeino(ino); 7061558Srgrimes return (0); 7071558Srgrimes } 70823675Speter memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 7091558Srgrimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 7101558Srgrimes cp < &bp->b_un.b_buf[sblock.fs_fsize]; 7111558Srgrimes cp += DIRBLKSIZ) 71223675Speter memmove(cp, &emptydir, sizeof emptydir); 7131558Srgrimes dirty(bp); 7141558Srgrimes dp->di_nlink = 2; 7151558Srgrimes inodirty(); 7161558Srgrimes if (ino == ROOTINO) { 71741474Sjulian inoinfo(ino)->ino_linkcnt = dp->di_nlink; 7181558Srgrimes cacheino(dp, ino); 7191558Srgrimes return(ino); 7201558Srgrimes } 72141474Sjulian if (inoinfo(parent)->ino_state != DSTATE && 72241474Sjulian inoinfo(parent)->ino_state != DFOUND) { 7231558Srgrimes freeino(ino); 7241558Srgrimes return (0); 7251558Srgrimes } 7261558Srgrimes cacheino(dp, ino); 72763810Smckusick inp = getinoinfo(ino); 72863810Smckusick inp->i_parent = parent; 72963810Smckusick inp->i_dotdot = parent; 73041474Sjulian inoinfo(ino)->ino_state = inoinfo(parent)->ino_state; 73141474Sjulian if (inoinfo(ino)->ino_state == DSTATE) { 73241474Sjulian inoinfo(ino)->ino_linkcnt = dp->di_nlink; 73341474Sjulian inoinfo(parent)->ino_linkcnt++; 7341558Srgrimes } 7351558Srgrimes dp = ginode(parent); 7361558Srgrimes dp->di_nlink++; 7371558Srgrimes inodirty(); 7381558Srgrimes return (ino); 7391558Srgrimes} 7401558Srgrimes 7411558Srgrimes/* 7421558Srgrimes * free a directory inode 7431558Srgrimes */ 7447585Sbdestatic void 7451558Srgrimesfreedir(ino, parent) 7461558Srgrimes ino_t ino, parent; 7471558Srgrimes{ 7481558Srgrimes struct dinode *dp; 7491558Srgrimes 7501558Srgrimes if (ino != parent) { 7511558Srgrimes dp = ginode(parent); 7521558Srgrimes dp->di_nlink--; 7531558Srgrimes inodirty(); 7541558Srgrimes } 7551558Srgrimes freeino(ino); 7561558Srgrimes} 7571558Srgrimes 7581558Srgrimes/* 7591558Srgrimes * generate a temporary name for the lost+found directory. 7601558Srgrimes */ 76123675Speterstatic int 7621558Srgrimeslftempname(bufp, ino) 7631558Srgrimes char *bufp; 7641558Srgrimes ino_t ino; 7651558Srgrimes{ 76692806Sobrien ino_t in; 76792806Sobrien char *cp; 7681558Srgrimes int namlen; 7691558Srgrimes 7701558Srgrimes cp = bufp + 2; 7711558Srgrimes for (in = maxino; in > 0; in /= 10) 7721558Srgrimes cp++; 7731558Srgrimes *--cp = 0; 7741558Srgrimes namlen = cp - bufp; 7751558Srgrimes in = ino; 7761558Srgrimes while (cp > bufp) { 7771558Srgrimes *--cp = (in % 10) + '0'; 7781558Srgrimes in /= 10; 7791558Srgrimes } 7801558Srgrimes *cp = '#'; 7811558Srgrimes return (namlen); 7821558Srgrimes} 7831558Srgrimes 7841558Srgrimes/* 7851558Srgrimes * Get a directory block. 7861558Srgrimes * Insure that it is held until another is requested. 7871558Srgrimes */ 78823675Speterstatic struct bufarea * 7891558Srgrimesgetdirblk(blkno, size) 79023675Speter ufs_daddr_t blkno; 7911558Srgrimes long size; 7921558Srgrimes{ 7931558Srgrimes 7941558Srgrimes if (pdirbp != 0) 7951558Srgrimes pdirbp->b_flags &= ~B_INUSE; 7961558Srgrimes pdirbp = getdatablk(blkno, size); 7971558Srgrimes return (pdirbp); 7981558Srgrimes} 799