1*28942eadSforsyth #include "logfsos.h"
237da2899SCharles.Forsyth #include "logfs.h"
337da2899SCharles.Forsyth #include "fcall.h"
437da2899SCharles.Forsyth #include "local.h"
537da2899SCharles.Forsyth
637da2899SCharles.Forsyth char *
logfsserverwalk(LogfsServer * server,u32int fid,u32int newfid,ushort nwname,char ** wname,ushort * nwqid,Qid * wqid)737da2899SCharles.Forsyth logfsserverwalk(LogfsServer *server, u32int fid, u32int newfid, ushort nwname, char **wname, ushort *nwqid, Qid *wqid)
837da2899SCharles.Forsyth {
937da2899SCharles.Forsyth ushort i;
1037da2899SCharles.Forsyth Entry *e;
1137da2899SCharles.Forsyth char *errmsg;
1237da2899SCharles.Forsyth Fid *f;
1337da2899SCharles.Forsyth if(server->trace > 1) {
1437da2899SCharles.Forsyth print("logfsserverwalk(%ud, %ud, %ud, \"", fid, newfid, nwname);
1537da2899SCharles.Forsyth for(i = 0; i < nwname; i++) {
1637da2899SCharles.Forsyth if(i > 0)
1737da2899SCharles.Forsyth print("/");
1837da2899SCharles.Forsyth print("%s", wname[i]);
1937da2899SCharles.Forsyth }
2037da2899SCharles.Forsyth print("\")\n");
2137da2899SCharles.Forsyth }
2237da2899SCharles.Forsyth f = logfsfidmapfindentry(server->fidmap, fid);
2337da2899SCharles.Forsyth if(f == nil)
2437da2899SCharles.Forsyth return logfsebadfid;
2537da2899SCharles.Forsyth if(f->openmode >= 0)
2637da2899SCharles.Forsyth return logfsefidopen;
2737da2899SCharles.Forsyth errmsg = nil;
2837da2899SCharles.Forsyth e = f->entry;
2937da2899SCharles.Forsyth if(e->deadandgone)
3037da2899SCharles.Forsyth return Eio;
3137da2899SCharles.Forsyth for(i = 0; i < nwname; i++) {
3237da2899SCharles.Forsyth Entry *se;
3337da2899SCharles.Forsyth /*
3437da2899SCharles.Forsyth * deal with ..
3537da2899SCharles.Forsyth */
3637da2899SCharles.Forsyth if(strcmp(wname[i], "..") == 0)
3737da2899SCharles.Forsyth se = e->parent;
3837da2899SCharles.Forsyth else if(strcmp(wname[i], ".") == 0)
3937da2899SCharles.Forsyth se = e;
4037da2899SCharles.Forsyth else {
4137da2899SCharles.Forsyth /*
4237da2899SCharles.Forsyth * is it a directory?
4337da2899SCharles.Forsyth */
4437da2899SCharles.Forsyth if((e->qid.type & QTDIR) == 0) {
4537da2899SCharles.Forsyth errmsg = Enotdir;
4637da2899SCharles.Forsyth break;
4737da2899SCharles.Forsyth }
4837da2899SCharles.Forsyth /*
4937da2899SCharles.Forsyth * can we walk the walk, or just talk the protocol?
5037da2899SCharles.Forsyth */
5137da2899SCharles.Forsyth if(!logfsuserpermcheck(server, e, f, DMEXEC)) {
5237da2899SCharles.Forsyth errmsg = Eperm;
5337da2899SCharles.Forsyth break;
5437da2899SCharles.Forsyth }
5537da2899SCharles.Forsyth /*
5637da2899SCharles.Forsyth * search current entry for nwname[i]
5737da2899SCharles.Forsyth */
5837da2899SCharles.Forsyth for(se = e->u.dir.list; se; se = se->next)
5937da2899SCharles.Forsyth if(strcmp(se->name, wname[i]) == 0)
6037da2899SCharles.Forsyth break;
6137da2899SCharles.Forsyth if(se == nil) {
6237da2899SCharles.Forsyth errmsg = Enonexist;
6337da2899SCharles.Forsyth break;
6437da2899SCharles.Forsyth }
6537da2899SCharles.Forsyth }
6637da2899SCharles.Forsyth wqid[i] = se->qid;
6737da2899SCharles.Forsyth e = se;
6837da2899SCharles.Forsyth }
6937da2899SCharles.Forsyth if(nwname > 0 && i == 0) {
7037da2899SCharles.Forsyth /*
7137da2899SCharles.Forsyth * fell at the first fence
7237da2899SCharles.Forsyth */
7337da2899SCharles.Forsyth return errmsg;
7437da2899SCharles.Forsyth }
7537da2899SCharles.Forsyth *nwqid = i;
7637da2899SCharles.Forsyth if(i < nwname)
7737da2899SCharles.Forsyth return nil;
7837da2899SCharles.Forsyth /*
7937da2899SCharles.Forsyth * new fid required?
8037da2899SCharles.Forsyth */
8137da2899SCharles.Forsyth if(fid != newfid) {
8237da2899SCharles.Forsyth Fid *newf;
8337da2899SCharles.Forsyth char *errmsg;
8437da2899SCharles.Forsyth errmsg = logfsfidmapnewentry(server->fidmap, newfid, &newf);
8537da2899SCharles.Forsyth if(errmsg)
8637da2899SCharles.Forsyth return errmsg;
8737da2899SCharles.Forsyth if(newf == nil)
8837da2899SCharles.Forsyth return logfsefidinuse;
8937da2899SCharles.Forsyth newf->entry = e;
9037da2899SCharles.Forsyth newf->uname = f->uname;
9137da2899SCharles.Forsyth e->inuse++;
9237da2899SCharles.Forsyth }
9337da2899SCharles.Forsyth else {
9437da2899SCharles.Forsyth /*
9537da2899SCharles.Forsyth * this may now be right
9637da2899SCharles.Forsyth * 1. increment reference on new entry first in case e and f->entry are the same
9737da2899SCharles.Forsyth * 2. clunk the old one in case this has the effect of removing an old entry
9837da2899SCharles.Forsyth * 3. dump the directory read state if the entry has changed
9937da2899SCharles.Forsyth */
10037da2899SCharles.Forsyth e->inuse++;
10137da2899SCharles.Forsyth logfsentryclunk(f->entry);
10237da2899SCharles.Forsyth if(e != f->entry)
10337da2899SCharles.Forsyth logfsdrsfree(&f->drs);
10437da2899SCharles.Forsyth f->entry = e;
10537da2899SCharles.Forsyth }
10637da2899SCharles.Forsyth return nil;
10737da2899SCharles.Forsyth }
10837da2899SCharles.Forsyth
109