Split namec() into a start point and __namec_from
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 15 Sep 2015 19:10:56 +0000 (15:10 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 28 Sep 2015 19:14:00 +0000 (15:14 -0400)
The first half of namec() figures out which chan we should start from,
whether that's a #device attach point, /, or DOT.  Then the rest does
the actual walk and other stuff.

This splits namec() such that we can eventually call the namec_from for
an implementation of openat().

AFAIK, things like prefix and the difference between name and aname is
mostly for debugging.  In namec(), aname was the original name asked for
(e.g. #root/foo/bar), and name gets advanced up to the path relative to
the starting point (e.g. /foo/bar).

namec_from() is a helper that just calls __namec_from, as if you already
had a real chan and were walking farther down the line (hence the
can_mount).  This should be the essence of an openat.

kern/include/ns.h
kern/src/ns/chan.c

index ce02cdd..b8c4c95 100644 (file)
@@ -755,6 +755,8 @@ uint64_t ms2fastticks(uint32_t);
 void mul64fract(uint64_t *, uint64_t, uint64_t);
 void muxclose(struct mnt *);
 struct chan *namec(char *unused_char_p_t, int unused_int, int, uint32_t);
+struct chan *namec_from(struct chan *c, char *name, int amode, int omode,
+                        uint32_t perm);
 struct chan *newchan(void);
 struct egrp *newegrp(void);
 struct mount *newmount(struct mhead *, struct chan *, int unused_int,
index 3bd93bc..199c061 100644 (file)
@@ -957,94 +957,24 @@ void *memrchr(void *va, int c, long n)
  *
  * Acreatechan will never open. It will do all the tests and return a chan
  * for the directory where an open will succeed.
- */
-struct chan *namec(char *aname, int amode, int omode, uint32_t perm)
+ *
+ * The classic namec() is broken into a front end to get the starting point and
+ * a __namec_from, which does the guts of the lookup.  */
+static struct chan *__namec_from(struct chan *c, char *aname, int amode,
+                                 int omode, uint32_t perm, bool can_mount)
 {
        ERRSTACK(2);
-       int n, prefix, len, t, nomount, npath;
-       struct chan *c, *cnew;
+       int len, npath;
+       struct chan *cnew;
        struct cname *cname;
        Elemlist e;
        struct mhead *m;
        char tmperrbuf[ERRMAX];
        int saved_errno;
-       char *name, *devname, *devspec;
-       bool can_mount = TRUE;
        // Rune r;
 
        static_assert(!(CINTERNAL_FLAGS & CEXTERNAL_FLAGS));
 
-       name = aname;
-       if (name[0] == '\0')
-               error("empty file name");
-       validname(name, 1);
-       /*
-        * Find the starting off point (the current slash, the root of
-        * a device tree, or the current dot) as well as the name to
-        * evaluate starting there.
-        */
-       switch (name[0]) {
-               case '/':
-                       c = current->slash;
-                       if (!c)
-                               panic("no slash!");
-                       chan_incref(c);
-                       break;
-
-               case '#':
-                       can_mount = FALSE;
-                       devname = get_cur_genbuf();
-                       devname[0] = '\0';
-                       n = 0;
-                       name++; /* drop the # */
-                       while ((*name != '\0') && (*name != '/')) {
-                               if (n >= GENBUF_SZ - 1)
-                                       error(Efilename);
-                               devname[n++] = *name++;
-                       }
-                       devname[n] = '\0';
-                       /* for a name #foo.spec, devname = foo\0, devspec = spec\0.
-                        * genbuf contains foo\0spec\0.  for no spec, devspec = \0 */
-                       devspec = strchr(devname, '.');
-                       if (devspec) {
-                               *devspec = '\0';
-                               devspec++;
-                       } else {
-                               devspec = &devname[n];
-                       }
-                       if (!strcmp(devname, "mnt"))
-                               error(Enoattach);
-                       /* TODO: deal with this "nodevs" business. */
-                       #if 0
-                       /*
-                        *  the nodevs exceptions are
-                        *  |  it only gives access to pipes you create
-                        *  e  this process's environment
-                        *  s  private file2chan creation space
-                        *  D private secure sockets name space
-                        *  a private TLS name space
-                        */
-                       if (current->pgrp->nodevs &&
-                               //          (utfrune("|esDa", r) == NULL
-                               ((strchr("|esDa", get_cur_genbuf()[1]) == NULL)
-                                || (get_cur_genbuf()[1] == 's' // || r == 's'
-                                        && get_cur_genbuf()[n] != '\0')))
-                               error(Enoattach);
-                       #endif
-                       t = devno(devname, 1);
-                       if (t == -1)
-                               error("Unknown #device %s (spec %s)", devname, devspec);
-                       c = devtab[t].attach(devspec);
-                       break;
-               default:
-                       c = current->dot;
-                       if (!c)
-                               panic("no dot!");
-                       chan_incref(c);
-                       break;
-       }
-       prefix = name - aname;
-
        e.name = NULL;
        e.elems = NULL;
        e.off = NULL;
@@ -1061,7 +991,7 @@ struct chan *namec(char *aname, int amode, int omode, uint32_t perm)
        /*
         * Build a list of elements in the path.
         */
-       parsename(name, &e);
+       parsename(aname, &e);
 
        /*
         * On create, ....
@@ -1096,7 +1026,7 @@ NameError:
                 * the underlying failure.  implement this if you want the old stuff. */
 #if 0
                strncpy(tmperrbuf, current->errstr, sizeof(tmperrbuf));
-               len = prefix + e.off[npath];
+               len = prefix + e.off[npath]; // prefix was name - aname, the start pt
                if (len < ERRMAX / 3 || (name = memrchr(aname, '/', len)) == NULL
                        || name == aname)
                        snprintf(get_cur_genbuf(), sizeof current->genbuf, "%.*s", len,
@@ -1344,6 +1274,97 @@ Open:
        return c;
 }
 
+struct chan *namec(char *name, int amode, int omode, uint32_t perm)
+{
+       bool can_mount = TRUE;
+       struct chan *c;
+       char *devname, *devspec;
+       int n, devtype;
+
+       if (name[0] == '\0')
+               error("empty file name");
+       validname(name, 1);
+       /*
+        * Find the starting off point (the current slash, the root of
+        * a device tree, or the current dot) as well as the name to
+        * evaluate starting there.
+        */
+       switch (name[0]) {
+               case '/':
+                       c = current->slash;
+                       if (!c)
+                               panic("no slash!");
+                       chan_incref(c);
+                       break;
+
+               case '#':
+                       can_mount = FALSE;
+                       devname = get_cur_genbuf();
+                       devname[0] = '\0';
+                       n = 0;
+                       name++; /* drop the # */
+                       while ((*name != '\0') && (*name != '/')) {
+                               if (n >= GENBUF_SZ - 1)
+                                       error(Efilename);
+                               devname[n++] = *name++;
+                       }
+                       devname[n] = '\0';
+                       /* for a name #foo.spec, devname = foo\0, devspec = spec\0.
+                        * genbuf contains foo\0spec\0.  for no spec, devspec = \0 */
+                       devspec = strchr(devname, '.');
+                       if (devspec) {
+                               *devspec = '\0';
+                               devspec++;
+                       } else {
+                               devspec = &devname[n];
+                       }
+                       if (!strcmp(devname, "mnt"))
+                               error(Enoattach);
+                       /* TODO: deal with this "nodevs" business. */
+                       #if 0
+                       /*
+                        *  the nodevs exceptions are
+                        *  |  it only gives access to pipes you create
+                        *  e  this process's environment
+                        *  s  private file2chan creation space
+                        *  D private secure sockets name space
+                        *  a private TLS name space
+                        */
+                       if (current->pgrp->nodevs &&
+                               //          (utfrune("|esDa", r) == NULL
+                               ((strchr("|esDa", get_cur_genbuf()[1]) == NULL)
+                                || (get_cur_genbuf()[1] == 's' // || r == 's'
+                                        && get_cur_genbuf()[n] != '\0')))
+                               error(Enoattach);
+                       #endif
+                       devtype = devno(devname, 1);
+                       if (devtype == -1)
+                               error("Unknown #device %s (spec %s)", devname, devspec);
+                       c = devtab[devtype].attach(devspec);
+                       break;
+               default:
+                       /* this case also covers \0 */
+                       c = current->dot;
+                       if (!c)
+                               panic("no dot!");
+                       chan_incref(c);
+                       break;
+       }
+       return __namec_from(c, name, amode, omode, perm, can_mount);
+}
+
+struct chan *namec_from(struct chan *c, char *name, int amode, int omode,
+                        uint32_t perm)
+{
+       if (name[0] == '\0') {
+               /* Our responsibility to cclose 'c' on our error */
+               cclose(c);
+               error("empty file name");
+       }
+       validname(name, 1);
+       return __namec_from(c, name, amode, omode, perm, TRUE);
+}
+
 /*
  * name is valid. skip leading / and ./ as much as possible
  */