1 #include "lib9.h" 2 #include "logfs.h" 3 #include "fcall.h" 4 #include "local.h" 5 6 char * 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