sys_stat() and friends
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 10 Aug 2010 00:27:16 +0000 (17:27 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:50 +0000 (17:35 -0700)
Not heavily tested, and the numbers are not necessarily "right."  The
syscall accurately reports the values in the inode, but some of them are
neither set properly xnor kept up to date.

kern/include/vfs.h
kern/src/syscall.c
kern/src/vfs.c
tests/file_test.c

index da83841..5bd5ab4 100644 (file)
@@ -464,6 +464,8 @@ int create_file(struct inode *dir, struct dentry *dentry, int flags, int mode);
 int create_dir(struct inode *dir, struct dentry *dentry, int mode);
 int check_perms(struct inode *inode, int access_mode);
 void inode_release(struct kref *kref);
+struct inode *lookup_inode(char *path, int flags);
+void stat_inode(struct inode *inode, struct kstat *kstat);
 
 /* File functions */
 ssize_t generic_file_read(struct file *file, char *buf, size_t count,
index 49bee59..21c2df6 100644 (file)
@@ -824,7 +824,7 @@ static intreg_t sys_open(struct proc *p, const char *path, size_t path_l,
                warn("File insertion failed");
                return -1;
        }
-       printd("File Open, res=%d\n", fd);
+       printd("File %s Open, res=%d\n", path, fd);
        return fd;
 }
 
@@ -835,12 +835,6 @@ static intreg_t sys_close(struct proc *p, int fd)
                set_errno(current_tf, EBADF);
                return -1;
        }
-       /* TEMP TEST */
-       if (kref_refcnt(&file->f_kref)) {
-               printk("sys_close: Detected positive refcnt %d for file %s\n",
-                      kref_refcnt(&file->f_kref), file_name(file));
-               panic("Idiot.");
-       }
        return 0;
 }
 
@@ -849,47 +843,77 @@ static intreg_t sys_close(struct proc *p, int fd)
        frontend_syscall_errno(p,APPSERVER_SYSCALL_##which,\
                           (int)(a0),(int)(a1),(int)(a2),(int)(a3))
 
-#define NEWLIB_STAT_SIZE 64
-intreg_t sys_fstat(struct proc *p, int fd, void *buf)
+static intreg_t sys_fstat(struct proc *p, int fd, struct kstat *u_stat)
 {
-       int *kbuf = kmalloc(NEWLIB_STAT_SIZE, 0);
-       int ret = ufe(fstat,fd,PADDR(kbuf),0,0);
-       if(ret != -1 && memcpy_to_user_errno(p,buf,kbuf,NEWLIB_STAT_SIZE))
-               ret = -1;
+       struct kstat *kbuf;
+       struct file *file = get_file_from_fd(&p->open_files, fd);
+       if (!file) {
+               set_errno(current_tf, EBADF);
+               return -1;
+       }
+       kbuf = kmalloc(sizeof(struct kstat), 0);
+       if (!kbuf) {
+               kref_put(&file->f_kref);
+               set_errno(current_tf, ENOMEM);
+               return -1;
+       }
+       stat_inode(file->f_dentry->d_inode, kbuf);
+       kref_put(&file->f_kref);
+       /* TODO: UMEM: pin the memory, copy directly, and skip the kernel buffer */
+       if (memcpy_to_user_errno(p, u_stat, kbuf, sizeof(struct kstat))) {
+               kfree(kbuf);
+               set_errno(current_tf, EINVAL);
+               return -1;
+       }
        kfree(kbuf);
-       return ret;
+       return 0;
 }
 
-intreg_t sys_stat(struct proc *p, const char *path, size_t path_l, void *buf)
+/* sys_stat() and sys_lstat() do nearly the same thing, differing in how they
+ * treat a symlink for the final item, which (probably) will be controlled by
+ * the lookup flags */
+static intreg_t stat_helper(struct proc *p, const char *path, size_t path_l,
+                            struct kstat *u_stat, int flags)
 {
-       char* fn = user_strdup_errno(p,path,PGSIZE);
-       if(fn == NULL)
+       struct kstat *kbuf;
+       struct inode *path_i;
+       char *t_path = user_strdup_errno(p, path, path_l);
+       if (!t_path)
                return -1;
-
-       int *kbuf = kmalloc(NEWLIB_STAT_SIZE, 0);
-       int ret = ufe(stat,PADDR(fn),PADDR(kbuf),0,0);
-       if(ret != -1 && memcpy_to_user_errno(p,buf,kbuf,NEWLIB_STAT_SIZE))
-               ret = -1;
-
-       user_memdup_free(p,fn);
+       path_i = lookup_inode(t_path, flags);
+       user_memdup_free(p, t_path);
+       if (!path_i)
+               return -1;
+       kbuf = kmalloc(sizeof(struct kstat), 0);
+       if (!kbuf) {
+               set_errno(current_tf, ENOMEM);
+               kref_put(&path_i->i_kref);
+               return -1;
+       }
+       stat_inode(path_i, kbuf);
+       kref_put(&path_i->i_kref);
+       /* TODO: UMEM: pin the memory, copy directly, and skip the kernel buffer */
+       if (memcpy_to_user_errno(p, u_stat, kbuf, sizeof(struct kstat))) {
+               kfree(kbuf);
+               set_errno(current_tf, EINVAL);
+               return -1;
+       }
        kfree(kbuf);
-       return ret;
+       return 0;
 }
 
