[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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



Thanks!

On Sun, Aug 21, 2005 at 06:39:21PM +1000, Rusty Russell wrote:
> 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
> 

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.