3169b16d10
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.
136 lines
3.1 KiB
C
136 lines
3.1 KiB
C
/*
|
|
* 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 "vdir.h"
|
|
|
|
VFS_NODE_TYPE(VFSVDirNode, {
|
|
ht_str2ptr_t table;
|
|
});
|
|
|
|
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, name, subnode);
|
|
}
|
|
|
|
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((subnode = ht_get(&vdir->table, primpath, NULL))) {
|
|
return vfs_locate(subnode, subpath);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
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, iter);
|
|
} else {
|
|
ht_iter_next(iter);
|
|
}
|
|
|
|
return iter->has_data ? iter->key : NULL;
|
|
}
|
|
|
|
static void vfs_vdir_iter_stop(VFSNode *node, void **opaque) {
|
|
if(*opaque) {
|
|
ht_iter_end((ht_str2ptr_iter_t*)*opaque);
|
|
mem_free(*opaque);
|
|
*opaque = NULL;
|
|
}
|
|
}
|
|
|
|
static VFSInfo vfs_vdir_query(VFSNode *node) {
|
|
return (VFSInfo) {
|
|
.exists = true,
|
|
.is_dir = true,
|
|
};
|
|
}
|
|
|
|
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((VFSNode*)iter.value);
|
|
}
|
|
|
|
ht_iter_end(&iter);
|
|
ht_destroy(ht);
|
|
}
|
|
|
|
static bool vfs_vdir_mount(VFSNode *vdir, const char *mountpoint, VFSNode *subtree) {
|
|
if(!mountpoint) {
|
|
vfs_set_error("Virtual directories don't support merging");
|
|
return false;
|
|
}
|
|
|
|
vfs_vdir_attach_node(vdir, mountpoint, subtree);
|
|
return true;
|
|
}
|
|
|
|
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, mountpoint, NULL))) {
|
|
vfs_set_error("Mountpoint '%s' doesn't exist", mountpoint);
|
|
return false;
|
|
}
|
|
|
|
ht_unset(&vdir->table, mountpoint);
|
|
vfs_decref(mountee);
|
|
return true;
|
|
}
|
|
|
|
static bool vfs_vdir_mkdir(VFSNode *node, const char *subdir) {
|
|
return vfs_vdir_mount(node, NOT_NULL(subdir), vfs_vdir_create());
|
|
}
|
|
|
|
static char *vfs_vdir_repr(VFSNode *node) {
|
|
return strdup("virtual directory");
|
|
}
|
|
|
|
VFS_NODE_FUNCS(VFSVDirNode, {
|
|
.repr = vfs_vdir_repr,
|
|
.query = vfs_vdir_query,
|
|
.free = vfs_vdir_free,
|
|
.mount = vfs_vdir_mount,
|
|
.unmount = vfs_vdir_unmount,
|
|
.locate = vfs_vdir_locate,
|
|
.iter = vfs_vdir_iter,
|
|
.iter_stop = vfs_vdir_iter_stop,
|
|
.mkdir = vfs_vdir_mkdir,
|
|
});
|
|
|
|
VFSNode *vfs_vdir_create(void) {
|
|
auto vdir = VFS_ALLOC(VFSVDirNode);
|
|
ht_create(&vdir->table);
|
|
return &vdir->as_generic;
|
|
}
|