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