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 if (preen == 0) 478 printf("\n"); 479 } 480 return (1); 481 } 482 483 /* 484 * fix an entry in a directory. 485 */ 486 int 487 changeino(dir, name, newnum) 488 ino_t dir; 489 char *name; 490 ino_t newnum; 491 { 492 struct inodesc idesc; 493 494 bzero((char *)&idesc, sizeof(struct inodesc)); 495 idesc.id_type = DATA; 496 idesc.id_func = chgino; 497 idesc.id_number = dir; 498 idesc.id_fix = DONTKNOW; 499 idesc.id_name = name; 500 idesc.id_parent = newnum; /* new value for name */ 501 return (ckinode(ginode(dir), &idesc)); 502 } 503 504 /* 505 * make an entry in a directory 506 */ 507 int 508 makeentry(parent, ino, name) 509 ino_t parent, ino; 510 char *name; 511 { 512 struct dinode *dp; 513 struct inodesc idesc; 514 char pathbuf[MAXPATHLEN + 1]; 515 516 if (parent < ROOTINO || parent >= maxino || 517 ino < ROOTINO || ino >= maxino) 518 return (0); 519 bzero((char *)&idesc, sizeof(struct inodesc)); 520 idesc.id_type = DATA; 521 idesc.id_func = mkentry; 522 idesc.id_number = parent; 523 idesc.id_parent = ino; /* this is the inode to enter */ 524 idesc.id_fix = DONTKNOW; 525 idesc.id_name = name; 526 dp = ginode(parent); 527 if (dp->di_size % DIRBLKSIZ) { 528 dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 529 inodirty(); 530 } 531 if ((ckinode(dp, &idesc) & ALTERED) != 0) 532 return (1); 533 getpathname(pathbuf, parent, parent); 534 dp = ginode(parent); 535 if (expanddir(dp, pathbuf) == 0) 536 return (0); 537 return (ckinode(dp, &idesc) & ALTERED); 538 } 539 540 /* 541 * Attempt to expand the size of a directory 542 */ 543 int 544 expanddir(dp, name) 545 register struct dinode *dp; 546 char *name; 547 { 548 daddr_t lastbn, newblk; 549 register struct bufarea *bp; 550 char *cp, firstblk[DIRBLKSIZ]; 551 552 lastbn = lblkno(&sblock, dp->di_size); 553 if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 554 return (0); 555 if ((newblk = allocblk(sblock.fs_frag)) == 0) 556 return (0); 557 dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 558 dp->di_db[lastbn] = newblk; 559 dp->di_size += sblock.fs_bsize; 560 dp->di_blocks += btodb(sblock.fs_bsize); 561 bp = getdirblk(dp->di_db[lastbn + 1], 562 (long)dblksize(&sblock, dp, lastbn + 1)); 563 if (bp->b_errs) 564 goto bad; 565 bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 566 bp = getdirblk(newblk, sblock.fs_bsize); 567 if (bp->b_errs) 568 goto bad; 569 bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 570 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 571 cp < &bp->b_un.b_buf[sblock.fs_bsize]; 572 cp += DIRBLKSIZ) 573 bcopy((char *)&emptydir, cp, sizeof emptydir); 574 dirty(bp); 575 bp = getdirblk(dp->di_db[lastbn + 1], 576 (long)dblksize(&sblock, dp, lastbn + 1)); 577 if (bp->b_errs) 578 goto bad; 579 bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir); 580 pwarn("NO SPACE LEFT IN %s", name); 581 if (preen) 582 printf(" (EXPANDED)\n"); 583 else if (reply("EXPAND") == 0) 584 goto bad; 585 dirty(bp); 586 inodirty(); 587 return (1); 588 bad: 589 dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 590 dp->di_db[lastbn + 1] = 0; 591 dp->di_size -= sblock.fs_bsize; 592 dp->di_blocks -= btodb(sblock.fs_bsize); 593 freeblk(newblk, sblock.fs_frag); 594 return (0); 595 } 596 597 /* 598 * allocate a new directory 599 */ 600 ino_t 601 allocdir(parent, request, mode) 602 ino_t parent, request; 603 int mode; 604 { 605 ino_t ino; 606 char *cp; 607 struct dinode *dp; 608 register struct bufarea *bp; 609 struct dirtemplate *dirp; 610 611 ino = allocino(request, IFDIR|mode); 612 if (newinofmt) 613 dirp = &dirhead; 614 else 615 dirp = (struct dirtemplate *)&odirhead; 616 dirp->dot_ino = ino; 617 dirp->dotdot_ino = parent; 618 dp = ginode(ino); 619 bp = getdirblk(dp->di_db[0], sblock.fs_fsize); 620 if (bp->b_errs) { 621 freeino(ino); 622 return (0); 623 } 624 bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate)); 625 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 626 cp < &bp->b_un.b_buf[sblock.fs_fsize]; 627 cp += DIRBLKSIZ) 628 bcopy((char *)&emptydir, cp, sizeof emptydir); 629 dirty(bp); 630 dp->di_nlink = 2; 631 inodirty(); 632 if (ino == ROOTINO) { 633 lncntp[ino] = dp->di_nlink; 634 cacheino(dp, ino); 635 return(ino); 636 } 637 if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 638 freeino(ino); 639 return (0); 640 } 641 cacheino(dp, ino); 642 statemap[ino] = statemap[parent]; 643 if (statemap[ino] == DSTATE) { 644 lncntp[ino] = dp->di_nlink; 645 lncntp[parent]++; 646 } 647 dp = ginode(parent); 648 dp->di_nlink++; 649 inodirty(); 650 return (ino); 651 } 652 653 /* 654 * free a directory inode 655 */ 656 static void 657 freedir(ino, parent) 658 ino_t ino, parent; 659 { 660 struct dinode *dp; 661 662 if (ino != parent) { 663 dp = ginode(parent); 664 dp->di_nlink--; 665 inodirty(); 666 } 667 freeino(ino); 668 } 669 670 /* 671 * generate a temporary name for the lost+found directory. 672 */ 673 int 674 lftempname(bufp, ino) 675 char *bufp; 676 ino_t ino; 677 { 678 register ino_t in; 679 register char *cp; 680 int namlen; 681 682 cp = bufp + 2; 683 for (in = maxino; in > 0; in /= 10) 684 cp++; 685 *--cp = 0; 686 namlen = cp - bufp; 687 in = ino; 688 while (cp > bufp) { 689 *--cp = (in % 10) + '0'; 690 in /= 10; 691 } 692 *cp = '#'; 693 return (namlen); 694 } 695 696 /* 697 * Get a directory block. 698 * Insure that it is held until another is requested. 699 */ 700 struct bufarea * 701 getdirblk(blkno, size) 702 daddr_t blkno; 703 long size; 704 { 705 706 if (pdirbp != 0) 707 pdirbp->b_flags &= ~B_INUSE; 708 pdirbp = getdatablk(blkno, size); 709 return (pdirbp); 710 } 711