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[] = "from: @(#)dir.c 8.1 (Berkeley) 6/5/93";*/ 36 static char *rcsid = "$Id: dir.c,v 1.15 1994/12/05 20:15:44 cgd Exp $"; 37 #endif /* not lint */ 38 39 #include <sys/param.h> 40 #include <sys/time.h> 41 #include <ufs/ufs/dinode.h> 42 #include <ufs/ufs/dir.h> 43 #include <ufs/ffs/fs.h> 44 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 49 #include "fsck.h" 50 #include "extern.h" 51 52 char *lfname = "lost+found"; 53 int lfmode = 01777; 54 struct dirtemplate emptydir = { 0, DIRBLKSIZ }; 55 struct dirtemplate dirhead = { 56 0, 12, DT_DIR, 1, ".", 57 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 58 }; 59 struct odirtemplate odirhead = { 60 0, 12, 1, ".", 61 0, DIRBLKSIZ - 12, 2, ".." 62 }; 63 64 int expanddir __P((struct dinode *, char *)); 65 void freedir __P((ino_t, ino_t)); 66 struct direct *fsck_readdir(); 67 struct bufarea *getdirblk(); 68 int lftempname __P((char *, ino_t)); 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 memcpy(dbuf, dp, (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 memcpy(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 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 if (idesc->id_fix == IGNORE) 177 return (0); 178 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 179 bp = getdirblk(idesc->id_blkno, blksiz); 180 dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 181 dp->d_reclen = DIRBLKSIZ; 182 dp->d_ino = 0; 183 dp->d_type = 0; 184 dp->d_namlen = 0; 185 dp->d_name[0] = '\0'; 186 if (fix) 187 dirty(bp); 188 idesc->id_loc += DIRBLKSIZ; 189 idesc->id_filesize -= DIRBLKSIZ; 190 return (dp); 191 } 192 dpok: 193 if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 194 return NULL; 195 dploc = idesc->id_loc; 196 dp = (struct direct *)(bp->b_un.b_buf + dploc); 197 idesc->id_loc += dp->d_reclen; 198 idesc->id_filesize -= dp->d_reclen; 199 if ((idesc->id_loc % DIRBLKSIZ) == 0) 200 return (dp); 201 ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 202 if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 203 dircheck(idesc, ndp) == 0) { 204 size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 205 idesc->id_loc += size; 206 idesc->id_filesize -= size; 207 if (idesc->id_fix == IGNORE) 208 return (0); 209 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 210 bp = getdirblk(idesc->id_blkno, blksiz); 211 dp = (struct direct *)(bp->b_un.b_buf + dploc); 212 dp->d_reclen += size; 213 if (fix) 214 dirty(bp); 215 } 216 return (dp); 217 } 218 219 /* 220 * Verify that a directory entry is valid. 221 * This is a superset of the checks made in the kernel. 222 */ 223 int 224 dircheck(idesc, dp) 225 struct inodesc *idesc; 226 register struct direct *dp; 227 { 228 register int size; 229 register char *cp; 230 u_char namlen, type; 231 int spaceleft; 232 233 spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 234 if (dp->d_ino >= maxino || 235 dp->d_reclen == 0 || 236 dp->d_reclen > spaceleft || 237 (dp->d_reclen & 0x3) != 0) 238 return (0); 239 if (dp->d_ino == 0) 240 return (1); 241 size = DIRSIZ(!newinofmt, dp); 242 # if (BYTE_ORDER == LITTLE_ENDIAN) 243 if (!newinofmt) { 244 type = dp->d_namlen; 245 namlen = dp->d_type; 246 } else { 247 namlen = dp->d_namlen; 248 type = dp->d_type; 249 } 250 # else 251 namlen = dp->d_namlen; 252 type = dp->d_type; 253 # endif 254 if (dp->d_reclen < size || 255 idesc->id_filesize < size || 256 namlen > MAXNAMLEN || 257 type > 15) 258 return (0); 259 for (cp = dp->d_name, size = 0; size < namlen; size++) 260 if (*cp == '\0' || (*cp++ == '/')) 261 return (0); 262 if (*cp != '\0') 263 return (0); 264 return (1); 265 } 266 267 void 268 direrror(ino, errmesg) 269 ino_t ino; 270 char *errmesg; 271 { 272 273 fileerror(ino, ino, errmesg); 274 } 275 276 void 277 fileerror(cwd, ino, errmesg) 278 ino_t cwd, ino; 279 char *errmesg; 280 { 281 register struct dinode *dp; 282 char pathbuf[MAXPATHLEN + 1]; 283 284 pwarn("%s ", errmesg); 285 pinode(ino); 286 printf("\n"); 287 getpathname(pathbuf, cwd, ino); 288 if (ino < ROOTINO || ino > maxino) { 289 pfatal("NAME=%s\n", pathbuf); 290 return; 291 } 292 dp = ginode(ino); 293 if (ftypeok(dp)) 294 pfatal("%s=%s\n", 295 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 296 else 297 pfatal("NAME=%s\n", pathbuf); 298 } 299 300 void 301 adjust(idesc, lcnt) 302 register struct inodesc *idesc; 303 short lcnt; 304 { 305 register struct dinode *dp; 306 307 dp = ginode(idesc->id_number); 308 if (dp->di_nlink == lcnt) { 309 if (linkup(idesc->id_number, (ino_t)0) == 0) 310 clri(idesc, "UNREF", 0); 311 } else { 312 pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 313 ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 314 pinode(idesc->id_number); 315 printf(" COUNT %d SHOULD BE %d", 316 dp->di_nlink, dp->di_nlink - lcnt); 317 if (preen) { 318 if (lcnt < 0) { 319 printf("\n"); 320 pfatal("LINK COUNT INCREASING"); 321 } 322 printf(" (ADJUSTED)\n"); 323 } 324 if (preen || reply("ADJUST") == 1) { 325 dp->di_nlink -= lcnt; 326 inodirty(); 327 } 328 } 329 } 330 331 int 332 mkentry(idesc) 333 struct inodesc *idesc; 334 { 335 register struct direct *dirp = idesc->id_dirp; 336 struct direct newent; 337 int newlen, oldlen; 338 339 newent.d_namlen = strlen(idesc->id_name); 340 newlen = DIRSIZ(0, &newent); 341 if (dirp->d_ino != 0) 342 oldlen = DIRSIZ(0, dirp); 343 else 344 oldlen = 0; 345 if (dirp->d_reclen - oldlen < newlen) 346 return (KEEPON); 347 newent.d_reclen = dirp->d_reclen - oldlen; 348 dirp->d_reclen = oldlen; 349 dirp = (struct direct *)(((char *)dirp) + oldlen); 350 dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 351 if (newinofmt) 352 dirp->d_type = typemap[idesc->id_parent]; 353 else 354 dirp->d_type = 0; 355 dirp->d_reclen = newent.d_reclen; 356 dirp->d_namlen = newent.d_namlen; 357 memcpy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1); 358 # if (BYTE_ORDER == LITTLE_ENDIAN) 359 /* 360 * If the entry was split, dirscan() will only reverse the byte 361 * order of the original entry, and not the new one, before 362 * writing it back out. So, we reverse the byte order here if 363 * necessary. 364 */ 365 if (oldlen != 0 && !newinofmt && !doinglevel2) { 366 u_char tmp; 367 368 tmp = dirp->d_namlen; 369 dirp->d_namlen = dirp->d_type; 370 dirp->d_type = tmp; 371 } 372 # endif 373 return (ALTERED|STOP); 374 } 375 376 int 377 chgino(idesc) 378 struct inodesc *idesc; 379 { 380 register struct direct *dirp = idesc->id_dirp; 381 382 if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 383 return (KEEPON); 384 dirp->d_ino = idesc->id_parent; 385 if (newinofmt) 386 dirp->d_type = typemap[idesc->id_parent]; 387 else 388 dirp->d_type = 0; 389 return (ALTERED|STOP); 390 } 391 392 int 393 linkup(orphan, parentdir) 394 ino_t orphan; 395 ino_t parentdir; 396 { 397 register struct dinode *dp; 398 int lostdir; 399 ino_t oldlfdir; 400 struct inodesc idesc; 401 char tempname[BUFSIZ]; 402 403 memset(&idesc, 0, sizeof(struct inodesc)); 404 dp = ginode(orphan); 405 lostdir = (dp->di_mode & IFMT) == IFDIR; 406 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 407 pinode(orphan); 408 if (preen && dp->di_size == 0) 409 return (0); 410 if (preen) 411 printf(" (RECONNECTED)\n"); 412 else 413 if (reply("RECONNECT") == 0) 414 return (0); 415 if (lfdir == 0) { 416 dp = ginode(ROOTINO); 417 idesc.id_name = lfname; 418 idesc.id_type = DATA; 419 idesc.id_func = findino; 420 idesc.id_number = ROOTINO; 421 if ((ckinode(dp, &idesc) & FOUND) != 0) { 422 lfdir = idesc.id_parent; 423 } else { 424 pwarn("NO lost+found DIRECTORY"); 425 if (preen || reply("CREATE")) { 426 lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 427 if (lfdir != 0) { 428 if (makeentry(ROOTINO, lfdir, lfname) != 0) { 429 if (preen) 430 printf(" (CREATED)\n"); 431 } else { 432 freedir(lfdir, ROOTINO); 433 lfdir = 0; 434 if (preen) 435 printf("\n"); 436 } 437 } 438 } 439 } 440 if (lfdir == 0) { 441 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 442 printf("\n\n"); 443 return (0); 444 } 445 } 446 dp = ginode(lfdir); 447 if ((dp->di_mode & IFMT) != IFDIR) { 448 pfatal("lost+found IS NOT A DIRECTORY"); 449 if (reply("REALLOCATE") == 0) 450 return (0); 451 oldlfdir = lfdir; 452 if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 453 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 454 return (0); 455 } 456 if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 457 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 458 return (0); 459 } 460 inodirty(); 461 idesc.id_type = ADDR; 462 idesc.id_func = pass4check; 463 idesc.id_number = oldlfdir; 464 adjust(&idesc, lncntp[oldlfdir] + 1); 465 lncntp[oldlfdir] = 0; 466 dp = ginode(lfdir); 467 } 468 if (statemap[lfdir] != DFOUND) { 469 pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 470 return (0); 471 } 472 (void)lftempname(tempname, orphan); 473 if (makeentry(lfdir, orphan, tempname) == 0) { 474 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 475 printf("\n\n"); 476 return (0); 477 } 478 lncntp[orphan]--; 479 if (lostdir) { 480 if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 481 parentdir != (ino_t)-1) 482 (void)makeentry(orphan, lfdir, ".."); 483 dp = ginode(lfdir); 484 dp->di_nlink++; 485 inodirty(); 486 lncntp[lfdir]++; 487 pwarn("DIR I=%lu CONNECTED. ", orphan); 488 if (parentdir != (ino_t)-1) 489 printf("PARENT WAS I=%lu\n", parentdir); 490 if (preen == 0) 491 printf("\n"); 492 } 493 return (1); 494 } 495 496 /* 497 * fix an entry in a directory. 498 */ 499 int 500 changeino(dir, name, newnum) 501 ino_t dir; 502 char *name; 503 ino_t newnum; 504 { 505 struct inodesc idesc; 506 507 memset(&idesc, 0, sizeof(struct inodesc)); 508 idesc.id_type = DATA; 509 idesc.id_func = chgino; 510 idesc.id_number = dir; 511 idesc.id_fix = DONTKNOW; 512 idesc.id_name = name; 513 idesc.id_parent = newnum; /* new value for name */ 514 return (ckinode(ginode(dir), &idesc)); 515 } 516 517 /* 518 * make an entry in a directory 519 */ 520 int 521 makeentry(parent, ino, name) 522 ino_t parent, ino; 523 char *name; 524 { 525 struct dinode *dp; 526 struct inodesc idesc; 527 char pathbuf[MAXPATHLEN + 1]; 528 529 if (parent < ROOTINO || parent >= maxino || 530 ino < ROOTINO || ino >= maxino) 531 return (0); 532 memset(&idesc, 0, sizeof(struct inodesc)); 533 idesc.id_type = DATA; 534 idesc.id_func = mkentry; 535 idesc.id_number = parent; 536 idesc.id_parent = ino; /* this is the inode to enter */ 537 idesc.id_fix = DONTKNOW; 538 idesc.id_name = name; 539 dp = ginode(parent); 540 if (dp->di_size % DIRBLKSIZ) { 541 dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 542 inodirty(); 543 } 544 if ((ckinode(dp, &idesc) & ALTERED) != 0) 545 return (1); 546 getpathname(pathbuf, parent, parent); 547 dp = ginode(parent); 548 if (expanddir(dp, pathbuf) == 0) 549 return (0); 550 return (ckinode(dp, &idesc) & ALTERED); 551 } 552 553 /* 554 * Attempt to expand the size of a directory 555 */ 556 int 557 expanddir(dp, name) 558 register struct dinode *dp; 559 char *name; 560 { 561 daddr_t lastbn, newblk; 562 register struct bufarea *bp; 563 char *cp, firstblk[DIRBLKSIZ]; 564 565 lastbn = lblkno(&sblock, dp->di_size); 566 if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 567 return (0); 568 if ((newblk = allocblk(sblock.fs_frag)) == 0) 569 return (0); 570 dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 571 dp->di_db[lastbn] = newblk; 572 dp->di_size += sblock.fs_bsize; 573 dp->di_blocks += btodb(sblock.fs_bsize); 574 bp = getdirblk(dp->di_db[lastbn + 1], 575 (long)dblksize(&sblock, dp, lastbn + 1)); 576 if (bp->b_errs) 577 goto bad; 578 memcpy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 579 bp = getdirblk(newblk, sblock.fs_bsize); 580 if (bp->b_errs) 581 goto bad; 582 memcpy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 583 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 584 cp < &bp->b_un.b_buf[sblock.fs_bsize]; 585 cp += DIRBLKSIZ) 586 memcpy(cp, &emptydir, sizeof emptydir); 587 dirty(bp); 588 bp = getdirblk(dp->di_db[lastbn + 1], 589 (long)dblksize(&sblock, dp, lastbn + 1)); 590 if (bp->b_errs) 591 goto bad; 592 memcpy(bp->b_un.b_buf, &emptydir, sizeof emptydir); 593 pwarn("NO SPACE LEFT IN %s", name); 594 if (preen) 595 printf(" (EXPANDED)\n"); 596 else if (reply("EXPAND") == 0) 597 goto bad; 598 dirty(bp); 599 inodirty(); 600 return (1); 601 bad: 602 dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 603 dp->di_db[lastbn + 1] = 0; 604 dp->di_size -= sblock.fs_bsize; 605 dp->di_blocks -= btodb(sblock.fs_bsize); 606 freeblk(newblk, sblock.fs_frag); 607 return (0); 608 } 609 610 /* 611 * allocate a new directory 612 */ 613 int 614 allocdir(parent, request, mode) 615 ino_t parent, request; 616 int mode; 617 { 618 ino_t ino; 619 char *cp; 620 struct dinode *dp; 621 register struct bufarea *bp; 622 struct dirtemplate *dirp; 623 624 ino = allocino(request, IFDIR|mode); 625 if (newinofmt) 626 dirp = &dirhead; 627 else 628 dirp = (struct dirtemplate *)&odirhead; 629 dirp->dot_ino = ino; 630 dirp->dotdot_ino = parent; 631 dp = ginode(ino); 632 bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 633 if (bp->b_errs) { 634 freeino(ino); 635 return (0); 636 } 637 memcpy(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 638 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 639 cp < &bp->b_un.b_buf[sblock.fs_fsize]; 640 cp += DIRBLKSIZ) 641 memcpy(cp, &emptydir, sizeof emptydir); 642 dirty(bp); 643 dp->di_nlink = 2; 644 inodirty(); 645 if (ino == ROOTINO) { 646 lncntp[ino] = dp->di_nlink; 647 cacheino(dp, ino); 648 return(ino); 649 } 650 if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 651 freeino(ino); 652 return (0); 653 } 654 cacheino(dp, ino); 655 statemap[ino] = statemap[parent]; 656 if (statemap[ino] == DSTATE) { 657 lncntp[ino] = dp->di_nlink; 658 lncntp[parent]++; 659 } 660 dp = ginode(parent); 661 dp->di_nlink++; 662 inodirty(); 663 return (ino); 664 } 665 666 /* 667 * free a directory inode 668 */ 669 void 670 freedir(ino, parent) 671 ino_t ino, parent; 672 { 673 struct dinode *dp; 674 675 if (ino != parent) { 676 dp = ginode(parent); 677 dp->di_nlink--; 678 inodirty(); 679 } 680 freeino(ino); 681 } 682 683 /* 684 * generate a temporary name for the lost+found directory. 685 */ 686 int 687 lftempname(bufp, ino) 688 char *bufp; 689 ino_t ino; 690 { 691 register ino_t in; 692 register char *cp; 693 int namlen; 694 695 cp = bufp + 2; 696 for (in = maxino; in > 0; in /= 10) 697 cp++; 698 *--cp = 0; 699 namlen = cp - bufp; 700 in = ino; 701 while (cp > bufp) { 702 *--cp = (in % 10) + '0'; 703 in /= 10; 704 } 705 *cp = '#'; 706 return (namlen); 707 } 708 709 /* 710 * Get a directory block. 711 * Insure that it is held until another is requested. 712 */ 713 struct bufarea * 714 getdirblk(blkno, size) 715 daddr_t blkno; 716 long size; 717 { 718 719 if (pdirbp != 0) 720 pdirbp->b_flags &= ~B_INUSE; 721 pdirbp = getdatablk(blkno, size); 722 return (pdirbp); 723 } 724