vfs can read directories

Sun, 17 Mar 2013 12:47:59 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 17 Mar 2013 12:47:59 +0100
changeset 55
b7908bf38f9f
parent 54
3a1d5a52adfc
child 56
c6cf20b09043

vfs can read directories

src/server/daemon/vfs.c file | annotate | diff | comparison | revisions
src/server/daemon/vfs.h file | annotate | diff | comparison | revisions
src/server/safs/service.c file | annotate | diff | comparison | revisions
--- a/src/server/daemon/vfs.c	Sat Mar 16 23:11:34 2013 +0100
+++ b/src/server/daemon/vfs.c	Sun Mar 17 12:47:59 2013 +0100
@@ -40,6 +40,11 @@
     sys_file_close
 };
 
+static VFS_DIRIO sys_dir_io = {
+    sys_dir_read,
+    sys_dir_close
+};
+
 VFSContext* vfs_request_context(Session *sn, Request *rq) {
     VFSContext *ctx = pool_malloc(sn->pool, sizeof(VFSContext));
     ctx->sn = sn;
@@ -103,6 +108,7 @@
     VFSFile *file = pool ?
             pool_malloc(pool, sizeof(VFSFile)) : malloc(sizeof(VFSFile));
     if(!file) {
+        close(fd);
         return NULL;
     }
     file->ctx = ctx;
@@ -200,6 +206,92 @@
     }
 }
 
+VFS_DIR vfs_opendir(VFSContext *ctx, char *path) {
+    Session *sn;
+    Request *rq;
+    pool_handle_t *pool;
+    uint32_t access_mask;
+    
+    if(ctx) {
+        access_mask = ctx->aclreqaccess;
+        access_mask |= ACL_LIST;
+        if(!ctx->pool) {
+            // TODO: log warning
+            // broken VFSContext
+        }
+        if(ctx->vfs) {
+            // ctx->aclreqaccess should be the complete access mask
+            uint32_t m = ctx->aclreqaccess; // save original access mask
+            ctx->aclreqaccess = access_mask; // set mask for vfs->opendir call
+            VFS_DIR dir = ctx->vfs->opendir(ctx, path);
+            ctx->aclreqaccess = m; // restore original access mask
+            return dir;
+        } else {
+            pool = ctx->pool;
+        }
+    } else {
+        sn = NULL;
+        rq = NULL;
+        pool = NULL;
+        access_mask = ACL_LIST;
+    }
+    
+    // check ACLs
+    uid_t uid; // uid and gid will be initialized by sys_acl_check
+    gid_t gid;
+    if(sys_acl_check(ctx, access_mask, &uid, &gid)) {
+        return NULL;
+    }
+    
+    // open file
+    int sys_fd = open(path, O_RDONLY);
+    if(sys_fd == -1) {
+        if(ctx) {
+            ctx->vfs_errno = errno;
+            sys_set_error_status(ctx);
+        }
+        return NULL;
+    }
+    
+    DIR *sys_dir = fdopendir(sys_fd);
+    if(!sys_dir) {
+        if(ctx) {
+            ctx->vfs_errno = errno;
+            sys_set_error_status(ctx);
+        }
+        return NULL;
+    }
+    
+    VFSDir *dir = pool ?
+            pool_malloc(pool, sizeof(VFSDir)) : malloc(sizeof(VFSDir));
+    if(!dir) {
+        closedir(sys_dir);
+        return NULL;
+    }
+    dir->ctx = ctx;
+    dir->data = sys_dir;
+    dir->fd = sys_fd;
+    dir->io = &sys_dir_io;
+    return dir;
+}
+
+int vfs_readdir(VFS_DIR dir, VFS_ENTRY *entry) {
+    return dir->io->readdir(dir, entry, 0);
+}
+
+int vfs_readdir_stat(VFS_DIR dir, VFS_ENTRY *entry) {
+    return dir->io->readdir(dir, entry, 1);
+}
+
+void vfs_closedir(VFS_DIR dir) {
+    dir->io->close(dir);
+    if(dir->ctx) {
+        pool_free(dir->ctx->pool, dir);
+    } else {
+        free(dir);
+    }
+}
+
 
 // private
 
@@ -263,3 +355,23 @@
 void sys_file_close(SYS_FILE fd) {
     close(fd->fd);
 }
