ref: db38a568c302f9d1820649849eeeaf4087b3c976
parent: 56cc98ba722d066c454b107a786b51cb740bd2b2
author: Ori Bernstein <[email protected]>
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;
}