src/server/daemon/vfs.c

branch
webdav
changeset 211
2160585200ac
parent 193
aa8393527b1e
child 241
4adad7faf452
--- a/src/server/daemon/vfs.c	Tue Aug 13 22:14:32 2019 +0200
+++ b/src/server/daemon/vfs.c	Thu Oct 31 10:26:35 2019 +0100
@@ -52,9 +52,11 @@
     sys_vfs_stat,
     sys_vfs_fstat,
     sys_vfs_opendir,
+    sys_vfs_fdopendir,
     sys_vfs_mkdir,
     sys_vfs_unlink,
-    VFS_CHECKS_ACL
+    VFS_CHECKS_ACL,
+    NULL
 };
 
 static VFS_IO sys_file_io = {
@@ -202,6 +204,27 @@
     return dir;
 }
 
+VFS_DIR vfs_fdopendir(VFSContext *ctx, SYS_FILE fd) {
+    WS_ASSERT(ctx);
+    WS_ASSERT(path);
+    
+    uint32_t access_mask = ctx->aclreqaccess | ACL_LIST;
+    
+    // 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->open call
+    if((ctx->vfs->flags & VFS_CHECKS_ACL) != VFS_CHECKS_ACL) {
+        // VFS does not evaluates the ACL itself, so we have to do it here
+        SysACL sysacl;
+        if(sys_acl_check(ctx, access_mask, &sysacl)) {
+            return NULL;
+        }
+    }
+    VFS_DIR dir = ctx->vfs->fdopendir(ctx, fd);
+    ctx->aclreqaccess = m; // restore original access mask
+    return dir;
+}
+
 int vfs_readdir(VFS_DIR dir, VFS_ENTRY *entry) {
     WS_ASSERT(dir);
     WS_ASSERT(entry);
@@ -422,6 +445,62 @@
     return dir;
 }
 
+VFS_DIR sys_vfs_fdopendir(VFSContext *ctx, SYS_FILE fd) {
+    uint32_t access_mask = ctx->aclreqaccess;
+    pool_handle_t *pool = ctx->pool;
+    
+    // check ACLs
+    SysACL sysacl;
+    if(sys_acl_check(ctx, access_mask, &sysacl)) {
+        return NULL;
+    }
+    
+    if(sysacl.acl) {
+        if(!fs_acl_check_fd(&sysacl, ctx->user, fd->fd, access_mask)) {
+            acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user);
+            return NULL;
+        }
+    }
+    
+    // open directory
+    DIR *sys_dir = fdopendir(fd->fd);
+    if(!sys_dir) {
+        if(ctx) {
+            ctx->vfs_errno = errno;
+            sys_set_error_status(ctx);
+        }
+        return NULL;
+    }
+    
+    SysVFSDir *dir_data = VFS_MALLOC(pool, sizeof(SysVFSDir));
+    if(!dir_data) {
+        closedir(sys_dir);
+        return NULL;
+    }
+    long maxfilelen = fpathconf(fd->fd, _PC_NAME_MAX);
+    size_t entry_len = offsetof(struct dirent, d_name) + maxfilelen + 1;
+    dir_data->cur = VFS_MALLOC(pool, entry_len);
+    if(!dir_data->cur) {
+        closedir(sys_dir);
+        VFS_FREE(pool, dir_data);
+        return NULL;
+    }
+    dir_data->dir = sys_dir;
+    
+    VFSDir *dir = VFS_MALLOC(pool, sizeof(VFSDir));
+    if(!dir) {
+        closedir(sys_dir);
+        VFS_FREE(pool, dir_data->cur);
+        VFS_FREE(pool, dir_data);
+        return NULL;
+    }
+    dir->ctx = ctx;
+    dir->data = dir_data;
+    dir->fd = fd->fd;
+    dir->io = &sys_dir_io;
+    return dir;
+}
+
 int sys_vfs_mkdir(VFSContext *ctx, char *path) {
     return sys_path_op(ctx, path, sys_mkdir);
 }
@@ -539,6 +618,7 @@
             entry->name = name;
             if(getstat) {
                 // TODO: check ACLs again for new path
+                entry->stat_errno = 0;
                 if(fstatat(dir->fd, result->d_name, &entry->stat, 0)) {
                     entry->stat_errno = errno;
                 }

mercurial