ref: 1583a55d91725ddf4166b0c0fe7623a88a5f9cd3
parent: cdb9a6e131c162f8c6f29b4fb131bb78b9ea7928
author: cinap_lenrek <[email protected]>
date: Tue Apr 4 20:25:04 EDT 2017
kern: merge with chan.c, dev.c, pgrp.c from 9front, fix waserror() botch in devwalk()
--- a/kern/chan.c
+++ b/kern/chan.c
@@ -4,69 +4,15 @@
#include "fns.h"
#include "error.h"
-int chandebug=0; /* toggled by sysr1 */
-QLock chanprint; /* probably asking for trouble (deadlocks) -rsc */
-
-int domount(Chan**, Mhead**);
-
-void
-dumpmount(void) /* DEBUGGING */
-{
- Pgrp *pg;
- Mount *t;
- Mhead **h, **he, *f;
-
- if(up == nil){
- print("no process for dumpmount\n");
- return;
- }
- pg = up->pgrp;
- if(pg == nil){
- print("no pgrp for dumpmount\n");
- return;
- }
- rlock(&pg->ns);
- if(waserror()) {
- runlock(&pg->ns);
- nexterror();
- }
-
- he = &pg->mnthash[MNTHASH];
- for(h = pg->mnthash; h < he; h++) {
- for(f = *h; f; f = f->hash) {
- print("head: %p: %s 0x%llux.%lud %C %lud -> \n", f,
- f->from->name->s, f->from->qid.path,
- f->from->qid.vers, devtab[f->from->type]->dc,
- f->from->dev);
- for(t = f->mount; t; t = t->next)
- print("\t%p: %s (umh %p) (path %.8llux dev %C %lud)\n", t, t->to->name->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev);
- }
- }
- poperror();
- runlock(&pg->ns);
-}
-
-
-char*
-chanpath(Chan *c)
-{
- if(c == nil)
- return "<nil chan>";
- if(c->name == nil)
- return "<nil name>";
- if(c->name->s == nil)
- return "<nil name.s>";
- return c->name->s;
-}
-
enum
{
- CNAMESLOP = 20
+ PATHSLOP = 20,
+ PATHMSLOP = 20,
};
-struct
+static struct Chanalloc
{
- Lock lk;
+ Lock lk;
int fid;
Chan *free;
Chan *list;
@@ -76,16 +22,30 @@
struct Elemlist
{
+ char *aname; /* original name */
char *name; /* copy of name, so '/' can be overwritten */
int nelems;
char **elems;
int *off;
int mustbedir;
+ int nerror;
+ int prefix;
};
#define SEP(c) ((c) == 0 || (c) == '/')
-void cleancname(Cname*);
+char*
+chanpath(Chan *c)
+{
+ if(c == nil)
+ return "<nil chan>";
+ if(c->path == nil)
+ return "<nil path>";
+ if(c->path->s == nil)
+ return "<nil path.s>";
+ return c->path->s;
+}
+
int
isdotdot(char *p)
{
@@ -96,7 +56,6 @@
incref(Ref *r)
{
int x;
-
lock(&r->lk);
x = ++r->ref;
unlock(&r->lk);
@@ -107,13 +66,11 @@
decref(Ref *r)
{
int x;
-
lock(&r->lk);
x = --r->ref;
unlock(&r->lk);
if(x < 0)
panic("decref, pc=0x%p", getcallerpc(&r));
-
return x;
}
@@ -129,20 +86,19 @@
int nt;
nt = strlen(t);
- if(nt+1 <= ns){
- memmove(s, t, nt+1);
+ if(nt < ns){
+ memmove(s, t, nt);
+ s[nt] = '\0';
return;
}
- /* too long */
- if(ns < 4){
- /* but very short! */
- strncpy(s, t, ns);
- return;
- }
- /* truncate with ... at character boundary (very rare case) */
- memmove(s, t, ns-4);
+ /* too long, truncate */
+ nt = ns-1;
+ memmove(s, t, nt);
+ s[nt] = '\0';
+ /* append ... if there is space */
ns -= 4;
- s[ns] = '\0';
+ if(ns < 0)
+ return;
/* look for first byte of UTF-8 sequence by skipping continuation bytes */
while(ns>0 && (s[--ns]&0xC0)==0x80)
;
@@ -168,17 +124,18 @@
int n;
char *t, *prev;
- n = strlen(s)+1;
+ n = strlen(s);
/* if it's a user, we can wait for memory; if not, something's very wrong */
- if(up){
- t = smalloc(n);
- setmalloctag(t, getcallerpc(&p));
- }else{
- t = malloc(n);
+ if(up != nil)
+ t = smalloc(n+1);
+ else{
+ t = malloc(n+1);
if(t == nil)
panic("kstrdup: no memory");
}
+ setmalloctag(t, getcallerpc(&p));
memmove(t, s, n);
+ t[n] = '\0';
prev = *p;
*p = t;
free(prev);
@@ -221,18 +178,19 @@
lock(&chanalloc.lk);
c = chanalloc.free;
- if(c != 0)
+ if(c != nil){
chanalloc.free = c->next;
- unlock(&chanalloc.lk);
-
- if(c == nil) {
+ c->next = nil;
+ } else {
+ unlock(&chanalloc.lk);
c = smalloc(sizeof(Chan));
lock(&chanalloc.lk);
- c->fid = ++chanalloc.fid;
c->link = chanalloc.list;
chanalloc.list = c;
- unlock(&chanalloc.lk);
}
+ if(c->fid == 0)
+ c->fid = ++chanalloc.fid;
+ unlock(&chanalloc.lk);
/* if you get an error before associating with a dev,
close calls rootclose, a nop */
@@ -241,82 +199,181 @@
c->ref.ref = 1;
c->dev = 0;
c->offset = 0;
+ c->devoffset = 0;
c->iounit = 0;
- c->umh = 0;
+ c->umh = nil;
+ c->umc = nil;
c->uri = 0;
c->dri = 0;
- c->aux = 0;
- c->mchan = 0;
- c->mux = 0;
+ c->dirrock = nil;
+ c->nrock = 0;
+ c->mrock = 0;
+ c->ismtpt = 0;
+ c->mux = nil;
+ c->aux = nil;
+ c->mchan = nil;
memset(&c->mqid, 0, sizeof(c->mqid));
- c->name = 0;
+ c->path = nil;
+
return c;
}
-static Ref ncname;
-
-Cname*
-newcname(char *s)
+Path*
+newpath(char *s)
{
- Cname *n;
int i;
+ Path *p;
- n = smalloc(sizeof(Cname));
+ p = smalloc(sizeof(Path));
i = strlen(s);
- n->len = i;
- n->alen = i+CNAMESLOP;
- n->s = smalloc(n->alen);
- memmove(n->s, s, i+1);
- n->ref.ref = 1;
- incref(&ncname);
- return n;
+ p->len = i;
+ p->alen = i+PATHSLOP;
+ p->s = smalloc(p->alen);
+ memmove(p->s, s, i+1);
+ p->ref.ref = 1;
+
+ /*
+ * Cannot use newpath for arbitrary names because the mtpt
+ * array will not be populated correctly. The names #/ and / are
+ * allowed, but other names with / in them draw warnings.
+ */
+ if(strchr(s, '/') != nil && strcmp(s, "#/") != 0 && strcmp(s, "/") != 0)
+ print("newpath: %s from %#p\n", s, getcallerpc(&s));
+
+ p->mlen = 1;
+ p->malen = PATHMSLOP;
+ p->mtpt = smalloc(p->malen*sizeof p->mtpt[0]);
+ return p;
}
+static Path*
+copypath(Path *p)
+{
+ int i;
+ Path *pp;
+
+ pp = smalloc(sizeof(Path));
+ pp->ref.ref = 1;
+
+ pp->len = p->len;
+ pp->alen = p->alen;
+ pp->s = smalloc(p->alen);
+ memmove(pp->s, p->s, p->len+1);
+
+ pp->mlen = p->mlen;
+ pp->malen = p->malen;
+ pp->mtpt = smalloc(p->malen*sizeof pp->mtpt[0]);
+ for(i=0; i<pp->mlen; i++){
+ pp->mtpt[i] = p->mtpt[i];
+ if(pp->mtpt[i] != nil)
+ incref(&pp->mtpt[i]->ref);
+ }
+
+ return pp;
+}
+
void
-cnameclose(Cname *n)
+pathclose(Path *p)
{
- if(n == nil)
+ int i;
+
+ if(p == nil || decref(&p->ref))
return;
- if(decref(&n->ref))
- return;
- decref(&ncname);
- free(n->s);
- free(n);
+ for(i=0; i<p->mlen; i++)
+ if(p->mtpt[i] != nil)
+ cclose(p->mtpt[i]);
+ free(p->mtpt);
+ free(p->s);
+ free(p);
}
-Cname*
-addelem(Cname *n, char *s)
+/*
+ * In place, rewrite name to compress multiple /, eliminate ., and process ..
+ * (Really only called to remove a trailing .. that has been added.
+ * Otherwise would need to update n->mtpt as well.)
+ */
+static void
+fixdotdotname(Path *p)
{
- int i, a;
- char *t;
- Cname *new;
+ char *r;
- if(s[0]=='.' && s[1]=='\0')
- return n;
+ if(p->s[0] == '#'){
+ r = strchr(p->s, '/');
+ if(r == nil)
+ return;
+ cleanname(r);
- if(n->ref.ref > 1){
+ /*
+ * The correct name is #i rather than #i/,
+ * but the correct name of #/ is #/.
+ */
+ if(strcmp(r, "/")==0 && p->s[1] != '/')
+ *r = '\0';
+ }else
+ cleanname(p->s);
+ p->len = strlen(p->s);
+}
+
+static Path*
+uniquepath(Path *p)
+{
+ Path *new;
+
+ if(p->ref.ref > 1){
/* copy on write */
- new = newcname(n->s);
- cnameclose(n);
- n = new;
+ new = copypath(p);
+ pathclose(p);
+ p = new;
}
+ return p;
+}
+static Path*
+addelem(Path *p, char *s, Chan *from)
+{
+ char *t;
+ int a, i;
+ Chan *c, **tt;
+
+ if(s[0]=='.' && s[1]=='\0')
+ return p;
+
+ p = uniquepath(p);
+
i = strlen(s);
- if(n->len+1+i+1 > n->alen){
- a = n->len+1+i+1 + CNAMESLOP;
+ a = p->len+1+i+1;
+ if(a > p->alen){
+ a += PATHSLOP;
t = smalloc(a);
- memmove(t, n->s, n->len+1);
- free(n->s);
- n->s = t;
- n->alen = a;
+ memmove(t, p->s, p->len+1);
+ free(p->s);
+ p->s = t;
+ p->alen = a;
}
- if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/') /* don't insert extra slash if one is present */
- n->s[n->len++] = '/';
- memmove(n->s+n->len, s, i+1);
- n->len += i;
- if(isdotdot(s))
- cleancname(n);
- return n;
+ /* don't insert extra slash if one is present */
+ if(p->len>0 && p->s[p->len-1]!='/' && s[0]!='/')
+ p->s[p->len++] = '/';
+ memmove(p->s+p->len, s, i+1);
+ p->len += i;
+ if(isdotdot(s)){
+ fixdotdotname(p);
+ if(p->mlen > 1 && (c = p->mtpt[--p->mlen]) != nil){
+ p->mtpt[p->mlen] = nil;
+ cclose(c);
+ }
+ }else{
+ if(p->mlen >= p->malen){
+ p->malen = p->mlen+1+PATHMSLOP;
+ tt = smalloc(p->malen*sizeof tt[0]);
+ memmove(tt, p->mtpt, p->mlen*sizeof tt[0]);
+ free(p->mtpt);
+ p->mtpt = tt;
+ }
+ p->mtpt[p->mlen++] = from;
+ if(from != nil)
+ incref(&from->ref);
+ }
+ return p;
}
void
@@ -324,6 +381,12 @@
{
c->flag = CFREE;
+ if(c->dirrock != nil){
+ free(c->dirrock);
+ c->dirrock = nil;
+ c->nrock = 0;
+ c->mrock = 0;
+ }
if(c->umh != nil){
putmhead(c->umh);
c->umh = nil;
@@ -341,7 +404,8 @@
c->mchan = nil;
}
- cnameclose(c->name);
+ pathclose(c->path);
+ c->path = nil;
lock(&chanalloc.lk);
c->next = chanalloc.free;
@@ -352,8 +416,8 @@
void
cclose(Chan *c)
{
- if(c->flag&CFREE)
- panic("cclose %p", getcallerpc(&c));
+ if(c == nil || c->ref.ref < 1 || c->flag&CFREE)
+ panic("cclose %#p", getcallerpc(&c));
if(decref(&c->ref))
return;
@@ -373,7 +437,7 @@
{
Chan *nc;
- if(c->ref.ref != 1) {
+ if(c->ref.ref != 1){
nc = cclone(c);
cclose(c);
c = nc;
@@ -389,11 +453,11 @@
}
int
-eqchan(Chan *a, Chan *b, int pathonly)
+eqchan(Chan *a, Chan *b, int skipvers)
{
if(a->qid.path != b->qid.path)
return 0;
- if(!pathonly && a->qid.vers!=b->qid.vers)
+ if(!skipvers && a->qid.vers!=b->qid.vers)
return 0;
if(a->type != b->type)
return 0;
@@ -403,11 +467,11 @@
}
int
-eqchantdqid(Chan *a, int type, int dev, Qid qid, int pathonly)
+eqchantdqid(Chan *a, int type, int dev, Qid qid, int skipvers)
{
if(a->qid.path != qid.path)
return 0;
- if(!pathonly && a->qid.vers!=qid.vers)
+ if(!skipvers && a->qid.vers!=qid.vers)
return 0;
if(a->type != type)
return 0;
@@ -425,34 +489,56 @@
mh->ref.ref = 1;
mh->from = from;
incref(&from->ref);
+ return mh;
+}
/*
- n = from->name->len;
- if(n >= sizeof(mh->fromname))
- n = sizeof(mh->fromname)-1;
- memmove(mh->fromname, from->name->s, n);
- mh->fromname[n] = 0;
-*/
- return mh;
+ * This is necessary because there are many
+ * pointers to the top of a given mount list:
+ *
+ * - the mhead in the namespace hash table
+ * - the mhead in chans returned from findmount:
+ * used in namec and then by unionread.
+ * - the mhead in chans returned from createdir:
+ * used in the open/create race protect, which is gone.
+ *
+ * The RWlock in the Mhead protects the mount list it contains.
+ * The mount list is deleted in cunmount() and closepgrp().
+ * The RWlock ensures that nothing is using the mount list at that time.
+ *
+ * It is okay to replace c->mh with whatever you want as
+ * long as you are sure you have a unique reference to it.
+ *
+ * This comment might belong somewhere else.
+ */
+void
+putmhead(Mhead *m)
+{
+ if(m != nil && decref(&m->ref) == 0){
+ assert(m->mount == nil);
+ cclose(m->from);
+ free(m);
+ }
}
int
cmount(Chan **newp, Chan *old, int flag, char *spec)
{
- Pgrp *pg;
int order, flg;
+ Chan *new;
Mhead *m, **l, *mh;
Mount *nm, *f, *um, **h;
- Chan *new;
+ Pgrp *pg;
if(QTDIR & (old->qid.type^(*newp)->qid.type))
error(Emount);
-if(old->umh)print("cmount old extra umh\n");
+ if(old->umh != nil)
+ print("cmount: unexpected umh, caller %#p\n", getcallerpc(&newp));
order = flag&MORDER;
- if((old->qid.type&QTDIR)==0 && order != MREPL)
+ if((old->qid.type&QTDIR) == 0 && order != MREPL)
error(Emount);
new = *newp;
@@ -459,23 +545,25 @@
mh = new->umh;
/*
- * Not allowed to bind when the old directory
- * is itself a union. (Maybe it should be allowed, but I don't see
- * what the semantics would be.)
+ * Not allowed to bind when the old directory is itself a union.
+ * (Maybe it should be allowed, but I don't see what the semantics
+ * would be.)
*
* We need to check mh->mount->next to tell unions apart from
* simple mount points, so that things like
* mount -c fd /root
* bind -c /root /
- * work. The check of mount->mflag catches things like
+ * work.
+ *
+ * The check of mount->mflag allows things like
* mount fd /root
* bind -c /root /
*
* This is far more complicated than it should be, but I don't
- * see an easier way at the moment. -rsc
+ * see an easier way at the moment.
*/
- if((flag&MCREATE) && mh && mh->mount
- && (mh->mount->next || !(mh->mount->mflag&MCREATE)))
+ if((flag&MCREATE) != 0 && mh != nil && mh->mount != nil
+ && (mh->mount->next != nil || (mh->mount->mflag&MCREATE) == 0))
error(Emount);
pg = up->pgrp;
@@ -482,13 +570,13 @@
wlock(&pg->ns);
l = &MOUNTH(pg, old->qid);
- for(m = *l; m; m = m->hash) {
+ for(m = *l; m != nil; m = m->hash){
if(eqchan(m->from, old, 1))
break;
l = &m->hash;
}
- if(m == nil) {
+ if(m == nil){
/*
* nothing mounted here yet. create a mount
* head and add to the hash table.
@@ -501,7 +589,7 @@
* node to the mount chain.
*/
if(order != MREPL)
- m->mount = newmount(m, old, 0, 0);
+ m->mount = newmount(old, 0, nil);
}
wlock(&m->lock);
if(waserror()){
@@ -510,8 +598,8 @@
}
wunlock(&pg->ns);
- nm = newmount(m, new, flag, spec);
- if(mh != nil && mh->mount != nil) {
+ nm = newmount(new, flag, spec);
+ if(mh != nil && mh->mount != nil){
/*
* copy a union when binding it onto a directory
*/
@@ -520,33 +608,31 @@
flg = MAFTER;
h = &nm->next;
um = mh->mount;
- for(um = um->next; um; um = um->next) {
- f = newmount(m, um->to, flg, um->spec);
+ for(um = um->next; um != nil; um = um->next){
+ f = newmount(um->to, flg, um->spec);
*h = f;
h = &f->next;
}
}
- if(m->mount && order == MREPL) {
+ if(m->mount != nil && order == MREPL){
mountfree(m->mount);
- m->mount = 0;
+ m->mount = nil;
}
if(flag & MCREATE)
nm->mflag |= MCREATE;
- if(m->mount && order == MAFTER) {
- for(f = m->mount; f->next; f = f->next)
+ if(m->mount != nil && order == MAFTER){
+ for(f = m->mount; f->next != nil; f = f->next)
;
f->next = nm;
- }
- else {
- for(f = nm; f->next; f = f->next)
+ }else{
+ for(f = nm; f->next != nil; f = f->next)
;
f->next = m->mount;
m->mount = nm;
}
-
wunlock(&m->lock);
poperror();
return nm->mountid;
@@ -559,7 +645,7 @@
Mhead *m, **l;
Mount *f, **p;
- if(mnt->umh) /* should not happen */
+ if(mnt->umh != nil) /* should not happen */
print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh);
/*
@@ -575,47 +661,44 @@
wlock(&pg->ns);
l = &MOUNTH(pg, mnt->qid);
- for(m = *l; m; m = m->hash) {
+ for(m = *l; m != nil; m = m->hash){
if(eqchan(m->from, mnt, 1))
break;
l = &m->hash;
}
- if(m == 0) {
+ if(m == nil){
wunlock(&pg->ns);
error(Eunmount);
}
wlock(&m->lock);
- if(mounted == 0) {
+ f = m->mount;
+ if(mounted == nil){
*l = m->hash;
- wunlock(&pg->ns);
- mountfree(m->mount);
m->mount = nil;
- cclose(m->from);
wunlock(&m->lock);
+ wunlock(&pg->ns);
+ mountfree(f);
putmhead(m);
return;
}
-
- p = &m->mount;
- for(f = *p; f; f = f->next) {
- /* BUG: Needs to be 2 pass */
+ for(p = &m->mount; f != nil; f = f->next){
if(eqchan(f->to, mounted, 1) ||
- (f->to->mchan && eqchan(f->to->mchan, mounted, 1))) {
+ (f->to->mchan != nil && eqchan(f->to->mchan, mounted, 1))){
*p = f->next;
- f->next = 0;
- mountfree(f);
- if(m->mount == nil) {
+ f->next = nil;
+ if(m->mount == nil){
*l = m->hash;
- cclose(m->from);
wunlock(&m->lock);
wunlock(&pg->ns);
+ mountfree(f);
putmhead(m);
return;
}
wunlock(&m->lock);
wunlock(&pg->ns);
+ mountfree(f);
return;
}
p = &f->next;
@@ -631,105 +714,119 @@
Chan *nc;
Walkqid *wq;
+ if(c == nil || c->ref.ref < 1 || c->flag&CFREE)
+ panic("cclone: %#p", getcallerpc(&c));
wq = devtab[c->type]->walk(c, nil, nil, 0);
if(wq == nil)
error("clone failed");
nc = wq->clone;
free(wq);
- nc->name = c->name;
- if(c->name)
- incref(&c->name->ref);
+ if((nc->path = c->path) != nil)
+ incref(&c->path->ref);
return nc;
}
+/* also used by sysfile.c:/^mountfix */
int
findmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid)
{
+ Chan *to;
Pgrp *pg;
Mhead *m;
pg = up->pgrp;
rlock(&pg->ns);
- for(m = MOUNTH(pg, qid); m; m = m->hash){
- rlock(&m->lock);
-if(m->from == nil){
- print("m %p m->from 0\n", m);
- runlock(&m->lock);
- continue;
-}
- if(eqchantdqid(m->from, type, dev, qid, 1)) {
+ for(m = MOUNTH(pg, qid); m != nil; m = m->hash){
+ if(eqchantdqid(m->from, type, dev, qid, 1)){
+ rlock(&m->lock);
runlock(&pg->ns);
- if(mp != nil){
+ if(mp != nil)
incref(&m->ref);
- if(*mp != nil)
- putmhead(*mp);
+ to = m->mount->to;
+ incref(&to->ref);
+ runlock(&m->lock);
+ if(mp != nil){
+ putmhead(*mp);
*mp = m;
}
if(*cp != nil)
cclose(*cp);
- incref(&m->mount->to->ref);
- *cp = m->mount->to;
- runlock(&m->lock);
+ *cp = to;
return 1;
}
- runlock(&m->lock);
}
-
runlock(&pg->ns);
return 0;
}
-int
-domount(Chan **cp, Mhead **mp)
+/*
+ * Calls findmount but also updates path.
+ */
+static int
+domount(Chan **cp, Mhead **mp, Path **path)
{
- return findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid);
+ Chan **lc, *from;
+ Path *p;
+
+ if(findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid) == 0)
+ return 0;
+
+ if(path != nil){
+ p = *path;
+ p = uniquepath(p);
+ if(p->mlen <= 0)
+ print("domount: path %s has mlen==%d\n", p->s, p->mlen);
+ else{
+ from = (*mp)->from;
+ incref(&from->ref);
+ lc = &p->mtpt[p->mlen-1];
+ if(*lc != nil)
+ cclose(*lc);
+ *lc = from;
+ }
+ *path = p;
+ }
+ return 1;
}
-Chan*
-undomount(Chan *c, Cname *name)
+/*
+ * If c is the right-hand-side of a mount point, returns the left hand side.
+ * Changes name to reflect the fact that we've uncrossed the mountpoint,
+ * so name had better be ours to change!
+ */
+static Chan*
+undomount(Chan *c, Path *path)
{
Chan *nc;
- Pgrp *pg;
- Mount *t;
- Mhead **h, **he, *f;
- pg = up->pgrp;
- rlock(&pg->ns);
- if(waserror()) {
- runlock(&pg->ns);
- nexterror();
- }
+ if(path->ref.ref != 1 || path->mlen == 0)
+ print("undomount: path %s ref %ld mlen %d caller %#p\n",
+ path->s, path->ref, path->mlen, getcallerpc(&c));
- he = &pg->mnthash[MNTHASH];
- for(h = pg->mnthash; h < he; h++) {
- for(f = *h; f; f = f->hash) {
- if(strcmp(f->from->name->s, name->s) != 0)
- continue;
- for(t = f->mount; t; t = t->next) {
- if(eqchan(c, t->to, 1)) {
- /*
- * We want to come out on the left hand side of the mount
- * point using the element of the union that we entered on.
- * To do this, find the element that has a from name of
- * c->name->s.
- */
- if(strcmp(t->head->from->name->s, name->s) != 0)
- continue;
- nc = t->head->from;
- incref(&nc->ref);
- cclose(c);
- c = nc;
- break;
- }
- }
- }
+ if(path->mlen > 0 && (nc = path->mtpt[path->mlen-1]) != nil){
+ cclose(c);
+ path->mtpt[path->mlen-1] = nil;
+ c = nc;
}
- poperror();
- runlock(&pg->ns);
return c;
}
/*
+ * Call dev walk but catch errors.
+ */
+static Walkqid*
+ewalk(Chan *c, Chan *nc, char **name, int nname)
+{
+ Walkqid *wq;
+
+ if(waserror())
+ return nil;
+ wq = devtab[c->type]->walk(c, nc, name, nname);
+ poperror();
+ return wq;
+}
+
+/*
* Either walks all the way or not at all. No partial results in *cp.
* *nerror is the number of names to display in an error message.
*/
@@ -737,17 +834,17 @@
int
walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
{
- int dev, dotdot, i, n, nhave, ntry, type;
- Chan *c, *nc;
- Cname *cname;
- Mount *f;
+ int dev, didmount, dotdot, i, n, nhave, ntry, type;
+ Chan *c, *nc, *mtpt;
+ Path *path;
Mhead *mh, *nmh;
+ Mount *f;
Walkqid *wq;
c = *cp;
incref(&c->ref);
- cname = c->name;
- incref(&cname->ref);
+ path = c->path;
+ incref(&path->ref);
mh = nil;
/*
@@ -757,20 +854,21 @@
* 3. move to the first mountpoint along the way.
* 4. repeat.
*
- * An invariant is that each time through the loop, c is on the undomount
- * side of the mount point, and c's name is cname.
+ * Each time through the loop:
+ *
+ * If didmount==0, c is on the undomount side of the mount point.
+ * If didmount==1, c is on the domount side of the mount point.
+ * Either way, c's full path is path.
*/
+ didmount = 0;
for(nhave=0; nhave<nnames; nhave+=n){
- if((c->qid.type&QTDIR)==0){
+ if((c->qid.type&QTDIR) == 0){
if(nerror)
*nerror = nhave;
- cnameclose(cname);
+ pathclose(path);
cclose(c);
- strcpy(up->errstr, Enotdir);
- if(mh != nil)
-{print("walk 1\n");
- putmhead(mh);
-}
+ kstrcpy(up->errstr, Enotdir, ERRMAX);
+ putmhead(mh);
return -1;
}
ntry = nnames - nhave;
@@ -779,83 +877,89 @@
dotdot = 0;
for(i=0; i<ntry; i++){
if(isdotdot(names[nhave+i])){
- if(i==0) {
+ if(i==0){
dotdot = 1;
ntry = 1;
- } else
+ }else
ntry = i;
break;
}
}
- if(!dotdot && !nomount)
- domount(&c, &mh);
-
+ if(!dotdot && !nomount && !didmount)
+ domount(&c, &mh, &path);
+
type = c->type;
dev = c->dev;
- if((wq = devtab[type]->walk(c, nil, names+nhave, ntry)) == nil){
+ if((wq = ewalk(c, nil, names+nhave, ntry)) == nil){
/* try a union mount, if any */
- if(mh && !nomount){
+ if(mh != nil && !nomount){
/*
- * mh->mount == c, so start at mh->mount->next
+ * mh->mount->to == c, so start at mh->mount->next
*/
rlock(&mh->lock);
- for(f = mh->mount->next; f; f = f->next)
- if((wq = devtab[f->to->type]->walk(f->to, nil, names+nhave, ntry)) != nil)
+ if((f = mh->mount) != nil)
+ f = f->next;
+ for(; f != nil; f = f->next)
+ if((wq = ewalk(f->to, nil, names+nhave, ntry)) != nil){
+ type = f->to->type;
+ dev = f->to->dev;
break;
+ }
runlock(&mh->lock);
- if(f != nil){
- type = f->to->type;
- dev = f->to->dev;
- }
}
if(wq == nil){
cclose(c);
- cnameclose(cname);
+ pathclose(path);
if(nerror)
*nerror = nhave+1;
- if(mh != nil)
- putmhead(mh);
+ putmhead(mh);
return -1;
}
}
- nmh = nil;
- if(dotdot) {
+ didmount = 0;
+ if(dotdot){
assert(wq->nqid == 1);
assert(wq->clone != nil);
- cname = addelem(cname, "..");
- nc = undomount(wq->clone, cname);
+ path = addelem(path, "..", nil);
+ nc = undomount(wq->clone, path);
+ nmh = nil;
n = 1;
- } else {
+ }else{
nc = nil;
- if(!nomount)
- for(i=0; i<wq->nqid && i<ntry-1; i++)
- if(findmount(&nc, &nmh, type, dev, wq->qid[i]))
+ nmh = nil;
+ if(!nomount){
+ for(i=0; i<wq->nqid && i<ntry-1; i++){
+ if(findmount(&nc, &nmh, type, dev, wq->qid[i])){
+ didmount = 1;
break;
+ }
+ }
+ }
if(nc == nil){ /* no mount points along path */
if(wq->clone == nil){
cclose(c);
- cnameclose(cname);
- if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){
+ pathclose(path);
+ if(wq->nqid == 0 || (wq->qid[wq->nqid-1].type&QTDIR) != 0){
if(nerror)
*nerror = nhave+wq->nqid+1;
- strcpy(up->errstr, Edoesnotexist);
+ kstrcpy(up->errstr, Edoesnotexist, ERRMAX);
}else{
if(nerror)
*nerror = nhave+wq->nqid;
- strcpy(up->errstr, Enotdir);
+ kstrcpy(up->errstr, Enotdir, ERRMAX);
}
free(wq);
- if(mh != nil)
- putmhead(mh);
+ putmhead(mh);
return -1;
}
n = wq->nqid;
nc = wq->clone;
}else{ /* stopped early, at a mount point */
+ didmount = 1;
if(wq->clone != nil){
cclose(wq->clone);
wq->clone = nil;
@@ -862,8 +966,12 @@
}
n = i+1;
}
- for(i=0; i<n; i++)
- cname = addelem(cname, names[nhave+i]);
+ for(i=0; i<n; i++){
+ mtpt = nil;
+ if(i==n-1 && nmh!=nil)
+ mtpt = nmh->from;
+ path = addelem(path, names[nhave+i], mtpt);
+ }
}
cclose(c);
c = nc;
@@ -871,11 +979,8 @@
mh = nmh;
free(wq);
}
-
putmhead(mh);
-
c = cunique(c);
-
if(c->umh != nil){ //BUG
print("walk umh\n");
putmhead(c->umh);
@@ -882,13 +987,13 @@
c->umh = nil;
}
- cnameclose(c->name);
- c->name = cname;
+ pathclose(c->path);
+ c->path = path;
cclose(*cp);
*cp = c;
if(nerror)
- *nerror = 0;
+ *nerror = nhave;
return 0;
}
@@ -902,12 +1007,12 @@
Mount *f;
rlock(&m->lock);
- if(waserror()) {
+ if(waserror()){
runlock(&m->lock);
nexterror();
}
- for(f = m->mount; f; f = f->next) {
- if(f->mflag&MCREATE) {
+ for(f = m->mount; f != nil; f = f->next){
+ if((f->mflag&MCREATE) != 0){
nc = cclone(f->to);
runlock(&m->lock);
poperror();
@@ -924,31 +1029,6 @@
{
}
-/*
- * In place, rewrite name to compress multiple /, eliminate ., and process ..
- */
-void
-cleancname(Cname *n)
-{
- char *p;
-
- if(n->s[0] == '#'){
- p = strchr(n->s, '/');
- if(p == nil)
- return;
- cleanname(p);
-
- /*
- * The correct name is #i rather than #i/,
- * but the correct name of #/ is #/.
- */
- if(strcmp(p, "/")==0 && n->s[1] != '/')
- *p = '\0';
- }else
- cleanname(n->s);
- n->len = strlen(n->s);
-}
-
static void
growparse(Elemlist *e)
{
@@ -956,13 +1036,13 @@
int *inew;
enum { Delta = 8 };
- if(e->nelems % Delta == 0){
+ if((e->nelems % Delta) == 0){
new = smalloc((e->nelems+Delta) * sizeof(char*));
memmove(new, e->elems, e->nelems*sizeof(char*));
free(e->elems);
e->elems = new;
inew = smalloc((e->nelems+Delta+1) * sizeof(int));
- memmove(inew, e->off, e->nelems*sizeof(int));
+ memmove(inew, e->off, (e->nelems+1)*sizeof(int));
free(e->off);
e->off = inew;
}
@@ -978,11 +1058,11 @@
* rather than a directory.
*/
static void
-parsename(char *name, Elemlist *e)
+parsename(char *aname, Elemlist *e)
{
- char *slash;
+ char *name, *slash;
- kstrdup(&e->name, name);
+ kstrdup(&e->name, aname);
name = e->name;
e->nelems = 0;
e->elems = nil;
@@ -990,7 +1070,8 @@
e->off[0] = skipslash(name) - name;
for(;;){
name = skipslash(name);
- if(*name=='\0'){
+ if(*name == '\0'){
+ e->off[e->nelems] = name+strlen(name) - e->name;
e->mustbedir = 1;
break;
}
@@ -1009,7 +1090,7 @@
}
void*
-mymemrchr(void *va, int c, long n)
+memrchr(void *va, int c, long n)
{
uchar *a, *e;
@@ -1020,28 +1101,79 @@
return nil;
}
+void
+namelenerror(char *aname, int len, char *err)
+{
+ char *ename, *name, *next;
+ int i, errlen;
+
+ /*
+ * If the name is short enough, just use the whole thing.
+ */
+ errlen = strlen(err);
+ if(len < ERRMAX/3 || len+errlen < 2*ERRMAX/3)
+ snprint(up->genbuf, sizeof up->genbuf, "%.*s",
+ utfnlen(aname, len), aname);
+ else{
+ /*
+ * Print a suffix of the name, but try to get a little info.
+ */
+ ename = aname+len;
+ next = ename;
+ do{
+ name = next;
+ next = memrchr(aname, '/', name-aname);
+ if(next == nil)
+ next = aname;
+ len = ename-next;
+ }while(len < ERRMAX/3 || len + errlen < 2*ERRMAX/3);
+
+ /*
+ * If the name is ridiculously long, chop it.
+ */
+ if(name == ename){
+ name = ename-ERRMAX/4;
+ if(name <= aname)
+ panic("bad math in namelenerror");
+ /* walk out of current UTF sequence */
+ for(i=0; (*name&0xC0)==0x80 && i<UTFmax; i++)
+ name++;
+ }
+ snprint(up->genbuf, sizeof up->genbuf, "...%.*s",
+ utfnlen(name, ename-name), name);
+ }
+ snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, err);
+ nexterror();
+}
+
+void
+nameerror(char *name, char *err)
+{
+ namelenerror(name, strlen(name), err);
+}
+
/*
* Turn a name into a channel.
* &name[0] is known to be a valid address. It may be a kernel address.
*
- * Opening with amode Aopen, Acreate, or Aremove guarantees
+ * Opening with amode Aopen, Acreate, Aremove, or Aaccess guarantees
* that the result will be the only reference to that particular fid.
* This is necessary since we might pass the result to
* devtab[]->remove().
*
- * Opening Atodir, Amount, or Aaccess does not guarantee this.
+ * Opening Atodir or Amount does not guarantee this.
*
- * Opening Aaccess can, under certain conditions, return a
- * correct Chan* but with an incorrect Cname attached.
- * Since the functions that open Aaccess (sysstat, syswstat, sys_stat)
- * do not use the Cname*, this avoids an unnecessary clone.
+ * Under certain circumstances, opening Aaccess will cause
+ * an unnecessary clone in order to get a cunique Chan so it
+ * can attach the correct name. Sysstat and sys_stat need the
+ * correct name so they can rewrite the stat info.
*/
Chan*
namec(char *aname, int amode, int omode, ulong perm)
{
- int n, prefix, len, t, nomount, npath;
+ int len, n, t, nomount;
Chan *c, *cnew;
- Cname *cname;
+ Path *path;
Elemlist e;
Rune r;
Mhead *m;
@@ -1048,10 +1180,14 @@
char *createerr, tmperrbuf[ERRMAX];
char *name;
- name = aname;
- if(name[0] == '\0')
+ if(aname[0] == '\0')
error("empty file name");
- validname(name, 1);
+ aname = validnamedup(aname, 1);
+ if(waserror()){
+ free(aname);
+ nexterror();
+ }
+ name = aname;
/*
* Find the starting off point (the current slash, the root of
@@ -1069,7 +1205,7 @@
nomount = 1;
up->genbuf[0] = '\0';
n = 0;
- while(*name!='\0' && (*name != '/' || n < 2)){
+ while(*name != '\0' && (*name != '/' || n < 2)){
if(n >= sizeof(up->genbuf)-1)
error(Efilename);
up->genbuf[n++] = *name++;
@@ -1088,9 +1224,6 @@
* any others left unprotected)
*/
n = chartorune(&r, up->genbuf+1)+1;
- /* actually / is caught by parsing earlier */
- if(utfrune("M", r))
- error(Enoattach);
if(up->pgrp->noattach && utfrune("|decp", r)==nil)
error(Enoattach);
t = devno(r, 1);
@@ -1104,23 +1237,34 @@
incref(&c->ref);
break;
}
- prefix = name - aname;
+ e.aname = aname;
+ e.prefix = name - aname;
e.name = nil;
e.elems = nil;
e.off = nil;
e.nelems = 0;
+ e.nerror = 0;
if(waserror()){
cclose(c);
free(e.name);
free(e.elems);
+ /*
+ * Prepare nice error, showing first e.nerror elements of name.
+ */
+ if(e.nerror == 0)
+ nexterror();
+ strcpy(tmperrbuf, up->errstr);
+ if(e.off[e.nerror]==0)
+ print("nerror=%d but off=%d\n",
+ e.nerror, e.off[e.nerror]);
+ len = e.prefix+e.off[e.nerror];
free(e.off);
-//dumpmount();
- nexterror();
+ namelenerror(aname, len, tmperrbuf);
}
/*
- * Build a list of elements in the path.
+ * Build a list of elements in the name.
*/
parsename(name, &e);
@@ -1130,9 +1274,8 @@
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;
+ e.nerror = e.nelems;
+ error("create without DMDIR");
}
/* don't try to walk the last path element just yet. */
@@ -1141,66 +1284,58 @@
e.nelems--;
}
- if(walk(&c, e.elems, e.nelems, nomount, &npath) < 0){
- if(npath < 0 || npath > e.nelems){
- print("namec %s walk error npath=%d\n", aname, npath);
- nexterror();
+ if(walk(&c, e.elems, e.nelems, nomount, &e.nerror) < 0){
+ if(e.nerror < 0 || e.nerror > e.nelems){
+ print("namec %s walk error nerror=%d\n", aname, e.nerror);
+ e.nerror = 0;
}
- strcpy(tmperrbuf, up->errstr);
- NameError:
- len = prefix+e.off[npath];
- if(len < ERRMAX/3 || (name=mymemrchr(aname, '/', len))==nil || name==aname)
- snprint(up->genbuf, sizeof up->genbuf, "%.*s", len, aname);
- else
- snprint(up->genbuf, sizeof up->genbuf, "...%.*s", (int)(len-(name-aname)), name);
- snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, tmperrbuf);
nexterror();
}
- if(e.mustbedir && !(c->qid.type&QTDIR)){
- npath = e.nelems;
- strcpy(tmperrbuf, "not a directory");
- goto NameError;
- }
+ if(e.mustbedir && (c->qid.type&QTDIR) == 0)
+ error("not a directory");
- if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR)){
- npath = e.nelems;
+ if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR) != 0)
error("cannot exec directory");
- }
switch(amode){
- case Aaccess:
- if(!nomount)
- domount(&c, nil);
- break;
-
case Abind:
+ /* no need to maintain path - cannot dotdot an Abind */
m = nil;
if(!nomount)
- domount(&c, &m);
- if(c->umh != nil)
- putmhead(c->umh);
+ domount(&c, &m, nil);
+ putmhead(c->umh);
c->umh = m;
break;
+ case Aaccess:
case Aremove:
case Aopen:
Open:
- /* save the name; domount might change c */
- cname = c->name;
- incref(&cname->ref);
+ /* save&update the name; domount might change c */
+ path = c->path;
+ incref(&path->ref);
+ if(waserror()){
+ pathclose(path);
+ nexterror();
+ }
m = nil;
if(!nomount)
- domount(&c, &m);
+ domount(&c, &m, &path);
/* our own copy to open or remove */
c = cunique(c);
/* now it's our copy anyway, we can put the name back */
- cnameclose(c->name);
- c->name = cname;
+ pathclose(c->path);
+ c->path = path;
+ poperror();
+ /* record whether c is on a mount point */
+ c->ismtpt = m!=nil;
+
switch(amode){
+ case Aaccess:
case Aremove:
putmhead(m);
break;
@@ -1207,14 +1342,13 @@
case Aopen:
case Acreate:
-if(c->umh != nil){
- print("cunique umh Open\n");
- putmhead(c->umh);
- c->umh = nil;
-}
-
+ if(c->umh != nil){
+ print("cunique umh Open\n");
+ putmhead(c->umh);
+ c->umh = nil;
+ }
/* only save the mount head if it's a multiple element union */
- if(m && m->mount && m->mount->next)
+ if(m != nil && m->mount != nil && m->mount->next != nil)
c->umh = m;
else
putmhead(m);
@@ -1222,9 +1356,6 @@
/* save registers else error() in open has wrong value of c saved */
saveregisters();
- if(omode == OEXEC)
- c->flag &= ~CCACHE;
-
c = devtab[c->type]->open(c, omode&~OCEXEC);
if(omode & OCEXEC)
@@ -1240,7 +1371,7 @@
* Directories (e.g. for cd) are left before the mount point,
* so one may mount on / or . and see the effect.
*/
- if(!(c->qid.type & QTDIR))
+ if((c->qid.type&QTDIR) == 0)
error(Enotdir);
break;
@@ -1259,6 +1390,7 @@
* If omode&OEXCL is set, just give up.
*/
e.nelems++;
+ e.nerror++;
if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){
if(omode&OEXCL)
error(Eexist);
@@ -1323,9 +1455,9 @@
* if findmount gave us a new Chan.
*/
cnew = cunique(cnew);
- cnameclose(cnew->name);
- cnew->name = c->name;
- incref(&cnew->name->ref);
+ pathclose(cnew->path);
+ cnew->path = c->path;
+ incref(&cnew->path->ref);
cnew = devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm);
poperror();
@@ -1333,38 +1465,34 @@
cnew->flag |= CCEXEC;
if(omode & ORCLOSE)
cnew->flag |= CRCLOSE;
- if(m)
- putmhead(m);
+ putmhead(m);
cclose(c);
c = cnew;
- c->name = addelem(c->name, e.elems[e.nelems-1]);
+ c->path = addelem(c->path, e.elems[e.nelems-1], nil);
break;
- }else{ /* create failed */
- cclose(cnew);
- if(m)
- putmhead(m);
- if(omode & OEXCL)
- nexterror();
- /* save error */
- createerr = up->errstr;
- up->errstr = tmperrbuf;
- /* note: we depend that walk does not error */
- if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){
- up->errstr = createerr;
- error(createerr); /* report true error */
- }
+ }
+
+ /* create failed */
+ cclose(cnew);
+ putmhead(m);
+ if(omode & OEXCL)
+ nexterror();
+ /* save error */
+ createerr = up->errstr;
+ up->errstr = tmperrbuf;
+ /* note: we depend that walk does not error */
+ if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){
up->errstr = createerr;
- omode |= OTRUNC;
- goto Open;
+ error(createerr); /* report true error */
}
- panic("namec: not reached");
+ up->errstr = createerr;
+ omode |= OTRUNC;
+ goto Open;
default:
- panic("unknown namec access %d\n", amode);
+ panic("unknown namec access %d", amode);
}
- poperror();
-
/* place final element in genbuf for e.g. exec */
if(e.nelems > 0)
kstrcpy(up->genbuf, e.elems[e.nelems-1], sizeof up->genbuf);
@@ -1373,6 +1501,9 @@
free(e.name);
free(e.elems);
free(e.off);
+ poperror(); /* e c */
+ free(aname);
+ poperror(); /* aname */
return c;
}
@@ -1389,22 +1520,12 @@
}
char isfrog[256]={
- /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */
- /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x08 */
- /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 */
- /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x18 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
- 0, 0, 0, 0, 0, 0, 0, 1, /* 0x28 (1 is '/', 0x2F) */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x38 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */
- 0, 0, 0, 0, 0, 0, 0, 1, /* 0x78 (1 is DEL, 0x7F) */
+ /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1,
+ /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1,
+ /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1,
+ /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1,
+ ['/'] 1,
+ [0x7f] 1,
};
/*
@@ -1416,30 +1537,36 @@
* routine works for kernel and user memory both.
* The parameter slashok flags whether a slash character is an error
* or a valid character.
+ *
+ * The parameter dup flags whether the string should be copied
+ * out of user space before being scanned the second time.
+ * (Otherwise a malicious thread could remove the NUL, causing us
+ * to access unchecked addresses.)
*/
-void
-validname(char *aname, int slashok)
+static char*
+validname0(char *aname, int slashok, int dup, uintptr pc)
{
- char *ename, *name;
- int c;
+ char *ename, *name, *s;
+ int c, n;
Rune r;
name = aname;
-/*
- if(((ulong)name & KZERO) != KZERO) {
- p = name;
- t = BY2PG-((ulong)p&(BY2PG-1));
- while((ename=vmemchr(p, 0, t)) == nil) {
- p += t;
- t = BY2PG;
- }
- }else
-*/
- ename = memchr(name, 0, (1<<16));
+ ename = memchr(name, 0, (1<<16));
if(ename==nil || ename-name>=(1<<16))
- error("name too long");
+ error(Etoolong);
+ s = nil;
+ if(dup){
+ n = ename-name;
+ s = smalloc(n+1);
+ memmove(s, name, n);
+ s[n] = 0;
+ aname = s;
+ name = s;
+ setmalloctag(s, pc);
+ }
+
while(*name){
/* all characters above '~' are ok */
c = *(uchar*)name;
@@ -1447,47 +1574,33 @@
name += chartorune(&r, name);
else{
if(isfrog[c])
- if(!slashok || c!='/'){
- snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname);
- error(up->genbuf);
+ if(!slashok || c!='/'){
+ snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname);
+ free(s);
+ error(up->genbuf);
}
name++;
}
}
+ return s;
}
void
-isdir(Chan *c)
+validname(char *aname, int slashok)
{
- if(c->qid.type & QTDIR)
- return;
- error(Enotdir);
+ validname0(aname, slashok, 0, getcallerpc(&aname));
}
-/*
- * This is necessary because there are many
- * pointers to the top of a given mount list:
- *
- * - the mhead in the namespace hash table
- * - the mhead in chans returned from findmount:
- * used in namec and then by unionread.
- * - the mhead in chans returned from createdir:
- * used in the open/create race protect, which is gone.
- *
- * The RWlock in the Mhead protects the mount list it contains.
- * The mount list is deleted when we cunmount.
- * The RWlock ensures that nothing is using the mount list at that time.
- *
- * It is okay to replace c->mh with whatever you want as
- * long as you are sure you have a unique reference to it.
- *
- * This comment might belong somewhere else.
- */
+char*
+validnamedup(char *aname, int slashok)
+{
+ return validname0(aname, slashok, 1, getcallerpc(&aname));
+}
+
void
-putmhead(Mhead *m)
+isdir(Chan *c)
{
- if(m && decref(&m->ref) == 0){
- m->mount = (Mount*)0xCafeBeef;
- free(m);
- }
+ if(c->qid.type & QTDIR)
+ return;
+ error(Enotdir);
}
--- a/kern/dat.h
+++ b/kern/dat.h
@@ -6,7 +6,6 @@
typedef struct Chan Chan;
typedef struct Cmdbuf Cmdbuf;
typedef struct Cmdtab Cmdtab;
-typedef struct Cname Cname;
typedef struct Conf Conf;
typedef struct Dev Dev;
typedef struct Dirtab Dirtab;
@@ -22,6 +21,7 @@
typedef struct Mntwalk Mntwalk;
typedef struct Mnt Mnt;
typedef struct Mhead Mhead;
+typedef struct Path Path;
typedef struct Pgrps Pgrps;
typedef struct Pgrp Pgrp;
typedef struct Proc Proc;
@@ -135,10 +135,12 @@
struct Chan
{
- Ref ref;
+ Ref ref;
+ Lock lk;
Chan* next; /* allocation */
Chan* link;
- vlong offset; /* in file */
+ vlong offset; /* in fd */
+ vlong devoffset; /* in underlying device; see read */
ushort type;
ulong dev;
ushort mode; /* read/write */
@@ -145,28 +147,37 @@
ushort flag;
Qid qid;
int fid; /* for devmnt */
- ulong iounit; /* chunk size for i/o; 0==default */
+ ulong iounit; /* chunk size for i/o; 0==default */
Mhead* umh; /* mount point that derived Chan; used in unionread */
Chan* umc; /* channel in union; held for union read */
QLock umqlock; /* serialize unionreads */
int uri; /* union read index */
int dri; /* devdirread index */
- ulong mountid;
- Mnt *mux; /* Mnt for clients using me for messages */
- void* aux;
- Qid pgrpid; /* for #p/notepg */
- ulong mid; /* for ns in devproc */
+ uchar* dirrock; /* directory entry rock for translations */
+ int nrock;
+ int mrock;
+ QLock rockqlock;
+ int ismtpt;
+ Mnt* mux; /* Mnt for clients using me for messages */
+ union {
+ void* aux;
+ Qid pgrpid; /* for #p/notepg */
+ ulong mid; /* for ns in devproc */
+ };
Chan* mchan; /* channel to mounted server */
Qid mqid; /* qid of root of mount point */
- Cname *name;
+ Path* path;
};
-struct Cname
+struct Path
{
- Ref ref;
- int alen; /* allocated length */
- int len; /* strlen(s) */
+ Ref ref;
char *s;
+ Chan **mtpt; /* mtpt history */
+ int len; /* strlen(s) */
+ int alen; /* allocated length of s */
+ int mlen; /* number of path elements */
+ int malen; /* allocated length of mtpt */
};
struct Dev
@@ -198,7 +209,7 @@
char name[KNAMELEN];
Qid qid;
vlong length;
- ulong perm;
+ long perm;
};
struct Walkqid
@@ -315,7 +326,7 @@
struct Fgrp
{
- Ref ref;
+ Ref ref;
Chan **fd;
int nfd; /* number allocated */
int maxfd; /* highest fd in use */
--- a/kern/dev.c
+++ b/kern/dev.c
@@ -24,7 +24,7 @@
return i;
}
if(user == 0)
- panic("devno %C 0x%ux", c, c);
+ panic("devno %C %#ux", c, c);
return -1;
}
@@ -124,6 +124,7 @@
Chan*
devattach(int tc, char *spec)
{
+ int n;
Chan *c;
char *buf;
@@ -132,9 +133,10 @@
c->type = devno(tc, 0);
if(spec == nil)
spec = "";
- buf = smalloc(4+strlen(spec)+1);
- sprint(buf, "#%C%s", tc, spec);
- c->name = newcname(buf);
+ n = 1+UTFmax+strlen(spec)+1;
+ buf = smalloc(n);
+ snprint(buf, n, "#%C%s", tc, spec);
+ c->path = newpath(buf);
free(buf);
return c;
}
@@ -146,7 +148,7 @@
Chan *nc;
if(c->flag & COPEN)
- panic("clone of open file type %C\n", devtab[c->type]->dc);
+ panic("clone of open file type %C", devtab[c->type]->dc);
nc = newchan();
@@ -156,10 +158,7 @@
nc->qid = c->qid;
nc->offset = c->offset;
nc->umh = nil;
- nc->mountid = c->mountid;
nc->aux = c->aux;
- nc->pgrpid = c->pgrpid;
- nc->mid = c->mid;
nc->mqid = c->mqid;
return nc;
}
@@ -175,18 +174,17 @@
if(nname > 0)
isdir(c);
- alloc = 0;
+ alloc = (nc == nil);
wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
if(waserror()){
- if(alloc && wq->clone!=nil)
+ if(alloc && wq->clone != nil)
cclose(wq->clone);
free(wq);
return nil;
}
- if(nc == nil){
+ if(alloc){
nc = devclone(c);
nc->type = 0; /* device doesn't know about this channel yet */
- alloc = 1;
}
wq->clone = nc;
@@ -251,7 +249,7 @@
if(alloc)
cclose(wq->clone);
wq->clone = nil;
- }else if(wq->clone){
+ }else if(wq->clone != nil){
/* attach cloned channel to same device */
wq->clone->type = c->type;
}
@@ -265,16 +263,16 @@
Dir dir;
char *p, *elem;
- for(i=0;; i++)
+ for(i=0;; i++){
switch((*gen)(c, nil, tab, ntab, i, &dir)){
case -1:
if(c->qid.type & QTDIR){
- if(c->name == nil)
+ if(c->path == nil)
elem = "???";
- else if(strcmp(c->name->s, "/") == 0)
+ else if(strcmp(c->path->s, "/") == 0)
elem = "/";
else
- for(elem=p=c->name->s; *p; p++)
+ for(elem=p=c->path->s; *p; p++)
if(*p == '/')
elem = p+1;
devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);
@@ -283,7 +281,6 @@
error(Ebadarg);
return n;
}
- print("devstat %C %llux\n", devtab[c->type]->dc, c->qid.path);
error(Enonexist);
case 0:
@@ -299,8 +296,7 @@
}
break;
}
- error(Egreg); /* not reached? */
- return -1;
+ }
}
long
@@ -307,13 +303,10 @@
devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
{
long m, dsz;
- struct{
- Dir d;
- char slop[100];
- }dir;
+ Dir dir;
for(m=0; m<n; c->dri++) {
- switch((*gen)(c, nil, tab, ntab, c->dri, &dir.d)){
+ switch((*gen)(c, nil, tab, ntab, c->dri, &dir)){
case -1:
return m;
@@ -321,7 +314,7 @@
break;
case 1:
- dsz = convD2M(&dir.d, (uchar*)d, n-m);
+ dsz = convD2M(&dir, (uchar*)d, n-m);
if(dsz <= BIT16SZ){ /* <= not < because this isn't stat; read is stuck */
if(m == 0)
error(Eshort);
@@ -396,7 +389,7 @@
USED(perm);
error(Eperm);
- return nil;
+ return 0;
}
Block*
--- a/kern/devlfd.c
+++ b/kern/devlfd.c
@@ -16,7 +16,7 @@
c = newchan();
c->type = devno('L', 0);
c->aux = (void*)(uintptr)fd;
- c->name = newcname("fd");
+ c->path = newpath("fd");
c->mode = ORDWR;
c->qid.type = 0;
c->qid.path = 0;
--- a/kern/error.c
+++ b/kern/error.c
@@ -48,3 +48,4 @@
char Ebadstat[] = "malformed stat buffer";
char Enegoff[] = "negative i/o offset";
char Ecmdargs[] = "wrong #args in control message";
+char Etoolong[] = "name too long";
--- a/kern/error.h
+++ b/kern/error.h
@@ -48,3 +48,4 @@
extern char Ebadstat[]; /* malformed stat buffer */
extern char Enegoff[]; /* negative i/o offset */
extern char Ecmdargs[]; /* wrong #args in control message */
+extern char Etoolong[]; /* name too long */
--- a/kern/fns.h
+++ b/kern/fns.h
@@ -26,7 +26,6 @@
void closergrp(Rgrp*);
void cmderror(Cmdbuf*, char*);
int cmount(Chan**, Chan*, int, char*);
-void cnameclose(Cname*);
Block* concatblock(Block*);
Block* copyblock(Block*, int);
void cunmount(Chan*, Chan*);
@@ -107,13 +106,13 @@
Chan* newchan(void);
int newfd(Chan*);
Mhead* newmhead(Chan*);
-Mount* newmount(Mhead*, Chan*, int, char*);
+Mount* newmount(Chan*, int, char*);
+Path* newpath(char*);
Pgrp* newpgrp(void);
Rgrp* newrgrp(void);
Proc* newproc(void);
char* nextelem(char*, char*);
void nexterror(void);
-Cname* newcname(char*);
int openmode(ulong);
void oserrstr(void);
void oserror(void);
@@ -121,6 +120,7 @@
Block* padblock(Block*, int);
void panic(char*, ...);
Cmdbuf* parsecmd(char *a, int n);
+void pathclose(Path*);
void pexit(char*, int);
void printinit(void);
int procindex(ulong);
@@ -201,6 +201,7 @@
long userwrite(char*, int);
#define validaddr(a, b, c)
void validname(char*, int);
+char* validnamedup(char*, int);
void validstat(uchar*, int);
void* vmemchr(void*, int, int);
Proc* wakeup(Rendez*);
--- a/kern/pgrp.c
+++ b/kern/pgrp.c
@@ -7,39 +7,6 @@
static Ref pgrpid;
static Ref mountid;
-#ifdef NOTDEF
-void
-pgrpnote(ulong noteid, char *a, long n, int flag)
-{
- Proc *p, *ep;
- char buf[ERRMAX];
-
- if(n >= ERRMAX-1)
- error(Etoobig);
-
- memmove(buf, a, n);
- buf[n] = 0;
- p = proctab(0);
- ep = p+conf.nproc;
- for(; p < ep; p++) {
- if(p->state == Dead)
- continue;
- if(up != p && p->noteid == noteid && p->kp == 0) {
- qlock(&p->debug);
- if(p->pid == 0 || p->noteid != noteid){
- qunlock(&p->debug);
- continue;
- }
- if(!waserror()) {
- postnote(p, 0, buf, flag);
- poperror();
- }
- qunlock(&p->debug);
- }
- }
-}
-#endif
-
Pgrp*
newpgrp(void)
{
@@ -71,29 +38,24 @@
void
closepgrp(Pgrp *p)
{
- Mhead **h, **e, *f, *next;
+ Mhead **h, **e, *f;
+ Mount *m;
- if(decref(&p->ref) != 0)
+ if(decref(&p->ref))
return;
- qlock(&p->debug);
- wlock(&p->ns);
- p->pgrpid = -1;
-
e = &p->mnthash[MNTHASH];
for(h = p->mnthash; h < e; h++) {
- for(f = *h; f; f = next) {
+ while((f = *h) != nil){
+ *h = f->hash;
wlock(&f->lock);
- cclose(f->from);
- mountfree(f->mount);
+ m = f->mount;
f->mount = nil;
- next = f->hash;
wunlock(&f->lock);
+ mountfree(m);
putmhead(f);
}
}
- wunlock(&p->ns);
- qunlock(&p->debug);
free(p);
}
@@ -102,12 +64,12 @@
{
Mount *f;
- m->order = 0;
- if(*order == 0) {
+ m->order = nil;
+ if(*order == nil) {
*order = m;
return;
}
- for(f = *order; f; f = f->order) {
+ for(f = *order; f != nil; f = f->order) {
if(m->mountid < f->mountid) {
m->order = f;
*order = m;
@@ -124,25 +86,31 @@
void
pgrpcpy(Pgrp *to, Pgrp *from)
{
- int i;
Mount *n, *m, **link, *order;
Mhead *f, **tom, **l, *mh;
+ int i;
- wlock(&from->ns);
- order = 0;
+ wlock(&to->ns);
+ rlock(&from->ns);
+ order = nil;
tom = to->mnthash;
for(i = 0; i < MNTHASH; i++) {
l = tom++;
- for(f = from->mnthash[i]; f; f = f->hash) {
+ for(f = from->mnthash[i]; f != nil; f = f->hash) {
rlock(&f->lock);
mh = newmhead(f->from);
*l = mh;
l = &mh->hash;
link = &mh->mount;
- for(m = f->mount; m; m = m->next) {
- n = newmount(mh, m->to, m->mflag, m->spec);
- m->copy = n;
- pgrpinsert(&order, m);
+ for(m = f->mount; m != nil; m = m->next) {
+ n = smalloc(sizeof(Mount));
+ n->mountid = m->mountid;
+ n->mflag = m->mflag;
+ n->to = m->to;
+ incref(&n->to->ref);
+ if(m->spec != nil)
+ kstrdup(&n->spec, m->spec);
+ pgrpinsert(&order, n);
*link = n;
link = &n->next;
}
@@ -152,11 +120,10 @@
/*
* Allocate mount ids in the same sequence as the parent group
*/
- lock(&mountid.lk);
- for(m = order; m; m = m->order)
- m->copy->mountid = mountid.ref++;
- unlock(&mountid.lk);
- wunlock(&from->ns);
+ for(m = order; m != nil; m = m->order)
+ m->mountid = incref(&mountid);
+ runlock(&from->ns);
+ wunlock(&to->ns);
}
Fgrp*
@@ -181,8 +148,9 @@
if(i != 0)
new->nfd += DELTAFD - i;
new->fd = malloc(new->nfd*sizeof(Chan*));
- if(new->fd == 0){
+ if(new->fd == nil){
unlock(&f->ref.lk);
+ free(new);
error("no memory for fgrp");
}
new->ref.ref = 1;
@@ -189,7 +157,7 @@
new->maxfd = f->maxfd;
for(i = 0; i <= f->maxfd; i++) {
- if((c = f->fd[i])){
+ if((c = f->fd[i]) != nil){
incref(&c->ref);
new->fd[i] = c;
}
@@ -205,15 +173,14 @@
int i;
Chan *c;
- if(f == 0)
+ if(f == nil || decref(&f->ref))
return;
- if(decref(&f->ref) != 0)
- return;
-
for(i = 0; i <= f->maxfd; i++)
- if((c = f->fd[i]))
+ if((c = f->fd[i]) != nil){
+ f->fd[i] = nil;
cclose(c);
+ }
free(f->fd);
free(f);
@@ -220,17 +187,16 @@
}
Mount*
-newmount(Mhead *mh, Chan *to, int flag, char *spec)
+newmount(Chan *to, int flag, char *spec)
{
Mount *m;
m = smalloc(sizeof(Mount));
m->to = to;
- m->head = mh;
incref(&to->ref);
m->mountid = incref(&mountid);
m->mflag = flag;
- if(spec != 0)
+ if(spec != nil)
kstrdup(&m->spec, spec);
return m;
@@ -241,12 +207,10 @@
{
Mount *f;
- while(m) {
- f = m->next;
- cclose(m->to);
- m->mountid = 0;
- free(m->spec);
- free(m);
- m = f;
+ while((f = m) != nil) {
+ m = m->next;
+ cclose(f->to);
+ free(f->spec);
+ free(f);
}
}
--- a/kern/procinit.c
+++ b/kern/procinit.c
@@ -18,8 +18,8 @@
_setproc(p);
up->slash = namec("#/", Atodir, 0, 0);
- cnameclose(up->slash->name);
- up->slash->name = newcname("/");
+ pathclose(up->slash->path);
+ up->slash->path = newpath("/");
up->dot = cclone(up->slash);
}
--- a/kern/sysfile.c
+++ b/kern/sysfile.c
@@ -190,10 +190,10 @@
c = fdtochan(fd, -1, 0, 1);
- if(c->name == nil)
+ if(c->path == nil)
snprint(buf, nbuf, "<null>");
else
- snprint(buf, nbuf, "%s", c->name->s);
+ snprint(buf, nbuf, "%s", c->path->s);
cclose(c);
return 0;
}