shithub: gefs

Download patch

ref: db38a568c302f9d1820649849eeeaf4087b3c976
parent: 56cc98ba722d066c454b107a786b51cb740bd2b2
author: Ori Bernstein <ori@eigenstate.org>
date: Wed Dec 15 00:08:59 EST 2021

fs: first cut at implementing wstat

--- a/dat.h
+++ b/dat.h
@@ -6,6 +6,7 @@
 typedef struct Key	Key;
 typedef struct Val	Val;
 typedef struct Kvp	Kvp;
+typedef struct Xdir	Xdir;
 typedef struct Bptr	Bptr;
 typedef struct Bfree	Bfree;
 typedef struct Path	Path;
@@ -86,9 +87,11 @@
 };
 
 //#define Efs	"i will not buy this fs, it is scratched"
+#define Eimpl	"not implemented"
 #define Efs (abort(), "nope")
 #define Eio	"i/o error"
-#define Efid	"bad fid"
+#define Efid	"unknown fid"
+#define Etype	"invalid fid type"
 #define Edscan	"invalid dir scan offset"
 #define Eexist	"does not exist"
 #define Ebotch	"protocol botch"
@@ -100,11 +103,55 @@
 #define Einuse	"resource in use"
 #define Ebadf	"invalid file"
 #define Emem	"out of memory"
-#define Ename	"invalid file name"
+#define Ename	"create/wstat -- bad character in file name"
 #define Enomem	"out of memory"
 #define Eattach	"attach required"
-#define Enosnap	"no snapshot by that name exists"
+#define Enosnap	"attach -- bad specifier"
+#define Edir	"invalid directory"
+#define Ebadu	"attach -- unknown user or failed authentication"
 
+#define Ewstatb	"wstat -- unknown bits in qid.type/mode"
+#define Ewstatd	"wstat -- attempt to change directory"
+#define Ewstatg	"wstat -- not in group"
+#define Ewstatl	"wstat -- attempt to make length negative"
+#define Ewstatm	"wstat -- attempt to change muid"
+#define Ewstato	"wstat -- not owner or group leader"
+#define Ewstatp	"wstat -- attempt to change qid.path"
+#define Ewstatq	"wstat -- qid.type/dir.mode mismatch"
+#define Ewstatu	"wstat -- not owner"
+#define Ewstatv	"wstat -- attempt to change qid.vers"
+
+
+//#define Echar		"bad character in directory name",
+//#define Eopen		"read/write -- on non open fid",
+//#define Ecount	"read/write -- count too big",
+//#define Ealloc	"phase error -- directory entry not allocated",
+//#define Eqid		"phase error -- qid does not match",
+//#define Eaccess	"access permission denied",
+//#define Eentry	"directory entry not found",
+//#define Emode		"open/create -- unknown mode",
+//#define Edir1		"walk -- in a non-directory",
+//#define Edir2		"create -- in a non-directory",
+//#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",
+//#define Eoffset	"read/write -- offset negative",
+//#define Elocked	"open/create -- file is locked",
+//#define Ebroken	"read/write -- lock is broken",
+//#define Eauth		"attach -- authentication failed",
+//#define Eauth2	"read/write -- authentication unimplemented",
+//#define Etoolong	"name too long",
+//#define Efidinuse	"fid in use",
+//#define Econvert	"protocol botch",
+//#define Eversion	"version conversion",
+//#define Eauthnone	"auth -- user 'none' requires no authentication",
+//#define Eauthdisabled	"auth -- authentication disabled",	/* development */
+//#define Eauthfile	"auth -- out of auth files",
+
 /*
  * All metadata blocks share a common header:
  * 
@@ -197,15 +244,17 @@
 };
 
 enum {
-	Onop,
-	Oinsert,	/* new kvp */
-	Odelete,	/* delete kvp */
-	Oclearb,	/* free block ptr if exists */
-	Owstat,		/* kvp dirent */
+	Onop	= 0,	/* nothing */
+	Oinsert	= 1,	/* new kvp */
+	Odelete	= 2,	/* delete kvp */
+	Oclearb	= 3,	/* free block ptr if exists */
+	Owstat	= 4,	/* kvp dirent */
+
 	/* wstat flags */
 	Owsize	= 1<<4,
 	Owmode	= 1<<5,
 	Owmtime	= 1<<6,
+	Owatime	= 1<<7,
 };
 
 /*
@@ -361,14 +410,26 @@
 	Kvp;
 };
 
+struct Xdir {
+	/* file data */
+	Qid	qid;	/* unique id from server */
+	vlong	mode;	/* permissions */
+	vlong	atime;	/* last read time */
+	vlong	mtime;	/* last write time */
+	uvlong	length;	/* file length */
+	int	uid;	/* owner name */
+	int	gid;	/* group name */
+	int	muid;	/* last modifier name */
+	char	name[Keymax];	/* last element of path */
+};
+
 struct Dent {
 	RWLock;
 	Key;
+	Xdir;
 	Dent	*next;
 	long	ref;
 
-	Qid	qid;
-	vlong	length;
 	char	buf[Maxent];
 };
 
@@ -485,4 +546,3 @@
 	void	**wp;
 	void*	args[];	/* list of saved pointers, [->size] */
 };
-
--- a/dump.c
+++ b/dump.c
@@ -271,6 +271,7 @@
 	Tree t;
 
 	name = "main";
