--- 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); +}