WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-tools

[Xen-tools] [PATCH] Xenstore mkdir/write implicitly create directories

To: Xen Tools <xen-tools@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-tools] [PATCH] Xenstore mkdir/write implicitly create directories
From: Rusty Russell <rusty@xxxxxxxxxxxxxxx>
Date: Sun, 21 Aug 2005 18:39:21 +1000
Delivery-date: Sun, 21 Aug 2005 22:22:35 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-tools-request@lists.xensource.com?subject=help>
List-id: Xen control tools developers <xen-tools.lists.xensource.com>
List-post: <mailto:xen-tools@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-tools>, <mailto:xen-tools-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-tools>, <mailto:xen-tools-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-tools-bounces@xxxxxxxxxxxxxxxxxxx
Hi Anthony,

        You asked for this a while ago.  This changes the xenstore so that
mkdir and write implicitly create subdirs.

Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx>

# HG changeset patch
# User Rusty Russell <rusty@xxxxxxxxxxxxxxx>
# Node ID 7522ea52b829e2d18cea672da9851f8e7ef6f269
# Parent  07b986fec159c8bd18f7f109ca78c5b1250ee07c
Make directories implicitly for mkdir and write.
Change directory code: make then move (safer than delete-if-fail).

diff -r 07b986fec159 -r 7522ea52b829 tools/xenstore/testsuite/02directory.test
--- a/tools/xenstore/testsuite/02directory.test Sun Aug 21 06:29:47 2005
+++ b/tools/xenstore/testsuite/02directory.test Sun Aug 21 06:38:22 2005
@@ -32,3 +32,16 @@
 mkdir /dir
 expect mkdir failed: File exists
 mkdir /dir/test2
+
+# Mkdir implicitly creates directories.
+mkdir /dir/1/2/3/4
+expect test2
+expect 1
+dir /dir
+expect 2
+dir /dir/1
+expect 3
+dir /dir/1/2
+expect 4
+dir /dir/1/2/3
+dir /dir/1/2/3/4
diff -r 07b986fec159 -r 7522ea52b829 tools/xenstore/testsuite/03write.test
--- a/tools/xenstore/testsuite/03write.test     Sun Aug 21 06:29:47 2005
+++ b/tools/xenstore/testsuite/03write.test     Sun Aug 21 06:38:22 2005
@@ -18,3 +18,22 @@
 write /test create contents3
 expect contents3
 read /test
+
+# Write should implicitly create directories
+write /dir/test create contents
+expect test
+dir /dir
+expect contents
+read /dir/test
+write /dir/1/2/3/4 excl contents4
+expect test
+expect 1
+dir /dir
+expect 2
+dir /dir/1
+expect 3
+dir /dir/1/2
+expect 4
+dir /dir/1/2/3
+expect contents4
+read /dir/1/2/3/4
diff -r 07b986fec159 -r 7522ea52b829 
tools/xenstore/testsuite/06dirpermissions.test
--- a/tools/xenstore/testsuite/06dirpermissions.test    Sun Aug 21 06:29:47 2005
+++ b/tools/xenstore/testsuite/06dirpermissions.test    Sun Aug 21 06:38:22 2005
@@ -117,3 +117,11 @@
 write /dir/subdir/subfile excl contents
 expect 3 READ/WRITE
 getperm /dir/subdir/subfile
+
+# Inheritence works through multiple directories, too.
+write /dir/subdir/1/2/3/4 excl contents
+expect 3 READ/WRITE
+getperm /dir/subdir/1/2/3/4
+mkdir /dir/subdir/a/b/c/d
+expect 3 READ/WRITE
+getperm /dir/subdir/a/b/c/d
diff -r 07b986fec159 -r 7522ea52b829 tools/xenstore/xenstored_core.c
--- a/tools/xenstore/xenstored_core.c   Sun Aug 21 06:29:47 2005
+++ b/tools/xenstore/xenstored_core.c   Sun Aug 21 06:38:22 2005
@@ -423,14 +423,24 @@
        return node_dir_inside_transaction(trans, node);
 }
 
+static char *datafile(const char *dir)
+{
+       return talloc_asprintf(dir, "%s/.data", dir);
+}
+
 static char *node_datafile(struct transaction *trans, const char *node)
 {
-       return talloc_asprintf(node, "%s/.data", node_dir(trans, node));
+       return datafile(node_dir(trans, node));
+}
+
+static char *permfile(const char *dir)
+{
+       return talloc_asprintf(dir, "%s/.perms", dir);
 }
 
 static char *node_permfile(struct transaction *trans, const char *node)
 {
-       return talloc_asprintf(node, "%s/.perms", node_dir(trans, node));
+       return permfile(node_dir(trans, node));
 }
 
 struct buffered_data *new_buffer(void *ctx)
@@ -557,15 +567,14 @@
 }
 
 /* If it fails, returns NULL and sets errno. */
