V10/cmd/chuck/harder.c
#include "fs.h"
int rerunmsg;
attach(n)
{ int lf;
char x[24];
if(imap[n].type == Unalloc) {
pmesg("ino %d is unallocated, not put in lost+found\n", n);
return;
}
pmesg("re-attaching ino %d\n", n);
lf = nams(ROOTINO, "lost+found");
if(lf <= 0)
lf = mkdir(ROOTINO, "lost+found");
if(lf <= 0) {
pmesg("can't find or create /lost+found. HELP!\n");
exitcode = 1;
return;
}
sprintf(x, "%d", n);
if(addtodir(lf, n, x) >= 0) {
imap[n].nrefs++;
fixlinks(n);
}
}
mkdir(n, s)
char *s;
{ int i, b;
struct dinode *dip;
struct direct *dp;
i = alloci(Dir);
dip = (struct dinode *) (buf + 2*bsize + (i-1)*sizeof(*dip));
dip->di_mode = (IFDIR | 0777);
dip->di_uid = dip->di_gid = 0;
b = allocb(i, First);
dip->di_nlink = imap[i].nrefs = 2; /* a little lie */
dip->di_ctime = dip->di_mtime = dip->di_atime = time(0);
/* now write . and .. */
memset(buf, 0, bsize);
dp = (struct direct *) buf;
dp->d_ino = i;
strcpy(dp->d_name, ".");
dp++;
dp->d_ino = n;
strcpy(dp->d_name, "..");
if(bwrite(b, buf, 1)) {
pmesg("write of new dir blk %d failed\n", b);
return(-1);
}
/* now stick it in its parent */
if(addtodir(n, i, "lost+found") >= 0) {
wrti(i);
return(i);
}
pmesg("addtodir failed\n");
return(-1);
}
fndfr(dir, pbno, n)
int *pbno;
{ struct direct *dp;
int i;
if(bread(n, buf, 1)) {
pmesg("couldn't read dir block %d\n", n);
return(-1);
}
*pbno = n;
dp = (struct direct *) buf;
for(i = 0; i < bsize/sizeof(*dp); i++, dp++)
if(dp->d_ino == 0)
return(i);
return(-1);
}
addtodir(dir, ino, s)
char *s;
{ int i, bno;
struct direct *dp;
i = nami(dir, ino);
if(i >= 0) {
pmesg("ino %d already in dir (%d,%s) (it's ok)\n", ino, dir, prname(dir));
/* since you cared enough to ask for it: */
imap[ino].parent = dir;
return(-1);
}
i = dirsrch(dir, &bno, fndfr);
if(i < 0) {
bno = allocb(dir, Other);
wrti(dir);
memset(buf, 0, bsize);
i = 0;
}
dp = (struct direct *)buf + i;
dp->d_ino = ino;
strncpy(dp->d_name, s, DIRSIZ);
imap[ino].parent = dir;
/* if ino was a directory, its wretched pointers are wrong */
if(flags['w'] && bwrite(bno, buf, 1) < 0) {
pmesg("couldn't rewrite dir block %d\n", bno);
return(-1);
}
if(!rerunmsg++)
pmesg("!!counts may be wrong, RERUN chuck!\n");
return(0);
}
alloci(t)
{ int i;
for(i = 2; i < ninode; i++)
if(imap[i].type == Unalloc) {
imap[i].type = t;
/* and adjust some counts? */
return(i);
}
return(-1);
}
/* doesn't understand about holes BUG*/
allocb(ino, t)
{ int i, j;
long addr[NADDR];
struct dinode *dip;
dip = (struct dinode *) (buf + 2*bsize + (ino-1)*sizeof(*dip));
l3tol(addr, dip->di_addr, NADDR);
for(j = 0; j < NADDR-3; j++) /* secret knowledge!! */
if(!addr[j])
break;
if(j >= NADDR-3) {
pmesg("won't allocate indirect block (bug)%d %d\n"); /* BUG */
return(-1);
}
dip->di_size += 4096;
for(i = fblk; i < lblk; i++)
if(bmap[i].type == Free) {
bmap[i].ino = ino;
bmap[i].type = t;
addr[j] = i;
ltol3(dip->di_addr, addr, NADDR);
/* and adjust some counts? */
return(i);
}
pmesg("no more free blocks\n");
return(-1);
}
expg(dir, x, n)
{ struct direct *dp;
static struct direct nildp;
int i;
if(bread(n, buf, 1)) {
pmesg("expg read block %d failed\n", n);
return(-1);
}
dp = (struct direct *) buf;
for(i = 0; i < bsize/sizeof(*dp); i++ , dp++)
if(dp->d_ino == x) {
*dp = nildp;
if(flags['w'] && bwrite(n, buf, 1))
pmesg("couldn't rewrite dir block\n");
}
return(-1); /* in case it occurs many times in the directory */
}
/* remove the ref to the inode from a directory it's in */
/* if you want more than one, run it lots of times */
expunge(n)
{ int i, j;
j = imap[n].parent;
if(!j || imap[j].type != Dir) {
pmesg("parent is %d, not dir\n", j);
return(-1);
}
i = dirsrch(j, n, expg);
}
fixdots(ino)
{ struct dinode *dp = (struct dinode *)(buf + 2*bsize + (ino-1)*sizeof(*dp));
int addr[NADDR], i;
if(imap[ino].type == Unalloc) /* someone else really fixed it */
return;
pmesg("fixdots %s\n", prino(ino));
if(imap[ino].type != Dir) {
pmesg("fixdir called on non-dir %s\n", prino(ino));
return;
}
/* now redo all the checking and fix everything in sight */
l3tol(addr, dp->di_addr, NADDR);
if(fixfirst(ino, dp, addr[0]) < 0) {
pmesg("too hard, try rerunning chuck\n");
exitcode++;
rerunmsg++;
return;
}
for(i = 0; i < erptr; i++)
switch(erlist[i].type) {
case Enotdot: case Edotino: case Enotdotdot: case Ebadparent:
if(erlist[i].a == ino)
erlist[i].done = 1;
}
}
fixfirst(ino, dp, addr)
struct dinode *dp;
{ struct direct *d;
static struct direct nildir;
int i;
if(addr < fblk || addr >= lblk) {
pmesg("first block address %d bogus\n", addr); /* FIX */
return(-1);
}
if(bread(addr, buf, 1) < 0) {
pmesg("couldn't read %d\n", addr);
return(-1);
}
d = (struct direct *) buf;
if(firstspace() < 0) /* make space at beginning for . and .. */
return(-1);
/* this strategy may leave some link counts wrong, FIX */
/* also, who made dp->d_size large enough? FIX */
*d = nildir;
d->d_ino = ino;
strcpy(d->d_name, ".");
d++;
i = imap[ino].parent; /* what if we are a directory? FIX */
if(i < ROOTINO || i >= ninode) {
pmesg("parent is %d, and so illegal\n", i);
return(-1);
}
*d = nildir;
d->d_ino = i;
strcpy(d->d_name, "..");
if(flags['w'] && bwrite(addr, buf, 1) < 0) {
pmesg("couldn't rewrite %d\n");
return(-1);
}
return(0);
}
firstspace()
{ struct direct *dp = (struct direct *)buf;
int i, cnt, baddot, baddotdot, fa, fb;
for(fa = fb = cnt = i = 0; i < bsize/sizeof(*dp); i++) {
if(dp->d_ino)
continue;
cnt++;
if(!fa) {
fa = i;
continue;
}
if(!fb)
fb = i;
}
dp = (struct direct *) buf;
baddot = strcmp(dp->d_name, ".");
baddotdot = strcmp(dp[1].d_name, "..");
if(cnt - baddot - baddotdot < 0) {
pmesg("first block of directory overfull\n");
return(-1); /* too hard FIX */
}
if(baddot)
dp[fa] = dp[0];
if(baddotdot)
dp[fb] = dp[1];
return(0);
}
xfxnm(dir, ret, n)
int *ret;
{ struct direct *dp;
int i, j, cnt = 0;
if(bread(n, buf, 1)) {
pmesg("dir %d couldn't read dir block %d\n", dir, n);
return(*ret = -1);
}
dp = (struct direct *)buf;
for(i = 0; i < bsize/sizeof(*dp); i++, dp++) {
if(!dp->d_ino)
continue;
if(dp->d_ino == dir && dp->d_name[0] != '.') { /* FIX */
dp->d_ino = 0; /* dirs can't refer to themselves */
/* link count now wrong, in safe direction */
}
if(dp->d_ino < 1 || dp->d_ino >= ninode)
dp->d_ino = 0; /* bad inumber */
if(imap[dp->d_ino].type == Unalloc) { /* ambitious FIX*/
if(cnt++ == 10)
pmesg("...\n");
else if(cnt < 10)
pmesg("dir entry %d,%.16s unalloc inode\n", dp->d_ino,
dp->d_name);
dp->d_ino = 0;
}
for(j = 0; j < DIRSIZ; j++) {
if(!dp->d_name[j])
break;
if(dp->d_name[j] & 0x80) { /* ascii! */
dp->d_name[j] &= 0x7f;
j--; /* did we zero it? */
continue;
}
}
if(j == 0) {
pmesg("ino %d in dir %d had no name\n", dp->d_ino, dir);
pmesg("being called #%d\n", dp->d_ino);
sprintf(dp->d_name, "#%d", dp->d_ino);
continue;
}
for(; j < DIRSIZ;j++)
dp->d_name[j] = 0;
}
if(flags['w'] && bwrite(n, buf, 1)) {
pmesg("couldn't rewrite blk %d ino %d\n", n, dir);
return(*ret = -1);
}
return(-1);
}
fixnames(ino)
{ int retcode = 0, j;
(void) dirsrch(ino, &retcode, xfxnm);
if(retcode < 0) {
pmesg("fixnames failed\n");
return;
}
for(j = 0; j < erptr; j++)
if(erlist[j].type == Ebadname && erlist[j].a == ino)
erlist[j].done = 1;
}