diff --git a/src/index.c b/src/index.c index 6fdb46e18..0e77105b8 100644 --- a/src/index.c +++ b/src/index.c @@ -289,8 +289,7 @@ int git_index_add(git_index *index, const char *rel_path, int stage) if (index->repository == NULL) return GIT_EBAREINDEX; - strcpy(full_path, index->repository->path_workdir); - strcat(full_path, rel_path); + git__joinpath(full_path, index->repository->path_workdir, rel_path); if (gitfo_exists(full_path) < 0) return GIT_ENOTFOUND; diff --git a/src/refs.c b/src/refs.c index eca50ddaa..a3055650f 100644 --- a/src/refs.c +++ b/src/refs.c @@ -159,8 +159,7 @@ static int read_loose_ref(gitfo_buf *file_content, const char *name, const char char ref_path[GIT_PATH_MAX]; /* Determine the full path of the ref */ - strcpy(ref_path, repo_path); - strcat(ref_path, name); + git__joinpath(ref_path, repo_path, name); /* Does it even exist ? */ if (gitfo_exists(ref_path) < GIT_SUCCESS) @@ -228,8 +227,7 @@ static int read_packed_refs(gitfo_buf *packfile, const char *repo_path) char ref_path[GIT_PATH_MAX]; /* Determine the full path of the file */ - strcpy(ref_path, repo_path); - strcat(ref_path, GIT_PACKEDREFS_FILE); + git__joinpath(ref_path, repo_path, GIT_PACKEDREFS_FILE); /* Does it even exist ? */ if (gitfo_exists(ref_path) < GIT_SUCCESS) @@ -528,8 +526,7 @@ int git_reference_write(git_reference *ref) if ((error = check_refname(ref->name)) < GIT_SUCCESS) return error; - strcpy(ref_path, ref->owner->path_repository); - strcat(ref_path, ref->name); + git__joinpath(ref_path, ref->owner->path_repository, ref->name); if ((error = git_filelock_init(&lock, ref_path)) < GIT_SUCCESS) goto error_cleanup; diff --git a/src/util.c b/src/util.c index 67b74eeba..fc1682f90 100644 --- a/src/util.c +++ b/src/util.c @@ -202,30 +202,30 @@ const char *git__topdir(const char *path) return &path[i + 1]; } -char *git__joinpath(const char *path_a, const char *path_b) +void git__joinpath_n(char *buffer_out, int count, ...) { - int len_a, len_b; - char *path_new; + va_list ap; + int i; - assert(path_a && path_b); + va_start(ap, count); + for (i = 0; i < count; ++i) { + const char *path; + int len; - len_a = strlen(path_a); - len_b = strlen(path_b); + path = va_arg(ap, const char *); + if (i > 0 && *path == '/') + path++; - path_new = git__malloc(len_a + len_b + 2); - if (path_new == NULL) - return NULL; + len = strlen(path); + memcpy(buffer_out, path, len); + buffer_out = buffer_out + len; - strcpy(path_new, path_a); + if (i < count - 1 && buffer_out[-1] != '/') + *buffer_out++ = '/'; + } + va_end(ap); - if (len_a > 0 && len_b > 0 && path_new[len_a - 1] != '/') - path_new[len_a++] = '/'; - - if (path_b[0] == '/') - path_b++; - - strcpy(path_new + len_a, path_b); - return path_new; + *buffer_out = '\0'; } static char *strtok_raw(char *output, char *src, char *delimit, int keep) diff --git a/src/util.h b/src/util.h index 0f010929f..d5320e15b 100644 --- a/src/util.h +++ b/src/util.h @@ -62,9 +62,15 @@ extern const char *git__topdir(const char *path); * Join two paths together. Takes care of properly fixing the * middle slashes and everything * - * Returns a newly allocated string; must be free'd manually. + * The paths are joined together into buffer_out; this is expected + * to be an user allocated buffer of `GIT_PATH_MAX` size */ -extern char *git__joinpath(const char *path_a, const char *path_b); +extern void git__joinpath_n(char *buffer_out, int npath, ...); + +GIT_INLINE(void) git__joinpath(char *buffer_out, const char *path_a, const char *path_b) +{ + git__joinpath_n(buffer_out, 2, path_a, path_b); +} extern void git__hexdump(const char *buffer, size_t n); extern uint32_t git__hash(const void *key, int len, uint32_t seed); @@ -84,18 +90,6 @@ GIT_INLINE(int) git__is_sizet(git_off_t p) # define git__rotl(v, s) (uint32_t)(((uint32_t)(v) << (s)) | ((uint32_t)(v) >> (32 - (s)))) #endif -enum git_splitpath_flags -{ - GIT_SPL_PATH = 1, - GIT_SPL_FILE = 2, - GIT_SPL_EXT = 4, - GIT_SPL_PATH_FILE = GIT_SPL_PATH + GIT_SPL_FILE, - GIT_SPL_FILE_EXT = GIT_SPL_FILE + GIT_SPL_EXT, - GIT_SPL_EXT_NO_PERIOD = 8, -}; - - -extern char *git__splitpath(char *path, int flag); extern char *git__strtok(char *output, char *src, char *delimit); extern char *git__strtok_keep(char *output, char *src, char *delimit); diff --git a/tests/t00-core.c b/tests/t00-core.c index f20aa9d76..96bf3e772 100644 --- a/tests/t00-core.c +++ b/tests/t00-core.c @@ -344,25 +344,15 @@ END_TEST static int ensure_joinpath(const char *path_a, const char *path_b, const char *expected_path) { - int error = GIT_SUCCESS; - char* joined_path; - - joined_path = git__joinpath(path_a, path_b); - if (joined_path == NULL) - return GIT_ERROR; - - if (strcmp(joined_path, expected_path)) - error = GIT_ERROR; - - free(joined_path); - - return error; + char joined_path[GIT_PATH_MAX]; + git__joinpath(joined_path, path_a, path_b); + return strcmp(joined_path, expected_path) == 0 ? GIT_SUCCESS : GIT_ERROR; } BEGIN_TEST("path", joinpath) - must_pass(ensure_joinpath("", "", "")); - must_pass(ensure_joinpath("", "a", "a")); - must_pass(ensure_joinpath("a", "", "a")); + must_pass(ensure_joinpath("", "", "/")); + must_pass(ensure_joinpath("", "a", "/a")); + must_pass(ensure_joinpath("a", "", "a/")); must_pass(ensure_joinpath("a", "b", "a/b")); must_pass(ensure_joinpath("/", "a", "/a")); must_pass(ensure_joinpath("/", "", "/")); diff --git a/tests/t10-refs.c b/tests/t10-refs.c index 222f09997..2d055c978 100644 --- a/tests/t10-refs.c +++ b/tests/t10-refs.c @@ -192,7 +192,7 @@ BEGIN_TEST("createref", create_new_symbolic_ref) git_reference *new_reference, *looked_up_ref, *resolved_ref; git_repository *repo; git_oid id; - char *ref_path; + char ref_path[GIT_PATH_MAX]; const char *new_head_tracker = "another-head-tracker"; @@ -201,8 +201,7 @@ BEGIN_TEST("createref", create_new_symbolic_ref) must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); /* Retrieve the physical path to the symbolic ref for further cleaning */ - ref_path = git__joinpath(repo->path_repository, new_head_tracker); - must_be_true(ref_path != NULL); + git__joinpath(ref_path, repo->path_repository, new_head_tracker); /* Create and write the new symbolic reference */ must_pass(git_reference_new(&new_reference, repo)); @@ -211,16 +210,16 @@ BEGIN_TEST("createref", create_new_symbolic_ref) must_pass(git_reference_write(new_reference)); /* Ensure the reference can be looked-up... */ - must_pass(git_repository_lookup_ref(&looked_up_ref, repo, new_head_tracker)); - must_be_true(looked_up_ref->type == GIT_REF_SYMBOLIC); - must_be_true(looked_up_ref->packed == 0); - must_be_true(strcmp(looked_up_ref->name, new_head_tracker) == 0); - - /* ...peeled.. */ - must_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); - must_be_true(resolved_ref->type == GIT_REF_OID); - - /* ...and that it points to the current master tip */ + must_pass(git_repository_lookup_ref(&looked_up_ref, repo, new_head_tracker)); + must_be_true(looked_up_ref->type == GIT_REF_SYMBOLIC); + must_be_true(looked_up_ref->packed == 0); + must_be_true(strcmp(looked_up_ref->name, new_head_tracker) == 0); + + /* ...peeled.. */ + must_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); + must_be_true(resolved_ref->type == GIT_REF_OID); + + /* ...and that it points to the current master tip */ must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0); git_repository_free(repo); @@ -228,21 +227,20 @@ BEGIN_TEST("createref", create_new_symbolic_ref) /* Similar test with a fresh new repository */ must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_lookup_ref(&looked_up_ref, repo, new_head_tracker)); - must_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); + must_pass(git_repository_lookup_ref(&looked_up_ref, repo, new_head_tracker)); + must_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0); git_repository_free(repo); must_pass(gitfo_unlink(ref_path)); /* TODO: replace with git_reference_delete() when available */ - free(ref_path); END_TEST BEGIN_TEST("createref", create_new_object_id_ref) git_reference *new_reference, *looked_up_ref; git_repository *repo; git_oid id; - char *ref_path; + char ref_path[GIT_PATH_MAX]; const char *new_head = "refs/heads/new-head"; @@ -251,8 +249,7 @@ BEGIN_TEST("createref", create_new_object_id_ref) must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); /* Retrieve the physical path to the symbolic ref for further cleaning */ - ref_path = git__joinpath(repo->path_repository, new_head); - must_be_true(ref_path != NULL); + git__joinpath(ref_path, repo->path_repository, new_head); /* Create and write the new object id reference */ must_pass(git_reference_new(&new_reference, repo)); @@ -261,12 +258,12 @@ BEGIN_TEST("createref", create_new_object_id_ref) must_pass(git_reference_write(new_reference)); /* Ensure the reference can be looked-up... */ - must_pass(git_repository_lookup_ref(&looked_up_ref, repo, new_head)); - must_be_true(looked_up_ref->type == GIT_REF_OID); - must_be_true(looked_up_ref->packed == 0); - must_be_true(strcmp(looked_up_ref->name, new_head) == 0); - - /* ...and that it points to the current master tip */ + must_pass(git_repository_lookup_ref(&looked_up_ref, repo, new_head)); + must_be_true(looked_up_ref->type == GIT_REF_OID); + must_be_true(looked_up_ref->packed == 0); + must_be_true(strcmp(looked_up_ref->name, new_head) == 0); + + /* ...and that it points to the current master tip */ must_be_true(git_oid_cmp(&id, git_reference_oid(looked_up_ref)) == 0); git_repository_free(repo); @@ -274,13 +271,12 @@ BEGIN_TEST("createref", create_new_object_id_ref) /* Similar test with a fresh new repository */ must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_lookup_ref(&looked_up_ref, repo, new_head)); + must_pass(git_repository_lookup_ref(&looked_up_ref, repo, new_head)); must_be_true(git_oid_cmp(&id, git_reference_oid(looked_up_ref)) == 0); git_repository_free(repo); must_pass(gitfo_unlink(ref_path)); /* TODO: replace with git_reference_delete() when available */ - free(ref_path); END_TEST git_testsuite *libgit2_suite_refs(void)