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