dir.c revision 7586
1130812Smarcel/* 2130812Smarcel * Copyright (c) 1980, 1986, 1993 3130812Smarcel * The Regents of the University of California. All rights reserved. 4130812Smarcel * 5130812Smarcel * Redistribution and use in source and binary forms, with or without 6130812Smarcel * modification, are permitted provided that the following conditions 7130812Smarcel * are met: 8130812Smarcel * 1. Redistributions of source code must retain the above copyright 9130812Smarcel * notice, this list of conditions and the following disclaimer. 10130812Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11130812Smarcel * notice, this list of conditions and the following disclaimer in the 12130812Smarcel * documentation and/or other materials provided with the distribution. 13130812Smarcel * 3. All advertising materials mentioning features or use of this software 14130812Smarcel * must display the following acknowledgement: 15130812Smarcel * This product includes software developed by the University of 16130812Smarcel * California, Berkeley and its contributors. 17130812Smarcel * 4. Neither the name of the University nor the names of its contributors 18130812Smarcel * may be used to endorse or promote products derived from this software 19130812Smarcel * without specific prior written permission. 20130812Smarcel * 21130812Smarcel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22130812Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23130812Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24130812Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25130812Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26130812Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27130812Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28130812Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29130812Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30130812Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31130812Smarcel * SUCH DAMAGE. 32130812Smarcel */ 33130812Smarcel 34130812Smarcel#ifndef lint 35130812Smarcelstatic const char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 6/5/93"; 36130812Smarcel#endif /* not lint */ 37130812Smarcel 38130812Smarcel#include <sys/param.h> 39130812Smarcel#include <sys/time.h> 40130812Smarcel#include <ufs/ufs/dinode.h> 41130812Smarcel#include <ufs/ufs/dir.h> 42130812Smarcel#include <ufs/ffs/fs.h> 43130812Smarcel#include <stdio.h> 44130812Smarcel#include <stdlib.h> 45130812Smarcel#include <string.h> 46130812Smarcel#include "fsck.h" 47130812Smarcel 48130812Smarcelchar *lfname = "lost+found"; 49130812Smarcelint lfmode = 01777; 50130812Smarcelstruct dirtemplate emptydir = { 0, DIRBLKSIZ }; 51130812Smarcelstruct dirtemplate dirhead = { 52130812Smarcel 0, 12, DT_DIR, 1, ".", 53130812Smarcel 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 54130812Smarcel}; 55130812Smarcelstruct odirtemplate odirhead = { 56130812Smarcel 0, 12, 1, ".", 57130812Smarcel 0, DIRBLKSIZ - 12, 2, ".." 58130812Smarcel}; 59130812Smarcel 60130812Smarcel 61130812Smarcelstatic int chgino __P((struct inodesc *idesc)); 62130812Smarcelstatic int dircheck __P((struct inodesc *idesc, struct direct *dp)); 63130812Smarcelstatic int expanddir __P((struct dinode *dp, char *name)); 64130812Smarcelstatic void freedir __P((ino_t ino, ino_t parent)); 65130812Smarcelstatic struct direct * fsck_readdir __P((struct inodesc *idesc)); 66130812Smarcelstatic struct bufarea * getdirblk __P((daddr_t blkno, long size)); 67130812Smarcelstatic int lftempname __P((char *bufp, ino_t ino)); 68130812Smarcelstatic int mkentry __P((struct inodesc *idesc)); 69130812Smarcel 70130812Smarcel/* 71130812Smarcel * Propagate connected state through the tree. 72130812Smarcel */ 73130812Smarcelvoid 74130812Smarcelpropagate() 75130812Smarcel{ 76130812Smarcel register struct inoinfo **inpp, *inp; 77130812Smarcel struct inoinfo **inpend; 78130812Smarcel long change; 79130812Smarcel 80130812Smarcel inpend = &inpsort[inplast]; 81130812Smarcel do { 82130812Smarcel change = 0; 83130812Smarcel for (inpp = inpsort; inpp < inpend; inpp++) { 84130812Smarcel inp = *inpp; 85130812Smarcel if (inp->i_parent == 0) 86130812Smarcel continue; 87130812Smarcel if (statemap[inp->i_parent] == DFOUND && 88130812Smarcel statemap[inp->i_number] == DSTATE) { 89130812Smarcel statemap[inp->i_number] = DFOUND; 90130812Smarcel change++; 91130812Smarcel } 92130812Smarcel } 93130812Smarcel } while (change > 0); 94130812Smarcel} 95130812Smarcel 96130812Smarcel/* 97130812Smarcel * Scan each entry in a directory block. 98130812Smarcel */ 99130812Smarcelint 100130812Smarceldirscan(idesc) 101130812Smarcel register struct inodesc *idesc; 102130812Smarcel{ 103130812Smarcel register struct direct *dp; 104130812Smarcel register struct bufarea *bp; 105130812Smarcel int dsize, n; 106130812Smarcel long blksiz; 107130812Smarcel char dbuf[DIRBLKSIZ]; 108130812Smarcel 109130812Smarcel if (idesc->id_type != DATA) 110130812Smarcel errexit("wrong type to dirscan %d\n", idesc->id_type); 111130812Smarcel if (idesc->id_entryno == 0 && 112130812Smarcel (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 113130812Smarcel idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 114130812Smarcel blksiz = idesc->id_numfrags * sblock.fs_fsize; 115130812Smarcel if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 116130812Smarcel idesc->id_filesize -= blksiz; 117130812Smarcel return (SKIP); 118130812Smarcel } 119130812Smarcel idesc->id_loc = 0; 120130812Smarcel for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 121130812Smarcel dsize = dp->d_reclen; 122130812Smarcel bcopy((char *)dp, dbuf, (size_t)dsize); 123130812Smarcel# if (BYTE_ORDER == LITTLE_ENDIAN) 124130812Smarcel if (!newinofmt) { 125130812Smarcel struct direct *tdp = (struct direct *)dbuf; 126130812Smarcel u_char tmp; 127130812Smarcel 128130812Smarcel tmp = tdp->d_namlen; 129130812Smarcel tdp->d_namlen = tdp->d_type; 130130812Smarcel tdp->d_type = tmp; 131130812Smarcel } 132130812Smarcel# endif 133130812Smarcel idesc->id_dirp = (struct direct *)dbuf; 134130812Smarcel if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 135130812Smarcel# if (BYTE_ORDER == LITTLE_ENDIAN) 136130812Smarcel if (!newinofmt && !doinglevel2) { 137130812Smarcel struct direct *tdp; 138130812Smarcel u_char tmp; 139130812Smarcel 140130812Smarcel tdp = (struct direct *)dbuf; 141130812Smarcel tmp = tdp->d_namlen; 142130812Smarcel tdp->d_namlen = tdp->d_type; 143130812Smarcel tdp->d_type = tmp; 144130812Smarcel } 145130812Smarcel# endif 146130812Smarcel bp = getdirblk(idesc->id_blkno, blksiz); 147130812Smarcel bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize, 148130812Smarcel (size_t)dsize); 149130812Smarcel dirty(bp); 150130812Smarcel sbdirty(); 151130812Smarcel } 152130812Smarcel if (n & STOP) 153130812Smarcel return (n); 154130812Smarcel } 155130812Smarcel return (idesc->id_filesize > 0 ? KEEPON : STOP); 156130812Smarcel} 157130812Smarcel 158130812Smarcel/* 159130812Smarcel * get next entry in a directory. 160130812Smarcel */ 161130812Smarcelstruct direct * 162130812Smarcelfsck_readdir(idesc) 163130812Smarcel register struct inodesc *idesc; 164130812Smarcel{ 165130812Smarcel register struct direct *dp, *ndp; 166130812Smarcel register struct bufarea *bp; 167130812Smarcel long size, blksiz, fix, dploc; 168130812Smarcel 169130812Smarcel blksiz = idesc->id_numfrags * sblock.fs_fsize; 170130812Smarcel bp = getdirblk(idesc->id_blkno, blksiz); 171130812Smarcel if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 172130812Smarcel idesc->id_loc < blksiz) { 173130812Smarcel dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 174130812Smarcel if (dircheck(idesc, dp)) 175130812Smarcel goto dpok; 176130812Smarcel fix = dofix(idesc, "DIRECTORY CORRUPTED"); 177130812Smarcel bp = getdirblk(idesc->id_blkno, blksiz); 178130812Smarcel dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 179130812Smarcel dp->d_reclen = DIRBLKSIZ; 180130812Smarcel dp->d_ino = 0; 181130812Smarcel dp->d_type = 0; 182130812Smarcel dp->d_namlen = 0; 183130812Smarcel dp->d_name[0] = '\0'; 184130812Smarcel if (fix) 185130812Smarcel dirty(bp); 186130812Smarcel idesc->id_loc += DIRBLKSIZ; 187130812Smarcel idesc->id_filesize -= DIRBLKSIZ; 188130812Smarcel return (dp); 189130812Smarcel } 190130812Smarceldpok: 191130812Smarcel if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 192130812Smarcel return NULL; 193130812Smarcel dploc = idesc->id_loc; 194130812Smarcel dp = (struct direct *)(bp->b_un.b_buf + dploc); 195130812Smarcel idesc->id_loc += dp->d_reclen; 196130812Smarcel idesc->id_filesize -= dp->d_reclen; 197130812Smarcel if ((idesc->id_loc % DIRBLKSIZ) == 0) 198130812Smarcel return (dp); 199130812Smarcel ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 200130812Smarcel if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 201130812Smarcel dircheck(idesc, ndp) == 0) { 202130812Smarcel size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 203130812Smarcel idesc->id_loc += size; 204130812Smarcel idesc->id_filesize -= size; 205130812Smarcel fix = dofix(idesc, "DIRECTORY CORRUPTED"); 206130812Smarcel bp = getdirblk(idesc->id_blkno, blksiz); 207130812Smarcel dp = (struct direct *)(bp->b_un.b_buf + dploc); 208130812Smarcel dp->d_reclen += size; 209130812Smarcel if (fix) 210130812Smarcel dirty(bp); 211130812Smarcel } 212130812Smarcel return (dp); 213130812Smarcel} 214130812Smarcel 215130812Smarcel/* 216130812Smarcel * Verify that a directory entry is valid. 217130812Smarcel * This is a superset of the checks made in the kernel. 218130812Smarcel */ 219130812Smarcelint 220130812Smarceldircheck(idesc, dp) 221130812Smarcel struct inodesc *idesc; 222130812Smarcel register struct direct *dp; 223130812Smarcel{ 224130812Smarcel register int size; 225130812Smarcel register char *cp; 226130812Smarcel u_char namlen, type; 227130812Smarcel int spaceleft; 228130812Smarcel 229130812Smarcel size = DIRSIZ(!newinofmt, dp); 230130812Smarcel spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 231130812Smarcel# if (BYTE_ORDER == LITTLE_ENDIAN) 232130812Smarcel if (!newinofmt) { 233130812Smarcel type = dp->d_namlen; 234130812Smarcel namlen = dp->d_type; 235130812Smarcel } else { 236130812Smarcel namlen = dp->d_namlen; 237130812Smarcel type = dp->d_type; 238130812Smarcel } 239130812Smarcel# else 240130812Smarcel namlen = dp->d_namlen; 241130812Smarcel type = dp->d_type; 242130812Smarcel# endif 243130812Smarcel if (dp->d_ino < maxino && 244130812Smarcel dp->d_reclen != 0 && 245130812Smarcel dp->d_reclen <= spaceleft && 246130812Smarcel (dp->d_reclen & 0x3) == 0 && 247130812Smarcel dp->d_reclen >= size && 248130812Smarcel idesc->id_filesize >= size && 249130812Smarcel namlen <= MAXNAMLEN && 250130812Smarcel type <= 15) { 251130812Smarcel if (dp->d_ino == 0) 252130812Smarcel return (1); 253130812Smarcel for (cp = dp->d_name, size = 0; size < namlen; size++) 254130812Smarcel if (*cp == 0 || (*cp++ == '/')) 255130812Smarcel return (0); 256130812Smarcel if (*cp == 0) 257130812Smarcel return (1); 258130812Smarcel } 259130812Smarcel return (0); 260130812Smarcel} 261130812Smarcel 262130812Smarcelvoid 263130812Smarceldirerror(ino, errmesg) 264130812Smarcel ino_t ino; 265130812Smarcel char *errmesg; 266130812Smarcel{ 267130812Smarcel 268130812Smarcel fileerror(ino, ino, errmesg); 269130812Smarcel} 270130812Smarcel 271130812Smarcelvoid 272130812Smarcelfileerror(cwd, ino, errmesg) 273130812Smarcel ino_t cwd, ino; 274130812Smarcel char *errmesg; 275130812Smarcel{ 276130812Smarcel register struct dinode *dp; 277130812Smarcel char pathbuf[MAXPATHLEN + 1]; 278130812Smarcel 279130812Smarcel pwarn("%s ", errmesg); 280130812Smarcel pinode(ino); 281130812Smarcel printf("\n"); 282130812Smarcel getpathname(pathbuf, cwd, ino); 283130812Smarcel if (ino < ROOTINO || ino > maxino) { 284130812Smarcel pfatal("NAME=%s\n", pathbuf); 285130812Smarcel return; 286130812Smarcel } 287130812Smarcel dp = ginode(ino); 288130812Smarcel if (ftypeok(dp)) 289130812Smarcel pfatal("%s=%s\n", 290130812Smarcel (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 291130812Smarcel else 292130812Smarcel pfatal("NAME=%s\n", pathbuf); 293130812Smarcel} 294130812Smarcel 295130812Smarcelvoid 296130812Smarceladjust(idesc, lcnt) 297130812Smarcel register struct inodesc *idesc; 298130812Smarcel short lcnt; 299130812Smarcel{ 300130812Smarcel register struct dinode *dp; 301130812Smarcel 302130812Smarcel dp = ginode(idesc->id_number); 303130812Smarcel if (dp->di_nlink == lcnt) { 304130812Smarcel if (linkup(idesc->id_number, (ino_t)0) == 0) 305130812Smarcel clri(idesc, "UNREF", 0); 306130812Smarcel } else { 307130812Smarcel pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 308130812Smarcel ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 309130812Smarcel pinode(idesc->id_number); 310130812Smarcel printf(" COUNT %d SHOULD BE %d", 311130812Smarcel dp->di_nlink, dp->di_nlink - lcnt); 312130812Smarcel if (preen) { 313130812Smarcel if (lcnt < 0) { 314130812Smarcel printf("\n"); 315130812Smarcel pfatal("LINK COUNT INCREASING"); 316130812Smarcel } 317130812Smarcel printf(" (ADJUSTED)\n"); 318130812Smarcel } 319130812Smarcel if (preen || reply("ADJUST") == 1) { 320130812Smarcel dp->di_nlink -= lcnt; 321130812Smarcel inodirty(); 322130812Smarcel } 323130812Smarcel } 324130812Smarcel} 325130812Smarcel 326130812Smarcelint 327130812Smarcelmkentry(idesc) 328130812Smarcel struct inodesc *idesc; 329130812Smarcel{ 330130812Smarcel register struct direct *dirp = idesc->id_dirp; 331130812Smarcel struct direct newent; 332130812Smarcel int newlen, oldlen; 333130812Smarcel 334130812Smarcel newent.d_namlen = strlen(idesc->id_name); 335130812Smarcel newlen = DIRSIZ(0, &newent); 336130812Smarcel if (dirp->d_ino != 0) 337130812Smarcel oldlen = DIRSIZ(0, dirp); 338130812Smarcel else 339130812Smarcel oldlen = 0; 340130812Smarcel if (dirp->d_reclen - oldlen < newlen) 341130812Smarcel return (KEEPON); 342130812Smarcel newent.d_reclen = dirp->d_reclen - oldlen; 343130812Smarcel dirp->d_reclen = oldlen; 344130812Smarcel dirp = (struct direct *)(((char *)dirp) + oldlen); 345130812Smarcel dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 346130812Smarcel if (newinofmt) { 347130812Smarcel dirp->d_type = typemap[idesc->id_parent]; 348130812Smarcel dirp->d_namlen = newent.d_namlen; 349130812Smarcel } else { 350130812Smarcel# if (BYTE_ORDER == LITTLE_ENDIAN) 351130812Smarcel dirp->d_type = newent.d_namlen; 352130812Smarcel dirp->d_namlen = 0; 353130812Smarcel# else 354130812Smarcel dirp->d_type = 0; 355130812Smarcel dirp->d_namlen = newent.d_namlen; 356130812Smarcel# endif 357130812Smarcel } 358130812Smarcel dirp->d_reclen = newent.d_reclen; 359130812Smarcel bcopy(idesc->id_name, dirp->d_name, (size_t)newent.d_namlen + 1); 360130812Smarcel return (ALTERED|STOP); 361130812Smarcel} 362130812Smarcel 363130812Smarcelint 364130812Smarcelchgino(idesc) 365130812Smarcel struct inodesc *idesc; 366130812Smarcel{ 367130812Smarcel register struct direct *dirp = idesc->id_dirp; 368130812Smarcel 369130812Smarcel if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 370130812Smarcel return (KEEPON); 371130812Smarcel dirp->d_ino = idesc->id_parent; 372130812Smarcel if (newinofmt) 373130812Smarcel dirp->d_type = typemap[idesc->id_parent]; 374130812Smarcel else 375130812Smarcel dirp->d_type = 0; 376130812Smarcel return (ALTERED|STOP); 377130812Smarcel} 378130812Smarcel 379130812Smarcelint 380130812Smarcellinkup(orphan, parentdir) 381130812Smarcel ino_t orphan; 382130812Smarcel ino_t parentdir; 383130812Smarcel{ 384130812Smarcel register struct dinode *dp; 385130812Smarcel int lostdir; 386130812Smarcel ino_t oldlfdir; 387130812Smarcel struct inodesc idesc; 388130812Smarcel char tempname[BUFSIZ]; 389130812Smarcel 390130812Smarcel bzero((char *)&idesc, sizeof(struct inodesc)); 391130812Smarcel dp = ginode(orphan); 392130812Smarcel lostdir = (dp->di_mode & IFMT) == IFDIR; 393130812Smarcel pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 394130812Smarcel pinode(orphan); 395130812Smarcel if (preen && dp->di_size == 0) 396130812Smarcel return (0); 397130812Smarcel if (preen) 398130812Smarcel printf(" (RECONNECTED)\n"); 399130812Smarcel else 400130812Smarcel if (reply("RECONNECT") == 0) 401130812Smarcel return (0); 402130812Smarcel if (lfdir == 0) { 403130812Smarcel dp = ginode(ROOTINO); 404130812Smarcel idesc.id_name = lfname; 405130812Smarcel idesc.id_type = DATA; 406130812Smarcel idesc.id_func = findino; 407130812Smarcel idesc.id_number = ROOTINO; 408130812Smarcel if ((ckinode(dp, &idesc) & FOUND) != 0) { 409130812Smarcel lfdir = idesc.id_parent; 410130812Smarcel } else { 411130812Smarcel pwarn("NO lost+found DIRECTORY"); 412130812Smarcel if (preen || reply("CREATE")) { 413130812Smarcel lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 414130812Smarcel if (lfdir != 0) { 415130812Smarcel if (makeentry(ROOTINO, lfdir, lfname) != 0) { 416130812Smarcel if (preen) 417130812Smarcel printf(" (CREATED)\n"); 418130812Smarcel } else { 419130812Smarcel freedir(lfdir, ROOTINO); 420130812Smarcel lfdir = 0; 421130812Smarcel if (preen) 422130812Smarcel printf("\n"); 423130812Smarcel } 424130812Smarcel } 425130812Smarcel } 426130812Smarcel } 427130812Smarcel if (lfdir == 0) { 428130812Smarcel pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 429130812Smarcel printf("\n\n"); 430130812Smarcel return (0); 431130812Smarcel } 432130812Smarcel } 433130812Smarcel dp = ginode(lfdir); 434130812Smarcel if ((dp->di_mode & IFMT) != IFDIR) { 435130812Smarcel pfatal("lost+found IS NOT A DIRECTORY"); 436130812Smarcel if (reply("REALLOCATE") == 0) 437130812Smarcel return (0); 438130812Smarcel oldlfdir = lfdir; 439130812Smarcel if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 440130812Smarcel pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 441130812Smarcel return (0); 442130812Smarcel } 443130812Smarcel if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 444130812Smarcel pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 445130812Smarcel return (0); 446130812Smarcel } 447130812Smarcel inodirty(); 448130812Smarcel idesc.id_type = ADDR; 449130812Smarcel idesc.id_func = pass4check; 450130812Smarcel idesc.id_number = oldlfdir; 451130812Smarcel adjust(&idesc, lncntp[oldlfdir] + 1); 452130812Smarcel lncntp[oldlfdir] = 0; 453130812Smarcel dp = ginode(lfdir); 454130812Smarcel } 455130812Smarcel if (statemap[lfdir] != DFOUND) { 456130812Smarcel pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 457130812Smarcel return (0); 458130812Smarcel } 459130812Smarcel (void)lftempname(tempname, orphan); 460130812Smarcel if (makeentry(lfdir, orphan, tempname) == 0) { 461130812Smarcel pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 462130812Smarcel printf("\n\n"); 463130812Smarcel return (0); 464130812Smarcel } 465130812Smarcel lncntp[orphan]--; 466130812Smarcel if (lostdir) { 467130812Smarcel if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 468130812Smarcel parentdir != (ino_t)-1) 469130812Smarcel (void)makeentry(orphan, lfdir, ".."); 470130812Smarcel dp = ginode(lfdir); 471130812Smarcel dp->di_nlink++; 472130812Smarcel inodirty(); 473130812Smarcel lncntp[lfdir]++; 474130812Smarcel pwarn("DIR I=%lu CONNECTED. ", orphan); 475130812Smarcel if (parentdir != (ino_t)-1) 476130812Smarcel printf("PARENT WAS I=%lu\n", parentdir); 477130812Smarcel if (preen == 0) 478130812Smarcel printf("\n"); 479130812Smarcel } 480130812Smarcel return (1); 481130812Smarcel} 482130812Smarcel 483130812Smarcel/* 484130812Smarcel * fix an entry in a directory. 485130812Smarcel */ 486130812Smarcelint 487130812Smarcelchangeino(dir, name, newnum) 488130812Smarcel ino_t dir; 489130812Smarcel char *name; 490130812Smarcel ino_t newnum; 491130812Smarcel{ 492130812Smarcel struct inodesc idesc; 493130812Smarcel 494130812Smarcel bzero((char *)&idesc, sizeof(struct inodesc)); 495130812Smarcel idesc.id_type = DATA; 496130812Smarcel idesc.id_func = chgino; 497130812Smarcel idesc.id_number = dir; 498130812Smarcel idesc.id_fix = DONTKNOW; 499130812Smarcel idesc.id_name = name; 500130812Smarcel idesc.id_parent = newnum; /* new value for name */ 501130812Smarcel return (ckinode(ginode(dir), &idesc)); 502130812Smarcel} 503130812Smarcel 504130812Smarcel/* 505130812Smarcel * make an entry in a directory 506130812Smarcel */ 507130812Smarcelint 508130812Smarcelmakeentry(parent, ino, name) 509130812Smarcel ino_t parent, ino; 510130812Smarcel char *name; 511130812Smarcel{ 512130812Smarcel struct dinode *dp; 513130812Smarcel struct inodesc idesc; 514130812Smarcel char pathbuf[MAXPATHLEN + 1]; 515130812Smarcel 516130812Smarcel if (parent < ROOTINO || parent >= maxino || 517130812Smarcel ino < ROOTINO || ino >= maxino) 518130812Smarcel return (0); 519130812Smarcel bzero((char *)&idesc, sizeof(struct inodesc)); 520130812Smarcel idesc.id_type = DATA; 521130812Smarcel idesc.id_func = mkentry; 522130812Smarcel idesc.id_number = parent; 523130812Smarcel idesc.id_parent = ino; /* this is the inode to enter */ 524130812Smarcel idesc.id_fix = DONTKNOW; 525130812Smarcel idesc.id_name = name; 526130812Smarcel dp = ginode(parent); 527130812Smarcel if (dp->di_size % DIRBLKSIZ) { 528130812Smarcel dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 529130812Smarcel inodirty(); 530130812Smarcel } 531130812Smarcel if ((ckinode(dp, &idesc) & ALTERED) != 0) 532130812Smarcel return (1); 533130812Smarcel getpathname(pathbuf, parent, parent); 534130812Smarcel dp = ginode(parent); 535130812Smarcel if (expanddir(dp, pathbuf) == 0) 536130812Smarcel return (0); 537130812Smarcel return (ckinode(dp, &idesc) & ALTERED); 538130812Smarcel} 539130812Smarcel 540130812Smarcel/* 541130812Smarcel * Attempt to expand the size of a directory 542130812Smarcel */ 543130812Smarcelint 544130812Smarcelexpanddir(dp, name) 545130812Smarcel register struct dinode *dp; 546130812Smarcel char *name; 547130812Smarcel{ 548130812Smarcel daddr_t lastbn, newblk; 549130812Smarcel register struct bufarea *bp; 550130812Smarcel char *cp, firstblk[DIRBLKSIZ]; 551130812Smarcel 552130812Smarcel lastbn = lblkno(&sblock, dp->di_size); 553130812Smarcel if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 554130812Smarcel return (0); 555130812Smarcel if ((newblk = allocblk(sblock.fs_frag)) == 0) 556130812Smarcel return (0); 557130812Smarcel dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 558130812Smarcel dp->di_db[lastbn] = newblk; 559130812Smarcel dp->di_size += sblock.fs_bsize; 560130812Smarcel dp->di_blocks += btodb(sblock.fs_bsize); 561130812Smarcel bp = getdirblk(dp->di_db[lastbn + 1], 562130812Smarcel (long)dblksize(&sblock, dp, lastbn + 1)); 563130812Smarcel if (bp->b_errs) 564130812Smarcel goto bad; 565130812Smarcel bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 566130812Smarcel bp = getdirblk(newblk, sblock.fs_bsize); 567130812Smarcel if (bp->b_errs) 568130812Smarcel goto bad; 569130812Smarcel bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 570130812Smarcel for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 571130812Smarcel cp < &bp->b_un.b_buf[sblock.fs_bsize]; 572130812Smarcel cp += DIRBLKSIZ) 573130812Smarcel bcopy((char *)&emptydir, cp, sizeof emptydir); 574130812Smarcel dirty(bp); 575130812Smarcel bp = getdirblk(dp->di_db[lastbn + 1], 576130812Smarcel (long)dblksize(&sblock, dp, lastbn + 1)); 577130812Smarcel if (bp->b_errs) 578130812Smarcel goto bad; 579130812Smarcel bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 580130812Smarcel pwarn("NO SPACE LEFT IN %s", name); 581130812Smarcel if (preen) 582130812Smarcel printf(" (EXPANDED)\n"); 583130812Smarcel else if (reply("EXPAND") == 0) 584130812Smarcel goto bad; 585130812Smarcel dirty(bp); 586130812Smarcel inodirty(); 587130812Smarcel return (1); 588130812Smarcelbad: 589130812Smarcel dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 590130812Smarcel dp->di_db[lastbn + 1] = 0; 591130812Smarcel dp->di_size -= sblock.fs_bsize; 592130812Smarcel dp->di_blocks -= btodb(sblock.fs_bsize); 593130812Smarcel freeblk(newblk, sblock.fs_frag); 594130812Smarcel return (0); 595130812Smarcel} 596130812Smarcel 597130812Smarcel/* 598130812Smarcel * allocate a new directory 599130812Smarcel */ 600130812Smarcelino_t 601130812Smarcelallocdir(parent, request, mode) 602130812Smarcel ino_t parent, request; 603130812Smarcel int mode; 604130812Smarcel{ 605130812Smarcel ino_t ino; 606130812Smarcel char *cp; 607130812Smarcel struct dinode *dp; 608130812Smarcel register struct bufarea *bp; 609130812Smarcel struct dirtemplate *dirp; 610130812Smarcel 611130812Smarcel ino = allocino(request, IFDIR|mode); 612130812Smarcel if (newinofmt) 613130812Smarcel dirp = &dirhead; 614130812Smarcel else 615130812Smarcel dirp = (struct dirtemplate *)&odirhead; 616130812Smarcel dirp->dot_ino = ino; 617130812Smarcel dirp->dotdot_ino = parent; 618130812Smarcel dp = ginode(ino); 619130812Smarcel bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 620130812Smarcel if (bp->b_errs) { 621130812Smarcel freeino(ino); 622130812Smarcel return (0); 623130812Smarcel } 624130812Smarcel bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate)); 625130812Smarcel for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 626130812Smarcel cp < &bp->b_un.b_buf[sblock.fs_fsize]; 627130812Smarcel cp += DIRBLKSIZ) 628130812Smarcel bcopy((char *)&emptydir, cp, sizeof emptydir); 629130812Smarcel dirty(bp); 630130812Smarcel dp->di_nlink = 2; 631130812Smarcel inodirty(); 632130812Smarcel if (ino == ROOTINO) { 633130812Smarcel lncntp[ino] = dp->di_nlink; 634130812Smarcel cacheino(dp, ino); 635130812Smarcel return(ino); 636130812Smarcel } 637130812Smarcel if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 638130812Smarcel freeino(ino); 639130812Smarcel return (0); 640130812Smarcel } 641130812Smarcel cacheino(dp, ino); 642130812Smarcel statemap[ino] = statemap[parent]; 643130812Smarcel if (statemap[ino] == DSTATE) { 644130812Smarcel lncntp[ino] = dp->di_nlink; 645130812Smarcel lncntp[parent]++; 646130812Smarcel } 647130812Smarcel dp = ginode(parent); 648130812Smarcel dp->di_nlink++; 649130812Smarcel inodirty(); 650130812Smarcel return (ino); 651130812Smarcel} 652130812Smarcel 653130812Smarcel/* 654130812Smarcel * free a directory inode 655130812Smarcel */ 656130812Smarcelstatic void 657130812Smarcelfreedir(ino, parent) 658130812Smarcel ino_t ino, parent; 659130812Smarcel{ 660130812Smarcel struct dinode *dp; 661130812Smarcel 662130812Smarcel if (ino != parent) { 663130812Smarcel dp = ginode(parent); 664130812Smarcel dp->di_nlink--; 665130812Smarcel inodirty(); 666130812Smarcel } 667130812Smarcel freeino(ino); 668130812Smarcel} 669130812Smarcel 670130812Smarcel/* 671130812Smarcel * generate a temporary name for the lost+found directory. 672130812Smarcel */ 673130812Smarcelint 674130812Smarcellftempname(bufp, ino) 675130812Smarcel char *bufp; 676130812Smarcel ino_t ino; 677130812Smarcel{ 678130812Smarcel register ino_t in; 679130812Smarcel register char *cp; 680130812Smarcel int namlen; 681130812Smarcel 682130812Smarcel cp = bufp + 2; 683130812Smarcel for (in = maxino; in > 0; in /= 10) 684130812Smarcel cp++; 685130812Smarcel *--cp = 0; 686130812Smarcel namlen = cp - bufp; 687130812Smarcel in = ino; 688130812Smarcel while (cp > bufp) { 689130812Smarcel *--cp = (in % 10) + '0'; 690130812Smarcel in /= 10; 691130812Smarcel } 692130812Smarcel *cp = '#'; 693130812Smarcel return (namlen); 694130812Smarcel} 695130812Smarcel 696130812Smarcel/* 697130812Smarcel * Get a directory block. 698130812Smarcel * Insure that it is held until another is requested. 699130812Smarcel */ 700130812Smarcelstruct bufarea * 701130812Smarcelgetdirblk(blkno, size) 702130812Smarcel daddr_t blkno; 703130812Smarcel long size; 704130812Smarcel{ 705130812Smarcel 706130812Smarcel if (pdirbp != 0) 707130812Smarcel pdirbp->b_flags &= ~B_INUSE; 708130812Smarcel pdirbp = getdatablk(blkno, size); 709130812Smarcel return (pdirbp); 710130812Smarcel} 711130812Smarcel