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