18fae3551SRodney W. Grimes /* 28fae3551SRodney W. Grimes * Copyright (c) 1980, 1986, 1993 38fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 48fae3551SRodney W. Grimes * 58fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 68fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 78fae3551SRodney W. Grimes * are met: 88fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 98fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 108fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 128fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 138fae3551SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 148fae3551SRodney W. Grimes * must display the following acknowledgement: 158fae3551SRodney W. Grimes * This product includes software developed by the University of 168fae3551SRodney W. Grimes * California, Berkeley and its contributors. 178fae3551SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 188fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 198fae3551SRodney W. Grimes * without specific prior written permission. 208fae3551SRodney W. Grimes * 218fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 228fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 238fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 248fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 258fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 268fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 278fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 288fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 298fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 308fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 318fae3551SRodney W. Grimes * SUCH DAMAGE. 328fae3551SRodney W. Grimes */ 338fae3551SRodney W. Grimes 348fae3551SRodney W. Grimes #ifndef lint 358fae3551SRodney W. Grimes static char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 6/5/93"; 368fae3551SRodney W. Grimes #endif /* not lint */ 378fae3551SRodney W. Grimes 388fae3551SRodney W. Grimes #include <sys/param.h> 398fae3551SRodney W. Grimes #include <sys/time.h> 408fae3551SRodney W. Grimes #include <ufs/ufs/dinode.h> 418fae3551SRodney W. Grimes #include <ufs/ufs/dir.h> 428fae3551SRodney W. Grimes #include <ufs/ffs/fs.h> 438fae3551SRodney W. Grimes #include <stdlib.h> 448fae3551SRodney W. Grimes #include <string.h> 458fae3551SRodney W. Grimes #include "fsck.h" 468fae3551SRodney W. Grimes 478fae3551SRodney W. Grimes char *lfname = "lost+found"; 488fae3551SRodney W. Grimes int lfmode = 01777; 498fae3551SRodney W. Grimes struct dirtemplate emptydir = { 0, DIRBLKSIZ }; 508fae3551SRodney W. Grimes struct dirtemplate dirhead = { 518fae3551SRodney W. Grimes 0, 12, DT_DIR, 1, ".", 528fae3551SRodney W. Grimes 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 538fae3551SRodney W. Grimes }; 548fae3551SRodney W. Grimes struct odirtemplate odirhead = { 558fae3551SRodney W. Grimes 0, 12, 1, ".", 568fae3551SRodney W. Grimes 0, DIRBLKSIZ - 12, 2, ".." 578fae3551SRodney W. Grimes }; 588fae3551SRodney W. Grimes 598fae3551SRodney W. Grimes struct direct *fsck_readdir(); 608fae3551SRodney W. Grimes struct bufarea *getdirblk(); 618fae3551SRodney W. Grimes 628fae3551SRodney W. Grimes /* 638fae3551SRodney W. Grimes * Propagate connected state through the tree. 648fae3551SRodney W. Grimes */ 658fae3551SRodney W. Grimes propagate() 668fae3551SRodney W. Grimes { 678fae3551SRodney W. Grimes register struct inoinfo **inpp, *inp; 688fae3551SRodney W. Grimes struct inoinfo **inpend; 698fae3551SRodney W. Grimes long change; 708fae3551SRodney W. Grimes 718fae3551SRodney W. Grimes inpend = &inpsort[inplast]; 728fae3551SRodney W. Grimes do { 738fae3551SRodney W. Grimes change = 0; 748fae3551SRodney W. Grimes for (inpp = inpsort; inpp < inpend; inpp++) { 758fae3551SRodney W. Grimes inp = *inpp; 768fae3551SRodney W. Grimes if (inp->i_parent == 0) 778fae3551SRodney W. Grimes continue; 788fae3551SRodney W. Grimes if (statemap[inp->i_parent] == DFOUND && 798fae3551SRodney W. Grimes statemap[inp->i_number] == DSTATE) { 808fae3551SRodney W. Grimes statemap[inp->i_number] = DFOUND; 818fae3551SRodney W. Grimes change++; 828fae3551SRodney W. Grimes } 838fae3551SRodney W. Grimes } 848fae3551SRodney W. Grimes } while (change > 0); 858fae3551SRodney W. Grimes } 868fae3551SRodney W. Grimes 878fae3551SRodney W. Grimes /* 888fae3551SRodney W. Grimes * Scan each entry in a directory block. 898fae3551SRodney W. Grimes */ 908fae3551SRodney W. Grimes dirscan(idesc) 918fae3551SRodney W. Grimes register struct inodesc *idesc; 928fae3551SRodney W. Grimes { 938fae3551SRodney W. Grimes register struct direct *dp; 948fae3551SRodney W. Grimes register struct bufarea *bp; 958fae3551SRodney W. Grimes int dsize, n; 968fae3551SRodney W. Grimes long blksiz; 978fae3551SRodney W. Grimes char dbuf[DIRBLKSIZ]; 988fae3551SRodney W. Grimes 998fae3551SRodney W. Grimes if (idesc->id_type != DATA) 1008fae3551SRodney W. Grimes errexit("wrong type to dirscan %d\n", idesc->id_type); 1018fae3551SRodney W. Grimes if (idesc->id_entryno == 0 && 1028fae3551SRodney W. Grimes (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 1038fae3551SRodney W. Grimes idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 1048fae3551SRodney W. Grimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1058fae3551SRodney W. Grimes if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 1068fae3551SRodney W. Grimes idesc->id_filesize -= blksiz; 1078fae3551SRodney W. Grimes return (SKIP); 1088fae3551SRodney W. Grimes } 1098fae3551SRodney W. Grimes idesc->id_loc = 0; 1108fae3551SRodney W. Grimes for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 1118fae3551SRodney W. Grimes dsize = dp->d_reclen; 1128fae3551SRodney W. Grimes bcopy((char *)dp, dbuf, (size_t)dsize); 1138fae3551SRodney W. Grimes # if (BYTE_ORDER == LITTLE_ENDIAN) 1148fae3551SRodney W. Grimes if (!newinofmt) { 1158fae3551SRodney W. Grimes struct direct *tdp = (struct direct *)dbuf; 1168fae3551SRodney W. Grimes u_char tmp; 1178fae3551SRodney W. Grimes 1188fae3551SRodney W. Grimes tmp = tdp->d_namlen; 1198fae3551SRodney W. Grimes tdp->d_namlen = tdp->d_type; 1208fae3551SRodney W. Grimes tdp->d_type = tmp; 1218fae3551SRodney W. Grimes } 1228fae3551SRodney W. Grimes # endif 1238fae3551SRodney W. Grimes idesc->id_dirp = (struct direct *)dbuf; 1248fae3551SRodney W. Grimes if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 1258fae3551SRodney W. Grimes # if (BYTE_ORDER == LITTLE_ENDIAN) 1268fae3551SRodney W. Grimes if (!newinofmt && !doinglevel2) { 1278fae3551SRodney W. Grimes struct direct *tdp; 1288fae3551SRodney W. Grimes u_char tmp; 1298fae3551SRodney W. Grimes 1308fae3551SRodney W. Grimes tdp = (struct direct *)dbuf; 1318fae3551SRodney W. Grimes tmp = tdp->d_namlen; 1328fae3551SRodney W. Grimes tdp->d_namlen = tdp->d_type; 1338fae3551SRodney W. Grimes tdp->d_type = tmp; 1348fae3551SRodney W. Grimes } 1358fae3551SRodney W. Grimes # endif 1368fae3551SRodney W. Grimes bp = getdirblk(idesc->id_blkno, blksiz); 1378fae3551SRodney W. Grimes bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize, 1388fae3551SRodney W. Grimes (size_t)dsize); 1398fae3551SRodney W. Grimes dirty(bp); 1408fae3551SRodney W. Grimes sbdirty(); 1418fae3551SRodney W. Grimes } 1428fae3551SRodney W. Grimes if (n & STOP) 1438fae3551SRodney W. Grimes return (n); 1448fae3551SRodney W. Grimes } 1458fae3551SRodney W. Grimes return (idesc->id_filesize > 0 ? KEEPON : STOP); 1468fae3551SRodney W. Grimes } 1478fae3551SRodney W. Grimes 1488fae3551SRodney W. Grimes /* 1498fae3551SRodney W. Grimes * get next entry in a directory. 1508fae3551SRodney W. Grimes */ 1518fae3551SRodney W. Grimes struct direct * 1528fae3551SRodney W. Grimes fsck_readdir(idesc) 1538fae3551SRodney W. Grimes register struct inodesc *idesc; 1548fae3551SRodney W. Grimes { 1558fae3551SRodney W. Grimes register struct direct *dp, *ndp; 1568fae3551SRodney W. Grimes register struct bufarea *bp; 1578fae3551SRodney W. Grimes long size, blksiz, fix, dploc; 1588fae3551SRodney W. Grimes 1598fae3551SRodney W. Grimes blksiz = idesc->id_numfrags * sblock.fs_fsize; 1608fae3551SRodney W. Grimes bp = getdirblk(idesc->id_blkno, blksiz); 1618fae3551SRodney W. Grimes if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 1628fae3551SRodney W. Grimes idesc->id_loc < blksiz) { 1638fae3551SRodney W. Grimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1648fae3551SRodney W. Grimes if (dircheck(idesc, dp)) 1658fae3551SRodney W. Grimes goto dpok; 1668fae3551SRodney W. Grimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1678fae3551SRodney W. Grimes bp = getdirblk(idesc->id_blkno, blksiz); 1688fae3551SRodney W. Grimes dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1698fae3551SRodney W. Grimes dp->d_reclen = DIRBLKSIZ; 1708fae3551SRodney W. Grimes dp->d_ino = 0; 1718fae3551SRodney W. Grimes dp->d_type = 0; 1728fae3551SRodney W. Grimes dp->d_namlen = 0; 1738fae3551SRodney W. Grimes dp->d_name[0] = '\0'; 1748fae3551SRodney W. Grimes if (fix) 1758fae3551SRodney W. Grimes dirty(bp); 1768fae3551SRodney W. Grimes idesc->id_loc += DIRBLKSIZ; 1778fae3551SRodney W. Grimes idesc->id_filesize -= DIRBLKSIZ; 1788fae3551SRodney W. Grimes return (dp); 1798fae3551SRodney W. Grimes } 1808fae3551SRodney W. Grimes dpok: 1818fae3551SRodney W. Grimes if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 1828fae3551SRodney W. Grimes return NULL; 1838fae3551SRodney W. Grimes dploc = idesc->id_loc; 1848fae3551SRodney W. Grimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 1858fae3551SRodney W. Grimes idesc->id_loc += dp->d_reclen; 1868fae3551SRodney W. Grimes idesc->id_filesize -= dp->d_reclen; 1878fae3551SRodney W. Grimes if ((idesc->id_loc % DIRBLKSIZ) == 0) 1888fae3551SRodney W. Grimes return (dp); 1898fae3551SRodney W. Grimes ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 1908fae3551SRodney W. Grimes if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 1918fae3551SRodney W. Grimes dircheck(idesc, ndp) == 0) { 1928fae3551SRodney W. Grimes size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 1938fae3551SRodney W. Grimes idesc->id_loc += size; 1948fae3551SRodney W. Grimes idesc->id_filesize -= size; 1958fae3551SRodney W. Grimes fix = dofix(idesc, "DIRECTORY CORRUPTED"); 1968fae3551SRodney W. Grimes bp = getdirblk(idesc->id_blkno, blksiz); 1978fae3551SRodney W. Grimes dp = (struct direct *)(bp->b_un.b_buf + dploc); 1988fae3551SRodney W. Grimes dp->d_reclen += size; 1998fae3551SRodney W. Grimes if (fix) 2008fae3551SRodney W. Grimes dirty(bp); 2018fae3551SRodney W. Grimes } 2028fae3551SRodney W. Grimes return (dp); 2038fae3551SRodney W. Grimes } 2048fae3551SRodney W. Grimes 2058fae3551SRodney W. Grimes /* 2068fae3551SRodney W. Grimes * Verify that a directory entry is valid. 2078fae3551SRodney W. Grimes * This is a superset of the checks made in the kernel. 2088fae3551SRodney W. Grimes */ 2098fae3551SRodney W. Grimes dircheck(idesc, dp) 2108fae3551SRodney W. Grimes struct inodesc *idesc; 2118fae3551SRodney W. Grimes register struct direct *dp; 2128fae3551SRodney W. Grimes { 2138fae3551SRodney W. Grimes register int size; 2148fae3551SRodney W. Grimes register char *cp; 2158fae3551SRodney W. Grimes u_char namlen, type; 2168fae3551SRodney W. Grimes int spaceleft; 2178fae3551SRodney W. Grimes 2188fae3551SRodney W. Grimes size = DIRSIZ(!newinofmt, dp); 2198fae3551SRodney W. Grimes spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 2208fae3551SRodney W. Grimes # if (BYTE_ORDER == LITTLE_ENDIAN) 2218fae3551SRodney W. Grimes if (!newinofmt) { 2228fae3551SRodney W. Grimes type = dp->d_namlen; 2238fae3551SRodney W. Grimes namlen = dp->d_type; 2248fae3551SRodney W. Grimes } else { 2258fae3551SRodney W. Grimes namlen = dp->d_namlen; 2268fae3551SRodney W. Grimes type = dp->d_type; 2278fae3551SRodney W. Grimes } 2288fae3551SRodney W. Grimes # else 2298fae3551SRodney W. Grimes namlen = dp->d_namlen; 2308fae3551SRodney W. Grimes type = dp->d_type; 2318fae3551SRodney W. Grimes # endif 2328fae3551SRodney W. Grimes if (dp->d_ino < maxino && 2338fae3551SRodney W. Grimes dp->d_reclen != 0 && 2348fae3551SRodney W. Grimes dp->d_reclen <= spaceleft && 2358fae3551SRodney W. Grimes (dp->d_reclen & 0x3) == 0 && 2368fae3551SRodney W. Grimes dp->d_reclen >= size && 2378fae3551SRodney W. Grimes idesc->id_filesize >= size && 2388fae3551SRodney W. Grimes namlen <= MAXNAMLEN && 2398fae3551SRodney W. Grimes type <= 15) { 2408fae3551SRodney W. Grimes if (dp->d_ino == 0) 2418fae3551SRodney W. Grimes return (1); 2428fae3551SRodney W. Grimes for (cp = dp->d_name, size = 0; size < namlen; size++) 2438fae3551SRodney W. Grimes if (*cp == 0 || (*cp++ == '/')) 2448fae3551SRodney W. Grimes return (0); 2458fae3551SRodney W. Grimes if (*cp == 0) 2468fae3551SRodney W. Grimes return (1); 2478fae3551SRodney W. Grimes } 2488fae3551SRodney W. Grimes return (0); 2498fae3551SRodney W. Grimes } 2508fae3551SRodney W. Grimes 2518fae3551SRodney W. Grimes direrror(ino, errmesg) 2528fae3551SRodney W. Grimes ino_t ino; 2538fae3551SRodney W. Grimes char *errmesg; 2548fae3551SRodney W. Grimes { 2558fae3551SRodney W. Grimes 2568fae3551SRodney W. Grimes fileerror(ino, ino, errmesg); 2578fae3551SRodney W. Grimes } 2588fae3551SRodney W. Grimes 2598fae3551SRodney W. Grimes fileerror(cwd, ino, errmesg) 2608fae3551SRodney W. Grimes ino_t cwd, ino; 2618fae3551SRodney W. Grimes char *errmesg; 2628fae3551SRodney W. Grimes { 2638fae3551SRodney W. Grimes register struct dinode *dp; 2648fae3551SRodney W. Grimes char pathbuf[MAXPATHLEN + 1]; 2658fae3551SRodney W. Grimes 2668fae3551SRodney W. Grimes pwarn("%s ", errmesg); 2678fae3551SRodney W. Grimes pinode(ino); 2688fae3551SRodney W. Grimes printf("\n"); 2698fae3551SRodney W. Grimes getpathname(pathbuf, cwd, ino); 2708fae3551SRodney W. Grimes if (ino < ROOTINO || ino > maxino) { 2718fae3551SRodney W. Grimes pfatal("NAME=%s\n", pathbuf); 2728fae3551SRodney W. Grimes return; 2738fae3551SRodney W. Grimes } 2748fae3551SRodney W. Grimes dp = ginode(ino); 2758fae3551SRodney W. Grimes if (ftypeok(dp)) 2768fae3551SRodney W. Grimes pfatal("%s=%s\n", 2778fae3551SRodney W. Grimes (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 2788fae3551SRodney W. Grimes else 2798fae3551SRodney W. Grimes pfatal("NAME=%s\n", pathbuf); 2808fae3551SRodney W. Grimes } 2818fae3551SRodney W. Grimes 2828fae3551SRodney W. Grimes adjust(idesc, lcnt) 2838fae3551SRodney W. Grimes register struct inodesc *idesc; 2848fae3551SRodney W. Grimes short lcnt; 2858fae3551SRodney W. Grimes { 2868fae3551SRodney W. Grimes register struct dinode *dp; 2878fae3551SRodney W. Grimes 2888fae3551SRodney W. Grimes dp = ginode(idesc->id_number); 2898fae3551SRodney W. Grimes if (dp->di_nlink == lcnt) { 2908fae3551SRodney W. Grimes if (linkup(idesc->id_number, (ino_t)0) == 0) 2918fae3551SRodney W. Grimes clri(idesc, "UNREF", 0); 2928fae3551SRodney W. Grimes } else { 2938fae3551SRodney W. Grimes pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 2948fae3551SRodney W. Grimes ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 2958fae3551SRodney W. Grimes pinode(idesc->id_number); 2968fae3551SRodney W. Grimes printf(" COUNT %d SHOULD BE %d", 2978fae3551SRodney W. Grimes dp->di_nlink, dp->di_nlink - lcnt); 2988fae3551SRodney W. Grimes if (preen) { 2998fae3551SRodney W. Grimes if (lcnt < 0) { 3008fae3551SRodney W. Grimes printf("\n"); 3018fae3551SRodney W. Grimes pfatal("LINK COUNT INCREASING"); 3028fae3551SRodney W. Grimes } 3038fae3551SRodney W. Grimes printf(" (ADJUSTED)\n"); 3048fae3551SRodney W. Grimes } 3058fae3551SRodney W. Grimes if (preen || reply("ADJUST") == 1) { 3068fae3551SRodney W. Grimes dp->di_nlink -= lcnt; 3078fae3551SRodney W. Grimes inodirty(); 3088fae3551SRodney W. Grimes } 3098fae3551SRodney W. Grimes } 3108fae3551SRodney W. Grimes } 3118fae3551SRodney W. Grimes 3128fae3551SRodney W. Grimes mkentry(idesc) 3138fae3551SRodney W. Grimes struct inodesc *idesc; 3148fae3551SRodney W. Grimes { 3158fae3551SRodney W. Grimes register struct direct *dirp = idesc->id_dirp; 3168fae3551SRodney W. Grimes struct direct newent; 3178fae3551SRodney W. Grimes int newlen, oldlen; 3188fae3551SRodney W. Grimes 3198fae3551SRodney W. Grimes newent.d_namlen = strlen(idesc->id_name); 3208fae3551SRodney W. Grimes newlen = DIRSIZ(0, &newent); 3218fae3551SRodney W. Grimes if (dirp->d_ino != 0) 3228fae3551SRodney W. Grimes oldlen = DIRSIZ(0, dirp); 3238fae3551SRodney W. Grimes else 3248fae3551SRodney W. Grimes oldlen = 0; 3258fae3551SRodney W. Grimes if (dirp->d_reclen - oldlen < newlen) 3268fae3551SRodney W. Grimes return (KEEPON); 3278fae3551SRodney W. Grimes newent.d_reclen = dirp->d_reclen - oldlen; 3288fae3551SRodney W. Grimes dirp->d_reclen = oldlen; 3298fae3551SRodney W. Grimes dirp = (struct direct *)(((char *)dirp) + oldlen); 3308fae3551SRodney W. Grimes dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 3318fae3551SRodney W. Grimes if (newinofmt) 3328fae3551SRodney W. Grimes dirp->d_type = typemap[idesc->id_parent]; 3338fae3551SRodney W. Grimes else 3348fae3551SRodney W. Grimes dirp->d_type = 0; 3358fae3551SRodney W. Grimes dirp->d_reclen = newent.d_reclen; 3368fae3551SRodney W. Grimes dirp->d_namlen = newent.d_namlen; 3378fae3551SRodney W. Grimes bcopy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 3388fae3551SRodney W. Grimes return (ALTERED|STOP); 3398fae3551SRodney W. Grimes } 3408fae3551SRodney W. Grimes 3418fae3551SRodney W. Grimes chgino(idesc) 3428fae3551SRodney W. Grimes struct inodesc *idesc; 3438fae3551SRodney W. Grimes { 3448fae3551SRodney W. Grimes register struct direct *dirp = idesc->id_dirp; 3458fae3551SRodney W. Grimes 3468fae3551SRodney W. Grimes if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 3478fae3551SRodney W. Grimes return (KEEPON); 3488fae3551SRodney W. Grimes dirp->d_ino = idesc->id_parent; 3498fae3551SRodney W. Grimes if (newinofmt) 3508fae3551SRodney W. Grimes dirp->d_type = typemap[idesc->id_parent]; 3518fae3551SRodney W. Grimes else 3528fae3551SRodney W. Grimes dirp->d_type = 0; 3538fae3551SRodney W. Grimes return (ALTERED|STOP); 3548fae3551SRodney W. Grimes } 3558fae3551SRodney W. Grimes 3568fae3551SRodney W. Grimes linkup(orphan, parentdir) 3578fae3551SRodney W. Grimes ino_t orphan; 3588fae3551SRodney W. Grimes ino_t parentdir; 3598fae3551SRodney W. Grimes { 3608fae3551SRodney W. Grimes register struct dinode *dp; 3618fae3551SRodney W. Grimes int lostdir; 3628fae3551SRodney W. Grimes ino_t oldlfdir; 3638fae3551SRodney W. Grimes struct inodesc idesc; 3648fae3551SRodney W. Grimes char tempname[BUFSIZ]; 3658fae3551SRodney W. Grimes extern int pass4check(); 3668fae3551SRodney W. Grimes 3678fae3551SRodney W. Grimes bzero((char *)&idesc, sizeof(struct inodesc)); 3688fae3551SRodney W. Grimes dp = ginode(orphan); 3698fae3551SRodney W. Grimes lostdir = (dp->di_mode & IFMT) == IFDIR; 3708fae3551SRodney W. Grimes pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 3718fae3551SRodney W. Grimes pinode(orphan); 3728fae3551SRodney W. Grimes if (preen && dp->di_size == 0) 3738fae3551SRodney W. Grimes return (0); 3748fae3551SRodney W. Grimes if (preen) 3758fae3551SRodney W. Grimes printf(" (RECONNECTED)\n"); 3768fae3551SRodney W. Grimes else 3778fae3551SRodney W. Grimes if (reply("RECONNECT") == 0) 3788fae3551SRodney W. Grimes return (0); 3798fae3551SRodney W. Grimes if (lfdir == 0) { 3808fae3551SRodney W. Grimes dp = ginode(ROOTINO); 3818fae3551SRodney W. Grimes idesc.id_name = lfname; 3828fae3551SRodney W. Grimes idesc.id_type = DATA; 3838fae3551SRodney W. Grimes idesc.id_func = findino; 3848fae3551SRodney W. Grimes idesc.id_number = ROOTINO; 3858fae3551SRodney W. Grimes if ((ckinode(dp, &idesc) & FOUND) != 0) { 3868fae3551SRodney W. Grimes lfdir = idesc.id_parent; 3878fae3551SRodney W. Grimes } else { 3888fae3551SRodney W. Grimes pwarn("NO lost+found DIRECTORY"); 3898fae3551SRodney W. Grimes if (preen || reply("CREATE")) { 3908fae3551SRodney W. Grimes lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 3918fae3551SRodney W. Grimes if (lfdir != 0) { 3928fae3551SRodney W. Grimes if (makeentry(ROOTINO, lfdir, lfname) != 0) { 3938fae3551SRodney W. Grimes if (preen) 3948fae3551SRodney W. Grimes printf(" (CREATED)\n"); 3958fae3551SRodney W. Grimes } else { 3968fae3551SRodney W. Grimes freedir(lfdir, ROOTINO); 3978fae3551SRodney W. Grimes lfdir = 0; 3988fae3551SRodney W. Grimes if (preen) 3998fae3551SRodney W. Grimes printf("\n"); 4008fae3551SRodney W. Grimes } 4018fae3551SRodney W. Grimes } 4028fae3551SRodney W. Grimes } 4038fae3551SRodney W. Grimes } 4048fae3551SRodney W. Grimes if (lfdir == 0) { 4058fae3551SRodney W. Grimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 4068fae3551SRodney W. Grimes printf("\n\n"); 4078fae3551SRodney W. Grimes return (0); 4088fae3551SRodney W. Grimes } 4098fae3551SRodney W. Grimes } 4108fae3551SRodney W. Grimes dp = ginode(lfdir); 4118fae3551SRodney W. Grimes if ((dp->di_mode & IFMT) != IFDIR) { 4128fae3551SRodney W. Grimes pfatal("lost+found IS NOT A DIRECTORY"); 4138fae3551SRodney W. Grimes if (reply("REALLOCATE") == 0) 4148fae3551SRodney W. Grimes return (0); 4158fae3551SRodney W. Grimes oldlfdir = lfdir; 4168fae3551SRodney W. Grimes if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 4178fae3551SRodney W. Grimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4188fae3551SRodney W. Grimes return (0); 4198fae3551SRodney W. Grimes } 4208fae3551SRodney W. Grimes if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 4218fae3551SRodney W. Grimes pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 4228fae3551SRodney W. Grimes return (0); 4238fae3551SRodney W. Grimes } 4248fae3551SRodney W. Grimes inodirty(); 4258fae3551SRodney W. Grimes idesc.id_type = ADDR; 4268fae3551SRodney W. Grimes idesc.id_func = pass4check; 4278fae3551SRodney W. Grimes idesc.id_number = oldlfdir; 4288fae3551SRodney W. Grimes adjust(&idesc, lncntp[oldlfdir] + 1); 4298fae3551SRodney W. Grimes lncntp[oldlfdir] = 0; 4308fae3551SRodney W. Grimes dp = ginode(lfdir); 4318fae3551SRodney W. Grimes } 4328fae3551SRodney W. Grimes if (statemap[lfdir] != DFOUND) { 4338fae3551SRodney W. Grimes pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 4348fae3551SRodney W. Grimes return (0); 4358fae3551SRodney W. Grimes } 4368fae3551SRodney W. Grimes (void)lftempname(tempname, orphan); 4378fae3551SRodney W. Grimes if (makeentry(lfdir, orphan, tempname) == 0) { 4388fae3551SRodney W. Grimes pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 4398fae3551SRodney W. Grimes printf("\n\n"); 4408fae3551SRodney W. Grimes return (0); 4418fae3551SRodney W. Grimes } 4428fae3551SRodney W. Grimes lncntp[orphan]--; 4438fae3551SRodney W. Grimes if (lostdir) { 4448fae3551SRodney W. Grimes if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 4458fae3551SRodney W. Grimes parentdir != (ino_t)-1) 4468fae3551SRodney W. Grimes (void)makeentry(orphan, lfdir, ".."); 4478fae3551SRodney W. Grimes dp = ginode(lfdir); 4488fae3551SRodney W. Grimes dp->di_nlink++; 4498fae3551SRodney W. Grimes inodirty(); 4508fae3551SRodney W. Grimes lncntp[lfdir]++; 4518fae3551SRodney W. Grimes pwarn("DIR I=%lu CONNECTED. ", orphan); 4528fae3551SRodney W. Grimes if (parentdir != (ino_t)-1) 4538fae3551SRodney W. Grimes printf("PARENT WAS I=%lu\n", parentdir); 4548fae3551SRodney W. Grimes if (preen == 0) 4558fae3551SRodney W. Grimes printf("\n"); 4568fae3551SRodney W. Grimes } 4578fae3551SRodney W. Grimes return (1); 4588fae3551SRodney W. Grimes } 4598fae3551SRodney W. Grimes 4608fae3551SRodney W. Grimes /* 4618fae3551SRodney W. Grimes * fix an entry in a directory. 4628fae3551SRodney W. Grimes */ 4638fae3551SRodney W. Grimes changeino(dir, name, newnum) 4648fae3551SRodney W. Grimes ino_t dir; 4658fae3551SRodney W. Grimes char *name; 4668fae3551SRodney W. Grimes ino_t newnum; 4678fae3551SRodney W. Grimes { 4688fae3551SRodney W. Grimes struct inodesc idesc; 4698fae3551SRodney W. Grimes 4708fae3551SRodney W. Grimes bzero((char *)&idesc, sizeof(struct inodesc)); 4718fae3551SRodney W. Grimes idesc.id_type = DATA; 4728fae3551SRodney W. Grimes idesc.id_func = chgino; 4738fae3551SRodney W. Grimes idesc.id_number = dir; 4748fae3551SRodney W. Grimes idesc.id_fix = DONTKNOW; 4758fae3551SRodney W. Grimes idesc.id_name = name; 4768fae3551SRodney W. Grimes idesc.id_parent = newnum; /* new value for name */ 4778fae3551SRodney W. Grimes return (ckinode(ginode(dir), &idesc)); 4788fae3551SRodney W. Grimes } 4798fae3551SRodney W. Grimes 4808fae3551SRodney W. Grimes /* 4818fae3551SRodney W. Grimes * make an entry in a directory 4828fae3551SRodney W. Grimes */ 4838fae3551SRodney W. Grimes makeentry(parent, ino, name) 4848fae3551SRodney W. Grimes ino_t parent, ino; 4858fae3551SRodney W. Grimes char *name; 4868fae3551SRodney W. Grimes { 4878fae3551SRodney W. Grimes struct dinode *dp; 4888fae3551SRodney W. Grimes struct inodesc idesc; 4898fae3551SRodney W. Grimes char pathbuf[MAXPATHLEN + 1]; 4908fae3551SRodney W. Grimes 4918fae3551SRodney W. Grimes if (parent < ROOTINO || parent >= maxino || 4928fae3551SRodney W. Grimes ino < ROOTINO || ino >= maxino) 4938fae3551SRodney W. Grimes return (0); 4948fae3551SRodney W. Grimes bzero((char *)&idesc, sizeof(struct inodesc)); 4958fae3551SRodney W. Grimes idesc.id_type = DATA; 4968fae3551SRodney W. Grimes idesc.id_func = mkentry; 4978fae3551SRodney W. Grimes idesc.id_number = parent; 4988fae3551SRodney W. Grimes idesc.id_parent = ino; /* this is the inode to enter */ 4998fae3551SRodney W. Grimes idesc.id_fix = DONTKNOW; 5008fae3551SRodney W. Grimes idesc.id_name = name; 5018fae3551SRodney W. Grimes dp = ginode(parent); 5028fae3551SRodney W. Grimes if (dp->di_size % DIRBLKSIZ) { 5038fae3551SRodney W. Grimes dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 5048fae3551SRodney W. Grimes inodirty(); 5058fae3551SRodney W. Grimes } 5068fae3551SRodney W. Grimes if ((ckinode(dp, &idesc) & ALTERED) != 0) 5078fae3551SRodney W. Grimes return (1); 5088fae3551SRodney W. Grimes getpathname(pathbuf, parent, parent); 5098fae3551SRodney W. Grimes dp = ginode(parent); 5108fae3551SRodney W. Grimes if (expanddir(dp, pathbuf) == 0) 5118fae3551SRodney W. Grimes return (0); 5128fae3551SRodney W. Grimes return (ckinode(dp, &idesc) & ALTERED); 5138fae3551SRodney W. Grimes } 5148fae3551SRodney W. Grimes 5158fae3551SRodney W. Grimes /* 5168fae3551SRodney W. Grimes * Attempt to expand the size of a directory 5178fae3551SRodney W. Grimes */ 5188fae3551SRodney W. Grimes expanddir(dp, name) 5198fae3551SRodney W. Grimes register struct dinode *dp; 5208fae3551SRodney W. Grimes char *name; 5218fae3551SRodney W. Grimes { 5228fae3551SRodney W. Grimes daddr_t lastbn, newblk; 5238fae3551SRodney W. Grimes register struct bufarea *bp; 5248fae3551SRodney W. Grimes char *cp, firstblk[DIRBLKSIZ]; 5258fae3551SRodney W. Grimes 5268fae3551SRodney W. Grimes lastbn = lblkno(&sblock, dp->di_size); 5278fae3551SRodney W. Grimes if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 5288fae3551SRodney W. Grimes return (0); 5298fae3551SRodney W. Grimes if ((newblk = allocblk(sblock.fs_frag)) == 0) 5308fae3551SRodney W. Grimes return (0); 5318fae3551SRodney W. Grimes dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 5328fae3551SRodney W. Grimes dp->di_db[lastbn] = newblk; 5338fae3551SRodney W. Grimes dp->di_size += sblock.fs_bsize; 5348fae3551SRodney W. Grimes dp->di_blocks += btodb(sblock.fs_bsize); 5358fae3551SRodney W. Grimes bp = getdirblk(dp->di_db[lastbn + 1], 5368fae3551SRodney W. Grimes (long)dblksize(&sblock, dp, lastbn + 1)); 5378fae3551SRodney W. Grimes if (bp->b_errs) 5388fae3551SRodney W. Grimes goto bad; 5398fae3551SRodney W. Grimes bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 5408fae3551SRodney W. Grimes bp = getdirblk(newblk, sblock.fs_bsize); 5418fae3551SRodney W. Grimes if (bp->b_errs) 5428fae3551SRodney W. Grimes goto bad; 5438fae3551SRodney W. Grimes bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 5448fae3551SRodney W. Grimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 5458fae3551SRodney W. Grimes cp < &bp->b_un.b_buf[sblock.fs_bsize]; 5468fae3551SRodney W. Grimes cp += DIRBLKSIZ) 5478fae3551SRodney W. Grimes bcopy((char *)&emptydir, cp, sizeof emptydir); 5488fae3551SRodney W. Grimes dirty(bp); 5498fae3551SRodney W. Grimes bp = getdirblk(dp->di_db[lastbn + 1], 5508fae3551SRodney W. Grimes (long)dblksize(&sblock, dp, lastbn + 1)); 5518fae3551SRodney W. Grimes if (bp->b_errs) 5528fae3551SRodney W. Grimes goto bad; 5538fae3551SRodney W. Grimes bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 5548fae3551SRodney W. Grimes pwarn("NO SPACE LEFT IN %s", name); 5558fae3551SRodney W. Grimes if (preen) 5568fae3551SRodney W. Grimes printf(" (EXPANDED)\n"); 5578fae3551SRodney W. Grimes else if (reply("EXPAND") == 0) 5588fae3551SRodney W. Grimes goto bad; 5598fae3551SRodney W. Grimes dirty(bp); 5608fae3551SRodney W. Grimes inodirty(); 5618fae3551SRodney W. Grimes return (1); 5628fae3551SRodney W. Grimes bad: 5638fae3551SRodney W. Grimes dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 5648fae3551SRodney W. Grimes dp->di_db[lastbn + 1] = 0; 5658fae3551SRodney W. Grimes dp->di_size -= sblock.fs_bsize; 5668fae3551SRodney W. Grimes dp->di_blocks -= btodb(sblock.fs_bsize); 5678fae3551SRodney W. Grimes freeblk(newblk, sblock.fs_frag); 5688fae3551SRodney W. Grimes return (0); 5698fae3551SRodney W. Grimes } 5708fae3551SRodney W. Grimes 5718fae3551SRodney W. Grimes /* 5728fae3551SRodney W. Grimes * allocate a new directory 5738fae3551SRodney W. Grimes */ 5748fae3551SRodney W. Grimes allocdir(parent, request, mode) 5758fae3551SRodney W. Grimes ino_t parent, request; 5768fae3551SRodney W. Grimes int mode; 5778fae3551SRodney W. Grimes { 5788fae3551SRodney W. Grimes ino_t ino; 5798fae3551SRodney W. Grimes char *cp; 5808fae3551SRodney W. Grimes struct dinode *dp; 5818fae3551SRodney W. Grimes register struct bufarea *bp; 5828fae3551SRodney W. Grimes struct dirtemplate *dirp; 5838fae3551SRodney W. Grimes 5848fae3551SRodney W. Grimes ino = allocino(request, IFDIR|mode); 5858fae3551SRodney W. Grimes if (newinofmt) 5868fae3551SRodney W. Grimes dirp = &dirhead; 5878fae3551SRodney W. Grimes else 5888fae3551SRodney W. Grimes dirp = (struct dirtemplate *)&odirhead; 5898fae3551SRodney W. Grimes dirp->dot_ino = ino; 5908fae3551SRodney W. Grimes dirp->dotdot_ino = parent; 5918fae3551SRodney W. Grimes dp = ginode(ino); 5928fae3551SRodney W. Grimes bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 5938fae3551SRodney W. Grimes if (bp->b_errs) { 5948fae3551SRodney W. Grimes freeino(ino); 5958fae3551SRodney W. Grimes return (0); 5968fae3551SRodney W. Grimes } 5978fae3551SRodney W. Grimes bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate)); 5988fae3551SRodney W. Grimes for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 5998fae3551SRodney W. Grimes cp < &bp->b_un.b_buf[sblock.fs_fsize]; 6008fae3551SRodney W. Grimes cp += DIRBLKSIZ) 6018fae3551SRodney W. Grimes bcopy((char *)&emptydir, cp, sizeof emptydir); 6028fae3551SRodney W. Grimes dirty(bp); 6038fae3551SRodney W. Grimes dp->di_nlink = 2; 6048fae3551SRodney W. Grimes inodirty(); 6058fae3551SRodney W. Grimes if (ino == ROOTINO) { 6068fae3551SRodney W. Grimes lncntp[ino] = dp->di_nlink; 6078fae3551SRodney W. Grimes cacheino(dp, ino); 6088fae3551SRodney W. Grimes return(ino); 6098fae3551SRodney W. Grimes } 6108fae3551SRodney W. Grimes if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 6118fae3551SRodney W. Grimes freeino(ino); 6128fae3551SRodney W. Grimes return (0); 6138fae3551SRodney W. Grimes } 6148fae3551SRodney W. Grimes cacheino(dp, ino); 6158fae3551SRodney W. Grimes statemap[ino] = statemap[parent]; 6168fae3551SRodney W. Grimes if (statemap[ino] == DSTATE) { 6178fae3551SRodney W. Grimes lncntp[ino] = dp->di_nlink; 6188fae3551SRodney W. Grimes lncntp[parent]++; 6198fae3551SRodney W. Grimes } 6208fae3551SRodney W. Grimes dp = ginode(parent); 6218fae3551SRodney W. Grimes dp->di_nlink++; 6228fae3551SRodney W. Grimes inodirty(); 6238fae3551SRodney W. Grimes return (ino); 6248fae3551SRodney W. Grimes } 6258fae3551SRodney W. Grimes 6268fae3551SRodney W. Grimes /* 6278fae3551SRodney W. Grimes * free a directory inode 6288fae3551SRodney W. Grimes */ 6298fae3551SRodney W. Grimes freedir(ino, parent) 6308fae3551SRodney W. Grimes ino_t ino, parent; 6318fae3551SRodney W. Grimes { 6328fae3551SRodney W. Grimes struct dinode *dp; 6338fae3551SRodney W. Grimes 6348fae3551SRodney W. Grimes if (ino != parent) { 6358fae3551SRodney W. Grimes dp = ginode(parent); 6368fae3551SRodney W. Grimes dp->di_nlink--; 6378fae3551SRodney W. Grimes inodirty(); 6388fae3551SRodney W. Grimes } 6398fae3551SRodney W. Grimes freeino(ino); 6408fae3551SRodney W. Grimes } 6418fae3551SRodney W. Grimes 6428fae3551SRodney W. Grimes /* 6438fae3551SRodney W. Grimes * generate a temporary name for the lost+found directory. 6448fae3551SRodney W. Grimes */ 6458fae3551SRodney W. Grimes lftempname(bufp, ino) 6468fae3551SRodney W. Grimes char *bufp; 6478fae3551SRodney W. Grimes ino_t ino; 6488fae3551SRodney W. Grimes { 6498fae3551SRodney W. Grimes register ino_t in; 6508fae3551SRodney W. Grimes register char *cp; 6518fae3551SRodney W. Grimes int namlen; 6528fae3551SRodney W. Grimes 6538fae3551SRodney W. Grimes cp = bufp + 2; 6548fae3551SRodney W. Grimes for (in = maxino; in > 0; in /= 10) 6558fae3551SRodney W. Grimes cp++; 6568fae3551SRodney W. Grimes *--cp = 0; 6578fae3551SRodney W. Grimes namlen = cp - bufp; 6588fae3551SRodney W. Grimes in = ino; 6598fae3551SRodney W. Grimes while (cp > bufp) { 6608fae3551SRodney W. Grimes *--cp = (in % 10) + '0'; 6618fae3551SRodney W. Grimes in /= 10; 6628fae3551SRodney W. Grimes } 6638fae3551SRodney W. Grimes *cp = '#'; 6648fae3551SRodney W. Grimes return (namlen); 6658fae3551SRodney W. Grimes } 6668fae3551SRodney W. Grimes 6678fae3551SRodney W. Grimes /* 6688fae3551SRodney W. Grimes * Get a directory block. 6698fae3551SRodney W. Grimes * Insure that it is held until another is requested. 6708fae3551SRodney W. Grimes */ 6718fae3551SRodney W. Grimes struct bufarea * 6728fae3551SRodney W. Grimes getdirblk(blkno, size) 6738fae3551SRodney W. Grimes daddr_t blkno; 6748fae3551SRodney W. Grimes long size; 6758fae3551SRodney W. Grimes { 6768fae3551SRodney W. Grimes 6778fae3551SRodney W. Grimes if (pdirbp != 0) 6788fae3551SRodney W. Grimes pdirbp->b_flags &= ~B_INUSE; 6798fae3551SRodney W. Grimes pdirbp = getdatablk(blkno, size); 6808fae3551SRodney W. Grimes return (pdirbp); 6818fae3551SRodney W. Grimes } 682