Signed-off-by: Federico Simoncelli <fsimonce(a)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;
+}
--
1.7.1