/* * make an entry in a directory */ int makeentry(ino_t parent, ino_t ino, const char *name) { struct ext2fs_dinode *dp; struct inodesc idesc; char pathbuf[MAXPATHLEN + 1]; if ((parent < EXT2_FIRSTINO && parent != EXT2_ROOTINO) || parent >= maxino || (ino < EXT2_FIRSTINO && ino < EXT2_ROOTINO) || ino >= maxino) return (0); memset(&idesc, 0, sizeof(struct inodesc)); idesc.id_type = DATA; idesc.id_func = mkentry; idesc.id_number = parent; idesc.id_parent = ino; /* this is the inode to enter */ idesc.id_fix = DONTKNOW; idesc.id_name = name; dp = ginode(parent); if (inosize(dp) % sblock.e2fs_bsize) { inossize(dp, roundup(inosize(dp), sblock.e2fs_bsize)); inodirty(); } if ((ckinode(dp, &idesc) & ALTERED) != 0) return (1); getpathname(pathbuf, sizeof(pathbuf), parent, parent); dp = ginode(parent); if (expanddir(dp, pathbuf) == 0) return (0); return (ckinode(dp, &idesc) & ALTERED); }
/* * Attempt to expand the size of a directory */ static int expanddir(struct ext2fs_dinode *dp, char *name) { daddr_t lastbn, newblk; struct bufarea *bp; char *firstblk; lastbn = lblkno(&sblock, inosize(dp)); if (lastbn >= NDADDR - 1 || fs2h32(dp->e2di_blocks[lastbn]) == 0 || inosize(dp) == 0) { return (0); } if ((newblk = allocblk()) == 0) { return (0); } dp->e2di_blocks[lastbn + 1] = dp->e2di_blocks[lastbn]; dp->e2di_blocks[lastbn] = h2fs32(newblk); inossize(dp, inosize(dp) + sblock.e2fs_bsize); dp->e2di_nblock = h2fs32(fs2h32(dp->e2di_nblock) + 1); bp = getdirblk(fs2h32(dp->e2di_blocks[lastbn + 1]), sblock.e2fs_bsize); if (bp->b_errs) goto bad; if ((firstblk = malloc(sblock.e2fs_bsize)) == NULL) err(8, "cannot allocate first block"); memcpy(firstblk, bp->b_un.b_buf, sblock.e2fs_bsize); bp = getdirblk(newblk, sblock.e2fs_bsize); if (bp->b_errs) { free(firstblk); goto bad; } memcpy(bp->b_un.b_buf, firstblk, sblock.e2fs_bsize); free(firstblk); dirty(bp); bp = getdirblk(fs2h32(dp->e2di_blocks[lastbn + 1]), sblock.e2fs_bsize); if (bp->b_errs) goto bad; emptydir.dot_reclen = h2fs16(sblock.e2fs_bsize); memcpy(bp->b_un.b_buf, &emptydir, sizeof emptydir); pwarn("NO SPACE LEFT IN %s", name); if (preen) printf(" (EXPANDED)\n"); else if (reply("EXPAND") == 0) goto bad; dirty(bp); inodirty(); return (1); bad: dp->e2di_blocks[lastbn] = dp->e2di_blocks[lastbn + 1]; dp->e2di_blocks[lastbn + 1] = 0; inossize(dp, inosize(dp) - sblock.e2fs_bsize); dp->e2di_nblock = h2fs32(fs2h32(dp->e2di_nblock) - 1); freeblk(newblk); return (0); }
void pass4(void) { ino_t inumber; struct zlncnt *zlnp; struct ext2fs_dinode *dp; struct inodesc idesc; int n; memset(&idesc, 0, sizeof(struct inodesc)); idesc.id_type = ADDR; idesc.id_func = pass4check; for (inumber = EXT2_ROOTINO; inumber <= lastino; inumber++) { if (inumber < EXT2_FIRSTINO && inumber > EXT2_ROOTINO) continue; idesc.id_number = inumber; switch (statemap[inumber]) { case FSTATE: case DFOUND: n = lncntp[inumber]; if (n) adjust(&idesc, (short)n); else { for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) if (zlnp->zlncnt == inumber) { zlnp->zlncnt = zlnhead->zlncnt; zlnp = zlnhead; zlnhead = zlnhead->next; free((char *)zlnp); clri(&idesc, "UNREF", 1); break; } } break; case DSTATE: clri(&idesc, "UNREF", 1); break; case DCLEAR: dp = ginode(inumber); if (inosize(dp) == 0) { clri(&idesc, "ZERO LENGTH", 1); break; } /* fall through */ case FCLEAR: clri(&idesc, "BAD/DUP", 1); break; case USTATE: break; default: errexit("BAD STATE %d FOR INODE I=%llu\n", statemap[inumber], (unsigned long long)inumber); } } }
int linkup(ino_t orphan, ino_t parentdir) { struct ext2fs_dinode *dp; int lostdir; ino_t oldlfdir; struct inodesc idesc; char tempname[BUFSIZ]; memset(&idesc, 0, sizeof(struct inodesc)); dp = ginode(orphan); lostdir = (fs2h16(dp->e2di_mode) & IFMT) == IFDIR; pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); pinode(orphan); if (preen && inosize(dp) == 0) return (0); if (preen) printf(" (RECONNECTED)\n"); else if (reply("RECONNECT") == 0) return (0); if (lfdir == 0) { dp = ginode(EXT2_ROOTINO); idesc.id_name = lfname; idesc.id_type = DATA; idesc.id_func = findino; idesc.id_number = EXT2_ROOTINO; if ((ckinode(dp, &idesc) & FOUND) != 0) { lfdir = idesc.id_parent; } else { pwarn("NO lost+found DIRECTORY"); if (preen || reply("CREATE")) { lfdir = allocdir(EXT2_ROOTINO, (ino_t)0, lfmode); if (lfdir != 0) { if (makeentry(EXT2_ROOTINO, lfdir, lfname) != 0) { if (preen) printf(" (CREATED)\n"); } else { freedir(lfdir, EXT2_ROOTINO); lfdir = 0; if (preen) printf("\n"); } } } } if (lfdir == 0) { pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); printf("\n\n"); return (0); } } dp = ginode(lfdir); if ((fs2h16(dp->e2di_mode) & IFMT) != IFDIR) { pfatal("lost+found IS NOT A DIRECTORY"); if (reply("REALLOCATE") == 0) return (0); oldlfdir = lfdir; if ((lfdir = allocdir(EXT2_ROOTINO, (ino_t)0, lfmode)) == 0) { pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); return (0); } if ((changeino(EXT2_ROOTINO, lfname, lfdir) & ALTERED) == 0) { pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); return (0); } inodirty(); idesc.id_type = ADDR; idesc.id_func = pass4check; idesc.id_number = oldlfdir; adjust(&idesc, lncntp[oldlfdir] + 1); lncntp[oldlfdir] = 0; dp = ginode(lfdir); } if (statemap[lfdir] != DFOUND) { pfatal("SORRY. NO lost+found DIRECTORY\n\n"); return (0); } (void)lftempname(tempname, orphan); if (makeentry(lfdir, orphan, tempname) == 0) { pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); printf("\n\n"); return (0); } lncntp[orphan]--; if (lostdir) { if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && parentdir != (ino_t)-1) (void)makeentry(orphan, lfdir, ".."); dp = ginode(lfdir); dp->e2di_nlink = h2fs16(fs2h16(dp->e2di_nlink) +1); inodirty(); lncntp[lfdir]++; pwarn("DIR I=%llu CONNECTED. ", (unsigned long long)orphan); if (parentdir != (ino_t)-1) printf("PARENT WAS I=%llu\n", (unsigned long long)parentdir); if (preen == 0) printf("\n"); } return (1); }