Clarifies O_TRUNC warnings
[akaros.git] / kern / src / ns / sysfile.c
index 5479c84..f286fb7 100644 (file)
@@ -49,7 +49,10 @@ newfd(struct chan *c)
                return -1;
        }
        /* VFS hack */
-       i = get_fd(&current->open_files, f->minfd);
+       /* We'd like to ask it to start at f->minfd, but that would require us to
+        * know if we closed anything.  Since we share the FD numbers with the VFS,
+        * there is no way to know that. */
+       i = get_fd(&current->open_files, 0);
        assert(f->fd[i] == 0);
        #if 0 // 9ns style
        /* TODO: use a unique integer allocator */
@@ -99,13 +102,18 @@ fdtochan(struct fgrp *f, int fd, int mode, int chkmnt, int iref)
        if(mode<0 || c->mode==ORDWR)
                return c;
 
-       if((mode&OTRUNC) && c->mode==OREAD) {
+       if ((mode & OTRUNC) && IS_RDONLY(c->mode)) {
                if(iref)
                        cclose(c);
                error(Ebadusefd);
        }
 
+       /* TODO: this is probably wrong.  if you get this from a dev, in the dev's
+        * open, you are probably saving mode directly, without passing it through
+        * openmode. */
        if((mode&~OTRUNC) != c->mode) {
+               warn("Trunc mode issue: mode %o, mode minus trunc %o, chan mode %o\n",
+                    mode, mode & ~OTRUNC, c->mode);
                if(iref)
                        cclose(c);
                error(Ebadusefd);
@@ -127,10 +135,10 @@ kchanio(void *vc, void *buf, int n, int mode)
                return -1;
        }
 
-       if(mode == OREAD)
-               r = devtab[c->type]->read(c, buf, n, c->offset);
+       if (IS_RDONLY(mode))
+               r = devtab[c->type].read(c, buf, n, c->offset);
        else
-               r = devtab[c->type]->write(c, buf, n, c->offset);
+               r = devtab[c->type].write(c, buf, n, c->offset);
 
        spin_lock(&c->lock);
        c->offset += r;
@@ -139,9 +147,14 @@ kchanio(void *vc, void *buf, int n, int mode)
        return r;
 }
 
-int
-openmode(uint32_t o)
+
+int openmode(uint32_t omode)
 {
+#if 0
+    /* this is the old plan9 style.  i think they want to turn exec into read,
+     * and strip off anything higher, and just return the RD/WR style bits.  not
+     * stuff like ORCLOSE.  the lack of OEXCL might be a bug on their part (it's
+     * the only one of their non-RW-related flags that isn't masked out) */
        if(o >= (OTRUNC|OCEXEC|ORCLOSE|OEXEC))
                error(Ebadarg);
        o &= ~(OTRUNC|OCEXEC|ORCLOSE);
@@ -150,6 +163,12 @@ openmode(uint32_t o)
        if(o == OEXEC)
                return OREAD;
        return o;
+#endif
+    /* no error checking (we have a shitload of flags anyway), and we return the
+     * basic access modes (RD/WR/ETC) */
+    if (omode == O_EXEC)
+        return O_RDONLY;
+    return omode & O_ACCMODE;
 }
 
 void
@@ -310,6 +329,7 @@ sysfstat(int fd, uint8_t *buf, int n)
 {
        ERRSTACK(2);
        struct chan *c;
+       struct dir dir9ns;
 
        if (waserror()) {
                poperror();
@@ -321,12 +341,13 @@ sysfstat(int fd, uint8_t *buf, int n)
                cclose(c);
                nexterror();
        }
-       devtab[c->type]->stat(c, buf, n);
+       devtab[c->type].stat(c, (void*)&dir9ns, sizeof(struct dir));
 
        poperror();
        cclose(c);
 
        poperror();
+       convM2kstat((void*)&dir9ns, sizeof(struct dir), (struct kstat*)buf);
        return n;
 }
 
@@ -437,7 +458,7 @@ syspipe(int fd[2])
 
        f = current->fgrp;
 
-       d = devtab[devno('|', 0)];
+       d = &devtab[devno('|', 0)];
        c[0] = namec("#|", Atodir, 0, 0);
        c[1] = 0;
        fd[0] = -1;
@@ -494,7 +515,7 @@ sysfwstat(int fd, uint8_t *buf, int n)
                cclose(c);
                nexterror();
        }
-       n = devtab[c->type]->wstat(c, buf, n);
+       n = devtab[c->type].wstat(c, buf, n);
        poperror();
        cclose(c);
 
