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