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 "$FreeBSD$"; 40 #endif /* not lint */ 41 42 #include <sys/param.h> 43 #include <sys/time.h> 44 #include <sys/sysctl.h> 45 46 #include <ufs/ufs/dinode.h> 47 #include <ufs/ufs/dir.h> 48 #include <ufs/ffs/fs.h> 49 50 #include <err.h> 51 #include <string.h> 52 53 #include "fsck.h" 54 55 char *lfname = "lost+found"; 56 int lfmode = 01777; 57 struct dirtemplate emptydir = { 58 0, DIRBLKSIZ, DT_UNKNOWN, 0, "", 59 0, 0, DT_UNKNOWN, 0, "" 60 }; 61 struct dirtemplate dirhead = { 62 0, 12, DT_DIR, 1, ".", 63 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 64 }; 65 struct odirtemplate odirhead = { 66 0, 12, 1, ".", 67 0, DIRBLKSIZ - 12, 2, ".." 68 }; 69 70 static int chgino(struct inodesc *); 71 static int dircheck(struct inodesc *, struct direct *); 72 static int expanddir(struct dinode *dp, char *name); 73 static void freedir(ino_t ino, ino_t parent); 74 static struct direct *fsck_readdir(struct inodesc *); 75 static struct bufarea *getdirblk(ufs_daddr_t blkno, long size); 76 static int lftempname(char *bufp, ino_t ino); 77 static int mkentry(struct inodesc *); 78 79 /* 80 * Propagate connected state through the tree. 81 */ 82 void 83 propagate(void) 84 { 85 struct inoinfo **inpp, *inp; 86 struct inoinfo **inpend; 87 long change; 88 89 inpend = &inpsort[inplast]; 90 do { 91 change = 0; 92 for (inpp = inpsort; inpp < inpend; inpp++) { 93 inp = *inpp; 94 if (inp->i_parent == 0) 95 continue; 96 if (inoinfo(inp->i_parent)->ino_state == DFOUND && 97 inoinfo(inp->i_number)->ino_state == DSTATE) { 98 inoinfo(inp->i_number)->ino_state = DFOUND; 99 change++; 100 } 101 } 102 } while (change > 0); 103 } 104 105 /* 106 * Scan each entry in a directory block. 107 */ 108 int 109 dirscan(struct inodesc *idesc) 110 { 111 struct direct *dp; 112 struct bufarea *bp; 113 u_int dsize, n; 114 long blksiz; 115 char dbuf[DIRBLKSIZ]; 116 117 if (idesc->id_type != DATA) 118 errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 119 if (idesc->id_entryno == 0 && 120 (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 121 idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 122 blksiz = idesc->id_numfrags * sblock.fs_fsize; 123 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 124 idesc->id_filesize -= blksiz; 125 return (SKIP); 126 } 127 idesc->id_loc = 0; 128 for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 129 dsize = dp->d_reclen; 130 if (dsize > sizeof(dbuf)) 131 dsize = sizeof(dbuf); 132 memmove(dbuf, dp, (size_t)dsize); 133 idesc->id_dirp = (struct direct *)dbuf; 134 if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 135 bp = getdirblk(idesc->id_blkno, blksiz); 136 memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 137 (size_t)dsize); 138 dirty(bp); 139 sbdirty(); 140 } 141 if (n & STOP) 142 return (n); 143 } 144 return (idesc->id_filesize > 0 ? KEEPON : STOP); 145 } 146 147 /* 148 * get next entry in a directory. 149 */ 150 static struct direct * 151 fsck_readdir(struct inodesc *idesc) 152 { 153 struct direct *dp, *ndp; 154 struct bufarea *bp; 155 long size, blksiz, fix, dploc; 156 157 blksiz = idesc->id_numfrags * sblock.fs_fsize; 158 bp = getdirblk(idesc->id_blkno, blksiz); 159 if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 160 idesc->id_loc < blksiz) { 161 dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 162 if (dircheck(idesc, dp)) 163 goto dpok; 164 if (idesc->id_fix == IGNORE) 165 return (0); 166 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 167 bp = getdirblk(idesc->id_blkno, blksiz); 168 dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 169 dp->d_reclen = DIRBLKSIZ; 170 dp->d_ino = 0; 171 dp->d_type = 0; 172 dp->d_namlen = 0; 173 dp->d_name[0] = '\0'; 174 if (fix) 175 dirty(bp); 176 idesc->id_loc += DIRBLKSIZ; 177 idesc->id_filesize -= DIRBLKSIZ; 178 return (dp); 179 } 180 dpok: 181 if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 182 return NULL; 183 dploc = idesc->id_loc; 184 dp = (struct direct *)(bp->b_un.b_buf + dploc); 185 idesc->id_loc += dp->d_reclen; 186 idesc->id_filesize -= dp->d_reclen; 187 if ((idesc->id_loc % DIRBLKSIZ) == 0) 188 return (dp); 189 ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 190 if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 191 dircheck(idesc, ndp) == 0) { 192 size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 193 idesc->id_loc += size; 194 idesc->id_filesize -= size; 195 if (idesc->id_fix == IGNORE) 196 return (0); 197 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 198 bp = getdirblk(idesc->id_blkno, blksiz); 199 dp = (struct direct *)(bp->b_un.b_buf + dploc); 200 dp->d_reclen += size; 201 if (fix) 202 dirty(bp); 203 } 204 return (dp); 205 } 206 207 /* 208 * Verify that a directory entry is valid. 209 * This is a superset of the checks made in the kernel. 210 */ 211 static int 212 dircheck(struct inodesc *idesc, struct direct *dp) 213 { 214 int size; 215 char *cp; 216 u_char namlen, type; 217 int spaceleft; 218 219 spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 220 if (dp->d_reclen == 0 || 221 dp->d_reclen > spaceleft || 222 (dp->d_reclen & 0x3) != 0) 223 goto bad; 224 if (dp->d_ino == 0) 225 return (1); 226 size = DIRSIZ(0, dp); 227 namlen = dp->d_namlen; 228 type = dp->d_type; 229 if (dp->d_reclen < size || 230 idesc->id_filesize < size || 231 namlen > MAXNAMLEN || 232 type > 15) 233 goto bad; 234 for (cp = dp->d_name, size = 0; size < namlen; size++) 235 if (*cp == '\0' || (*cp++ == '/')) 236 goto bad; 237 if (*cp != '\0') 238 goto bad; 239 return (1); 240 bad: 241 if (debug) 242 printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n", 243 dp->d_ino, dp->d_reclen, dp->d_namlen, dp->d_type, 244 dp->d_name); 245 return (0); 246 } 247 248 void 249 direrror(ino_t ino, char *errmesg) 250 { 251 252 fileerror(ino, ino, errmesg); 253 } 254 255 void 256 fileerror(ino_t cwd, ino_t ino, char *errmesg) 257 { 258 struct dinode *dp; 259 char pathbuf[MAXPATHLEN + 1]; 260 261 pwarn("%s ", errmesg); 262 pinode(ino); 263 printf("\n"); 264 getpathname(pathbuf, cwd, ino); 265 if (ino < ROOTINO || ino > maxino) { 266 pfatal("NAME=%s\n", pathbuf); 267 return; 268 } 269 dp = ginode(ino); 270 if (ftypeok(dp)) 271 pfatal("%s=%s\n", 272 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 273 else 274 pfatal("NAME=%s\n", pathbuf); 275 } 276 277 void 278 adjust(struct inodesc *idesc, int lcnt) 279 { 280 struct dinode *dp; 281 int saveresolved; 282 283 dp = ginode(idesc->id_number); 284 if (dp->di_nlink == lcnt) { 285 /* 286 * If we have not hit any unresolved problems, are running 287 * in preen mode, and are on a filesystem using soft updates, 288 * then just toss any partially allocated files. 289 */ 290 if (resolved && (preen || bkgrdflag) && usedsoftdep) { 291 clri(idesc, "UNREF", 1); 292 return; 293 } else { 294 /* 295 * The filesystem can be marked clean even if 296 * a file is not linked up, but is cleared. 297 * Hence, resolved should not be cleared when 298 * linkup is answered no, but clri is answered yes. 299 */ 300 saveresolved = resolved; 301 if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) { 302 resolved = saveresolved; 303 clri(idesc, "UNREF", 0); 304 return; 305 } 306 /* 307 * Account for the new reference created by linkup(). 308 */ 309 dp = ginode(idesc->id_number); 310 lcnt--; 311 } 312 } 313 if (lcnt != 0) { 314 pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 315 ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 316 pinode(idesc->id_number); 317 printf(" COUNT %d SHOULD BE %d", 318 dp->di_nlink, dp->di_nlink - lcnt); 319 if (preen || usedsoftdep) { 320 if (lcnt < 0) { 321 printf("\n"); 322 pfatal("LINK COUNT INCREASING"); 323 } 324 if (preen) 325 printf(" (ADJUSTED)\n"); 326 } 327 if (preen || reply("ADJUST") == 1) { 328 if (bkgrdflag == 0) { 329 dp->di_nlink -= lcnt; 330 inodirty(); 331 } else { 332 cmd.value = idesc->id_number; 333 cmd.size = -lcnt; 334 if (debug) 335 printf("adjrefcnt ino %ld amt %ld\n", 336 (long)cmd.value, cmd.size); 337 if (sysctl(adjrefcnt, MIBSIZE, 0, 0, 338 &cmd, sizeof cmd) == -1) 339 rwerror("ADJUST INODE", cmd.value); 340 } 341 } 342 } 343 } 344 345 static int 346 mkentry(struct inodesc *idesc) 347 { 348 struct direct *dirp = idesc->id_dirp; 349 struct direct newent; 350 int newlen, oldlen; 351 352 newent.d_namlen = strlen(idesc->id_name); 353 newlen = DIRSIZ(0, &newent); 354 if (dirp->d_ino != 0) 355 oldlen = DIRSIZ(0, dirp); 356 else 357 oldlen = 0; 358 if (dirp->d_reclen - oldlen < newlen) 359 return (KEEPON); 360 newent.d_reclen = dirp->d_reclen - oldlen; 361 dirp->d_reclen = oldlen; 362 dirp = (struct direct *)(((char *)dirp) + oldlen); 363 dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 364 dirp->d_reclen = newent.d_reclen; 365 dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 366 dirp->d_namlen = newent.d_namlen; 367 memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 368 return (ALTERED|STOP); 369 } 370 371 static int 372 chgino(struct inodesc *idesc) 373 { 374 struct direct *dirp = idesc->id_dirp; 375 376 if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 377 return (KEEPON); 378 dirp->d_ino = idesc->id_parent; 379 dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 380 return (ALTERED|STOP); 381 } 382 383 int 384 linkup(ino_t orphan, ino_t parentdir, char *name) 385 { 386 struct dinode *dp; 387 int lostdir; 388 ino_t oldlfdir; 389 struct inodesc idesc; 390 char tempname[BUFSIZ]; 391 392 memset(&idesc, 0, sizeof(struct inodesc)); 393 dp = ginode(orphan); 394 lostdir = (dp->di_mode & IFMT) == IFDIR; 395 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 396 pinode(orphan); 397 if (preen && dp->di_size == 0) 398 return (0); 399 if (cursnapshot != 0) { 400 pfatal("FILE LINKUP IN SNAPSHOT"); 401 return (0); 402 } 403 if (preen) 404 printf(" (RECONNECTED)\n"); 405 else 406 if (reply("RECONNECT") == 0) 407 return (0); 408 if (lfdir == 0) { 409 dp = ginode(ROOTINO); 410 idesc.id_name = lfname; 411 idesc.id_type = DATA; 412 idesc.id_func = findino; 413 idesc.id_number = ROOTINO; 414 if ((ckinode(dp, &idesc) & FOUND) != 0) { 415 lfdir = idesc.id_parent; 416 } else { 417 pwarn("NO lost+found DIRECTORY"); 418 if (preen || reply("CREATE")) { 419 lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 420 if (lfdir != 0) { 421 if (makeentry(ROOTINO, lfdir, lfname) != 0) { 422 numdirs++; 423 if (preen) 424 printf(" (CREATED)\n"); 425 } else { 426 freedir(lfdir, ROOTINO); 427 lfdir = 0; 428 if (preen) 429 printf("\n"); 430 } 431 } 432 } 433 } 434 if (lfdir == 0) { 435 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 436 printf("\n\n"); 437 return (0); 438 } 439 } 440 dp = ginode(lfdir); 441 if ((dp->di_mode & IFMT) != IFDIR) { 442 pfatal("lost+found IS NOT A DIRECTORY"); 443 if (reply("REALLOCATE") == 0) 444 return (0); 445 oldlfdir = lfdir; 446 if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 447 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 448 return (0); 449 } 450 if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 451 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 452 return (0); 453 } 454 inodirty(); 455 idesc.id_type = ADDR; 456 idesc.id_func = pass4check; 457 idesc.id_number = oldlfdir; 458 adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1); 459 inoinfo(oldlfdir)->ino_linkcnt = 0; 460 dp = ginode(lfdir); 461 } 462 if (inoinfo(lfdir)->ino_state != DFOUND) { 463 pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 464 return (0); 465 } 466 (void)lftempname(tempname, orphan); 467 if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) { 468 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 469 printf("\n\n"); 470 return (0); 471 } 472 inoinfo(orphan)->ino_linkcnt--; 473 if (lostdir) { 474 if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 475 parentdir != (ino_t)-1) 476 (void)makeentry(orphan, lfdir, ".."); 477 dp = ginode(lfdir); 478 dp->di_nlink++; 479 inodirty(); 480 inoinfo(lfdir)->ino_linkcnt++; 481 pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan); 482 if (parentdir != (ino_t)-1) { 483 printf("PARENT WAS I=%lu\n", (u_long)parentdir); 484 /* 485 * The parent directory, because of the ordering 486 * guarantees, has had the link count incremented 487 * for the child, but no entry was made. This 488 * fixes the parent link count so that fsck does 489 * not need to be rerun. 490 */ 491 inoinfo(parentdir)->ino_linkcnt++; 492 } 493 if (preen == 0) 494 printf("\n"); 495 } 496 return (1); 497 } 498 499 /* 500 * fix an entry in a directory. 501 */ 502 int 503 changeino(ino_t dir, char *name, ino_t newnum) 504 { 505 struct inodesc idesc; 506 507 memset(&idesc, 0, sizeof(struct inodesc)); 508 idesc.id_type = DATA; 509 idesc.id_func = chgino; 510 idesc.id_number = dir; 511 idesc.id_fix = DONTKNOW; 512 idesc.id_name = name; 513 idesc.id_parent = newnum; /* new value for name */ 514 return (ckinode(ginode(dir), &idesc)); 515 } 516 517 /* 518 * make an entry in a directory 519 */ 520 int 521 makeentry(ino_t parent, ino_t ino, char *name) 522 { 523 struct dinode *dp; 524 struct inodesc idesc; 525 char pathbuf[MAXPATHLEN + 1]; 526 527 if (parent < ROOTINO || parent >= maxino || 528 ino < ROOTINO || ino >= maxino) 529 return (0); 530 memset(&idesc, 0, sizeof(struct inodesc)); 531 idesc.id_type = DATA; 532 idesc.id_func = mkentry; 533 idesc.id_number = parent; 534 idesc.id_parent = ino; /* this is the inode to enter */ 535 idesc.id_fix = DONTKNOW; 536 idesc.id_name = name; 537 dp = ginode(parent); 538 if (dp->di_size % DIRBLKSIZ) { 539 dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 540 inodirty(); 541 } 542 if ((ckinode(dp, &idesc) & ALTERED) != 0) 543 return (1); 544 getpathname(pathbuf, parent, parent); 545 dp = ginode(parent); 546 if (expanddir(dp, pathbuf) == 0) 547 return (0); 548 return (ckinode(dp, &idesc) & ALTERED); 549 } 550 551 /* 552 * Attempt to expand the size of a directory 553 */ 554 static int 555 expanddir(struct dinode *dp, char *name) 556 { 557 ufs_daddr_t lastbn, newblk; 558 struct bufarea *bp; 559 char *cp, firstblk[DIRBLKSIZ]; 560 561 lastbn = lblkno(&sblock, dp->di_size); 562 if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 563 return (0); 564 if ((newblk = allocblk(sblock.fs_frag)) == 0) 565 return (0); 566 dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 567 dp->di_db[lastbn] = newblk; 568 dp->di_size += sblock.fs_bsize; 569 dp->di_blocks += btodb(sblock.fs_bsize); 570 bp = getdirblk(dp->di_db[lastbn + 1], 571 (long)dblksize(&sblock, dp, lastbn + 1)); 572 if (bp->b_errs) 573 goto bad; 574 memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 575 bp = getdirblk(newblk, sblock.fs_bsize); 576 if (bp->b_errs) 577 goto bad; 578 memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 579 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 580 cp < &bp->b_un.b_buf[sblock.fs_bsize]; 581 cp += DIRBLKSIZ) 582 memmove(cp, &emptydir, sizeof emptydir); 583 dirty(bp); 584 bp = getdirblk(dp->di_db[lastbn + 1], 585 (long)dblksize(&sblock, dp, lastbn + 1)); 586 if (bp->b_errs) 587 goto bad; 588 memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 589 pwarn("NO SPACE LEFT IN %s", name); 590 if (preen) 591 printf(" (EXPANDED)\n"); 592 else if (reply("EXPAND") == 0) 593 goto bad; 594 dirty(bp); 595 inodirty(); 596 return (1); 597 bad: 598 dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 599 dp->di_db[lastbn + 1] = 0; 600 dp->di_size -= sblock.fs_bsize; 601 dp->di_blocks -= btodb(sblock.fs_bsize); 602 freeblk(newblk, sblock.fs_frag); 603 return (0); 604 } 605 606 /* 607 * allocate a new directory 608 */ 609 ino_t 610 allocdir(ino_t parent, ino_t request, int mode) 611 { 612 ino_t ino; 613 char *cp; 614 struct dinode *dp; 615 struct bufarea *bp; 616 struct inoinfo *inp; 617 struct dirtemplate *dirp; 618 619 ino = allocino(request, IFDIR|mode); 620 dirp = &dirhead; 621 dirp->dot_ino = ino; 622 dirp->dotdot_ino = parent; 623 dp = ginode(ino); 624 bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 625 if (bp->b_errs) { 626 freeino(ino); 627 return (0); 628 } 629 memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 630 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 631 cp < &bp->b_un.b_buf[sblock.fs_fsize]; 632 cp += DIRBLKSIZ) 633 memmove(cp, &emptydir, sizeof emptydir); 634 dirty(bp); 635 dp->di_nlink = 2; 636 inodirty(); 637 if (ino == ROOTINO) { 638 inoinfo(ino)->ino_linkcnt = dp->di_nlink; 639 cacheino(dp, ino); 640 return(ino); 641 } 642 if (inoinfo(parent)->ino_state != DSTATE && 643 inoinfo(parent)->ino_state != DFOUND) { 644 freeino(ino); 645 return (0); 646 } 647 cacheino(dp, ino); 648 inp = getinoinfo(ino); 649 inp->i_parent = parent; 650 inp->i_dotdot = parent; 651 inoinfo(ino)->ino_state = inoinfo(parent)->ino_state; 652 if (inoinfo(ino)->ino_state == DSTATE) { 653 inoinfo(ino)->ino_linkcnt = dp->di_nlink; 654 inoinfo(parent)->ino_linkcnt++; 655 } 656 dp = ginode(parent); 657 dp->di_nlink++; 658 inodirty(); 659 return (ino); 660 } 661 662 /* 663 * free a directory inode 664 */ 665 static void 666 freedir(ino_t ino, ino_t parent) 667 { 668 struct dinode *dp; 669 670 if (ino != parent) { 671 dp = ginode(parent); 672 dp->di_nlink--; 673 inodirty(); 674 } 675 freeino(ino); 676 } 677 678 /* 679 * generate a temporary name for the lost+found directory. 680 */ 681 static int 682 lftempname(char *bufp, ino_t ino) 683 { 684 ino_t in; 685 char *cp; 686 int namlen; 687 688 cp = bufp + 2; 689 for (in = maxino; in > 0; in /= 10) 690 cp++; 691 *--cp = 0; 692 namlen = cp - bufp; 693 in = ino; 694 while (cp > bufp) { 695 *--cp = (in % 10) + '0'; 696 in /= 10; 697 } 698 *cp = '#'; 699 return (namlen); 700 } 701 702 /* 703 * Get a directory block. 704 * Insure that it is held until another is requested. 705 */ 706 static struct bufarea * 707 getdirblk(ufs_daddr_t blkno, long size) 708 { 709 710 if (pdirbp != 0) 711 pdirbp->b_flags &= ~B_INUSE; 712 pdirbp = getdatablk(blkno, size); 713 return (pdirbp); 714 } 715