1 #include "logfsos.h"
2 #include "logfs.h"
3 #include "fcall.h"
4 #include "local.h"
5
6 char *
logfsserverwalk(LogfsServer * server,u32int fid,u32int newfid,ushort nwname,char ** wname,ushort * nwqid,Qid * wqid)7 logfsserverwalk(LogfsServer *server, u32int fid, u32int newfid, ushort nwname, char **wname, ushort *nwqid, Qid *wqid)
8 {
9 ushort i;
10 Entry *e;
11 char *errmsg;
12 Fid *f;
13 if(server->trace > 1) {
14 print("logfsserverwalk(%ud, %ud, %ud, \"", fid, newfid, nwname);
15 for(i = 0; i < nwname; i++) {
16 if(i > 0)
17 print("/");
18 print("%s", wname[i]);
19 }
20 print("\")\n");
21 }
22 f = logfsfidmapfindentry(server->fidmap, fid);
23 if(f == nil)
24 return logfsebadfid;
25 if(f->openmode >= 0)
26 return logfsefidopen;
27 errmsg = nil;
28 e = f->entry;
29 if(e->deadandgone)
30 return Eio;
31 for(i = 0; i < nwname; i++) {
32 Entry *se;
33 /*
34 * deal with ..
35 */
36 if(strcmp(wname[i], "..") == 0)
37 se = e->parent;
38 else if(strcmp(wname[i], ".") == 0)
39 se = e;
40 else {
41 /*
42 * is it a directory?
43 */
44 if((e->qid.type & QTDIR) == 0) {
45 errmsg = Enotdir;
46 break;
47 }
48 /*
49 * can we walk the walk, or just talk the protocol?
50 */
51 if(!logfsuserpermcheck(server, e, f, DMEXEC)) {
52 errmsg = Eperm;
53 break;
54 }
55 /*
56 * search current entry for nwname[i]
57 */
58 for(se = e->u.dir.list; se; se = se->next)
59 if(strcmp(se->name, wname[i]) == 0)
60 break;
61 if(se == nil) {
62 errmsg = Enonexist;
63 break;
64 }
65 }
66 wqid[i] = se->qid;
67 e = se;
68 }
69 if(nwname > 0 && i == 0) {
70 /*
71 * fell at the first fence
72 */
73 return errmsg;
74 }
75 *nwqid = i;
76 if(i < nwname)
77 return nil;
78 /*
79 * new fid required?
80 */
81 if(fid != newfid) {
82 Fid *newf;
83 char *errmsg;
84 errmsg = logfsfidmapnewentry(server->fidmap, newfid, &newf);
85 if(errmsg)
86 return errmsg;
87 if(newf == nil)
88 return logfsefidinuse;
89 newf->entry = e;
90 newf->uname = f->uname;
91 e->inuse++;
92 }
93 else {
94 /*
95 * this may now be right
96 * 1. increment reference on new entry first in case e and f->entry are the same
97 * 2. clunk the old one in case this has the effect of removing an old entry
98 * 3. dump the directory read state if the entry has changed
99 */
100 e->inuse++;
101 logfsentryclunk(f->entry);
102 if(e != f->entry)
103 logfsdrsfree(&f->drs);
104 f->entry = e;
105 }
106 return nil;
107 }
108
109