# HG changeset patch # User Olaf Wintermann # Date 1363520879 -3600 # Node ID b7908bf38f9f78874025fa20382fdab4f550c019 # Parent 3a1d5a52adfc05173f49a4615aef0358839cf527 vfs can read directories diff -r 3a1d5a52adfc -r b7908bf38f9f src/server/daemon/vfs.c --- 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); +} diff -r 3a1d5a52adfc -r b7908bf38f9f src/server/daemon/vfs.h --- 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 } diff -r 3a1d5a52adfc -r b7908bf38f9f src/server/safs/service.c --- 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, "
\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, "csd, out->ptr, out->length); /* close */ - closedir(dir); + vfs_closedir(dir); sbuf_free(out); return REQ_PROCEED;