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