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 #if 0 36 static const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; 37 #endif 38 static const char rcsid[] = 39 "$FreeBSD$"; 40 #endif /* not lint */ 41 42 #include <sys/param.h> 43 #include <sys/time.h> 44 #include <sys/sysctl.h> 45 46 #include <ufs/ufs/dinode.h> 47 #include <ufs/ufs/dir.h> 48 #include <ufs/ffs/fs.h> 49 50 #include <err.h> 51 #include <string.h> 52 53 #include "fsck.h" 54 55 const char *lfname = "lost+found"; 56 int lfmode = 01777; 57 struct dirtemplate emptydir = { 58 0, DIRBLKSIZ, DT_UNKNOWN, 0, "", 59 0, 0, DT_UNKNOWN, 0, "" 60 }; 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 chgino(struct inodesc *); 71 static int dircheck(struct inodesc *, struct direct *); 72 static int expanddir(union dinode *dp, char *name); 73 static void freedir(ino_t ino, ino_t parent); 74 static struct direct *fsck_readdir(struct inodesc *); 75 static struct bufarea *getdirblk(ufs2_daddr_t blkno, long size); 76 static int lftempname(char *bufp, ino_t ino); 77 static int mkentry(struct inodesc *); 78 79 /* 80 * Propagate connected state through the tree. 81 */ 82 void 83 propagate(void) 84 { 85 struct inoinfo **inpp, *inp; 86 struct inoinfo **inpend; 87 long change; 88 89 inpend = &inpsort[inplast]; 90 do { 91 change = 0; 92 for (inpp = inpsort; inpp < inpend; inpp++) { 93 inp = *inpp; 94 if (inp->i_parent == 0) 95 continue; 96 if (inoinfo(inp->i_parent)->ino_state == DFOUND && 97 inoinfo(inp->i_number)->ino_state == DSTATE) { 98 inoinfo(inp->i_number)->ino_state = DFOUND; 99 change++; 100 } 101 } 102 } while (change > 0); 103 } 104 105 /* 106 * Scan each entry in a directory block. 107 */ 108 int 109 dirscan(struct inodesc *idesc) 110 { 111 struct direct *dp; 112 struct bufarea *bp; 113 u_int dsize, n; 114 long blksiz; 115 char dbuf[DIRBLKSIZ]; 116 117 if (idesc->id_type != DATA) 118 errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); 119 if (idesc->id_entryno == 0 && 120 (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) 121 idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); 122 blksiz = idesc->id_numfrags * sblock.fs_fsize; 123 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 124 idesc->id_filesize -= blksiz; 125 return (SKIP); 126 } 127 idesc->id_loc = 0; 128 for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { 129 dsize = dp->d_reclen; 130 if (dsize > sizeof(dbuf)) 131 dsize = sizeof(dbuf); 132 memmove(dbuf, dp, (size_t)dsize); 133 idesc->id_dirp = (struct direct *)dbuf; 134 if ((n = (*idesc->id_func)(idesc)) & ALTERED) { 135 bp = getdirblk(idesc->id_blkno, blksiz); 136 memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, 137 (size_t)dsize); 138 dirty(bp); 139 sbdirty(); 140 } 141 if (n & STOP) 142 return (n); 143 } 144 return (idesc->id_filesize > 0 ? KEEPON : STOP); 145 } 146 147 /* 148 * get next entry in a directory. 149 */ 150 static struct direct * 151 fsck_readdir(struct inodesc *idesc) 152 { 153 struct direct *dp, *ndp; 154 struct bufarea *bp; 155 long size, blksiz, fix, dploc; 156 157 blksiz = idesc->id_numfrags * sblock.fs_fsize; 158 bp = getdirblk(idesc->id_blkno, blksiz); 159 if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 160 idesc->id_loc < blksiz) { 161 dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 162 if (dircheck(idesc, dp)) 163 goto dpok; 164 if (idesc->id_fix == IGNORE) 165 return (0); 166 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 167 bp = getdirblk(idesc->id_blkno, blksiz); 168 dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 169 dp->d_reclen = DIRBLKSIZ; 170 dp->d_ino = 0; 171 dp->d_type = 0; 172 dp->d_namlen = 0; 173 dp->d_name[0] = '\0'; 174 if (fix) 175 dirty(bp); 176 idesc->id_loc += DIRBLKSIZ; 177 idesc->id_filesize -= DIRBLKSIZ; 178 return (dp); 179 } 180 dpok: 181 if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) 182 return NULL; 183 dploc = idesc->id_loc; 184 dp = (struct direct *)(bp->b_un.b_buf + dploc); 185 idesc->id_loc += dp->d_reclen; 186 idesc->id_filesize -= dp->d_reclen; 187 if ((idesc->id_loc % DIRBLKSIZ) == 0) 188 return (dp); 189 ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); 190 if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 191 dircheck(idesc, ndp) == 0) { 192 size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 193 idesc->id_loc += size; 194 idesc->id_filesize -= size; 195 if (idesc->id_fix == IGNORE) 196 return (0); 197 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 198 bp = getdirblk(idesc->id_blkno, blksiz); 199 dp = (struct direct *)(bp->b_un.b_buf + dploc); 200 dp->d_reclen += size; 201 if (fix) 202 dirty(bp); 203 } 204 return (dp); 205 } 206 207 /* 208 * Verify that a directory entry is valid. 209 * This is a superset of the checks made in the kernel. 210 */ 211 static int 212 dircheck(struct inodesc *idesc, struct direct *dp) 213 { 214 int size; 215 char *cp; 216 u_char namlen, type; 217 int spaceleft; 218 219 spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 220 if (dp->d_reclen == 0 || 221 dp->d_reclen > spaceleft || 222 (dp->d_reclen & 0x3) != 0) 223 goto bad; 224 if (dp->d_ino == 0) 225 return (1); 226 size = DIRSIZ(0, dp); 227 namlen = dp->d_namlen; 228 type = dp->d_type; 229 if (dp->d_reclen < size || 230 idesc->id_filesize < size || 231 namlen > MAXNAMLEN || 232 type > 15) 233 goto bad; 234 for (cp = dp->d_name, size = 0; size < namlen; size++) 235 if (*cp == '\0' || (*cp++ == '/')) 236 goto bad; 237 if (*cp != '\0') 238 goto bad; 239 return (1); 240 bad: 241 if (debug) 242 printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n", 243 dp->d_ino, dp->d_reclen, dp->d_namlen, dp->d_type, 244 dp->d_name); 245 return (0); 246 } 247 248 void 249 direrror(ino_t ino, const char *errmesg) 250 { 251 252 fileerror(ino, ino, errmesg); 253 } 254 255 void 256 fileerror(ino_t cwd, ino_t ino, const char *errmesg) 257 { 258 union dinode *dp; 259 char pathbuf[MAXPATHLEN + 1]; 260 261 pwarn("%s ", errmesg); 262 pinode(ino); 263 printf("\n"); 264 getpathname(pathbuf, cwd, ino); 265 if (ino < ROOTINO || ino > maxino) { 266 pfatal("NAME=%s\n", pathbuf); 267 return; 268 } 269 dp = ginode(ino); 270 if (ftypeok(dp)) 271 pfatal("%s=%s\n", 272 (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE", 273 pathbuf); 274 else 275 pfatal("NAME=%s\n", pathbuf); 276 } 277 278 void 279 adjust(struct inodesc *idesc, int lcnt) 280 { 281 union dinode *dp; 282 int saveresolved; 283 284 dp = ginode(idesc->id_number); 285 if (DIP(dp, di_nlink) == lcnt) { 286 /* 287 * If we have not hit any unresolved problems, are running 288 * in preen mode, and are on a file system using soft updates, 289 * then just toss any partially allocated files. 290 */ 291 if (resolved && (preen || bkgrdflag) && usedsoftdep) { 292 clri(idesc, "UNREF", 1); 293 return; 294 } else { 295 /* 296 * The file system can be marked clean even if 297 * a file is not linked up, but is cleared. 298 * Hence, resolved should not be cleared when 299 * linkup is answered no, but clri is answered yes. 300 */ 301 saveresolved = resolved; 302 if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) { 303 resolved = saveresolved; 304 clri(idesc, "UNREF", 0); 305 return; 306 } 307 /* 308 * Account for the new reference created by linkup(). 309 */ 310 dp = ginode(idesc->id_number); 311 lcnt--; 312 } 313 } 314 if (lcnt != 0) { 315 pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 316 ((DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE")); 317 pinode(idesc->id_number); 318 printf(" COUNT %d SHOULD BE %d", 319 DIP(dp, di_nlink), DIP(dp, di_nlink) - lcnt); 320 if (preen || usedsoftdep) { 321 if (lcnt < 0) { 322 printf("\n"); 323 pfatal("LINK COUNT INCREASING"); 324 } 325 if (preen) 326 printf(" (ADJUSTED)\n"); 327 } 328 if (preen || reply("ADJUST") == 1) { 329 if (bkgrdflag == 0) { 330 DIP(dp, di_nlink) -= lcnt; 331 inodirty(); 332 } else { 333 cmd.value = idesc->id_number; 334 cmd.size = -lcnt; 335 if (debug) 336 printf("adjrefcnt ino %ld amt %lld\n", 337 (long)cmd.value, 338 (long long)cmd.size); 339 if (sysctl(adjrefcnt, MIBSIZE, 0, 0, 340 &cmd, sizeof cmd) == -1) 341 rwerror("ADJUST INODE", cmd.value); 342 } 343 } 344 } 345 } 346 347 static int 348 mkentry(struct inodesc *idesc) 349 { 350 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); 356 if (dirp->d_ino != 0) 357 oldlen = DIRSIZ(0, dirp); 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 dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 368 dirp->d_namlen = newent.d_namlen; 369 memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 370 return (ALTERED|STOP); 371 } 372 373 static int 374 chgino(struct inodesc *idesc) 375 { 376 struct direct *dirp = idesc->id_dirp; 377 378 if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 379 return (KEEPON); 380 dirp->d_ino = idesc->id_parent; 381 dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 382 return (ALTERED|STOP); 383 } 384 385 int 386 linkup(ino_t orphan, ino_t parentdir, char *name) 387 { 388 union dinode *dp; 389 int lostdir; 390 ino_t oldlfdir; 391 struct inodesc idesc; 392 char tempname[BUFSIZ]; 393 394 memset(&idesc, 0, sizeof(struct inodesc)); 395 dp = ginode(orphan); 396 lostdir = (DIP(dp, di_mode) & IFMT) == IFDIR; 397 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 398 pinode(orphan); 399 if (preen && DIP(dp, di_size) == 0) 400 return (0); 401 if (cursnapshot != 0) { 402 pfatal("FILE LINKUP IN SNAPSHOT"); 403 return (0); 404 } 405 if (preen) 406 printf(" (RECONNECTED)\n"); 407 else 408 if (reply("RECONNECT") == 0) 409 return (0); 410 if (lfdir == 0) { 411 dp = ginode(ROOTINO); 412 idesc.id_name = strdup(lfname); 413 idesc.id_type = DATA; 414 idesc.id_func = findino; 415 idesc.id_number = ROOTINO; 416 if ((ckinode(dp, &idesc) & FOUND) != 0) { 417 lfdir = idesc.id_parent; 418 } else { 419 pwarn("NO lost+found DIRECTORY"); 420 if (preen || reply("CREATE")) { 421 lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 422 if (lfdir != 0) { 423 if (makeentry(ROOTINO, lfdir, lfname) != 0) { 424 numdirs++; 425 if (preen) 426 printf(" (CREATED)\n"); 427 } else { 428 freedir(lfdir, ROOTINO); 429 lfdir = 0; 430 if (preen) 431 printf("\n"); 432 } 433 } 434 } 435 } 436 if (lfdir == 0) { 437 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 438 printf("\n\n"); 439 return (0); 440 } 441 } 442 dp = ginode(lfdir); 443 if ((DIP(dp, di_mode) & IFMT) != IFDIR) { 444 pfatal("lost+found IS NOT A DIRECTORY"); 445 if (reply("REALLOCATE") == 0) 446 return (0); 447 oldlfdir = lfdir; 448 if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 449 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 450 return (0); 451 } 452 if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 453 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 454 return (0); 455 } 456 inodirty(); 457 idesc.id_type = ADDR; 458 idesc.id_func = pass4check; 459 idesc.id_number = oldlfdir; 460 adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1); 461 inoinfo(oldlfdir)->ino_linkcnt = 0; 462 dp = ginode(lfdir); 463 } 464 if (inoinfo(lfdir)->ino_state != DFOUND) { 465 pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 466 return (0); 467 } 468 (void)lftempname(tempname, orphan); 469 if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) { 470 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 471 printf("\n\n"); 472 return (0); 473 } 474 inoinfo(orphan)->ino_linkcnt--; 475 if (lostdir) { 476 if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 477 parentdir != (ino_t)-1) 478 (void)makeentry(orphan, lfdir, ".."); 479 dp = ginode(lfdir); 480 DIP(dp, di_nlink)++; 481 inodirty(); 482 inoinfo(lfdir)->ino_linkcnt++; 483 pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan); 484 if (parentdir != (ino_t)-1) { 485 printf("PARENT WAS I=%lu\n", (u_long)parentdir); 486 /* 487 * The parent directory, because of the ordering 488 * guarantees, has had the link count incremented 489 * for the child, but no entry was made. This 490 * fixes the parent link count so that fsck does 491 * not need to be rerun. 492 */ 493 inoinfo(parentdir)->ino_linkcnt++; 494 } 495 if (preen == 0) 496 printf("\n"); 497 } 498 return (1); 499 } 500 501 /* 502 * fix an entry in a directory. 503 */ 504 int 505 changeino(ino_t dir, const char *name, ino_t newnum) 506 { 507 struct inodesc idesc; 508 509 memset(&idesc, 0, sizeof(struct inodesc)); 510 idesc.id_type = DATA; 511 idesc.id_func = chgino; 512 idesc.id_number = dir; 513 idesc.id_fix = DONTKNOW; 514 idesc.id_name = strdup(name); 515 idesc.id_parent = newnum; /* new value for name */ 516 return (ckinode(ginode(dir), &idesc)); 517 } 518 519 /* 520 * make an entry in a directory 521 */ 522 int 523 makeentry(ino_t parent, ino_t ino, const char *name) 524 { 525 union 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 = strdup(name); 539 dp = ginode(parent); 540 if (DIP(dp, di_size) % DIRBLKSIZ) { 541 DIP(dp, di_size) = roundup(DIP(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 static int 557 expanddir(union dinode *dp, char *name) 558 { 559 ufs2_daddr_t lastbn, newblk; 560 struct bufarea *bp; 561 char *cp, firstblk[DIRBLKSIZ]; 562 563 lastbn = lblkno(&sblock, DIP(dp, di_size)); 564 if (lastbn >= NDADDR - 1 || DIP(dp, di_db[lastbn]) == 0 || 565 DIP(dp, di_size) == 0) 566 return (0); 567 if ((newblk = allocblk(sblock.fs_frag)) == 0) 568 return (0); 569 DIP(dp, di_db[lastbn + 1]) = DIP(dp, di_db[lastbn]); 570 DIP(dp, di_db[lastbn]) = newblk; 571 DIP(dp, di_size) += sblock.fs_bsize; 572 DIP(dp, di_blocks) += btodb(sblock.fs_bsize); 573 bp = getdirblk(DIP(dp, di_db[lastbn + 1]), 574 sblksize(&sblock, DIP(dp, di_size), lastbn + 1)); 575 if (bp->b_errs) 576 goto bad; 577 memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 578 bp = getdirblk(newblk, sblock.fs_bsize); 579 if (bp->b_errs) 580 goto bad; 581 memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 582 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 583 cp < &bp->b_un.b_buf[sblock.fs_bsize]; 584 cp += DIRBLKSIZ) 585 memmove(cp, &emptydir, sizeof emptydir); 586 dirty(bp); 587 bp = getdirblk(DIP(dp, di_db[lastbn + 1]), 588 sblksize(&sblock, DIP(dp, di_size), lastbn + 1)); 589 if (bp->b_errs) 590 goto bad; 591 memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 592 pwarn("NO SPACE LEFT IN %s", name); 593 if (preen) 594 printf(" (EXPANDED)\n"); 595 else if (reply("EXPAND") == 0) 596 goto bad; 597 dirty(bp); 598 inodirty(); 599 return (1); 600 bad: 601 DIP(dp, di_db[lastbn]) = DIP(dp, di_db[lastbn + 1]); 602 DIP(dp, di_db[lastbn + 1]) = 0; 603 DIP(dp, di_size) -= sblock.fs_bsize; 604 DIP(dp, di_blocks) -= btodb(sblock.fs_bsize); 605 freeblk(newblk, sblock.fs_frag); 606 return (0); 607 } 608 609 /* 610 * allocate a new directory 611 */ 612 ino_t 613 allocdir(ino_t parent, ino_t request, int mode) 614 { 615 ino_t ino; 616 char *cp; 617 union dinode *dp; 618 struct bufarea *bp; 619 struct inoinfo *inp; 620 struct dirtemplate *dirp; 621 622 ino = allocino(request, IFDIR|mode); 623 dirp = &dirhead; 624 dirp->dot_ino = ino; 625 dirp->dotdot_ino = parent; 626 dp = ginode(ino); 627 bp = getdirblk(DIP(dp, di_db[0]), sblock.fs_fsize); 628 if (bp->b_errs) { 629 freeino(ino); 630 return (0); 631 } 632 memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 633 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 634 cp < &bp->b_un.b_buf[sblock.fs_fsize]; 635 cp += DIRBLKSIZ) 636 memmove(cp, &emptydir, sizeof emptydir); 637 dirty(bp); 638 DIP(dp, di_nlink) = 2; 639 inodirty(); 640 if (ino == ROOTINO) { 641 inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink); 642 cacheino(dp, ino); 643 return(ino); 644 } 645 if (inoinfo(parent)->ino_state != DSTATE && 646 inoinfo(parent)->ino_state != DFOUND) { 647 freeino(ino); 648 return (0); 649 } 650 cacheino(dp, ino); 651 inp = getinoinfo(ino); 652 inp->i_parent = parent; 653 inp->i_dotdot = parent; 654 inoinfo(ino)->ino_state = inoinfo(parent)->ino_state; 655 if (inoinfo(ino)->ino_state == DSTATE) { 656 inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink); 657 inoinfo(parent)->ino_linkcnt++; 658 } 659 dp = ginode(parent); 660 DIP(dp, di_nlink)++; 661 inodirty(); 662 return (ino); 663 } 664 665 /* 666 * free a directory inode 667 */ 668 static void 669 freedir(ino_t ino, ino_t parent) 670 { 671 union dinode *dp; 672 673 if (ino != parent) { 674 dp = ginode(parent); 675 DIP(dp, di_nlink)--; 676 inodirty(); 677 } 678 freeino(ino); 679 } 680 681 /* 682 * generate a temporary name for the lost+found directory. 683 */ 684 static int 685 lftempname(char *bufp, ino_t ino) 686 { 687 ino_t in; 688 char *cp; 689 int namlen; 690 691 cp = bufp + 2; 692 for (in = maxino; in > 0; in /= 10) 693 cp++; 694 *--cp = 0; 695 namlen = cp - bufp; 696 in = ino; 697 while (cp > bufp) { 698 *--cp = (in % 10) + '0'; 699 in /= 10; 700 } 701 *cp = '#'; 702 return (namlen); 703 } 704 705 /* 706 * Get a directory block. 707 * Insure that it is held until another is requested. 708 */ 709 static struct bufarea * 710 getdirblk(ufs2_daddr_t blkno, long size) 711 { 712 713 if (pdirbp != 0) 714 pdirbp->b_flags &= ~B_INUSE; 715 pdirbp = getdatablk(blkno, size); 716 return (pdirbp); 717 } 718