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