dir.c revision 23796
195719Sbenno/* 295719Sbenno * Copyright (c) 1980, 1986, 1993 395719Sbenno * The Regents of the University of California. All rights reserved. 4139825Simp * 595719Sbenno * Redistribution and use in source and binary forms, with or without 695719Sbenno * modification, are permitted provided that the following conditions 795719Sbenno * are met: 895719Sbenno * 1. Redistributions of source code must retain the above copyright 995719Sbenno * notice, this list of conditions and the following disclaimer. 1095719Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1195719Sbenno * notice, this list of conditions and the following disclaimer in the 1295719Sbenno * documentation and/or other materials provided with the distribution. 1395719Sbenno * 3. All advertising materials mentioning features or use of this software 1495719Sbenno * must display the following acknowledgement: 1595719Sbenno * This product includes software developed by the University of 1695719Sbenno * California, Berkeley and its contributors. 1795719Sbenno * 4. Neither the name of the University nor the names of its contributors 1895719Sbenno * may be used to endorse or promote products derived from this software 1995719Sbenno * without specific prior written permission. 2095719Sbenno * 2195719Sbenno * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2295719Sbenno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2395719Sbenno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2495719Sbenno * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2595719Sbenno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2695719Sbenno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2795719Sbenno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2895719Sbenno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2995719Sbenno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3095719Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3195719Sbenno * SUCH DAMAGE. 3295719Sbenno */ 3395719Sbenno 3495719Sbenno#ifndef lint 3595719Sbennostatic const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; 3695719Sbenno#endif /* not lint */ 3795719Sbenno 3895719Sbenno#include <sys/param.h> 39174599Smarcel#include <sys/time.h> 4095719Sbenno 4195719Sbenno#include <ufs/ufs/dinode.h> 42293641Snwhitehorn#include <ufs/ufs/dir.h> 43293641Snwhitehorn#include <ufs/ffs/fs.h> 44293641Snwhitehorn 45293641Snwhitehorn#include <err.h> 46293641Snwhitehorn#include <string.h> 47293641Snwhitehorn 4895719Sbenno#include "fsck.h" 4995719Sbenno 50209975Snwhitehornchar *lfname = "lost+found"; 51209975Snwhitehornint lfmode = 01777; 52209975Snwhitehornstruct dirtemplate emptydir = { 0, DIRBLKSIZ }; 53209975Snwhitehornstruct dirtemplate dirhead = { 54209975Snwhitehorn 0, 12, DT_DIR, 1, ".", 55212722Snwhitehorn 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 56212722Snwhitehorn}; 57212722Snwhitehornstruct odirtemplate odirhead = { 58212722Snwhitehorn 0, 12, 1, ".", 59222620Snwhitehorn 0, DIRBLKSIZ - 12, 2, ".." 60222620Snwhitehorn}; 61209975Snwhitehorn 62209975Snwhitehornstatic int chgino __P((struct inodesc *)); 63209975Snwhitehornstatic int dircheck __P((struct inodesc *, struct direct *)); 64209975Snwhitehornstatic int expanddir __P((struct dinode *dp, char *name)); 65209975Snwhitehornstatic void freedir __P((ino_t ino, ino_t parent)); 66209975Snwhitehornstatic struct direct *fsck_readdir __P((struct inodesc *)); 67222620Snwhitehornstatic struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size)); 68279751Snwhitehornstatic int lftempname __P((char *bufp, ino_t ino)); 69222620Snwhitehornstatic int mkentry __P((struct inodesc *)); 70209975Snwhitehorn 71212722Snwhitehorn/* 72212722Snwhitehorn * Propagate connected state through the tree. 73212722Snwhitehorn */ 74222620Snwhitehornvoid 75209975Snwhitehornpropagate() 76222620Snwhitehorn{ 77222620Snwhitehorn register struct inoinfo **inpp, *inp; 78222620Snwhitehorn struct inoinfo **inpend; 79209975Snwhitehorn long change; 80209975Snwhitehorn 81212722Snwhitehorn inpend = &inpsort[inplast]; 8295719Sbenno do { 83212722Snwhitehorn change = 0; 84222620Snwhitehorn for (inpp = inpsort; inpp < inpend; inpp++) { 85222620Snwhitehorn inp = *inpp; 86212722Snwhitehorn if (inp->i_parent == 0) 8795719Sbenno continue; 88212722Snwhitehorn if (statemap[inp->i_parent] == DFOUND && 89212722Snwhitehorn statemap[inp->i_number] == DSTATE) { 90212722Snwhitehorn statemap[inp->i_number] = DFOUND; 91212722Snwhitehorn change++; 92279751Snwhitehorn } 93222620Snwhitehorn } 9495719Sbenno } while (change > 0); 95222620Snwhitehorn} 96279751Snwhitehorn 97222620Snwhitehorn/* 98212722Snwhitehorn * Scan each entry in a directory block. 99222620Snwhitehorn */ 100212722Snwhitehornint 101222620Snwhitehorndirscan(idesc) 102222620Snwhitehorn register struct inodesc *idesc; 103279751Snwhitehorn{ 104222620Snwhitehorn register struct direct *dp; 105222620Snwhitehorn register struct bufarea *bp; 106212722Snwhitehorn int dsize, n; 107125441Sgrehan long blksiz; 108125441Sgrehan char dbuf[DIRBLKSIZ]; 109125441Sgrehan 110188860Snwhitehorn if (idesc->id_type != DATA) 111209975Snwhitehorn errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 112125441Sgrehan if (idesc->id_entryno == 0 && 113125441Sgrehan (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 114125441Sgrehan idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 115125441Sgrehan blksiz = idesc->id_numfrags * sblock.fs_fsize; 116125441Sgrehan if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 117125441Sgrehan idesc->id_filesize -= blksiz; 118230123Snwhitehorn return (SKIP); 119230123Snwhitehorn } 120230123Snwhitehorn idesc->id_loc = 0; 121125441Sgrehan for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 122125441Sgrehan dsize = dp->d_reclen; 123125441Sgrehan memmove(dbuf, dp, (size_t)dsize); 124125441Sgrehan# if (BYTE_ORDER == LITTLE_ENDIAN) 125125441Sgrehan if (!newinofmt) { 126209975Snwhitehorn struct direct *tdp = (struct direct *)dbuf; 127125441Sgrehan u_char tmp; 128209975Snwhitehorn 129230123Snwhitehorn tmp = tdp->d_namlen; 130125441Sgrehan tdp->d_namlen = tdp->d_type; 131125441Sgrehan tdp->d_type = tmp; 132125441Sgrehan } 133125441Sgrehan# endif 134209975Snwhitehorn idesc->id_dirp = (struct direct *)dbuf; 135209975Snwhitehorn if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 136209975Snwhitehorn# if (BYTE_ORDER == LITTLE_ENDIAN) 137209975Snwhitehorn if (!newinofmt && !doinglevel2) { 138209975Snwhitehorn struct direct *tdp; 139209975Snwhitehorn u_char tmp; 140125441Sgrehan 141209975Snwhitehorn tdp = (struct direct *)dbuf; 142209975Snwhitehorn tmp = tdp->d_namlen; 143209975Snwhitehorn tdp->d_namlen = tdp->d_type; 144209975Snwhitehorn tdp->d_type = tmp; 145209975Snwhitehorn } 146209975Snwhitehorn# endif 147209975Snwhitehorn bp = getdirblk(idesc->id_blkno, blksiz); 148209975Snwhitehorn memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 149209975Snwhitehorn (size_t)dsize); 150209975Snwhitehorn dirty(bp); 151209975Snwhitehorn sbdirty(); 152209975Snwhitehorn } 153209975Snwhitehorn if (n & STOP) 154209975Snwhitehorn return (n); 155209975Snwhitehorn } 156209975Snwhitehorn return (idesc->id_filesize > 0 ? KEEPON : STOP); 157209975Snwhitehorn} 158209975Snwhitehorn 159209975Snwhitehorn/* 160209975Snwhitehorn * get next entry in a directory. 161209975Snwhitehorn */ 162209975Snwhitehornstatic struct direct * 163209975Snwhitehornfsck_readdir(idesc) 164209975Snwhitehorn register struct inodesc *idesc; 165209975Snwhitehorn{ 166209975Snwhitehorn register struct direct *dp, *ndp; 167209975Snwhitehorn register struct bufarea *bp; 168209975Snwhitehorn long size, blksiz, fix, dploc; 169209975Snwhitehorn 170209975Snwhitehorn blksiz = idesc->id_numfrags * sblock.fs_fsize; 171209975Snwhitehorn bp = getdirblk(idesc->id_blkno, blksiz); 172209975Snwhitehorn if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 173209975Snwhitehorn idesc->id_loc < blksiz) { 174209975Snwhitehorn dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 175209975Snwhitehorn if (dircheck(idesc, dp)) 176209975Snwhitehorn goto dpok; 177209975Snwhitehorn if (idesc->id_fix == IGNORE) 178209975Snwhitehorn return (0); 179125441Sgrehan fix = dofix(idesc, "DIRECTORY CORRUPTED"); 180125441Sgrehan bp = getdirblk(idesc->id_blkno, blksiz); 181188860Snwhitehorn dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 182209975Snwhitehorn dp->d_reclen = DIRBLKSIZ; 183209975Snwhitehorn dp->d_ino = 0; 184209975Snwhitehorn dp->d_type = 0; 185209975Snwhitehorn dp->d_namlen = 0; 186209975Snwhitehorn dp->d_name[0] = '\0'; 187209975Snwhitehorn if (fix) 188223485Snwhitehorn dirty(bp); 189223485Snwhitehorn idesc->id_loc += DIRBLKSIZ; 19095719Sbenno idesc->id_filesize -= DIRBLKSIZ; 191125441Sgrehan return (dp); 192223485Snwhitehorn } 193223485Snwhitehorndpok: 194223485Snwhitehorn if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 195223485Snwhitehorn return NULL; 196223485Snwhitehorn dploc = idesc->id_loc; 197125441Sgrehan dp = (struct direct *)(bp->b_un.b_buf + dploc); 198209975Snwhitehorn idesc->id_loc += dp->d_reclen; 199209975Snwhitehorn idesc->id_filesize -= dp->d_reclen; 200209975Snwhitehorn if ((idesc->id_loc % DIRBLKSIZ) == 0) 201209975Snwhitehorn return (dp); 202209975Snwhitehorn ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 203125441Sgrehan if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 204209975Snwhitehorn dircheck(idesc, ndp) == 0) { 205209975Snwhitehorn size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 206209975Snwhitehorn idesc->id_loc += size; 207125441Sgrehan idesc->id_filesize -= size; 208125441Sgrehan if (idesc->id_fix == IGNORE) 209125441Sgrehan return (0); 210230123Snwhitehorn fix = dofix(idesc, "DIRECTORY CORRUPTED"); 211209975Snwhitehorn bp = getdirblk(idesc->id_blkno, blksiz); 212209975Snwhitehorn dp = (struct direct *)(bp->b_un.b_buf + dploc); 213209975Snwhitehorn dp->d_reclen += size; 214209975Snwhitehorn if (fix) 215209975Snwhitehorn dirty(bp); 216209975Snwhitehorn } 217209975Snwhitehorn return (dp); 218209975Snwhitehorn} 219209975Snwhitehorn 220209975Snwhitehorn/* 221209975Snwhitehorn * Verify that a directory entry is valid. 222209975Snwhitehorn * This is a superset of the checks made in the kernel. 223209975Snwhitehorn */ 224209975Snwhitehornstatic int 225209975Snwhitehorndircheck(idesc, dp) 226209975Snwhitehorn struct inodesc *idesc; 227209975Snwhitehorn register struct direct *dp; 228209975Snwhitehorn{ 229209975Snwhitehorn register int size; 230209975Snwhitehorn register char *cp; 231209975Snwhitehorn u_char namlen, type; 232209975Snwhitehorn int spaceleft; 233209975Snwhitehorn 234209975Snwhitehorn spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 235209975Snwhitehorn if (dp->d_ino >= maxino || 236209975Snwhitehorn dp->d_reclen == 0 || 237209975Snwhitehorn dp->d_reclen > spaceleft || 238209975Snwhitehorn (dp->d_reclen & 0x3) != 0) 239209975Snwhitehorn return (0); 240209975Snwhitehorn if (dp->d_ino == 0) 241209975Snwhitehorn return (1); 242209975Snwhitehorn size = DIRSIZ(!newinofmt, dp); 243125441Sgrehan# if (BYTE_ORDER == LITTLE_ENDIAN) 244230123Snwhitehorn if (!newinofmt) { 245125441Sgrehan type = dp->d_namlen; 246230123Snwhitehorn namlen = dp->d_type; 247230123Snwhitehorn } else { 248230123Snwhitehorn namlen = dp->d_namlen; 249125441Sgrehan type = dp->d_type; 250125441Sgrehan } 251230123Snwhitehorn# else 252230123Snwhitehorn namlen = dp->d_namlen; 253125441Sgrehan type = dp->d_type; 254125441Sgrehan# endif 255125441Sgrehan if (dp->d_reclen < size || 256209975Snwhitehorn idesc->id_filesize < size || 257209975Snwhitehorn namlen > MAXNAMLEN || 258209975Snwhitehorn type > 15) 259209975Snwhitehorn return (0); 260209975Snwhitehorn for (cp = dp->d_name, size = 0; size < namlen; size++) 261209975Snwhitehorn if (*cp == '\0' || (*cp++ == '/')) 262209975Snwhitehorn return (0); 263212722Snwhitehorn if (*cp != '\0') 264209975Snwhitehorn return (0); 265209975Snwhitehorn return (1); 266209975Snwhitehorn} 267209975Snwhitehorn 268209975Snwhitehornvoid 269209975Snwhitehorndirerror(ino, errmesg) 270230123Snwhitehorn ino_t ino; 271230123Snwhitehorn char *errmesg; 272230123Snwhitehorn{ 273230123Snwhitehorn 274125441Sgrehan fileerror(ino, ino, errmesg); 275230123Snwhitehorn} 276230123Snwhitehorn 277125441Sgrehanvoid 278230123Snwhitehornfileerror(cwd, ino, errmesg) 27995719Sbenno ino_t cwd, ino; 280242723Sjhibbits char *errmesg; 281242723Sjhibbits{ 282242723Sjhibbits register struct dinode *dp; 283242723Sjhibbits char pathbuf[MAXPATHLEN + 1]; 284242723Sjhibbits 285242723Sjhibbits pwarn("%s ", errmesg); 286242723Sjhibbits pinode(ino); 287242723Sjhibbits printf("\n"); 288242723Sjhibbits getpathname(pathbuf, cwd, ino); 289242723Sjhibbits if (ino < ROOTINO || ino > maxino) { 290242723Sjhibbits pfatal("NAME=%s\n", pathbuf); 291242723Sjhibbits return; 292242723Sjhibbits } 29395719Sbenno dp = ginode(ino); 294178628Smarcel if (ftypeok(dp)) 295178628Smarcel pfatal("%s=%s\n", 296198400Snwhitehorn (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 297198400Snwhitehorn else 298198400Snwhitehorn pfatal("NAME=%s\n", pathbuf); 299132571Sgrehan} 300277561Snwhitehorn 301178628Smarcelvoid 302209975Snwhitehornadjust(idesc, lcnt) 303209975Snwhitehorn register struct inodesc *idesc; 304209975Snwhitehorn int lcnt; 305209975Snwhitehorn{ 306209975Snwhitehorn register struct dinode *dp; 307209975Snwhitehorn 308277498Snwhitehorn dp = ginode(idesc->id_number); 309277498Snwhitehorn if (dp->di_nlink == lcnt) { 310277498Snwhitehorn if (linkup(idesc->id_number, (ino_t)0) == 0) 311277498Snwhitehorn clri(idesc, "UNREF", 0); 312277498Snwhitehorn } else { 313209975Snwhitehorn pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 314277498Snwhitehorn ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 315277561Snwhitehorn pinode(idesc->id_number); 316198400Snwhitehorn printf(" COUNT %d SHOULD BE %d", 317198400Snwhitehorn dp->di_nlink, dp->di_nlink - lcnt); 318277335Snwhitehorn if (preen) { 319178628Smarcel if (lcnt < 0) { 320277335Snwhitehorn printf("\n"); 321277335Snwhitehorn pfatal("LINK COUNT INCREASING"); 322277335Snwhitehorn } 323218824Snwhitehorn printf(" (ADJUSTED)\n"); 324209975Snwhitehorn } 325227386Snwhitehorn if (preen || reply("ADJUST") == 1) { 326218824Snwhitehorn dp->di_nlink -= lcnt; 327209975Snwhitehorn inodirty(); 328218824Snwhitehorn } 329209975Snwhitehorn } 330209975Snwhitehorn} 331261309Sjhibbits 332261309Sjhibbitsstatic int 333261309Sjhibbitsmkentry(idesc) 334261309Sjhibbits struct inodesc *idesc; 335261309Sjhibbits{ 336261309Sjhibbits register struct direct *dirp = idesc->id_dirp; 337261309Sjhibbits struct direct newent; 338261309Sjhibbits int newlen, oldlen; 339261309Sjhibbits 340261309Sjhibbits newent.d_namlen = strlen(idesc->id_name); 341261309Sjhibbits newlen = DIRSIZ(0, &newent); 342261309Sjhibbits if (dirp->d_ino != 0) 343218824Snwhitehorn oldlen = DIRSIZ(0, dirp); 344209975Snwhitehorn else 345261309Sjhibbits oldlen = 0; 346178628Smarcel if (dirp->d_reclen - oldlen < newlen) 347178628Smarcel return (KEEPON); 348178628Smarcel newent.d_reclen = dirp->d_reclen - oldlen; 349178628Smarcel dirp->d_reclen = oldlen; 350132571Sgrehan dirp = (struct direct *)(((char *)dirp) + oldlen); 351132571Sgrehan dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 35295719Sbenno dirp->d_reclen = newent.d_reclen; 353277498Snwhitehorn if (newinofmt) 35495719Sbenno dirp->d_type = typemap[idesc->id_parent]; 355178628Smarcel else 356277561Snwhitehorn dirp->d_type = 0; 357277498Snwhitehorn dirp->d_namlen = newent.d_namlen; 35896773Sbenno memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 359125441Sgrehan# if (BYTE_ORDER == LITTLE_ENDIAN) 360188860Snwhitehorn /* 361188860Snwhitehorn * If the entry was split, dirscan() will only reverse the byte 362279751Snwhitehorn * order of the original entry, and not the new one, before 363277498Snwhitehorn * writing it back out. So, we reverse the byte order here if 364279189Snwhitehorn * necessary. 365277498Snwhitehorn */ 366277561Snwhitehorn if (oldlen != 0 && !newinofmt && !doinglevel2) { 36795719Sbenno u_char tmp; 36895719Sbenno 369230123Snwhitehorn tmp = dirp->d_namlen; 370230123Snwhitehorn dirp->d_namlen = dirp->d_type; 371230123Snwhitehorn dirp->d_type = tmp; 372230123Snwhitehorn } 373230123Snwhitehorn# endif 374277561Snwhitehorn return (ALTERED|STOP); 375277498Snwhitehorn} 376230123Snwhitehorn 377230123Snwhitehornstatic int 378230123Snwhitehornchgino(idesc) 379230123Snwhitehorn struct inodesc *idesc; 380230123Snwhitehorn{ 381230123Snwhitehorn register struct direct *dirp = idesc->id_dirp; 382230123Snwhitehorn 383230123Snwhitehorn if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 384277498Snwhitehorn return (KEEPON); 385230123Snwhitehorn dirp->d_ino = idesc->id_parent; 386230123Snwhitehorn if (newinofmt) 387230123Snwhitehorn dirp->d_type = typemap[idesc->id_parent]; 388230123Snwhitehorn else 389230123Snwhitehorn dirp->d_type = 0; 390230123Snwhitehorn return (ALTERED|STOP); 391277498Snwhitehorn} 392277498Snwhitehorn 393277498Snwhitehornint 394277498Snwhitehornlinkup(orphan, parentdir) 395277498Snwhitehorn ino_t orphan; 396277498Snwhitehorn ino_t parentdir; 397230123Snwhitehorn{ 398277498Snwhitehorn register struct dinode *dp; 399277498Snwhitehorn int lostdir; 400277498Snwhitehorn ino_t oldlfdir; 401277498Snwhitehorn struct inodesc idesc; 402277498Snwhitehorn char tempname[BUFSIZ]; 403277498Snwhitehorn 404277498Snwhitehorn memset(&idesc, 0, sizeof(struct inodesc)); 405277498Snwhitehorn dp = ginode(orphan); 406277498Snwhitehorn lostdir = (dp->di_mode & IFMT) == IFDIR; 407277498Snwhitehorn pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 408277498Snwhitehorn pinode(orphan); 409277561Snwhitehorn if (preen && dp->di_size == 0) 410230123Snwhitehorn return (0); 411230123Snwhitehorn if (preen) 412230123Snwhitehorn printf(" (RECONNECTED)\n"); 413230123Snwhitehorn else 414230123Snwhitehorn if (reply("RECONNECT") == 0) 415230123Snwhitehorn return (0); 416230123Snwhitehorn if (lfdir == 0) { 417230123Snwhitehorn dp = ginode(ROOTINO); 418230123Snwhitehorn idesc.id_name = lfname; 419230123Snwhitehorn idesc.id_type = DATA; 420230123Snwhitehorn idesc.id_func = findino; 421230123Snwhitehorn idesc.id_number = ROOTINO; 422230123Snwhitehorn if ((ckinode(dp, &idesc) & FOUND) != 0) { 423230123Snwhitehorn lfdir = idesc.id_parent; 424230123Snwhitehorn } else { 425230123Snwhitehorn pwarn("NO lost+found DIRECTORY"); 426230123Snwhitehorn if (preen || reply("CREATE")) { 427230123Snwhitehorn lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 428230123Snwhitehorn if (lfdir != 0) { 429230123Snwhitehorn if (makeentry(ROOTINO, lfdir, lfname) != 0) { 430230123Snwhitehorn if (preen) 431230123Snwhitehorn printf(" (CREATED)\n"); 432230123Snwhitehorn } else { 433230123Snwhitehorn freedir(lfdir, ROOTINO); 434230123Snwhitehorn lfdir = 0; 435230123Snwhitehorn if (preen) 436230123Snwhitehorn printf("\n"); 437230123Snwhitehorn } 438230123Snwhitehorn } 439230123Snwhitehorn } 440230123Snwhitehorn } 441230123Snwhitehorn if (lfdir == 0) { 442230123Snwhitehorn pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 443230123Snwhitehorn printf("\n\n"); 444230123Snwhitehorn return (0); 445230123Snwhitehorn } 446230123Snwhitehorn } 447230123Snwhitehorn dp = ginode(lfdir); 448230123Snwhitehorn if ((dp->di_mode & IFMT) != IFDIR) { 449230123Snwhitehorn pfatal("lost+found IS NOT A DIRECTORY"); 450230123Snwhitehorn if (reply("REALLOCATE") == 0) 451230123Snwhitehorn return (0); 452230123Snwhitehorn oldlfdir = lfdir; 453230123Snwhitehorn if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 454230123Snwhitehorn pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 455230123Snwhitehorn return (0); 456230123Snwhitehorn } 457230123Snwhitehorn if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 458230123Snwhitehorn pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 459230123Snwhitehorn return (0); 460230123Snwhitehorn } 461230123Snwhitehorn inodirty(); 462230123Snwhitehorn idesc.id_type = ADDR; 463230123Snwhitehorn idesc.id_func = pass4check; 464230123Snwhitehorn idesc.id_number = oldlfdir; 465230123Snwhitehorn adjust(&idesc, lncntp[oldlfdir] + 1); 466230123Snwhitehorn lncntp[oldlfdir] = 0; 467230123Snwhitehorn dp = ginode(lfdir); 468230123Snwhitehorn } 469230123Snwhitehorn if (statemap[lfdir] != DFOUND) { 470230123Snwhitehorn pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 471230123Snwhitehorn return (0); 472230123Snwhitehorn } 473230123Snwhitehorn (void)lftempname(tempname, orphan); 474277334Snwhitehorn if (makeentry(lfdir, orphan, tempname) == 0) { 475230123Snwhitehorn pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 476230123Snwhitehorn printf("\n\n"); 477230123Snwhitehorn return (0); 478230123Snwhitehorn } 479230123Snwhitehorn lncntp[orphan]--; 480230123Snwhitehorn if (lostdir) { 481230123Snwhitehorn if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 482230123Snwhitehorn parentdir != (ino_t)-1) 483230123Snwhitehorn (void)makeentry(orphan, lfdir, ".."); 484230123Snwhitehorn dp = ginode(lfdir); 485230123Snwhitehorn dp->di_nlink++; 486230123Snwhitehorn inodirty(); 487230123Snwhitehorn lncntp[lfdir]++; 488230123Snwhitehorn pwarn("DIR I=%lu CONNECTED. ", orphan); 489230123Snwhitehorn if (parentdir != (ino_t)-1) { 490230123Snwhitehorn printf("PARENT WAS I=%lu\n", parentdir); 491230123Snwhitehorn /* 492230123Snwhitehorn * The parent directory, because of the ordering 493230123Snwhitehorn * guarantees, has had the link count incremented 494230123Snwhitehorn * for the child, but no entry was made. This 495230123Snwhitehorn * fixes the parent link count so that fsck does 496230123Snwhitehorn * not need to be rerun. 497230123Snwhitehorn */ 498230123Snwhitehorn lncntp[parentdir]++; 499230123Snwhitehorn 500230123Snwhitehorn } 501230123Snwhitehorn if (preen == 0) 502230123Snwhitehorn printf("\n"); 503230123Snwhitehorn } 504230123Snwhitehorn return (1); 505230123Snwhitehorn} 506230123Snwhitehorn 507230123Snwhitehorn/* 508230123Snwhitehorn * fix an entry in a directory. 509230123Snwhitehorn */ 510230123Snwhitehornint 511230123Snwhitehornchangeino(dir, name, newnum) 512230123Snwhitehorn ino_t dir; 513230123Snwhitehorn char *name; 514230123Snwhitehorn ino_t newnum; 515230123Snwhitehorn{ 516230123Snwhitehorn struct inodesc idesc; 517230123Snwhitehorn 518230123Snwhitehorn memset(&idesc, 0, sizeof(struct inodesc)); 519230123Snwhitehorn idesc.id_type = DATA; 520230123Snwhitehorn idesc.id_func = chgino; 521230123Snwhitehorn idesc.id_number = dir; 522230123Snwhitehorn idesc.id_fix = DONTKNOW; 523230123Snwhitehorn idesc.id_name = name; 524230123Snwhitehorn idesc.id_parent = newnum; /* new value for name */ 525230123Snwhitehorn return (ckinode(ginode(dir), &idesc)); 526230123Snwhitehorn} 527230123Snwhitehorn 52895719Sbenno/* 52995719Sbenno * make an entry in a directory 530277561Snwhitehorn */ 53196773Sbennoint 532125441Sgrehanmakeentry(parent, ino, name) 533125441Sgrehan ino_t parent, ino; 534209975Snwhitehorn char *name; 535209975Snwhitehorn{ 536209975Snwhitehorn struct dinode *dp; 537209975Snwhitehorn struct inodesc idesc; 538209975Snwhitehorn char pathbuf[MAXPATHLEN + 1]; 539125441Sgrehan 540125441Sgrehan if (parent < ROOTINO || parent >= maxino || 541209975Snwhitehorn ino < ROOTINO || ino >= maxino) 542209975Snwhitehorn return (0); 543125441Sgrehan memset(&idesc, 0, sizeof(struct inodesc)); 544125441Sgrehan idesc.id_type = DATA; 545125441Sgrehan idesc.id_func = mkentry; 546188860Snwhitehorn idesc.id_number = parent; 547277498Snwhitehorn idesc.id_parent = ino; /* this is the inode to enter */ 548277498Snwhitehorn idesc.id_fix = DONTKNOW; 549277498Snwhitehorn idesc.id_name = name; 550277498Snwhitehorn dp = ginode(parent); 551277498Snwhitehorn if (dp->di_size % DIRBLKSIZ) { 552277498Snwhitehorn dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 553277498Snwhitehorn inodirty(); 554277498Snwhitehorn } 555277498Snwhitehorn if ((ckinode(dp, &idesc) & ALTERED) != 0) 556277498Snwhitehorn return (1); 557188951Snwhitehorn getpathname(pathbuf, parent, parent); 558188860Snwhitehorn dp = ginode(parent); 559188860Snwhitehorn if (expanddir(dp, pathbuf) == 0) 560188860Snwhitehorn return (0); 561188860Snwhitehorn return (ckinode(dp, &idesc) & ALTERED); 562125441Sgrehan} 563125441Sgrehan 564277498Snwhitehorn/* 565277561Snwhitehorn * Attempt to expand the size of a directory 56695719Sbenno */ 56795719Sbennostatic int 56895719Sbennoexpanddir(dp, name) 569277498Snwhitehorn register struct dinode *dp; 57095719Sbenno char *name; 571277561Snwhitehorn{ 57296773Sbenno ufs_daddr_t lastbn, newblk; 573125441Sgrehan register struct bufarea *bp; 574125441Sgrehan char *cp, firstblk[DIRBLKSIZ]; 575209975Snwhitehorn 576209975Snwhitehorn lastbn = lblkno(&sblock, dp->di_size); 577209975Snwhitehorn if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 578209975Snwhitehorn return (0); 579209975Snwhitehorn if ((newblk = allocblk(sblock.fs_frag)) == 0) 580125441Sgrehan return (0); 581125441Sgrehan dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 582125441Sgrehan dp->di_db[lastbn] = newblk; 583125441Sgrehan dp->di_size += sblock.fs_bsize; 584125441Sgrehan dp->di_blocks += btodb(sblock.fs_bsize); 585125441Sgrehan bp = getdirblk(dp->di_db[lastbn + 1], 586277498Snwhitehorn (long)dblksize(&sblock, dp, lastbn + 1)); 587277498Snwhitehorn if (bp->b_errs) 588277498Snwhitehorn goto bad; 589277498Snwhitehorn memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 590277498Snwhitehorn bp = getdirblk(newblk, sblock.fs_bsize); 591277498Snwhitehorn if (bp->b_errs) 592277561Snwhitehorn goto bad; 59395719Sbenno memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 59495719Sbenno for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 59595719Sbenno cp < &bp->b_un.b_buf[sblock.fs_bsize]; 59695719Sbenno cp += DIRBLKSIZ) 59795719Sbenno memmove(cp, &emptydir, sizeof emptydir); 598188951Snwhitehorn dirty(bp); 599188860Snwhitehorn bp = getdirblk(dp->di_db[lastbn + 1], 600188860Snwhitehorn (long)dblksize(&sblock, dp, lastbn + 1)); 601188860Snwhitehorn if (bp->b_errs) 602188860Snwhitehorn goto bad; 603125441Sgrehan memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 604209975Snwhitehorn pwarn("NO SPACE LEFT IN %s", name); 605209975Snwhitehorn if (preen) 606209975Snwhitehorn printf(" (EXPANDED)\n"); 607209975Snwhitehorn else if (reply("EXPAND") == 0) 608209975Snwhitehorn goto bad; 609209975Snwhitehorn dirty(bp); 610209975Snwhitehorn inodirty(); 611209975Snwhitehorn return (1); 612209975Snwhitehornbad: 613209975Snwhitehorn dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 614125441Sgrehan dp->di_db[lastbn + 1] = 0; 615125441Sgrehan dp->di_size -= sblock.fs_bsize; 616209975Snwhitehorn dp->di_blocks -= btodb(sblock.fs_bsize); 617209975Snwhitehorn freeblk(newblk, sblock.fs_frag); 618125441Sgrehan return (0); 619132571Sgrehan} 620258800Snwhitehorn 621132571Sgrehan/* 622132571Sgrehan * allocate a new directory 623132571Sgrehan */ 624132571Sgrehanino_t 625266136Sjhibbitsallocdir(parent, request, mode) 626132571Sgrehan ino_t parent, request; 627132571Sgrehan int mode; 628132571Sgrehan{ 629209975Snwhitehorn ino_t ino; 630132571Sgrehan char *cp; 631132571Sgrehan struct dinode *dp; 632132571Sgrehan register struct bufarea *bp; 633132571Sgrehan struct dirtemplate *dirp; 634209975Snwhitehorn 635209975Snwhitehorn ino = allocino(request, IFDIR|mode); 636209975Snwhitehorn if (newinofmt) 637209975Snwhitehorn dirp = &dirhead; 638209975Snwhitehorn else 639209975Snwhitehorn dirp = (struct dirtemplate *)&odirhead; 640209975Snwhitehorn dirp->dot_ino = ino; 641209975Snwhitehorn dirp->dotdot_ino = parent; 642209975Snwhitehorn dp = ginode(ino); 643209975Snwhitehorn bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 644209975Snwhitehorn if (bp->b_errs) { 645209975Snwhitehorn freeino(ino); 646209975Snwhitehorn return (0); 647209975Snwhitehorn } 648191039Snwhitehorn memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 649132571Sgrehan for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 650132571Sgrehan cp < &bp->b_un.b_buf[sblock.fs_fsize]; 651125441Sgrehan cp += DIRBLKSIZ) 65295719Sbenno memmove(cp, &emptydir, sizeof emptydir); 65395719Sbenno dirty(bp); 654125441Sgrehan dp->di_nlink = 2; 655125441Sgrehan inodirty(); 656125441Sgrehan if (ino == ROOTINO) { 65795719Sbenno lncntp[ino] = dp->di_nlink; 658188860Snwhitehorn cacheino(dp, ino); 659188860Snwhitehorn return(ino); 660209975Snwhitehorn } 661209975Snwhitehorn if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 662209975Snwhitehorn freeino(ino); 663212722Snwhitehorn return (0); 664209975Snwhitehorn } 665209975Snwhitehorn cacheino(dp, ino); 666277498Snwhitehorn statemap[ino] = statemap[parent]; 667188860Snwhitehorn if (statemap[ino] == DSTATE) { 668188860Snwhitehorn lncntp[ino] = dp->di_nlink; 669188860Snwhitehorn lncntp[parent]++; 670188860Snwhitehorn } 671188860Snwhitehorn dp = ginode(parent); 672188860Snwhitehorn dp->di_nlink++; 673188860Snwhitehorn inodirty(); 674188860Snwhitehorn return (ino); 675188860Snwhitehorn} 676188860Snwhitehorn 677188860Snwhitehorn/* 678279750Snwhitehorn * free a directory inode 679188860Snwhitehorn */ 680188860Snwhitehornstatic void 681188860Snwhitehornfreedir(ino, parent) 682188860Snwhitehorn ino_t ino, parent; 683188860Snwhitehorn{ 684188860Snwhitehorn struct dinode *dp; 685209975Snwhitehorn 686209975Snwhitehorn if (ino != parent) { 687209975Snwhitehorn dp = ginode(parent); 688209975Snwhitehorn dp->di_nlink--; 689209975Snwhitehorn inodirty(); 690209975Snwhitehorn } 691209975Snwhitehorn freeino(ino); 692188860Snwhitehorn} 693188860Snwhitehorn 694188860Snwhitehorn/* 695188860Snwhitehorn * generate a temporary name for the lost+found directory. 696188860Snwhitehorn */ 697188860Snwhitehornstatic int 698188860Snwhitehornlftempname(bufp, ino) 699188860Snwhitehorn char *bufp; 700277498Snwhitehorn ino_t ino; 701188860Snwhitehorn{ 702188860Snwhitehorn register ino_t in; 703188860Snwhitehorn register char *cp; 704188860Snwhitehorn int namlen; 705188860Snwhitehorn 706188860Snwhitehorn cp = bufp + 2; 707188860Snwhitehorn for (in = maxino; in > 0; in /= 10) 708125441Sgrehan cp++; 709125441Sgrehan *--cp = 0; 710125441Sgrehan namlen = cp - bufp; 711125441Sgrehan in = ino; 712209975Snwhitehorn while (cp > bufp) { 713209975Snwhitehorn *--cp = (in % 10) + '0'; 714209975Snwhitehorn in /= 10; 715212722Snwhitehorn } 716209975Snwhitehorn *cp = '#'; 717209975Snwhitehorn return (namlen); 71895719Sbenno} 71995719Sbenno 72095719Sbenno/* 72195719Sbenno * Get a directory block. 722125441Sgrehan * Insure that it is held until another is requested. 723125441Sgrehan */ 72499032Sbennostatic struct bufarea * 72595719Sbennogetdirblk(blkno, size) 726277334Snwhitehorn ufs_daddr_t blkno; 727209975Snwhitehorn long size; 728218824Snwhitehorn{ 729209975Snwhitehorn 730209975Snwhitehorn if (pdirbp != 0) 731209975Snwhitehorn pdirbp->b_flags &= ~B_INUSE; 73296773Sbenno pdirbp = getdatablk(blkno, size); 73395719Sbenno return (pdirbp); 734125441Sgrehan} 735125441Sgrehan