diff options
author | Edward Thomson <ethomson@github.com> | 2021-09-27 08:39:39 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-27 08:39:39 -0400 |
commit | 853ba203208fcb4e7c3765f53a4d17a3db77f160 (patch) | |
tree | 20c1b9a712e79a3e56ae86ab6eda2b0645c0ca03 | |
parent | a6f6a9f4576b4d9bdcf9f9b1d6389a3f19f450da (diff) | |
parent | 091bd738d79d5485936578ed2cb7edb96efbc80f (diff) | |
download | libgit2-853ba203208fcb4e7c3765f53a4d17a3db77f160.tar.gz |
Merge pull request #6073 from libgit2/ethomson/attr_lookups
-rw-r--r-- | include/git2/repository.h | 12 | ||||
-rw-r--r-- | src/attr.c | 2 | ||||
-rw-r--r-- | src/blob.c | 9 | ||||
-rw-r--r-- | src/checkout.c | 13 | ||||
-rw-r--r-- | src/repository.c | 24 | ||||
-rw-r--r-- | src/win32/posix_w32.c | 3 | ||||
-rw-r--r-- | tests/repo/hashfile.c | 89 |
7 files changed, 123 insertions, 29 deletions
diff --git a/include/git2/repository.h b/include/git2/repository.h index e69901644..8d1cffc9b 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -762,13 +762,15 @@ GIT_EXTERN(int) git_repository_mergehead_foreach( * * @param out Output value of calculated SHA * @param repo Repository pointer - * @param path Path to file on disk whose contents should be hashed. If the - * repository is not NULL, this can be a relative path. + * @param path Path to file on disk whose contents should be hashed. This + * may be an absolute path or a relative path, in which case it + * will be treated as a path within the working directory. * @param type The object type to hash as (e.g. GIT_OBJECT_BLOB) * @param as_path The path to use to look up filtering rules. If this is - * NULL, then the `path` parameter will be used instead. If - * this is passed as the empty string, then no filters will be - * applied when calculating the hash. + * an empty string then no filters will be applied when + * calculating the hash. If this is `NULL` and the `path` + * parameter is a file within the repository's working + * directory, then the `path` will be used. * @return 0 on success, or an error code */ GIT_EXTERN(int) git_repository_hashfile( diff --git a/src/attr.c b/src/attr.c index 14eab5b46..cd704a490 100644 --- a/src/attr.c +++ b/src/attr.c @@ -629,6 +629,8 @@ static int collect_attr_files( const char *workdir = git_repository_workdir(repo); attr_walk_up_info info = { NULL }; + GIT_ASSERT(!git_path_is_absolute(path)); + if ((error = attr_setup(repo, attr_session, opts)) < 0) return error; diff --git a/src/blob.c b/src/blob.c index 06a4a0026..09b5b5d91 100644 --- a/src/blob.c +++ b/src/blob.c @@ -277,21 +277,20 @@ int git_blob_create_from_disk( { int error; git_buf full_path = GIT_BUF_INIT; - const char *workdir, *hintpath; + const char *workdir, *hintpath = NULL; if ((error = git_path_prettify(&full_path, path, NULL)) < 0) { git_buf_dispose(&full_path); return error; } - hintpath = git_buf_cstr(&full_path); workdir = git_repository_workdir(repo); - if (workdir && !git__prefixcmp(hintpath, workdir)) - hintpath += strlen(workdir); + if (workdir && !git__prefixcmp(full_path.ptr, workdir)) + hintpath = full_path.ptr + strlen(workdir); error = git_blob__create_from_paths( - id, NULL, repo, git_buf_cstr(&full_path), hintpath, 0, true); + id, NULL, repo, git_buf_cstr(&full_path), hintpath, 0, !!hintpath); git_buf_dispose(&full_path); return error; diff --git a/src/checkout.c b/src/checkout.c index 713159152..3a171066b 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -1520,8 +1520,7 @@ static int blob_content_to_file( int fd; int error = 0; - if (hint_path == NULL) - hint_path = path; + GIT_ASSERT(hint_path != NULL); if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0) return error; @@ -1789,7 +1788,7 @@ static int checkout_blob( } error = checkout_write_content( - data, &file->id, fullpath->ptr, NULL, file->mode, &st); + data, &file->id, fullpath->ptr, file->path, file->mode, &st); /* update the index unless prevented */ if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) @@ -1975,7 +1974,7 @@ static int checkout_write_entry( checkout_conflictdata *conflict, const git_index_entry *side) { - const char *hint_path = NULL, *suffix; + const char *hint_path, *suffix; git_buf *fullpath; struct stat st; int error; @@ -1998,10 +1997,10 @@ static int checkout_write_entry( if (checkout_path_suffixed(fullpath, suffix) < 0) return -1; - - hint_path = side->path; } + hint_path = side->path; + if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 && (error = checkout_safe_for_update_only(data, fullpath->ptr, side->mode)) <= 0) return error; @@ -2118,7 +2117,7 @@ static int checkout_write_merge( filter_session.temp_buf = &data->tmp; if ((error = git_filter_list__load( - &fl, data->repo, NULL, git_buf_cstr(&path_workdir), + &fl, data->repo, NULL, result.path, GIT_FILTER_TO_WORKTREE, &filter_session)) < 0 || (error = git_filter_list__convert_buf(&out_data, fl, &in_data)) < 0) goto done; diff --git a/src/repository.c b/src/repository.c index 8f0f477c4..9b3e9c9e3 100644 --- a/src/repository.c +++ b/src/repository.c @@ -2840,34 +2840,36 @@ int git_repository_hashfile( git_file fd = -1; uint64_t len; git_buf full_path = GIT_BUF_INIT; + const char *workdir = git_repository_workdir(repo); /* as_path can be NULL */ GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(path); GIT_ASSERT_ARG(repo); - /* At some point, it would be nice if repo could be NULL to just - * apply filter rules defined in system and global files, but for - * now that is not possible because git_filters_load() needs it. - */ - - if ((error = git_path_join_unrooted( - &full_path, path, git_repository_workdir(repo), NULL)) < 0 || + if ((error = git_path_join_unrooted(&full_path, path, workdir, NULL)) < 0 || (error = git_path_validate_workdir_buf(repo, &full_path)) < 0) return error; - if (!as_path) - as_path = path; + /* + * NULL as_path means that we should derive it from the + * given path. + */ + if (!as_path) { + if (workdir && !git__prefixcmp(full_path.ptr, workdir)) + as_path = full_path.ptr + strlen(workdir); + else + as_path = ""; + } /* passing empty string for "as_path" indicated --no-filters */ if (strlen(as_path) > 0) { error = git_filter_list_load( &fl, repo, NULL, as_path, GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT); + if (error < 0) return error; - } else { - error = 0; } /* at this point, error is a count of the number of loaded filters */ diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 66d12cfcf..8af07e6fa 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -648,6 +648,8 @@ int p_getcwd(char *buffer_out, size_t size) if (!cwd) return -1; + git_win32_path_remove_namespace(cwd, wcslen(cwd)); + /* Convert the working directory back to UTF-8 */ if (git__utf16_to_8(buffer_out, size, cwd) < 0) { DWORD code = GetLastError(); @@ -660,6 +662,7 @@ int p_getcwd(char *buffer_out, size_t size) return -1; } + git_path_mkposix(buffer_out); return 0; } diff --git a/tests/repo/hashfile.c b/tests/repo/hashfile.c index 0fb4e6772..bffb51bb5 100644 --- a/tests/repo/hashfile.c +++ b/tests/repo/hashfile.c @@ -10,6 +10,7 @@ void test_repo_hashfile__initialize(void) void test_repo_hashfile__cleanup(void) { + cl_fixture_cleanup("absolute"); cl_git_sandbox_cleanup(); _repo = NULL; } @@ -38,10 +39,18 @@ void test_repo_hashfile__simple(void) git_buf_dispose(&full); } -void test_repo_hashfile__filtered(void) +void test_repo_hashfile__filtered_in_workdir(void) { + git_buf root = GIT_BUF_INIT, txt = GIT_BUF_INIT, bin = GIT_BUF_INIT; + char cwd[GIT_PATH_MAX]; git_oid a, b; + cl_must_pass(p_getcwd(cwd, GIT_PATH_MAX)); + cl_must_pass(p_mkdir("absolute", 0777)); + cl_git_pass(git_buf_joinpath(&root, cwd, "status")); + cl_git_pass(git_buf_joinpath(&txt, root.ptr, "testfile.txt")); + cl_git_pass(git_buf_joinpath(&bin, root.ptr, "testfile.bin")); + cl_repo_set_bool(_repo, "core.autocrlf", true); cl_git_append2file("status/.gitattributes", "*.txt text\n*.bin binary\n\n"); @@ -55,21 +64,41 @@ void test_repo_hashfile__filtered(void) cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, NULL)); cl_assert(git_oid_cmp(&a, &b)); + /* not equal hashes because of filtering when specified by absolute path */ + cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB)); + cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, NULL)); + cl_assert(git_oid_cmp(&a, &b)); + /* equal hashes because filter is binary */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, NULL)); cl_assert_equal_oid(&a, &b); + /* equal hashes because filter is binary when specified by absolute path */ + cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB)); + cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, NULL)); + cl_assert_equal_oid(&a, &b); + /* equal hashes when 'as_file' points to binary filtering */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, "foo.bin")); cl_assert_equal_oid(&a, &b); + /* equal hashes when 'as_file' points to binary filtering (absolute path) */ + cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB)); + cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, "foo.bin")); + cl_assert_equal_oid(&a, &b); + /* not equal hashes when 'as_file' points to text filtering */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, "foo.txt")); cl_assert(git_oid_cmp(&a, &b)); + /* not equal hashes when 'as_file' points to text filtering */ + cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB)); + cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, "foo.txt")); + cl_assert(git_oid_cmp(&a, &b)); + /* equal hashes when 'as_file' is empty and turns off filtering */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, "")); @@ -79,7 +108,65 @@ void test_repo_hashfile__filtered(void) cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, "")); cl_assert_equal_oid(&a, &b); + cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB)); + cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, "")); + cl_assert_equal_oid(&a, &b); + + cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB)); + cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, "")); + cl_assert_equal_oid(&a, &b); + /* some hash type failures */ cl_git_fail(git_odb_hashfile(&a, "status/testfile.txt", 0)); cl_git_fail(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_ANY, NULL)); + + git_buf_dispose(&txt); + git_buf_dispose(&bin); + git_buf_dispose(&root); +} + +void test_repo_hashfile__filtered_outside_workdir(void) +{ + git_buf root = GIT_BUF_INIT, txt = GIT_BUF_INIT, bin = GIT_BUF_INIT; + char cwd[GIT_PATH_MAX]; + git_oid a, b; + + cl_must_pass(p_getcwd(cwd, GIT_PATH_MAX)); + cl_must_pass(p_mkdir("absolute", 0777)); + cl_git_pass(git_buf_joinpath(&root, cwd, "absolute")); + cl_git_pass(git_buf_joinpath(&txt, root.ptr, "testfile.txt")); + cl_git_pass(git_buf_joinpath(&bin, root.ptr, "testfile.bin")); + + cl_repo_set_bool(_repo, "core.autocrlf", true); + cl_git_append2file("status/.gitattributes", "*.txt text\n*.bin binary\n\n"); + + /* create some sample content with CRLF in it */ + cl_git_mkfile("absolute/testfile.txt", "content\r\n"); + cl_git_mkfile("absolute/testfile.bin", "other\r\nstuff\r\n"); + + /* not equal hashes because of filtering */ + cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.txt", GIT_OBJECT_BLOB)); + cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, "testfile.txt")); + cl_assert(git_oid_cmp(&a, &b)); + + /* equal hashes because filter is binary */ + cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.bin", GIT_OBJECT_BLOB)); + cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, "testfile.bin")); + cl_assert_equal_oid(&a, &b); + + /* + * equal hashes because no filtering occurs for absolute paths outside the working + * directory unless as_path is specified + */ + cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.txt", GIT_OBJECT_BLOB)); + cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, NULL)); + cl_assert_equal_oid(&a, &b); + + cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.bin", GIT_OBJECT_BLOB)); + cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, NULL)); + cl_assert_equal_oid(&a, &b); + + git_buf_dispose(&txt); + git_buf_dispose(&bin); + git_buf_dispose(&root); } |