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