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