1 /* $NetBSD: dir.c,v 1.32 2013/06/18 18:18:58 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/time.h> 35 #include <sys/buf.h> 36 #include <sys/mount.h> 37 38 #include <ufs/lfs/lfs.h> 39 #include <ufs/lfs/lfs_inode.h> 40 41 #include <err.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 46 #include "bufcache.h" 47 #include "vnode.h" 48 #include "lfs_user.h" 49 50 #include "fsck.h" 51 #include "fsutil.h" 52 #include "extern.h" 53 54 const char *lfname = "lost+found"; 55 int lfmode = 01700; 56 struct lfs_dirtemplate emptydir = { 57 .dot_ino = 0, 58 .dot_reclen = LFS_DIRBLKSIZ, 59 }; 60 struct lfs_dirtemplate dirhead = { 61 .dot_ino = 0, 62 .dot_reclen = 12, 63 .dot_type = LFS_DT_DIR, 64 .dot_namlen = 1, 65 .dot_name = ".", 66 .dotdot_ino = 0, 67 .dotdot_reclen = LFS_DIRBLKSIZ - 12, 68 .dotdot_type = LFS_DT_DIR, 69 .dotdot_namlen = 2, 70 .dotdot_name = ".." 71 }; 72 struct lfs_odirtemplate odirhead = { 73 .dot_ino = 0, 74 .dot_reclen = 12, 75 .dot_namlen = 1, 76 .dot_name = ".", 77 .dotdot_ino = 0, 78 .dotdot_reclen = LFS_DIRBLKSIZ - 12, 79 .dotdot_namlen = 2, 80 .dotdot_name = ".." 81 }; 82 83 static int expanddir(struct uvnode *, struct ulfs1_dinode *, char *); 84 static void freedir(ino_t, ino_t); 85 static struct lfs_direct *fsck_readdir(struct uvnode *, struct inodesc *); 86 static int lftempname(char *, ino_t); 87 static int mkentry(struct inodesc *); 88 static int chgino(struct inodesc *); 89 90 /* 91 * Propagate connected state through the tree. 92 */ 93 void 94 propagate(void) 95 { 96 struct inoinfo **inpp, *inp, *pinp; 97 struct inoinfo **inpend; 98 99 /* 100 * Create a list of children for each directory. 101 */ 102 inpend = &inpsort[inplast]; 103 for (inpp = inpsort; inpp < inpend; inpp++) { 104 inp = *inpp; 105 if (inp->i_parent == 0 || 106 inp->i_number == ULFS_ROOTINO) 107 continue; 108 pinp = getinoinfo(inp->i_parent); 109 inp->i_parentp = pinp; 110 inp->i_sibling = pinp->i_child; 111 pinp->i_child = inp; 112 } 113 inp = getinoinfo(ULFS_ROOTINO); 114 while (inp) { 115 statemap[inp->i_number] = DFOUND; 116 if (inp->i_child && 117 statemap[inp->i_child->i_number] == DSTATE) 118 inp = inp->i_child; 119 else if (inp->i_sibling) 120 inp = inp->i_sibling; 121 else 122 inp = inp->i_parentp; 123 } 124 } 125 126 /* 127 * Scan each entry in a directory block. 128 */ 129 int 130 dirscan(struct inodesc *idesc) 131 { 132 struct lfs_direct *dp; 133 struct ubuf *bp; 134 int dsize, n; 135 long blksiz; 136 char dbuf[LFS_DIRBLKSIZ]; 137 struct uvnode *vp; 138 139 if (idesc->id_type != DATA) 140 errexit("wrong type to dirscan %d", idesc->id_type); 141 if (idesc->id_entryno == 0 && 142 (idesc->id_filesize & (LFS_DIRBLKSIZ - 1)) != 0) 143 idesc->id_filesize = roundup(idesc->id_filesize, LFS_DIRBLKSIZ); 144 blksiz = idesc->id_numfrags * fs->lfs_fsize; 145 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 146 idesc->id_filesize -= blksiz; 147 return (SKIP); 148 } 149 idesc->id_loc = 0; 150 151 vp = vget(fs, idesc->id_number); 152 for (dp = fsck_readdir(vp, idesc); dp != NULL; 153 dp = fsck_readdir(vp, idesc)) { 154 dsize = dp->d_reclen; 155 memcpy(dbuf, dp, (size_t) dsize); 156 idesc->id_dirp = (struct lfs_direct *) dbuf; 157 if ((n = (*idesc->id_func) (idesc)) & ALTERED) { 158 bread(vp, idesc->id_lblkno, blksiz, NOCRED, 0, &bp); 159 memcpy(bp->b_data + idesc->id_loc - dsize, dbuf, 160 (size_t) dsize); 161 VOP_BWRITE(bp); 162 sbdirty(); 163 } 164 if (n & STOP) 165 return (n); 166 } 167 return (idesc->id_filesize > 0 ? KEEPON : STOP); 168 } 169 170 /* 171 * get next entry in a directory. 172 */ 173 static struct lfs_direct * 174 fsck_readdir(struct uvnode *vp, struct inodesc *idesc) 175 { 176 struct lfs_direct *dp, *ndp; 177 struct ubuf *bp; 178 long size, blksiz, fix, dploc; 179 180 blksiz = idesc->id_numfrags * fs->lfs_fsize; 181 bread(vp, idesc->id_lblkno, blksiz, NOCRED, 0, &bp); 182 if (idesc->id_loc % LFS_DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 183 idesc->id_loc < blksiz) { 184 dp = (struct lfs_direct *) (bp->b_data + idesc->id_loc); 185 if (dircheck(idesc, dp)) 186 goto dpok; 187 brelse(bp, 0); 188 if (idesc->id_fix == IGNORE) 189 return (0); 190 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 191 bread(vp, idesc->id_lblkno, blksiz, NOCRED, 0, &bp); 192 dp = (struct lfs_direct *) (bp->b_data + idesc->id_loc); 193 dp->d_reclen = LFS_DIRBLKSIZ; 194 dp->d_ino = 0; 195 dp->d_type = 0; 196 dp->d_namlen = 0; 197 dp->d_name[0] = '\0'; 198 if (fix) 199 VOP_BWRITE(bp); 200 else 201 brelse(bp, 0); 202 idesc->id_loc += LFS_DIRBLKSIZ; 203 idesc->id_filesize -= LFS_DIRBLKSIZ; 204 return (dp); 205 } 206 dpok: 207 if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) { 208 brelse(bp, 0); 209 return NULL; 210 } 211 dploc = idesc->id_loc; 212 dp = (struct lfs_direct *) (bp->b_data + dploc); 213 idesc->id_loc += dp->d_reclen; 214 idesc->id_filesize -= dp->d_reclen; 215 if ((idesc->id_loc % LFS_DIRBLKSIZ) == 0) { 216 brelse(bp, 0); 217 return dp; 218 } 219 ndp = (struct lfs_direct *) (bp->b_data + idesc->id_loc); 220 if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 221 dircheck(idesc, ndp) == 0) { 222 brelse(bp, 0); 223 size = LFS_DIRBLKSIZ - (idesc->id_loc % LFS_DIRBLKSIZ); 224 idesc->id_loc += size; 225 idesc->id_filesize -= size; 226 if (idesc->id_fix == IGNORE) 227 return 0; 228 fix = dofix(idesc, "DIRECTORY CORRUPTED"); 229 bread(vp, idesc->id_lblkno, blksiz, NOCRED, 0, &bp); 230 dp = (struct lfs_direct *) (bp->b_data + dploc); 231 dp->d_reclen += size; 232 if (fix) 233 VOP_BWRITE(bp); 234 else 235 brelse(bp, 0); 236 } else 237 brelse(bp, 0); 238 239 return (dp); 240 } 241 242 /* 243 * Verify that a directory entry is valid. 244 * This is a superset of the checks made in the kernel. 245 */ 246 int 247 dircheck(struct inodesc *idesc, struct lfs_direct *dp) 248 { 249 int size; 250 char *cp; 251 u_char namlen, type; 252 int spaceleft; 253 254 spaceleft = LFS_DIRBLKSIZ - (idesc->id_loc % LFS_DIRBLKSIZ); 255 if (dp->d_ino >= maxino || 256 dp->d_reclen == 0 || 257 dp->d_reclen > spaceleft || 258 (dp->d_reclen & 0x3) != 0) { 259 pwarn("ino too large, reclen=0, reclen>space, or reclen&3!=0\n"); 260 pwarn("dp->d_ino = 0x%x\tdp->d_reclen = 0x%x\n", 261 dp->d_ino, dp->d_reclen); 262 pwarn("maxino = %llu\tspaceleft = 0x%x\n", 263 (unsigned long long)maxino, spaceleft); 264 return (0); 265 } 266 if (dp->d_ino == 0) 267 return (1); 268 size = LFS_DIRSIZ(0, dp, 0); 269 namlen = dp->d_namlen; 270 type = dp->d_type; 271 if (dp->d_reclen < size || 272 idesc->id_filesize < size || 273 /* namlen > MAXNAMLEN || */ 274 type > 15) { 275 printf("reclen<size, filesize<size, namlen too large, or type>15\n"); 276 return (0); 277 } 278 for (cp = dp->d_name, size = 0; size < namlen; size++) 279 if (*cp == '\0' || (*cp++ == '/')) { 280 printf("name contains NUL or /\n"); 281 return (0); 282 } 283 if (*cp != '\0') { 284 printf("name size misstated\n"); 285 return (0); 286 } 287 return (1); 288 } 289 290 void 291 direrror(ino_t ino, const char *errmesg) 292 { 293 294 fileerror(ino, ino, errmesg); 295 } 296 297 void 298 fileerror(ino_t cwd, ino_t ino, const char *errmesg) 299 { 300 char pathbuf[MAXPATHLEN + 1]; 301 struct uvnode *vp; 302 303 pwarn("%s ", errmesg); 304 pinode(ino); 305 printf("\n"); 306 pwarn("PARENT=%lld\n", (long long)cwd); 307 getpathname(pathbuf, sizeof(pathbuf), cwd, ino); 308 if (ino < ULFS_ROOTINO || ino >= maxino) { 309 pfatal("NAME=%s\n", pathbuf); 310 return; 311 } 312 vp = vget(fs, ino); 313 if (vp == NULL) 314 pfatal("INO is NULL\n"); 315 else { 316 if (ftypeok(VTOD(vp))) 317 pfatal("%s=%s\n", 318 (VTOI(vp)->i_ffs1_mode & LFS_IFMT) == LFS_IFDIR ? 319 "DIR" : "FILE", pathbuf); 320 else 321 pfatal("NAME=%s\n", pathbuf); 322 } 323 } 324 325 void 326 adjust(struct inodesc *idesc, short lcnt) 327 { 328 struct uvnode *vp; 329 struct ulfs1_dinode *dp; 330 331 vp = vget(fs, idesc->id_number); 332 dp = VTOD(vp); 333 if (dp->di_nlink == lcnt) { 334 if (linkup(idesc->id_number, (ino_t) 0) == 0) 335 clri(idesc, "UNREF", 0); 336 } else { 337 pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 338 ((dp->di_mode & LFS_IFMT) == LFS_IFDIR ? "DIR" : "FILE")); 339 pinode(idesc->id_number); 340 printf(" COUNT %d SHOULD BE %d", 341 dp->di_nlink, dp->di_nlink - lcnt); 342 if (preen) { 343 if (lcnt < 0) { 344 printf("\n"); 345 pfatal("LINK COUNT INCREASING"); 346 } 347 printf(" (ADJUSTED)\n"); 348 } 349 if (preen || reply("ADJUST") == 1) { 350 dp->di_nlink -= lcnt; 351 inodirty(VTOI(vp)); 352 } 353 } 354 } 355 356 static int 357 mkentry(struct inodesc *idesc) 358 { 359 struct lfs_direct *dirp = idesc->id_dirp; 360 struct lfs_direct newent; 361 int newlen, oldlen; 362 363 newent.d_namlen = strlen(idesc->id_name); 364 newlen = LFS_DIRSIZ(0, &newent, 0); 365 if (dirp->d_ino != 0) 366 oldlen = LFS_DIRSIZ(0, dirp, 0); 367 else 368 oldlen = 0; 369 if (dirp->d_reclen - oldlen < newlen) 370 return (KEEPON); 371 newent.d_reclen = dirp->d_reclen - oldlen; 372 dirp->d_reclen = oldlen; 373 dirp = (struct lfs_direct *) (((char *) dirp) + oldlen); 374 dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ 375 dirp->d_reclen = newent.d_reclen; 376 dirp->d_type = typemap[idesc->id_parent]; 377 dirp->d_namlen = newent.d_namlen; 378 memcpy(dirp->d_name, idesc->id_name, (size_t) dirp->d_namlen + 1); 379 return (ALTERED | STOP); 380 } 381 382 static int 383 chgino(struct inodesc *idesc) 384 { 385 struct lfs_direct *dirp = idesc->id_dirp; 386 387 if (memcmp(dirp->d_name, idesc->id_name, (int) dirp->d_namlen + 1)) 388 return (KEEPON); 389 dirp->d_ino = idesc->id_parent; 390 dirp->d_type = typemap[idesc->id_parent]; 391 return (ALTERED | STOP); 392 } 393 394 int 395 linkup(ino_t orphan, ino_t parentdir) 396 { 397 struct ulfs1_dinode *dp; 398 int lostdir; 399 ino_t oldlfdir; 400 struct inodesc idesc; 401 char tempname[BUFSIZ]; 402 struct uvnode *vp; 403 404 memset(&idesc, 0, sizeof(struct inodesc)); 405 vp = vget(fs, orphan); 406 dp = VTOD(vp); 407 lostdir = (dp->di_mode & LFS_IFMT) == LFS_IFDIR; 408 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 409 pinode(orphan); 410 if (preen && dp->di_size == 0) 411 return (0); 412 if (preen) 413 printf(" (RECONNECTED)\n"); 414 else if (reply("RECONNECT") == 0) 415 return (0); 416 if (lfdir == 0) { 417 dp = ginode(ULFS_ROOTINO); 418 idesc.id_name = lfname; 419 idesc.id_type = DATA; 420 idesc.id_func = findino; 421 idesc.id_number = ULFS_ROOTINO; 422 if ((ckinode(dp, &idesc) & FOUND) != 0) { 423 lfdir = idesc.id_parent; 424 } else { 425 pwarn("NO lost+found DIRECTORY"); 426 if (preen || reply("CREATE")) { 427 lfdir = allocdir(ULFS_ROOTINO, (ino_t) 0, lfmode); 428 if (lfdir != 0) { 429 if (makeentry(ULFS_ROOTINO, lfdir, lfname) != 0) { 430 if (preen) 431 printf(" (CREATED)\n"); 432 } else { 433 freedir(lfdir, ULFS_ROOTINO); 434 lfdir = 0; 435 if (preen) 436 printf("\n"); 437 } 438 } 439 } 440 } 441 if (lfdir == 0) { 442 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 443 printf("\n\n"); 444 return (0); 445 } 446 } 447 vp = vget(fs, lfdir); 448 dp = VTOD(vp); 449 if ((dp->di_mode & LFS_IFMT) != LFS_IFDIR) { 450 pfatal("lost+found IS NOT A DIRECTORY"); 451 if (reply("REALLOCATE") == 0) 452 return (0); 453 oldlfdir = lfdir; 454 if ((lfdir = allocdir(ULFS_ROOTINO, (ino_t) 0, lfmode)) == 0) { 455 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 456 return (0); 457 } 458 if ((changeino(ULFS_ROOTINO, lfname, lfdir) & ALTERED) == 0) { 459 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 460 return (0); 461 } 462 inodirty(VTOI(vp)); 463 idesc.id_type = ADDR; 464 idesc.id_func = pass4check; 465 idesc.id_number = oldlfdir; 466 adjust(&idesc, lncntp[oldlfdir] + 1); 467 lncntp[oldlfdir] = 0; 468 vp = vget(fs, lfdir); 469 dp = VTOD(vp); 470 } 471 if (statemap[lfdir] != DFOUND) { 472 pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 473 return (0); 474 } 475 (void) lftempname(tempname, orphan); 476 if (makeentry(lfdir, orphan, tempname) == 0) { 477 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 478 printf("\n\n"); 479 return (0); 480 } 481 lncntp[orphan]--; 482 if (lostdir) { 483 if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 484 parentdir != (ino_t) - 1) 485 (void) makeentry(orphan, lfdir, ".."); 486 vp = vget(fs, lfdir); 487 VTOI(vp)->i_ffs1_nlink++; 488 inodirty(VTOI(vp)); 489 lncntp[lfdir]++; 490 pwarn("DIR I=%llu CONNECTED. ", (unsigned long long)orphan); 491 if (parentdir != (ino_t) - 1) 492 printf("PARENT WAS I=%llu\n", 493 (unsigned long long)parentdir); 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, const 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 516 return (ckinode(ginode(dir), &idesc)); 517 } 518 519 /* 520 * make an entry in a directory 521 */ 522 int 523 makeentry(ino_t parent, ino_t ino, const char *name) 524 { 525 struct ulfs1_dinode *dp; 526 struct inodesc idesc; 527 char pathbuf[MAXPATHLEN + 1]; 528 struct uvnode *vp; 529 530 if (parent < ULFS_ROOTINO || parent >= maxino || 531 ino < ULFS_ROOTINO || ino >= maxino) 532 return (0); 533 memset(&idesc, 0, sizeof(struct inodesc)); 534 idesc.id_type = DATA; 535 idesc.id_func = mkentry; 536 idesc.id_number = parent; 537 idesc.id_parent = ino; /* this is the inode to enter */ 538 idesc.id_fix = DONTKNOW; 539 idesc.id_name = name; 540 vp = vget(fs, parent); 541 dp = VTOD(vp); 542 if (dp->di_size % LFS_DIRBLKSIZ) { 543 dp->di_size = roundup(dp->di_size, LFS_DIRBLKSIZ); 544 inodirty(VTOI(vp)); 545 } 546 if ((ckinode(dp, &idesc) & ALTERED) != 0) 547 return (1); 548 getpathname(pathbuf, sizeof(pathbuf), parent, parent); 549 vp = vget(fs, parent); 550 dp = VTOD(vp); 551 if (expanddir(vp, dp, pathbuf) == 0) 552 return (0); 553 return (ckinode(dp, &idesc) & ALTERED); 554 } 555 556 /* 557 * Attempt to expand the size of a directory 558 */ 559 static int 560 expanddir(struct uvnode *vp, struct ulfs1_dinode *dp, char *name) 561 { 562 daddr_t lastbn; 563 struct ubuf *bp; 564 char *cp, firstblk[LFS_DIRBLKSIZ]; 565 566 lastbn = lfs_lblkno(fs, dp->di_size); 567 if (lastbn >= ULFS_NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) 568 return (0); 569 dp->di_db[lastbn + 1] = dp->di_db[lastbn]; 570 dp->di_db[lastbn] = 0; 571 bp = getblk(vp, lastbn, fs->lfs_bsize); 572 VOP_BWRITE(bp); 573 dp->di_size += fs->lfs_bsize; 574 dp->di_blocks += lfs_btofsb(fs, fs->lfs_bsize); 575 bread(vp, dp->di_db[lastbn + 1], 576 (long) lfs_dblksize(fs, dp, lastbn + 1), NOCRED, 0, &bp); 577 if (bp->b_flags & B_ERROR) 578 goto bad; 579 memcpy(firstblk, bp->b_data, LFS_DIRBLKSIZ); 580 bread(vp, lastbn, fs->lfs_bsize, NOCRED, 0, &bp); 581 if (bp->b_flags & B_ERROR) 582 goto bad; 583 memcpy(bp->b_data, firstblk, LFS_DIRBLKSIZ); 584 for (cp = &bp->b_data[LFS_DIRBLKSIZ]; 585 cp < &bp->b_data[fs->lfs_bsize]; 586 cp += LFS_DIRBLKSIZ) 587 memcpy(cp, &emptydir, sizeof emptydir); 588 VOP_BWRITE(bp); 589 bread(vp, dp->di_db[lastbn + 1], 590 (long) lfs_dblksize(fs, dp, lastbn + 1), NOCRED, 0, &bp); 591 if (bp->b_flags & B_ERROR) 592 goto bad; 593 memcpy(bp->b_data, &emptydir, sizeof emptydir); 594 pwarn("NO SPACE LEFT IN %s", name); 595 if (preen) 596 printf(" (EXPANDED)\n"); 597 else if (reply("EXPAND") == 0) 598 goto bad; 599 VOP_BWRITE(bp); 600 inodirty(VTOI(vp)); 601 return (1); 602 bad: 603 dp->di_db[lastbn] = dp->di_db[lastbn + 1]; 604 dp->di_db[lastbn + 1] = 0; 605 dp->di_size -= fs->lfs_bsize; 606 dp->di_blocks -= lfs_btofsb(fs, fs->lfs_bsize); 607 return (0); 608 } 609 610 /* 611 * allocate a new directory 612 */ 613 int 614 allocdir(ino_t parent, ino_t request, int mode) 615 { 616 ino_t ino; 617 char *cp; 618 struct ulfs1_dinode *dp; 619 struct ubuf *bp; 620 struct lfs_dirtemplate *dirp; 621 struct uvnode *vp; 622 623 ino = allocino(request, LFS_IFDIR | mode); 624 dirp = &dirhead; 625 dirp->dot_ino = ino; 626 dirp->dotdot_ino = parent; 627 vp = vget(fs, ino); 628 dp = VTOD(vp); 629 bread(vp, dp->di_db[0], fs->lfs_fsize, NOCRED, 0, &bp); 630 if (bp->b_flags & B_ERROR) { 631 brelse(bp, 0); 632 freeino(ino); 633 return (0); 634 } 635 memcpy(bp->b_data, dirp, sizeof(struct lfs_dirtemplate)); 636 for (cp = &bp->b_data[LFS_DIRBLKSIZ]; 637 cp < &bp->b_data[fs->lfs_fsize]; 638 cp += LFS_DIRBLKSIZ) 639 memcpy(cp, &emptydir, sizeof emptydir); 640 VOP_BWRITE(bp); 641 dp->di_nlink = 2; 642 inodirty(VTOI(vp)); 643 if (ino == ULFS_ROOTINO) { 644 lncntp[ino] = dp->di_nlink; 645 cacheino(dp, ino); 646 return (ino); 647 } 648 if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 649 freeino(ino); 650 return (0); 651 } 652 cacheino(dp, ino); 653 statemap[ino] = statemap[parent]; 654 if (statemap[ino] == DSTATE) { 655 lncntp[ino] = dp->di_nlink; 656 lncntp[parent]++; 657 } 658 vp = vget(fs, parent); 659 dp = VTOD(vp); 660 dp->di_nlink++; 661 inodirty(VTOI(vp)); 662 return (ino); 663 } 664 665 /* 666 * free a directory inode 667 */ 668 static void 669 freedir(ino_t ino, ino_t parent) 670 { 671 struct uvnode *vp; 672 673 if (ino != parent) { 674 vp = vget(fs, parent); 675 VTOI(vp)->i_ffs1_nlink--; 676 inodirty(VTOI(vp)); 677 } 678 freeino(ino); 679 } 680 681 /* 682 * generate a temporary name for the lost+found directory. 683 */ 684 static int 685 lftempname(char *bufp, ino_t ino) 686 { 687 ino_t in; 688 char *cp; 689 int namlen; 690 691 cp = bufp + 2; 692 for (in = maxino; in > 0; in /= 10) 693 cp++; 694 *--cp = 0; 695 namlen = cp - bufp; 696 in = ino; 697 while (cp > bufp) { 698 *--cp = (in % 10) + '0'; 699 in /= 10; 700 } 701 *cp = '#'; 702 return (namlen); 703 } 704