From 37da2899f40661e3e9631e497da8dc59b971cbd0 Mon Sep 17 00:00:00 2001 From: "Charles.Forsyth" Date: Fri, 22 Dec 2006 17:07:39 +0000 Subject: 20060303a --- liblogfs/walk.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 liblogfs/walk.c (limited to 'liblogfs/walk.c') diff --git a/liblogfs/walk.c b/liblogfs/walk.c new file mode 100644 index 00000000..05ae3f9c --- /dev/null +++ b/liblogfs/walk.c @@ -0,0 +1,108 @@ +#include "lib9.h" +#include "logfs.h" +#include "fcall.h" +#include "local.h" + +char * +logfsserverwalk(LogfsServer *server, u32int fid, u32int newfid, ushort nwname, char **wname, ushort *nwqid, Qid *wqid) +{ + ushort i; + Entry *e; + char *errmsg; + Fid *f; + if(server->trace > 1) { + print("logfsserverwalk(%ud, %ud, %ud, \"", fid, newfid, nwname); + for(i = 0; i < nwname; i++) { + if(i > 0) + print("/"); + print("%s", wname[i]); + } + print("\")\n"); + } + f = logfsfidmapfindentry(server->fidmap, fid); + if(f == nil) + return logfsebadfid; + if(f->openmode >= 0) + return logfsefidopen; + errmsg = nil; + e = f->entry; + if(e->deadandgone) + return Eio; + for(i = 0; i < nwname; i++) { + Entry *se; + /* + * deal with .. + */ + if(strcmp(wname[i], "..") == 0) + se = e->parent; + else if(strcmp(wname[i], ".") == 0) + se = e; + else { + /* + * is it a directory? + */ + if((e->qid.type & QTDIR) == 0) { + errmsg = Enotdir; + break; + } + /* + * can we walk the walk, or just talk the protocol? + */ + if(!logfsuserpermcheck(server, e, f, DMEXEC)) { + errmsg = Eperm; + break; + } + /* + * search current entry for nwname[i] + */ + for(se = e->u.dir.list; se; se = se->next) + if(strcmp(se->name, wname[i]) == 0) + break; + if(se == nil) { + errmsg = Enonexist; + break; + } + } + wqid[i] = se->qid; + e = se; + } + if(nwname > 0 && i == 0) { + /* + * fell at the first fence + */ + return errmsg; + } + *nwqid = i; + if(i < nwname) + return nil; + /* + * new fid required? + */ + if(fid != newfid) { + Fid *newf; + char *errmsg; + errmsg = logfsfidmapnewentry(server->fidmap, newfid, &newf); + if(errmsg) + return errmsg; + if(newf == nil) + return logfsefidinuse; + newf->entry = e; + newf->uname = f->uname; + e->inuse++; + } + else { + /* + * this may now be right + * 1. increment reference on new entry first in case e and f->entry are the same + * 2. clunk the old one in case this has the effect of removing an old entry + * 3. dump the directory read state if the entry has changed + */ + e->inuse++; + logfsentryclunk(f->entry); + if(e != f->entry) + logfsdrsfree(&f->drs); + f->entry = e; + } + return nil; +} + -- cgit v1.2.3