ref: 6d1172bebe46706be40afd60f087afd15cf485cb
parent: 2ae0be32e919e3981e3c5f1012cb9bf68b9d858a
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Dec 26 17:25:19 EST 2021
fs: correct behavior of remove() we used to allow removing nonempty dirs, and we didn't clunk the fid; fix both.
--- a/dat.h
+++ b/dat.h
@@ -52,6 +52,7 @@
Fillsz = 2, /* block fill count */
Offksz = 17, /* type, qid, off */
Snapsz = 9, /* tag, snapid */
+ Dpfxsz = 9,
Ndead = 8, /* number of deadlist heads */
Deadsz = 8+8+8+8+8, /* prev, head, head hash, tail, tail hash */
Treesz = 8+Ptrsz+Ndead*Deadsz, /* ref, height, root, deadlist */
@@ -124,6 +125,7 @@
#define Ewstatq "wstat -- qid.type/dir.mode mismatch"
#define Ewstatu "wstat -- not owner"
#define Ewstatv "wstat -- attempt to change qid.vers"
+#define Enempty "remove -- directory not empty"
//#define Echar "bad character in directory name",
@@ -139,7 +141,6 @@
//#define Ephase "phase error -- cannot happen",
//#define Eexist "create/wstat -- file exists",
//#define Edot "create/wstat -- . and .. illegal names",
-//#define Eempty "remove -- directory not empty",
//#define Ewalk "walk -- too many (system wide)",
//#define Eronly "file system read only",
//#define Efull "file system full",
--- a/fs.c
+++ b/fs.c
@@ -419,7 +419,7 @@
unlock(&fs->fidtablk);
if(o != nil){
- werrstr("fid in use: %d == %d", o->fid, new);
+ fprint(2, "fid in use: %d == %d", o->fid, new);
abort();
free(n);
return nil;
@@ -595,8 +595,7 @@
prev = o->qpath;
r.type = Rwalk;
for(i = 0; i < m->nwname; i++){
- up = prev;
- if((p = packdkey(kbuf, sizeof(kbuf), up, m->wname[i])) == nil){
+ if((p = packdkey(kbuf, sizeof(kbuf), prev, m->wname[i])) == nil){
rerror(m, Elength);
putfid(o);
return;
@@ -611,6 +610,7 @@
putfid(o);
return;
}
+ up = prev;
prev = d.qid.path;
r.wqid[i] = d.qid;
}
@@ -921,6 +921,34 @@
putfid(f);
}
+char*
+candelete(Fid *f)
+{
+ char *e, pfx[Dpfxsz];
+ int done;
+ Scan *s;
+
+ if(f->dent->qid.type == QTFILE)
+ return nil;
+ if((s = mallocz(sizeof(Scan), 1)) == nil)
+ return Enomem;
+
+ pfx[0] = Kent;
+ PBIT64(pfx+1, f->qpath);
+ if((e = btscan(&f->mnt->root, s, pfx, sizeof(pfx))) != nil){
+ btdone(s);
+ free(s);
+ return e;
+ }
+ done = 0;
+ if((e = btnext(s, &s->kv, &done)) != nil)
+ return e;
+ btdone(s);
+ if(done)
+ return nil;
+ return Enempty;
+}
+
void
fsremove(Fmsg *m)
{
@@ -935,6 +963,12 @@
}
rlock(f->dent);
+ if((e = candelete(f)) != nil){
+ runlock(f->dent);
+ rerror(m, e);
+ clunkfid(f);
+ return;
+ }
mb.op = Odelete;
mb.k = f->dent->k;
mb.nk = f->dent->nk;
@@ -942,26 +976,27 @@
if((e = btupsert(&f->mnt->root, &mb, 1)) != nil){
runlock(f->dent);
rerror(m, e);
- putfid(f);
+ clunkfid(f);
return;
}
- if((e = clearb(f, 0, f->dent->length)) != nil){
- runlock(f->dent);
- rerror(m, e);
- putfid(f);
- return;
+ if(f->dent->qid.type == QTFILE){
+ if((e = clearb(f, 0, f->dent->length)) != nil){
+ runlock(f->dent);
+ rerror(m, e);
+ clunkfid(f);
+ return;
+ }
}
runlock(f->dent);
- clunkfid(f);
if((e = updatesnap(f)) != nil){
rerror(m, e);
- putfid(f);
+ clunkfid(f);
return;
}
r.type = Rremove;
respond(m, &r);
- putfid(f);
+ clunkfid(f);
}
int
@@ -1034,7 +1069,7 @@
char*
fsreaddir(Fmsg *m, Fid *f, Fcall *r)
{
- char pfx[9], *p, *e;
+ char pfx[Dpfxsz], *p, *e;
int n, ns, done;
Scan *s;
Dir d;