+
+int sys_dir_read(VFS_DIR dir, VFS_ENTRY *entry, int getstat) {
+    struct dirent *e = readdir(dir->data);
+    if(e) {
+        entry->name = e->d_name;
+        if(getstat) {
+            // TODO: check ACLs again for new path
+            if(fstatat(dir->fd, e->d_name, &entry->stat, 0)) {
+                entry->stat_errno = errno;
+            }
+        }
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+void sys_dir_close(VFS_DIR dir) {
+    closedir(dir->data);
+}
--- a/src/server/daemon/vfs.h	Sat Mar 16 23:11:34 2013 +0100
+++ b/src/server/daemon/vfs.h	Sun Mar 17 12:47:59 2013 +0100
@@ -36,13 +36,20 @@
 extern "C" {
 #endif
 
-typedef struct VFS_IO    VFS_IO;
-typedef struct VFSFile   VFSFile;
+typedef struct VFS_IO     VFS_IO;
+typedef struct VFS_DIRIO  VFS_DIRIO;
+typedef struct VFSFile    VFSFile;
+typedef struct VFSDir     VFSDir;
+typedef struct VFSEntry   VFSEntry;
+
+#define VFS_DIR           VFSDir*
+#define VFS_ENTRY         VFSEntry
 
 struct VFS {
     SYS_FILE (*open)(VFSContext *ctx, char *path, int oflags);
     int (*stat)(VFSContext *ctx, char *path, struct stat *buf);
     int (*fstat)(VFSContext *ctx, SYS_FILE fd, struct stat *buf);
+    VFS_DIR (*opendir)(VFSContext *ctx, char *path);
 };
 
 struct VFSContext {
@@ -63,12 +70,30 @@
     int fd; // native file descriptor if available, or -1
 };
 
+struct VFSDir {
+    VFSContext *ctx;
+    VFS_DIRIO *io;
+    void *data; // private data used by the VFSDir implementation
+    int fd; // native file descriptor if available, or -1
+};
+
+struct VFSEntry {
+    char *name;
+    struct stat stat;
+    int stat_errno;
+};
+
 struct VFS_IO {
     ssize_t (*read)(SYS_FILE fd, void *buf, size_t nbyte);
     ssize_t (*write)(SYS_FILE fd, const void *buf, size_t nbyte);
     void (*close)(SYS_FILE fd);
 };
 
+struct VFS_DIRIO {
+    int (*readdir)(VFS_DIR dir, VFS_ENTRY *entry, int getstat);
+    void (*close)(VFS_DIR dir);
+};
+
 /*
  * creates a VFSContext for a Request
  * vfs calls will do ACL checks
@@ -82,6 +107,10 @@
 int vfs_stat(VFSContext *ctx, char *path, struct stat *buf);
 int vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf);
 void vfs_close(SYS_FILE fd);
+VFS_DIR vfs_opendir(VFSContext *ctx, char *path);
+int vfs_readdir(VFS_DIR dir, VFS_ENTRY *entry);
+int vfs_readdir_stat(VFS_DIR dir, VFS_ENTRY *entry);
+void vfs_closedir(VFS_DIR dir);
 
 // private
 int sys_acl_check(VFSContext *ctx, uint32_t acm, uid_t *uid, gid_t *gid);
@@ -89,6 +118,8 @@
 ssize_t sys_file_read(SYS_FILE fd, void *buf, size_t nbyte);
 ssize_t sys_file_write(SYS_FILE fd, const void *buf, size_t nbyte);
 void sys_file_close(SYS_FILE fd);
+int sys_dir_read(VFS_DIR dir, VFS_ENTRY *entry, int getstat);
+void sys_dir_close(VFS_DIR dir);
 
 #ifdef	__cplusplus
 }
--- a/src/server/safs/service.c	Sat Mar 16 23:11:34 2013 +0100
+++ b/src/server/safs/service.c	Sun Mar 17 12:47:59 2013 +0100
@@ -107,15 +107,6 @@
     net_sendfile(sn->csd, &sfd);
     
     vfs_close(fd);
-    
-
-    /* send file*/
-    //SystemIOStream *io = (SystemIOStream*) sn->csd;
-    //off_t fileoffset = 0;
-    //int len = atoi(pblock_findkeyval(pb_key_content_length, rq->srvhdrs));
-    //sendfile(io->fd, fd->fd, &fileoffset, len);
-
-    //close(fd);
 
     return REQ_PROCEED;
 }
@@ -139,30 +130,9 @@
     sstr_t r_uri = sstr(uri);
 
     /* open the file */
-    int fd = open(ppath, O_RDONLY);
-    if(fd < 0) {
-        //perror("service_index: open");
-
-        int status = 500;
-        switch(errno) {
-            case EACCES: {
-                status = 403;
-                break;
-            }
-            case ENOENT: {
-                status = 404;
-                break;
-            }
-        }
-        protocol_status(sn, rq, status, NULL);
-        //printf("REQ_ABORTED\n");
-        return REQ_ABORTED;
-    }
-
-    DIR *dir = fdopendir(fd);
-    if(dir == NULL) {
-        protocol_status(sn, rq, 500, NULL);
-        //printf("DIR is null\n");
+    VFSContext *vfs = vfs_request_context(sn, rq);
+    VFS_DIR dir = vfs_opendir(vfs, ppath);
+    if(!dir) {
         return REQ_ABORTED;
     }
 
@@ -175,13 +145,14 @@
     sbuf_puts(out, uri);
     sbuf_puts(out, "</h1><hr>\n\n");
 
-    struct dirent *f;
-    while((f = readdir(dir)) != NULL) {
-        if(strcmp(f->d_name, ".") == 0 || strcmp(f->d_name, "..") == 0) {
+    //struct dirent *f;
+    VFS_ENTRY f;
+    while((vfs_readdir(dir, &f)) != NULL) {
+        if(strcmp(f.name, ".") == 0 || strcmp(f.name, "..") == 0) {
             continue;
         }
-
-        sstr_t filename = sstr(f->d_name);
+        
+        sstr_t filename = sstr(f.name);
 
         sbuf_puts(out, "<a href=\"");
         sbuf_append(out, r_uri);
@@ -203,7 +174,7 @@
     net_write(sn->csd, out->ptr, out->length);
 
     /* close */
-    closedir(dir);
+    vfs_closedir(dir);
     sbuf_free(out);
 
     return REQ_PROCEED;

mercurial