-static struct xs_permissions *get_perms(struct transaction *transaction,
-                                       const char *node, unsigned int *num)
+static struct xs_permissions *get_perms(const char *dir, unsigned int *num)
 {
        unsigned int size;
        char *strings;
        struct xs_permissions *ret;
        int *fd;
 
-       fd = talloc_open(node_permfile(transaction, node), O_RDONLY, 0);
+       fd = talloc_open(permfile(dir), O_RDONLY, 0);
        if (!fd)
                return NULL;
        strings = read_all(fd, &size);
@@ -573,14 +582,14 @@
                return NULL;
 
        *num = xs_count_strings(strings, size);
-       ret = talloc_array(node, struct xs_permissions, *num);
+       ret = talloc_array(dir, struct xs_permissions, *num);
        if (!xs_strings_to_perms(ret, *num, strings))
-               corrupt(NULL, "Permissions corrupt for %s", node);
+               corrupt(NULL, "Permissions corrupt for %s", dir);
 
        return ret;
 }
 
-static char *perms_to_strings(const char *node,
+static char *perms_to_strings(const void *ctx,
                              struct xs_permissions *perms, unsigned int num,
                              unsigned int *len)
 {
@@ -592,7 +601,7 @@
                if (!xs_perm_to_string(&perms[i], buffer))
                        return NULL;
 
-               strings = talloc_realloc(node, strings, char,
+               strings = talloc_realloc(ctx, strings, char,
                                         *len + strlen(buffer) + 1);
                strcpy(strings + *len, buffer);
                *len += strlen(buffer) + 1;
@@ -625,16 +634,23 @@
        return 0;
 }
 
+/* Create a self-destructing temporary path */
+static char *temppath(const char *path)
+{
+       char *tmppath = talloc_asprintf(path, "%s.tmp", path);
+       talloc_set_destructor(tmppath, destroy_path);
+       return tmppath;
+}
+
 /* Create a self-destructing temporary file */
 static char *tempfile(const char *path, void *contents, unsigned int len)
 {
        int *fd;
-       char *tmppath = talloc_asprintf(path, "%s.tmp", path);
+       char *tmppath = temppath(path);
 
        fd = talloc_open(tmppath, O_WRONLY|O_CREAT|O_EXCL, 0640);
        if (!fd)
                return NULL;
-       talloc_set_destructor(tmppath, destroy_path);
        if (!xs_write_all(*fd, contents, len))
                return NULL;
 
@@ -732,7 +748,7 @@
 
        do {
                node = get_parent(node);
-               perms = get_perms(conn->transaction, node, &num);
+               perms = get_perms(node_dir(conn->transaction, node), &num);
                if (perms)
                        break;
        } while (!streq(node, "/"));
@@ -788,7 +804,7 @@
                return false;
        }
 
-       perms = get_perms(conn->transaction, node, &num);
+       perms = get_perms(node_dir(conn->transaction, node), &num);
 
        if (perms) {
                if (perm_for_id(conn->id, perms, num) & perm)
@@ -875,44 +891,64 @@
                send_reply(conn, XS_READ, value, size);
 }
 
-/* Create a new directory.  Optionally put data in it (if data != NULL) */
-static bool new_directory(struct connection *conn,
-                         const char *node, void *data, unsigned int datalen)
+/* Commit this directory, eg. comitting a/b.tmp/c causes a/b.tmp -> a.b */
+static bool commit_dir(char *dir)
+{
+       char *dot, *slash, *dest;
+
+       dot = strrchr(dir, '.');
+       slash = strchr(dot, '/');
+       if (slash)
+               *slash = '\0';
+
+       dest = talloc_asprintf(dir, "%.*s", dot - dir, dir);
+       return rename(dir, dest) == 0;
+}
+
+/* Create a temporary directory.  Put data in it (if data != NULL) */
+static char *tempdir(struct connection *conn,
+                    const char *node, void *data, unsigned int datalen)
 {
        struct xs_permissions *perms;
        char *permstr;
        unsigned int num, len;
        int *fd;
-       char *dir = node_dir(conn->transaction, node);
-
-       if (mkdir(dir, 0750) != 0)
-               return false;
-
-       /* Set destructor so we clean up if neccesary. */
-       talloc_set_destructor(dir, destroy_path);
-
-       perms = get_perms(conn->transaction, get_parent(node), &num);
+       char *dir;
+
+       dir = temppath(node_dir(conn->transaction, node));
+       if (mkdir(dir, 0750) != 0) {
+               if (errno != ENOENT)
+                       return NULL;
+
+               dir = tempdir(conn, get_parent(node), NULL, 0);
+               if (!dir)
+                       return NULL;
+
+               dir = talloc_asprintf(dir, "%s%s", dir, strrchr(node, '/'));
+               if (mkdir(dir, 0750) != 0)
+                       return NULL;
+               talloc_set_destructor(dir, destroy_path);
+       }
+
+       perms = get_perms(get_parent(dir), &num);
+       assert(perms);
        /* Domains own what they create. */
        if (conn->id)
                perms->id = conn->id;
 
        permstr = perms_to_strings(dir, perms, num, &len);
-       fd = talloc_open(node_permfile(conn->transaction, node),
-                        O_WRONLY|O_CREAT|O_EXCL, 0640);
+       fd = talloc_open(permfile(dir), O_WRONLY|O_CREAT|O_EXCL, 0640);
        if (!fd || !xs_write_all(*fd, permstr, len))
-               return false;
+               return NULL;
 
        if (data) {
-               char *datapath = node_datafile(conn->transaction, node);
+               char *datapath = datafile(dir);
 
                fd = talloc_open(datapath, O_WRONLY|O_CREAT|O_EXCL, 0640);
                if (!fd || !xs_write_all(*fd, data, datalen))
-                       return false;
-       }
-
-       /* Finished! */
-       talloc_set_destructor(dir, NULL);
-       return true;
+                       return NULL;
+       }
+       return dir;
 }
 
 /* path, flags, data... */
@@ -959,6 +995,8 @@
        }
 
        if (lstat(node_dir(conn->transaction, node), &st) != 0) {
+               char *dir;
+
                /* Does not exist... */
                if (errno != ENOENT) {
                        send_error(conn, errno);
@@ -971,10 +1009,12 @@
                        return;
                }
 
-               if (!new_directory(conn, node, in->buffer + offset, datalen)) {
+               dir = tempdir(conn, node, in->buffer + offset, datalen);
+               if (!dir || !commit_dir(dir)) {
                        send_error(conn, errno);
                        return;
                }
+               
        } else {
                /* Exists... */
                if (streq(vec[1], XS_WRITE_CREATE_EXCL)) {
@@ -999,6 +1039,9 @@
 
 static void do_mkdir(struct connection *conn, const char *node)
 {
+       char *dir;
+       struct stat st;
+
        node = canonicalize(conn, node);
        if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_ENOENT_OK)) {
                send_error(conn, errno);
@@ -1013,7 +1056,14 @@
        if (transaction_block(conn, node))
                return;
 
-       if (!new_directory(conn, node, NULL, 0)) {
+       /* Must not already exist. */
+       if (lstat(node_dir(conn->transaction, node), &st) == 0) {
+               send_error(conn, EEXIST);
+               return;
+       }
+
+       dir = tempdir(conn, node, NULL, 0);
+       if (!dir || !commit_dir(dir)) {
                send_error(conn, errno);
                return;
        }
@@ -1073,7 +1123,7 @@
                return;
        }
 
-       perms = get_perms(conn->transaction, node, &num);
+       perms = get_perms(node_dir(conn->transaction, node), &num);
        if (!perms) {
                send_error(conn, errno);
                return;
diff -r 07b986fec159 -r 7522ea52b829 tools/xenstore/xs_random.c
--- a/tools/xenstore/xs_random.c        Sun Aug 21 06:29:47 2005
+++ b/tools/xenstore/xs_random.c        Sun Aug 21 06:38:22 2005
@@ -303,6 +303,34 @@
        return true;
 }
 
+static char *parent_filename(const char *name)
+{
+       char *slash = strrchr(name + 1, '/');
+       if (!slash)
+               return talloc_strdup(name, "/");
+       return talloc_asprintf(name, "%.*s", slash-name, name);
+}
+
+static void make_dirs(const char *filename)
+{
+       struct stat st;
+
+       if (lstat(filename, &st) == 0 && S_ISREG(st.st_mode))
+               convert_to_dir(filename);
+
+       if (mkdir(filename, 0700) == 0) {
+               init_perms(filename);
+               return;
+       }
+       if (errno == EEXIST)
+               return;
+
+       make_dirs(parent_filename(filename));
+       if (mkdir(filename, 0700) != 0)
+               barf_perror("Failed to mkdir %s", filename);
+       init_perms(filename);
+}
+
 static bool file_write(struct file_ops_info *info,
                       const char *path, const void *data,
                       unsigned int len, int createflags)
@@ -329,6 +357,9 @@
                }
        }
 
+       if (createflags & O_CREAT)
+               make_dirs(parent_filename(filename));
+
        fd = open(filename, createflags|O_TRUNC|O_WRONLY, 0600);
        if (fd < 0) {
                /* FIXME: Another hack. */
@@ -352,6 +383,7 @@
        if (!write_ok(info, path))
                return false;
 
+       make_dirs(parent_filename(dirname));
        if (mkdir(dirname, 0700) != 0)
                return false;
 
@@ -420,7 +452,7 @@
        }
 
        if (abort) {
-               cmd = talloc_asprintf(NULL, "rm -r %s", info->transact_base);
+               cmd = talloc_asprintf(NULL, "rm -rf %s", info->transact_base);
                do_command(cmd);
                goto success;
        }
@@ -1004,8 +1036,8 @@
        } else {
                dup2(fds[1], STDOUT_FILENO);
                close(fds[0]);
-#if 0
-               execlp("valgrind", "valgrind", "xenstored_test", "--output-pid",
+#if 1
+               execlp("valgrind", "valgrind", "-q", 
"--suppressions=testsuite/vg-suppressions", "xenstored_test", "--output-pid",
                       "--no-fork", NULL);
 #else
                execlp("./xenstored_test", "xenstored_test", "--output-pid",

-- 
A bad analogy is like a leaky screwdriver -- Richard Braakman


_______________________________________________
Xen-tools mailing list
Xen-tools@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-tools