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 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, char *errmesg) 250 { 251 252 fileerror(ino, ino, errmesg); 253 } 254 255 void 256 fileerror(ino_t cwd, ino_t ino, 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 filesystem 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 filesystem 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 %ld\n", 337 (long)cmd.value, cmd.size); 338 if (sysctl(adjrefcnt, MIBSIZE, 0, 0, 339 &cmd, sizeof cmd) == -1) 340 rwerror("ADJUST INODE", cmd.value); 341 } 342 } 343 } 344 } 345 346 static int 347 mkentry(struct inodesc *idesc) 348 { 349 struct direct *dirp = idesc->id_dirp; 350 struct direct newent; 351 int newlen, oldlen; 352 353 newent.d_namlen = strlen(idesc->id_name); 354 newlen = DIRSIZ(0, &newent); 355 if (dirp->d_ino != 0) 356 oldlen = DIRSIZ(0, dirp); 357 else 358 oldlen = 0; 359 if (dirp->d_reclen - oldlen < newlen) 360 return (KEEPON); 361 newent.d_reclen = dirp->d_reclen - oldlen; 362 dirp->d_reclen = oldlen; 363 dirp = (struct direct *)(((char *)dirp) + oldlen); 364 dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 365 dirp->d_reclen = newent.d_reclen; 366 dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 367 dirp->d_namlen = newent.d_namlen; 368 memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); 369 return (ALTERED|STOP); 370 } 371 372 static int 373 chgino(struct inodesc *idesc) 374 { 375 struct direct *dirp = idesc->id_dirp; 376 377 if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) 378 return (KEEPON); 379 dirp->d_ino = idesc->id_parent; 380 dirp->d_type = inoinfo(idesc->id_parent)->ino_type; 381 return (ALTERED|STOP); 382 } 383 384 int 385 linkup(ino_t orphan, ino_t parentdir, char *name) 386 { 387 union dinode *dp; 388 int lostdir; 389 ino_t oldlfdir; 390 struct inodesc idesc; 391 char tempname[BUFSIZ]; 392 393 memset(&idesc, 0, sizeof(struct inodesc)); 394 dp = ginode(orphan); 395 lostdir = (DIP(dp, di_mode) & IFMT) == IFDIR; 396 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 397 pinode(orphan); 398 if (preen && DIP(dp, di_size) == 0) 399 return (0); 400 if (cursnapshot != 0) { 401 pfatal("FILE LINKUP IN SNAPSHOT"); 402 return (0); 403 } 404 if (preen) 405 printf(" (RECONNECTED)\n"); 406 else 407 if (reply("RECONNECT") == 0) 408 return (0); 409 if (lfdir == 0) { 410 dp = ginode(ROOTINO); 411 idesc.id_name = lfname; 412 idesc.id_type = DATA; 413 idesc.id_func = findino; 414 idesc.id_number = ROOTINO; 415 if ((ckinode(dp, &idesc) & FOUND) != 0) { 416 lfdir = idesc.id_parent; 417 } else { 418 pwarn("NO lost+found DIRECTORY"); 419 if (preen || reply("CREATE")) { 420 lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); 421 if (lfdir != 0) { 422 if (makeentry(ROOTINO, lfdir, lfname) != 0) { 423 numdirs++; 424 if (preen) 425 printf(" (CREATED)\n"); 426 } else { 427 freedir(lfdir, ROOTINO); 428 lfdir = 0; 429 if (preen) 430 printf("\n"); 431 } 432 } 433 } 434 } 435 if (lfdir == 0) { 436 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 437 printf("\n\n"); 438 return (0); 439 } 440 } 441 dp = ginode(lfdir); 442 if ((DIP(dp, di_mode) & IFMT) != IFDIR) { 443 pfatal("lost+found IS NOT A DIRECTORY"); 444 if (reply("REALLOCATE") == 0) 445 return (0); 446 oldlfdir = lfdir; 447 if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) { 448 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 449 return (0); 450 } 451 if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { 452 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 453 return (0); 454 } 455 inodirty(); 456 idesc.id_type = ADDR; 457 idesc.id_func = pass4check; 458 idesc.id_number = oldlfdir; 459 adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1); 460 inoinfo(oldlfdir)->ino_linkcnt = 0; 461 dp = ginode(lfdir); 462 } 463 if (inoinfo(lfdir)->ino_state != DFOUND) { 464 pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 465 return (0); 466 } 467 (void)lftempname(tempname, orphan); 468 if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) { 469 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 470 printf("\n\n"); 471 return (0); 472 } 473 inoinfo(orphan)->ino_linkcnt--; 474 if (lostdir) { 475 if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 476 parentdir != (ino_t)-1) 477 (void)makeentry(orphan, lfdir, ".."); 478 dp = ginode(lfdir); 479 DIP(dp, di_nlink)++; 480 inodirty(); 481 inoinfo(lfdir)->ino_linkcnt++; 482 pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan); 483 if (parentdir != (ino_t)-1) { 484 printf("PARENT WAS I=%lu\n", (u_long)parentdir); 485 /* 486 * The parent directory, because of the ordering 487 * guarantees, has had the link count incremented 488 * for the child, but no entry was made. This 489 * fixes the parent link count so that fsck does 490 * not need to be rerun. 491 */ 492 inoinfo(parentdir)->ino_linkcnt++; 493 } 494 if (preen == 0) 495 printf("\n"); 496 } 497 return (1); 498 } 499 500 /* 501 * fix an entry in a directory. 502 */ 503 int 504 changeino(ino_t dir, char *name, ino_t newnum) 505 { 506 struct inodesc idesc; 507 508 memset(&idesc, 0, sizeof(struct inodesc)); 509 idesc.id_type = DATA; 510 idesc.id_func = chgino; 511 idesc.id_number = dir; 512 idesc.id_fix = DONTKNOW; 513 idesc.id_name = name; 514 idesc.id_parent = newnum; /* new value for name */ 515 return (ckinode(ginode(dir), &idesc)); 516 } 517 518 /* 519 * make an entry in a directory 520 */ 521 int 522 makeentry(ino_t parent, ino_t ino, char *name) 523 { 524 union dinode *dp; 525 struct inodesc idesc; 526 char pathbuf[MAXPATHLEN + 1]; 527 528 if (parent < ROOTINO || parent >= maxino || 529 ino < ROOTINO || ino >= maxino) 530 return (0); 531 memset(&idesc, 0, sizeof(struct inodesc)); 532 idesc.id_type = DATA; 533 idesc.id_func = mkentry; 534 idesc.id_number = parent; 535 idesc.id_parent = ino; /* this is the inode to enter */ 536 idesc.id_fix = DONTKNOW; 537 idesc.id_name = name; 538 dp = ginode(parent); 539 if (DIP(dp, di_size) % DIRBLKSIZ) { 540 DIP(dp, di_size) = roundup(DIP(dp, di_size), DIRBLKSIZ); 541 inodirty(); 542 } 543 if ((ckinode(dp, &idesc) & ALTERED) != 0) 544 return (1); 545 getpathname(pathbuf, parent, parent); 546 dp = ginode(parent); 547 if (expanddir(dp, pathbuf) == 0) 548 return (0); 549 return (ckinode(dp, &idesc) & ALTERED); 550 } 551 552 /* 553 * Attempt to expand the size of a directory 554 */ 555 static int 556 expanddir(union dinode *dp, char *name) 557 { 558 ufs2_daddr_t lastbn, newblk; 559 struct bufarea *bp; 560 char *cp, firstblk[DIRBLKSIZ]; 561 562 lastbn = lblkno(&sblock, DIP(dp, di_size)); 563 if (lastbn >= NDADDR - 1 || DIP(dp, di_db[lastbn]) == 0 || 564 DIP(dp, di_size) == 0) 565 return (0); 566 if ((newblk = allocblk(sblock.fs_frag)) == 0) 567 return (0); 568 DIP(dp, di_db[lastbn + 1]) = DIP(dp, di_db[lastbn]); 569 DIP(dp, di_db[lastbn]) = newblk; 570 DIP(dp, di_size) += sblock.fs_bsize; 571 DIP(dp, di_blocks) += btodb(sblock.fs_bsize); 572 bp = getdirblk(DIP(dp, di_db[lastbn + 1]), 573 sblksize(&sblock, DIP(dp, di_size), lastbn + 1)); 574 if (bp->b_errs) 575 goto bad; 576 memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ); 577 bp = getdirblk(newblk, sblock.fs_bsize); 578 if (bp->b_errs) 579 goto bad; 580 memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ); 581 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 582 cp < &bp->b_un.b_buf[sblock.fs_bsize]; 583 cp += DIRBLKSIZ) 584 memmove(cp, &emptydir, sizeof emptydir); 585 dirty(bp); 586 bp = getdirblk(DIP(dp, di_db[lastbn + 1]), 587 sblksize(&sblock, DIP(dp, di_size), lastbn + 1)); 588 if (bp->b_errs) 589 goto bad; 590 memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); 591 pwarn("NO SPACE LEFT IN %s", name); 592 if (preen) 593 printf(" (EXPANDED)\n"); 594 else if (reply("EXPAND") == 0) 595 goto bad; 596 dirty(bp); 597 inodirty(); 598 return (1); 599 bad: 600 DIP(dp, di_db[lastbn]) = DIP(dp, di_db[lastbn + 1]); 601 DIP(dp, di_db[lastbn + 1]) = 0; 602 DIP(dp, di_size) -= sblock.fs_bsize; 603 DIP(dp, di_blocks) -= btodb(sblock.fs_bsize); 604 freeblk(newblk, sblock.fs_frag); 605 return (0); 606 } 607 608 /* 609 * allocate a new directory 610 */ 611 ino_t 612 allocdir(ino_t parent, ino_t request, int mode) 613 { 614 ino_t ino; 615 char *cp; 616 union dinode *dp; 617 struct bufarea *bp; 618 struct inoinfo *inp; 619 struct dirtemplate *dirp; 620 621 ino = allocino(request, IFDIR|mode); 622 dirp = &dirhead; 623 dirp->dot_ino = ino; 624 dirp->dotdot_ino = parent; 625 dp = ginode(ino); 626 bp = getdirblk(DIP(dp, di_db[0]), sblock.fs_fsize); 627 if (bp->b_errs) { 628 freeino(ino); 629 return (0); 630 } 631 memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); 632 for (cp = &bp->b_un.b_buf[DIRBLKSIZ]; 633 cp < &bp->b_un.b_buf[sblock.fs_fsize]; 634 cp += DIRBLKSIZ) 635 memmove(cp, &emptydir, sizeof emptydir); 636 dirty(bp); 637 DIP(dp, di_nlink) = 2; 638 inodirty(); 639 if (ino == ROOTINO) { 640 inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink); 641 cacheino(dp, ino); 642 return(ino); 643 } 644 if (inoinfo(parent)->ino_state != DSTATE && 645 inoinfo(parent)->ino_state != DFOUND) { 646 freeino(ino); 647 return (0); 648 } 649 cacheino(dp, ino); 650 inp = getinoinfo(ino); 651 inp->i_parent = parent; 652 inp->i_dotdot = parent; 653 inoinfo(ino)->ino_state = inoinfo(parent)->ino_state; 654 if (inoinfo(ino)->ino_state == DSTATE) { 655 inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink); 656 inoinfo(parent)->ino_linkcnt++; 657 } 658 dp = ginode(parent); 659 DIP(dp, di_nlink)++; 660 inodirty(); 661 return (ino); 662 } 663 664 /* 665 * free a directory inode 666 */ 667 static void 668 freedir(ino_t ino, ino_t parent) 669 { 670 union dinode *dp; 671 672 if (ino != parent) { 673 dp = ginode(parent); 674 DIP(dp, di_nlink)--; 675 inodirty(); 676 } 677 freeino(ino); 678 } 679 680 /* 681 * generate a temporary name for the lost+found directory. 682 */ 683 static int 684 lftempname(char *bufp, ino_t ino) 685 { 686 ino_t in; 687 char *cp; 688 int namlen; 689 690 cp = bufp + 2; 691 for (in = maxino; in > 0; in /= 10) 692 cp++; 693 *--cp = 0; 694 namlen = cp - bufp; 695 in = ino; 696 while (cp > bufp) { 697 *--cp = (in % 10) + '0'; 698 in /= 10; 699 } 700 *cp = '#'; 701 return (namlen); 702 } 703 704 /* 705 * Get a directory block. 706 * Insure that it is held until another is requested. 707 */ 708 static struct bufarea * 709 getdirblk(ufs2_daddr_t blkno, long size) 710 { 711 712 if (pdirbp != 0) 713 pdirbp->b_flags &= ~B_INUSE; 714 pdirbp = getdatablk(blkno, size); 715 return (pdirbp); 716 } 717