repo: introduce git_repository_workdir_path Add a simple accessor for workdir paths to get an absolute on-disk path given a repository and a relative path within it. This is useful to avoid copy-pasta `git_buf_joinpath` and to ensure that we validate working directory paths while honoring `core.longpaths` settings.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
diff --git a/src/repository.c b/src/repository.c
index de1a895..c243f1d 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -2494,6 +2494,22 @@ const char *git_repository_workdir(const git_repository *repo)
return repo->workdir;
}
+int git_repository_workdir_path(
+ git_buf *out, git_repository *repo, const char *path)
+{
+ int error;
+
+ if (!repo->workdir) {
+ git_error_set(GIT_ERROR_REPOSITORY, "repository has no working directory");
+ return GIT_EBAREREPO;
+ }
+
+ if (!(error = git_buf_joinpath(out, repo->workdir, path)))
+ error = git_path_validate_workdir_buf(repo, out);
+
+ return error;
+}
+
const char *git_repository_commondir(const git_repository *repo)
{
GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL);
diff --git a/src/repository.h b/src/repository.h
index 4df8500..f48dd9e 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -241,4 +241,12 @@ bool git_repository__reserved_names(
*/
int git_repository_initialbranch(git_buf *out, git_repository *repo);
+/*
+ * Given a relative `path`, this makes it absolute based on the
+ * repository's working directory. This will perform validation
+ * to ensure that the path is not longer than MAX_PATH on Windows
+ * (unless `core.longpaths` is set in the repo config).
+ */
+int git_repository_workdir_path(git_buf *out, git_repository *repo, const char *path);
+
#endif
diff --git a/tests/win32/longpath.c b/tests/win32/longpath.c
index 80ae08d..b2efba4 100644
--- a/tests/win32/longpath.c
+++ b/tests/win32/longpath.c
@@ -4,6 +4,7 @@
#include "clone.h"
#include "buffer.h"
#include "futils.h"
+#include "repository.h"
static git_buf path = GIT_BUF_INIT;
@@ -29,6 +30,7 @@ void test_win32_longpath__initialize(void)
void test_win32_longpath__cleanup(void)
{
git_buf_dispose(&path);
+ cl_git_sandbox_cleanup();
}
#ifdef GIT_WIN32
@@ -60,3 +62,17 @@ void test_win32_longpath__errmsg_on_checkout(void)
assert_name_too_long();
#endif
}
+
+void test_win32_longpath__workdir_path_validated(void)
+{
+#ifdef GIT_WIN32
+ git_repository *repo = cl_git_sandbox_init("testrepo");
+ git_buf out = GIT_BUF_INIT;
+
+ cl_git_pass(git_repository_workdir_path(&out, repo, "a.txt"));
+
+ /* even if the repo path is a drive letter, this is too long */
+ cl_git_fail(git_repository_workdir_path(&out, repo, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.txt"));
+ cl_assert(git__prefixcmp(git_error_last()->message, "path too long") == 0);
+#endif
+}