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