shithub: gefs

Download patch

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;