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