@@ -576,7 +597,7 @@ sysmount(int fd, int afd, char *old, int flags, char *spec)
        mntparam.authchan = ac.c;
        mntparam.spec = spec;
        mntparam.flags = flags;
-       c0.c = devtab[devno('M', 0)]->attach(( char *)&mntparam);
+       c0.c = devtab[devno('M', 0)].attach(( char *)&mntparam);
 
        r = bindmount(c0.c, old, flags, spec);
        poperror();
@@ -622,7 +643,7 @@ sysunmount(char *old, char *new)
 }
 
 int
-sysopen(char *path, int mode)
+sysopen(char *path, int vfs_flags)
 {
        ERRSTACK(2);
        int fd;
@@ -633,8 +654,8 @@ sysopen(char *path, int mode)
                return -1;
        }
 
-       openmode(mode);                         /* error check only */
-       c = namec(path, Aopen, mode, 0);
+       openmode(vfs_flags);                         /* error check only */
+       c = namec(path, Aopen, vfs_flags, 0);
        if(waserror()){
                cclose(c);
                nexterror();
@@ -672,10 +693,10 @@ unionread(struct chan *c, void *va, long n)
                        if (!waserror()) { /* discard style */
                                if(c->umc == NULL){
                                        c->umc = cclone(mount->to);
-                                       c->umc = devtab[c->umc->type]->open(c->umc, OREAD);
+                                       c->umc = devtab[c->umc->type].open(c->umc, OREAD);
                                }
        
-                               nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);
+                               nr = devtab[c->umc->type].read(c->umc, va, n, c->umc->offset);
                                if(nr < 0)
                                        nr = 0; /* dev.c can return -1 */
                                c->umc->offset += nr;
@@ -718,7 +739,13 @@ rread(int fd, void *va, long n, int64_t *offp)
        struct chan *c;
        int64_t off;
 
+       /* dirty dirent hack */
+       void *real_va = va;
+       void *buf_for_M = 0;
+       long real_n = n;
+
        if (waserror()) {
+               kfree(buf_for_M);
                poperror();
                return -1;
        }
@@ -733,6 +760,25 @@ rread(int fd, void *va, long n, int64_t *offp)
                error(Etoosmall);
 
        dir = c->qid.type & QTDIR;
+
+       /* dirty kdirent hack: userspace is expecting kdirents, but all of 9ns
+        * produces Ms.  i'm assuming we're only being asked to read a single
+        * dirent, which is usually the case for calls like readdir() (which just
+        * calls read for a single dirent).
+        *
+        * another thing: the chan's offset moves forward by an amount such that a
+        * future read of the chan will give the next dirent.  we also return n,
+        * the amount of reading from the 9ns system.  this is fine, since it is
+        * where we'll pick up next time (off += n, from userspace).  we might need
+        * to put that info in d_off, but it seems to work (and no one wants to
+        * mess with glibc code) */
+       if (dir) {
+               assert(n >= sizeof(struct kdirent));
+               buf_for_M = kmalloc(sizeof(struct dir), KMALLOC_WAIT);
+               va = buf_for_M;
+               n = sizeof(struct dir);
+       }
+
        if(dir && c->umh)
                n = unionread(c, va, n);
        else{
@@ -753,12 +799,18 @@ rread(int fd, void *va, long n, int64_t *offp)
                        }
                        unionrewind(c);
                }
-               n = devtab[c->type]->read(c, va, n, off);
+               n = devtab[c->type].read(c, va, n, off);
                spin_lock(&c->lock);
                c->offset += n;
                spin_unlock(&c->lock);
        }
 
+       /* dirty kdirent hack */
+       if (dir) {
+               convM2kdirent(buf_for_M, sizeof(struct dir), real_va, 0);
+               kfree(buf_for_M);
+       }
+
        poperror();
        cclose(c);
 
@@ -795,7 +847,7 @@ sysremove(char *path)
                cclose(c);
                nexterror();
        }
