From 5defe39b3175e78780c3e9ee830840861cd9619e Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Mon, 3 Mar 2003 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2003-03-03 --- port/chan.c | 50 +++++++++++++++++++++++++++++++++++--------------- port/devroot.c | 16 ++++++++++++---- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/port/chan.c b/port/chan.c index d74a4d9b98bf9d9b378ced97ff06547f85570323..47a508ea18190dae9bd684ff010b373fcf765b8b 100644 --- a/port/chan.c +++ b/port/chan.c @@ -81,6 +81,7 @@ struct Elemlist int nelems; char **elems; int *off; + int mustbedir; }; #define SEP(c) ((c) == 0 || (c) == '/') @@ -974,6 +975,10 @@ growparse(Elemlist *e) * The name is known to be valid. * Copy the name so slashes can be overwritten. * An empty string will set nelem=0. + * A path ending in / or /. or /.//./ etc. will have + * e.mustbedir = 1, so that we correctly + * reject, e.g., "/adm/users/." when /adm/users is a file + * rather than a directory. */ static void parsename(char *name, Elemlist *e) @@ -985,17 +990,19 @@ parsename(char *name, Elemlist *e) e->nelems = 0; e->elems = nil; e->off = smalloc(sizeof(int)); - e->off[0] = 0; + e->off[0] = skipslash(name) - name; for(;;){ name = skipslash(name); - if(*name=='\0') + if(*name=='\0'){ + e->mustbedir = 1; break; + } growparse(e); - e->elems[e->nelems++] = name; slash = utfrune(name, '/'); if(slash == nil){ e->off[e->nelems] = name+strlen(name) - e->name; + e->mustbedir = 0; break; } e->off[e->nelems] = slash - e->name; @@ -1059,7 +1066,6 @@ namec(char *aname, int amode, int omode, ulong perm) case '/': c = up->slash; incref(c); - name = skipslash(name); break; case '#': @@ -1099,7 +1105,6 @@ namec(char *aname, int amode, int omode, ulong perm) default: c = up->dot; incref(c); - name = skipslash(name); break; } prefix = name - aname; @@ -1123,11 +1128,19 @@ namec(char *aname, int amode, int omode, ulong perm) parsename(name, &e); /* - * On create, don't try to walk the last path element just yet. + * On create, .... */ if(amode == Acreate){ + /* perm must have DMDIR if last element is / or /. */ + if(e.mustbedir && !(perm&DMDIR)){ + npath = e.nelems; + strcpy(tmperrbuf, "create without DMDIR"); + goto NameError; + } + + /* don't try to walk the last path element just yet. */ if(e.nelems == 0) - error(Eisdir); + error(Eexist); e.nelems--; } @@ -1136,8 +1149,9 @@ namec(char *aname, int amode, int omode, ulong perm) print("namec %s walk error npath=%d\n", aname, npath); nexterror(); } - len = prefix+e.off[npath]; strcpy(tmperrbuf, up->errstr); + NameError: + len = prefix+e.off[npath]; if(len < ERRMAX/3 || (name=memrchr(aname, '/', len))==nil || name==aname) snprint(up->genbuf, sizeof up->genbuf, "%.*s", len, aname); else @@ -1146,6 +1160,17 @@ namec(char *aname, int amode, int omode, ulong perm) nexterror(); } + if(e.mustbedir && !(c->qid.type&QTDIR)){ + npath = e.nelems; + strcpy(tmperrbuf, "not a directory"); + goto NameError; + } + + if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR)){ + npath = e.nelems; + error("cannot exec directory"); + } + switch(amode){ case Aaccess: if(!nomount) @@ -1356,18 +1381,13 @@ if(c->umh != nil){ } /* - * name is valid. skip leading / and ./ and trailing . + * name is valid. skip leading / and ./ as much as possible */ char* skipslash(char *name) { - Again: - while(*name == '/') - name++; - if(*name=='.' && (name[1]=='\0' || name[1]=='/')){ + while(name[0]=='/' || (name[0]=='.' && (name[1]==0 || name[1]=='/'))) name++; - goto Again; - } return name; } diff --git a/port/devroot.c b/port/devroot.c index c380b6e6983a6059ade0ffa6c93c636badd8685b..20799edd62a9720db8ea1f33ef2dd80fe4135a60 100644 --- a/port/devroot.c +++ b/port/devroot.c @@ -121,6 +121,10 @@ rootgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp) switch((int)c->qid.path){ case Qdir: + if(s == DEVDOTDOT){ + devdir(c, (Qid){Qdir, 0, QTDIR}, "#/", 0, eve, 0555, dp); + return 1; + } return devgen(c, name, rootlist.dir, rootlist.ndir, s, dp); case Qboot: if(s == DEVDOTDOT){ @@ -129,6 +133,8 @@ rootgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp) } return devgen(c, name, bootlist.dir, bootlist.ndir, s, dp); default: + if(s != 0) + return -1; if((int)c->qid.path < Qboot){ t = c->qid.path-1; l = &rootlist; @@ -138,8 +144,6 @@ rootgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp) } if(t >= l->ndir) return -1; - if(s != 0) - return -1; d = &l->dir[t]; devdir(c, d->qid, d->name, d->length, eve, d->perm, dp); return 1; @@ -196,8 +200,12 @@ rootread(Chan *c, void *buf, long n, vlong off) l = &bootlist; } - d = &l->dir[t-1]; - data = l->data[t-1]; + t--; + if(t >= l->ndir) + error(Egreg); + + d = &l->dir[t]; + data = l->data[t]; if(offset >= d->length) return 0; if(offset+n > d->length)