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
|