-       devtab[c->type]->remove(c);
+       devtab[c->type].remove(c);
        /*
         * Remove clunks the fid, but we need to recover the Chan
         * so fake it up.  rootclose() is known to be a nop.
@@ -826,7 +878,7 @@ sysseek(int fd, int64_t off, int whence)
                nexterror();
        }
 
-       if(devtab[c->type]->dc == '|')
+       if(devtab[c->type].dc == '|')
                error(Eisstream);
 
        switch(whence) {
@@ -913,6 +965,7 @@ sysstat(char *path, uint8_t *buf, int n)
 {
        ERRSTACK(2);
        struct chan *c;
+       struct dir dir9ns;
 
        if (waserror()) {
                poperror();
@@ -924,11 +977,12 @@ sysstat(char *path, uint8_t *buf, int n)
                cclose(c);
                nexterror();
        }
-       devtab[c->type]->stat(c, buf, n);
+       devtab[c->type].stat(c, (void*)&dir9ns, sizeof(struct dir));
        poperror();
        cclose(c);
 
        poperror();
+       convM2kstat((void*)&dir9ns, sizeof(struct dir), (struct kstat*)buf);
        return 0;
 }
 
@@ -973,7 +1027,7 @@ rwrite(int fd, void *va, long n, int64_t *offp)
        }
        if(off < 0)
                error(Enegoff);
-       m = devtab[c->type]->write(c, va, n, off);
+       m = devtab[c->type].write(c, va, n, off);
        poperror();
 
        if(offp == NULL && m < n){
@@ -1018,7 +1072,7 @@ syswstat(char *path, uint8_t *buf, int n)
                cclose(c);
                nexterror();
        }
-       n = devtab[c->type]->wstat(c, buf, n);
+       n = devtab[c->type].wstat(c, buf, n);
        poperror();
        cclose(c);
 
@@ -1049,7 +1103,7 @@ chandirstat(struct chan *c)
                        poperror();
                        return NULL;
                }
-               n = devtab[c->type]->stat(c, buf, nd);
+               n = devtab[c->type].stat(c, buf, nd);
                poperror();
                if(n < BIT16SZ){
                        kfree(d);
@@ -1146,10 +1200,10 @@ sysdirfwstat(int fd, struct dir *dir)
 }
 
 static long
-dirpackage(uint8_t *buf, long ts, struct dir **d)
+dirpackage(uint8_t *buf, long ts, struct kdirent **d)
 {
        char *s;
-       long ss, i, n, nn, m;
+       long ss, i, n, nn, m = 0;
 
        *d = NULL;
        if(ts <= 0)
@@ -1171,18 +1225,18 @@ dirpackage(uint8_t *buf, long ts, struct dir **d)
        if(i != ts)
                error("bad directory format");
 
-       *d = kzmalloc(n * sizeof(struct dir) + ss, 0);
+       *d = kzmalloc(n * sizeof(**d) + ss, 0);
        if(*d == NULL)
                error(Enomem);
 
        /*
         * then convert all buffers
         */
-       s = ( char *)*d + n * sizeof(struct dir);
+       s = ( char *)*d + n * sizeof(**d);
        nn = 0;
        for(i = 0; i < ts; i += m){
                m = BIT16SZ + GBIT16(( uint8_t *)&buf[i]);
-               if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
+               if(nn >= n || /*convM2D*/convM2kdirent(&buf[i], m, *d + nn, s) != m){
                        kfree(*d);
                        *d = NULL;
                        error("bad directory entry");
@@ -1195,7 +1249,7 @@ dirpackage(uint8_t *buf, long ts, struct dir **d)
 }
 
 long
-sysdirread(int fd, struct dir **d)
+sysdirread(int fd, struct kdirent **d)
 {
        ERRSTACK(2);
        uint8_t *buf;
@@ -1277,18 +1331,19 @@ void close_9ns_files(struct proc *p, bool only_cloexec)
        }
 }
 
-void print_chaninfo(struct chan *ch)
+void print_chaninfo(struct chan *c)
 {
        char buf[64] = {0};
-#if 0
-FIXME
+       bool has_dev = c->type != -1;
        printk("Chan pathname: %s, Dev: %s, Devinfo: %s\n",
-              "ch->path ? ch->path->s : \"no path",
-              ch->dev ? ch->dev->name: "no dev",
-                  ch->dev ? ch->dev->chaninfo(ch, buf, sizeof(buf)) : "no info");
-       if (!ch->dev)
-               printk("No dev: intermediate chan? qid.path: %p\n", ch->qid.path);
-#endif
+              c->name ? c->name->s : "no cname",
+              has_dev ? devtab[c->type].name : "no dev",
+                  /* TODO: chaninfo op */
+              //has_dev ? devtab[c->type].chaninfo(c, buf, sizeof(buf)) :
+                              "no info");
+       if (!has_dev)
+               printk("No dev: intermediate chan? qid.path: %p\n", c->qid.path);
+       printk("\n");
 }
 
 void print_9ns_files(struct proc *p)