Signed-off-by: Federico Simoncelli fsimonce@redhat.com --- src/client.c | 56 +++++++++++++++++------ src/sanlock.h | 4 +- tests/Makefile | 17 ++++-- tests/sanlk_path.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 186 insertions(+), 21 deletions(-) create mode 100644 tests/sanlk_path.c
diff --git a/src/client.c b/src/client.c index e8b61be..3c7287e 100644 --- a/src/client.c +++ b/src/client.c @@ -238,28 +238,56 @@ int sanlock_init(struct sanlk_lockspace *ls,
/* src has colons unescaped, dst should have them escaped with backslash */
-static void copy_path_out(char *dst, char *src) +size_t sanlock_path_export(char *dst, const char *src, size_t dstlen) { - int i, j = 0; + 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;
- for (i = 0; i < strlen(src); i++) { - if (src[i] == ':') - dst[j++] = '\'; - dst[j++] = src[i]; + if (*p == '\0') return j; /* success */ + p++; + + next_loop: + j++; } + + return 0; }
/* src has colons escaped with backslash, dst should have backslash removed */
-static void copy_path_in(char *dst, char *src) +size_t sanlock_path_import(char *dst, const char *src, size_t dstlen) { - int i, j = 0; + size_t j = 0; + const char *p = src;
- for (i = 0; i < strlen(src); i++) { - if (src[i] == '\') - continue; - dst[j++] = src[i]; + 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) @@ -636,7 +664,7 @@ int sanlock_res_to_str(struct sanlk_resource *res, char **str_ret)
for (d = 0; d < res->num_disks; d++) { memset(path, 0, sizeof(path)); - copy_path_out(path, res->disks[d].path); + sanlock_path_export(path, res->disks[d].path, sizeof(path));
ret = snprintf(str + pos, len - pos, ":%s:%llu", path, (unsigned long long)res->disks[d].offset); @@ -946,7 +974,7 @@ int sanlock_str_to_lockspace(char *str, struct sanlk_lockspace *ls) if (host_id) ls->host_id = atoll(host_id); if (path) - copy_path_in(ls->host_id_disk.path, path); + sanlock_path_import(ls->host_id_disk.path, path, sizeof(ls->host_id_disk.path)); if (offset) ls->host_id_disk.offset = atoll(offset);
diff --git a/src/sanlock.h b/src/sanlock.h index e36c40e..457ab7a 100644 --- a/src/sanlock.h +++ b/src/sanlock.h @@ -91,5 +91,7 @@ struct sanlk_lockspace { struct sanlk_disk host_id_disk; };
-#endif +size_t sanlock_path_export(char *dst, const char *src, size_t dstlen); +size_t sanlock_path_import(char *dst, const char *src, size_t dstlen);
+#endif diff --git a/tests/Makefile b/tests/Makefile index 838ad23..28f5d21 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -2,11 +2,13 @@ TARGET1 = devcount TARGET2 = sanlk_load TARGET3 = sanlk_client TARGET4 = killpath +TARGET5 = sanlk_path
SOURCE1 = devcount.c SOURCE2 = sanlk_load.c SOURCE3 = sanlk_client.c SOURCE4 = killpath.c +SOURCE5 = sanlk_path.c
CFLAGS += -D_GNU_SOURCE -g \ -Wall \ @@ -29,20 +31,23 @@ CFLAGS += -D_GNU_SOURCE -g \
LDFLAGS = -lrt -laio -lblkid -lsanlock
-all: $(TARGET1) $(TARGET2) $(TARGET3) $(TARGET4) +all: $(TARGET1) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5)
$(TARGET1): $(SOURCE1) - $(CC) $(CFLAGS) $(LDFLAGS) $(SOURCE1) -o $@ -L. -L../src + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src
$(TARGET2): $(SOURCE2) - $(CC) $(CFLAGS) $(LDFLAGS) $(SOURCE2) -o $@ -L. -L../src + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src
$(TARGET3): $(SOURCE3) - $(CC) $(CFLAGS) $(LDFLAGS) $(SOURCE3) -o $@ -L. -L../src + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src
$(TARGET4): $(SOURCE4) - $(CC) $(CFLAGS) $(LDFLAGS) $(SOURCE4) -o $@ -L. -L../src + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src + +$(TARGET5): $(SOURCE5) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src
clean: - rm -f *.o *.so *.so.* $(TARGET) $(TARGET2) $(TARGET3) $(TARGET4) + rm -f *.o *.so *.so.* $(TARGET) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5)
diff --git a/tests/sanlk_path.c b/tests/sanlk_path.c new file mode 100644 index 0000000..f9d8f6f --- /dev/null +++ b/tests/sanlk_path.c @@ -0,0 +1,130 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "sanlock.h" +#include "sanlock_resource.h" + +#define DSTMAXSIZE 1024 + +static int __test_passed = 0; + +#define check_perror(expression, fmt, args...) \ +if (expression) { \ + __test_passed++; \ +} \ +else { \ + fprintf(stderr, "%s:%i " fmt "\n", __FILE__, __LINE__, ##args); \ + exit(1); \ +} + +void test_sanlock_path_export(void) +{ + int rv, dst_len; + char dst_str[DSTMAXSIZE]; + const char *src_str, *dst_exp; + + /* regular behavior, no escapes */ + src_str = "Hello World"; + dst_exp = src_str; + dst_len = strlen(dst_exp); + + memset(dst_str, 'X', DSTMAXSIZE); + + /* destination too short */ + rv = sanlock_path_export(dst_str, src_str, dst_len); + check_perror(rv == 0, "sanlock_path_export wrong return code: %u", rv); + check_perror(dst_str[dst_len] == 'X', + "sanlock_path_export buffer overflow"); + + /* destination long enough */ + rv = sanlock_path_export(dst_str, src_str, dst_len + 1); + check_perror(rv == dst_len, + "sanlock_path_export wrong return code: %u", rv); + check_perror(dst_str[dst_len] == '\0', + "sanlock_path_import destination not terminated"); + check_perror(!strncmp(dst_str, dst_exp, dst_len), + "sanlock_path_export destination is different"); + + /* special behavior, escapes */ + src_str = "Hello World:"; + dst_exp = "Hello World\:"; + dst_len = strlen(dst_exp); + + memset(dst_str, 'X', DSTMAXSIZE); + + /* destination too short */ + rv = sanlock_path_export(dst_str, src_str, dst_len); + check_perror(rv == 0, "sanlock_path_export wrong return code: %u", rv); + check_perror(dst_str[dst_len] == 'X', + "sanlock_path_export buffer overflow"); + + /* destination long enough */ + rv = sanlock_path_export(dst_str, src_str, dst_len + 1); + check_perror(rv == dst_len, + "sanlock_path_export wrong return code: %u", rv); + check_perror(dst_str[dst_len] == '\0', + "sanlock_path_import destination not terminated"); + check_perror(!strncmp(dst_str, dst_exp, dst_len), + "sanlock_path_export destination is different"); +} + +void test_sanlock_path_import(void) +{ + int rv, dst_len; + char dst_str[DSTMAXSIZE]; + const char *src_str, *dst_exp; + + /* regular behavior, no escapes */ + src_str = "Hello World"; + dst_exp = src_str; + dst_len = strlen(dst_exp); + + memset(dst_str, 'X', DSTMAXSIZE); + + /* destination too short */ + rv = sanlock_path_import(dst_str, src_str, dst_len); + check_perror(rv == 0, "sanlock_path_import wrong return code: %u", rv); + check_perror(dst_str[dst_len] == 'X', + "sanlock_path_import buffer overflow"); + + /* destination long enough */ + rv = sanlock_path_import(dst_str, src_str, dst_len + 1); + check_perror(rv == dst_len, + "sanlock_path_import wrong return code: %u", rv); + check_perror(dst_str[dst_len] == '\0', + "sanlock_path_import destination not terminated"); + check_perror(!strncmp(dst_str, dst_exp, dst_len), + "sanlock_path_import destination is different"); + + /* special behavior, escapes */ + src_str = "Hello World\:"; + dst_exp = "Hello World:"; + dst_len = strlen(dst_exp); + + memset(dst_str, 'X', DSTMAXSIZE); + + /* destination too short */ + rv = sanlock_path_import(dst_str, src_str, dst_len); + check_perror(rv == 0, "sanlock_path_import wrong return code: %u", rv); + check_perror(dst_str[dst_len] == 'X', + "sanlock_path_import buffer overflow"); + + /* destination long enough */ + rv = sanlock_path_import(dst_str, src_str, dst_len + 1); + check_perror(rv == dst_len, + "sanlock_path_import wrong return code: %u", rv); + check_perror(dst_str[dst_len] == '\0', + "sanlock_path_import destination not terminated"); + check_perror(!strncmp(dst_str, dst_exp, dst_len), + "sanlock_path_import destination is different"); +} + +int main(int argc, char *argv[]) +{ + test_sanlock_path_export(); + test_sanlock_path_import(); + printf("OK, %i tests sucessfully passed.\n", __test_passed); + return 0; +}
sanlock-devel@lists.fedorahosted.org