+	memset(&t, 0, sizeof(t));
 	if(na == 1)
 		name = ap[0];
 	if((e = opensnap(&t, name)) != nil){
--- a/fs.c
+++ b/fs.c
@@ -649,7 +649,7 @@
 	int n;
 
 	if((f = getfid(m->fid)) == nil){
-		rerror(m, "no such fid");
+		rerror(m, Efid);
 		return;
 	}
 	if((err = btlookup(&f->mnt->root, f->dent, &kv, kvbuf, sizeof(kvbuf))) != nil){
@@ -672,10 +672,129 @@
 void
 fswstat(Fmsg *m)
 {
-	USED(m);
-	rerror(m, "wstat unimplemented");
+	char *p, *e, strs[65535], rnbuf[Kvmax], opbuf[Kvmax], kvbuf[Kvmax];
+	int nm, sync;
+	vlong up;
+	Fcall r;
+	Dent *de;
+	Msg mb[3];
+	Dir o, d;
+	Fid *f;
+	Kvp kv;
+	Key k;
+
+	nm = 0;
+	sync = 1;
+	if((f = getfid(m->fid)) == nil){
+		rerror(m, Efid);
+		return;
+	}
+	if(f->dent->qid.type != QTDIR && f->dent->qid.type != QTFILE){
+		rerror(m, Efid);
+		goto Out;
+	}
+	if(convM2D(m->stat, m->nstat, &d, strs) <= BIT16SZ){
+		rerror(m, Edir);
+		goto Out;
+	}
+	de = f->dent;
+	k = f->dent->Key;
+
+	/* A nop qid change is allowed. */
+	if(d.qid.path != ~0 || d.qid.vers != ~0){
+		if(d.qid.path != de->qid.path){
+			rerror(m, Ewstatp);
+			goto Out;
+		}
+		if(d.qid.vers != de->qid.vers){
+			rerror(m, Ewstatv);
+			goto Out;
+		}
+		sync = 0;
+	}
+
+	/*
+	 * rename: verify name is valid, same name renames are nops.
+	 * this is inserted into the tree as a pair of delete/create
+	 * messages.
+	 */
+	if(d.name != nil && *d.name != '\0'){
+		if(okname(d.name) == -1){
+			rerror(m, Ename);
+			goto Out;
+		}
+		/* renaming to the same name is a nop. */
+		mb[nm].op = Odelete;
+		mb[nm].Key = f->dent->Key;
+		nm++;
+		if((e = btlookup(&f->mnt->root, f->dent, &kv, kvbuf, sizeof(kvbuf))) != nil){
+			rerror(m, e);
+			goto Out;
+		}
+		if(kv2dir(&kv, &o) == -1){
+			rerror(m, "stat: %r");
+			goto Out;
+		}
+		o.name = d.name;
+		mb[nm].op = Oinsert;
+		up = GBIT64(f->dent->k+1);
+		if(dir2kv(up, &o, &mb[nm], rnbuf, sizeof(rnbuf)) == -1){
+			rerror(m, Efs);
+			goto Out;
+		}
+		sync = 0;
+		k = mb[nm].Key;
+		nm++;
+	}
+
+	p = opbuf;
+	mb[nm].Key = k;
+	mb[nm].op = Owstat;
+	mb[nm].statop = 0;
+	if(d.mode != ~0){
+		mb[nm].statop |= Owmode;
+		PBIT32(p, d.mode);
+		p += 4;
+		sync = 0;
+	}
+	if(d.length != ~0){
+		mb[nm].statop |= Owsize;
+		PBIT64(p, d.length);
+		p += 8;
+		sync = 0;
+	}
+	if(d.mtime != ~0){
+		mb[nm].statop |= Owmtime;
+		PBIT64(p, (vlong)d.mtime*Nsec);
+		p += 8;
+		sync = 0;
+	}
+	mb[nm].v = opbuf;
+	mb[nm].nv = p - opbuf;
+	nm++;
+	if(sync){
+		rerror(m, Eimpl);
+	}else{
+for(int i = 0; i < nm; i++){
+print("upsert %M\n", &mb[i]);
 }
+		if((e = btupsert(&f->mnt->root, mb, nm)) != nil){
+			rerror(m, e);
+			goto Out;
+		}
+		if((e = snapshot(&f->mnt->root, f->mnt->name, 1)) != nil){
+			rerror(m, e);
+			goto Out;
+		}
+		r.type = Rwstat;
+		respond(m, &r);
+	}
 
+Out:
+	putfid(f);
+}
+
+
 void
 fsclunk(Fmsg *m)
 {
@@ -683,7 +802,7 @@
 	Fid *f;
 
 	if((f = getfid(m->fid)) == nil){
-		rerror(m, "no such fid");
+		rerror(m, Efid);
 		return;
 	}
 
@@ -715,7 +834,7 @@
 		return;
 	}
 	if((f = getfid(m->fid)) == nil){
-		rerror(m, "no such fid");
+		rerror(m, Efid);
 		return;
 	}
 	if(m->perm & (DMMOUNT|DMAUTH)){
@@ -806,7 +925,7 @@
 	char *e;
 
 	if((f = getfid(m->fid)) == nil){
-		rerror(m, "no such fid");
+		rerror(m, Efid);
 		return;
 	}