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