src/server/daemon/vfs.c

changeset 55
b7908bf38f9f
parent 54
3a1d5a52adfc
child 56
c6cf20b09043
--- 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);
+}

mercurial