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 #if 0 35 #ifndef lint 36 static const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95"; 37 #endif /* not lint */ 38 #endif 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 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 size_t size; 215 char *cp; 216 u_char type; 217 u_int namlen; 218 int spaceleft; 219 220 spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); 221 if (dp->d_reclen == 0 || 222 dp->d_reclen > spaceleft || 223 (dp->d_reclen & 0x3) != 0) 224 goto bad; 225 if (dp->d_ino == 0) 226 return (1); 227 size = DIRSIZ(0, dp); 228 namlen = dp->d_namlen; 229 type = dp->d_type; 230 if (dp->d_reclen < size || 231 idesc->id_filesize < size || 232 namlen > MAXNAMLEN || 233 type > 15) 234 goto bad; 235 for (cp = dp->d_name, size = 0; size < namlen; size++) 236 if (*cp == '\0' || (*cp++ == '/')) 237 goto bad; 238 if (*cp != '\0') 239 goto bad; 240 return (1); 241 bad: 242 if (debug) 243 printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n", 244 dp->d_ino, dp->d_reclen, dp->d_namlen, dp->d_type, 245 dp->d_name); 246 return (0); 247 } 248 249 void 250 direrror(ino_t ino, const char *errmesg) 251 { 252 253 fileerror(ino, ino, errmesg); 254 } 255 256 void 257 fileerror(ino_t cwd, ino_t ino, const char *errmesg) 258 { 259 union dinode *dp; 260 char pathbuf[MAXPATHLEN + 1]; 261 262 pwarn("%s ", errmesg); 263 pinode(ino); 264 printf("\n"); 265 getpathname(pathbuf, cwd, ino); 266 if (ino < ROOTINO || ino > maxino) { 267 pfatal("NAME=%s\n", pathbuf); 268 return; 269 } 270 dp = ginode(ino); 271 if (ftypeok(dp)) 272 pfatal("%s=%s\n", 273 (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE", 274 pathbuf); 275 else 276 pfatal("NAME=%s\n", pathbuf); 277 } 278 279 void 280 adjust(struct inodesc *idesc, int lcnt) 281 { 282 union dinode *dp; 283 int saveresolved; 284 285 dp = ginode(idesc->id_number); 286 if (DIP(dp, di_nlink) == lcnt) { 287 /* 288 * If we have not hit any unresolved problems, are running 289 * in preen mode, and are on a file system using soft updates, 290 * then just toss any partially allocated files. 291 */ 292 if (resolved && (preen || bkgrdflag) && usedsoftdep) { 293 clri(idesc, "UNREF", 1); 294 return; 295 } else { 296 /* 297 * The file system can be marked clean even if 298 * a file is not linked up, but is cleared. 299 * Hence, resolved should not be cleared when 300 * linkup is answered no, but clri is answered yes. 301 */ 302 saveresolved = resolved; 303 if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) { 304 resolved = saveresolved; 305 clri(idesc, "UNREF", 0); 306 return; 307 } 308 /* 309 * Account for the new reference created by linkup(). 310 */ 311 dp = ginode(idesc->id_number); 312 lcnt--; 313 } 314 } 315 if (lcnt != 0) { 316 pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 317 ((DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE")); 318 pinode(idesc->id_number); 319 printf(" COUNT %d SHOULD BE %d", 320 DIP(dp, di_nlink), DIP(dp, di_nlink) - lcnt); 321 if (preen || usedsoftdep) { 322 if (lcnt < 0) { 323 printf("\n"); 324 pfatal("LINK COUNT INCREASING"); 325 } 326 if (preen) 327 printf(" (ADJUSTED)\n"); 328 } 329 if (preen || reply("ADJUST") == 1) { 330 if (bkgrdflag == 0) { 331 DIP(dp, di_nlink) -= lcnt; 332 inodirty(); 333 } else { 334 cmd.value = idesc->id_number; 335 cmd.size = -lcnt; 336 if (debug) 337 printf("adjrefcnt ino %ld amt %lld\n", 338 (long)cmd.value, 339 (long long)cmd.size); 340 if (sysctl(adjrefcnt, MIBSIZE, 0, 0, 341 &cmd, sizeof cmd) == -1) 342 rwerror("ADJUST INODE", cmd.value); 343 } 344 } 345 } 346 } 347 348 static int 349 mkentry(struct inodesc *idesc) 350 { 351 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); 357 if (dirp->d_ino != 0) 358 oldlen = DIRSIZ(0, dirp); 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 dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 369 dirp->d_namlen = newent.d_namlen; 370 memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 371 return (ALTERED|STOP); 372 } 373 374 static int 375 chgino(struct inodesc *idesc) 376 { 377 struct direct *dirp = idesc->id_dirp; 378 379 if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 380 return (KEEPON); 381 dirp->d_ino = idesc->id_parent; 382 dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 383 return (ALTERED|STOP); 384 } 385 386 int 387 linkup(ino_t orphan, ino_t parentdir, char *name) 388 { 389 union dinode *dp; 390 int lostdir; 391 ino_t oldlfdir; 392 struct inodesc idesc; 393 char tempname[BUFSIZ]; 394 395 memset(&idesc, 0, sizeof(struct inodesc)); 396 dp = ginode(orphan); 397 lostdir = (DIP(dp, di_mode) & IFMT) == IFDIR; 398 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 399 pinode(orphan); 400 if (preen && DIP(dp, di_size) == 0) 401 return (0); 402 if (cursnapshot != 0) { 403 pfatal("FILE LINKUP IN SNAPSHOT"); 404 return (0); 405 } 406 if (preen) 407 printf(" (RECONNECTED)\n"); 408 else 409 if (reply("RECONNECT") == 0) 410 return (0); 411 if (lfdir == 0) { 412 dp = ginode(ROOTINO); 413 idesc.id_name = strdup(lfname); 414 idesc.id_type = DATA; 415 idesc.id_func = findino; 416 idesc.id_number = ROOTINO; 417 if ((ckinode(dp, &idesc) & FOUND) != 0) { 418 lfdir = idesc.id_parent; 419 } else { 420 pwarn("NO lost+found DIRECTORY"); 421 if (preen || reply("CREATE")) { 422 lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 423 if (lfdir != 0) { 424 if (makeentry(ROOTINO, lfdir, lfname) != 0) { 425 numdirs++; 426 if (preen) 427 printf(" (CREATED)\n"); 428 } else { 429 freedir(lfdir, ROOTINO); 430 lfdir = 0; 431 if (preen) 432 printf("\n"); 433 } 434 } 435 } 436 } 437 if (lfdir == 0) { 438 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 439 printf("\n\n"); 440 return (0); 441 } 442 } 443 dp = ginode(lfdir); 444 if ((DIP(dp, di_mode) & IFMT) != IFDIR) { 445 pfatal("lost+found IS NOT A DIRECTORY"); 446 if (reply("REALLOCATE") == 0) 447 return (0); 448 oldlfdir = lfdir; 449 if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 450 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 451 return (0); 452 } 453 if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 454 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 455 return (0); 456 } 457 inodirty(); 458 idesc.id_type = ADDR; 459 idesc.id_func = pass4check; 460 idesc.id_number = oldlfdir; 461 adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1); 462 inoinfo(oldlfdir)->ino_linkcnt = 0; 463 dp = ginode(lfdir); 464 } 465 if (inoinfo(lfdir)->ino_state != DFOUND) { 466 pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 467 return (0); 468 } 469 (void)lftempname(tempname, orphan); 470 if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) { 471 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 472 printf("\n\n"); 473 return (0); 474 } 475 inoinfo(orphan)->ino_linkcnt--; 476 if (lostdir) { 477 if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 478 parentdir != (ino_t)-1) 479 (void)makeentry(orphan, lfdir, ".."); 480 dp = ginode(lfdir); 481 DIP(dp, di_nlink)++; 482 inodirty(); 483 inoinfo(lfdir)->ino_linkcnt++; 484 pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan); 485 if (parentdir != (ino_t)-1) { 486 printf("PARENT WAS I=%lu\n", (u_long)parentdir); 487 /* 488 * The parent directory, because of the ordering 489 * guarantees, has had the link count incremented 490 * for the child, but no entry was made. This 491 * fixes the parent link count so that fsck does 492 * not need to be rerun. 493 */ 494 inoinfo(parentdir)->ino_linkcnt++; 495 } 496 if (preen == 0) 497 printf("\n"); 498 } 499 return (1); 500 } 501 502 /* 503 * fix an entry in a directory. 504 */ 505 int 506 changeino(ino_t dir, const char *name, ino_t newnum) 507 { 508 struct inodesc idesc; 509 510 memset(&idesc, 0, sizeof(struct inodesc)); 511 idesc.id_type = DATA; 512 idesc.id_func = chgino; 513 idesc.id_number = dir; 514 idesc.id_fix = DONTKNOW; 515 idesc.id_name = strdup(name); 516 idesc.id_parent = newnum; /* new value for name */ 517 return (ckinode(ginode(dir), &idesc)); 518 } 519 520 /* 521 * make an entry in a directory 522 */ 523 int 524 makeentry(ino_t parent, ino_t ino, const char *name) 525 { 526 union dinode *dp; 527 struct inodesc idesc; 528 char pathbuf[MAXPATHLEN + 1]; 529 530 if (parent < ROOTINO || parent >= maxino || 531 ino < ROOTINO || ino >= maxino) 532 return (0); 533 memset(&idesc, 0, sizeof(struct inodesc)); 534 idesc.id_type = DATA; 535 idesc.id_func = mkentry; 536 idesc.id_number = parent; 537 idesc.id_parent = ino; /* this is the inode to enter */ 538 idesc.id_fix = DONTKNOW; 539 idesc.id_name = strdup(name); 540 dp = ginode(parent); 541 if (DIP(dp, di_size) % DIRBLKSIZ) { 542 DIP(dp, di_size) = roundup(DIP(dp, di_size), DIRBLKSIZ); 543 inodirty(); 544 } 545 if ((ckinode(dp, &idesc) & ALTERED) != 0) 546 return (1); 547 getpathname(pathbuf, parent, parent); 548 dp = ginode(parent); 549 if (expanddir(dp, pathbuf) == 0) 550 return (0); 551 return (ckinode(dp, &idesc) & ALTERED); 552 } 553 554 /* 555 * Attempt to expand the size of a directory 556 */ 557 static int 558 expanddir(union dinode *dp, char *name) 559 { 560 ufs2_daddr_t lastbn, newblk; 561 struct bufarea *bp; 562 char *cp, firstblk[DIRBLKSIZ]; 563 564 lastbn = lblkno(&sblock, DIP(dp, di_size)); 565 if (lastbn >= NDADDR - 1 || DIP(dp, di_db[lastbn]) == 0 || 566 DIP(dp, di_size) == 0) 567 return (0); 568 if ((newblk = allocblk(sblock.fs_frag)) == 0) 569 return (0); 570 DIP(dp, di_db[lastbn + 1]) = DIP(dp, di_db[lastbn]); 571 DIP(dp, di_db[lastbn]) = newblk; 572 DIP(dp, di_size) += sblock.fs_bsize; 573 DIP(dp, di_blocks) += btodb(sblock.fs_bsize); 574 bp = getdirblk(DIP(dp, di_db[lastbn + 1]), 575 sblksize(&sblock, DIP(dp, di_size), lastbn + 1)); 576 if (bp->b_errs) 577 goto bad; 578 memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 579 bp = getdirblk(newblk, sblock.fs_bsize); 580 if (bp->b_errs) 581 goto bad; 582 memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 583 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 584 cp < &bp->b_un.b_buf[sblock.fs_bsize]; 585 cp += DIRBLKSIZ) 586 memmove(cp, &emptydir, sizeof emptydir); 587 dirty(bp); 588 bp = getdirblk(DIP(dp, di_db[lastbn + 1]), 589 sblksize(&sblock, DIP(dp, di_size), lastbn + 1)); 590 if (bp->b_errs) 591 goto bad; 592 memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 593 pwarn("NO SPACE LEFT IN %s", name); 594 if (preen) 595 printf(" (EXPANDED)\n"); 596 else if (reply("EXPAND") == 0) 597 goto bad; 598 dirty(bp); 599 inodirty(); 600 return (1); 601 bad: 602 DIP(dp, di_db[lastbn]) = DIP(dp, di_db[lastbn + 1]); 603 DIP(dp, di_db[lastbn + 1]) = 0; 604 DIP(dp, di_size) -= sblock.fs_bsize; 605 DIP(dp, di_blocks) -= btodb(sblock.fs_bsize); 606 freeblk(newblk, sblock.fs_frag); 607 return (0); 608 } 609 610 /* 611 * allocate a new directory 612 */ 613 ino_t 614 allocdir(ino_t parent, ino_t request, int mode) 615 { 616 ino_t ino; 617 char *cp; 618 union dinode *dp; 619 struct bufarea *bp; 620 struct inoinfo *inp; 621 struct dirtemplate *dirp; 622 623 ino = allocino(request, IFDIR|mode); 624 dirp = &dirhead; 625 dirp->dot_ino = ino; 626 dirp->dotdot_ino = parent; 627 dp = ginode(ino); 628 bp = getdirblk(DIP(dp, di_db[0]), sblock.fs_fsize); 629 if (bp->b_errs) { 630 freeino(ino); 631 return (0); 632 } 633 memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 634 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 635 cp < &bp->b_un.b_buf[sblock.fs_fsize]; 636 cp += DIRBLKSIZ) 637 memmove(cp, &emptydir, sizeof emptydir); 638 dirty(bp); 639 DIP(dp, di_nlink) = 2; 640 inodirty(); 641 if (ino == ROOTINO) { 642 inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink); 643 cacheino(dp, ino); 644 return(ino); 645 } 646 if (inoinfo(parent)->ino_state != DSTATE && 647 inoinfo(parent)->ino_state != DFOUND) { 648 freeino(ino); 649 return (0); 650 } 651 cacheino(dp, ino); 652 inp = getinoinfo(ino); 653 inp->i_parent = parent; 654 inp->i_dotdot = parent; 655 inoinfo(ino)->ino_state = inoinfo(parent)->ino_state; 656 if (inoinfo(ino)->ino_state == DSTATE) { 657 inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink); 658 inoinfo(parent)->ino_linkcnt++; 659 } 660 dp = ginode(parent); 661 DIP(dp, di_nlink)++; 662 inodirty(); 663 return (ino); 664 } 665 666 /* 667 * free a directory inode 668 */ 669 static void 670 freedir(ino_t ino, ino_t parent) 671 { 672 union dinode *dp; 673 674 if (ino != parent) { 675 dp = ginode(parent); 676 DIP(dp, di_nlink)--; 677 inodirty(); 678 } 679 freeino(ino); 680 } 681 682 /* 683 * generate a temporary name for the lost+found directory. 684 */ 685 static int 686 lftempname(char *bufp, ino_t ino) 687 { 688 ino_t in; 689 char *cp; 690 int namlen; 691 692 cp = bufp + 2; 693 for (in = maxino; in > 0; in /= 10) 694 cp++; 695 *--cp = 0; 696 namlen = cp - bufp; 697 in = ino; 698 while (cp > bufp) { 699 *--cp = (in % 10) + '0'; 700 in /= 10; 701 } 702 *cp = '#'; 703 return (namlen); 704 } 705 706 /* 707 * Get a directory block. 708 * Insure that it is held until another is requested. 709 */ 710 static struct bufarea * 711 getdirblk(ufs2_daddr_t blkno, long size) 712 { 713 714 if (pdirbp != 0) 715 pdirbp->b_flags &= ~B_INUSE; 716 pdirbp = getdatablk(blkno, size); 717 return (pdirbp); 718 } 719