From 2fb9d6de95b7ba430cb2fab0da754a8074fa0c43 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 7 May 2012 10:04:50 +0200 Subject: [PATCH 1/9] remote: ensure the allocated remote is freed when an error occurs during its loading --- src/remote.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/remote.c b/src/remote.c index 98c256929..a30841427 100644 --- a/src/remote.c +++ b/src/remote.c @@ -102,11 +102,15 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) remote->name = git__strdup(name); GITERR_CHECK_ALLOC(remote->name); - if (git_vector_init(&remote->refs, 32, NULL) < 0) - return -1; + if (git_vector_init(&remote->refs, 32, NULL) < 0) { + error = -1; + goto cleanup; + } - if (git_buf_printf(&buf, "remote.%s.url", name) < 0) - return -1; + if (git_buf_printf(&buf, "remote.%s.url", name) < 0) { + error = -1; + goto cleanup; + } if (git_config_get_string(config, git_buf_cstr(&buf), &val) < 0) { error = -1; @@ -118,8 +122,10 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) GITERR_CHECK_ALLOC(remote->url); git_buf_clear(&buf); - if (git_buf_printf(&buf, "remote.%s.fetch", name) < 0) - return -1; + if (git_buf_printf(&buf, "remote.%s.fetch", name) < 0) { + error = -1; + goto cleanup; + } error = parse_remote_refspec(config, &remote->fetch, git_buf_cstr(&buf)); if (error == GIT_ENOTFOUND) @@ -131,8 +137,10 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) } git_buf_clear(&buf); - if (git_buf_printf(&buf, "remote.%s.push", name) < 0) - return -1; + if (git_buf_printf(&buf, "remote.%s.push", name) < 0) { + error = -1; + goto cleanup; + } error = parse_remote_refspec(config, &remote->push, git_buf_cstr(&buf)); if (error == GIT_ENOTFOUND) From 9fb70f378ace77bf20ec67c5bce044114a0e0f93 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 7 May 2012 10:57:34 +0200 Subject: [PATCH 2/9] remote: make git_remote_load() return GIT_ENOTFOUND when the remote url cannot be retrieved from the config file --- src/remote.c | 4 +--- tests-clar/network/remotes.c | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/remote.c b/src/remote.c index a30841427..6a1390dba 100644 --- a/src/remote.c +++ b/src/remote.c @@ -112,10 +112,8 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) goto cleanup; } - if (git_config_get_string(config, git_buf_cstr(&buf), &val) < 0) { - error = -1; + if ((error = git_config_get_string(config, git_buf_cstr(&buf), &val)) < 0) goto cleanup; - } remote->repo = repo; remote->url = git__strdup(val); diff --git a/tests-clar/network/remotes.c b/tests-clar/network/remotes.c index 766a461b9..f03d983c3 100644 --- a/tests-clar/network/remotes.c +++ b/tests-clar/network/remotes.c @@ -153,3 +153,8 @@ void test_network_remotes__list(void) git_config_free(cfg); } + +void test_network_remotes__loading_a_missing_remote_returns_ENOTFOUND(void) +{ + cl_assert_equal_i(GIT_ENOTFOUND, git_remote_load(&_remote, _repo, "just-left-few-minutes-ago")); +} From cb0ce16bbe8efe2098ef9cfffcf158301b036565 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 7 May 2012 15:42:13 +0200 Subject: [PATCH 3/9] object: make git_object_lookup() return GIT_ENOTFOUND when searching for an existing object by specifying an incorrect type --- src/object.c | 4 ++-- tests-clar/object/lookup.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 tests-clar/object/lookup.c diff --git a/src/object.c b/src/object.c index e02bd69ba..02be5dac8 100644 --- a/src/object.c +++ b/src/object.c @@ -150,8 +150,8 @@ int git_object_lookup_prefix( if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) { git_odb_object_free(odb_obj); - giterr_set(GITERR_INVALID, "The given type does not match the type on the ODB"); - return -1; + giterr_set(GITERR_ODB, "The given type does not match the type on the ODB"); + return GIT_ENOTFOUND; } type = odb_obj->raw.type; diff --git a/tests-clar/object/lookup.c b/tests-clar/object/lookup.c new file mode 100644 index 000000000..4db2ecfbe --- /dev/null +++ b/tests-clar/object/lookup.c @@ -0,0 +1,35 @@ +#include "clar_libgit2.h" + +#include "repository.h" + +static git_repository *g_repo; + +void test_object_lookup__initialize(void) +{ + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); +} + +void test_object_lookup__cleanup(void) +{ + git_repository_free(g_repo); +} + +void test_object_lookup__looking_up_an_exisiting_object_by_its_wrong_type_returns_ENOTFOUND(void) +{ + const char *commit = "e90810b8df3e80c413d903f631643c716887138d"; + git_oid oid; + git_object *object; + + cl_git_pass(git_oid_fromstr(&oid, commit)); + cl_assert_equal_i(GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_TAG)); +} + +void test_object_lookup__looking_up_a_non_exisiting_object_returns_ENOTFOUND(void) +{ + const char *unknown = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; + git_oid oid; + git_object *object; + + cl_git_pass(git_oid_fromstr(&oid, unknown)); + cl_assert_equal_i(GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_ANY)); +} From 46811561ae19701d4d0fc4b00113667f81961dfc Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 7 May 2012 13:56:42 +0200 Subject: [PATCH 4/9] path: Make git_path_prettify() properly handle ENOTDIR errno value --- src/path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/path.c b/src/path.c index 703f43af1..ccf80edb4 100644 --- a/src/path.c +++ b/src/path.c @@ -207,7 +207,7 @@ int git_path_prettify(git_buf *path_out, const char *path, const char *base) if (p_realpath(path, buf) == NULL) { giterr_set(GITERR_OS, "Failed to resolve path '%s'", path); git_buf_clear(path_out); - return (errno == ENOENT) ? GIT_ENOTFOUND : -1; + return (errno == ENOENT || errno == ENOTDIR) ? GIT_ENOTFOUND : -1; } return git_buf_sets(path_out, buf); From 9abb5bca5d094f832d2c68342aefc8809ec8ca09 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 7 May 2012 13:58:01 +0200 Subject: [PATCH 5/9] compat: make p_realpath Windows implementation be a bit more POSIX compliant and fail if the provided path does not lead to an existing entry --- src/path.c | 6 +++++- src/win32/posix_w32.c | 21 +++++++++++++++++---- tests-clar/core/path.c | 13 +++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/path.c b/src/path.c index ccf80edb4..9f31676b1 100644 --- a/src/path.c +++ b/src/path.c @@ -205,9 +205,13 @@ int git_path_prettify(git_buf *path_out, const char *path, const char *base) } if (p_realpath(path, buf) == NULL) { + /* giterr_set resets the errno when dealing with a GITERR_OS kind of error */ + int error = (errno == ENOENT || errno == ENOTDIR) ? GIT_ENOTFOUND : -1; giterr_set(GITERR_OS, "Failed to resolve path '%s'", path); + git_buf_clear(path_out); - return (errno == ENOENT || errno == ENOTDIR) ? GIT_ENOTFOUND : -1; + + return error; } return git_buf_sets(path_out, buf); diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 617291899..10de70da8 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -326,7 +326,7 @@ int p_hide_directory__w32(const char *path) char *p_realpath(const char *orig_path, char *buffer) { - int ret; + int ret, buffer_sz = 0; wchar_t* orig_path_w = gitwin_to_utf16(orig_path); wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t)); @@ -336,13 +336,14 @@ char *p_realpath(const char *orig_path, char *buffer) ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL); git__free(orig_path_w); - if (!ret || ret > GIT_PATH_MAX) { + /* According to MSDN, a return value equals to zero means a failure. */ + if (ret == 0 || ret > GIT_PATH_MAX) { buffer = NULL; goto done; } if (buffer == NULL) { - int buffer_sz = WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, NULL, 0, NULL, NULL); + buffer_sz = WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, NULL, 0, NULL, NULL); if (!buffer_sz || !(buffer = (char *)git__malloc(buffer_sz)) || @@ -350,10 +351,22 @@ char *p_realpath(const char *orig_path, char *buffer) { git__free(buffer); buffer = NULL; + goto done; } } else { - if (!WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL)) + if (!WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL)) { buffer = NULL; + goto done; + } + } + + if (!git_path_exists(buffer)) + { + if (buffer_sz > 0) + git__free(buffer); + + buffer = NULL; + errno = ENOENT; } done: diff --git a/tests-clar/core/path.c b/tests-clar/core/path.c index f02e0f761..d826612ac 100644 --- a/tests-clar/core/path.c +++ b/tests-clar/core/path.c @@ -405,3 +405,16 @@ void test_core_path__12_offset_to_path_root(void) cl_assert(git_path_root("//computername") == -1); #endif } + +#define NON_EXISTING_FILEPATH "i_hope_i_do_not_exist" + +void test_core_path__13_cannot_prettify_a_non_existing_file(void) +{ + git_buf p = GIT_BUF_INIT; + + cl_must_pass(git_path_exists(NON_EXISTING_FILEPATH) == false); + cl_assert_equal_i(GIT_ENOTFOUND, git_path_prettify(&p, NON_EXISTING_FILEPATH, NULL)); + cl_assert_equal_i(GIT_ENOTFOUND, git_path_prettify(&p, NON_EXISTING_FILEPATH "/so-do-i", NULL)); + + git_buf_free(&p); +} From d7d8a0bfd4ab86d7c87d4f318c6b3e6fa7dab746 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 7 May 2012 16:16:08 +0200 Subject: [PATCH 6/9] repository: ensure git_repository_open() returns ENOTFOUND when being passed a path leading to no repository --- tests-clar/repo/open.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests-clar/repo/open.c b/tests-clar/repo/open.c index 1813887ec..91443e8ae 100644 --- a/tests-clar/repo/open.c +++ b/tests-clar/repo/open.c @@ -274,3 +274,9 @@ void test_repo_open__win32_path(void) git_buf_free(&winpath); #endif } + +void test_repo_open__opening_a_non_existing_repository_returns_ENOTFOUND(void) +{ + git_repository *repo; + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_open(&repo, "i-do-not/exist")); +} \ No newline at end of file From 0b0957a66109b545ded7332591b4fcb8f7e13fd0 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 7 May 2012 17:04:06 +0200 Subject: [PATCH 7/9] fileops: replace integer usage with more explicit enum in some git_futils_rmdir_r() calls --- tests-clar/repo/discover.c | 2 +- tests-clar/repo/open.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests-clar/repo/discover.c b/tests-clar/repo/discover.c index 6b17d6dba..f1c084146 100644 --- a/tests-clar/repo/discover.c +++ b/tests-clar/repo/discover.c @@ -135,7 +135,7 @@ void test_repo_discover__0(void) ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path); - cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, 1)); + cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, GIT_DIRREMOVAL_FILES_AND_DIRS)); git_repository_free(repo); git_buf_free(&ceiling_dirs_buf); } diff --git a/tests-clar/repo/open.c b/tests-clar/repo/open.c index 91443e8ae..292466390 100644 --- a/tests-clar/repo/open.c +++ b/tests-clar/repo/open.c @@ -7,7 +7,7 @@ void test_repo_open__cleanup(void) cl_git_sandbox_cleanup(); if (git_path_isdir("alternate")) - git_futils_rmdir_r("alternate", 1); + git_futils_rmdir_r("alternate", GIT_DIRREMOVAL_FILES_AND_DIRS); } void test_repo_open__bare_empty_repo(void) @@ -202,8 +202,8 @@ void test_repo_open__bad_gitlinks(void) cl_git_fail(git_repository_open_ext(&repo, "alternate", 0, NULL)); } - git_futils_rmdir_r("invalid", 1); - git_futils_rmdir_r("invalid2", 1); + git_futils_rmdir_r("invalid", GIT_DIRREMOVAL_FILES_AND_DIRS); + git_futils_rmdir_r("invalid2", GIT_DIRREMOVAL_FILES_AND_DIRS); } #ifdef GIT_WIN32 From 464cf248fd05f76cd377298b98b82132c9088569 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 7 May 2012 17:25:16 +0200 Subject: [PATCH 8/9] repository: ensure git_repository_discover() returns ENOTFOUND when unable to find a repository given the constraints --- src/repository.c | 5 +++-- tests-clar/repo/discover.c | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/repository.c b/src/repository.c index d4de38104..ea9673731 100644 --- a/src/repository.c +++ b/src/repository.c @@ -397,13 +397,14 @@ int git_repository_discover( { git_buf path = GIT_BUF_INIT; uint32_t flags = across_fs ? GIT_REPOSITORY_OPEN_CROSS_FS : 0; + int error; assert(start_path && repository_path && size > 0); *repository_path = '\0'; - if (find_repo(&path, NULL, start_path, flags, ceiling_dirs) < 0) - return -1; + if ((error = find_repo(&path, NULL, start_path, flags, ceiling_dirs)) < 0) + return error != GIT_ENOTFOUND ? -1 : error; if (size < (size_t)(path.size + 1)) { giterr_set(GITERR_REPOSITORY, diff --git a/tests-clar/repo/discover.c b/tests-clar/repo/discover.c index f1c084146..b3d639bd1 100644 --- a/tests-clar/repo/discover.c +++ b/tests-clar/repo/discover.c @@ -82,7 +82,7 @@ void test_repo_discover__0(void) append_ceiling_dir(&ceiling_dirs_buf, TEMP_REPO_FOLDER); ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); - cl_git_fail(git_repository_discover(repository_path, sizeof(repository_path), DISCOVER_FOLDER, 0, ceiling_dirs)); + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(repository_path, sizeof(repository_path), DISCOVER_FOLDER, 0, ceiling_dirs)); cl_git_pass(git_repository_init(&repo, DISCOVER_FOLDER, 1)); cl_git_pass(git_repository_discover(repository_path, sizeof(repository_path), DISCOVER_FOLDER, 0, ceiling_dirs)); @@ -117,7 +117,7 @@ void test_repo_discover__0(void) cl_git_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs)); cl_git_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs)); cl_git_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs)); - cl_git_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs)); + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs)); append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER); ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); @@ -125,9 +125,9 @@ void test_repo_discover__0(void) //this must pass as ceiling_directories cannot predent the current //working directory to be checked cl_git_pass(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER, 0, ceiling_dirs)); - cl_git_fail(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs)); - cl_git_fail(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs)); - cl_git_fail(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs)); + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs)); + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs)); + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs)); //.gitfile redirection should not be affected by ceiling directories ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs, sub_repository_path); From 722c08afecfc2a9cb737e711a2bcc5f1a64c2b08 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 7 May 2012 21:21:48 +0200 Subject: [PATCH 9/9] status: Prevent git_status_file() from returning ENOTFOUND when not applicable --- src/status.c | 8 ++++---- tests-clar/status/worktree.c | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/status.c b/src/status.c index ff8535c66..546dc863d 100644 --- a/src/status.c +++ b/src/status.c @@ -340,17 +340,17 @@ int git_status_file( assert(status_flags && repo && path); if ((workdir = git_repository_workdir(repo)) == NULL) { - giterr_set(GITERR_OS, "Cannot get file status from bare repo"); - return GIT_ENOTFOUND; + giterr_set(GITERR_INVALID, "Cannot get file status from bare repo"); + return -1; } if (git_buf_joinpath(&temp_path, workdir, path) < 0) return -1; if (git_path_isdir(temp_path.ptr)) { - giterr_set(GITERR_OS, "Cannot get file status for directory '%s'", temp_path.ptr); + giterr_set(GITERR_INVALID, "Cannot get file status for directory '%s'", temp_path.ptr); git_buf_free(&temp_path); - return GIT_ENOTFOUND; + return -1; } e = status_entry_new(NULL, path); diff --git a/tests-clar/status/worktree.c b/tests-clar/status/worktree.c index 8f48cf16a..2a647ffb0 100644 --- a/tests-clar/status/worktree.c +++ b/tests-clar/status/worktree.c @@ -275,6 +275,7 @@ void test_status_worktree__single_folder(void) error = git_status_file(&status_flags, repo, "subdir"); cl_git_fail(error); + cl_assert(error != GIT_ENOTFOUND); } @@ -384,3 +385,18 @@ void test_status_worktree__issue_592_5(void) git_buf_free(&path); } + +void test_status_worktree__cannot_retrieve_the_status_of_a_bare_repository(void) +{ + git_repository *repo; + int error, status = 0; + + cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); + + error = git_status_file(&status, repo, "dummy"); + + cl_git_fail(error); + cl_assert(error != GIT_ENOTFOUND); + + git_repository_free(repo); +} \ No newline at end of file