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