src/client.c | 193 ++++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 131 insertions(+), 62 deletions(-)
New commits:
commit b05645531988165aacc5e55c35aed922d19dbf50
Author: David Teigland <teigland(a)redhat.com>
Date: Mon Nov 18 15:42:23 2013 -0600
sanlock: fix spaces in path names
When represented in string form, a resource or lockspace
path name should have escaped colons and spaces, i.e.
a backslash should precede the colon or space.
When represented in a structure, a resource or lockspace
path name should not contain escape chars so that the
string can be passed to open(2).
sanlock_path_export (sanlock_res_to_str)
. add backslash before spaces in path (in addition to colons)
sanlock_state_to_args
. allow individual res strings to contain escaped spaces
. detect when an unescaped space exists in an individual
res string and insert a backslash before it
Signed-off-by: David Teigland <teigland(a)redhat.com>
diff --git a/src/client.c b/src/client.c
index 68e71e6..14c70d1 100644
--- a/src/client.c
+++ b/src/client.c
@@ -712,60 +712,6 @@ int sanlock_init(struct sanlk_lockspace *ls,
return sanlock_write_resource(res, max_hosts, num_hosts, 0);
}
-/* src has colons unescaped, dst should have them escaped with backslash */
-
-size_t sanlock_path_export(char *dst, const char *src, size_t dstlen)
-{
- size_t j = 0, escaped = 0;
- const char *p = src;
-
- while (j < dstlen) {
- if (*p == ':' || *p == '\\') {
- if (!escaped) {
- dst[j] = '\\', escaped = 1;
- goto next_loop;
- }
-
- escaped = 0;
- }
-
- dst[j] = *p;
-
- if (*p == '\0') return j; /* success */
- p++;
-
- next_loop:
- j++;
- }
-
- return 0;
-}
-
-/* src has colons escaped with backslash, dst should have backslash removed */
-
-size_t sanlock_path_import(char *dst, const char *src, size_t dstlen)
-{
- size_t j = 0;
- const char *p = src;
-
- while (j < dstlen) {
- if (*p == '\\')
- goto next_loop;
-
- dst[j] = *p;
-
- if (*p == '\0')
- return j;
-
- j++;
-
- next_loop:
- p++;
- }
-
- return 0;
-}
-
int sanlock_register(void)
{
int sock, rv;
@@ -1262,6 +1208,91 @@ int sanlock_get_lvb(uint32_t flags, struct sanlk_resource *res, char *lvb, int l
}
/*
+ * src may have colons/spaces escaped (with backslash) or unescaped.
+ * if unescaped colons/spaces are found, insert backslash before them.
+ *
+ * returns strlen of dst.
+ */
+
+size_t sanlock_path_export(char *dst, const char *src, size_t dstlen)
+{
+ int i = 0; /* pos in src */
+ int j = 0; /* pos in dst */
+
+ memset(dst, 0, dstlen);
+
+ for (i = 0; i < strlen(src); i++) {
+
+ /* take an escape character plus whatever follows it. */
+
+ if (src[i] == '\\') {
+ if (j > dstlen - 3)
+ goto out;
+
+ dst[j] = src[i];
+ j++;
+ i++;
+ dst[j] = src[i];
+
+ goto next_char;
+ }
+
+ /* add escape character before an unescaped space or colon. */
+
+ if ((src[i] == ' ') || (src[i] == ':')) {
+ if (j > dstlen - 3)
+ goto out;
+
+ dst[j] = '\\';
+ j++;
+ dst[j] = src[i];
+
+ goto next_char;
+ }
+
+ /* copy non-special char from src to dst. */
+
+ if (j > dstlen - 2)
+ goto out;
+
+ dst[j] = src[i];
+
+ next_char:
+ if (dst[j] == '\0')
+ goto out;
+
+ j++;
+ }
+ out:
+ return strlen(dst);
+}
+
+/* src has colons/spaces escaped with backslash, dst should have backslash removed */
+
+size_t sanlock_path_import(char *dst, const char *src, size_t dstlen)
+{
+ size_t j = 0;
+ const char *p = src;
+
+ while (j < dstlen) {
+ if (*p == '\\')
+ goto next_loop;
+
+ dst[j] = *p;
+
+ if (*p == '\0')
+ return j;
+
+ j++;
+
+ next_loop:
+ p++;
+ }
+
+ return 0;
+}
+
+/*
* convert from struct sanlk_resource to string with format:
* <lockspace_name>:<resource_name>:<path>:<offset>[:<path>:<offset>...]:<lver>
*/
@@ -1323,6 +1354,11 @@ int sanlock_res_to_str(struct sanlk_resource *res, char **str_ret)
/*
* convert to struct sanlk_resource from string with format:
* <lockspace_name>:<resource_name>:<path>:<offset>[:<path>:<offset>...][:<lver>]
+ *
+ * If str contains a backslash escape character, the backslash needs to be
+ * excluded from the string in res struct. The path string in the res struct
+ * needs to be suitable for passing to open(2), which means it should not
+ * include escape characters.
*/
int sanlock_str_to_res(char *str, struct sanlk_resource **res_ret)
@@ -1374,6 +1410,8 @@ int sanlock_str_to_res(char *str, struct sanlk_resource **res_ret)
if (str[i] == '\\') {
if (i == (len - 1))
goto fail;
+ if (j >= SANLK_PATH_LEN)
+ goto fail;
i++;
sub[j++] = str[i];
@@ -1465,14 +1503,6 @@ int sanlock_args_to_state(int res_count,
return -EINVAL;
}
- /* space is str separator, so it's invalid within each str */
-
- if (strstr(str, " ")) {
- free(str);
- free(state);
- return -EINVAL;
- }
-
if (i)
strcat(state, " ");
strcat(state, str);
@@ -1498,9 +1528,15 @@ int sanlock_state_to_args(char *res_state,
struct sanlk_resource *res;
char str[SANLK_MAX_RES_STR + 1];
int count = 1, arg_count = 0;
+ int escape = 0;
+ int sep_colons = 0;
int i, j, len, rv;
for (i = 0; i < strlen(res_state); i++) {
+ if (res_state[i] == '\\') {
+ i++;
+ continue;
+ }
if (res_state[i] == ' ')
count++;
}
@@ -1514,11 +1550,43 @@ int sanlock_state_to_args(char *res_state,
j = 0;
memset(str, 0, sizeof(str));
+ sep_colons = 0;
len = strlen(res_state);
for (i = 0; i < len + 1; i++) {
+
+ if (i < len && res_state[i] == '\\') {
+ str[j++] = res_state[i];
+ escape = 1;
+ continue;
+ }
+
+ if (i < len && escape) {
+ str[j++] = res_state[i];
+ escape = 0;
+ continue;
+ }
+
+ if ((i < len) && (res_state[i] == ' ') && (sep_colons < 3)) {
+ /*
+ * This is a bit dubious. It's meant to detect when
+ * a res string contains an unescaped space, and
+ * inserts an escape char before it. An unescaped
+ * space within a res string would otherwise be
+ * misinterpreted as a separator between res strings.
+ * If we've not yet seen three colons within a single
+ * res string, then we should not be at the end yet.
+ */
+ str[j++] = '\\';
+ str[j++] = res_state[i];
+ continue;
+ }
+
if (i < len && res_state[i] != ' ') {
+ if (res_state[i] == ':')
+ sep_colons++;
+
str[j++] = res_state[i];
continue;
}
@@ -1534,6 +1602,7 @@ int sanlock_state_to_args(char *res_state,
j = 0;
memset(str, 0, sizeof(str));
+ sep_colons = 0;
}
/* caller to free res_count res and args */