1 /* 2 * Copyright (c) 1980, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 #if 0 36 static const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; 37 #endif 38 static const char rcsid[] = 39 "$Id: dir.c,v 1.10 1998/06/15 07:07:10 charnier Exp $"; 40 #endif /* not lint */ 41 42 #include <sys/param.h> 43 44 #include <ufs/ufs/dinode.h> 45 #include <ufs/ufs/dir.h> 46 #include <ufs/ffs/fs.h> 47 48 #include <err.h> 49 #include <string.h> 50 51 #include "fsck.h" 52 53 char *lfname = "lost+found"; 54 int lfmode = 01777; 55 struct dirtemplate emptydir = { 0, DIRBLKSIZ }; 56 struct dirtemplate dirhead = { 57 0, 12, DT_DIR, 1, ".", 58 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 59 }; 60 struct odirtemplate odirhead = { 61 0, 12, 1, ".", 62 0, DIRBLKSIZ - 12, 2, ".." 63 }; 64 65 static int chgino __P((struct inodesc *)); 66 static int dircheck __P((struct inodesc *, struct direct *)); 67 static int expanddir __P((struct dinode *dp, char *name)); 68 static void freedir __P((ino_t ino, ino_t parent)); 69 static struct direct *fsck_readdir __P((struct inodesc *)); 70 static struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size)); 71 static int lftempname __P((char *bufp, ino_t ino)); 72 static int mkentry __P((struct inodesc *)); 73 74 /* 75 * Propagate connected state through the tree. 76 */ 77 void 78 propagate() 79 { 80 register struct inoinfo **inpp, *inp; 81 struct inoinfo **inpend; 82 long change; 83 84 inpend = &inpsort[inplast]; 85 do { 86 change = 0; 87 for (inpp = inpsort; inpp < inpend; inpp++) { 88 inp = *inpp; 89 if (inp->i_parent == 0) 90 continue; 91 if (statemap[inp->i_parent] == DFOUND && 92 statemap[inp->i_number] == DSTATE) { 93 statemap[inp->i_number] = DFOUND; 94 change++; 95 } 96 } 97 } while (change > 0); 98 } 99 100 /* 101 * Scan each entry in a directory block. 102 */ 103 int 104 dirscan(idesc) 105 register struct inodesc *idesc; 106 { 107 register struct direct *dp; 108 register struct bufarea *bp; 109 int dsize, n; 110 long blksiz; 111 char dbuf[DIRBLKSIZ]; 112 113 if (idesc->id_type != DATA) 114 errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 115 if (idesc->id_entryno == 0 && 116 (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 117 idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 118 blksiz = idesc->id_numfrags * sblock.fs_fsize; 119 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 120 idesc->id_filesize -= blksiz; 121 return (SKIP); 122 } 123 idesc->id_loc = 0; 124 for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 125 dsize = dp->d_reclen; 126 memmove(dbuf, dp, (size_t)dsize); 127 # if (BYTE_ORDER == LITTLE_ENDIAN) 128 if (!newinofmt) { 129 struct direct *tdp = (struct direct *)dbuf; 130 u_char tmp; 131 132 tmp = tdp->d_namlen; 133 tdp->d_namlen = tdp->d_type; 134 tdp->d_type = tmp; 135 } 136 # endif 137 idesc->id_dirp = (struct direct *)dbuf; 138 if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 139 # if (BYTE_ORDER == LITTLE_ENDIAN) 140 if (!newinofmt && !doinglevel2) { 141 struct direct *tdp; 142 u_char tmp; 143 144 tdp = (struct direct *)dbuf; 145 tmp = tdp->d_namlen; 146 tdp->d_namlen = tdp->d_type; 147 tdp->d_type = tmp; 148 } 149 # endif 150 bp = getdirblk(idesc->id_blkno, blksiz); 151 memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 152 (size_t)dsize); 153 dirty(bp); 154 sbdirty(); 155 } 156 if (n & STOP) 157 return (n); 158 } 159 return (idesc->id_filesize > 0 ? KEEPON : STOP); 160 } 161 162 /* 163 * get next entry in a directory. 164 */ 165 static struct direct * 166 fsck_readdir(idesc) 167 register struct inodesc *idesc; 168 { 169 register struct direct *dp, *ndp; 170 register struct bufarea *bp; 171 long size, blksiz, fix, dploc; 172 173 blksiz = idesc->id_numfrags * sblock.fs_fsize; 174 bp = getdirblk(idesc->id_blkno, blksiz); 175 if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 176 idesc->id_loc < blksiz) { 177 dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 178 if (dircheck(idesc, dp)) 179 goto dpok; 180 if (idesc->id_fix == IGNORE) 181 return (0); 182 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 183 bp = getdirblk(idesc->id_blkno, blksiz); 184 dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 185 dp->d_reclen = DIRBLKSIZ; 186 dp->d_ino = 0; 187 dp->d_type = 0; 188 dp->d_namlen = 0; 189 dp->d_name[0] = '\0'; 190 if (fix) 191 dirty(bp); 192 idesc->id_loc += DIRBLKSIZ; 193 idesc->id_filesize -= DIRBLKSIZ; 194 return (dp); 195 } 196 dpok: 197 if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 198 return NULL; 199 dploc = idesc->id_loc; 200 dp = (struct direct *)(bp->b_un.b_buf + dploc); 201 idesc->id_loc += dp->d_reclen; 202 idesc->id_filesize -= dp->d_reclen; 203 if ((idesc->id_loc % DIRBLKSIZ) == 0) 204 return (dp); 205 ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 206 if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 207 dircheck(idesc, ndp) == 0) { 208 size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 209 idesc->id_loc += size; 210 idesc->id_filesize -= size; 211 if (idesc->id_fix == IGNORE) 212 return (0); 213 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 214 bp = getdirblk(idesc->id_blkno, blksiz); 215 dp = (struct direct *)(bp->b_un.b_buf + dploc); 216 dp->d_reclen += size; 217 if (fix) 218 dirty(bp); 219 } 220 return (dp); 221 } 222 223 /* 224 * Verify that a directory entry is valid. 225 * This is a superset of the checks made in the kernel. 226 */ 227 static int 228 dircheck(idesc, dp) 229 struct inodesc *idesc; 230 register struct direct *dp; 231 { 232 register int size; 233 register char *cp; 234 u_char namlen, type; 235 int spaceleft; 236 237 spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 238 if (dp->d_ino >= maxino || 239 dp->d_reclen == 0 || 240 dp->d_reclen > spaceleft || 241 (dp->d_reclen & 0x3) != 0) 242 return (0); 243 if (dp->d_ino == 0) 244 return (1); 245 size = DIRSIZ(!newinofmt, dp); 246 # if (BYTE_ORDER == LITTLE_ENDIAN) 247 if (!newinofmt) { 248 type = dp->d_namlen; 249 namlen = dp->d_type; 250 } else { 251 namlen = dp->d_namlen; 252 type = dp->d_type; 253 } 254 # else 255 namlen = dp->d_namlen; 256 type = dp->d_type; 257 # endif 258 if (dp->d_reclen < size || 259 idesc->id_filesize < size || 260 namlen > MAXNAMLEN || 261 type > 15) 262 return (0); 263 for (cp = dp->d_name, size = 0; size < namlen; size++) 264 if (*cp == '\0' || (*cp++ == '/')) 265 return (0); 266 if (*cp != '\0') 267 return (0); 268 return (1); 269 } 270 271 void 272 direrror(ino, errmesg) 273 ino_t ino; 274 char *errmesg; 275 { 276 277 fileerror(ino, ino, errmesg); 278 } 279 280 void 281 fileerror(cwd, ino, errmesg) 282 ino_t cwd, ino; 283 char *errmesg; 284 { 285 register struct dinode *dp; 286 char pathbuf[MAXPATHLEN + 1]; 287 288 pwarn("%s ", errmesg); 289 pinode(ino); 290 printf("\n"); 291 getpathname(pathbuf, cwd, ino); 292 if (ino < ROOTINO || ino > maxino) { 293 pfatal("NAME=%s\n", pathbuf); 294 return; 295 } 296 dp = ginode(ino); 297 if (ftypeok(dp)) 298 pfatal("%s=%s\n", 299 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 300 else 301 pfatal("NAME=%s\n", pathbuf); 302 } 303 304 void 305 adjust(idesc, lcnt) 306 register struct inodesc *idesc; 307 int lcnt; 308 { 309 register struct dinode *dp; 310 311 dp = ginode(idesc->id_number); 312 if (dp->di_nlink == lcnt) { 313 if (linkup(idesc->id_number, (ino_t)0) == 0) 314 clri(idesc, "UNREF", 0); 315 } else { 316 pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 317 ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 318 pinode(idesc->id_number); 319 printf(" COUNT %d SHOULD BE %d", 320 dp->di_nlink, dp->di_nlink - lcnt); 321 if (preen || usedsoftdep) { 322 if (lcnt < 0) { 323 printf("\n"); 324 pfatal("LINK COUNT INCREASING"); 325 } 326 if (preen) 327 printf(" (ADJUSTED)\n"); 328 } 329 if (preen || reply("ADJUST") == 1) { 330 dp->di_nlink -= lcnt; 331 inodirty(); 332 } 333 } 334 } 335 336 static int 337 mkentry(idesc) 338 struct inodesc *idesc; 339 { 340 register struct direct *dirp = idesc->id_dirp; 341 struct direct newent; 342 int newlen, oldlen; 343 344 newent.d_namlen = strlen(idesc->id_name); 345 newlen = DIRSIZ(0, &newent); 346 if (dirp->d_ino != 0) 347 oldlen = DIRSIZ(0, dirp); 348 else 349 oldlen = 0; 350 if (dirp->d_reclen - oldlen < newlen) 351 return (KEEPON); 352 newent.d_reclen = dirp->d_reclen - oldlen; 353 dirp->d_reclen = oldlen; 354 dirp = (struct direct *)(((char *)dirp) + oldlen); 355 dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 356 dirp->d_reclen = newent.d_reclen; 357 if (newinofmt) 358 dirp->d_type = typemap[idesc->id_parent]; 359 else 360 dirp->d_type = 0; 361 dirp->d_namlen = newent.d_namlen; 362 memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 363 # if (BYTE_ORDER == LITTLE_ENDIAN) 364 /* 365 * If the entry was split, dirscan() will only reverse the byte 366 * order of the original entry, and not the new one, before 367 * writing it back out. So, we reverse the byte order here if 368 * necessary. 369 */ 370 if (oldlen != 0 && !newinofmt && !doinglevel2) { 371 u_char tmp; 372 373 tmp = dirp->d_namlen; 374 dirp->d_namlen = dirp->d_type; 375 dirp->d_type = tmp; 376 } 377 # endif 378 return (ALTERED|STOP); 379 } 380 381 static int 382 chgino(idesc) 383 struct inodesc *idesc; 384 { 385 register struct direct *dirp = idesc->id_dirp; 386 387 if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 388 return (KEEPON); 389 dirp->d_ino = idesc->id_parent; 390 if (newinofmt) 391 dirp->d_type = typemap[idesc->id_parent]; 392 else 393 dirp->d_type = 0; 394 return (ALTERED|STOP); 395 } 396 397 int 398 linkup(orphan, parentdir) 399 ino_t orphan; 400 ino_t parentdir; 401 { 402 register struct dinode *dp; 403 int lostdir; 404 ino_t oldlfdir; 405 struct inodesc idesc; 406 char tempname[BUFSIZ]; 407 408 memset(&idesc, 0, sizeof(struct inodesc)); 409 dp = ginode(orphan); 410 lostdir = (dp->di_mode & IFMT) == IFDIR; 411 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 412 pinode(orphan); 413 if ((preen || usedsoftdep) && dp->di_size == 0) 414 return (0); 415 if (preen) 416 printf(" (RECONNECTED)\n"); 417 else 418 if (reply("RECONNECT") == 0) 419 return (0); 420 if (parentdir != 0) 421 lncntp[parentdir]++; 422 if (lfdir == 0) { 423 dp = ginode(ROOTINO); 424 idesc.id_name = lfname; 425 idesc.id_type = DATA; 426 idesc.id_func = findino; 427 idesc.id_number = ROOTINO; 428 if ((ckinode(dp, &idesc) & FOUND) != 0) { 429 lfdir = idesc.id_parent; 430 } else { 431 pwarn("NO lost+found DIRECTORY"); 432 if (preen || reply("CREATE")) { 433 lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 434 if (lfdir != 0) { 435 if (makeentry(ROOTINO, lfdir, lfname) != 0) { 436 if (preen) 437 printf(" (CREATED)\n"); 438 } else { 439 freedir(lfdir, ROOTINO); 440 lfdir = 0; 441 if (preen) 442 printf("\n"); 443 } 444 } 445 } 446 } 447 if (lfdir == 0) { 448 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 449 printf("\n\n"); 450 return (0); 451 } 452 } 453 dp = ginode(lfdir); 454 if ((dp->di_mode & IFMT) != IFDIR) { 455 pfatal("lost+found IS NOT A DIRECTORY"); 456 if (reply("REALLOCATE") == 0) 457 return (0); 458 oldlfdir = lfdir; 459 if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 460 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 461 return (0); 462 } 463 if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 464 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 465 return (0); 466 } 467 inodirty(); 468 idesc.id_type = ADDR; 469 idesc.id_func = pass4check; 470 idesc.id_number = oldlfdir; 471 adjust(&idesc, lncntp[oldlfdir] + 1); 472 lncntp[oldlfdir] = 0; 473 dp = ginode(lfdir); 474 } 475 if (statemap[lfdir] != DFOUND) { 476 pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 477 return (0); 478 } 479 (void)lftempname(tempname, orphan); 480 if (makeentry(lfdir, orphan, tempname) == 0) { 481 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 482 printf("\n\n"); 483 return (0); 484 } 485 lncntp[orphan]--; 486 if (lostdir) { 487 if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 488 parentdir != (ino_t)-1) 489 (void)makeentry(orphan, lfdir, ".."); 490 dp = ginode(lfdir); 491 dp->di_nlink++; 492 inodirty(); 493 lncntp[lfdir]++; 494 pwarn("DIR I=%lu CONNECTED. ", orphan); 495 if (parentdir != (ino_t)-1) { 496 printf("PARENT WAS I=%lu\n", (u_long)parentdir); 497 /* 498 * The parent directory, because of the ordering 499 * guarantees, has had the link count incremented 500 * for the child, but no entry was made. This 501 * fixes the parent link count so that fsck does 502 * not need to be rerun. 503 */ 504 lncntp[parentdir]++; 505 506 } 507 if (preen == 0) 508 printf("\n"); 509 } 510 return (1); 511 } 512 513 /* 514 * fix an entry in a directory. 515 */ 516 int 517 changeino(dir, name, newnum) 518 ino_t dir; 519 char *name; 520 ino_t newnum; 521 { 522 struct inodesc idesc; 523 524 memset(&idesc, 0, sizeof(struct inodesc)); 525 idesc.id_type = DATA; 526 idesc.id_func = chgino; 527 idesc.id_number = dir; 528 idesc.id_fix = DONTKNOW; 529 idesc.id_name = name; 530 idesc.id_parent = newnum; /* new value for name */ 531 return (ckinode(ginode(dir), &idesc)); 532 } 533 534 /* 535 * make an entry in a directory 536 */ 537 int 538 makeentry(parent, ino, name) 539 ino_t parent, ino; 540 char *name; 541 { 542 struct dinode *dp; 543 struct inodesc idesc; 544 char pathbuf[MAXPATHLEN + 1]; 545 546 if (parent < ROOTINO || parent >= maxino || 547 ino < ROOTINO || ino >= maxino) 548 return (0); 549 memset(&idesc, 0, sizeof(struct inodesc)); 550 idesc.id_type = DATA; 551 idesc.id_func = mkentry; 552 idesc.id_number = parent; 553 idesc.id_parent = ino; /* this is the inode to enter */ 554 idesc.id_fix = DONTKNOW; 555 idesc.id_name = name; 556 dp = ginode(parent); 557 if (dp->di_size % DIRBLKSIZ) { 558 dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 559 inodirty(); 560 } 561 if ((ckinode(dp, &idesc) & ALTERED) != 0) 562 return (1); 563 getpathname(pathbuf, parent, parent); 564 dp = ginode(parent); 565 if (expanddir(dp, pathbuf) == 0) 566 return (0); 567 return (ckinode(dp, &idesc) & ALTERED); 568 } 569 570 /* 571 * Attempt to expand the size of a directory 572 */ 573 static int 574 expanddir(dp, name) 575 register struct dinode *dp; 576 char *name; 577 { 578 ufs_daddr_t lastbn, newblk; 579 register struct bufarea *bp; 580 char *cp, firstblk[DIRBLKSIZ]; 581 582 lastbn = lblkno(&sblock, dp->di_size); 583 if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 584 return (0); 585 if ((newblk = allocblk(sblock.fs_frag)) == 0) 586 return (0); 587 dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 588 dp->di_db[lastbn] = newblk; 589 dp->di_size += sblock.fs_bsize; 590 dp->di_blocks += btodb(sblock.fs_bsize); 591 bp = getdirblk(dp->di_db[lastbn + 1], 592 (long)dblksize(&sblock, dp, lastbn + 1)); 593 if (bp->b_errs) 594 goto bad; 595 memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 596 bp = getdirblk(newblk, sblock.fs_bsize); 597 if (bp->b_errs) 598 goto bad; 599 memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 600 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 601 cp < &bp->b_un.b_buf[sblock.fs_bsize]; 602 cp += DIRBLKSIZ) 603 memmove(cp, &emptydir, sizeof emptydir); 604 dirty(bp); 605 bp = getdirblk(dp->di_db[lastbn + 1], 606 (long)dblksize(&sblock, dp, lastbn + 1)); 607 if (bp->b_errs) 608 goto bad; 609 memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 610 pwarn("NO SPACE LEFT IN %s", name); 611 if (preen) 612 printf(" (EXPANDED)\n"); 613 else if (reply("EXPAND") == 0) 614 goto bad; 615 dirty(bp); 616 inodirty(); 617 return (1); 618 bad: 619 dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 620 dp->di_db[lastbn + 1] = 0; 621 dp->di_size -= sblock.fs_bsize; 622 dp->di_blocks -= btodb(sblock.fs_bsize); 623 freeblk(newblk, sblock.fs_frag); 624 return (0); 625 } 626 627 /* 628 * allocate a new directory 629 */ 630 ino_t 631 allocdir(parent, request, mode) 632 ino_t parent, request; 633 int mode; 634 { 635 ino_t ino; 636 char *cp; 637 struct dinode *dp; 638 register struct bufarea *bp; 639 struct dirtemplate *dirp; 640 641 ino = allocino(request, IFDIR|mode); 642 if (newinofmt) 643 dirp = &dirhead; 644 else 645 dirp = (struct dirtemplate *)&odirhead; 646 dirp->dot_ino = ino; 647 dirp->dotdot_ino = parent; 648 dp = ginode(ino); 649 bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 650 if (bp->b_errs) { 651 freeino(ino); 652 return (0); 653 } 654 memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 655 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 656 cp < &bp->b_un.b_buf[sblock.fs_fsize]; 657 cp += DIRBLKSIZ) 658 memmove(cp, &emptydir, sizeof emptydir); 659 dirty(bp); 660 dp->di_nlink = 2; 661 inodirty(); 662 if (ino == ROOTINO) { 663 lncntp[ino] = dp->di_nlink; 664 cacheino(dp, ino); 665 return(ino); 666 } 667 if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 668 freeino(ino); 669 return (0); 670 } 671 cacheino(dp, ino); 672 statemap[ino] = statemap[parent]; 673 if (statemap[ino] == DSTATE) { 674 lncntp[ino] = dp->di_nlink; 675 lncntp[parent]++; 676 } 677 dp = ginode(parent); 678 dp->di_nlink++; 679 inodirty(); 680 return (ino); 681 } 682 683 /* 684 * free a directory inode 685 */ 686 static void 687 freedir(ino, parent) 688 ino_t ino, parent; 689 { 690 struct dinode *dp; 691 692 if (ino != parent) { 693 dp = ginode(parent); 694 dp->di_nlink--; 695 inodirty(); 696 } 697 freeino(ino); 698 } 699 700 /* 701 * generate a temporary name for the lost+found directory. 702 */ 703 static int 704 lftempname(bufp, ino) 705 char *bufp; 706 ino_t ino; 707 { 708 register ino_t in; 709 register char *cp; 710 int namlen; 711 712 cp = bufp + 2; 713 for (in = maxino; in > 0; in /= 10) 714 cp++; 715 *--cp = 0; 716 namlen = cp - bufp; 717 in = ino; 718 while (cp > bufp) { 719 *--cp = (in % 10) + '0'; 720 in /= 10; 721 } 722 *cp = '#'; 723 return (namlen); 724 } 725 726 /* 727 * Get a directory block. 728 * Insure that it is held until another is requested. 729 */ 730 static struct bufarea * 731 getdirblk(blkno, size) 732 ufs_daddr_t blkno; 733 long size; 734 { 735 736 if (pdirbp != 0) 737 pdirbp->b_flags &= ~B_INUSE; 738 pdirbp = getdatablk(blkno, size); 739 return (pdirbp); 740 } 741