summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/buffer.c18
-rw-r--r--tests-clay/clay.h13
-rw-r--r--tests-clay/clay_main.c17
-rw-r--r--tests-clay/core/path.c51
-rw-r--r--tests/test_helpers.c2
5 files changed, 78 insertions, 23 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 27e20d562..def3496ce 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -328,6 +328,10 @@ int git_buf_join(
size_t strlen_a = strlen(str_a);
size_t strlen_b = strlen(str_b);
int need_sep = 0;
+ ssize_t offset_a = -1;
+
+ /* not safe to have str_b point internally to the buffer */
+ assert(str_b < buf->ptr || str_b > buf->ptr + buf->size);
/* figure out if we need to insert a separator */
if (separator && strlen_a) {
@@ -336,14 +340,24 @@ int git_buf_join(
need_sep = 1;
}
+ /* str_a could be part of the buffer */
+ if (str_a >= buf->ptr && str_a < buf->ptr + buf->size)
+ offset_a = str_a - buf->ptr;
+
error = git_buf_grow(buf, strlen_a + strlen_b + need_sep + 1);
if (error < GIT_SUCCESS)
return error;
- memmove(buf->ptr, str_a, strlen_a);
+ /* fix up internal pointers */
+ if (offset_a >= 0)
+ str_a = buf->ptr + offset_a;
+
+ /* do the actual copying */
+ if (offset_a != 0)
+ memmove(buf->ptr, str_a, strlen_a);
if (need_sep)
buf->ptr[strlen_a] = separator;
- memmove(buf->ptr + strlen_a + need_sep, str_b, strlen_b);
+ memcpy(buf->ptr + strlen_a + need_sep, str_b, strlen_b);
buf->size = strlen_a + strlen_b + need_sep;
buf->ptr[buf->size] = '\0';
diff --git a/tests-clay/clay.h b/tests-clay/clay.h
index 3f09d4f06..5db24a4c9 100644
--- a/tests-clay/clay.h
+++ b/tests-clay/clay.h
@@ -106,12 +106,13 @@ extern void test_core_filebuf__4(void);
extern void test_core_filebuf__5(void);
extern void test_core_oid__initialize(void);
extern void test_core_oid__streq(void);
-extern void test_core_path__0(void);
-extern void test_core_path__1(void);
-extern void test_core_path__2(void);
-extern void test_core_path__5(void);
-extern void test_core_path__6(void);
-extern void test_core_path__7(void);
+extern void test_core_path__0_dirname(void);
+extern void test_core_path__1_basename(void);
+extern void test_core_path__2_topdir(void);
+extern void test_core_path__5_joins(void);
+extern void test_core_path__6_long_joins(void);
+extern void test_core_path__7_path_to_dir(void);
+extern void test_core_path__8_self_join(void);
extern void test_core_rmdir__delete_recursive(void);
extern void test_core_rmdir__fail_to_delete_non_empty_dir(void);
extern void test_core_rmdir__initialize(void);
diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c
index ce3b66b87..80c13f429 100644
--- a/tests-clay/clay_main.c
+++ b/tests-clay/clay_main.c
@@ -167,12 +167,13 @@ static const struct clay_func _clay_cb_core_oid[] = {
{"streq", &test_core_oid__streq}
};
static const struct clay_func _clay_cb_core_path[] = {
- {"0", &test_core_path__0},
- {"1", &test_core_path__1},
- {"2", &test_core_path__2},
- {"5", &test_core_path__5},
- {"6", &test_core_path__6},
- {"7", &test_core_path__7}
+ {"0_dirname", &test_core_path__0_dirname},
+ {"1_basename", &test_core_path__1_basename},
+ {"2_topdir", &test_core_path__2_topdir},
+ {"5_joins", &test_core_path__5_joins},
+ {"6_long_joins", &test_core_path__6_long_joins},
+ {"7_path_to_dir", &test_core_path__7_path_to_dir},
+ {"8_self_join", &test_core_path__8_self_join}
};
static const struct clay_func _clay_cb_core_rmdir[] = {
{"delete_recursive", &test_core_rmdir__delete_recursive},
@@ -361,7 +362,7 @@ static const struct clay_suite _clay_suites[] = {
"core::path",
{NULL, NULL},
{NULL, NULL},
- _clay_cb_core_path, 6
+ _clay_cb_core_path, 7
},
{
"core::rmdir",
@@ -516,7 +517,7 @@ static const struct clay_suite _clay_suites[] = {
};
static size_t _clay_suite_count = 36;
-static size_t _clay_callback_count = 119;
+static size_t _clay_callback_count = 120;
/* Core test functions */
static void
diff --git a/tests-clay/core/path.c b/tests-clay/core/path.c
index 1a588a39f..49f85f085 100644
--- a/tests-clay/core/path.c
+++ b/tests-clay/core/path.c
@@ -70,7 +70,7 @@ check_joinpath_n(
/* get the dirname of a path */
-void test_core_path__0(void)
+void test_core_path__0_dirname(void)
{
check_dirname(NULL, ".");
check_dirname("", ".");
@@ -90,7 +90,7 @@ void test_core_path__0(void)
}
/* get the base name of a path */
-void test_core_path__1(void)
+void test_core_path__1_basename(void)
{
check_basename(NULL, ".");
check_basename("", ".");
@@ -107,7 +107,7 @@ void test_core_path__1(void)
}
/* get the latest component in a path */
-void test_core_path__2(void)
+void test_core_path__2_topdir(void)
{
check_topdir(".git/", ".git/");
check_topdir("/.git/", ".git/");
@@ -124,7 +124,7 @@ void test_core_path__2(void)
}
/* properly join path components */
-void test_core_path__5(void)
+void test_core_path__5_joins(void)
{
check_joinpath("", "", "");
check_joinpath("", "a", "a");
@@ -148,6 +148,10 @@ void test_core_path__5(void)
check_joinpath("/abcdefgh", "/12345678/", "/abcdefgh/12345678/");
check_joinpath("/abcdefgh/", "12345678/", "/abcdefgh/12345678/");
+ check_joinpath(REP1024("aaaa"), "", REP1024("aaaa") "/");
+ check_joinpath(REP1024("aaaa/"), "", REP1024("aaaa/"));
+ check_joinpath(REP1024("/aaaa"), "", REP1024("/aaaa") "/");
+
check_joinpath(REP1024("aaaa"), REP1024("bbbb"),
REP1024("aaaa") "/" REP1024("bbbb"));
check_joinpath(REP1024("/aaaa"), REP1024("/bbbb"),
@@ -155,7 +159,7 @@ void test_core_path__5(void)
}
/* properly join path components for more than one path */
-void test_core_path__6(void)
+void test_core_path__6_long_joins(void)
{
check_joinpath_n("", "", "", "", "");
check_joinpath_n("", "a", "", "", "a/");
@@ -208,7 +212,7 @@ check_string_to_dir(
}
/* convert paths to dirs */
-void test_core_path__7(void)
+void test_core_path__7_path_to_dir(void)
{
check_path_to_dir("", "");
check_path_to_dir(".", "./");
@@ -234,3 +238,38 @@ void test_core_path__7(void)
check_string_to_dir("abcd", 5, "abcd/");
check_string_to_dir("abcd", 6, "abcd/");
}
+
+/* join path to itself */
+void test_core_path__8_self_join(void)
+{
+ git_buf path = GIT_BUF_INIT;
+ ssize_t asize = 0;
+
+ asize = path.asize;
+ cl_git_pass(git_buf_sets(&path, "/foo"));
+ cl_assert_strequal(path.ptr, "/foo");
+ cl_assert(asize < path.asize);
+
+ asize = path.asize;
+ cl_git_pass(git_buf_joinpath(&path, path.ptr, "this is a new string"));
+ cl_assert_strequal(path.ptr, "/foo/this is a new string");
+ cl_assert(asize < path.asize);
+
+ asize = path.asize;
+ cl_git_pass(git_buf_joinpath(&path, path.ptr, "/grow the buffer, grow the buffer, grow the buffer"));
+ cl_assert_strequal(path.ptr, "/foo/this is a new string/grow the buffer, grow the buffer, grow the buffer");
+ cl_assert(asize < path.asize);
+
+ git_buf_free(&path);
+ cl_git_pass(git_buf_sets(&path, "/foo/bar"));
+
+ cl_git_pass(git_buf_joinpath(&path, path.ptr + 4, "baz"));
+ cl_assert_strequal(path.ptr, "/bar/baz");
+
+ asize = path.asize;
+ cl_git_pass(git_buf_joinpath(&path, path.ptr + 4, "somethinglongenoughtorealloc"));
+ cl_assert_strequal(path.ptr, "/baz/somethinglongenoughtorealloc");
+ cl_assert(asize < path.asize);
+
+ git_buf_free(&path);
+}
diff --git a/tests/test_helpers.c b/tests/test_helpers.c
index d4ed10d94..40b3499bb 100644
--- a/tests/test_helpers.c
+++ b/tests/test_helpers.c
@@ -236,7 +236,7 @@ static int copy_filesystem_element_recurs(void *_data, git_buf *source)
copydir_data *data = (copydir_data *)_data;
git_buf_truncate(&data->dst, data->dst_baselen);
- git_buf_joinpath(&data->dst, data->dst.ptr, source->ptr + data->src_baselen);
+ git_buf_puts(&data->dst, source->ptr + data->src_baselen);
if (git_futils_isdir(source->ptr) == GIT_SUCCESS)
return git_futils_direach(source, copy_filesystem_element_recurs, _data);