summaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authordzwdz2024-07-20 23:17:36 +0200
committerdzwdz2024-07-20 23:17:36 +0200
commit1fc2d9c88af77c3af81b6bd461e6b019b97d2dbb (patch)
tree56d19935958983882872495f556bdb74c8ae26b8 /src/cmd
parente88aee660ea668cc96d8a5a11060b6e02b2f0fd7 (diff)
*: moving files
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/mv.c17
-rw-r--r--src/cmd/tmpfs.c71
2 files changed, 87 insertions, 1 deletions
diff --git a/src/cmd/mv.c b/src/cmd/mv.c
new file mode 100644
index 0000000..e7bcc46
--- /dev/null
+++ b/src/cmd/mv.c
@@ -0,0 +1,17 @@
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+int
+main(int argc, const char *argv[])
+{
+ if (argc != 3) {
+ fprintf(stderr, "usage: mv from to\n");
+ return 1;
+ }
+
+ if (rename(argv[1], argv[2]) < 0) {
+ fprintf(stderr, "mv: %s\n", strerror(errno));
+ return 1;
+ }
+}
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 <assert.h>
#include <camellia/flags.h>
#include <camellia/fs/dir.h>
#include <camellia/fs/misc.h>
@@ -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;
}