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