Fri, 17 Jan 2020 22:23:30 +0100
implement multistatus writer
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2019 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include <ucx/string.h> #include <ucx/list.h> #include <ucx/map.h> #include "../daemon/session.h" #include "testutils.h" #include "vfs.h" typedef struct TestVFS { UcxMap *files; } TestVFS; typedef struct TestVFSFile { VFSFile file; sstr_t path; int isdir; } TestVFSFile; typedef struct TestVFSDir { VFSDir dir; TestVFSFile *file; UcxMapIterator i; sstr_t name; } TestVFSDir; /* dir io */ static char* test_resource_name(char *url) { sstr_t urlstr = sstr(url); if(urlstr.ptr[urlstr.length-1] == '/') { urlstr.length--; } sstr_t resname = sstrrchr(urlstr, '/'); if(resname.length > 1) { return resname.ptr+1; } else { return url; } } int testvfs_readdir(VFS_DIR dir, VFS_ENTRY *entry, int getstat) { TestVFS *vfs = dir->ctx->vfs->instance; TestVFSDir *vfsdir = (TestVFSDir*)dir; sstr_t prefix = sstrcat(2, vfsdir->file->path, S("/")); TestVFSFile *file = NULL; UCX_MAP_FOREACH(key, file, vfsdir->i) { if(sstrprefix(file->path, prefix)) { break; } else { file = NULL; } } free(prefix.ptr); if(file) { vfsdir->name = sstrdup_a( session_get_allocator(dir->ctx->sn), sstr(test_resource_name(file->path.ptr))); ZERO(entry, sizeof(VFS_ENTRY)); entry->name = vfsdir->name.ptr; return 1; } else { return 0; } } void testvfs_dir_close(VFS_DIR dir) { TestVFSDir *testdir = (TestVFSDir*)dir; pool_free(testdir->dir.ctx->sn->pool, dir); } VFS_DIRIO test_dir_io = { testvfs_readdir, testvfs_dir_close }; /* vfs funcs */ SYS_FILE testvfs_open(VFSContext *ctx, char *path, int oflags) { TestVFS *vfs = ctx->vfs->instance; TestVFSFile *file = NULL; sstr_t s_path = sstr(path); if(sstrsuffix(s_path, S("/"))) { s_path.length--; } file = ucx_map_sstr_get(vfs->files, s_path); if(!file) { if((oflags & O_CREAT) == O_CREAT) { file = pool_malloc(ctx->sn->pool, sizeof(TestVFSFile)); ZERO(file, sizeof(TestVFSFile)); file->path = sstrdup_a(session_get_allocator(ctx->sn), s_path); ucx_map_sstr_put(vfs->files, s_path, file); } } return (SYS_FILE)file; } int testvfs_stat(VFSContext *ctx, char *path, struct stat *buf) { TestVFS *vfs = ctx->vfs->instance; TestVFSFile *file = NULL; sstr_t s_path = sstr(path); if(sstrsuffix(s_path, S("/"))) { s_path.length--; } file = ucx_map_sstr_get(vfs->files, s_path); if(!file) { return 1; } return 0; } int testvfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) { return 0; } VFS_DIR testvfs_opendir(VFSContext *ctx, char *path) { TestVFS *vfs = ctx->vfs->instance; TestVFSFile *file = NULL; sstr_t s_path = sstr(path); if(sstrsuffix(s_path, S("/"))) { s_path.length--; } file = ucx_map_sstr_get(vfs->files, s_path); if(!file) { return NULL; } if(!file->isdir) { return NULL; } TestVFSDir *dir = pool_malloc(ctx->sn->pool, sizeof(TestVFSDir)); ZERO(dir, sizeof(TestVFSDir)); dir->file = file; dir->i = ucx_map_iterator(vfs->files); dir->dir.ctx = ctx; dir->dir.io = &test_dir_io; return (VFS_DIR)dir; } VFS_DIR testvfs_fdopendir(VFSContext *ctx, SYS_FILE fd) { TestVFS *vfs = ctx->vfs->instance; TestVFSFile *file = (TestVFSFile*)fd; if(!file->isdir) { return NULL; } TestVFSDir *dir = pool_malloc(ctx->sn->pool, sizeof(TestVFSDir)); ZERO(dir, sizeof(TestVFSDir)); dir->file = file; dir->i = ucx_map_iterator(vfs->files); dir->dir.ctx = ctx; dir->dir.io = &test_dir_io; return (VFS_DIR)dir; } int testvfs_mkdir(VFSContext *ctx, char *path) { SYS_FILE fd = testvfs_open(ctx, path, O_CREAT); if(!fd) { return 1; } TestVFSFile *file = (TestVFSFile*)fd; file->isdir = 1; return 0; } int testvfs_unlink(VFSContext *ctx, char *path) { return 0; } static VFS testVFSClass = { testvfs_open, testvfs_stat, testvfs_fstat, testvfs_opendir, testvfs_fdopendir, testvfs_mkdir, testvfs_unlink, 0, NULL }; VFS* testvfs_create(Session *sn) { TestVFS *vfs = pool_malloc(sn->pool, sizeof(TestVFS)); vfs->files = ucx_map_new_a(session_get_allocator(sn), 64); testVFSClass.instance = vfs; return &testVFSClass; } /* ------------------------------------------------------------------------- */ // // VFS Tests // /* ------------------------------------------------------------------------- */ UCX_TEST(test_vfs_open) { Session *sn = testutil_session(); Request *rq = testutil_request(sn->pool, "PUT", "/"); rq->vfs = testvfs_create(sn); VFSContext *vfs = vfs_request_context(sn, rq); UCX_TEST_BEGIN; UCX_TEST_ASSERT(vfs, "vfs is NULL"); SYS_FILE f1 = vfs_open(vfs, "/file1", O_CREAT); UCX_TEST_ASSERT(f1, "f1 not opened"); SYS_FILE f2 = vfs_open(vfs, "/file1", 0); UCX_TEST_ASSERT(f2, "f2 not opened"); UCX_TEST_END; testutil_destroy_session(sn); } UCX_TEST(test_vfs_mkdir) { Session *sn = testutil_session(); Request *rq = testutil_request(sn->pool, "PUT", "/"); rq->vfs = testvfs_create(sn); VFSContext *vfs = vfs_request_context(sn, rq); UCX_TEST_BEGIN; int err = vfs_mkdir(vfs, "/dir"); UCX_TEST_ASSERT(err == 0, "error not 0"); SYS_FILE fd = vfs_open(vfs, "/dir", 0); UCX_TEST_ASSERT(fd, "no fd"); UCX_TEST_END; testutil_destroy_session(sn); } UCX_TEST(test_vfs_opendir) { Session *sn = testutil_session(); Request *rq = testutil_request(sn->pool, "PUT", "/"); rq->vfs = testvfs_create(sn); VFSContext *vfs = vfs_request_context(sn, rq); UCX_TEST_BEGIN; int err = vfs_mkdir(vfs, "/dir"); UCX_TEST_ASSERT(err == 0, "error not 0"); VFSDir *dir = vfs_opendir(vfs, "/dir"); UCX_TEST_ASSERT(dir, "no dir"); UCX_TEST_END; testutil_destroy_session(sn); } UCX_TEST(test_vfs_readdir) { Session *sn = testutil_session(); Request *rq = testutil_request(sn->pool, "PUT", "/"); rq->vfs = testvfs_create(sn); VFSContext *vfs = vfs_request_context(sn, rq); UCX_TEST_BEGIN; int err = vfs_mkdir(vfs, "/dir"); UCX_TEST_ASSERT(err == 0, "error not 0"); // add some test file to /dir UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file1", O_CREAT), "creation of file1 failed"); UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file2", O_CREAT), "creation of file2 failed"); UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file3", O_CREAT), "creation of file3 failed"); UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file4", O_CREAT), "creation of file4 failed"); VFSDir *dir = vfs_opendir(vfs, "/dir"); UCX_TEST_ASSERT(dir, "dir not opened"); UcxMap *files = ucx_map_new(8); VFSEntry entry; while(vfs_readdir(dir, &entry)) { ucx_map_cstr_put(files, entry.name, dir); } UCX_TEST_ASSERT(files->count == 4, "wrong files count"); UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file1"), "file1 missing"); UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file2"), "file2 missing"); UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file3"), "file3 missing"); UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file4"), "file4 missing"); ucx_map_free(files); UCX_TEST_END; testutil_destroy_session(sn); }