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 else 334 dirp->d_type = 0; 335 dirp->d_reclen = newent.d_reclen; 336 dirp->d_namlen = newent.d_namlen; 337 bcopy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 338 return (ALTERED|STOP); 339 } 340 341 chgino(idesc) 342 struct inodesc *idesc; 343 { 344 register struct direct *dirp = idesc->id_dirp; 345 346 if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 347 return (KEEPON); 348 dirp->d_ino = idesc->id_parent; 349 if (newinofmt) 350 dirp->d_type = typemap[idesc->id_parent]; 351 else 352 dirp->d_type = 0; 353 return (ALTERED|STOP); 354 } 355 356 linkup(orphan, parentdir) 357 ino_t orphan; 358 ino_t parentdir; 359 { 360 register struct dinode *dp; 361 int lostdir; 362 ino_t oldlfdir; 363 struct inodesc idesc; 364 char tempname[BUFSIZ]; 365 extern int pass4check(); 366 367 bzero((char *)&idesc, sizeof(struct inodesc)); 368 dp = ginode(orphan); 369 lostdir = (dp->di_mode & IFMT) == IFDIR; 370 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 371 pinode(orphan); 372 if (preen && dp->di_size == 0) 373 return (0); 374 if (preen) 375 printf(" (RECONNECTED)\n"); 376 else 377 if (reply("RECONNECT") == 0) 378 return (0); 379 if (lfdir == 0) { 380 dp = ginode(ROOTINO); 381 idesc.id_name = lfname; 382 idesc.id_type = DATA; 383 idesc.id_func = findino; 384 idesc.id_number = ROOTINO; 385 if ((ckinode(dp, &idesc) & FOUND) != 0) { 386 lfdir = idesc.id_parent; 387 } else { 388 pwarn("NO lost+found DIRECTORY"); 389 if (preen || reply("CREATE")) { 390 lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 391 if (lfdir != 0) { 392 if (makeentry(ROOTINO, lfdir, lfname) != 0) { 393 if (preen) 394 printf(" (CREATED)\n"); 395 } else { 396 freedir(lfdir, ROOTINO); 397 lfdir = 0; 398 if (preen) 399 printf("\n"); 400 } 401 } 402 } 403 } 404 if (lfdir == 0) { 405 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 406 printf("\n\n"); 407 return (0); 408 } 409 } 410 dp = ginode(lfdir); 411 if ((dp->di_mode & IFMT) != IFDIR) { 412 pfatal("lost+found IS NOT A DIRECTORY"); 413 if (reply("REALLOCATE") == 0) 414 return (0); 415 oldlfdir = lfdir; 416 if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 417 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 418 return (0); 419 } 420 if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 421 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 422 return (0); 423 } 424 inodirty(); 425 idesc.id_type = ADDR; 426 idesc.id_func = pass4check; 427 idesc.id_number = oldlfdir; 428 adjust(&idesc, lncntp[oldlfdir] + 1); 429 lncntp[oldlfdir] = 0; 430 dp = ginode(lfdir); 431 } 432 if (statemap[lfdir] != DFOUND) { 433 pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 434 return (0); 435 } 436 (void)lftempname(tempname, orphan); 437 if (makeentry(lfdir, orphan, tempname) == 0) { 438 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 439 printf("\n\n"); 440 return (0); 441 } 442 lncntp[orphan]--; 443 if (lostdir) { 444 if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 445 parentdir != (ino_t)-1) 446 (void)makeentry(orphan, lfdir, ".."); 447 dp = ginode(lfdir); 448 dp->di_nlink++; 449 inodirty(); 450 lncntp[lfdir]++; 451 pwarn("DIR I=%lu CONNECTED. ", orphan); 452 if (parentdir != (ino_t)-1) 453 printf("PARENT WAS I=%lu\n", parentdir); 454 if (preen == 0) 455 printf("\n"); 456 } 457 return (1); 458 } 459 460 /* 461 * fix an entry in a directory. 462 */ 463 changeino(dir, name, newnum) 464 ino_t dir; 465 char *name; 466 ino_t newnum; 467 { 468 struct inodesc idesc; 469 470 bzero((char *)&idesc, sizeof(struct inodesc)); 471 idesc.id_type = DATA; 472 idesc.id_func = chgino; 473 idesc.id_number = dir; 474 idesc.id_fix = DONTKNOW; 475 idesc.id_name = name; 476 idesc.id_parent = newnum; /* new value for name */ 477 return (ckinode(ginode(dir), &idesc)); 478 } 479 480 /* 481 * make an entry in a directory 482 */ 483 makeentry(parent, ino, name) 484 ino_t parent, ino; 485 char *name; 486 { 487 struct dinode *dp; 488 struct inodesc idesc; 489 char pathbuf[MAXPATHLEN + 1]; 490 491 if (parent < ROOTINO || parent >= maxino || 492 ino < ROOTINO || ino >= maxino) 493 return (0); 494 bzero((char *)&idesc, sizeof(struct inodesc)); 495 idesc.id_type = DATA; 496 idesc.id_func = mkentry; 497 idesc.id_number = parent; 498 idesc.id_parent = ino; /* this is the inode to enter */ 499 idesc.id_fix = DONTKNOW; 500 idesc.id_name = name; 501 dp = ginode(parent); 502 if (dp->di_size % DIRBLKSIZ) { 503 dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 504 inodirty(); 505 } 506 if ((ckinode(dp, &idesc) & ALTERED) != 0) 507 return (1); 508 getpathname(pathbuf, parent, parent); 509 dp = ginode(parent); 510 if (expanddir(dp, pathbuf) == 0) 511 return (0); 512 return (ckinode(dp, &idesc) & ALTERED); 513 } 514 515 /* 516 * Attempt to expand the size of a directory 517 */ 518 expanddir(dp, name) 519 register struct dinode *dp; 520 char *name; 521 { 522 daddr_t lastbn, newblk; 523 register struct bufarea *bp; 524 char *cp, firstblk[DIRBLKSIZ]; 525 526 lastbn = lblkno(&sblock, dp->di_size); 527 if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 528 return (0); 529 if ((newblk = allocblk(sblock.fs_frag)) == 0) 530 return (0); 531 dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 532 dp->di_db[lastbn] = newblk; 533 dp->di_size += sblock.fs_bsize; 534 dp->di_blocks += btodb(sblock.fs_bsize); 535 bp = getdirblk(dp->di_db[lastbn + 1], 536 (long)dblksize(&sblock, dp, lastbn + 1)); 537 if (bp->b_errs) 538 goto bad; 539 bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 540 bp = getdirblk(newblk, sblock.fs_bsize); 541 if (bp->b_errs) 542 goto bad; 543 bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 544 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 545 cp < &bp->b_un.b_buf[sblock.fs_bsize]; 546 cp += DIRBLKSIZ) 547 bcopy((char *)&emptydir, cp, sizeof emptydir); 548 dirty(bp); 549 bp = getdirblk(dp->di_db[lastbn + 1], 550 (long)dblksize(&sblock, dp, lastbn + 1)); 551 if (bp->b_errs) 552 goto bad; 553 bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 554 pwarn("NO SPACE LEFT IN %s", name); 555 if (preen) 556 printf(" (EXPANDED)\n"); 557 else if (reply("EXPAND") == 0) 558 goto bad; 559 dirty(bp); 560 inodirty(); 561 return (1); 562 bad: 563 dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 564 dp->di_db[lastbn + 1] = 0; 565 dp->di_size -= sblock.fs_bsize; 566 dp->di_blocks -= btodb(sblock.fs_bsize); 567 freeblk(newblk, sblock.fs_frag); 568 return (0); 569 } 570 571 /* 572 * allocate a new directory 573 */ 574 allocdir(parent, request, mode) 575 ino_t parent, request; 576 int mode; 577 { 578 ino_t ino; 579 char *cp; 580 struct dinode *dp; 581 register struct bufarea *bp; 582 struct dirtemplate *dirp; 583 584 ino = allocino(request, IFDIR|mode); 585 if (newinofmt) 586 dirp = &dirhead; 587 else 588 dirp = (struct dirtemplate *)&odirhead; 589 dirp->dot_ino = ino; 590 dirp->dotdot_ino = parent; 591 dp = ginode(ino); 592 bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 593 if (bp->b_errs) { 594 freeino(ino); 595 return (0); 596 } 597 bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate)); 598 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 599 cp < &bp->b_un.b_buf[sblock.fs_fsize]; 600 cp += DIRBLKSIZ) 601 bcopy((char *)&emptydir, cp, sizeof emptydir); 602 dirty(bp); 603 dp->di_nlink = 2; 604 inodirty(); 605 if (ino == ROOTINO) { 606 lncntp[ino] = dp->di_nlink; 607 cacheino(dp, ino); 608 return(ino); 609 } 610 if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 611 freeino(ino); 612 return (0); 613 } 614 cacheino(dp, ino); 615 statemap[ino] = statemap[parent]; 616 if (statemap[ino] == DSTATE) { 617 lncntp[ino] = dp->di_nlink; 618 lncntp[parent]++; 619 } 620 dp = ginode(parent); 621 dp->di_nlink++; 622 inodirty(); 623 return (ino); 624 } 625 626 /* 627 * free a directory inode 628 */ 629 freedir(ino, parent) 630 ino_t ino, parent; 631 { 632 struct dinode *dp; 633 634 if (ino != parent) { 635 dp = ginode(parent); 636 dp->di_nlink--; 637 inodirty(); 638 } 639 freeino(ino); 640 } 641 642 /* 643 * generate a temporary name for the lost+found directory. 644 */ 645 lftempname(bufp, ino) 646 char *bufp; 647 ino_t ino; 648 { 649 register ino_t in; 650 register char *cp; 651 int namlen; 652 653 cp = bufp + 2; 654 for (in = maxino; in > 0; in /= 10) 655 cp++; 656 *--cp = 0; 657 namlen = cp - bufp; 658 in = ino; 659 while (cp > bufp) { 660 *--cp = (in % 10) + '0'; 661 in /= 10; 662 } 663 *cp = '#'; 664 return (namlen); 665 } 666 667 /* 668 * Get a directory block. 669 * Insure that it is held until another is requested. 670 */ 671 struct bufarea * 672 getdirblk(blkno, size) 673 daddr_t blkno; 674 long size; 675 { 676 677 if (pdirbp != 0) 678 pdirbp->b_flags &= ~B_INUSE; 679 pdirbp = getdatablk(blkno, size); 680 return (pdirbp); 681 } 682