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