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