1 /* $NetBSD: dir.c,v 1.5 2001/07/13 20:30:18 perseant Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/param.h> 37 #include <sys/time.h> 38 #include <ufs/ufs/dinode.h> 39 #include <ufs/ufs/dir.h> 40 #include <sys/mount.h> /* XXX */ 41 #include <ufs/lfs/lfs.h> 42 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 47 #include "fsck.h" 48 #include "fsutil.h" 49 #include "extern.h" 50 51 char *lfname = "lost+found"; 52 int lfmode = 01700; 53 struct dirtemplate emptydir = {0, DIRBLKSIZ}; 54 struct dirtemplate dirhead = { 55 0, 12, DT_DIR, 1, ".", 56 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 57 }; 58 struct odirtemplate odirhead = { 59 0, 12, 1, ".", 60 0, DIRBLKSIZ - 12, 2, ".." 61 }; 62 63 static int expanddir(struct dinode *, char *); 64 static void freedir(ino_t, ino_t); 65 static struct direct *fsck_readdir(struct inodesc *); 66 static struct bufarea *getdirblk(daddr_t, long); 67 static int lftempname(char *, ino_t); 68 static int mkentry(struct inodesc *); 69 static int chgino(struct inodesc *); 70 71 /* 72 * Propagate connected state through the tree. 73 */ 74 void 75 propagate() 76 { 77 register struct inoinfo **inpp, *inp, *pinp; 78 struct inoinfo **inpend; 79 80 /* 81 * Create a list of children for each directory. 82 */ 83 inpend = &inpsort[inplast]; 84 for (inpp = inpsort; inpp < inpend; inpp++) { 85 inp = *inpp; 86 if (inp->i_parent == 0 || 87 inp->i_number == ROOTINO) 88 continue; 89 pinp = getinoinfo(inp->i_parent); 90 inp->i_parentp = pinp; 91 inp->i_sibling = pinp->i_child; 92 pinp->i_child = inp; 93 } 94 inp = getinoinfo(ROOTINO); 95 while (inp) { 96 statemap[inp->i_number] = DFOUND; 97 if (inp->i_child && 98 statemap[inp->i_child->i_number] == DSTATE) 99 inp = inp->i_child; 100 else if (inp->i_sibling) 101 inp = inp->i_sibling; 102 else 103 inp = inp->i_parentp; 104 } 105 } 106 107 /* 108 * Scan each entry in a directory block. 109 */ 110 int 111 dirscan(struct inodesc * idesc) 112 { 113 register struct direct *dp; 114 register struct bufarea *bp; 115 int dsize, n; 116 long blksiz; 117 char dbuf[DIRBLKSIZ]; 118 119 if (idesc->id_type != DATA) 120 errexit("wrong type to dirscan %d\n", idesc->id_type); 121 if (idesc->id_entryno == 0 && 122 (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 123 idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 124 blksiz = idesc->id_numfrags * sblock.lfs_fsize; 125 if (chkrange(idesc->id_blkno, fragstofsb(&sblock, idesc->id_numfrags))) { 126 idesc->id_filesize -= blksiz; 127 return (SKIP); 128 } 129 idesc->id_loc = 0; 130 for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 131 dsize = dp->d_reclen; 132 memcpy(dbuf, dp, (size_t)dsize); 133 # if (BYTE_ORDER == LITTLE_ENDIAN) 134 if (!newinofmt) { 135 struct direct *tdp = (struct direct *)dbuf; 136 u_char tmp; 137 138 tmp = tdp->d_namlen; 139 tdp->d_namlen = tdp->d_type; 140 tdp->d_type = tmp; 141 } 142 # endif 143 idesc->id_dirp = (struct direct *)dbuf; 144 if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 145 # if (BYTE_ORDER == LITTLE_ENDIAN) 146 if (!newinofmt && !doinglevel2) { 147 struct direct *tdp; 148 u_char tmp; 149 150 tdp = (struct direct *)dbuf; 151 tmp = tdp->d_namlen; 152 tdp->d_namlen = tdp->d_type; 153 tdp->d_type = tmp; 154 } 155 # endif 156 bp = getdirblk(idesc->id_blkno, blksiz); 157 memcpy(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 158 (size_t)dsize); 159 dirty(bp); 160 sbdirty(); 161 } 162 if (n & STOP) 163 return (n); 164 } 165 return (idesc->id_filesize > 0 ? KEEPON : STOP); 166 } 167 168 /* 169 * get next entry in a directory. 170 */ 171 static struct direct * 172 fsck_readdir(struct inodesc * idesc) 173 { 174 register struct direct *dp, *ndp; 175 register struct bufarea *bp; 176 long size, blksiz, fix, dploc; 177 178 blksiz = idesc->id_numfrags * sblock.lfs_fsize; 179 bp = getdirblk(idesc->id_blkno, blksiz); 180 if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 181 idesc->id_loc < blksiz) { 182 dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 183 if (dircheck(idesc, dp)) 184 goto dpok; 185 if (idesc->id_fix == IGNORE) 186 return (0); 187 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 188 bp = getdirblk(idesc->id_blkno, blksiz); 189 dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 190 dp->d_reclen = DIRBLKSIZ; 191 dp->d_ino = 0; 192 dp->d_type = 0; 193 dp->d_namlen = 0; 194 dp->d_name[0] = '\0'; 195 if (fix) 196 dirty(bp); 197 idesc->id_loc += DIRBLKSIZ; 198 idesc->id_filesize -= DIRBLKSIZ; 199 return (dp); 200 } 201 dpok: 202 if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 203 return NULL; 204 dploc = idesc->id_loc; 205 dp = (struct direct *)(bp->b_un.b_buf + dploc); 206 idesc->id_loc += dp->d_reclen; 207 idesc->id_filesize -= dp->d_reclen; 208 if ((idesc->id_loc % DIRBLKSIZ) == 0) 209 return (dp); 210 ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 211 if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 212 dircheck(idesc, ndp) == 0) { 213 size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 214 idesc->id_loc += size; 215 idesc->id_filesize -= size; 216 if (idesc->id_fix == IGNORE) 217 return (0); 218 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 219 bp = getdirblk(idesc->id_blkno, blksiz); 220 dp = (struct direct *)(bp->b_un.b_buf + dploc); 221 dp->d_reclen += size; 222 if (fix) 223 dirty(bp); 224 } 225 return (dp); 226 } 227 228 /* 229 * Verify that a directory entry is valid. 230 * This is a superset of the checks made in the kernel. 231 */ 232 int 233 dircheck(struct inodesc * idesc, struct direct * dp) 234 { 235 register int size; 236 register char *cp; 237 u_char namlen, type; 238 int spaceleft; 239 240 spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 241 if (dp->d_ino >= maxino || 242 dp->d_reclen == 0 || 243 dp->d_reclen > spaceleft || 244 (dp->d_reclen & 0x3) != 0) { 245 pwarn("ino too large, reclen=0, reclen>space, or reclen&3!=0\n"); 246 pwarn("dp->d_ino = 0x%x\tdp->d_reclen = 0x%x\n", 247 dp->d_ino, dp->d_reclen); 248 pwarn("maxino = 0x%x\tspaceleft = 0x%x\n", maxino, spaceleft); 249 return (0); 250 } 251 if (dp->d_ino == 0) 252 return (1); 253 size = DIRSIZ(!newinofmt, dp, 0); 254 # if (BYTE_ORDER == LITTLE_ENDIAN) 255 if (!newinofmt) { 256 type = dp->d_namlen; 257 namlen = dp->d_type; 258 } else { 259 namlen = dp->d_namlen; 260 type = dp->d_type; 261 } 262 # else 263 namlen = dp->d_namlen; 264 type = dp->d_type; 265 # endif 266 if (dp->d_reclen < size || 267 idesc->id_filesize < size || 268 namlen > MAXNAMLEN || 269 type > 15) { 270 printf("reclen<size, filesize<size, namlen too large, or type>15\n"); 271 return (0); 272 } 273 for (cp = dp->d_name, size = 0; size < namlen; size++) 274 if (*cp == '\0' || (*cp++ == '/')) { 275 printf("name contains NUL or /\n"); 276 return (0); 277 } 278 if (*cp != '\0') { 279 printf("name size misstated\n"); 280 return (0); 281 } 282 return (1); 283 } 284 285 void 286 direrror(ino_t ino, char *errmesg) 287 { 288 289 fileerror(ino, ino, errmesg); 290 } 291 292 void 293 fileerror(ino_t cwd, ino_t ino, char *errmesg) 294 { 295 register struct dinode *dp; 296 char pathbuf[MAXPATHLEN + 1]; 297 298 pwarn("%s ", errmesg); 299 pinode(ino); 300 printf("\n"); 301 getpathname(pathbuf, cwd, ino); 302 if (ino < ROOTINO || ino >= maxino) { 303 pfatal("NAME=%s\n", pathbuf); 304 return; 305 } 306 dp = ginode(ino); 307 if (dp == NULL) 308 pfatal("INO is NULL\n"); 309 else { 310 if (ftypeok(dp)) 311 pfatal("%s=%s\n", 312 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); 313 else 314 pfatal("NAME=%s\n", pathbuf); 315 } 316 } 317 318 void 319 adjust(struct inodesc * idesc, short lcnt) 320 { 321 register struct dinode *dp; 322 323 dp = ginode(idesc->id_number); 324 if (dp->di_nlink == lcnt) { 325 if (linkup(idesc->id_number, (ino_t)0) == 0) 326 clri(idesc, "UNREF", 0); 327 } else { 328 pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 329 ((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE")); 330 pinode(idesc->id_number); 331 printf(" COUNT %d SHOULD BE %d", 332 dp->di_nlink, dp->di_nlink - lcnt); 333 if (preen) { 334 if (lcnt < 0) { 335 printf("\n"); 336 pfatal("LINK COUNT INCREASING"); 337 } 338 printf(" (ADJUSTED)\n"); 339 } 340 if (preen || reply("ADJUST") == 1) { 341 dp->di_nlink -= lcnt; 342 inodirty(); 343 } 344 } 345 } 346 347 static int 348 mkentry(struct inodesc * idesc) 349 { 350 register struct direct *dirp = idesc->id_dirp; 351 struct direct newent; 352 int newlen, oldlen; 353 354 newent.d_namlen = strlen(idesc->id_name); 355 newlen = DIRSIZ(0, &newent, 0); 356 if (dirp->d_ino != 0) 357 oldlen = DIRSIZ(0, dirp, 0); 358 else 359 oldlen = 0; 360 if (dirp->d_reclen - oldlen < newlen) 361 return (KEEPON); 362 newent.d_reclen = dirp->d_reclen - oldlen; 363 dirp->d_reclen = oldlen; 364 dirp = (struct direct *)(((char *)dirp) + oldlen); 365 dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 366 dirp->d_reclen = newent.d_reclen; 367 if (newinofmt) 368 dirp->d_type = typemap[idesc->id_parent]; 369 else 370 dirp->d_type = 0; 371 dirp->d_namlen = newent.d_namlen; 372 memcpy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1); 373 # if (BYTE_ORDER == LITTLE_ENDIAN) 374 /* 375 * If the entry was split, dirscan()will only reverse the byte 376 * order of the original entry, and not the new one, before 377 * writing it back out. So, we reverse the byte order here if 378 * necessary. 379 */ 380 if (oldlen != 0 && !newinofmt && !doinglevel2) { 381 u_char tmp; 382 383 tmp = dirp->d_namlen; 384 dirp->d_namlen = dirp->d_type; 385 dirp->d_type = tmp; 386 } 387 # endif 388 return (ALTERED | STOP); 389 } 390 391 static int 392 chgino(struct inodesc * idesc) 393 { 394 register struct direct *dirp = idesc->id_dirp; 395 396 if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 397 return (KEEPON); 398 dirp->d_ino = idesc->id_parent; 399 if (newinofmt) 400 dirp->d_type = typemap[idesc->id_parent]; 401 else 402 dirp->d_type = 0; 403 return (ALTERED | STOP); 404 } 405 406 int 407 linkup(ino_t orphan, ino_t parentdir) 408 { 409 register struct dinode *dp; 410 int lostdir; 411 ino_t oldlfdir; 412 struct inodesc idesc; 413 char tempname[BUFSIZ]; 414 415 memset(&idesc, 0, sizeof(struct inodesc)); 416 dp = ginode(orphan); 417 lostdir = (dp->di_mode & IFMT) == IFDIR; 418 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 419 pinode(orphan); 420 if (preen && dp->di_size == 0) 421 return (0); 422 if (preen) 423 printf(" (RECONNECTED)\n"); 424 else if (reply("RECONNECT") == 0) 425 return (0); 426 if (lfdir == 0) { 427 dp = ginode(ROOTINO); 428 idesc.id_name = lfname; 429 idesc.id_type = DATA; 430 idesc.id_func = findino; 431 idesc.id_number = ROOTINO; 432 if ((ckinode(dp, &idesc) & FOUND) != 0) { 433 lfdir = idesc.id_parent; 434 } else { 435 pwarn("NO lost+found DIRECTORY"); 436 if (preen || reply("CREATE")) { 437 lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 438 if (lfdir != 0) { 439 if (makeentry(ROOTINO, lfdir, lfname) != 0) { 440 if (preen) 441 printf(" (CREATED)\n"); 442 } else { 443 freedir(lfdir, ROOTINO); 444 lfdir = 0; 445 if (preen) 446 printf("\n"); 447 } 448 } 449 } 450 } 451 if (lfdir == 0) { 452 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 453 printf("\n\n"); 454 return (0); 455 } 456 } 457 dp = ginode(lfdir); 458 if ((dp->di_mode & IFMT) != IFDIR) { 459 pfatal("lost+found IS NOT A DIRECTORY"); 460 if (reply("REALLOCATE") == 0) 461 return (0); 462 oldlfdir = lfdir; 463 if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 464 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 465 return (0); 466 } 467 if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 468 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 469 return (0); 470 } 471 inodirty(); 472 idesc.id_type = ADDR; 473 idesc.id_func = pass4check; 474 idesc.id_number = oldlfdir; 475 adjust(&idesc, lncntp[oldlfdir] + 1); 476 lncntp[oldlfdir] = 0; 477 dp = ginode(lfdir); 478 } 479 if (statemap[lfdir] != DFOUND) { 480 pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 481 return (0); 482 } 483 (void)lftempname(tempname, orphan); 484 if (makeentry(lfdir, orphan, tempname) == 0) { 485 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 486 printf("\n\n"); 487 return (0); 488 } 489 lncntp[orphan]--; 490 if (lostdir) { 491 if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 492 parentdir != (ino_t)-1) 493 (void)makeentry(orphan, lfdir, ".."); 494 dp = ginode(lfdir); 495 dp->di_nlink++; 496 inodirty(); 497 lncntp[lfdir]++; 498 pwarn("DIR I=%u CONNECTED. ", orphan); 499 if (parentdir != (ino_t)-1) 500 printf("PARENT WAS I=%u\n", parentdir); 501 if (preen == 0) 502 printf("\n"); 503 } 504 return (1); 505 } 506 507 /* 508 * fix an entry in a directory. 509 */ 510 int 511 changeino(ino_t dir, char *name, ino_t newnum) 512 { 513 struct inodesc idesc; 514 515 memset(&idesc, 0, sizeof(struct inodesc)); 516 idesc.id_type = DATA; 517 idesc.id_func = chgino; 518 idesc.id_number = dir; 519 idesc.id_fix = DONTKNOW; 520 idesc.id_name = name; 521 idesc.id_parent = newnum; /* new value for name */ 522 return (ckinode(ginode(dir), &idesc)); 523 } 524 525 /* 526 * make an entry in a directory 527 */ 528 int 529 makeentry(ino_t parent, ino_t ino, char *name) 530 { 531 struct dinode *dp; 532 struct inodesc idesc; 533 char pathbuf[MAXPATHLEN + 1]; 534 535 if (parent < ROOTINO || parent >= maxino || 536 ino < ROOTINO || ino >= maxino) 537 return (0); 538 memset(&idesc, 0, sizeof(struct inodesc)); 539 idesc.id_type = DATA; 540 idesc.id_func = mkentry; 541 idesc.id_number = parent; 542 idesc.id_parent = ino; /* this is the inode to enter */ 543 idesc.id_fix = DONTKNOW; 544 idesc.id_name = name; 545 dp = ginode(parent); 546 if (dp->di_size % DIRBLKSIZ) { 547 dp->di_size = roundup(dp->di_size, DIRBLKSIZ); 548 inodirty(); 549 } 550 if ((ckinode(dp, &idesc) & ALTERED) != 0) 551 return (1); 552 getpathname(pathbuf, parent, parent); 553 dp = ginode(parent); 554 if (expanddir(dp, pathbuf) == 0) 555 return (0); 556 return (ckinode(dp, &idesc) & ALTERED); 557 } 558 559 /* 560 * Attempt to expand the size of a directory 561 */ 562 static int 563 expanddir(struct dinode * dp, char *name) 564 { 565 daddr_t lastbn, newblk; 566 register struct bufarea *bp; 567 char *cp, firstblk[DIRBLKSIZ]; 568 569 lastbn = lblkno(&sblock, dp->di_size); 570 if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 571 return (0); 572 if ((newblk = allocblk(sblock.lfs_frag)) == 0) 573 return (0); 574 dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 575 dp->di_db[lastbn] = newblk; 576 dp->di_size += sblock.lfs_bsize; 577 dp->di_blocks += btofsb(&sblock, sblock.lfs_bsize); 578 bp = getdirblk(dp->di_db[lastbn + 1], 579 (long)dblksize(&sblock, dp, lastbn + 1)); 580 if (bp->b_errs) 581 goto bad; 582 memcpy(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 583 bp = getdirblk(newblk, sblock.lfs_bsize); 584 if (bp->b_errs) 585 goto bad; 586 memcpy(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 587 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 588 cp < &bp->b_un.b_buf[sblock.lfs_bsize]; 589 cp += DIRBLKSIZ) 590 memcpy(cp, &emptydir, sizeof emptydir); 591 dirty(bp); 592 bp = getdirblk(dp->di_db[lastbn + 1], 593 (long)dblksize(&sblock, dp, lastbn + 1)); 594 if (bp->b_errs) 595 goto bad; 596 memcpy(bp->b_un.b_buf, &emptydir, sizeof emptydir); 597 pwarn("NO SPACE LEFT IN %s", name); 598 if (preen) 599 printf(" (EXPANDED)\n"); 600 else if (reply("EXPAND") == 0) 601 goto bad; 602 dirty(bp); 603 inodirty(); 604 return (1); 605 bad: 606 dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 607 dp->di_db[lastbn + 1] = 0; 608 dp->di_size -= sblock.lfs_bsize; 609 dp->di_blocks -= btofsb(&sblock, sblock.lfs_bsize); 610 freeblk(newblk, sblock.lfs_frag); 611 return (0); 612 } 613 614 /* 615 * allocate a new directory 616 */ 617 int 618 allocdir(ino_t parent, ino_t request, int mode) 619 { 620 ino_t ino; 621 char *cp; 622 struct dinode *dp; 623 register struct bufarea *bp; 624 struct dirtemplate *dirp; 625 626 ino = allocino(request, IFDIR | mode); 627 if (newinofmt) 628 dirp = &dirhead; 629 else 630 dirp = (struct dirtemplate *) & odirhead; 631 dirp->dot_ino = ino; 632 dirp->dotdot_ino = parent; 633 dp = ginode(ino); 634 bp = getdirblk(dp->di_db[0], sblock.lfs_fsize); 635 if (bp->b_errs) { 636 freeino(ino); 637 return (0); 638 } 639 memcpy(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 640 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 641 cp < &bp->b_un.b_buf[sblock.lfs_fsize]; 642 cp += DIRBLKSIZ) 643 memcpy(cp, &emptydir, sizeof emptydir); 644 dirty(bp); 645 dp->di_nlink = 2; 646 inodirty(); 647 if (ino == ROOTINO) { 648 lncntp[ino] = dp->di_nlink; 649 cacheino(dp, ino); 650 return (ino); 651 } 652 if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 653 freeino(ino); 654 return (0); 655 } 656 cacheino(dp, ino); 657 statemap[ino] = statemap[parent]; 658 if (statemap[ino] == DSTATE) { 659 lncntp[ino] = dp->di_nlink; 660 lncntp[parent]++; 661 } 662 dp = ginode(parent); 663 dp->di_nlink++; 664 inodirty(); 665 return (ino); 666 } 667 668 /* 669 * free a directory inode 670 */ 671 static void 672 freedir(ino_t ino, ino_t parent) 673 { 674 struct dinode *dp; 675 676 if (ino != parent) { 677 dp = ginode(parent); 678 dp->di_nlink--; 679 inodirty(); 680 } 681 freeino(ino); 682 } 683 684 /* 685 * generate a temporary name for the lost+found directory. 686 */ 687 static int 688 lftempname(char *bufp, ino_t ino) 689 { 690 register ino_t in; 691 register char *cp; 692 int namlen; 693 694 cp = bufp + 2; 695 for (in = maxino; in > 0; in /= 10) 696 cp++; 697 *--cp = 0; 698 namlen = cp - bufp; 699 in = ino; 700 while (cp > bufp) { 701 *--cp = (in % 10) + '0'; 702 in /= 10; 703 } 704 *cp = '#'; 705 return (namlen); 706 } 707 708 /* 709 * Get a directory block. 710 * Ensure that it is held until another is requested. 711 */ 712 static struct bufarea * 713 getdirblk(daddr_t blkno, long size) 714 { 715 716 if (pdirbp != 0) 717 pdirbp->b_flags &= ~B_INUSE; 718 /* pdirbp = getdatablk(blkno, size); */ 719 pdirbp = getddblk(blkno, size); 720 return (pdirbp); 721 } 722