From 1fc2d9c88af77c3af81b6bd461e6b019b97d2dbb Mon Sep 17 00:00:00 2001 From: dzwdz Date: Sat, 20 Jul 2024 23:17:36 +0200 Subject: *: moving files --- src/cmd/tmpfs.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'src/cmd/tmpfs.c') diff --git a/src/cmd/tmpfs.c b/src/cmd/tmpfs.c index 6d58790..a031a44 100644 --- a/src/cmd/tmpfs.c +++ b/src/cmd/tmpfs.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -38,8 +39,10 @@ static struct node *tmpfs_open(const char *path, struct ufs_request *req); static struct node *node_getchild(struct node *parent, const char *name, size_t len); /** Corresponds to close(); drops a reference. */ static void node_close(struct node *node); +static long node_move(struct node *from, struct node *to); /** Removes a file. It's kept in memory until all the open handles are closed. */ static long node_remove(struct node *node); +static void node_sanity(struct node *node, struct node **from); static struct node *node_getchild(struct node *parent, const char *name, size_t len) { @@ -100,27 +103,84 @@ static struct node *tmpfs_open(const char *path, struct ufs_request *req) { static void node_close(struct node *node) { node->open--; - if (!node->ref && node != &node_root && node->open == 0) { + if (node->ref == NULL && node != &node_root && node->open == 0) { + if (node->name) { + free(node->name); + } free(node->buf); free(node); } } +static long node_move(struct node *from, struct node *to) { + if (from == &node_root || to == &node_root) { + return -1; + } + + assert(from && to); + /* 1. unlink from */ + if (from->ref) { + assert(*from->ref == from); + if (from->sibling) { + from->sibling->ref = from->ref; + *from->sibling->ref = from->sibling; + } else { + *from->ref = NULL; + } + from->sibling = NULL; + from->ref = NULL; + } else { + assert(from->sibling == NULL); + } + + /* 2. link *from in place of *to + * note that there's still a reference to *to in the handle */ + if (to->ref) { + assert(*to->ref == to); + from->sibling = to->sibling; + if (from->sibling) { + from->sibling->ref = &from->sibling; + } + from->ref = to->ref; + *from->ref = from; + + to->ref = NULL; + to->sibling = NULL; + } + from->name = to->name; + from->namelen = to->namelen; + to->name = NULL; + to->namelen = 0; + return 0; +} + static long node_remove(struct node *node) { if (node == &node_root) return -1; if (!node->ref) return -1; if (node->child) return -ENOTEMPTY; *node->ref = node->sibling; node->ref = NULL; + node->sibling = NULL; node_close(node); return 0; } +static void node_sanity(struct node *node, struct node **from) { + if (node == NULL) return; + if (node != &node_root && node->ref != from) { + assert(false); + } + node_sanity(node->sibling, &node->sibling); + node_sanity(node->child, &node->child); +} + int main(void) { const size_t buflen = 4096; char *buf = malloc(buflen); if (!buf) return -1; + node_sanity(&node_root, NULL); + for (;;) { struct ufs_request req; hid_t reqh = ufs_wait(buf, buflen, &req); @@ -189,10 +249,19 @@ int main(void) { _sys_fs_respond(reqh, NULL, -1, 0); break; + case VFSOP_DUPLEX: + if (req.flags == DUPLEX_REMOVE) { + _sys_fs_respond(reqh, NULL, node_move(req.id, req.id2), 0); + } else { + _sys_fs_respond(reqh, NULL, -ENOSYS, 0); + } + break; + default: _sys_fs_respond(reqh, NULL, -1, 0); break; } + node_sanity(&node_root, NULL); } return 1; } -- cgit v1.2.3