ia64/xen-unstable

changeset 6383:00071566ed1e

Make directories implicitly for mkdir and write.
Change directory code: make then move (safer than delete-if-fail).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Tue Aug 23 19:52:13 2005 +0000 (2005-08-23)
parents 0077e7207d01
children c51562192ef6
files tools/xenstore/testsuite/02directory.test tools/xenstore/testsuite/03write.test tools/xenstore/testsuite/06dirpermissions.test tools/xenstore/xenstored_core.c tools/xenstore/xs_random.c
line diff
     1.1 --- a/tools/xenstore/testsuite/02directory.test	Tue Aug 23 19:48:28 2005 +0000
     1.2 +++ b/tools/xenstore/testsuite/02directory.test	Tue Aug 23 19:52:13 2005 +0000
     1.3 @@ -32,3 +32,16 @@ expect mkdir failed: File exists
     1.4  mkdir /dir
     1.5  expect mkdir failed: File exists
     1.6  mkdir /dir/test2
     1.7 +
     1.8 +# Mkdir implicitly creates directories.
     1.9 +mkdir /dir/1/2/3/4
    1.10 +expect test2
    1.11 +expect 1
    1.12 +dir /dir
    1.13 +expect 2
    1.14 +dir /dir/1
    1.15 +expect 3
    1.16 +dir /dir/1/2
    1.17 +expect 4
    1.18 +dir /dir/1/2/3
    1.19 +dir /dir/1/2/3/4
     2.1 --- a/tools/xenstore/testsuite/03write.test	Tue Aug 23 19:48:28 2005 +0000
     2.2 +++ b/tools/xenstore/testsuite/03write.test	Tue Aug 23 19:52:13 2005 +0000
     2.3 @@ -18,3 +18,22 @@ read /test
     2.4  write /test create contents3
     2.5  expect contents3
     2.6  read /test
     2.7 +
     2.8 +# Write should implicitly create directories
     2.9 +write /dir/test create contents
    2.10 +expect test
    2.11 +dir /dir
    2.12 +expect contents
    2.13 +read /dir/test
    2.14 +write /dir/1/2/3/4 excl contents4
    2.15 +expect test
    2.16 +expect 1
    2.17 +dir /dir
    2.18 +expect 2
    2.19 +dir /dir/1
    2.20 +expect 3
    2.21 +dir /dir/1/2
    2.22 +expect 4
    2.23 +dir /dir/1/2/3
    2.24 +expect contents4
    2.25 +read /dir/1/2/3/4
     3.1 --- a/tools/xenstore/testsuite/06dirpermissions.test	Tue Aug 23 19:48:28 2005 +0000
     3.2 +++ b/tools/xenstore/testsuite/06dirpermissions.test	Tue Aug 23 19:52:13 2005 +0000
     3.3 @@ -117,3 +117,11 @@ setid 3
     3.4  write /dir/subdir/subfile excl contents
     3.5  expect 3 READ/WRITE
     3.6  getperm /dir/subdir/subfile
     3.7 +
     3.8 +# Inheritence works through multiple directories, too.
     3.9 +write /dir/subdir/1/2/3/4 excl contents
    3.10 +expect 3 READ/WRITE
    3.11 +getperm /dir/subdir/1/2/3/4
    3.12 +mkdir /dir/subdir/a/b/c/d
    3.13 +expect 3 READ/WRITE
    3.14 +getperm /dir/subdir/a/b/c/d
     4.1 --- a/tools/xenstore/xenstored_core.c	Tue Aug 23 19:48:28 2005 +0000
     4.2 +++ b/tools/xenstore/xenstored_core.c	Tue Aug 23 19:52:13 2005 +0000
     4.3 @@ -423,14 +423,24 @@ static char *node_dir(struct transaction
     4.4  	return node_dir_inside_transaction(trans, node);
     4.5  }
     4.6  
     4.7 +static char *datafile(const char *dir)
     4.8 +{
     4.9 +	return talloc_asprintf(dir, "%s/.data", dir);
    4.10 +}
    4.11 +
    4.12  static char *node_datafile(struct transaction *trans, const char *node)
    4.13  {
    4.14 -	return talloc_asprintf(node, "%s/.data", node_dir(trans, node));
    4.15 +	return datafile(node_dir(trans, node));
    4.16 +}
    4.17 +
    4.18 +static char *permfile(const char *dir)
    4.19 +{
    4.20 +	return talloc_asprintf(dir, "%s/.perms", dir);
    4.21  }
    4.22  
    4.23  static char *node_permfile(struct transaction *trans, const char *node)
    4.24  {
    4.25 -	return talloc_asprintf(node, "%s/.perms", node_dir(trans, node));
    4.26 +	return permfile(node_dir(trans, node));
    4.27  }
    4.28  
    4.29  struct buffered_data *new_buffer(void *ctx)
    4.30 @@ -557,15 +567,14 @@ static const char *onearg(struct buffere
    4.31  }
    4.32  
    4.33  /* If it fails, returns NULL and sets errno. */
    4.34 -static struct xs_permissions *get_perms(struct transaction *transaction,
    4.35 -					const char *node, unsigned int *num)
    4.36 +static struct xs_permissions *get_perms(const char *dir, unsigned int *num)
    4.37  {
    4.38  	unsigned int size;
    4.39  	char *strings;
    4.40  	struct xs_permissions *ret;
    4.41  	int *fd;
    4.42  
    4.43 -	fd = talloc_open(node_permfile(transaction, node), O_RDONLY, 0);
    4.44 +	fd = talloc_open(permfile(dir), O_RDONLY, 0);
    4.45  	if (!fd)
    4.46  		return NULL;
    4.47  	strings = read_all(fd, &size);
    4.48 @@ -573,14 +582,14 @@ static struct xs_permissions *get_perms(
    4.49  		return NULL;
    4.50  
    4.51  	*num = xs_count_strings(strings, size);
    4.52 -	ret = talloc_array(node, struct xs_permissions, *num);
    4.53 +	ret = talloc_array(dir, struct xs_permissions, *num);
    4.54  	if (!xs_strings_to_perms(ret, *num, strings))
    4.55 -		corrupt(NULL, "Permissions corrupt for %s", node);
    4.56 +		corrupt(NULL, "Permissions corrupt for %s", dir);
    4.57  
    4.58  	return ret;
    4.59  }
    4.60  
    4.61 -static char *perms_to_strings(const char *node,
    4.62 +static char *perms_to_strings(const void *ctx,
    4.63  			      struct xs_permissions *perms, unsigned int num,
    4.64  			      unsigned int *len)
    4.65  {
    4.66 @@ -592,7 +601,7 @@ static char *perms_to_strings(const char
    4.67  		if (!xs_perm_to_string(&perms[i], buffer))
    4.68  			return NULL;
    4.69  
    4.70 -		strings = talloc_realloc(node, strings, char,
    4.71 +		strings = talloc_realloc(ctx, strings, char,
    4.72  					 *len + strlen(buffer) + 1);
    4.73  		strcpy(strings + *len, buffer);
    4.74  		*len += strlen(buffer) + 1;
    4.75 @@ -625,16 +634,23 @@ int destroy_path(void *path)
    4.76  	return 0;
    4.77  }
    4.78  
    4.79 +/* Create a self-destructing temporary path */
    4.80 +static char *temppath(const char *path)
    4.81 +{
    4.82 +	char *tmppath = talloc_asprintf(path, "%s.tmp", path);
    4.83 +	talloc_set_destructor(tmppath, destroy_path);
    4.84 +	return tmppath;
    4.85 +}
    4.86 +
    4.87  /* Create a self-destructing temporary file */
    4.88  static char *tempfile(const char *path, void *contents, unsigned int len)
    4.89  {
    4.90  	int *fd;
    4.91 -	char *tmppath = talloc_asprintf(path, "%s.tmp", path);
    4.92 +	char *tmppath = temppath(path);
    4.93  
    4.94  	fd = talloc_open(tmppath, O_WRONLY|O_CREAT|O_EXCL, 0640);
    4.95  	if (!fd)
    4.96  		return NULL;
    4.97 -	talloc_set_destructor(tmppath, destroy_path);
    4.98  	if (!xs_write_all(*fd, contents, len))
    4.99  		return NULL;
   4.100  
   4.101 @@ -732,7 +748,7 @@ static enum xs_perm_type ask_parents(str
   4.102  
   4.103  	do {
   4.104  		node = get_parent(node);
   4.105 -		perms = get_perms(conn->transaction, node, &num);
   4.106 +		perms = get_perms(node_dir(conn->transaction, node), &num);
   4.107  		if (perms)
   4.108  			break;
   4.109  	} while (!streq(node, "/"));
   4.110 @@ -788,7 +804,7 @@ bool check_node_perms(struct connection 
   4.111  		return false;
   4.112  	}
   4.113  
   4.114 -	perms = get_perms(conn->transaction, node, &num);
   4.115 +	perms = get_perms(node_dir(conn->transaction, node), &num);
   4.116  
   4.117  	if (perms) {
   4.118  		if (perm_for_id(conn->id, perms, num) & perm)
   4.119 @@ -875,44 +891,64 @@ static void do_read(struct connection *c
   4.120  		send_reply(conn, XS_READ, value, size);
   4.121  }
   4.122  
   4.123 -/* Create a new directory.  Optionally put data in it (if data != NULL) */
   4.124 -static bool new_directory(struct connection *conn,
   4.125 -			  const char *node, void *data, unsigned int datalen)
   4.126 +/* Commit this directory, eg. comitting a/b.tmp/c causes a/b.tmp -> a.b */
   4.127 +static bool commit_dir(char *dir)
   4.128 +{
   4.129 +	char *dot, *slash, *dest;
   4.130 +
   4.131 +	dot = strrchr(dir, '.');
   4.132 +	slash = strchr(dot, '/');
   4.133 +	if (slash)
   4.134 +		*slash = '\0';
   4.135 +
   4.136 +	dest = talloc_asprintf(dir, "%.*s", dot - dir, dir);
   4.137 +	return rename(dir, dest) == 0;
   4.138 +}
   4.139 +
   4.140 +/* Create a temporary directory.  Put data in it (if data != NULL) */
   4.141 +static char *tempdir(struct connection *conn,
   4.142 +		     const char *node, void *data, unsigned int datalen)
   4.143  {
   4.144  	struct xs_permissions *perms;
   4.145  	char *permstr;
   4.146  	unsigned int num, len;
   4.147  	int *fd;
   4.148 -	char *dir = node_dir(conn->transaction, node);
   4.149 +	char *dir;
   4.150  
   4.151 -	if (mkdir(dir, 0750) != 0)
   4.152 -		return false;
   4.153 +	dir = temppath(node_dir(conn->transaction, node));
   4.154 +	if (mkdir(dir, 0750) != 0) {
   4.155 +		if (errno != ENOENT)
   4.156 +			return NULL;
   4.157  
   4.158 -	/* Set destructor so we clean up if neccesary. */
   4.159 -	talloc_set_destructor(dir, destroy_path);
   4.160 +		dir = tempdir(conn, get_parent(node), NULL, 0);
   4.161 +		if (!dir)
   4.162 +			return NULL;
   4.163  
   4.164 -	perms = get_perms(conn->transaction, get_parent(node), &num);
   4.165 +		dir = talloc_asprintf(dir, "%s%s", dir, strrchr(node, '/'));
   4.166 +		if (mkdir(dir, 0750) != 0)
   4.167 +			return NULL;
   4.168 +		talloc_set_destructor(dir, destroy_path);
   4.169 +	}
   4.170 +
   4.171 +	perms = get_perms(get_parent(dir), &num);
   4.172 +	assert(perms);
   4.173  	/* Domains own what they create. */
   4.174  	if (conn->id)
   4.175  		perms->id = conn->id;
   4.176  
   4.177  	permstr = perms_to_strings(dir, perms, num, &len);
   4.178 -	fd = talloc_open(node_permfile(conn->transaction, node),
   4.179 -			 O_WRONLY|O_CREAT|O_EXCL, 0640);
   4.180 +	fd = talloc_open(permfile(dir), O_WRONLY|O_CREAT|O_EXCL, 0640);
   4.181  	if (!fd || !xs_write_all(*fd, permstr, len))
   4.182 -		return false;
   4.183 +		return NULL;
   4.184  
   4.185  	if (data) {
   4.186 -		char *datapath = node_datafile(conn->transaction, node);
   4.187 +		char *datapath = datafile(dir);
   4.188  
   4.189  		fd = talloc_open(datapath, O_WRONLY|O_CREAT|O_EXCL, 0640);
   4.190  		if (!fd || !xs_write_all(*fd, data, datalen))
   4.191 -			return false;
   4.192 +			return NULL;
   4.193  	}
   4.194 -
   4.195 -	/* Finished! */
   4.196 -	talloc_set_destructor(dir, NULL);
   4.197 -	return true;
   4.198 +	return dir;
   4.199  }
   4.200  
   4.201  /* path, flags, data... */
   4.202 @@ -959,6 +995,8 @@ static void do_write(struct connection *
   4.203  	}
   4.204  
   4.205  	if (lstat(node_dir(conn->transaction, node), &st) != 0) {
   4.206 +		char *dir;
   4.207 +
   4.208  		/* Does not exist... */
   4.209  		if (errno != ENOENT) {
   4.210  			send_error(conn, errno);
   4.211 @@ -971,10 +1009,12 @@ static void do_write(struct connection *
   4.212  			return;
   4.213  		}
   4.214  
   4.215 -		if (!new_directory(conn, node, in->buffer + offset, datalen)) {
   4.216 +		dir = tempdir(conn, node, in->buffer + offset, datalen);
   4.217 +		if (!dir || !commit_dir(dir)) {
   4.218  			send_error(conn, errno);
   4.219  			return;
   4.220  		}
   4.221 +		
   4.222  	} else {
   4.223  		/* Exists... */
   4.224  		if (streq(vec[1], XS_WRITE_CREATE_EXCL)) {
   4.225 @@ -999,6 +1039,9 @@ static void do_write(struct connection *
   4.226  
   4.227  static void do_mkdir(struct connection *conn, const char *node)
   4.228  {
   4.229 +	char *dir;
   4.230 +	struct stat st;
   4.231 +
   4.232  	node = canonicalize(conn, node);
   4.233  	if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_ENOENT_OK)) {
   4.234  		send_error(conn, errno);
   4.235 @@ -1013,7 +1056,14 @@ static void do_mkdir(struct connection *
   4.236  	if (transaction_block(conn, node))
   4.237  		return;
   4.238  
   4.239 -	if (!new_directory(conn, node, NULL, 0)) {
   4.240 +	/* Must not already exist. */
   4.241 +	if (lstat(node_dir(conn->transaction, node), &st) == 0) {
   4.242 +		send_error(conn, EEXIST);
   4.243 +		return;
   4.244 +	}
   4.245 +
   4.246 +	dir = tempdir(conn, node, NULL, 0);
   4.247 +	if (!dir || !commit_dir(dir)) {
   4.248  		send_error(conn, errno);
   4.249  		return;
   4.250  	}
   4.251 @@ -1073,7 +1123,7 @@ static void do_get_perms(struct connecti
   4.252  		return;
   4.253  	}
   4.254  
   4.255 -	perms = get_perms(conn->transaction, node, &num);
   4.256 +	perms = get_perms(node_dir(conn->transaction, node), &num);
   4.257  	if (!perms) {
   4.258  		send_error(conn, errno);
   4.259  		return;
     5.1 --- a/tools/xenstore/xs_random.c	Tue Aug 23 19:48:28 2005 +0000
     5.2 +++ b/tools/xenstore/xs_random.c	Tue Aug 23 19:52:13 2005 +0000
     5.3 @@ -303,6 +303,34 @@ static bool file_set_perms(struct file_o
     5.4  	return true;
     5.5  }
     5.6  
     5.7 +static char *parent_filename(const char *name)
     5.8 +{
     5.9 +	char *slash = strrchr(name + 1, '/');
    5.10 +	if (!slash)
    5.11 +		return talloc_strdup(name, "/");
    5.12 +	return talloc_asprintf(name, "%.*s", slash-name, name);
    5.13 +}
    5.14 +
    5.15 +static void make_dirs(const char *filename)
    5.16 +{
    5.17 +	struct stat st;
    5.18 +
    5.19 +	if (lstat(filename, &st) == 0 && S_ISREG(st.st_mode))
    5.20 +		convert_to_dir(filename);
    5.21 +
    5.22 +	if (mkdir(filename, 0700) == 0) {
    5.23 +		init_perms(filename);
    5.24 +		return;
    5.25 +	}
    5.26 +	if (errno == EEXIST)
    5.27 +		return;
    5.28 +
    5.29 +	make_dirs(parent_filename(filename));
    5.30 +	if (mkdir(filename, 0700) != 0)
    5.31 +		barf_perror("Failed to mkdir %s", filename);
    5.32 +	init_perms(filename);
    5.33 +}
    5.34 +
    5.35  static bool file_write(struct file_ops_info *info,
    5.36  		       const char *path, const void *data,
    5.37  		       unsigned int len, int createflags)
    5.38 @@ -329,6 +357,9 @@ static bool file_write(struct file_ops_i
    5.39  		}
    5.40  	}
    5.41  
    5.42 +	if (createflags & O_CREAT)
    5.43 +		make_dirs(parent_filename(filename));
    5.44 +
    5.45  	fd = open(filename, createflags|O_TRUNC|O_WRONLY, 0600);
    5.46  	if (fd < 0) {
    5.47  		/* FIXME: Another hack. */
    5.48 @@ -352,6 +383,7 @@ static bool file_mkdir(struct file_ops_i
    5.49  	if (!write_ok(info, path))
    5.50  		return false;
    5.51  
    5.52 +	make_dirs(parent_filename(dirname));
    5.53  	if (mkdir(dirname, 0700) != 0)
    5.54  		return false;
    5.55  
    5.56 @@ -420,7 +452,7 @@ static bool file_transaction_end(struct 
    5.57  	}
    5.58  
    5.59  	if (abort) {
    5.60 -		cmd = talloc_asprintf(NULL, "rm -r %s", info->transact_base);
    5.61 +		cmd = talloc_asprintf(NULL, "rm -rf %s", info->transact_base);
    5.62  		do_command(cmd);
    5.63  		goto success;
    5.64  	}
    5.65 @@ -1004,8 +1036,8 @@ static void setup_xs_ops(void)
    5.66  	} else {
    5.67  		dup2(fds[1], STDOUT_FILENO);
    5.68  		close(fds[0]);
    5.69 -#if 0
    5.70 -		execlp("valgrind", "valgrind", "xenstored_test", "--output-pid",
    5.71 +#if 1
    5.72 +		execlp("valgrind", "valgrind", "-q", "--suppressions=testsuite/vg-suppressions", "xenstored_test", "--output-pid",
    5.73  		       "--no-fork", NULL);
    5.74  #else
    5.75  		execlp("./xenstored_test", "xenstored_test", "--output-pid",