vfs: refactor VFSNode allocation and handling of backend-specific data
VFSNode no longer has the generic void* data1 and data2 fields. Introduced a macro system that allows backends to easily "subclass" VFSNode to add extra fields.
This commit is contained in:
parent
b42899cc6a
commit
3169b16d10
25 changed files with 416 additions and 406 deletions
|
@ -17,10 +17,6 @@
|
|||
#include "rwops_zlib.h"
|
||||
#include "rwops_zstd.h"
|
||||
|
||||
#ifdef TAISEI_BUILDCONF_USE_ZIP
|
||||
#include "rwops_zipfile.h"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "rwops_trace.h"
|
||||
#endif
|
||||
|
|
|
@ -11,12 +11,6 @@ rwops_src = files(
|
|||
'rwops_zstd.c',
|
||||
)
|
||||
|
||||
if dep_zip.found()
|
||||
rwops_src += files(
|
||||
'rwops_zipfile.c',
|
||||
)
|
||||
endif
|
||||
|
||||
if is_debug_build
|
||||
rwops_src += files(
|
||||
'rwops_trace.c',
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "taisei.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "vfs/zipfile_impl.h"
|
||||
|
||||
SDL_RWops *SDL_RWFromZipFile(VFSNode *znode, VFSZipPathData *pdata) attr_nonnull_all;
|
|
@ -16,14 +16,14 @@
|
|||
// NOTE: Largely based on readonly_wrapper. Sorry for the copypasta.
|
||||
// This is currently hardcoded to only support transparent decompression of .zst files.
|
||||
|
||||
VFS_NODE_TYPE(VFSDecompNode, {
|
||||
VFSNode *wrapped;
|
||||
bool compr_zstd;
|
||||
});
|
||||
|
||||
#define ZST_SUFFIX ".zst"
|
||||
#define WRAPPED(n) ((VFSNode*)(n)->data1)
|
||||
|
||||
struct decomp_data {
|
||||
uint compr_zstd : 1;
|
||||
};
|
||||
|
||||
static_assert_nomsg(sizeof(struct decomp_data) <= sizeof(void*));
|
||||
#define WRAPPED(node) VFS_NODE_CAST(VFSDecompNode, node)->wrapped
|
||||
|
||||
static char *vfs_decomp_repr(VFSNode *node) {
|
||||
char *wrapped_repr = vfs_node_repr(WRAPPED(node), false);
|
||||
|
@ -64,9 +64,8 @@ static bool vfs_decomp_mkdir(VFSNode *parent, const char *subdir) {
|
|||
static VFSNode *vfs_decomp_locate(VFSNode *dirnode, const char *path) {
|
||||
VFSNode *wrapped = WRAPPED(dirnode);
|
||||
VFSNode *child = vfs_node_locate(wrapped, path);
|
||||
struct decomp_data data = { 0 };
|
||||
|
||||
VFSNode *ochild = NULL;
|
||||
bool zstd = false;
|
||||
|
||||
if(child != NULL && !vfs_node_query(child).exists) {
|
||||
ochild = child;
|
||||
|
@ -90,7 +89,7 @@ static VFSNode *vfs_decomp_locate(VFSNode *dirnode, const char *path) {
|
|||
vfs_decref(child);
|
||||
child = ochild;
|
||||
} else {
|
||||
data.compr_zstd = true;
|
||||
zstd = true;
|
||||
|
||||
if(ochild) {
|
||||
vfs_decref(ochild);
|
||||
|
@ -106,7 +105,10 @@ static VFSNode *vfs_decomp_locate(VFSNode *dirnode, const char *path) {
|
|||
|
||||
VFSNode *wrapped_child = NOT_NULL(vfs_decomp_wrap(child));
|
||||
vfs_decref(child);
|
||||
memcpy(&wrapped_child->data2, &data, sizeof(data));
|
||||
|
||||
if(zstd) {
|
||||
VFS_NODE_CAST(VFSDecompNode, wrapped_child)->compr_zstd = true;
|
||||
}
|
||||
|
||||
return wrapped_child;
|
||||
}
|
||||
|
@ -117,16 +119,13 @@ static SDL_RWops *vfs_decomp_open(VFSNode *filenode, VFSOpenMode mode) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct decomp_data data;
|
||||
memcpy(&data, &filenode->data2, sizeof(data));
|
||||
|
||||
SDL_RWops *raw = vfs_node_open(WRAPPED(filenode), mode);
|
||||
|
||||
if(!raw) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(data.compr_zstd) {
|
||||
if(VFS_NODE_CAST(VFSDecompNode, filenode)->compr_zstd) {
|
||||
return SDL_RWWrapZstdReaderSeekable(raw, -1, true);
|
||||
}
|
||||
|
||||
|
@ -203,7 +202,7 @@ static void vfs_decomp_iter_stop(VFSNode *node, void **opaque) {
|
|||
}
|
||||
}
|
||||
|
||||
static VFSNodeFuncs vfs_funcs_decomp = {
|
||||
VFS_NODE_FUNCS(VFSDecompNode, {
|
||||
.repr = vfs_decomp_repr,
|
||||
.query = vfs_decomp_query,
|
||||
.free = vfs_decomp_free,
|
||||
|
@ -215,7 +214,7 @@ static VFSNodeFuncs vfs_funcs_decomp = {
|
|||
.open = vfs_decomp_open,
|
||||
.mount = vfs_decomp_mount,
|
||||
.unmount = vfs_decomp_unmount,
|
||||
};
|
||||
});
|
||||
|
||||
VFSNode *vfs_decomp_wrap(VFSNode *base) {
|
||||
if(base == NULL) {
|
||||
|
@ -224,10 +223,9 @@ VFSNode *vfs_decomp_wrap(VFSNode *base) {
|
|||
|
||||
vfs_incref(base);
|
||||
|
||||
VFSNode *wrapper = vfs_alloc();
|
||||
wrapper->funcs = &vfs_funcs_decomp;
|
||||
wrapper->data1 = base;
|
||||
return wrapper;
|
||||
return &VFS_ALLOC(VFSDecompNode, {
|
||||
.wrapped = base,
|
||||
})->as_generic;
|
||||
}
|
||||
|
||||
bool vfs_make_decompress_view(const char *path) {
|
||||
|
@ -252,7 +250,7 @@ bool vfs_make_decompress_view(const char *path) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if(node->funcs == &vfs_funcs_decomp) {
|
||||
if(VFS_NODE_TRY_CAST(VFSDecompNode, node)) {
|
||||
vfs_decref(node);
|
||||
vfs_decref(parent);
|
||||
return true;
|
||||
|
|
|
@ -9,7 +9,6 @@ vfs_src = files(
|
|||
'readonly_wrapper.c',
|
||||
'syspath_public.c',
|
||||
'union.c',
|
||||
'union_public.c',
|
||||
'vdir.c',
|
||||
'zipfile_public.c',
|
||||
)
|
||||
|
@ -18,6 +17,7 @@ if dep_zip.found()
|
|||
vfs_src += files(
|
||||
'zipfile.c',
|
||||
'zippath.c',
|
||||
'zippath_rwops.c',
|
||||
)
|
||||
else
|
||||
vfs_src += files(
|
||||
|
|
|
@ -18,7 +18,7 @@ VFSInfo vfs_node_query(VFSNode *node) {
|
|||
return node->funcs->query(node);
|
||||
}
|
||||
|
||||
VFSNode* vfs_node_locate(VFSNode *root, const char *path) {
|
||||
VFSNode *vfs_node_locate(VFSNode *root, const char *path) {
|
||||
assert(root->funcs != NULL);
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
@ -36,7 +36,7 @@ VFSNode* vfs_node_locate(VFSNode *root, const char *path) {
|
|||
return root->funcs->locate(root, path);
|
||||
}
|
||||
|
||||
const char* vfs_node_iter(VFSNode *node, void **opaque) {
|
||||
const char *vfs_node_iter(VFSNode *node, void **opaque) {
|
||||
assert(node->funcs != NULL);
|
||||
|
||||
if(node->funcs->iter != NULL) {
|
||||
|
@ -56,7 +56,7 @@ void vfs_node_iter_stop(VFSNode *node, void **opaque) {
|
|||
}
|
||||
}
|
||||
|
||||
char* vfs_node_syspath(VFSNode *node) {
|
||||
char *vfs_node_syspath(VFSNode *node) {
|
||||
assert(node->funcs != NULL);
|
||||
|
||||
if(node->funcs->syspath == NULL) {
|
||||
|
@ -67,7 +67,7 @@ char* vfs_node_syspath(VFSNode *node) {
|
|||
return node->funcs->syspath(node);
|
||||
}
|
||||
|
||||
char* vfs_node_repr(VFSNode *node, bool try_syspath) {
|
||||
char *(vfs_node_repr)(VFSNode *node, bool try_syspath) {
|
||||
assert(node->funcs != NULL);
|
||||
assert(node->funcs->repr != NULL);
|
||||
char *r;
|
||||
|
@ -122,7 +122,7 @@ bool vfs_node_mkdir(VFSNode *parent, const char *subdir) {
|
|||
return parent->funcs->mkdir(parent, subdir);
|
||||
}
|
||||
|
||||
SDL_RWops* vfs_node_open(VFSNode *filenode, VFSOpenMode mode) {
|
||||
SDL_RWops *vfs_node_open(VFSNode *filenode, VFSOpenMode mode) {
|
||||
assert(filenode->funcs != NULL);
|
||||
|
||||
if(filenode->funcs->open == NULL) {
|
||||
|
|
|
@ -55,9 +55,7 @@ static vfs_tls_t* vfs_tls_get(void) {
|
|||
}
|
||||
|
||||
void vfs_init(void) {
|
||||
vfs_root = vfs_alloc();
|
||||
vfs_vdir_init(vfs_root);
|
||||
|
||||
vfs_root = vfs_vdir_create();
|
||||
vfs_tls_id = SDL_TLSCreate();
|
||||
|
||||
if(vfs_tls_id) {
|
||||
|
@ -95,12 +93,6 @@ void vfs_hook_on_shutdown(VFSShutdownHandler func, void *arg) {
|
|||
}));
|
||||
}
|
||||
|
||||
VFSNode* vfs_alloc(void) {
|
||||
auto node = ALLOC(VFSNode);
|
||||
vfs_incref(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
static void vfs_free(VFSNode *node) {
|
||||
if(!node) {
|
||||
return;
|
||||
|
@ -113,11 +105,11 @@ static void vfs_free(VFSNode *node) {
|
|||
mem_free(node);
|
||||
}
|
||||
|
||||
void vfs_incref(VFSNode *node) {
|
||||
void (vfs_incref)(VFSNode *node) {
|
||||
SDL_AtomicIncRef(&node->refcount);
|
||||
}
|
||||
|
||||
bool vfs_decref(VFSNode *node) {
|
||||
bool (vfs_decref)(VFSNode *node) {
|
||||
if(!node) {
|
||||
return true;
|
||||
}
|
||||
|
@ -130,7 +122,7 @@ bool vfs_decref(VFSNode *node) {
|
|||
return false;
|
||||
}
|
||||
|
||||
VFSNode* vfs_locate(VFSNode *root, const char *path) {
|
||||
VFSNode *(vfs_locate)(VFSNode *root, const char *path) {
|
||||
if(!*path) {
|
||||
vfs_incref(root);
|
||||
return root;
|
||||
|
|
|
@ -38,34 +38,98 @@ struct VFSNodeFuncs {
|
|||
};
|
||||
|
||||
struct VFSNode {
|
||||
VFSNodeFuncs *funcs;
|
||||
char as_generic[0];
|
||||
const VFSNodeFuncs *funcs;
|
||||
SDL_atomic_t refcount;
|
||||
void *data1;
|
||||
void *data2;
|
||||
};
|
||||
|
||||
#define VFS_NODE_TYPE_FUNCS_NAME(_typename) _vfs_funcs_##_typename
|
||||
|
||||
#define VFS_NODE_TYPE(_typename, ...) \
|
||||
typedef struct _typename { \
|
||||
VFSNode as_generic; \
|
||||
struct __VA_ARGS__; \
|
||||
} _typename; \
|
||||
extern const VFSNodeFuncs VFS_NODE_TYPE_FUNCS_NAME(_typename)
|
||||
|
||||
#define VFS_NODE_FUNCS(_typename, ...) \
|
||||
const VFSNodeFuncs VFS_NODE_TYPE_FUNCS_NAME(_typename) = __VA_ARGS__
|
||||
|
||||
#define IS_OF_VFS_NODE_BASE_TYPE(_node) \
|
||||
__builtin_types_compatible_p(VFSNode, typeof(*(_node)))
|
||||
|
||||
#define IS_OF_VFS_NODE_DERIVED_TYPE(_node) \
|
||||
(__builtin_types_compatible_p(VFSNode, typeof((_node)->as_generic)) \
|
||||
&& offsetof(typeof(*(_node)), as_generic) == 0)
|
||||
|
||||
#define IS_OF_VFS_NODE_TYPE(_node) \
|
||||
IS_OF_VFS_NODE_BASE_TYPE(_node) || IS_OF_VFS_NODE_DERIVED_TYPE(_node)
|
||||
|
||||
#define VFS_NODE_ASSERT_VALID(_node) \
|
||||
static_assert(IS_OF_VFS_NODE_TYPE(_node), "Expected a VFSNode or derived type")
|
||||
|
||||
#define VFS_NODE_AS_BASE(_node) ({ \
|
||||
VFS_NODE_ASSERT_VALID(_node); \
|
||||
__builtin_choose_expr(IS_OF_VFS_NODE_BASE_TYPE(_node), (_node), &(_node)->as_generic); \
|
||||
})
|
||||
|
||||
#define VFS_NODE_TRY_CAST(_typename, _node) ({ \
|
||||
VFSNode *_base_node = _node; \
|
||||
static_assert(IS_OF_VFS_NODE_DERIVED_TYPE( (&(_typename){}) ), \
|
||||
"Typename must be of a VFSNode-derived type"); \
|
||||
_typename* _n = UNION_CAST(VFSNode*, _typename*, NOT_NULL(_base_node)); \
|
||||
LIKELY(_n->as_generic.funcs == &VFS_NODE_TYPE_FUNCS_NAME(_typename))? _n : NULL; \
|
||||
})
|
||||
|
||||
#define VFS_NODE_CAST(_typename, _node) \
|
||||
NOT_NULL(VFS_NODE_TRY_CAST(_typename, _node))
|
||||
|
||||
#define VFS_ALLOC(_typename, ...) ({ \
|
||||
auto _node = ALLOC(_typename, ##__VA_ARGS__); \
|
||||
static_assert(IS_OF_VFS_NODE_DERIVED_TYPE(_node), \
|
||||
"Typename must be of a VFSNode-derived type"); \
|
||||
_node->as_generic.funcs = &VFS_NODE_TYPE_FUNCS_NAME(_typename); \
|
||||
vfs_incref(_node); \
|
||||
_node; \
|
||||
})
|
||||
|
||||
|
||||
extern VFSNode *vfs_root;
|
||||
|
||||
VFSNode* vfs_alloc(void);
|
||||
void vfs_incref(VFSNode *node) attr_nonnull(1);
|
||||
bool vfs_decref(VFSNode *node);
|
||||
bool vfs_mount(VFSNode *root, const char *mountpoint, VFSNode *subtree) attr_nonnull(1, 3) attr_nodiscard;
|
||||
bool vfs_mount_or_decref(VFSNode *root, const char *mountpoint, VFSNode *subtree) attr_nonnull(1, 3) attr_nodiscard;
|
||||
VFSNode* vfs_locate(VFSNode *root, const char *path) attr_nonnull(1, 2) attr_nodiscard;
|
||||
VFSNode *vfs_locate(VFSNode *root, const char *path) attr_nonnull(1, 2) attr_nodiscard;
|
||||
|
||||
// Light wrappers around the virtual functions, safe to call even on nodes that
|
||||
// don't implement the corresponding method. "free" is not included, there should
|
||||
// be no reason to call it. It wouldn't do what you'd expect anyway; use vfs_decref.
|
||||
char* vfs_node_repr(VFSNode *node, bool try_syspath) attr_returns_allocated attr_nonnull(1);
|
||||
char *vfs_node_repr(VFSNode *node, bool try_syspath) attr_returns_allocated attr_nonnull(1);
|
||||
VFSInfo vfs_node_query(VFSNode *node) attr_nonnull(1) attr_nodiscard attr_nonnull(1);
|
||||
char* vfs_node_syspath(VFSNode *node) attr_nonnull(1) attr_returns_max_aligned attr_nodiscard attr_nonnull(1);
|
||||
char *vfs_node_syspath(VFSNode *node) attr_nonnull(1) attr_returns_max_aligned attr_nodiscard attr_nonnull(1);
|
||||
bool vfs_node_mount(VFSNode *mountroot, const char *subname, VFSNode *mountee) attr_nonnull(1, 3);
|
||||
bool vfs_node_unmount(VFSNode *mountroot, const char *subname) attr_nonnull(1);
|
||||
VFSNode* vfs_node_locate(VFSNode *root, const char *path) attr_nonnull(1, 2) attr_nodiscard;
|
||||
const char* vfs_node_iter(VFSNode *node, void **opaque) attr_nonnull(1);
|
||||
VFSNode *vfs_node_locate(VFSNode *root, const char *path) attr_nonnull(1, 2) attr_nodiscard;
|
||||
const char *vfs_node_iter(VFSNode *node, void **opaque) attr_nonnull(1);
|
||||
void vfs_node_iter_stop(VFSNode *node, void **opaque) attr_nonnull(1);
|
||||
bool vfs_node_mkdir(VFSNode *parent, const char *subdir) attr_nonnull(1);
|
||||
SDL_RWops* vfs_node_open(VFSNode *filenode, VFSOpenMode mode) attr_nonnull(1) attr_nodiscard;
|
||||
SDL_RWops *vfs_node_open(VFSNode *filenode, VFSOpenMode mode) attr_nonnull(1) attr_nodiscard;
|
||||
|
||||
// NOTE: convenience wrappers added on demand
|
||||
|
||||
#define vfs_incref(node) \
|
||||
vfs_incref(VFS_NODE_AS_BASE(node))
|
||||
|
||||
#define vfs_decref(node) \
|
||||
vfs_decref(VFS_NODE_AS_BASE(node))
|
||||
|
||||
#define vfs_locate(root, path) \
|
||||
vfs_locate(VFS_NODE_AS_BASE(root), path)
|
||||
|
||||
#define vfs_node_repr(node, try_syspath) \
|
||||
vfs_node_repr(VFS_NODE_AS_BASE(node), try_syspath)
|
||||
|
||||
|
||||
void vfs_hook_on_shutdown(VFSShutdownHandler, void *arg);
|
||||
void vfs_print_tree_recurse(SDL_RWops *dest, VFSNode *root, char *prefix, const char *name) attr_nonnull(1, 2, 3, 4);
|
||||
|
|
|
@ -12,9 +12,13 @@
|
|||
#include "private.h"
|
||||
#include "rwops/rwops_ro.h"
|
||||
|
||||
#define WRAPPED(n) ((VFSNode*)(n)->data1)
|
||||
VFS_NODE_TYPE(VFSReadOnlyNode, {
|
||||
VFSNode *wrapped;
|
||||
});
|
||||
|
||||
static char* vfs_ro_repr(VFSNode *node) {
|
||||
#define WRAPPED(n) VFS_NODE_CAST(VFSReadOnlyNode, n)->wrapped
|
||||
|
||||
static char *vfs_ro_repr(VFSNode *node) {
|
||||
char *wrapped_repr = vfs_node_repr(WRAPPED(node), false);
|
||||
char *repr = strjoin("read-only view of ", wrapped_repr, NULL);
|
||||
mem_free(wrapped_repr);
|
||||
|
@ -80,7 +84,7 @@ static SDL_RWops* vfs_ro_open(VFSNode *filenode, VFSOpenMode mode) {
|
|||
return SDL_RWWrapReadOnly(vfs_node_open(WRAPPED(filenode), mode), true);
|
||||
}
|
||||
|
||||
static VFSNodeFuncs vfs_funcs_ro = {
|
||||
VFS_NODE_FUNCS(VFSReadOnlyNode, {
|
||||
.repr = vfs_ro_repr,
|
||||
.query = vfs_ro_query,
|
||||
.free = vfs_ro_free,
|
||||
|
@ -92,9 +96,9 @@ static VFSNodeFuncs vfs_funcs_ro = {
|
|||
.open = vfs_ro_open,
|
||||
.mount = vfs_ro_mount,
|
||||
.unmount = vfs_ro_unmount,
|
||||
};
|
||||
});
|
||||
|
||||
VFSNode* vfs_ro_wrap(VFSNode *base) {
|
||||
VFSNode *vfs_ro_wrap(VFSNode *base) {
|
||||
if(base == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -106,10 +110,9 @@ VFSNode* vfs_ro_wrap(VFSNode *base) {
|
|||
return base;
|
||||
}
|
||||
|
||||
VFSNode *wrapper = vfs_alloc();
|
||||
wrapper->funcs = &vfs_funcs_ro;
|
||||
wrapper->data1 = base;
|
||||
return wrapper;
|
||||
return &VFS_ALLOC(VFSReadOnlyNode, {
|
||||
.wrapped = base,
|
||||
})->as_generic;
|
||||
}
|
||||
|
||||
bool vfs_make_readonly(const char *path) {
|
||||
|
|
|
@ -13,4 +13,4 @@
|
|||
#include "syspath_public.h"
|
||||
|
||||
extern char *vfs_syspath_separators;
|
||||
bool vfs_syspath_init(VFSNode *node, const char *path);
|
||||
VFSNode *vfs_syspath_create(const char *path);
|
||||
|
|
|
@ -16,21 +16,23 @@
|
|||
|
||||
#include "syspath.h"
|
||||
|
||||
#define _path_ data1
|
||||
VFS_NODE_TYPE(VFSSysPathNode, {
|
||||
char *path;
|
||||
});
|
||||
|
||||
char *vfs_syspath_separators = "/";
|
||||
|
||||
static void vfs_syspath_init_internal(VFSNode *node, char *path);
|
||||
static VFSNode *vfs_syspath_create_internal(char *path);
|
||||
|
||||
static void vfs_syspath_free(VFSNode *node) {
|
||||
mem_free(node->_path_);
|
||||
mem_free(VFS_NODE_CAST(VFSSysPathNode, node)->path);
|
||||
}
|
||||
|
||||
static VFSInfo vfs_syspath_query(VFSNode *node) {
|
||||
struct stat fstat;
|
||||
VFSInfo i = {0};
|
||||
|
||||
if(stat(node->_path_, &fstat) >= 0) {
|
||||
if(stat(VFS_NODE_CAST(VFSSysPathNode, node)->path, &fstat) >= 0) {
|
||||
i.exists = true;
|
||||
i.is_dir = S_ISDIR(fstat.st_mode);
|
||||
}
|
||||
|
@ -38,9 +40,10 @@ static VFSInfo vfs_syspath_query(VFSNode *node) {
|
|||
return i;
|
||||
}
|
||||
|
||||
static SDL_RWops* vfs_syspath_open(VFSNode *node, VFSOpenMode mode) {
|
||||
static SDL_RWops *vfs_syspath_open(VFSNode *node, VFSOpenMode mode) {
|
||||
mode &= VFS_MODE_RWMASK;
|
||||
SDL_RWops *rwops = SDL_RWFromFile(node->_path_, mode == VFS_MODE_WRITE ? "w" : "r");
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
SDL_RWops *rwops = SDL_RWFromFile(pnode->path, mode == VFS_MODE_WRITE ? "w" : "r");
|
||||
|
||||
if(!rwops) {
|
||||
vfs_set_error_from_sdl();
|
||||
|
@ -49,18 +52,17 @@ static SDL_RWops* vfs_syspath_open(VFSNode *node, VFSOpenMode mode) {
|
|||
return rwops;
|
||||
}
|
||||
|
||||
static VFSNode* vfs_syspath_locate(VFSNode *node, const char *path) {
|
||||
VFSNode *n = vfs_alloc();
|
||||
vfs_syspath_init_internal(n, strfmt("%s%c%s", (char*)node->_path_, VFS_PATH_SEPARATOR, path));
|
||||
return n;
|
||||
static VFSNode *vfs_syspath_locate(VFSNode *node, const char *path) {
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
return vfs_syspath_create_internal(strjoin(pnode->path, "/", path, NULL));
|
||||
}
|
||||
|
||||
static const char* vfs_syspath_iter(VFSNode *node, void **opaque) {
|
||||
static const char *vfs_syspath_iter(VFSNode *node, void **opaque) {
|
||||
DIR *dir;
|
||||
struct dirent *e;
|
||||
|
||||
if(!*opaque) {
|
||||
*opaque = opendir(node->_path_);
|
||||
*opaque = opendir(VFS_NODE_CAST(VFSSysPathNode, node)->path);
|
||||
}
|
||||
|
||||
if(!(dir = *opaque)) {
|
||||
|
@ -87,12 +89,13 @@ static void vfs_syspath_iter_stop(VFSNode *node, void **opaque) {
|
|||
}
|
||||
}
|
||||
|
||||
static char* vfs_syspath_repr(VFSNode *node) {
|
||||
return strfmt("filesystem path (posix): %s", (char*)node->_path_);
|
||||
static char *vfs_syspath_repr(VFSNode *node) {
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
return strfmt("filesystem path (posix): %s", pnode->path);
|
||||
}
|
||||
|
||||
static char* vfs_syspath_syspath(VFSNode *node) {
|
||||
char *p = strdup(node->_path_);
|
||||
static char *vfs_syspath_syspath(VFSNode *node) {
|
||||
char *p = strdup(VFS_NODE_CAST(VFSSysPathNode, node)->path);
|
||||
vfs_syspath_normalize_inplace(p);
|
||||
return p;
|
||||
}
|
||||
|
@ -102,7 +105,8 @@ static bool vfs_syspath_mkdir(VFSNode *node, const char *subdir) {
|
|||
subdir = "";
|
||||
}
|
||||
|
||||
char *p = strfmt("%s%c%s", (char*)node->_path_, VFS_PATH_SEPARATOR, subdir);
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
char *p = strjoin(pnode->path, VFS_PATH_SEPARATOR_STR, subdir, NULL);
|
||||
bool ok = !mkdir(p, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
|
||||
if(!ok && errno == EEXIST) {
|
||||
|
@ -125,7 +129,7 @@ static bool vfs_syspath_mkdir(VFSNode *node, const char *subdir) {
|
|||
return ok;
|
||||
}
|
||||
|
||||
static VFSNodeFuncs vfs_funcs_syspath = {
|
||||
VFS_NODE_FUNCS(VFSSysPathNode, {
|
||||
.repr = vfs_syspath_repr,
|
||||
.query = vfs_syspath_query,
|
||||
.free = vfs_syspath_free,
|
||||
|
@ -135,7 +139,7 @@ static VFSNodeFuncs vfs_funcs_syspath = {
|
|||
.iter_stop = vfs_syspath_iter_stop,
|
||||
.mkdir = vfs_syspath_mkdir,
|
||||
.open = vfs_syspath_open,
|
||||
};
|
||||
});
|
||||
|
||||
void vfs_syspath_normalize(char *buf, size_t bufsize, const char *path) {
|
||||
char *bufptr = buf;
|
||||
|
@ -174,13 +178,13 @@ void vfs_syspath_join(char *buf, size_t bufsize, const char *parent, const char
|
|||
}
|
||||
}
|
||||
|
||||
static void vfs_syspath_init_internal(VFSNode *node, char *path) {
|
||||
static VFSNode *vfs_syspath_create_internal(char *path) {
|
||||
vfs_syspath_normalize_inplace(path);
|
||||
node->funcs = &vfs_funcs_syspath;
|
||||
node->_path_ = path;
|
||||
return &VFS_ALLOC(VFSSysPathNode, {
|
||||
.path = path,
|
||||
})->as_generic;
|
||||
}
|
||||
|
||||
bool vfs_syspath_init(VFSNode *node, const char *path) {
|
||||
vfs_syspath_init_internal(node, strdup(path));
|
||||
return true;
|
||||
VFSNode *vfs_syspath_create(const char *path) {
|
||||
return vfs_syspath_create_internal(strdup(path));
|
||||
}
|
||||
|
|
|
@ -41,9 +41,8 @@ static bool mkdir_with_parents(VFSNode *n, const char *fspath) {
|
|||
return false;
|
||||
}
|
||||
|
||||
VFSNode *pnode = vfs_alloc();
|
||||
if(!vfs_syspath_init(pnode, p)) {
|
||||
vfs_decref(pnode);
|
||||
VFSNode *pnode;
|
||||
if(!(pnode = vfs_syspath_create(p))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -53,9 +52,9 @@ static bool mkdir_with_parents(VFSNode *n, const char *fspath) {
|
|||
}
|
||||
|
||||
bool vfs_mount_syspath(const char *mountpoint, const char *fspath, uint flags) {
|
||||
VFSNode *rdir = vfs_alloc();
|
||||
VFSNode *rdir;
|
||||
|
||||
if(!vfs_syspath_init(rdir, fspath)) {
|
||||
if(!(rdir = vfs_syspath_create(fspath))) {
|
||||
vfs_set_error("Can't initialize path: %s", vfs_get_error());
|
||||
vfs_decref(rdir);
|
||||
return false;
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
|
||||
#include "syspath.h"
|
||||
|
||||
#define _path_ data1
|
||||
#define _wpath_ data2
|
||||
VFS_NODE_TYPE(VFSSysPathNode, {
|
||||
char *path;
|
||||
wchar_t *wpath;
|
||||
});
|
||||
|
||||
char *vfs_syspath_separators = "\\/";
|
||||
|
||||
|
@ -39,11 +41,12 @@ static WCHAR *WIN_UTF8ToString(char *s) {
|
|||
return buf;
|
||||
}
|
||||
|
||||
static bool vfs_syspath_init_internal(VFSNode *node, char *path);
|
||||
static VFSNode *vfs_syspath_create_internal(char *path);
|
||||
|
||||
static void vfs_syspath_free(VFSNode *node) {
|
||||
mem_free(node->_path_);
|
||||
mem_free(node->_wpath_);
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
mem_free(pnode->path);
|
||||
mem_free(pnode->wpath);
|
||||
}
|
||||
|
||||
static void _vfs_set_error_win32(const char *file, int line) {
|
||||
|
@ -70,14 +73,15 @@ static void _vfs_set_error_win32(const char *file, int line) {
|
|||
#define vfs_set_error_win32() _vfs_set_error_win32(_TAISEI_SRC_FILE, __LINE__)
|
||||
|
||||
static VFSInfo vfs_syspath_query(VFSNode *node) {
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
VFSInfo i = {0};
|
||||
|
||||
if(!PathFileExists(node->_wpath_)) {
|
||||
if(!PathFileExists(pnode->wpath)) {
|
||||
i.exists = false;
|
||||
return i;
|
||||
}
|
||||
|
||||
DWORD attrib = GetFileAttributes(node->_wpath_);
|
||||
DWORD attrib = GetFileAttributes(pnode->wpath);
|
||||
|
||||
if(attrib == INVALID_FILE_ATTRIBUTES) {
|
||||
vfs_set_error_win32();
|
||||
|
@ -90,9 +94,10 @@ static VFSInfo vfs_syspath_query(VFSNode *node) {
|
|||
return i;
|
||||
}
|
||||
|
||||
static SDL_RWops* vfs_syspath_open(VFSNode *node, VFSOpenMode mode) {
|
||||
static SDL_RWops *vfs_syspath_open(VFSNode *node, VFSOpenMode mode) {
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
mode &= VFS_MODE_RWMASK;
|
||||
SDL_RWops *rwops = SDL_RWFromFile(node->_path_, mode == VFS_MODE_WRITE ? "w" : "r");
|
||||
SDL_RWops *rwops = SDL_RWFromFile(pnode->path, mode == VFS_MODE_WRITE ? "w" : "r");
|
||||
|
||||
if(!rwops) {
|
||||
vfs_set_error_from_sdl();
|
||||
|
@ -101,18 +106,9 @@ static SDL_RWops* vfs_syspath_open(VFSNode *node, VFSOpenMode mode) {
|
|||
return rwops;
|
||||
}
|
||||
|
||||
static VFSNode* vfs_syspath_locate(VFSNode *node, const char *path) {
|
||||
VFSNode *n = vfs_alloc();
|
||||
char buf[strlen(path)+1], *base, *name;
|
||||
strcpy(buf, path);
|
||||
vfs_path_split_right(buf, &base, &name);
|
||||
|
||||
if(!vfs_syspath_init_internal(n, strfmt("%s%c%s", (char*)node->_path_, '\\', path))) {
|
||||
vfs_decref(n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return n;
|
||||
static VFSNode *vfs_syspath_locate(VFSNode *node, const char *path) {
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
return vfs_syspath_create_internal(strjoin(pnode->path, "\\", path, NULL));
|
||||
}
|
||||
|
||||
typedef struct VFSWin32IterData {
|
||||
|
@ -121,12 +117,13 @@ typedef struct VFSWin32IterData {
|
|||
} VFSWin32IterData;
|
||||
|
||||
static const char* vfs_syspath_iter(VFSNode *node, void **opaque) {
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
VFSWin32IterData *idata;
|
||||
WIN32_FIND_DATA fdata;
|
||||
HANDLE search_handle;
|
||||
|
||||
if(!*opaque) {
|
||||
char *pattern = strjoin(node->_path_, "\\*.*", NULL);
|
||||
char *pattern = strjoin(pnode->path, "\\*.*", NULL);
|
||||
wchar_t *wpattern = WIN_UTF8ToString(pattern);
|
||||
mem_free(pattern);
|
||||
search_handle = FindFirstFile(wpattern, &fdata);
|
||||
|
@ -185,21 +182,25 @@ static void vfs_syspath_iter_stop(VFSNode *node, void **opaque) {
|
|||
}
|
||||
|
||||
static char* vfs_syspath_repr(VFSNode *node) {
|
||||
return strfmt("filesystem path (win32): %s", (char*)node->_path_);
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
return strfmt("filesystem path (win32): %s", pnode->path);
|
||||
}
|
||||
|
||||
static char* vfs_syspath_syspath(VFSNode *node) {
|
||||
char *p = strdup(node->_path_);
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
char *p = strdup(pnode->path);
|
||||
vfs_syspath_normalize_inplace(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static bool vfs_syspath_mkdir(VFSNode *node, const char *subdir) {
|
||||
auto pnode = VFS_NODE_CAST(VFSSysPathNode, node);
|
||||
|
||||
if(!subdir) {
|
||||
subdir = "";
|
||||
}
|
||||
|
||||
char *p = strfmt("%s%c%s", (char*)node->_path_, '\\', subdir);
|
||||
char *p = strjoin(pnode->path, "\\", subdir, NULL);
|
||||
wchar_t *wp = WIN_UTF8ToString(p);
|
||||
bool ok = CreateDirectory(wp, NULL);
|
||||
DWORD err = GetLastError();
|
||||
|
@ -225,7 +226,7 @@ static bool vfs_syspath_mkdir(VFSNode *node, const char *subdir) {
|
|||
return ok;
|
||||
}
|
||||
|
||||
static VFSNodeFuncs vfs_funcs_syspath = {
|
||||
VFS_NODE_FUNCS(VFSSysPathNode, {
|
||||
.repr = vfs_syspath_repr,
|
||||
.query = vfs_syspath_query,
|
||||
.free = vfs_syspath_free,
|
||||
|
@ -235,7 +236,7 @@ static VFSNodeFuncs vfs_funcs_syspath = {
|
|||
.iter_stop = vfs_syspath_iter_stop,
|
||||
.mkdir = vfs_syspath_mkdir,
|
||||
.open = vfs_syspath_open,
|
||||
};
|
||||
});
|
||||
|
||||
void vfs_syspath_normalize(char *buf, size_t bufsize, const char *path) {
|
||||
// here we just remove redundant separators and convert forward slashes to back slashes.
|
||||
|
@ -308,20 +309,19 @@ static bool vfs_syspath_validate(char *path) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool vfs_syspath_init_internal(VFSNode *node, char *path) {
|
||||
static VFSNode *vfs_syspath_create_internal(char *path) {
|
||||
vfs_syspath_normalize_inplace(path);
|
||||
|
||||
if(!vfs_syspath_validate(path)) {
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->funcs = &vfs_funcs_syspath;
|
||||
node->_path_ = path;
|
||||
node->_wpath_ = WIN_UTF8ToString(path);
|
||||
|
||||
return true;
|
||||
return &VFS_ALLOC(VFSSysPathNode, {
|
||||
.path = path,
|
||||
.wpath = WIN_UTF8ToString(path),
|
||||
})->as_generic;
|
||||
}
|
||||
|
||||
bool vfs_syspath_init(VFSNode *node, const char *path) {
|
||||
return vfs_syspath_init_internal(node, strdup(path));
|
||||
VFSNode *vfs_syspath_create(const char *path) {
|
||||
return vfs_syspath_create_internal(strdup(path));
|
||||
}
|
||||
|
|
|
@ -10,12 +10,16 @@
|
|||
|
||||
#include "union.h"
|
||||
|
||||
#define _members_ data1
|
||||
#define _primary_member_ data2
|
||||
// TODO rewrite this to use more sensible data structures
|
||||
|
||||
static bool vfs_union_mount_internal(VFSNode *unode, const char *mountpoint, VFSNode *mountee, VFSInfo info, bool seterror);
|
||||
VFS_NODE_TYPE(VFSUnionNode, {
|
||||
ListContainer *members;
|
||||
VFSNode *primary_member;
|
||||
});
|
||||
|
||||
static void* vfs_union_delete_callback(List **list, List *elem, void *arg) {
|
||||
static bool vfs_union_mount_internal(VFSUnionNode *unode, const char *mountpoint, VFSNode *mountee, VFSInfo info, bool seterror);
|
||||
|
||||
static void *vfs_union_delete_callback(List **list, List *elem, void *arg) {
|
||||
ListContainer *c = (ListContainer*)elem;
|
||||
VFSNode *n = c->data;
|
||||
vfs_decref(n);
|
||||
|
@ -24,15 +28,16 @@ static void* vfs_union_delete_callback(List **list, List *elem, void *arg) {
|
|||
}
|
||||
|
||||
static void vfs_union_free(VFSNode *node) {
|
||||
list_foreach((ListContainer**)&node->_members_, vfs_union_delete_callback, NULL);
|
||||
auto unode = VFS_NODE_CAST(VFSUnionNode, node);
|
||||
list_foreach(&unode->members, vfs_union_delete_callback, NULL);
|
||||
}
|
||||
|
||||
static VFSNode* vfs_union_locate(VFSNode *node, const char *path) {
|
||||
VFSNode *u = vfs_alloc();
|
||||
vfs_union_init(u); // uniception!
|
||||
static VFSNode *vfs_union_locate(VFSNode *node, const char *path) {
|
||||
auto unode = VFS_NODE_CAST(VFSUnionNode, node);
|
||||
auto subunion = VFS_NODE_CAST(VFSUnionNode, vfs_union_create());
|
||||
|
||||
VFSInfo prim_info = VFSINFO_ERROR;
|
||||
ListContainer *first = node->_members_;
|
||||
ListContainer *first = unode->members;
|
||||
ListContainer *last = first;
|
||||
ListContainer *c;
|
||||
|
||||
|
@ -47,7 +52,7 @@ static VFSNode* vfs_union_locate(VFSNode *node, const char *path) {
|
|||
if(o) {
|
||||
VFSInfo i = vfs_node_query(o);
|
||||
|
||||
if(vfs_union_mount_internal(u, NULL, o, i, false)) {
|
||||
if(vfs_union_mount_internal(subunion, NULL, o, i, false)) {
|
||||
prim_info = i;
|
||||
} else {
|
||||
vfs_decref(o);
|
||||
|
@ -55,28 +60,28 @@ static VFSNode* vfs_union_locate(VFSNode *node, const char *path) {
|
|||
}
|
||||
}
|
||||
|
||||
if(u->_primary_member_) {
|
||||
if(!((List*)(u->_members_))->next || !prim_info.is_dir) {
|
||||
if(subunion->primary_member) {
|
||||
if(!subunion->members->next || !prim_info.is_dir) {
|
||||
// the temporary union contains just one member, or doesn't represent a directory
|
||||
// in those cases it's just a useless wrapper, so let's just return the primary member directly
|
||||
VFSNode *n = u->_primary_member_;
|
||||
VFSNode *n = subunion->primary_member;
|
||||
|
||||
// incref primary member to keep it alive
|
||||
vfs_incref(n);
|
||||
|
||||
// destroy the wrapper, also decrefs n
|
||||
vfs_decref(u);
|
||||
vfs_decref(subunion);
|
||||
|
||||
// no need to incref n, vfs_locate did that for us earlier
|
||||
return n;
|
||||
}
|
||||
} else {
|
||||
// all in vain...
|
||||
vfs_decref(u);
|
||||
u = NULL;
|
||||
vfs_decref(subunion);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return u;
|
||||
return &subunion->as_generic;
|
||||
}
|
||||
|
||||
typedef struct VFSUnionIterData {
|
||||
|
@ -86,12 +91,13 @@ typedef struct VFSUnionIterData {
|
|||
} VFSUnionIterData;
|
||||
|
||||
static const char* vfs_union_iter(VFSNode *node, void **opaque) {
|
||||
auto unode = VFS_NODE_CAST(VFSUnionNode, node);
|
||||
VFSUnionIterData *i = *opaque;
|
||||
const char *r = NULL;
|
||||
|
||||
if(!i) {
|
||||
i = ALLOC(typeof(*i));
|
||||
i->current = node->_members_;
|
||||
i->current = unode->members;
|
||||
i->opaque = NULL;
|
||||
ht_create(&i->visited);
|
||||
*opaque = i;
|
||||
|
@ -131,8 +137,10 @@ static void vfs_union_iter_stop(VFSNode *node, void **opaque) {
|
|||
}
|
||||
|
||||
static VFSInfo vfs_union_query(VFSNode *node) {
|
||||
if(node->_primary_member_) {
|
||||
VFSInfo i = vfs_node_query(node->_primary_member_);
|
||||
auto unode = VFS_NODE_CAST(VFSUnionNode, node);
|
||||
|
||||
if(unode->primary_member) {
|
||||
VFSInfo i = vfs_node_query(unode->primary_member);
|
||||
// can't trust the primary member here, others might be writable'
|
||||
i.is_readonly = false;
|
||||
return i;
|
||||
|
@ -142,7 +150,7 @@ static VFSInfo vfs_union_query(VFSNode *node) {
|
|||
return VFSINFO_ERROR;
|
||||
}
|
||||
|
||||
static bool vfs_union_mount_internal(VFSNode *unode, const char *mountpoint, VFSNode *mountee, VFSInfo info, bool seterror) {
|
||||
static bool vfs_union_mount_internal(VFSUnionNode *unode, const char *mountpoint, VFSNode *mountee, VFSInfo info, bool seterror) {
|
||||
if(!info.exists) {
|
||||
if(seterror) {
|
||||
char *r = vfs_node_repr(mountee, true);
|
||||
|
@ -160,13 +168,15 @@ static bool vfs_union_mount_internal(VFSNode *unode, const char *mountpoint, VFS
|
|||
return false;
|
||||
}
|
||||
|
||||
list_push((ListContainer**)&unode->_members_, list_wrap_container(mountee));
|
||||
unode->_primary_member_ = mountee;
|
||||
list_push(&unode->members, list_wrap_container(mountee));
|
||||
unode->primary_member = mountee;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool vfs_union_mount(VFSNode *unode, const char *mountpoint, VFSNode *mountee) {
|
||||
static bool vfs_union_mount(VFSNode *node, const char *mountpoint, VFSNode *mountee) {
|
||||
auto unode = VFS_NODE_CAST(VFSUnionNode, node);
|
||||
|
||||
if(mountpoint) {
|
||||
vfs_set_error("Attempted to use a named mountpoint '%s' on a union", mountpoint);
|
||||
return false;
|
||||
|
@ -175,8 +185,9 @@ static bool vfs_union_mount(VFSNode *unode, const char *mountpoint, VFSNode *mou
|
|||
return vfs_union_mount_internal(unode, NULL, mountee, vfs_node_query(mountee), true);
|
||||
}
|
||||
|
||||
static SDL_RWops* vfs_union_open(VFSNode *unode, VFSOpenMode mode) {
|
||||
VFSNode *n = unode->_primary_member_;
|
||||
static SDL_RWops* vfs_union_open(VFSNode *node, VFSOpenMode mode) {
|
||||
auto unode = VFS_NODE_CAST(VFSUnionNode, node);
|
||||
VFSNode *n = unode->primary_member;
|
||||
|
||||
if(n) {
|
||||
return vfs_node_open(n, mode);
|
||||
|
@ -187,10 +198,11 @@ static SDL_RWops* vfs_union_open(VFSNode *unode, VFSOpenMode mode) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static char* vfs_union_repr(VFSNode *node) {
|
||||
static char *vfs_union_repr(VFSNode *node) {
|
||||
auto unode = VFS_NODE_CAST(VFSUnionNode, node);
|
||||
char *mlist = strdup("union: "), *r;
|
||||
|
||||
for(ListContainer *c = node->_members_; c; c = c->next) {
|
||||
for(ListContainer *c = unode->members; c; c = c->next) {
|
||||
VFSNode *n = c->data;
|
||||
|
||||
strappend(&mlist, r = vfs_node_repr(n, false));
|
||||
|
@ -204,8 +216,9 @@ static char* vfs_union_repr(VFSNode *node) {
|
|||
return mlist;
|
||||
}
|
||||
|
||||
static char* vfs_union_syspath(VFSNode *node) {
|
||||
VFSNode *n = node->_primary_member_;
|
||||
static char *vfs_union_syspath(VFSNode *node) {
|
||||
auto unode = VFS_NODE_CAST(VFSUnionNode, node);
|
||||
VFSNode *n = unode->primary_member;
|
||||
|
||||
if(n) {
|
||||
return vfs_node_syspath(n);
|
||||
|
@ -216,7 +229,8 @@ static char* vfs_union_syspath(VFSNode *node) {
|
|||
}
|
||||
|
||||
static bool vfs_union_mkdir(VFSNode *node, const char *subdir) {
|
||||
VFSNode *n = node->_primary_member_;
|
||||
auto unode = VFS_NODE_CAST(VFSUnionNode, node);
|
||||
VFSNode *n = unode->primary_member;
|
||||
|
||||
if(n) {
|
||||
return vfs_node_mkdir(n, subdir);
|
||||
|
@ -226,7 +240,7 @@ static bool vfs_union_mkdir(VFSNode *node, const char *subdir) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static VFSNodeFuncs vfs_funcs_union = {
|
||||
VFS_NODE_FUNCS(VFSUnionNode, {
|
||||
.repr = vfs_union_repr,
|
||||
.query = vfs_union_query,
|
||||
.free = vfs_union_free,
|
||||
|
@ -237,9 +251,12 @@ static VFSNodeFuncs vfs_funcs_union = {
|
|||
.iter_stop = vfs_union_iter_stop,
|
||||
.mkdir = vfs_union_mkdir,
|
||||
.open = vfs_union_open,
|
||||
};
|
||||
});
|
||||
|
||||
void vfs_union_init(VFSNode *node) {
|
||||
node->funcs = &vfs_funcs_union;
|
||||
node->data1 = node->data2 = NULL;
|
||||
VFSNode *vfs_union_create(void) {
|
||||
return &VFS_ALLOC(VFSUnionNode)->as_generic;
|
||||
}
|
||||
|
||||
bool vfs_create_union_mountpoint(const char *mountpoint) {
|
||||
return vfs_mount_or_decref(vfs_root, mountpoint, vfs_union_create());
|
||||
}
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
#include "private.h"
|
||||
#include "union_public.h"
|
||||
|
||||
void vfs_union_init(VFSNode *node);
|
||||
VFSNode *vfs_union_create(void);
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "union.h"
|
||||
|
||||
bool vfs_create_union_mountpoint(const char *mountpoint) {
|
||||
VFSNode *unode = vfs_alloc();
|
||||
vfs_union_init(unode);
|
||||
return vfs_mount_or_decref(vfs_root, mountpoint, unode);
|
||||
}
|
|
@ -10,39 +10,44 @@
|
|||
|
||||
#include "vdir.h"
|
||||
|
||||
#define VDIR_TABLE(vdir) ((ht_str2ptr_t*)((vdir)->data1))
|
||||
VFS_NODE_TYPE(VFSVDirNode, {
|
||||
ht_str2ptr_t table;
|
||||
});
|
||||
|
||||
static void vfs_vdir_attach_node(VFSNode *vdir, const char *name, VFSNode *node) {
|
||||
VFSNode *oldnode = ht_get(VDIR_TABLE(vdir), name, NULL);
|
||||
static void vfs_vdir_attach_node(VFSNode *node, const char *name, VFSNode *subnode) {
|
||||
auto vdir = VFS_NODE_CAST(VFSVDirNode, node);
|
||||
VFSNode *oldnode = ht_get(&vdir->table, name, NULL);
|
||||
|
||||
if(oldnode) {
|
||||
vfs_decref(oldnode);
|
||||
}
|
||||
|
||||
ht_set(VDIR_TABLE(vdir), name, node);
|
||||
ht_set(&vdir->table, name, subnode);
|
||||
}
|
||||
|
||||
static VFSNode* vfs_vdir_locate(VFSNode *vdir, const char *path) {
|
||||
VFSNode *node;
|
||||
static VFSNode *vfs_vdir_locate(VFSNode *node, const char *path) {
|
||||
auto vdir = VFS_NODE_CAST(VFSVDirNode, node);
|
||||
VFSNode *subnode;
|
||||
char mutpath[strlen(path)+1];
|
||||
char *primpath, *subpath;
|
||||
|
||||
strcpy(mutpath, path);
|
||||
vfs_path_split_left(mutpath, &primpath, &subpath);
|
||||
|
||||
if((node = ht_get(VDIR_TABLE(vdir), mutpath, NULL))) {
|
||||
return vfs_locate(node, subpath);
|
||||
if((subnode = ht_get(&vdir->table, primpath, NULL))) {
|
||||
return vfs_locate(subnode, subpath);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* vfs_vdir_iter(VFSNode *vdir, void **opaque) {
|
||||
static const char *vfs_vdir_iter(VFSNode *node, void **opaque) {
|
||||
auto vdir = VFS_NODE_CAST(VFSVDirNode, node);
|
||||
ht_str2ptr_iter_t *iter = *opaque;
|
||||
|
||||
if(!iter) {
|
||||
iter = *opaque = ALLOC(typeof(*iter));
|
||||
ht_iter_begin(VDIR_TABLE(vdir), iter);
|
||||
ht_iter_begin(&vdir->table, iter);
|
||||
} else {
|
||||
ht_iter_next(iter);
|
||||
}
|
||||
|
@ -50,7 +55,7 @@ static const char* vfs_vdir_iter(VFSNode *vdir, void **opaque) {
|
|||
return iter->has_data ? iter->key : NULL;
|
||||
}
|
||||
|
||||
static void vfs_vdir_iter_stop(VFSNode *vdir, void **opaque) {
|
||||
static void vfs_vdir_iter_stop(VFSNode *node, void **opaque) {
|
||||
if(*opaque) {
|
||||
ht_iter_end((ht_str2ptr_iter_t*)*opaque);
|
||||
mem_free(*opaque);
|
||||
|
@ -58,26 +63,26 @@ static void vfs_vdir_iter_stop(VFSNode *vdir, void **opaque) {
|
|||
}
|
||||
}
|
||||
|
||||
static VFSInfo vfs_vdir_query(VFSNode *vdir) {
|
||||
static VFSInfo vfs_vdir_query(VFSNode *node) {
|
||||
return (VFSInfo) {
|
||||
.exists = true,
|
||||
.is_dir = true,
|
||||
};
|
||||
}
|
||||
|
||||
static void vfs_vdir_free(VFSNode *vdir) {
|
||||
ht_str2ptr_t *ht = VDIR_TABLE(vdir);
|
||||
static void vfs_vdir_free(VFSNode *node) {
|
||||
auto vdir = VFS_NODE_CAST(VFSVDirNode, node);
|
||||
ht_str2ptr_t *ht = &vdir->table;
|
||||
ht_str2ptr_iter_t iter;
|
||||
|
||||
ht_iter_begin(ht, &iter);
|
||||
|
||||
for(; iter.has_data; ht_iter_next(&iter)) {
|
||||
vfs_decref(iter.value);
|
||||
vfs_decref((VFSNode*)iter.value);
|
||||
}
|
||||
|
||||
ht_iter_end(&iter);
|
||||
ht_destroy(ht);
|
||||
mem_free(ht);
|
||||
}
|
||||
|
||||
static bool vfs_vdir_mount(VFSNode *vdir, const char *mountpoint, VFSNode *subtree) {
|
||||
|
@ -90,37 +95,29 @@ static bool vfs_vdir_mount(VFSNode *vdir, const char *mountpoint, VFSNode *subtr
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool vfs_vdir_unmount(VFSNode *vdir, const char *mountpoint) {
|
||||
static bool vfs_vdir_unmount(VFSNode *node, const char *mountpoint) {
|
||||
auto vdir = VFS_NODE_CAST(VFSVDirNode, node);
|
||||
VFSNode *mountee;
|
||||
|
||||
if(!(mountee = ht_get(VDIR_TABLE(vdir), mountpoint, NULL))) {
|
||||
if(!(mountee = ht_get(&vdir->table, mountpoint, NULL))) {
|
||||
vfs_set_error("Mountpoint '%s' doesn't exist", mountpoint);
|
||||
return false;
|
||||
}
|
||||
|
||||
ht_unset(VDIR_TABLE(vdir), mountpoint);
|
||||
ht_unset(&vdir->table, mountpoint);
|
||||
vfs_decref(mountee);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool vfs_vdir_mkdir(VFSNode *node, const char *subdir) {
|
||||
if(!subdir) {
|
||||
vfs_set_error("Virtual directory trying to create itself? How did you even get here?");
|
||||
return false;
|
||||
}
|
||||
|
||||
VFSNode *subnode = vfs_alloc();
|
||||
vfs_vdir_init(subnode);
|
||||
vfs_vdir_mount(node, subdir, subnode);
|
||||
|
||||
return true;
|
||||
return vfs_vdir_mount(node, NOT_NULL(subdir), vfs_vdir_create());
|
||||
}
|
||||
|
||||
static char* vfs_vdir_repr(VFSNode *node) {
|
||||
static char *vfs_vdir_repr(VFSNode *node) {
|
||||
return strdup("virtual directory");
|
||||
}
|
||||
|
||||
static VFSNodeFuncs vfs_funcs_vdir = {
|
||||
VFS_NODE_FUNCS(VFSVDirNode, {
|
||||
.repr = vfs_vdir_repr,
|
||||
.query = vfs_vdir_query,
|
||||
.free = vfs_vdir_free,
|
||||
|
@ -130,9 +127,10 @@ static VFSNodeFuncs vfs_funcs_vdir = {
|
|||
.iter = vfs_vdir_iter,
|
||||
.iter_stop = vfs_vdir_iter_stop,
|
||||
.mkdir = vfs_vdir_mkdir,
|
||||
};
|
||||
});
|
||||
|
||||
void vfs_vdir_init(VFSNode *node) {
|
||||
node->funcs = &vfs_funcs_vdir;
|
||||
node->data1 = ht_str2ptr_new();
|
||||
VFSNode *vfs_vdir_create(void) {
|
||||
auto vdir = VFS_ALLOC(VFSVDirNode);
|
||||
ht_create(&vdir->table);
|
||||
return &vdir->as_generic;
|
||||
}
|
||||
|
|
|
@ -11,4 +11,5 @@
|
|||
|
||||
#include "private.h"
|
||||
|
||||
void vfs_vdir_init(VFSNode *node);
|
||||
VFSNode *vfs_vdir_create(void)
|
||||
attr_returns_allocated;
|
||||
|
|
|
@ -14,10 +14,9 @@
|
|||
#define LOG_SDL_ERROR log_debug("SDL error: %s", SDL_GetError())
|
||||
|
||||
static zip_int64_t vfs_zipfile_srcfunc(void *userdata, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
|
||||
VFSNode *zipnode = userdata;
|
||||
VFSZipFileData *zdata = zipnode->data1;
|
||||
VFSZipNode *zipnode = userdata;
|
||||
VFSZipFileTLS *tls = vfs_zipfile_get_tls(zipnode, false);
|
||||
VFSNode *source = zdata->source;
|
||||
VFSNode *source = zipnode->source;
|
||||
zip_int64_t ret = -1;
|
||||
|
||||
if(!tls) {
|
||||
|
@ -134,24 +133,19 @@ static void vfs_zipfile_free_tls(VFSZipFileTLS *tls) {
|
|||
|
||||
static void vfs_zipfile_free(VFSNode *node) {
|
||||
if(node) {
|
||||
VFSZipFileData *zdata = node->data1;
|
||||
auto znode = VFS_NODE_CAST(VFSZipNode, node);
|
||||
VFSZipFileTLS *tls = SDL_TLSGet(znode->tls_id);
|
||||
|
||||
if(zdata) {
|
||||
SDL_TLSID tls_id = ((VFSZipFileData*)node->data1)->tls_id;
|
||||
VFSZipFileTLS *tls = SDL_TLSGet(tls_id);
|
||||
|
||||
if(tls) {
|
||||
vfs_zipfile_free_tls(tls);
|
||||
SDL_TLSSet(tls_id, NULL, NULL);
|
||||
}
|
||||
|
||||
if(zdata->source) {
|
||||
vfs_decref(zdata->source);
|
||||
}
|
||||
|
||||
ht_destroy(&zdata->pathmap);
|
||||
mem_free(zdata);
|
||||
if(tls) {
|
||||
vfs_zipfile_free_tls(tls);
|
||||
SDL_TLSSet(znode->tls_id, NULL, NULL);
|
||||
}
|
||||
|
||||
if(znode->source) {
|
||||
vfs_decref(znode->source);
|
||||
}
|
||||
|
||||
ht_destroy(&znode->pathmap);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,25 +157,24 @@ static VFSInfo vfs_zipfile_query(VFSNode *node) {
|
|||
};
|
||||
}
|
||||
|
||||
static char* vfs_zipfile_syspath(VFSNode *node) {
|
||||
VFSZipFileData *zdata = node->data1;
|
||||
return vfs_node_syspath(zdata->source);
|
||||
static char *vfs_zipfile_syspath(VFSNode *node) {
|
||||
return vfs_node_syspath(VFS_NODE_CAST(VFSZipNode, node)->source);
|
||||
}
|
||||
|
||||
static char* vfs_zipfile_repr(VFSNode *node) {
|
||||
VFSZipFileData *zdata = node->data1;
|
||||
char *srcrepr = vfs_node_repr(zdata->source, false);
|
||||
char *ziprepr = strfmt("zip archive %s", srcrepr);
|
||||
static char *vfs_zipfile_repr(VFSNode *node) {
|
||||
auto znode = VFS_NODE_CAST(VFSZipNode, node);
|
||||
char *srcrepr = vfs_node_repr(znode->source, false);
|
||||
char *ziprepr = strjoin("zip archive ", srcrepr, NULL);
|
||||
mem_free(srcrepr);
|
||||
return ziprepr;
|
||||
}
|
||||
|
||||
static VFSNode* vfs_zipfile_locate(VFSNode *node, const char *path) {
|
||||
VFSZipFileTLS *tls = vfs_zipfile_get_tls(node, true);
|
||||