-intreg_t sys_lstat(struct proc *p, const char *path, size_t path_l, void *buf)
+/* Follow a final symlink */
+static intreg_t sys_stat(struct proc *p, const char *path, size_t path_l,
+                         struct kstat *u_stat)
 {
-       char* fn = user_strdup_errno(p,path,PGSIZE);
-       if(fn == NULL)
-               return -1;
-
-       int *kbuf = kmalloc(NEWLIB_STAT_SIZE, 0);
-       int ret = ufe(lstat,PADDR(fn),PADDR(kbuf),0,0);
-       if(ret != -1 && memcpy_to_user_errno(p,buf,kbuf,NEWLIB_STAT_SIZE))
-               ret = -1;
+       return stat_helper(p, path, path_l, u_stat, LOOKUP_FOLLOW);
+}
 
-       user_memdup_free(p,fn);
-       kfree(kbuf);
-       return ret;
+/* Don't follow a final symlink */
+static intreg_t sys_lstat(struct proc *p, const char *path, size_t path_l,
+                          struct kstat *u_stat)
+{
+       return stat_helper(p, path, path_l, u_stat, 0);
 }
 
 intreg_t sys_fcntl(struct proc *p, int fd, int cmd, int arg)
index eb39a7c..80edb65 100644 (file)
@@ -608,6 +608,45 @@ void inode_release(struct kref *kref)
        // kref_put(inode->i_bdev->kref); /* assuming it's a bdev */
 }
 
+/* Looks up the inode for the given path, returning a refcnt'd inode (or 0).
+ * Permissions are applied for the current user, which is quite a broken system
+ * at the moment.  Flags are lookup flags. */
+struct inode *lookup_inode(char *path, int flags)
+{
+       struct inode *inode;
+       struct nameidata nd_r = {0}, *nd = &nd_r;
+       int error;
+
+       error = path_lookup(path, flags, nd);
+       if (error) {
+               path_release(nd);
+               set_errno(current_tf, -error);
+               return 0;
+       }
+       inode = nd->dentry->d_inode;
+       kref_get(&inode->i_kref, 1);
+       path_release(nd);
+       return inode;
+}
+
+/* Fills in kstat with the stat information for the inode */
+void stat_inode(struct inode *inode, struct kstat *kstat)
+{
+       kstat->st_dev = inode->i_sb->s_dev;
+       kstat->st_ino = inode->i_ino;
+       kstat->st_mode = inode->i_mode;
+       kstat->st_nlink = inode->i_nlink;
+       kstat->st_uid = inode->i_uid;
+       kstat->st_gid = inode->i_gid;
+       kstat->st_rdev = inode->i_rdev;
+       kstat->st_size = inode->i_size;
+       kstat->st_blksize = inode->i_blksize;
+       kstat->st_blocks = inode->i_blocks;
+       kstat->st_atime = inode->i_atime;
+       kstat->st_mtime = inode->i_mtime;
+       kstat->st_ctime = inode->i_ctime;
+}
+
 /* File functions */
 
 /* Read count bytes from the file into buf, starting at *offset, which is increased
@@ -722,7 +761,7 @@ struct file *do_file_open(char *path, int flags, int mode)
        struct inode *parent_i;
        struct nameidata nd_r = {0}, *nd = &nd_r;
        int lookup_flags = LOOKUP_PARENT;
-       int error = 0;
+       int error;
 
        /* lookup the parent */
        nd->intent = flags & (O_RDONLY|O_WRONLY|O_RDWR);
@@ -730,6 +769,7 @@ struct file *do_file_open(char *path, int flags, int mode)
                lookup_flags |= LOOKUP_CREATE;
        error = path_lookup(path, lookup_flags, nd);
        if (error) {
+               path_release(nd);
                set_errno(current_tf, -error);
                return 0;
        }
index a2ae2ed..9e2f80f 100644 (file)
@@ -34,4 +34,25 @@ int main()
        retval = access("/dir1/f1.txt", R_OK);
        if (retval < 0)
                printf("WARNING! Access error for f1.txt!\n");
+
+       struct stat st = {0};
+       //retval = stat("/bin/mhello", &st);
+       retval = fstat(fd, &st);
+       printf("Tried to stat, was told %d\n", retval);
+       printf("STAT RESULTS\n---------------------\n");
+       printf("dev       : %d\n", st.st_dev);
+       printf("ino       : %d\n", st.st_ino);
+       printf("mode      : %d\n", st.st_mode);
+       printf("nlink     : %d\n", st.st_nlink);
+       printf("uid       : %d\n", st.st_uid);
+       printf("gid       : %d\n", st.st_gid);
+       printf("rdev      : %d\n", st.st_rdev);
+       printf("size      : %d\n", st.st_size);
+       printf("blksize   : %d\n", st.st_blksize);
+       printf("blocks    : %d\n", st.st_blocks);
+       printf("atime     : %d\n", st.st_atime);
+       printf("mtime     : %d\n", st.st_mtime);
+       printf("ctime     : %d\n", st.st_ctime);
+       breakpoint();
+
 }