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