hjfs: dentry qid checking, prevent newentry() from allocating already in use slot
always check if the directory entry qid from the loc still matches the one on disk before doing anything. helps catching bugs and is basically equivalent to what cwfs does with its checktag. make a haveloc() check in newentry() to make sure we dont allocate a file slot thats still in use, but deleted. this seems to fix the NPROC>1 build problems.
This commit is contained in:
parent
ffa6f9c6ea
commit
b9bf9f1d54
5 changed files with 136 additions and 47 deletions
|
@ -269,7 +269,8 @@ getbuf(Dev *d, uvlong off, int type, int nodata)
|
|||
if(nodata)
|
||||
b->type = type;
|
||||
if(b->type != type && type != -1){
|
||||
dprint("hjfs: type mismatch, dev %s, block %lld, got %T, want %T, caller %#p\n", d->name, off, b->type, type, getcallerpc(&d));
|
||||
dprint("hjfs: type mismatch, dev %s, block %lld, got %T, want %T, caller %#p\n",
|
||||
d->name, off, b->type, type, getcallerpc(&d));
|
||||
werrstr("phase error -- type mismatch");
|
||||
putbuf(b);
|
||||
return nil;
|
||||
|
|
|
@ -143,8 +143,8 @@ again:
|
|||
p = getbuf(fs->d, l->next->blk, TDENTRY, 0);
|
||||
if(p == nil)
|
||||
goto err;
|
||||
d = &p->de[l->next->deind];
|
||||
for(i = 0; i < d->size; i++){
|
||||
d = getdent(l->next, p);
|
||||
if(d != nil) for(i = 0; i < d->size; i++){
|
||||
rc = getblk(fs, l->next, p, i, &r, GBREAD);
|
||||
if(rc <= 0)
|
||||
continue;
|
||||
|
|
|
@ -8,6 +8,7 @@ void unpack(Buf *, uchar *);
|
|||
Dev* newdev(char *);
|
||||
ThrData* getthrdata(void);
|
||||
Fs* initfs(Dev *, int, int);
|
||||
Dentry* getdent(FLoc *, Buf *);
|
||||
int getfree(Fs *, uvlong *);
|
||||
int putfree(Fs *, uvlong);
|
||||
Chan* chanattach(Fs *, int);
|
||||
|
|
|
@ -29,6 +29,35 @@ chref(Fs *fs, uvlong r, int stat)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
qidcmp(Qid *a, Qid *b)
|
||||
{
|
||||
if(a->type != b->type)
|
||||
return 1;
|
||||
if(a->path != b->path)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Dentry*
|
||||
getdent(FLoc *l, Buf *b)
|
||||
{
|
||||
Dentry *d;
|
||||
|
||||
d = &b->de[l->deind];
|
||||
if((d->mode & (DGONE | DALLOC)) == 0){
|
||||
dprint("hjfs: getdent: file gone, callerpc %#p\n", getcallerpc(&l));
|
||||
werrstr("phase error -- getdent");
|
||||
return nil;
|
||||
}
|
||||
if(qidcmp(d, l) != 0){
|
||||
dprint("hjfs: getdent: wrong qid, callerpc %#p\n", getcallerpc(&l));
|
||||
werrstr("phase error -- getdent");
|
||||
return nil;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
int
|
||||
getfree(Fs *fs, uvlong *r)
|
||||
{
|
||||
|
@ -364,13 +393,13 @@ haveloc(Fs *fs, uvlong blk, int deind, Loc *next)
|
|||
|
||||
qlock(&fs->loctree);
|
||||
l = next->child;
|
||||
do{
|
||||
if(l != nil) do{
|
||||
if(l->blk == blk && l->deind == deind){
|
||||
qunlock(&fs->loctree);
|
||||
return 1;
|
||||
}
|
||||
l = l->cnext;
|
||||
}while(l != next->child);
|
||||
} while(l != next->child);
|
||||
qunlock(&fs->loctree);
|
||||
return 0;
|
||||
}
|
||||
|
@ -511,7 +540,11 @@ getblk(Fs *fs, FLoc *L, Buf *bd, uvlong blk, uvlong *r, int mode)
|
|||
Dentry *d;
|
||||
|
||||
b = bd;
|
||||
d = &bd->de[L->deind];
|
||||
d = getdent(L, b);
|
||||
if(d == nil){
|
||||
dprint("hjfs: getblk: dirent gone\n");
|
||||
return -1;
|
||||
}
|
||||
if(blk < NDIRECT){
|
||||
loc = &d->db[blk];
|
||||
goto found;
|
||||
|
@ -696,7 +729,9 @@ trunc(Fs *fs, FLoc *ll, Buf *bd, uvlong size)
|
|||
uvlong l;
|
||||
int i, j;
|
||||
|
||||
d = &bd->de[ll->deind];
|
||||
d = getdent(ll, bd);
|
||||
if(d == nil)
|
||||
return -1;
|
||||
if(size >= d->size)
|
||||
goto done;
|
||||
blk = HOWMANY(size, RBLOCK);
|
||||
|
@ -758,7 +793,9 @@ findentry(Fs *fs, FLoc *l, Buf *b, char *name, FLoc *rl, int dump)
|
|||
uvlong r;
|
||||
Buf *c;
|
||||
|
||||
d = &b->de[l->deind];
|
||||
d = getdent(l, b);
|
||||
if(d == nil)
|
||||
return -1;
|
||||
for(i = 0; i < d->size; i++){
|
||||
if(getblk(fs, l, b, i, &r, GBREAD) <= 0)
|
||||
continue;
|
||||
|
@ -816,7 +853,10 @@ deltraverse(Fs *fs, Del *p, Buf *b, Del **last)
|
|||
if(b == nil)
|
||||
return -1;
|
||||
}
|
||||
s = b->de[p->deind].size;
|
||||
d = getdent(p, b);
|
||||
if(d == nil)
|
||||
return -1;
|
||||
s = d->size;
|
||||
for(i = 0; i < s; i++){
|
||||
rc = getblk(fs, p, b, i, &r, GBREAD);
|
||||
if(rc <= 0)
|
||||
|
@ -835,6 +875,7 @@ deltraverse(Fs *fs, Del *p, Buf *b, Del **last)
|
|||
dd = emalloc(sizeof(Del));
|
||||
dd->blk = i;
|
||||
dd->deind = j;
|
||||
dd->Qid = d->Qid;
|
||||
dd->prev = *last;
|
||||
(*last)->next = dd;
|
||||
*last = dd;
|
||||
|
@ -854,8 +895,10 @@ delete(Fs *fs, FLoc *l, Buf *b)
|
|||
Dentry *d;
|
||||
Buf *c;
|
||||
Del *first, *last, *p, *q;
|
||||
|
||||
d = &b->de[l->deind];
|
||||
|
||||
d = getdent(l, b);
|
||||
if(d == nil)
|
||||
return -1;
|
||||
if((d->type & QTDIR) == 0){
|
||||
trunc(fs, l, b, 0);
|
||||
memset(d, 0, sizeof(*d));
|
||||
|
@ -873,9 +916,12 @@ delete(Fs *fs, FLoc *l, Buf *b)
|
|||
c = getbuf(fs->d, p->blk, TDENTRY, 0);
|
||||
if(c == nil)
|
||||
continue;
|
||||
trunc(fs, p, c, 0);
|
||||
memset(&c->de[p->deind], 0, sizeof(Dentry));
|
||||
c->op |= BDELWRI;
|
||||
d = getdent(p, c);
|
||||
if(d != nil){
|
||||
trunc(fs, p, c, 0);
|
||||
memset(d, 0, sizeof(*d));
|
||||
c->op |= BDELWRI;
|
||||
}
|
||||
if(p != first)
|
||||
putbuf(c);
|
||||
}
|
||||
|
@ -885,16 +931,16 @@ delete(Fs *fs, FLoc *l, Buf *b)
|
|||
int
|
||||
newentry(Fs *fs, Loc *l, Buf *b, char *name, FLoc *res)
|
||||
{
|
||||
Dentry *d;
|
||||
Dentry *d, *dd;
|
||||
uvlong i, si, r;
|
||||
int j, sj, rc;
|
||||
Buf *c;
|
||||
FLoc f;
|
||||
|
||||
si = sj = -1;
|
||||
d = &b->de[l->deind];
|
||||
for(i = 0; i <= d->size; i++){
|
||||
if(i == d->size && si != -1)
|
||||
d = getdent(l, b);
|
||||
if(d != nil) for(i = 0; i <= d->size; i++){
|
||||
if(i >= d->size && si != -1)
|
||||
break;
|
||||
rc = getblk(fs, l, b, i, &r, si == -1 ? GBCREATE : GBREAD);
|
||||
if(rc < 0)
|
||||
|
@ -906,32 +952,34 @@ newentry(Fs *fs, Loc *l, Buf *b, char *name, FLoc *res)
|
|||
continue;
|
||||
if(rc == 0){
|
||||
memset(c->de, 0, sizeof(c->de));
|
||||
if(i == d->size){
|
||||
d->size++;
|
||||
if(i >= d->size){
|
||||
d->size = i+1;
|
||||
b->op |= BDELWRI;
|
||||
}
|
||||
c->op |= BDELWRI;
|
||||
}
|
||||
for(j = 0; j < DEPERBLK; j++){
|
||||
if(si == -1 && (c->de[j].mode & DALLOC) == 0){
|
||||
si = i;
|
||||
sj = j;
|
||||
dd = &c->de[j];
|
||||
if((dd->mode & DALLOC) != 0){
|
||||
if(strcmp(dd->name, name) == 0){
|
||||
werrstr(Eexists);
|
||||
putbuf(c);
|
||||
return 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(si == -1 && (c->de[j].mode & DGONE) != 0 && !haveloc(fs, r, j, l)){
|
||||
if(si != -1 || haveloc(fs, r, j, l))
|
||||
continue;
|
||||
if((dd->mode & DGONE) != 0){
|
||||
memset(&f, 0, sizeof(f));
|
||||
f.blk = r;
|
||||
f.deind = j;
|
||||
if(delete(fs, &f, c) >= 0){
|
||||
si = i;
|
||||
sj = j;
|
||||
}
|
||||
}
|
||||
if((c->de[j].mode & DALLOC) != 0 &&
|
||||
strcmp(c->de[j].name, name) == 0){
|
||||
werrstr(Eexists);
|
||||
putbuf(c);
|
||||
return 0;
|
||||
f.Qid = dd->Qid;
|
||||
if(delete(fs, &f, c) < 0)
|
||||
continue;
|
||||
}
|
||||
si = i;
|
||||
sj = j;
|
||||
}
|
||||
putbuf(c);
|
||||
}
|
||||
|
@ -942,5 +990,6 @@ newentry(Fs *fs, Loc *l, Buf *b, char *name, FLoc *res)
|
|||
if(getblk(fs, l, b, si, &res->blk, GBWRITE) <= 0)
|
||||
return -1;
|
||||
res->deind = sj;
|
||||
res->Qid = (Qid){0, 0, 0};
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,9 @@ chanwalk(Chan *ch, char *name)
|
|||
chend(ch);
|
||||
return -1;
|
||||
}
|
||||
d = &b->de[ch->loc->deind];
|
||||
d = getdent(ch->loc, b);
|
||||
if(d == nil)
|
||||
goto error;
|
||||
if((d->type & QTDIR) == 0){
|
||||
werrstr(Enotadir);
|
||||
goto error;
|
||||
|
@ -132,7 +134,9 @@ chancreat(Chan *ch, char *name, int perm, int mode)
|
|||
chend(ch);
|
||||
return -1;
|
||||
}
|
||||
d = &b->de[ch->loc->deind];
|
||||
d = getdent(ch->loc, b);
|
||||
if(d == nil)
|
||||
goto error;
|
||||
if((d->type & QTDIR) == 0){
|
||||
werrstr(Enotadir);
|
||||
goto error;
|
||||
|
@ -146,9 +150,9 @@ chancreat(Chan *ch, char *name, int perm, int mode)
|
|||
c = getbuf(ch->fs->d, f.blk, TDENTRY, 0);
|
||||
if(c == nil)
|
||||
goto error;
|
||||
c->op |= BDELWRI;
|
||||
b->op |= BDELWRI;
|
||||
modified(ch, d);
|
||||
b->op |= BDELWRI;
|
||||
c->op |= BDELWRI;
|
||||
if(isdir)
|
||||
perm &= ~0777 | d->mode & 0777;
|
||||
else
|
||||
|
@ -213,7 +217,9 @@ chanopen(Chan *ch, int mode)
|
|||
chend(ch);
|
||||
return -1;
|
||||
}
|
||||
d = &b->de[ch->loc->deind];
|
||||
d = getdent(ch->loc, b);
|
||||
if(d == nil)
|
||||
goto err;
|
||||
if(!permcheck(ch->fs, d, ch->uid, mode & OEXEC)){
|
||||
permerr:
|
||||
werrstr(Eperm);
|
||||
|
@ -325,7 +331,12 @@ chanwrite(Chan *ch, void *buf, ulong n, uvlong off)
|
|||
chend(ch);
|
||||
return -1;
|
||||
}
|
||||
d = &b->de[ch->loc->deind];
|
||||
d = getdent(ch->loc, b);
|
||||
if(d == nil){
|
||||
putbuf(b);
|
||||
chend(ch);
|
||||
return -1;
|
||||
}
|
||||
if((d->type & QTAPPEND) != 0)
|
||||
off = d->size;
|
||||
e = off + n;
|
||||
|
@ -392,7 +403,12 @@ chanread(Chan *ch, void *buf, ulong n, uvlong off)
|
|||
chend(ch);
|
||||
return -1;
|
||||
}
|
||||
d = &b->de[ch->loc->deind];
|
||||
d = getdent(ch->loc, b);
|
||||
if(d == nil){
|
||||
putbuf(b);
|
||||
chend(ch);
|
||||
return -1;
|
||||
}
|
||||
if(off >= d->size)
|
||||
n = 0;
|
||||
else if(off + n > d->size)
|
||||
|
@ -465,6 +481,7 @@ int
|
|||
chanstat(Chan *ch, Dir *di)
|
||||
{
|
||||
Buf *b;
|
||||
Dentry *d;
|
||||
|
||||
chbegin(ch);
|
||||
b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
|
||||
|
@ -472,7 +489,13 @@ chanstat(Chan *ch, Dir *di)
|
|||
chend(ch);
|
||||
return -1;
|
||||
}
|
||||
statbuf(ch->fs, &b->de[ch->loc->deind], di, nil);
|
||||
d = getdent(ch->loc, b);
|
||||
if(d == nil){
|
||||
putbuf(b);
|
||||
chend(ch);
|
||||
return -1;
|
||||
}
|
||||
statbuf(ch->fs, d, di, nil);
|
||||
putbuf(b);
|
||||
chend(ch);
|
||||
return 0;
|
||||
|
@ -504,7 +527,12 @@ chandirread(Chan *ch, void *buf, ulong n, uvlong off)
|
|||
chend(ch);
|
||||
return -1;
|
||||
}
|
||||
d = &b->de[ch->loc->deind];
|
||||
d = getdent(ch->loc, b);
|
||||
if(d == nil){
|
||||
putbuf(b);
|
||||
chend(ch);
|
||||
return -1;
|
||||
}
|
||||
if(ch->dwblk >= d->size){
|
||||
putbuf(b);
|
||||
chend(ch);
|
||||
|
@ -590,11 +618,16 @@ chanclunk(Chan *ch)
|
|||
b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
|
||||
if(b == nil)
|
||||
goto err;
|
||||
if(!permcheck(ch->fs, &p->de[ch->loc->next->deind], ch->uid, OWRITE)){
|
||||
d = getdent(ch->loc->next, p);
|
||||
if(d == nil)
|
||||
goto err;
|
||||
if(!permcheck(ch->fs, d, ch->uid, OWRITE)){
|
||||
werrstr(Eperm);
|
||||
goto err;
|
||||
}
|
||||
d = &b->de[ch->loc->deind];
|
||||
d = getdent(ch->loc, b);
|
||||
if(d == nil)
|
||||
goto err;
|
||||
if((d->type & QTDIR) != 0 && findentry(ch->fs, ch->loc, b, nil, nil, ch->flags & CHFDUMP) != 0)
|
||||
goto inval;
|
||||
if((d->mode & DGONE) != 0)
|
||||
|
@ -653,7 +686,10 @@ chanwstat(Chan *ch, Dir *di)
|
|||
pb = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
|
||||
if(pb == nil)
|
||||
goto error;
|
||||
if(!permcheck(ch->fs, &pb->de[ch->loc->next->deind], ch->uid, OWRITE))
|
||||
d = getdent(ch->loc->next, pb);
|
||||
if(d == nil)
|
||||
goto error;
|
||||
if(!permcheck(ch->fs, d, ch->uid, OWRITE))
|
||||
goto perm;
|
||||
rc = findentry(ch->fs, ch->loc->next, pb, di->name, nil, ch->flags & CHFDUMP);
|
||||
if(rc > 0)
|
||||
|
@ -664,7 +700,9 @@ chanwstat(Chan *ch, Dir *di)
|
|||
b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
|
||||
if(b == nil)
|
||||
goto error;
|
||||
d = &b->de[ch->loc->deind];
|
||||
d = getdent(ch->loc, b);
|
||||
if(d == nil)
|
||||
goto error;
|
||||
isdir = (d->type & QTDIR) != 0;
|
||||
owner = ch->uid == d->uid || ingroup(ch->fs, ch->uid, d->gid, 1) || (ch->fs->flags & FSNOPERM) != 0;
|
||||
if((uvlong)~di->length){
|
||||
|
|
Loading…
Reference in a new issue