From 0d0413b264b904efc01298210cd75dabff176fc0 Mon Sep 17 00:00:00 2001 From: David Sheets Date: Fri, 3 Jun 2016 16:31:49 +0100 Subject: [PATCH] transfused: introduce automatic mount point preparation Mount points are now made dynamically if either the leaf doesn't exist or the leaf has no children. Any proper prefix of the target mount point may or may not exist prior to mounting. Signed-off-by: David Sheets --- alpine/packages/transfused/transfused.c | 80 +++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/alpine/packages/transfused/transfused.c b/alpine/packages/transfused/transfused.c index 9f6d8780d..ed19d07fe 100644 --- a/alpine/packages/transfused/transfused.c +++ b/alpine/packages/transfused/transfused.c @@ -4,10 +4,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -438,6 +440,82 @@ void start_writer(connection_t * connection, int fuse) { connection->mount_point); } +char * alloc_dirname(connection_t * conn, char * path) { + size_t len = strlen(path) + 1; + char * input = must_malloc("alloc_dirname input", len); + char * output = must_malloc("alloc_dirname output", len); + char * dir; + strlcpy(input, path, len); + + dir = dirname(input); + if (dir == NULL) + die(1, conn->params, "", "Couldn't get dirname of %s: ", path); + strcpy(output, dir); + + free(input); + return output; +} + +void mkdir_p(connection_t * conn, char * path) { + char * parent; + + if (mkdir(path, 0700)) switch (errno) { + case ENOENT: + parent = alloc_dirname(conn, path); + mkdir_p(conn, parent); + free(parent); + if (mkdir(path, 0700)) + die(1, conn->params, "", "Couldn't create directory %s: ", path); + break; + default: + die(1, conn->params, "", "Couldn't create directory %s: ", path); + } +} + +int is_next_child_ok(connection_t * conn, DIR * dir) { + struct dirent * child; + + errno = 0; + child = readdir(dir); + if (child == NULL) { + if (errno != 0) + die(1, conn->params, "", "Couldn't read mount point %s: ", + conn->mount_point); + else return 0; + } else + if (strcmp(".", child->d_name) != 0 && strcmp("..", child->d_name) != 0) + die(1, conn->params, NULL, "Couldn't mount on %s: %s exists", + conn->mount_point, child->d_name); + return 1; +} + +// The leaf may exist but must be empty. Any proper path prefix may exist. +void prepare_mount_point(connection_t * conn) { + DIR * dir; + char * mount_point = conn->mount_point; + + dir = opendir(mount_point); + if (dir != NULL) { + if (is_next_child_ok(conn, dir)) + if (is_next_child_ok(conn, dir)) { + if (is_next_child_ok(conn, dir)) + die(1, conn->params, "", "Couldn't mount on %s: not empty", + mount_point); + else return; + } + if (closedir(dir)) + die(1, conn->params, "", "Couldn't close mount point %s: ", mount_point); + } else { + switch (errno) { + case ENOENT: break; + default: + die(1, conn->params, "", "Couldn't open mount point %s: ", mount_point); + } + } + + mkdir_p(conn, mount_point); +} + void * mount_connection(connection_t * conn) { int optc; char ** optv; @@ -451,6 +529,8 @@ void * mount_connection(connection_t * conn) { optv = read_opts(conn, buf); + prepare_mount_point(conn); + for (optc = 0; optv[optc] != NULL; optc++) {} fuse = get_fuse_sock(conn, optc, optv);