13e12c5d1SDavid du Colombier #include "u.h"
23e12c5d1SDavid du Colombier #include "../port/lib.h"
33e12c5d1SDavid du Colombier #include "mem.h"
43e12c5d1SDavid du Colombier #include "dat.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier #include "../port/error.h"
73e12c5d1SDavid du Colombier
89a747e4fSDavid du Colombier int chandebug=0; /* toggled by sysr1 */
94afe124fSDavid du Colombier #define DBG if(chandebug)iprint
109a747e4fSDavid du Colombier
117dd7cddfSDavid du Colombier enum
127dd7cddfSDavid du Colombier {
134afe124fSDavid du Colombier PATHSLOP = 20,
144afe124fSDavid du Colombier PATHMSLOP = 20,
157dd7cddfSDavid du Colombier };
167dd7cddfSDavid du Colombier
173e12c5d1SDavid du Colombier struct
183e12c5d1SDavid du Colombier {
193e12c5d1SDavid du Colombier Lock;
203e12c5d1SDavid du Colombier int fid;
217dd7cddfSDavid du Colombier Chan *free;
227dd7cddfSDavid du Colombier Chan *list;
233e12c5d1SDavid du Colombier }chanalloc;
243e12c5d1SDavid du Colombier
259a747e4fSDavid du Colombier typedef struct Elemlist Elemlist;
269a747e4fSDavid du Colombier
279a747e4fSDavid du Colombier struct Elemlist
289a747e4fSDavid du Colombier {
29312a1df1SDavid du Colombier char *aname; /* original name */
309a747e4fSDavid du Colombier char *name; /* copy of name, so '/' can be overwritten */
319a747e4fSDavid du Colombier int nelems;
329a747e4fSDavid du Colombier char **elems;
339a747e4fSDavid du Colombier int *off;
34fb7f0c93SDavid du Colombier int mustbedir;
35312a1df1SDavid du Colombier int nerror;
368b6d9ba0SDavid du Colombier int prefix;
379a747e4fSDavid du Colombier };
389a747e4fSDavid du Colombier
397dd7cddfSDavid du Colombier #define SEP(c) ((c) == 0 || (c) == '/')
404afe124fSDavid du Colombier
414afe124fSDavid du Colombier static void
dumpmount(void)424afe124fSDavid du Colombier dumpmount(void) /* DEBUGGING */
434afe124fSDavid du Colombier {
444afe124fSDavid du Colombier Pgrp *pg;
454afe124fSDavid du Colombier Mount *t;
464afe124fSDavid du Colombier Mhead **h, **he, *f;
474afe124fSDavid du Colombier
484afe124fSDavid du Colombier if(up == nil){
494afe124fSDavid du Colombier print("no process for dumpmount\n");
504afe124fSDavid du Colombier return;
514afe124fSDavid du Colombier }
524afe124fSDavid du Colombier pg = up->pgrp;
534afe124fSDavid du Colombier if(pg == nil){
544afe124fSDavid du Colombier print("no pgrp for dumpmount\n");
554afe124fSDavid du Colombier return;
564afe124fSDavid du Colombier }
574afe124fSDavid du Colombier rlock(&pg->ns);
584afe124fSDavid du Colombier if(waserror()){
594afe124fSDavid du Colombier runlock(&pg->ns);
604afe124fSDavid du Colombier nexterror();
614afe124fSDavid du Colombier }
624afe124fSDavid du Colombier
634afe124fSDavid du Colombier he = &pg->mnthash[MNTHASH];
644afe124fSDavid du Colombier for(h = pg->mnthash; h < he; h++){
654afe124fSDavid du Colombier for(f = *h; f; f = f->hash){
66567483c8SDavid du Colombier print("head: %#p: %s %#llux.%lud %C %lud -> \n", f,
674afe124fSDavid du Colombier f->from->path->s, f->from->qid.path,
684afe124fSDavid du Colombier f->from->qid.vers, devtab[f->from->type]->dc,
694afe124fSDavid du Colombier f->from->dev);
704afe124fSDavid du Colombier for(t = f->mount; t; t = t->next)
71567483c8SDavid du Colombier print("\t%#p: %s (umh %#p) (path %#.8llux dev %C %lud)\n", t, t->to->path->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev);
724afe124fSDavid du Colombier }
734afe124fSDavid du Colombier }
744afe124fSDavid du Colombier poperror();
754afe124fSDavid du Colombier runlock(&pg->ns);
764afe124fSDavid du Colombier }
774afe124fSDavid du Colombier
784afe124fSDavid du Colombier char*
chanpath(Chan * c)794afe124fSDavid du Colombier chanpath(Chan *c)
804afe124fSDavid du Colombier {
814afe124fSDavid du Colombier if(c == nil)
824afe124fSDavid du Colombier return "<nil chan>";
834afe124fSDavid du Colombier if(c->path == nil)
844afe124fSDavid du Colombier return "<nil path>";
854afe124fSDavid du Colombier if(c->path->s == nil)
864afe124fSDavid du Colombier return "<nil path.s>";
874afe124fSDavid du Colombier return c->path->s;
884afe124fSDavid du Colombier }
897dd7cddfSDavid du Colombier
903e12c5d1SDavid du Colombier int
isdotdot(char * p)919a747e4fSDavid du Colombier isdotdot(char *p)
929a747e4fSDavid du Colombier {
939a747e4fSDavid du Colombier return p[0]=='.' && p[1]=='.' && p[2]=='\0';
949a747e4fSDavid du Colombier }
959a747e4fSDavid du Colombier
96e288d156SDavid du Colombier long
incref(Ref * r)973e12c5d1SDavid du Colombier incref(Ref *r)
983e12c5d1SDavid du Colombier {
99e288d156SDavid du Colombier long x;
1003e12c5d1SDavid du Colombier
101fe853e23SDavid du Colombier lock(r);
1023e12c5d1SDavid du Colombier x = ++r->ref;
103fe853e23SDavid du Colombier unlock(r);
1043e12c5d1SDavid du Colombier return x;
1053e12c5d1SDavid du Colombier }
1063e12c5d1SDavid du Colombier
107e288d156SDavid du Colombier long
decref(Ref * r)1083e12c5d1SDavid du Colombier decref(Ref *r)
1093e12c5d1SDavid du Colombier {
110e288d156SDavid du Colombier long x;
1113e12c5d1SDavid du Colombier
112fe853e23SDavid du Colombier lock(r);
1133e12c5d1SDavid du Colombier x = --r->ref;
114fe853e23SDavid du Colombier unlock(r);
1153e12c5d1SDavid du Colombier if(x < 0)
116567483c8SDavid du Colombier panic("decref pc=%#p", getcallerpc(&r));
1173e12c5d1SDavid du Colombier
1183e12c5d1SDavid du Colombier return x;
1193e12c5d1SDavid du Colombier }
1203e12c5d1SDavid du Colombier
1219a747e4fSDavid du Colombier /*
1229a747e4fSDavid du Colombier * Rather than strncpy, which zeros the rest of the buffer, kstrcpy
1239a747e4fSDavid du Colombier * truncates if necessary, always zero terminates, does not zero fill,
1249a747e4fSDavid du Colombier * and puts ... at the end of the string if it's too long. Usually used to
1259a747e4fSDavid du Colombier * save a string in up->genbuf;
1269a747e4fSDavid du Colombier */
1279a747e4fSDavid du Colombier void
kstrcpy(char * s,char * t,int ns)1289a747e4fSDavid du Colombier kstrcpy(char *s, char *t, int ns)
1299a747e4fSDavid du Colombier {
1309a747e4fSDavid du Colombier int nt;
1319a747e4fSDavid du Colombier
1329a747e4fSDavid du Colombier nt = strlen(t);
1339a747e4fSDavid du Colombier if(nt+1 <= ns){
1349a747e4fSDavid du Colombier memmove(s, t, nt+1);
1359a747e4fSDavid du Colombier return;
1369a747e4fSDavid du Colombier }
1379a747e4fSDavid du Colombier /* too long */
1389a747e4fSDavid du Colombier if(ns < 4){
1399a747e4fSDavid du Colombier /* but very short! */
1409a747e4fSDavid du Colombier strncpy(s, t, ns);
1419a747e4fSDavid du Colombier return;
1429a747e4fSDavid du Colombier }
1439a747e4fSDavid du Colombier /* truncate with ... at character boundary (very rare case) */
1449a747e4fSDavid du Colombier memmove(s, t, ns-4);
1459a747e4fSDavid du Colombier ns -= 4;
1469a747e4fSDavid du Colombier s[ns] = '\0';
1479a747e4fSDavid du Colombier /* look for first byte of UTF-8 sequence by skipping continuation bytes */
1489a747e4fSDavid du Colombier while(ns>0 && (s[--ns]&0xC0)==0x80)
1499a747e4fSDavid du Colombier ;
1509a747e4fSDavid du Colombier strcpy(s+ns, "...");
1519a747e4fSDavid du Colombier }
1529a747e4fSDavid du Colombier
1539a747e4fSDavid du Colombier int
emptystr(char * s)1549a747e4fSDavid du Colombier emptystr(char *s)
1559a747e4fSDavid du Colombier {
1569a747e4fSDavid du Colombier if(s == nil)
1579a747e4fSDavid du Colombier return 1;
1589a747e4fSDavid du Colombier if(s[0] == '\0')
1599a747e4fSDavid du Colombier return 1;
1609a747e4fSDavid du Colombier return 0;
1619a747e4fSDavid du Colombier }
1629a747e4fSDavid du Colombier
1639a747e4fSDavid du Colombier /*
1649a747e4fSDavid du Colombier * Atomically replace *p with copy of s
1659a747e4fSDavid du Colombier */
1669a747e4fSDavid du Colombier void
kstrdup(char ** p,char * s)1679a747e4fSDavid du Colombier kstrdup(char **p, char *s)
1689a747e4fSDavid du Colombier {
1699a747e4fSDavid du Colombier int n;
1709a747e4fSDavid du Colombier char *t, *prev;
1719a747e4fSDavid du Colombier
1729a747e4fSDavid du Colombier n = strlen(s)+1;
1739a747e4fSDavid du Colombier /* if it's a user, we can wait for memory; if not, something's very wrong */
1749a747e4fSDavid du Colombier if(up){
1759a747e4fSDavid du Colombier t = smalloc(n);
1769a747e4fSDavid du Colombier setmalloctag(t, getcallerpc(&p));
1779a747e4fSDavid du Colombier }else{
1789a747e4fSDavid du Colombier t = malloc(n);
1799a747e4fSDavid du Colombier if(t == nil)
1809a747e4fSDavid du Colombier panic("kstrdup: no memory");
1819a747e4fSDavid du Colombier }
1829a747e4fSDavid du Colombier memmove(t, s, n);
1839a747e4fSDavid du Colombier prev = *p;
1849a747e4fSDavid du Colombier *p = t;
1859a747e4fSDavid du Colombier free(prev);
1869a747e4fSDavid du Colombier }
1879a747e4fSDavid du Colombier
188aeee3693SDavid du Colombier static int debugstart = 1;
189b4124be8SDavid du Colombier
1903e12c5d1SDavid du Colombier void
chandevreset(void)1913e12c5d1SDavid du Colombier chandevreset(void)
1923e12c5d1SDavid du Colombier {
1933e12c5d1SDavid du Colombier int i;
1943e12c5d1SDavid du Colombier
195922818baSDavid du Colombier todinit(); /* avoid later reentry causing infinite recursion */
196b4124be8SDavid du Colombier debugstart = getconf("*debugstart") != nil;
197b4124be8SDavid du Colombier if(debugstart)
198b4124be8SDavid du Colombier iprint("reset:");
199b4124be8SDavid du Colombier for(i=0; devtab[i] != nil; i++) {
200b4124be8SDavid du Colombier if(debugstart)
201b4124be8SDavid du Colombier iprint(" %s", devtab[i]->name);
2027dd7cddfSDavid du Colombier devtab[i]->reset();
2033e12c5d1SDavid du Colombier }
204b4124be8SDavid du Colombier if(debugstart)
205b4124be8SDavid du Colombier iprint("\n");
206b4124be8SDavid du Colombier }
2073e12c5d1SDavid du Colombier
2083e12c5d1SDavid du Colombier void
chandevinit(void)2093e12c5d1SDavid du Colombier chandevinit(void)
2103e12c5d1SDavid du Colombier {
2113e12c5d1SDavid du Colombier int i;
2123e12c5d1SDavid du Colombier
213b4124be8SDavid du Colombier if(debugstart)
214b4124be8SDavid du Colombier iprint("init:");
215b4124be8SDavid du Colombier for(i=0; devtab[i] != nil; i++) {
216b4124be8SDavid du Colombier if(debugstart)
217b4124be8SDavid du Colombier iprint(" %s", devtab[i]->name);
2187dd7cddfSDavid du Colombier devtab[i]->init();
2193e12c5d1SDavid du Colombier }
220b4124be8SDavid du Colombier if(debugstart)
221b4124be8SDavid du Colombier iprint("\n");
222b4124be8SDavid du Colombier }
2233e12c5d1SDavid du Colombier
2249a747e4fSDavid du Colombier void
chandevshutdown(void)2259a747e4fSDavid du Colombier chandevshutdown(void)
2269a747e4fSDavid du Colombier {
2279a747e4fSDavid du Colombier int i;
2289a747e4fSDavid du Colombier
2299a747e4fSDavid du Colombier /* shutdown in reverse order */
2309a747e4fSDavid du Colombier for(i=0; devtab[i] != nil; i++)
2319a747e4fSDavid du Colombier ;
2329a747e4fSDavid du Colombier for(i--; i >= 0; i--)
2339a747e4fSDavid du Colombier devtab[i]->shutdown();
2349a747e4fSDavid du Colombier }
2359a747e4fSDavid du Colombier
2363e12c5d1SDavid du Colombier Chan*
newchan(void)2373e12c5d1SDavid du Colombier newchan(void)
2383e12c5d1SDavid du Colombier {
2393e12c5d1SDavid du Colombier Chan *c;
2403e12c5d1SDavid du Colombier
2413e12c5d1SDavid du Colombier lock(&chanalloc);
2423e12c5d1SDavid du Colombier c = chanalloc.free;
2437dd7cddfSDavid du Colombier if(c != 0)
2443e12c5d1SDavid du Colombier chanalloc.free = c->next;
2453e12c5d1SDavid du Colombier unlock(&chanalloc);
2463e12c5d1SDavid du Colombier
2479a747e4fSDavid du Colombier if(c == nil){
2483e12c5d1SDavid du Colombier c = smalloc(sizeof(Chan));
2497dd7cddfSDavid du Colombier lock(&chanalloc);
2507dd7cddfSDavid du Colombier c->fid = ++chanalloc.fid;
2517dd7cddfSDavid du Colombier c->link = chanalloc.list;
2527dd7cddfSDavid du Colombier chanalloc.list = c;
2537dd7cddfSDavid du Colombier unlock(&chanalloc);
2543e12c5d1SDavid du Colombier }
2553e12c5d1SDavid du Colombier
2563e12c5d1SDavid du Colombier /* if you get an error before associating with a dev,
2573e12c5d1SDavid du Colombier close calls rootclose, a nop */
2583e12c5d1SDavid du Colombier c->type = 0;
2593e12c5d1SDavid du Colombier c->flag = 0;
2603e12c5d1SDavid du Colombier c->ref = 1;
2613e12c5d1SDavid du Colombier c->dev = 0;
2623e12c5d1SDavid du Colombier c->offset = 0;
263dc5a79c1SDavid du Colombier c->devoffset = 0;
2649a747e4fSDavid du Colombier c->iounit = 0;
2659a747e4fSDavid du Colombier c->umh = 0;
2667dd7cddfSDavid du Colombier c->uri = 0;
2679a747e4fSDavid du Colombier c->dri = 0;
2683e12c5d1SDavid du Colombier c->aux = 0;
2693e12c5d1SDavid du Colombier c->mchan = 0;
2707dd7cddfSDavid du Colombier c->mcp = 0;
2719a747e4fSDavid du Colombier c->mux = 0;
2729a747e4fSDavid du Colombier memset(&c->mqid, 0, sizeof(c->mqid));
2734afe124fSDavid du Colombier c->path = 0;
274dc5a79c1SDavid du Colombier c->ismtpt = 0;
2754afe124fSDavid du Colombier
2763e12c5d1SDavid du Colombier return c;
2773e12c5d1SDavid du Colombier }
2783e12c5d1SDavid du Colombier
2794afe124fSDavid du Colombier Ref npath;
2807dd7cddfSDavid du Colombier
2814afe124fSDavid du Colombier Path*
newpath(char * s)2824afe124fSDavid du Colombier newpath(char *s)
2837dd7cddfSDavid du Colombier {
2847dd7cddfSDavid du Colombier int i;
2854afe124fSDavid du Colombier Path *p;
2867dd7cddfSDavid du Colombier
2874afe124fSDavid du Colombier p = smalloc(sizeof(Path));
2887dd7cddfSDavid du Colombier i = strlen(s);
2894afe124fSDavid du Colombier p->len = i;
2904afe124fSDavid du Colombier p->alen = i+PATHSLOP;
2914afe124fSDavid du Colombier p->s = smalloc(p->alen);
2924afe124fSDavid du Colombier memmove(p->s, s, i+1);
2934afe124fSDavid du Colombier p->ref = 1;
2944afe124fSDavid du Colombier incref(&npath);
2954afe124fSDavid du Colombier
2964afe124fSDavid du Colombier /*
2974afe124fSDavid du Colombier * Cannot use newpath for arbitrary names because the mtpt
2984afe124fSDavid du Colombier * array will not be populated correctly. The names #/ and / are
2994afe124fSDavid du Colombier * allowed, but other names with / in them draw warnings.
3004afe124fSDavid du Colombier */
3014afe124fSDavid du Colombier if(strchr(s, '/') && strcmp(s, "#/") != 0 && strcmp(s, "/") != 0)
302567483c8SDavid du Colombier print("newpath: %s from %#p\n", s, getcallerpc(&s));
3034afe124fSDavid du Colombier
3044afe124fSDavid du Colombier p->mlen = 1;
3054afe124fSDavid du Colombier p->malen = PATHMSLOP;
3064afe124fSDavid du Colombier p->mtpt = smalloc(p->malen*sizeof p->mtpt[0]);
3074afe124fSDavid du Colombier return p;
3084afe124fSDavid du Colombier }
3094afe124fSDavid du Colombier
3104afe124fSDavid du Colombier static Path*
copypath(Path * p)3114afe124fSDavid du Colombier copypath(Path *p)
3124afe124fSDavid du Colombier {
3134afe124fSDavid du Colombier int i;
3144afe124fSDavid du Colombier Path *pp;
3154afe124fSDavid du Colombier
3164afe124fSDavid du Colombier pp = smalloc(sizeof(Path));
3174afe124fSDavid du Colombier pp->ref = 1;
3184afe124fSDavid du Colombier incref(&npath);
3194afe124fSDavid du Colombier DBG("copypath %s %p => %p\n", p->s, p, pp);
3204afe124fSDavid du Colombier
3214afe124fSDavid du Colombier pp->len = p->len;
3224afe124fSDavid du Colombier pp->alen = p->alen;
3234afe124fSDavid du Colombier pp->s = smalloc(p->alen);
3244afe124fSDavid du Colombier memmove(pp->s, p->s, p->len+1);
3254afe124fSDavid du Colombier
3264afe124fSDavid du Colombier pp->mlen = p->mlen;
3274afe124fSDavid du Colombier pp->malen = p->malen;
3284afe124fSDavid du Colombier pp->mtpt = smalloc(p->malen*sizeof pp->mtpt[0]);
3294afe124fSDavid du Colombier for(i=0; i<pp->mlen; i++){
3304afe124fSDavid du Colombier pp->mtpt[i] = p->mtpt[i];
3314afe124fSDavid du Colombier if(pp->mtpt[i])
3324afe124fSDavid du Colombier incref(pp->mtpt[i]);
3334afe124fSDavid du Colombier }
3344afe124fSDavid du Colombier
3354afe124fSDavid du Colombier return pp;
3367dd7cddfSDavid du Colombier }
3377dd7cddfSDavid du Colombier
3387dd7cddfSDavid du Colombier void
pathclose(Path * p)3394afe124fSDavid du Colombier pathclose(Path *p)
3407dd7cddfSDavid du Colombier {
3414afe124fSDavid du Colombier int i;
3424afe124fSDavid du Colombier
3434afe124fSDavid du Colombier if(p == nil)
3447dd7cddfSDavid du Colombier return;
3454afe124fSDavid du Colombier //XXX
3464afe124fSDavid du Colombier DBG("pathclose %p %s ref=%ld =>", p, p->s, p->ref);
3474afe124fSDavid du Colombier for(i=0; i<p->mlen; i++)
3484afe124fSDavid du Colombier DBG(" %p", p->mtpt[i]);
3494afe124fSDavid du Colombier DBG("\n");
3504afe124fSDavid du Colombier
3514afe124fSDavid du Colombier if(decref(p))
3527dd7cddfSDavid du Colombier return;
3534afe124fSDavid du Colombier decref(&npath);
3544afe124fSDavid du Colombier free(p->s);
3554afe124fSDavid du Colombier for(i=0; i<p->mlen; i++)
3564afe124fSDavid du Colombier if(p->mtpt[i])
3574afe124fSDavid du Colombier cclose(p->mtpt[i]);
3584afe124fSDavid du Colombier free(p->mtpt);
3594afe124fSDavid du Colombier free(p);
3607dd7cddfSDavid du Colombier }
3617dd7cddfSDavid du Colombier
3624afe124fSDavid du Colombier /*
3634afe124fSDavid du Colombier * In place, rewrite name to compress multiple /, eliminate ., and process ..
3644afe124fSDavid du Colombier * (Really only called to remove a trailing .. that has been added.
3654afe124fSDavid du Colombier * Otherwise would need to update n->mtpt as well.)
3664afe124fSDavid du Colombier */
3674afe124fSDavid du Colombier static void
fixdotdotname(Path * p)3684afe124fSDavid du Colombier fixdotdotname(Path *p)
3697dd7cddfSDavid du Colombier {
3704afe124fSDavid du Colombier char *r;
3714afe124fSDavid du Colombier
3724afe124fSDavid du Colombier if(p->s[0] == '#'){
3734afe124fSDavid du Colombier r = strchr(p->s, '/');
3744afe124fSDavid du Colombier if(r == nil)
3754afe124fSDavid du Colombier return;
3764afe124fSDavid du Colombier cleanname(r);
3774afe124fSDavid du Colombier
3784afe124fSDavid du Colombier /*
3794afe124fSDavid du Colombier * The correct name is #i rather than #i/,
3804afe124fSDavid du Colombier * but the correct name of #/ is #/.
3814afe124fSDavid du Colombier */
3824afe124fSDavid du Colombier if(strcmp(r, "/")==0 && p->s[1] != '/')
3834afe124fSDavid du Colombier *r = '\0';
3844afe124fSDavid du Colombier }else
3854afe124fSDavid du Colombier cleanname(p->s);
3864afe124fSDavid du Colombier p->len = strlen(p->s);
3874afe124fSDavid du Colombier }
3884afe124fSDavid du Colombier
3894afe124fSDavid du Colombier static Path*
uniquepath(Path * p)3904afe124fSDavid du Colombier uniquepath(Path *p)
3914afe124fSDavid du Colombier {
3924afe124fSDavid du Colombier Path *new;
3934afe124fSDavid du Colombier
3944afe124fSDavid du Colombier if(p->ref > 1){
3954afe124fSDavid du Colombier /* copy on write */
3964afe124fSDavid du Colombier new = copypath(p);
3974afe124fSDavid du Colombier pathclose(p);
3984afe124fSDavid du Colombier p = new;
3994afe124fSDavid du Colombier }
4004afe124fSDavid du Colombier return p;
4014afe124fSDavid du Colombier }
4024afe124fSDavid du Colombier
4034afe124fSDavid du Colombier static Path*
addelem(Path * p,char * s,Chan * from)4044afe124fSDavid du Colombier addelem(Path *p, char *s, Chan *from)
4054afe124fSDavid du Colombier {
4067dd7cddfSDavid du Colombier char *t;
4074afe124fSDavid du Colombier int a, i;
4084afe124fSDavid du Colombier Chan *c, **tt;
4097dd7cddfSDavid du Colombier
4109a747e4fSDavid du Colombier if(s[0]=='.' && s[1]=='\0')
4114afe124fSDavid du Colombier return p;
4129a747e4fSDavid du Colombier
4134afe124fSDavid du Colombier p = uniquepath(p);
4147dd7cddfSDavid du Colombier
4157dd7cddfSDavid du Colombier i = strlen(s);
4164afe124fSDavid du Colombier if(p->len+1+i+1 > p->alen){
4174afe124fSDavid du Colombier a = p->len+1+i+1 + PATHSLOP;
4187dd7cddfSDavid du Colombier t = smalloc(a);
4194afe124fSDavid du Colombier memmove(t, p->s, p->len+1);
4204afe124fSDavid du Colombier free(p->s);
4214afe124fSDavid du Colombier p->s = t;
4224afe124fSDavid du Colombier p->alen = a;
4237dd7cddfSDavid du Colombier }
4244afe124fSDavid du Colombier /* don't insert extra slash if one is present */
4254afe124fSDavid du Colombier if(p->len>0 && p->s[p->len-1]!='/' && s[0]!='/')
4264afe124fSDavid du Colombier p->s[p->len++] = '/';
4274afe124fSDavid du Colombier memmove(p->s+p->len, s, i+1);
4284afe124fSDavid du Colombier p->len += i;
4294afe124fSDavid du Colombier if(isdotdot(s)){
4304afe124fSDavid du Colombier fixdotdotname(p);
4314afe124fSDavid du Colombier DBG("addelem %s .. => rm %p\n", p->s, p->mtpt[p->mlen-1]);
4321fa40b8eSDavid du Colombier if(p->mlen>1 && (c = p->mtpt[--p->mlen])){
4334afe124fSDavid du Colombier p->mtpt[p->mlen] = nil;
4344afe124fSDavid du Colombier cclose(c);
4354afe124fSDavid du Colombier }
4364afe124fSDavid du Colombier }else{
4374afe124fSDavid du Colombier if(p->mlen >= p->malen){
4384afe124fSDavid du Colombier p->malen = p->mlen+1+PATHMSLOP;
4394afe124fSDavid du Colombier tt = smalloc(p->malen*sizeof tt[0]);
4404afe124fSDavid du Colombier memmove(tt, p->mtpt, p->mlen*sizeof tt[0]);
4414afe124fSDavid du Colombier free(p->mtpt);
4424afe124fSDavid du Colombier p->mtpt = tt;
4434afe124fSDavid du Colombier }
4444afe124fSDavid du Colombier DBG("addelem %s %s => add %p\n", p->s, s, from);
4454afe124fSDavid du Colombier p->mtpt[p->mlen++] = from;
4464afe124fSDavid du Colombier if(from)
4474afe124fSDavid du Colombier incref(from);
4484afe124fSDavid du Colombier }
4494afe124fSDavid du Colombier return p;
4507dd7cddfSDavid du Colombier }
4517dd7cddfSDavid du Colombier
4523e12c5d1SDavid du Colombier void
chanfree(Chan * c)4533e12c5d1SDavid du Colombier chanfree(Chan *c)
4543e12c5d1SDavid du Colombier {
4553e12c5d1SDavid du Colombier c->flag = CFREE;
4567dd7cddfSDavid du Colombier
457dc5a79c1SDavid du Colombier if(c->dirrock != nil){
458dc5a79c1SDavid du Colombier free(c->dirrock);
459dc5a79c1SDavid du Colombier c->dirrock = 0;
460dc5a79c1SDavid du Colombier c->nrock = 0;
461dc5a79c1SDavid du Colombier c->mrock = 0;
462dc5a79c1SDavid du Colombier }
4639a747e4fSDavid du Colombier if(c->umh != nil){
4649a747e4fSDavid du Colombier putmhead(c->umh);
4659a747e4fSDavid du Colombier c->umh = nil;
466219b2ee8SDavid du Colombier }
4679a747e4fSDavid du Colombier if(c->umc != nil){
4689a747e4fSDavid du Colombier cclose(c->umc);
4699a747e4fSDavid du Colombier c->umc = nil;
4709a747e4fSDavid du Colombier }
4719a747e4fSDavid du Colombier if(c->mux != nil){
4729a747e4fSDavid du Colombier muxclose(c->mux);
4739a747e4fSDavid du Colombier c->mux = nil;
4749a747e4fSDavid du Colombier }
4759a747e4fSDavid du Colombier if(c->mchan != nil){
4769a747e4fSDavid du Colombier cclose(c->mchan);
4779a747e4fSDavid du Colombier c->mchan = nil;
4787dd7cddfSDavid du Colombier }
4797dd7cddfSDavid du Colombier
4804afe124fSDavid du Colombier pathclose(c->path);
4814afe124fSDavid du Colombier c->path = nil;
4827dd7cddfSDavid du Colombier
4833e12c5d1SDavid du Colombier lock(&chanalloc);
4843e12c5d1SDavid du Colombier c->next = chanalloc.free;
4853e12c5d1SDavid du Colombier chanalloc.free = c;
4863e12c5d1SDavid du Colombier unlock(&chanalloc);
4873e12c5d1SDavid du Colombier }
4883e12c5d1SDavid du Colombier
4893e12c5d1SDavid du Colombier void
cclose(Chan * c)4907dd7cddfSDavid du Colombier cclose(Chan *c)
4913e12c5d1SDavid du Colombier {
4923e12c5d1SDavid du Colombier if(c->flag&CFREE)
493567483c8SDavid du Colombier panic("cclose %#p", getcallerpc(&c));
4949a747e4fSDavid du Colombier
4954afe124fSDavid du Colombier DBG("cclose %p name=%s ref=%ld\n", c, c->path->s, c->ref);
4967dd7cddfSDavid du Colombier if(decref(c))
4977dd7cddfSDavid du Colombier return;
4983e12c5d1SDavid du Colombier
4993e12c5d1SDavid du Colombier if(!waserror()){
5007dd7cddfSDavid du Colombier devtab[c->type]->close(c);
5013e12c5d1SDavid du Colombier poperror();
5023e12c5d1SDavid du Colombier }
5033e12c5d1SDavid du Colombier chanfree(c);
5043e12c5d1SDavid du Colombier }
5053e12c5d1SDavid du Colombier
5069a747e4fSDavid du Colombier /*
5072cca75a1SDavid du Colombier * Queue a chan to be closed by one of the clunk procs.
5082cca75a1SDavid du Colombier */
5092cca75a1SDavid du Colombier struct {
5102cca75a1SDavid du Colombier Chan *head;
5112cca75a1SDavid du Colombier Chan *tail;
5122cca75a1SDavid du Colombier int nqueued;
5132cca75a1SDavid du Colombier int nclosed;
5142cca75a1SDavid du Colombier Lock l;
5152cca75a1SDavid du Colombier QLock q;
5162cca75a1SDavid du Colombier Rendez r;
5172cca75a1SDavid du Colombier } clunkq;
5182cca75a1SDavid du Colombier void closeproc(void*);
5192cca75a1SDavid du Colombier
5202cca75a1SDavid du Colombier void
ccloseq(Chan * c)5212cca75a1SDavid du Colombier ccloseq(Chan *c)
5222cca75a1SDavid du Colombier {
5232cca75a1SDavid du Colombier if(c->flag&CFREE)
524567483c8SDavid du Colombier panic("cclose %#p", getcallerpc(&c));
5252cca75a1SDavid du Colombier
5262cca75a1SDavid du Colombier DBG("ccloseq %p name=%s ref=%ld\n", c, c->path->s, c->ref);
5272cca75a1SDavid du Colombier
5282cca75a1SDavid du Colombier if(decref(c))
5292cca75a1SDavid du Colombier return;
5302cca75a1SDavid du Colombier
5312cca75a1SDavid du Colombier lock(&clunkq.l);
5322cca75a1SDavid du Colombier clunkq.nqueued++;
5332cca75a1SDavid du Colombier c->next = nil;
5342cca75a1SDavid du Colombier if(clunkq.head)
5352cca75a1SDavid du Colombier clunkq.tail->next = c;
5362cca75a1SDavid du Colombier else
5372cca75a1SDavid du Colombier clunkq.head = c;
5382cca75a1SDavid du Colombier clunkq.tail = c;
5392cca75a1SDavid du Colombier unlock(&clunkq.l);
5402cca75a1SDavid du Colombier
5412cca75a1SDavid du Colombier if(!wakeup(&clunkq.r))
5422cca75a1SDavid du Colombier kproc("closeproc", closeproc, nil);
5432cca75a1SDavid du Colombier }
5442cca75a1SDavid du Colombier
5452cca75a1SDavid du Colombier static int
clunkwork(void *)5462cca75a1SDavid du Colombier clunkwork(void*)
5472cca75a1SDavid du Colombier {
5482cca75a1SDavid du Colombier return clunkq.head != nil;
5492cca75a1SDavid du Colombier }
5502cca75a1SDavid du Colombier
5512cca75a1SDavid du Colombier void
closeproc(void *)5522cca75a1SDavid du Colombier closeproc(void*)
5532cca75a1SDavid du Colombier {
5542cca75a1SDavid du Colombier Chan *c;
5552cca75a1SDavid du Colombier
5562cca75a1SDavid du Colombier for(;;){
5572cca75a1SDavid du Colombier qlock(&clunkq.q);
5582cca75a1SDavid du Colombier if(clunkq.head == nil){
5592cca75a1SDavid du Colombier if(!waserror()){
5602cca75a1SDavid du Colombier tsleep(&clunkq.r, clunkwork, nil, 5000);
5612cca75a1SDavid du Colombier poperror();
5622cca75a1SDavid du Colombier }
5632cca75a1SDavid du Colombier if(clunkq.head == nil){
5642cca75a1SDavid du Colombier qunlock(&clunkq.q);
5652cca75a1SDavid du Colombier pexit("no work", 1);
5662cca75a1SDavid du Colombier }
5672cca75a1SDavid du Colombier }
5682cca75a1SDavid du Colombier lock(&clunkq.l);
5692cca75a1SDavid du Colombier c = clunkq.head;
5702cca75a1SDavid du Colombier clunkq.head = c->next;
5712cca75a1SDavid du Colombier clunkq.nclosed++;
5722cca75a1SDavid du Colombier unlock(&clunkq.l);
5732cca75a1SDavid du Colombier qunlock(&clunkq.q);
5742cca75a1SDavid du Colombier if(!waserror()){
5752cca75a1SDavid du Colombier devtab[c->type]->close(c);
5762cca75a1SDavid du Colombier poperror();
5772cca75a1SDavid du Colombier }
5782cca75a1SDavid du Colombier chanfree(c);
5792cca75a1SDavid du Colombier }
5802cca75a1SDavid du Colombier }
5812cca75a1SDavid du Colombier
5822cca75a1SDavid du Colombier /*
5839a747e4fSDavid du Colombier * Make sure we have the only copy of c. (Copy on write.)
5849a747e4fSDavid du Colombier */
5859a747e4fSDavid du Colombier Chan*
cunique(Chan * c)5869a747e4fSDavid du Colombier cunique(Chan *c)
5879a747e4fSDavid du Colombier {
5889a747e4fSDavid du Colombier Chan *nc;
5899a747e4fSDavid du Colombier
5909a747e4fSDavid du Colombier if(c->ref != 1){
5919a747e4fSDavid du Colombier nc = cclone(c);
5929a747e4fSDavid du Colombier cclose(c);
5939a747e4fSDavid du Colombier c = nc;
5949a747e4fSDavid du Colombier }
5959a747e4fSDavid du Colombier
5969a747e4fSDavid du Colombier return c;
5979a747e4fSDavid du Colombier }
5989a747e4fSDavid du Colombier
5993e12c5d1SDavid du Colombier int
eqqid(Qid a,Qid b)6003e12c5d1SDavid du Colombier eqqid(Qid a, Qid b)
6013e12c5d1SDavid du Colombier {
6023e12c5d1SDavid du Colombier return a.path==b.path && a.vers==b.vers;
6033e12c5d1SDavid du Colombier }
6043e12c5d1SDavid du Colombier
6053e12c5d1SDavid du Colombier int
eqchan(Chan * a,Chan * b,int skipvers)6064afe124fSDavid du Colombier eqchan(Chan *a, Chan *b, int skipvers)
6073e12c5d1SDavid du Colombier {
6083e12c5d1SDavid du Colombier if(a->qid.path != b->qid.path)
6093e12c5d1SDavid du Colombier return 0;
6104afe124fSDavid du Colombier if(!skipvers && a->qid.vers!=b->qid.vers)
6113e12c5d1SDavid du Colombier return 0;
6123e12c5d1SDavid du Colombier if(a->type != b->type)
6133e12c5d1SDavid du Colombier return 0;
6143e12c5d1SDavid du Colombier if(a->dev != b->dev)
6153e12c5d1SDavid du Colombier return 0;
6163e12c5d1SDavid du Colombier return 1;
6173e12c5d1SDavid du Colombier }
6183e12c5d1SDavid du Colombier
6193e12c5d1SDavid du Colombier int
eqchantdqid(Chan * a,int type,int dev,Qid qid,int skipvers)6204afe124fSDavid du Colombier eqchantdqid(Chan *a, int type, int dev, Qid qid, int skipvers)
6219a747e4fSDavid du Colombier {
6229a747e4fSDavid du Colombier if(a->qid.path != qid.path)
6239a747e4fSDavid du Colombier return 0;
6244afe124fSDavid du Colombier if(!skipvers && a->qid.vers!=qid.vers)
6259a747e4fSDavid du Colombier return 0;
6269a747e4fSDavid du Colombier if(a->type != type)
6279a747e4fSDavid du Colombier return 0;
6289a747e4fSDavid du Colombier if(a->dev != dev)
6299a747e4fSDavid du Colombier return 0;
6309a747e4fSDavid du Colombier return 1;
6319a747e4fSDavid du Colombier }
6329a747e4fSDavid du Colombier
6333ff48bf5SDavid du Colombier Mhead*
newmhead(Chan * from)6343ff48bf5SDavid du Colombier newmhead(Chan *from)
6353ff48bf5SDavid du Colombier {
6363ff48bf5SDavid du Colombier Mhead *mh;
6373ff48bf5SDavid du Colombier
6383ff48bf5SDavid du Colombier mh = smalloc(sizeof(Mhead));
6393ff48bf5SDavid du Colombier mh->ref = 1;
6403ff48bf5SDavid du Colombier mh->from = from;
6413ff48bf5SDavid du Colombier incref(from);
6423ff48bf5SDavid du Colombier return mh;
6433ff48bf5SDavid du Colombier }
6443ff48bf5SDavid du Colombier
6459a747e4fSDavid du Colombier int
cmount(Chan ** newp,Chan * old,int flag,char * spec)6469a747e4fSDavid du Colombier cmount(Chan **newp, Chan *old, int flag, char *spec)
6473e12c5d1SDavid du Colombier {
6487dd7cddfSDavid du Colombier int order, flg;
6494afe124fSDavid du Colombier Chan *new;
6509a747e4fSDavid du Colombier Mhead *m, **l, *mh;
6517dd7cddfSDavid du Colombier Mount *nm, *f, *um, **h;
6524afe124fSDavid du Colombier Pgrp *pg;
6533e12c5d1SDavid du Colombier
6549a747e4fSDavid du Colombier if(QTDIR & (old->qid.type^(*newp)->qid.type))
6553e12c5d1SDavid du Colombier error(Emount);
6563e12c5d1SDavid du Colombier
6574afe124fSDavid du Colombier if(old->umh)
658567483c8SDavid du Colombier print("cmount: unexpected umh, caller %#p\n", getcallerpc(&newp));
6599a747e4fSDavid du Colombier
6603e12c5d1SDavid du Colombier order = flag&MORDER;
6613e12c5d1SDavid du Colombier
6629a747e4fSDavid du Colombier if((old->qid.type&QTDIR)==0 && order != MREPL)
6639a747e4fSDavid du Colombier error(Emount);
6649a747e4fSDavid du Colombier
6659a747e4fSDavid du Colombier new = *newp;
6669a747e4fSDavid du Colombier mh = new->umh;
6679a747e4fSDavid du Colombier
6689a747e4fSDavid du Colombier /*
6694afe124fSDavid du Colombier * Not allowed to bind when the old directory is itself a union.
6704afe124fSDavid du Colombier * (Maybe it should be allowed, but I don't see what the semantics
6714afe124fSDavid du Colombier * would be.)
6729a747e4fSDavid du Colombier *
6739a747e4fSDavid du Colombier * We need to check mh->mount->next to tell unions apart from
6749a747e4fSDavid du Colombier * simple mount points, so that things like
6759a747e4fSDavid du Colombier * mount -c fd /root
6769a747e4fSDavid du Colombier * bind -c /root /
6774afe124fSDavid du Colombier * work.
6784afe124fSDavid du Colombier *
6794afe124fSDavid du Colombier * The check of mount->mflag allows things like
6809a747e4fSDavid du Colombier * mount fd /root
6819a747e4fSDavid du Colombier * bind -c /root /
6829a747e4fSDavid du Colombier *
6839a747e4fSDavid du Colombier * This is far more complicated than it should be, but I don't
6844afe124fSDavid du Colombier * see an easier way at the moment.
6859a747e4fSDavid du Colombier */
6869a747e4fSDavid du Colombier if((flag&MCREATE) && mh && mh->mount
6879a747e4fSDavid du Colombier && (mh->mount->next || !(mh->mount->mflag&MCREATE)))
6883e12c5d1SDavid du Colombier error(Emount);
6893e12c5d1SDavid du Colombier
6907dd7cddfSDavid du Colombier pg = up->pgrp;
6913e12c5d1SDavid du Colombier wlock(&pg->ns);
6923e12c5d1SDavid du Colombier
6939a747e4fSDavid du Colombier l = &MOUNTH(pg, old->qid);
6943e12c5d1SDavid du Colombier for(m = *l; m; m = m->hash){
6953e12c5d1SDavid du Colombier if(eqchan(m->from, old, 1))
6963e12c5d1SDavid du Colombier break;
6973e12c5d1SDavid du Colombier l = &m->hash;
6983e12c5d1SDavid du Colombier }
6993e12c5d1SDavid du Colombier
7009a747e4fSDavid du Colombier if(m == nil){
7017dd7cddfSDavid du Colombier /*
7027dd7cddfSDavid du Colombier * nothing mounted here yet. create a mount
7037dd7cddfSDavid du Colombier * head and add to the hash table.
7047dd7cddfSDavid du Colombier */
7053ff48bf5SDavid du Colombier m = newmhead(old);
7063e12c5d1SDavid du Colombier *l = m;
7077dd7cddfSDavid du Colombier
7087dd7cddfSDavid du Colombier /*
7097dd7cddfSDavid du Colombier * if this is a union mount, add the old
7107dd7cddfSDavid du Colombier * node to the mount chain.
7117dd7cddfSDavid du Colombier */
7123e12c5d1SDavid du Colombier if(order != MREPL)
7137dd7cddfSDavid du Colombier m->mount = newmount(m, old, 0, 0);
7147dd7cddfSDavid du Colombier }
7157dd7cddfSDavid du Colombier wlock(&m->lock);
7167dd7cddfSDavid du Colombier if(waserror()){
7177dd7cddfSDavid du Colombier wunlock(&m->lock);
7187dd7cddfSDavid du Colombier nexterror();
7197dd7cddfSDavid du Colombier }
7207dd7cddfSDavid du Colombier wunlock(&pg->ns);
7217dd7cddfSDavid du Colombier
7227dd7cddfSDavid du Colombier nm = newmount(m, new, flag, spec);
7239a747e4fSDavid du Colombier if(mh != nil && mh->mount != nil){
7247dd7cddfSDavid du Colombier /*
7257dd7cddfSDavid du Colombier * copy a union when binding it onto a directory
7267dd7cddfSDavid du Colombier */
7277dd7cddfSDavid du Colombier flg = order;
7287dd7cddfSDavid du Colombier if(order == MREPL)
7297dd7cddfSDavid du Colombier flg = MAFTER;
7307dd7cddfSDavid du Colombier h = &nm->next;
7319a747e4fSDavid du Colombier um = mh->mount;
7327dd7cddfSDavid du Colombier for(um = um->next; um; um = um->next){
7337dd7cddfSDavid du Colombier f = newmount(m, um->to, flg, um->spec);
7347dd7cddfSDavid du Colombier *h = f;
7357dd7cddfSDavid du Colombier h = &f->next;
7367dd7cddfSDavid du Colombier }
7373e12c5d1SDavid du Colombier }
7383e12c5d1SDavid du Colombier
7393e12c5d1SDavid du Colombier if(m->mount && order == MREPL){
7403e12c5d1SDavid du Colombier mountfree(m->mount);
7413e12c5d1SDavid du Colombier m->mount = 0;
7423e12c5d1SDavid du Colombier }
7433e12c5d1SDavid du Colombier
7443e12c5d1SDavid du Colombier if(flag & MCREATE)
7459a747e4fSDavid du Colombier nm->mflag |= MCREATE;
7463e12c5d1SDavid du Colombier
7473e12c5d1SDavid du Colombier if(m->mount && order == MAFTER){
7483e12c5d1SDavid du Colombier for(f = m->mount; f->next; f = f->next)
7493e12c5d1SDavid du Colombier ;
7503e12c5d1SDavid du Colombier f->next = nm;
7514afe124fSDavid du Colombier }else{
7527dd7cddfSDavid du Colombier for(f = nm; f->next; f = f->next)
7537dd7cddfSDavid du Colombier ;
7547dd7cddfSDavid du Colombier f->next = m->mount;
7553e12c5d1SDavid du Colombier m->mount = nm;
7563e12c5d1SDavid du Colombier }
7573e12c5d1SDavid du Colombier
7587dd7cddfSDavid du Colombier wunlock(&m->lock);
7593e12c5d1SDavid du Colombier poperror();
7603e12c5d1SDavid du Colombier return nm->mountid;
7613e12c5d1SDavid du Colombier }
7623e12c5d1SDavid du Colombier
7633e12c5d1SDavid du Colombier void
cunmount(Chan * mnt,Chan * mounted)7647dd7cddfSDavid du Colombier cunmount(Chan *mnt, Chan *mounted)
7653e12c5d1SDavid du Colombier {
7663e12c5d1SDavid du Colombier Pgrp *pg;
7673e12c5d1SDavid du Colombier Mhead *m, **l;
7683e12c5d1SDavid du Colombier Mount *f, **p;
7693e12c5d1SDavid du Colombier
7709a747e4fSDavid du Colombier if(mnt->umh) /* should not happen */
7719a747e4fSDavid du Colombier print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh);
7729a747e4fSDavid du Colombier
7739a747e4fSDavid du Colombier /*
7749a747e4fSDavid du Colombier * It _can_ happen that mounted->umh is non-nil,
7759a747e4fSDavid du Colombier * because mounted is the result of namec(Aopen)
7769a747e4fSDavid du Colombier * (see sysfile.c:/^sysunmount).
7779a747e4fSDavid du Colombier * If we open a union directory, it will have a umh.
7789a747e4fSDavid du Colombier * Although surprising, this is okay, since the
7799a747e4fSDavid du Colombier * cclose will take care of freeing the umh.
7809a747e4fSDavid du Colombier */
7819a747e4fSDavid du Colombier
7827dd7cddfSDavid du Colombier pg = up->pgrp;
7833e12c5d1SDavid du Colombier wlock(&pg->ns);
7843e12c5d1SDavid du Colombier
7859a747e4fSDavid du Colombier l = &MOUNTH(pg, mnt->qid);
7863e12c5d1SDavid du Colombier for(m = *l; m; m = m->hash){
7873e12c5d1SDavid du Colombier if(eqchan(m->from, mnt, 1))
7883e12c5d1SDavid du Colombier break;
7893e12c5d1SDavid du Colombier l = &m->hash;
7903e12c5d1SDavid du Colombier }
7913e12c5d1SDavid du Colombier
7923e12c5d1SDavid du Colombier if(m == 0){
7933e12c5d1SDavid du Colombier wunlock(&pg->ns);
7943e12c5d1SDavid du Colombier error(Eunmount);
7953e12c5d1SDavid du Colombier }
7963e12c5d1SDavid du Colombier
7977dd7cddfSDavid du Colombier wlock(&m->lock);
7983e12c5d1SDavid du Colombier if(mounted == 0){
7993e12c5d1SDavid du Colombier *l = m->hash;
8003e12c5d1SDavid du Colombier wunlock(&pg->ns);
8013e12c5d1SDavid du Colombier mountfree(m->mount);
8027dd7cddfSDavid du Colombier m->mount = nil;
8037dd7cddfSDavid du Colombier cclose(m->from);
8047dd7cddfSDavid du Colombier wunlock(&m->lock);
8057dd7cddfSDavid du Colombier putmhead(m);
8063e12c5d1SDavid du Colombier return;
8073e12c5d1SDavid du Colombier }
8083e12c5d1SDavid du Colombier
8093e12c5d1SDavid du Colombier p = &m->mount;
8103e12c5d1SDavid du Colombier for(f = *p; f; f = f->next){
8117dd7cddfSDavid du Colombier /* BUG: Needs to be 2 pass */
8127dd7cddfSDavid du Colombier if(eqchan(f->to, mounted, 1) ||
8137dd7cddfSDavid du Colombier (f->to->mchan && eqchan(f->to->mchan, mounted, 1))){
8143e12c5d1SDavid du Colombier *p = f->next;
8153e12c5d1SDavid du Colombier f->next = 0;
8163e12c5d1SDavid du Colombier mountfree(f);
8177dd7cddfSDavid du Colombier if(m->mount == nil){
8183e12c5d1SDavid du Colombier *l = m->hash;
8197dd7cddfSDavid du Colombier cclose(m->from);
8207dd7cddfSDavid du Colombier wunlock(&m->lock);
8213ff48bf5SDavid du Colombier wunlock(&pg->ns);
8227dd7cddfSDavid du Colombier putmhead(m);
8233e12c5d1SDavid du Colombier return;
8243e12c5d1SDavid du Colombier }
8257dd7cddfSDavid du Colombier wunlock(&m->lock);
8263ff48bf5SDavid du Colombier wunlock(&pg->ns);
8273e12c5d1SDavid du Colombier return;
8283e12c5d1SDavid du Colombier }
8293e12c5d1SDavid du Colombier p = &f->next;
8303e12c5d1SDavid du Colombier }
8317dd7cddfSDavid du Colombier wunlock(&m->lock);
8323ff48bf5SDavid du Colombier wunlock(&pg->ns);
8333e12c5d1SDavid du Colombier error(Eunion);
8343e12c5d1SDavid du Colombier }
8353e12c5d1SDavid du Colombier
8363e12c5d1SDavid du Colombier Chan*
cclone(Chan * c)8379a747e4fSDavid du Colombier cclone(Chan *c)
8383e12c5d1SDavid du Colombier {
8399a747e4fSDavid du Colombier Chan *nc;
8409a747e4fSDavid du Colombier Walkqid *wq;
8419a747e4fSDavid du Colombier
8429a747e4fSDavid du Colombier wq = devtab[c->type]->walk(c, nil, nil, 0);
8439a747e4fSDavid du Colombier if(wq == nil)
8449a747e4fSDavid du Colombier error("clone failed");
8459a747e4fSDavid du Colombier nc = wq->clone;
8469a747e4fSDavid du Colombier free(wq);
8474afe124fSDavid du Colombier nc->path = c->path;
8484afe124fSDavid du Colombier if(c->path)
8494afe124fSDavid du Colombier incref(c->path);
8507dd7cddfSDavid du Colombier return nc;
8513e12c5d1SDavid du Colombier }
8523e12c5d1SDavid du Colombier
8534afe124fSDavid du Colombier /* also used by sysfile.c:/^mountfix */
8549a747e4fSDavid du Colombier int
findmount(Chan ** cp,Mhead ** mp,int type,int dev,Qid qid)8559a747e4fSDavid du Colombier findmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid)
8563e12c5d1SDavid du Colombier {
8573e12c5d1SDavid du Colombier Pgrp *pg;
8583e12c5d1SDavid du Colombier Mhead *m;
8593e12c5d1SDavid du Colombier
8607dd7cddfSDavid du Colombier pg = up->pgrp;
8613e12c5d1SDavid du Colombier rlock(&pg->ns);
8629a747e4fSDavid du Colombier for(m = MOUNTH(pg, qid); m; m = m->hash){
8637dd7cddfSDavid du Colombier rlock(&m->lock);
8649a747e4fSDavid du Colombier if(m->from == nil){
8659a747e4fSDavid du Colombier print("m %p m->from 0\n", m);
8667dd7cddfSDavid du Colombier runlock(&m->lock);
8679a747e4fSDavid du Colombier continue;
8683e12c5d1SDavid du Colombier }
8699a747e4fSDavid du Colombier if(eqchantdqid(m->from, type, dev, qid, 1)){
8707dd7cddfSDavid du Colombier runlock(&pg->ns);
8719a747e4fSDavid du Colombier if(mp != nil){
8727dd7cddfSDavid du Colombier incref(m);
8739a747e4fSDavid du Colombier if(*mp != nil)
8749a747e4fSDavid du Colombier putmhead(*mp);
8759a747e4fSDavid du Colombier *mp = m;
8769a747e4fSDavid du Colombier }
8779a747e4fSDavid du Colombier if(*cp != nil)
8789a747e4fSDavid du Colombier cclose(*cp);
8799a747e4fSDavid du Colombier incref(m->mount->to);
8809a747e4fSDavid du Colombier *cp = m->mount->to;
8817dd7cddfSDavid du Colombier runlock(&m->lock);
8829a747e4fSDavid du Colombier return 1;
8837dd7cddfSDavid du Colombier }
8847dd7cddfSDavid du Colombier runlock(&m->lock);
8853e12c5d1SDavid du Colombier }
8863e12c5d1SDavid du Colombier
8873e12c5d1SDavid du Colombier runlock(&pg->ns);
8889a747e4fSDavid du Colombier return 0;
8899a747e4fSDavid du Colombier }
8909a747e4fSDavid du Colombier
8914afe124fSDavid du Colombier /*
8924afe124fSDavid du Colombier * Calls findmount but also updates path.
8934afe124fSDavid du Colombier */
8944afe124fSDavid du Colombier static int
domount(Chan ** cp,Mhead ** mp,Path ** path)8954afe124fSDavid du Colombier domount(Chan **cp, Mhead **mp, Path **path)
8969a747e4fSDavid du Colombier {
8974afe124fSDavid du Colombier Chan **lc;
8984afe124fSDavid du Colombier Path *p;
8994afe124fSDavid du Colombier
9004afe124fSDavid du Colombier if(findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid) == 0)
9014afe124fSDavid du Colombier return 0;
9024afe124fSDavid du Colombier
9034afe124fSDavid du Colombier if(path){
9044afe124fSDavid du Colombier p = *path;
9054afe124fSDavid du Colombier p = uniquepath(p);
9064afe124fSDavid du Colombier if(p->mlen <= 0)
9074afe124fSDavid du Colombier print("domount: path %s has mlen==%d\n", p->s, p->mlen);
9084afe124fSDavid du Colombier else{
9094afe124fSDavid du Colombier lc = &p->mtpt[p->mlen-1];
9104afe124fSDavid du Colombier DBG("domount %p %s => add %p (was %p)\n", p, p->s, (*mp)->from, p->mtpt[p->mlen-1]);
9114afe124fSDavid du Colombier incref((*mp)->from);
9124afe124fSDavid du Colombier if(*lc)
9134afe124fSDavid du Colombier cclose(*lc);
9144afe124fSDavid du Colombier *lc = (*mp)->from;
9154afe124fSDavid du Colombier }
9164afe124fSDavid du Colombier *path = p;
9174afe124fSDavid du Colombier }
9184afe124fSDavid du Colombier return 1;
9193e12c5d1SDavid du Colombier }
9203e12c5d1SDavid du Colombier
9214afe124fSDavid du Colombier /*
9224afe124fSDavid du Colombier * If c is the right-hand-side of a mount point, returns the left hand side.
9234afe124fSDavid du Colombier * Changes name to reflect the fact that we've uncrossed the mountpoint,
9244afe124fSDavid du Colombier * so name had better be ours to change!
9254afe124fSDavid du Colombier */
9264afe124fSDavid du Colombier static Chan*
undomount(Chan * c,Path * path)9274afe124fSDavid du Colombier undomount(Chan *c, Path *path)
9283e12c5d1SDavid du Colombier {
9297dd7cddfSDavid du Colombier Chan *nc;
9303e12c5d1SDavid du Colombier
9314afe124fSDavid du Colombier if(path->ref != 1 || path->mlen == 0)
932567483c8SDavid du Colombier print("undomount: path %s ref %ld mlen %d caller %#p\n",
9334afe124fSDavid du Colombier path->s, path->ref, path->mlen, getcallerpc(&c));
9343e12c5d1SDavid du Colombier
9354afe124fSDavid du Colombier if(path->mlen>0 && (nc=path->mtpt[path->mlen-1]) != nil){
9364afe124fSDavid du Colombier DBG("undomount %p %s => remove %p\n", path, path->s, nc);
9377dd7cddfSDavid du Colombier cclose(c);
9384afe124fSDavid du Colombier path->mtpt[path->mlen-1] = nil;
9397dd7cddfSDavid du Colombier c = nc;
9403e12c5d1SDavid du Colombier }
9413e12c5d1SDavid du Colombier return c;
9423e12c5d1SDavid du Colombier }
9433e12c5d1SDavid du Colombier
9449a747e4fSDavid du Colombier /*
9454afe124fSDavid du Colombier * Call dev walk but catch errors.
9468b6d9ba0SDavid du Colombier */
9478b6d9ba0SDavid du Colombier static Walkqid*
ewalk(Chan * c,Chan * nc,char ** name,int nname)9488b6d9ba0SDavid du Colombier ewalk(Chan *c, Chan *nc, char **name, int nname)
9498b6d9ba0SDavid du Colombier {
9508b6d9ba0SDavid du Colombier Walkqid *wq;
9518b6d9ba0SDavid du Colombier
9528b6d9ba0SDavid du Colombier if(waserror())
9538b6d9ba0SDavid du Colombier return nil;
9548b6d9ba0SDavid du Colombier wq = devtab[c->type]->walk(c, nc, name, nname);
9558b6d9ba0SDavid du Colombier poperror();
9568b6d9ba0SDavid du Colombier return wq;
9578b6d9ba0SDavid du Colombier }
9588b6d9ba0SDavid du Colombier
9598b6d9ba0SDavid du Colombier /*
9609a747e4fSDavid du Colombier * Either walks all the way or not at all. No partial results in *cp.
9619a747e4fSDavid du Colombier * *nerror is the number of names to display in an error message.
9629a747e4fSDavid du Colombier */
9639a747e4fSDavid du Colombier static char Edoesnotexist[] = "does not exist";
9647dd7cddfSDavid du Colombier int
walk(Chan ** cp,char ** names,int nnames,int nomount,int * nerror)9659a747e4fSDavid du Colombier walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
9667dd7cddfSDavid du Colombier {
967c716ae23SDavid du Colombier int dev, didmount, dotdot, i, n, nhave, ntry, type;
9684afe124fSDavid du Colombier Chan *c, *nc, *mtpt;
9694afe124fSDavid du Colombier Path *path;
9709a747e4fSDavid du Colombier Mhead *mh, *nmh;
9714afe124fSDavid du Colombier Mount *f;
9729a747e4fSDavid du Colombier Walkqid *wq;
9733e12c5d1SDavid du Colombier
9749a747e4fSDavid du Colombier c = *cp;
9759a747e4fSDavid du Colombier incref(c);
9764afe124fSDavid du Colombier path = c->path;
9774afe124fSDavid du Colombier incref(path);
9789a747e4fSDavid du Colombier mh = nil;
9797dd7cddfSDavid du Colombier
9809a747e4fSDavid du Colombier /*
9819a747e4fSDavid du Colombier * While we haven't gotten all the way down the path:
9829a747e4fSDavid du Colombier * 1. step through a mount point, if any
9839a747e4fSDavid du Colombier * 2. send a walk request for initial dotdot or initial prefix without dotdot
9849a747e4fSDavid du Colombier * 3. move to the first mountpoint along the way.
9859a747e4fSDavid du Colombier * 4. repeat.
9869a747e4fSDavid du Colombier *
987c716ae23SDavid du Colombier * Each time through the loop:
988c716ae23SDavid du Colombier *
989c716ae23SDavid du Colombier * If didmount==0, c is on the undomount side of the mount point.
990c716ae23SDavid du Colombier * If didmount==1, c is on the domount side of the mount point.
991c716ae23SDavid du Colombier * Either way, c's full path is path.
9929a747e4fSDavid du Colombier */
993c716ae23SDavid du Colombier didmount = 0;
9949a747e4fSDavid du Colombier for(nhave=0; nhave<nnames; nhave+=n){
9959a747e4fSDavid du Colombier if((c->qid.type&QTDIR)==0){
9969a747e4fSDavid du Colombier if(nerror)
9979a747e4fSDavid du Colombier *nerror = nhave;
9984afe124fSDavid du Colombier pathclose(path);
9999a747e4fSDavid du Colombier cclose(c);
10009a747e4fSDavid du Colombier strcpy(up->errstr, Enotdir);
10013ff48bf5SDavid du Colombier if(mh != nil)
10023ff48bf5SDavid du Colombier putmhead(mh);
10039a747e4fSDavid du Colombier return -1;
10049a747e4fSDavid du Colombier }
10059a747e4fSDavid du Colombier ntry = nnames - nhave;
10069a747e4fSDavid du Colombier if(ntry > MAXWELEM)
10079a747e4fSDavid du Colombier ntry = MAXWELEM;
10083e12c5d1SDavid du Colombier dotdot = 0;
10099a747e4fSDavid du Colombier for(i=0; i<ntry; i++){
10109a747e4fSDavid du Colombier if(isdotdot(names[nhave+i])){
10119a747e4fSDavid du Colombier if(i==0){
10123e12c5d1SDavid du Colombier dotdot = 1;
10139a747e4fSDavid du Colombier ntry = 1;
10149a747e4fSDavid du Colombier }else
10159a747e4fSDavid du Colombier ntry = i;
10163e12c5d1SDavid du Colombier break;
10179a747e4fSDavid du Colombier }
10189a747e4fSDavid du Colombier }
10199a747e4fSDavid du Colombier
1020c716ae23SDavid du Colombier if(!dotdot && !nomount && !didmount)
10214afe124fSDavid du Colombier domount(&c, &mh, &path);
10229a747e4fSDavid du Colombier
10239a747e4fSDavid du Colombier type = c->type;
10249a747e4fSDavid du Colombier dev = c->dev;
10259a747e4fSDavid du Colombier
10268b6d9ba0SDavid du Colombier if((wq = ewalk(c, nil, names+nhave, ntry)) == nil){
10279a747e4fSDavid du Colombier /* try a union mount, if any */
10289a747e4fSDavid du Colombier if(mh && !nomount){
10299a747e4fSDavid du Colombier /*
1030dc5a79c1SDavid du Colombier * mh->mount->to == c, so start at mh->mount->next
10319a747e4fSDavid du Colombier */
10329a747e4fSDavid du Colombier rlock(&mh->lock);
1033d584e620SDavid du Colombier f = mh->mount;
1034d584e620SDavid du Colombier for(f = (f? f->next: f); f; f = f->next)
10358b6d9ba0SDavid du Colombier if((wq = ewalk(f->to, nil, names+nhave, ntry)) != nil)
10369a747e4fSDavid du Colombier break;
10379a747e4fSDavid du Colombier runlock(&mh->lock);
10389a747e4fSDavid du Colombier if(f != nil){
10399a747e4fSDavid du Colombier type = f->to->type;
10409a747e4fSDavid du Colombier dev = f->to->dev;
10419a747e4fSDavid du Colombier }
10429a747e4fSDavid du Colombier }
10439a747e4fSDavid du Colombier if(wq == nil){
10447dd7cddfSDavid du Colombier cclose(c);
10454afe124fSDavid du Colombier pathclose(path);
10469a747e4fSDavid du Colombier if(nerror)
10479a747e4fSDavid du Colombier *nerror = nhave+1;
10483ff48bf5SDavid du Colombier if(mh != nil)
10493ff48bf5SDavid du Colombier putmhead(mh);
10507dd7cddfSDavid du Colombier return -1;
10519a747e4fSDavid du Colombier }
10523e12c5d1SDavid du Colombier }
10537dd7cddfSDavid du Colombier
1054c716ae23SDavid du Colombier didmount = 0;
10559a747e4fSDavid du Colombier if(dotdot){
10569a747e4fSDavid du Colombier assert(wq->nqid == 1);
10579a747e4fSDavid du Colombier assert(wq->clone != nil);
10587dd7cddfSDavid du Colombier
10594afe124fSDavid du Colombier path = addelem(path, "..", nil);
10604afe124fSDavid du Colombier nc = undomount(wq->clone, path);
1061c716ae23SDavid du Colombier nmh = nil;
10629a747e4fSDavid du Colombier n = 1;
10639a747e4fSDavid du Colombier }else{
10649a747e4fSDavid du Colombier nc = nil;
10654afe124fSDavid du Colombier nmh = nil;
1066c716ae23SDavid du Colombier if(!nomount){
1067c716ae23SDavid du Colombier for(i=0; i<wq->nqid && i<ntry-1; i++){
1068c716ae23SDavid du Colombier if(findmount(&nc, &nmh, type, dev, wq->qid[i])){
1069c716ae23SDavid du Colombier didmount = 1;
10709a747e4fSDavid du Colombier break;
1071c716ae23SDavid du Colombier }
1072c716ae23SDavid du Colombier }
1073c716ae23SDavid du Colombier }
10749a747e4fSDavid du Colombier if(nc == nil){ /* no mount points along path */
10759a747e4fSDavid du Colombier if(wq->clone == nil){
10769a747e4fSDavid du Colombier cclose(c);
10774afe124fSDavid du Colombier pathclose(path);
10789a747e4fSDavid du Colombier if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){
10799a747e4fSDavid du Colombier if(nerror)
10809a747e4fSDavid du Colombier *nerror = nhave+wq->nqid+1;
10819a747e4fSDavid du Colombier strcpy(up->errstr, Edoesnotexist);
10829a747e4fSDavid du Colombier }else{
10839a747e4fSDavid du Colombier if(nerror)
10849a747e4fSDavid du Colombier *nerror = nhave+wq->nqid;
10859a747e4fSDavid du Colombier strcpy(up->errstr, Enotdir);
10869a747e4fSDavid du Colombier }
10879a747e4fSDavid du Colombier free(wq);
10883ff48bf5SDavid du Colombier if(mh != nil)
10893ff48bf5SDavid du Colombier putmhead(mh);
10909a747e4fSDavid du Colombier return -1;
10919a747e4fSDavid du Colombier }
10929a747e4fSDavid du Colombier n = wq->nqid;
10939a747e4fSDavid du Colombier nc = wq->clone;
10949a747e4fSDavid du Colombier }else{ /* stopped early, at a mount point */
1095c716ae23SDavid du Colombier didmount = 1;
10969a747e4fSDavid du Colombier if(wq->clone != nil){
10979a747e4fSDavid du Colombier cclose(wq->clone);
10989a747e4fSDavid du Colombier wq->clone = nil;
10999a747e4fSDavid du Colombier }
11009a747e4fSDavid du Colombier n = i+1;
11019a747e4fSDavid du Colombier }
11024afe124fSDavid du Colombier for(i=0; i<n; i++){
11034afe124fSDavid du Colombier mtpt = nil;
11044afe124fSDavid du Colombier if(i==n-1 && nmh)
11054afe124fSDavid du Colombier mtpt = nmh->from;
11064afe124fSDavid du Colombier path = addelem(path, names[nhave+i], mtpt);
11074afe124fSDavid du Colombier }
11089a747e4fSDavid du Colombier }
11099a747e4fSDavid du Colombier cclose(c);
11109a747e4fSDavid du Colombier c = nc;
11119a747e4fSDavid du Colombier putmhead(mh);
11129a747e4fSDavid du Colombier mh = nmh;
11139a747e4fSDavid du Colombier free(wq);
11149a747e4fSDavid du Colombier }
11159a747e4fSDavid du Colombier
11169a747e4fSDavid du Colombier putmhead(mh);
11179a747e4fSDavid du Colombier
11189a747e4fSDavid du Colombier c = cunique(c);
11199a747e4fSDavid du Colombier
11209a747e4fSDavid du Colombier if(c->umh != nil){ //BUG
11219a747e4fSDavid du Colombier print("walk umh\n");
11229a747e4fSDavid du Colombier putmhead(c->umh);
11239a747e4fSDavid du Colombier c->umh = nil;
11249a747e4fSDavid du Colombier }
11259a747e4fSDavid du Colombier
11264afe124fSDavid du Colombier pathclose(c->path);
11274afe124fSDavid du Colombier c->path = path;
11289a747e4fSDavid du Colombier
11299a747e4fSDavid du Colombier cclose(*cp);
11309a747e4fSDavid du Colombier *cp = c;
11319a747e4fSDavid du Colombier if(nerror)
1132312a1df1SDavid du Colombier *nerror = nhave;
11337dd7cddfSDavid du Colombier return 0;
11343e12c5d1SDavid du Colombier }
11353e12c5d1SDavid du Colombier
11363e12c5d1SDavid du Colombier /*
11373e12c5d1SDavid du Colombier * c is a mounted non-creatable directory. find a creatable one.
11383e12c5d1SDavid du Colombier */
11393e12c5d1SDavid du Colombier Chan*
createdir(Chan * c,Mhead * m)11409a747e4fSDavid du Colombier createdir(Chan *c, Mhead *m)
11413e12c5d1SDavid du Colombier {
11423e12c5d1SDavid du Colombier Chan *nc;
11433e12c5d1SDavid du Colombier Mount *f;
11443e12c5d1SDavid du Colombier
11459a747e4fSDavid du Colombier rlock(&m->lock);
11463e12c5d1SDavid du Colombier if(waserror()){
11479a747e4fSDavid du Colombier runlock(&m->lock);
11483e12c5d1SDavid du Colombier nexterror();
11493e12c5d1SDavid du Colombier }
11509a747e4fSDavid du Colombier for(f = m->mount; f; f = f->next){
11519a747e4fSDavid du Colombier if(f->mflag&MCREATE){
11529a747e4fSDavid du Colombier nc = cclone(f->to);
11539a747e4fSDavid du Colombier runlock(&m->lock);
11543e12c5d1SDavid du Colombier poperror();
11557dd7cddfSDavid du Colombier cclose(c);
11563e12c5d1SDavid du Colombier return nc;
11573e12c5d1SDavid du Colombier }
11583e12c5d1SDavid du Colombier }
11593e12c5d1SDavid du Colombier error(Enocreate);
11607dd7cddfSDavid du Colombier return 0;
11613e12c5d1SDavid du Colombier }
11623e12c5d1SDavid du Colombier
11633e12c5d1SDavid du Colombier void
saveregisters(void)11643e12c5d1SDavid du Colombier saveregisters(void)
11653e12c5d1SDavid du Colombier {
11663e12c5d1SDavid du Colombier }
11673e12c5d1SDavid du Colombier
11689a747e4fSDavid du Colombier static void
growparse(Elemlist * e)11699a747e4fSDavid du Colombier growparse(Elemlist *e)
11709a747e4fSDavid du Colombier {
11719a747e4fSDavid du Colombier char **new;
11729a747e4fSDavid du Colombier int *inew;
11739a747e4fSDavid du Colombier enum { Delta = 8 };
11749a747e4fSDavid du Colombier
11759a747e4fSDavid du Colombier if(e->nelems % Delta == 0){
11769a747e4fSDavid du Colombier new = smalloc((e->nelems+Delta) * sizeof(char*));
11779a747e4fSDavid du Colombier memmove(new, e->elems, e->nelems*sizeof(char*));
11789a747e4fSDavid du Colombier free(e->elems);
11799a747e4fSDavid du Colombier e->elems = new;
11809a747e4fSDavid du Colombier inew = smalloc((e->nelems+Delta+1) * sizeof(int));
11818b6d9ba0SDavid du Colombier memmove(inew, e->off, (e->nelems+1)*sizeof(int));
11829a747e4fSDavid du Colombier free(e->off);
11839a747e4fSDavid du Colombier e->off = inew;
11849a747e4fSDavid du Colombier }
11859a747e4fSDavid du Colombier }
11869a747e4fSDavid du Colombier
11879a747e4fSDavid du Colombier /*
11889a747e4fSDavid du Colombier * The name is known to be valid.
11899a747e4fSDavid du Colombier * Copy the name so slashes can be overwritten.
11909a747e4fSDavid du Colombier * An empty string will set nelem=0.
1191fb7f0c93SDavid du Colombier * A path ending in / or /. or /.//./ etc. will have
1192fb7f0c93SDavid du Colombier * e.mustbedir = 1, so that we correctly
1193fb7f0c93SDavid du Colombier * reject, e.g., "/adm/users/." when /adm/users is a file
1194fb7f0c93SDavid du Colombier * rather than a directory.
11959a747e4fSDavid du Colombier */
11969a747e4fSDavid du Colombier static void
parsename(char * aname,Elemlist * e)11978b6d9ba0SDavid du Colombier parsename(char *aname, Elemlist *e)
11989a747e4fSDavid du Colombier {
11998b6d9ba0SDavid du Colombier char *name, *slash;
12009a747e4fSDavid du Colombier
12018b6d9ba0SDavid du Colombier kstrdup(&e->name, aname);
12029a747e4fSDavid du Colombier name = e->name;
12039a747e4fSDavid du Colombier e->nelems = 0;
12049a747e4fSDavid du Colombier e->elems = nil;
12059a747e4fSDavid du Colombier e->off = smalloc(sizeof(int));
1206fb7f0c93SDavid du Colombier e->off[0] = skipslash(name) - name;
12079a747e4fSDavid du Colombier for(;;){
12089a747e4fSDavid du Colombier name = skipslash(name);
1209fb7f0c93SDavid du Colombier if(*name == '\0'){
12108b6d9ba0SDavid du Colombier e->off[e->nelems] = name+strlen(name) - e->name;
1211fb7f0c93SDavid du Colombier e->mustbedir = 1;
12129a747e4fSDavid du Colombier break;
1213fb7f0c93SDavid du Colombier }
12149a747e4fSDavid du Colombier growparse(e);
12159a747e4fSDavid du Colombier e->elems[e->nelems++] = name;
12169a747e4fSDavid du Colombier slash = utfrune(name, '/');
12179a747e4fSDavid du Colombier if(slash == nil){
12189a747e4fSDavid du Colombier e->off[e->nelems] = name+strlen(name) - e->name;
1219fb7f0c93SDavid du Colombier e->mustbedir = 0;
12209a747e4fSDavid du Colombier break;
12219a747e4fSDavid du Colombier }
12229a747e4fSDavid du Colombier e->off[e->nelems] = slash - e->name;
12239a747e4fSDavid du Colombier *slash++ = '\0';
12249a747e4fSDavid du Colombier name = slash;
12259a747e4fSDavid du Colombier }
12268b6d9ba0SDavid du Colombier
12274afe124fSDavid du Colombier if(0 && chandebug){
12288b6d9ba0SDavid du Colombier int i;
12298b6d9ba0SDavid du Colombier
12308b6d9ba0SDavid du Colombier print("parsename %s:", e->name);
12318b6d9ba0SDavid du Colombier for(i=0; i<=e->nelems; i++)
12328b6d9ba0SDavid du Colombier print(" %d", e->off[i]);
12338b6d9ba0SDavid du Colombier print("\n");
12348b6d9ba0SDavid du Colombier }
12359a747e4fSDavid du Colombier }
12369a747e4fSDavid du Colombier
12379a747e4fSDavid du Colombier void*
memrchr(void * va,int c,long n)12389a747e4fSDavid du Colombier memrchr(void *va, int c, long n)
12399a747e4fSDavid du Colombier {
12409a747e4fSDavid du Colombier uchar *a, *e;
12419a747e4fSDavid du Colombier
12429a747e4fSDavid du Colombier a = va;
12439a747e4fSDavid du Colombier for(e=a+n-1; e>a; e--)
12449a747e4fSDavid du Colombier if(*e == c)
12459a747e4fSDavid du Colombier return e;
12469a747e4fSDavid du Colombier return nil;
12479a747e4fSDavid du Colombier }
12489a747e4fSDavid du Colombier
1249dc5a79c1SDavid du Colombier void
namelenerror(char * aname,int len,char * err)1250312a1df1SDavid du Colombier namelenerror(char *aname, int len, char *err)
1251dc5a79c1SDavid du Colombier {
12528b6d9ba0SDavid du Colombier char *ename, *name, *next;
12538b6d9ba0SDavid du Colombier int i, errlen;
1254dc5a79c1SDavid du Colombier
12558b6d9ba0SDavid du Colombier /*
12568b6d9ba0SDavid du Colombier * If the name is short enough, just use the whole thing.
12578b6d9ba0SDavid du Colombier */
12588b6d9ba0SDavid du Colombier errlen = strlen(err);
12598b6d9ba0SDavid du Colombier if(len < ERRMAX/3 || len+errlen < 2*ERRMAX/3)
12608b6d9ba0SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "%.*s",
12618b6d9ba0SDavid du Colombier utfnlen(aname, len), aname);
12628b6d9ba0SDavid du Colombier else{
12638b6d9ba0SDavid du Colombier /*
12648b6d9ba0SDavid du Colombier * Print a suffix of the name, but try to get a little info.
12658b6d9ba0SDavid du Colombier */
12668b6d9ba0SDavid du Colombier ename = aname+len;
12678b6d9ba0SDavid du Colombier next = ename;
12688b6d9ba0SDavid du Colombier do{
12698b6d9ba0SDavid du Colombier name = next;
12708b6d9ba0SDavid du Colombier next = memrchr(aname, '/', name-aname);
12718b6d9ba0SDavid du Colombier if(next == nil)
12728b6d9ba0SDavid du Colombier next = aname;
12738b6d9ba0SDavid du Colombier len = ename-next;
12748b6d9ba0SDavid du Colombier }while(len < ERRMAX/3 || len + errlen < 2*ERRMAX/3);
12758b6d9ba0SDavid du Colombier
12768b6d9ba0SDavid du Colombier /*
12778b6d9ba0SDavid du Colombier * If the name is ridiculously long, chop it.
12788b6d9ba0SDavid du Colombier */
12798b6d9ba0SDavid du Colombier if(name == ename){
12808b6d9ba0SDavid du Colombier name = ename-ERRMAX/4;
12818b6d9ba0SDavid du Colombier if(name <= aname)
12828b6d9ba0SDavid du Colombier panic("bad math in namelenerror");
12838b6d9ba0SDavid du Colombier /* walk out of current UTF sequence */
1284d584e620SDavid du Colombier for(i=0; (*name&0xC0)==0x80 && i<UTFmax; i++)
12858b6d9ba0SDavid du Colombier name++;
12868b6d9ba0SDavid du Colombier }
12878b6d9ba0SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "...%.*s",
12888b6d9ba0SDavid du Colombier utfnlen(name, ename-name), name);
12898b6d9ba0SDavid du Colombier }
1290312a1df1SDavid du Colombier snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, err);
1291dc5a79c1SDavid du Colombier nexterror();
1292dc5a79c1SDavid du Colombier }
1293dc5a79c1SDavid du Colombier
1294312a1df1SDavid du Colombier void
nameerror(char * name,char * err)1295312a1df1SDavid du Colombier nameerror(char *name, char *err)
1296312a1df1SDavid du Colombier {
1297312a1df1SDavid du Colombier namelenerror(name, strlen(name), err);
1298312a1df1SDavid du Colombier }
1299312a1df1SDavid du Colombier
13007dd7cddfSDavid du Colombier /*
13013e12c5d1SDavid du Colombier * Turn a name into a channel.
13023e12c5d1SDavid du Colombier * &name[0] is known to be a valid address. It may be a kernel address.
13039a747e4fSDavid du Colombier *
1304dc5a79c1SDavid du Colombier * Opening with amode Aopen, Acreate, Aremove, or Aaccess guarantees
13059a747e4fSDavid du Colombier * that the result will be the only reference to that particular fid.
13069a747e4fSDavid du Colombier * This is necessary since we might pass the result to
13079a747e4fSDavid du Colombier * devtab[]->remove().
13089a747e4fSDavid du Colombier *
1309dc5a79c1SDavid du Colombier * Opening Atodir or Amount does not guarantee this.
13109a747e4fSDavid du Colombier *
1311dc5a79c1SDavid du Colombier * Under certain circumstances, opening Aaccess will cause
1312dc5a79c1SDavid du Colombier * an unnecessary clone in order to get a cunique Chan so it
1313dc5a79c1SDavid du Colombier * can attach the correct name. Sysstat and sys_stat need the
1314dc5a79c1SDavid du Colombier * correct name so they can rewrite the stat info.
13153e12c5d1SDavid du Colombier */
13163e12c5d1SDavid du Colombier Chan*
namec(char * aname,int amode,int omode,ulong perm)13179a747e4fSDavid du Colombier namec(char *aname, int amode, int omode, ulong perm)
13183e12c5d1SDavid du Colombier {
13198b6d9ba0SDavid du Colombier int len, n, t, nomount;
13209a747e4fSDavid du Colombier Chan *c, *cnew;
13214afe124fSDavid du Colombier Path *path;
13229a747e4fSDavid du Colombier Elemlist e;
13239a747e4fSDavid du Colombier Rune r;
13249a747e4fSDavid du Colombier Mhead *m;
13259a747e4fSDavid du Colombier char *createerr, tmperrbuf[ERRMAX];
13269a747e4fSDavid du Colombier char *name;
13273e12c5d1SDavid du Colombier
1328312a1df1SDavid du Colombier if(aname[0] == '\0')
13299a747e4fSDavid du Colombier error("empty file name");
1330312a1df1SDavid du Colombier aname = validnamedup(aname, 1);
13312db064f5SDavid du Colombier if(waserror()){
1332312a1df1SDavid du Colombier free(aname);
13332db064f5SDavid du Colombier nexterror();
13342db064f5SDavid du Colombier }
13354afe124fSDavid du Colombier DBG("namec %s %d %d\n", aname, amode, omode);
1336312a1df1SDavid du Colombier name = aname;
13373e12c5d1SDavid du Colombier
13389a747e4fSDavid du Colombier /*
13399a747e4fSDavid du Colombier * Find the starting off point (the current slash, the root of
13409a747e4fSDavid du Colombier * a device tree, or the current dot) as well as the name to
13419a747e4fSDavid du Colombier * evaluate starting there.
13429a747e4fSDavid du Colombier */
13439a747e4fSDavid du Colombier nomount = 0;
13447dd7cddfSDavid du Colombier switch(name[0]){
13457dd7cddfSDavid du Colombier case '/':
13469a747e4fSDavid du Colombier c = up->slash;
13479a747e4fSDavid du Colombier incref(c);
13487dd7cddfSDavid du Colombier break;
13499a747e4fSDavid du Colombier
13507dd7cddfSDavid du Colombier case '#':
13519a747e4fSDavid du Colombier nomount = 1;
13529a747e4fSDavid du Colombier up->genbuf[0] = '\0';
13537dd7cddfSDavid du Colombier n = 0;
13549a747e4fSDavid du Colombier while(*name != '\0' && (*name != '/' || n < 2)){
13559a747e4fSDavid du Colombier if(n >= sizeof(up->genbuf)-1)
13567dd7cddfSDavid du Colombier error(Efilename);
13579a747e4fSDavid du Colombier up->genbuf[n++] = *name++;
13587dd7cddfSDavid du Colombier }
13599a747e4fSDavid du Colombier up->genbuf[n] = '\0';
13607dd7cddfSDavid du Colombier /*
13617dd7cddfSDavid du Colombier * noattach is sandboxing.
13627dd7cddfSDavid du Colombier *
13637dd7cddfSDavid du Colombier * the OK exceptions are:
13647dd7cddfSDavid du Colombier * | it only gives access to pipes you create
13657dd7cddfSDavid du Colombier * d this process's file descriptors
13667dd7cddfSDavid du Colombier * e this process's environment
13677dd7cddfSDavid du Colombier * the iffy exceptions are:
13687dd7cddfSDavid du Colombier * c time and pid, but also cons and consctl
13697dd7cddfSDavid du Colombier * p control of your own processes (and unfortunately
13707dd7cddfSDavid du Colombier * any others left unprotected)
13717dd7cddfSDavid du Colombier */
13729a747e4fSDavid du Colombier n = chartorune(&r, up->genbuf+1)+1;
13737dd7cddfSDavid du Colombier /* actually / is caught by parsing earlier */
13747dd7cddfSDavid du Colombier if(utfrune("M", r))
13757dd7cddfSDavid du Colombier error(Enoattach);
137680ee5cbfSDavid du Colombier if(up->pgrp->noattach && utfrune("|decp", r)==nil)
13777dd7cddfSDavid du Colombier error(Enoattach);
1378bd389b36SDavid du Colombier t = devno(r, 1);
13793e12c5d1SDavid du Colombier if(t == -1)
13803e12c5d1SDavid du Colombier error(Ebadsharp);
1381aeee3693SDavid du Colombier if(debugstart && !devtab[t]->attached)
1382*70b6ec21SDavid du Colombier print("#%C...", devtab[t]->dc);
13839a747e4fSDavid du Colombier c = devtab[t]->attach(up->genbuf+n);
1384aeee3693SDavid du Colombier if(debugstart && c != nil)
1385aeee3693SDavid du Colombier devtab[t]->attached = 1;
13869a747e4fSDavid du Colombier break;
13877dd7cddfSDavid du Colombier
13889a747e4fSDavid du Colombier default:
13899a747e4fSDavid du Colombier c = up->dot;
13909a747e4fSDavid du Colombier incref(c);
13917dd7cddfSDavid du Colombier break;
13923e12c5d1SDavid du Colombier }
13933e12c5d1SDavid du Colombier
1394312a1df1SDavid du Colombier e.aname = aname;
13958b6d9ba0SDavid du Colombier e.prefix = name - aname;
13969a747e4fSDavid du Colombier e.name = nil;
13979a747e4fSDavid du Colombier e.elems = nil;
13989a747e4fSDavid du Colombier e.off = nil;
13999a747e4fSDavid du Colombier e.nelems = 0;
1400312a1df1SDavid du Colombier e.nerror = 0;
14013e12c5d1SDavid du Colombier if(waserror()){
14027dd7cddfSDavid du Colombier cclose(c);
14039a747e4fSDavid du Colombier free(e.name);
14049a747e4fSDavid du Colombier free(e.elems);
1405312a1df1SDavid du Colombier /*
1406312a1df1SDavid du Colombier * Prepare nice error, showing first e.nerror elements of name.
1407312a1df1SDavid du Colombier */
1408312a1df1SDavid du Colombier if(e.nerror == 0)
14093e12c5d1SDavid du Colombier nexterror();
1410312a1df1SDavid du Colombier strcpy(tmperrbuf, up->errstr);
14118b6d9ba0SDavid du Colombier if(e.off[e.nerror]==0)
14128b6d9ba0SDavid du Colombier print("nerror=%d but off=%d\n",
14138b6d9ba0SDavid du Colombier e.nerror, e.off[e.nerror]);
14144afe124fSDavid du Colombier if(0 && chandebug)
14158b6d9ba0SDavid du Colombier print("showing %d+%d/%d (of %d) of %s (%d %d)\n", e.prefix, e.off[e.nerror], e.nerror, e.nelems, aname, e.off[0], e.off[1]);
14168b6d9ba0SDavid du Colombier len = e.prefix+e.off[e.nerror];
14178b6d9ba0SDavid du Colombier free(e.off);
14188b6d9ba0SDavid du Colombier namelenerror(aname, len, tmperrbuf);
14193e12c5d1SDavid du Colombier }
14203e12c5d1SDavid du Colombier
14219a747e4fSDavid du Colombier /*
14224afe124fSDavid du Colombier * Build a list of elements in the name.
14239a747e4fSDavid du Colombier */
14249a747e4fSDavid du Colombier parsename(name, &e);
14253e12c5d1SDavid du Colombier
14263e12c5d1SDavid du Colombier /*
1427fb7f0c93SDavid du Colombier * On create, ....
14283e12c5d1SDavid du Colombier */
14299a747e4fSDavid du Colombier if(amode == Acreate){
1430fb7f0c93SDavid du Colombier /* perm must have DMDIR if last element is / or /. */
1431fb7f0c93SDavid du Colombier if(e.mustbedir && !(perm&DMDIR)){
1432312a1df1SDavid du Colombier e.nerror = e.nelems;
1433312a1df1SDavid du Colombier error("create without DMDIR");
1434fb7f0c93SDavid du Colombier }
1435fb7f0c93SDavid du Colombier
1436fb7f0c93SDavid du Colombier /* don't try to walk the last path element just yet. */
14379a747e4fSDavid du Colombier if(e.nelems == 0)
1438fb7f0c93SDavid du Colombier error(Eexist);
14399a747e4fSDavid du Colombier e.nelems--;
14409a747e4fSDavid du Colombier }
14413e12c5d1SDavid du Colombier
1442312a1df1SDavid du Colombier if(walk(&c, e.elems, e.nelems, nomount, &e.nerror) < 0){
1443312a1df1SDavid du Colombier if(e.nerror < 0 || e.nerror > e.nelems){
1444312a1df1SDavid du Colombier print("namec %s walk error nerror=%d\n", aname, e.nerror);
1445312a1df1SDavid du Colombier e.nerror = 0;
1446312a1df1SDavid du Colombier }
14479a747e4fSDavid du Colombier nexterror();
14489a747e4fSDavid du Colombier }
14493e12c5d1SDavid du Colombier
1450312a1df1SDavid du Colombier if(e.mustbedir && !(c->qid.type&QTDIR))
1451312a1df1SDavid du Colombier error("not a directory");
1452fb7f0c93SDavid du Colombier
1453312a1df1SDavid du Colombier if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR))
1454fb7f0c93SDavid du Colombier error("cannot exec directory");
1455fb7f0c93SDavid du Colombier
14563e12c5d1SDavid du Colombier switch(amode){
14579a747e4fSDavid du Colombier case Abind:
14584afe124fSDavid du Colombier /* no need to maintain path - cannot dotdot an Abind */
14599a747e4fSDavid du Colombier m = nil;
14609a747e4fSDavid du Colombier if(!nomount)
14614afe124fSDavid du Colombier domount(&c, &m, nil);
14623ff48bf5SDavid du Colombier if(c->umh != nil)
14633ff48bf5SDavid du Colombier putmhead(c->umh);
14649a747e4fSDavid du Colombier c->umh = m;
14659a747e4fSDavid du Colombier break;
14669a747e4fSDavid du Colombier
1467dc5a79c1SDavid du Colombier case Aaccess:
14689a747e4fSDavid du Colombier case Aremove:
14699a747e4fSDavid du Colombier case Aopen:
14709a747e4fSDavid du Colombier Open:
14714afe124fSDavid du Colombier /* save&update the name; domount might change c */
14724afe124fSDavid du Colombier path = c->path;
14734afe124fSDavid du Colombier incref(path);
14749a747e4fSDavid du Colombier m = nil;
14759a747e4fSDavid du Colombier if(!nomount)
14764afe124fSDavid du Colombier domount(&c, &m, &path);
14779a747e4fSDavid du Colombier
14789a747e4fSDavid du Colombier /* our own copy to open or remove */
14799a747e4fSDavid du Colombier c = cunique(c);
14809a747e4fSDavid du Colombier
14819a747e4fSDavid du Colombier /* now it's our copy anyway, we can put the name back */
14824afe124fSDavid du Colombier pathclose(c->path);
14834afe124fSDavid du Colombier c->path = path;
14849a747e4fSDavid du Colombier
1485dc5a79c1SDavid du Colombier /* record whether c is on a mount point */
1486dc5a79c1SDavid du Colombier c->ismtpt = m!=nil;
1487dc5a79c1SDavid du Colombier
14889a747e4fSDavid du Colombier switch(amode){
1489dc5a79c1SDavid du Colombier case Aaccess:
14909a747e4fSDavid du Colombier case Aremove:
14919a747e4fSDavid du Colombier putmhead(m);
14929a747e4fSDavid du Colombier break;
14939a747e4fSDavid du Colombier
14949a747e4fSDavid du Colombier case Aopen:
14959a747e4fSDavid du Colombier case Acreate:
14969a747e4fSDavid du Colombier if(c->umh != nil){
14973ff48bf5SDavid du Colombier print("cunique umh Open\n");
14989a747e4fSDavid du Colombier putmhead(c->umh);
14993ff48bf5SDavid du Colombier c->umh = nil;
15009a747e4fSDavid du Colombier }
15019a747e4fSDavid du Colombier /* only save the mount head if it's a multiple element union */
15029a747e4fSDavid du Colombier if(m && m->mount && m->mount->next)
15039a747e4fSDavid du Colombier c->umh = m;
15049a747e4fSDavid du Colombier else
15059a747e4fSDavid du Colombier putmhead(m);
15069a747e4fSDavid du Colombier
15079a747e4fSDavid du Colombier /* save registers else error() in open has wrong value of c saved */
15089a747e4fSDavid du Colombier saveregisters();
15099a747e4fSDavid du Colombier
15109a747e4fSDavid du Colombier if(omode == OEXEC)
15119a747e4fSDavid du Colombier c->flag &= ~CCACHE;
15129a747e4fSDavid du Colombier
15139a747e4fSDavid du Colombier c = devtab[c->type]->open(c, omode&~OCEXEC);
15149a747e4fSDavid du Colombier
15159a747e4fSDavid du Colombier if(omode & OCEXEC)
15169a747e4fSDavid du Colombier c->flag |= CCEXEC;
15179a747e4fSDavid du Colombier if(omode & ORCLOSE)
15189a747e4fSDavid du Colombier c->flag |= CRCLOSE;
15197dd7cddfSDavid du Colombier break;
15203e12c5d1SDavid du Colombier }
15213e12c5d1SDavid du Colombier break;
15223e12c5d1SDavid du Colombier
15233e12c5d1SDavid du Colombier case Atodir:
15243e12c5d1SDavid du Colombier /*
15253e12c5d1SDavid du Colombier * Directories (e.g. for cd) are left before the mount point,
15263e12c5d1SDavid du Colombier * so one may mount on / or . and see the effect.
15273e12c5d1SDavid du Colombier */
15289a747e4fSDavid du Colombier if(!(c->qid.type & QTDIR))
15293e12c5d1SDavid du Colombier error(Enotdir);
15303e12c5d1SDavid du Colombier break;
15313e12c5d1SDavid du Colombier
15323e12c5d1SDavid du Colombier case Amount:
15333e12c5d1SDavid du Colombier /*
15347dd7cddfSDavid du Colombier * When mounting on an already mounted upon directory,
15357dd7cddfSDavid du Colombier * one wants subsequent mounts to be attached to the
15369a747e4fSDavid du Colombier * original directory, not the replacement. Don't domount.
15373e12c5d1SDavid du Colombier */
15383e12c5d1SDavid du Colombier break;
15393e12c5d1SDavid du Colombier
15403e12c5d1SDavid du Colombier case Acreate:
15413e12c5d1SDavid du Colombier /*
15429a747e4fSDavid du Colombier * We've already walked all but the last element.
15439a747e4fSDavid du Colombier * If the last exists, try to open it OTRUNC.
15449a747e4fSDavid du Colombier * If omode&OEXCL is set, just give up.
15453e12c5d1SDavid du Colombier */
15469a747e4fSDavid du Colombier e.nelems++;
1547312a1df1SDavid du Colombier e.nerror++;
15489a747e4fSDavid du Colombier if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){
15499a747e4fSDavid du Colombier if(omode&OEXCL)
15509a747e4fSDavid du Colombier error(Eexist);
15513e12c5d1SDavid du Colombier omode |= OTRUNC;
15523e12c5d1SDavid du Colombier goto Open;
15533e12c5d1SDavid du Colombier }
15543e12c5d1SDavid du Colombier
15553e12c5d1SDavid du Colombier /*
15569a747e4fSDavid du Colombier * The semantics of the create(2) system call are that if the
15579a747e4fSDavid du Colombier * file exists and can be written, it is to be opened with truncation.
15589a747e4fSDavid du Colombier * On the other hand, the create(5) message fails if the file exists.
15599a747e4fSDavid du Colombier * If we get two create(2) calls happening simultaneously,
15609a747e4fSDavid du Colombier * they might both get here and send create(5) messages, but only
15619a747e4fSDavid du Colombier * one of the messages will succeed. To provide the expected create(2)
15629a747e4fSDavid du Colombier * semantics, the call with the failed message needs to try the above
15639a747e4fSDavid du Colombier * walk again, opening for truncation. This correctly solves the
15649a747e4fSDavid du Colombier * create/create race, in the sense that any observable outcome can
15659a747e4fSDavid du Colombier * be explained as one happening before the other.
15669a747e4fSDavid du Colombier * The create/create race is quite common. For example, it happens
15679a747e4fSDavid du Colombier * when two rc subshells simultaneously update the same
15689a747e4fSDavid du Colombier * environment variable.
15699a747e4fSDavid du Colombier *
15709a747e4fSDavid du Colombier * The implementation still admits a create/create/remove race:
15719a747e4fSDavid du Colombier * (A) walk to file, fails
15729a747e4fSDavid du Colombier * (B) walk to file, fails
15739a747e4fSDavid du Colombier * (A) create file, succeeds, returns
15749a747e4fSDavid du Colombier * (B) create file, fails
15759a747e4fSDavid du Colombier * (A) remove file, succeeds, returns
15769a747e4fSDavid du Colombier * (B) walk to file, return failure.
15779a747e4fSDavid du Colombier *
15789a747e4fSDavid du Colombier * This is hardly as common as the create/create race, and is really
15799a747e4fSDavid du Colombier * not too much worse than what might happen if (B) got a hold of a
15809a747e4fSDavid du Colombier * file descriptor and then the file was removed -- either way (B) can't do
15819a747e4fSDavid du Colombier * anything with the result of the create call. So we don't care about this race.
15829a747e4fSDavid du Colombier *
15839a747e4fSDavid du Colombier * Applications that care about more fine-grained decision of the races
15849a747e4fSDavid du Colombier * can use the OEXCL flag to get at the underlying create(5) semantics;
15859a747e4fSDavid du Colombier * by default we provide the common case.
15869a747e4fSDavid du Colombier *
15879a747e4fSDavid du Colombier * We need to stay behind the mount point in case we
15889a747e4fSDavid du Colombier * need to do the first walk again (should the create fail).
15899a747e4fSDavid du Colombier *
15909a747e4fSDavid du Colombier * We also need to cross the mount point and find the directory
15919a747e4fSDavid du Colombier * in the union in which we should be creating.
15929a747e4fSDavid du Colombier *
15939a747e4fSDavid du Colombier * The channel staying behind is c, the one moving forward is cnew.
15943e12c5d1SDavid du Colombier */
15959a747e4fSDavid du Colombier m = nil;
15969a747e4fSDavid du Colombier cnew = nil; /* is this assignment necessary? */
15979a747e4fSDavid du Colombier if(!waserror()){ /* try create */
15989a747e4fSDavid du Colombier if(!nomount && findmount(&cnew, &m, c->type, c->dev, c->qid))
15999a747e4fSDavid du Colombier cnew = createdir(cnew, m);
16009a747e4fSDavid du Colombier else{
16019a747e4fSDavid du Colombier cnew = c;
16029a747e4fSDavid du Colombier incref(cnew);
16033e12c5d1SDavid du Colombier }
16049a747e4fSDavid du Colombier
16059a747e4fSDavid du Colombier /*
16069a747e4fSDavid du Colombier * We need our own copy of the Chan because we're
16079a747e4fSDavid du Colombier * about to send a create, which will move it. Once we have
16089a747e4fSDavid du Colombier * our own copy, we can fix the name, which might be wrong
16099a747e4fSDavid du Colombier * if findmount gave us a new Chan.
16109a747e4fSDavid du Colombier */
16119a747e4fSDavid du Colombier cnew = cunique(cnew);
16124afe124fSDavid du Colombier pathclose(cnew->path);
16134afe124fSDavid du Colombier cnew->path = c->path;
16144afe124fSDavid du Colombier incref(cnew->path);
16159a747e4fSDavid du Colombier
16169a747e4fSDavid du Colombier devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm);
16179a747e4fSDavid du Colombier poperror();
16183e12c5d1SDavid du Colombier if(omode & OCEXEC)
16199a747e4fSDavid du Colombier cnew->flag |= CCEXEC;
16207dd7cddfSDavid du Colombier if(omode & ORCLOSE)
16219a747e4fSDavid du Colombier cnew->flag |= CRCLOSE;
16229a747e4fSDavid du Colombier if(m)
16239a747e4fSDavid du Colombier putmhead(m);
16249a747e4fSDavid du Colombier cclose(c);
16259a747e4fSDavid du Colombier c = cnew;
16264afe124fSDavid du Colombier c->path = addelem(c->path, e.elems[e.nelems-1], nil);
16273e12c5d1SDavid du Colombier break;
16289acf0835SDavid du Colombier }
16299acf0835SDavid du Colombier
16309acf0835SDavid du Colombier /* create failed */
16319a747e4fSDavid du Colombier cclose(cnew);
16329a747e4fSDavid du Colombier if(m)
16339a747e4fSDavid du Colombier putmhead(m);
16349a747e4fSDavid du Colombier if(omode & OEXCL)
16359a747e4fSDavid du Colombier nexterror();
16369a747e4fSDavid du Colombier /* save error */
16379a747e4fSDavid du Colombier createerr = up->errstr;
16389a747e4fSDavid du Colombier up->errstr = tmperrbuf;
16399a747e4fSDavid du Colombier /* note: we depend that walk does not error */
16409a747e4fSDavid du Colombier if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){
16419a747e4fSDavid du Colombier up->errstr = createerr;
16429a747e4fSDavid du Colombier error(createerr); /* report true error */
16439a747e4fSDavid du Colombier }
16449a747e4fSDavid du Colombier up->errstr = createerr;
16459a747e4fSDavid du Colombier omode |= OTRUNC;
16469a747e4fSDavid du Colombier goto Open;
16473e12c5d1SDavid du Colombier
16483e12c5d1SDavid du Colombier default:
16493e12c5d1SDavid du Colombier panic("unknown namec access %d\n", amode);
16503e12c5d1SDavid du Colombier }
16517dd7cddfSDavid du Colombier
16529a747e4fSDavid du Colombier /* place final element in genbuf for e.g. exec */
16539a747e4fSDavid du Colombier if(e.nelems > 0)
16549a747e4fSDavid du Colombier kstrcpy(up->genbuf, e.elems[e.nelems-1], sizeof up->genbuf);
16559a747e4fSDavid du Colombier else
16569a747e4fSDavid du Colombier kstrcpy(up->genbuf, ".", sizeof up->genbuf);
16579a747e4fSDavid du Colombier free(e.name);
16589a747e4fSDavid du Colombier free(e.elems);
16599a747e4fSDavid du Colombier free(e.off);
16602db064f5SDavid du Colombier poperror(); /* e c */
1661a4aabefcSDavid du Colombier free(aname);
1662a4aabefcSDavid du Colombier poperror(); /* aname */
16637dd7cddfSDavid du Colombier
16643e12c5d1SDavid du Colombier return c;
16653e12c5d1SDavid du Colombier }
16663e12c5d1SDavid du Colombier
16673e12c5d1SDavid du Colombier /*
1668fb7f0c93SDavid du Colombier * name is valid. skip leading / and ./ as much as possible
16693e12c5d1SDavid du Colombier */
16703e12c5d1SDavid du Colombier char*
skipslash(char * name)16713e12c5d1SDavid du Colombier skipslash(char *name)
16723e12c5d1SDavid du Colombier {
1673fb7f0c93SDavid du Colombier while(name[0]=='/' || (name[0]=='.' && (name[1]==0 || name[1]=='/')))
16743e12c5d1SDavid du Colombier name++;
16753e12c5d1SDavid du Colombier return name;
16763e12c5d1SDavid du Colombier }
16773e12c5d1SDavid du Colombier
16783e12c5d1SDavid du Colombier char isfrog[256]={
16793e12c5d1SDavid du Colombier /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1,
16803e12c5d1SDavid du Colombier /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1,
16813e12c5d1SDavid du Colombier /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1,
16823e12c5d1SDavid du Colombier /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1,
16833e12c5d1SDavid du Colombier ['/'] 1,
16843e12c5d1SDavid du Colombier [0x7f] 1,
16853e12c5d1SDavid du Colombier };
16863e12c5d1SDavid du Colombier
16873e12c5d1SDavid du Colombier /*
16889a747e4fSDavid du Colombier * Check that the name
16899a747e4fSDavid du Colombier * a) is in valid memory.
16909a747e4fSDavid du Colombier * b) is shorter than 2^16 bytes, so it can fit in a 9P string field.
16919a747e4fSDavid du Colombier * c) contains no frogs.
16929a747e4fSDavid du Colombier * The first byte is known to be addressible by the requester, so the
16939a747e4fSDavid du Colombier * routine works for kernel and user memory both.
16949a747e4fSDavid du Colombier * The parameter slashok flags whether a slash character is an error
16959a747e4fSDavid du Colombier * or a valid character.
16962db064f5SDavid du Colombier *
16972db064f5SDavid du Colombier * The parameter dup flags whether the string should be copied
16982db064f5SDavid du Colombier * out of user space before being scanned the second time.
16992db064f5SDavid du Colombier * (Otherwise a malicious thread could remove the NUL, causing us
17002db064f5SDavid du Colombier * to access unchecked addresses.)
17013e12c5d1SDavid du Colombier */
17022db064f5SDavid du Colombier static char*
validname0(char * aname,int slashok,int dup,ulong pc)17032db064f5SDavid du Colombier validname0(char *aname, int slashok, int dup, ulong pc)
17043e12c5d1SDavid du Colombier {
1705e1a0fcefSDavid du Colombier char *ename, *name, *s;
17062db064f5SDavid du Colombier int c, n;
17073e12c5d1SDavid du Colombier Rune r;
17083e12c5d1SDavid du Colombier
17099a747e4fSDavid du Colombier name = aname;
17104de34a7eSDavid du Colombier if((ulong)name < KZERO){
17112db064f5SDavid du Colombier if(!dup)
1712d584e620SDavid du Colombier print("warning: validname called from %#p with user pointer", pc);
1713e1a0fcefSDavid du Colombier ename = vmemchr(name, 0, (1<<16));
17149a747e4fSDavid du Colombier }else
17159a747e4fSDavid du Colombier ename = memchr(name, 0, (1<<16));
17169a747e4fSDavid du Colombier
17179a747e4fSDavid du Colombier if(ename==nil || ename-name>=(1<<16))
17189a747e4fSDavid du Colombier error("name too long");
17199a747e4fSDavid du Colombier
17202db064f5SDavid du Colombier s = nil;
17212db064f5SDavid du Colombier if(dup){
17222db064f5SDavid du Colombier n = ename-name;
17232db064f5SDavid du Colombier s = smalloc(n+1);
17242db064f5SDavid du Colombier memmove(s, name, n);
17252db064f5SDavid du Colombier s[n] = 0;
17262db064f5SDavid du Colombier aname = s;
17272db064f5SDavid du Colombier name = s;
1728824682f6SDavid du Colombier setmalloctag(s, pc);
17292db064f5SDavid du Colombier }
17302db064f5SDavid du Colombier
17319a747e4fSDavid du Colombier while(*name){
17329a747e4fSDavid du Colombier /* all characters above '~' are ok */
17339a747e4fSDavid du Colombier c = *(uchar*)name;
17349a747e4fSDavid du Colombier if(c >= Runeself)
17359a747e4fSDavid du Colombier name += chartorune(&r, name);
17369a747e4fSDavid du Colombier else{
17379a747e4fSDavid du Colombier if(isfrog[c])
17389a747e4fSDavid du Colombier if(!slashok || c!='/'){
17399a747e4fSDavid du Colombier snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname);
17402db064f5SDavid du Colombier free(s);
17419a747e4fSDavid du Colombier error(up->genbuf);
17429a747e4fSDavid du Colombier }
17439a747e4fSDavid du Colombier name++;
17449a747e4fSDavid du Colombier }
17459a747e4fSDavid du Colombier }
17462db064f5SDavid du Colombier return s;
17472db064f5SDavid du Colombier }
17482db064f5SDavid du Colombier
17492db064f5SDavid du Colombier void
validname(char * aname,int slashok)17502db064f5SDavid du Colombier validname(char *aname, int slashok)
17512db064f5SDavid du Colombier {
17522db064f5SDavid du Colombier validname0(aname, slashok, 0, getcallerpc(&aname));
17532db064f5SDavid du Colombier }
17542db064f5SDavid du Colombier
17552db064f5SDavid du Colombier char*
validnamedup(char * aname,int slashok)17562db064f5SDavid du Colombier validnamedup(char *aname, int slashok)
17572db064f5SDavid du Colombier {
1758824682f6SDavid du Colombier return validname0(aname, slashok, 1, getcallerpc(&aname));
17593e12c5d1SDavid du Colombier }
17603e12c5d1SDavid du Colombier
17613e12c5d1SDavid du Colombier void
isdir(Chan * c)17623e12c5d1SDavid du Colombier isdir(Chan *c)
17633e12c5d1SDavid du Colombier {
17649a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
17653e12c5d1SDavid du Colombier return;
17663e12c5d1SDavid du Colombier error(Enotdir);
17673e12c5d1SDavid du Colombier }
17687dd7cddfSDavid du Colombier
17699a747e4fSDavid du Colombier /*
17709a747e4fSDavid du Colombier * This is necessary because there are many
17719a747e4fSDavid du Colombier * pointers to the top of a given mount list:
17729a747e4fSDavid du Colombier *
17739a747e4fSDavid du Colombier * - the mhead in the namespace hash table
17749a747e4fSDavid du Colombier * - the mhead in chans returned from findmount:
17759a747e4fSDavid du Colombier * used in namec and then by unionread.
17769a747e4fSDavid du Colombier * - the mhead in chans returned from createdir:
17779a747e4fSDavid du Colombier * used in the open/create race protect, which is gone.
17789a747e4fSDavid du Colombier *
17799a747e4fSDavid du Colombier * The RWlock in the Mhead protects the mount list it contains.
17809a747e4fSDavid du Colombier * The mount list is deleted when we cunmount.
17819a747e4fSDavid du Colombier * The RWlock ensures that nothing is using the mount list at that time.
17829a747e4fSDavid du Colombier *
17839a747e4fSDavid du Colombier * It is okay to replace c->mh with whatever you want as
17849a747e4fSDavid du Colombier * long as you are sure you have a unique reference to it.
17859a747e4fSDavid du Colombier *
17869a747e4fSDavid du Colombier * This comment might belong somewhere else.
17879a747e4fSDavid du Colombier */
17887dd7cddfSDavid du Colombier void
putmhead(Mhead * m)17897dd7cddfSDavid du Colombier putmhead(Mhead *m)
17907dd7cddfSDavid du Colombier {
17919a747e4fSDavid du Colombier if(m && decref(m) == 0){
17929a747e4fSDavid du Colombier m->mount = (Mount*)0xCafeBeef;
17937dd7cddfSDavid du Colombier free(m);
17947dd7cddfSDavid du Colombier }
17959a747e4fSDavid du Colombier }
17962cca75a1SDavid du Colombier
1797