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