aboutsummaryrefslogtreecommitdiffstats
path: root/path.c
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2025-04-15 11:38:15 +0200
committerJunio C Hamano <gitster@pobox.com>2025-04-15 08:24:35 -0700
commit1a99fe8010642a71063536510c578c1543d763b4 (patch)
tree1151da975bf092257d71b0c4420056265e9be0f8 /path.c
parentobject-file: move `mkdir_in_gitdir()` into "path.c" (diff)
downloadgit-1a99fe8010642a71063536510c578c1543d763b4.tar.gz
git-1a99fe8010642a71063536510c578c1543d763b4.zip
object-file: move `safe_create_leading_directories()` into "path.c"
The `safe_create_leading_directories()` function and its relatives are located in "object-file.c", which is not a good fit as they provide generic functionality not related to objects at all. Move them into "path.c", which already hosts `safe_create_dir()` and its relative `safe_create_dir_in_gitdir()`. "path.c" is free of `the_repository`, but the moved functions depend on `the_repository` to read the "core.sharedRepository" config. Adapt the function signature to accept a repository as argument to fix the issue and adjust callers accordingly. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'path.c')
-rw-r--r--path.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/path.c b/path.c
index c688f87458..62d67166df 100644
--- a/path.c
+++ b/path.c
@@ -931,6 +931,86 @@ int safe_create_dir_in_gitdir(struct repository *repo, const char *path)
return adjust_shared_perm(repo, path);
}
+static enum scld_error safe_create_leading_directories_1(struct repository *repo,
+ char *path)
+{
+ char *next_component = path + offset_1st_component(path);
+ enum scld_error ret = SCLD_OK;
+
+ while (ret == SCLD_OK && next_component) {
+ struct stat st;
+ char *slash = next_component, slash_character;
+
+ while (*slash && !is_dir_sep(*slash))
+ slash++;
+
+ if (!*slash)
+ break;
+
+ next_component = slash + 1;
+ while (is_dir_sep(*next_component))
+ next_component++;
+ if (!*next_component)
+ break;
+
+ slash_character = *slash;
+ *slash = '\0';
+ if (!stat(path, &st)) {
+ /* path exists */
+ if (!S_ISDIR(st.st_mode)) {
+ errno = ENOTDIR;
+ ret = SCLD_EXISTS;
+ }
+ } else if (mkdir(path, 0777)) {
+ if (errno == EEXIST &&
+ !stat(path, &st) && S_ISDIR(st.st_mode))
+ ; /* somebody created it since we checked */
+ else if (errno == ENOENT)
+ /*
+ * Either mkdir() failed because
+ * somebody just pruned the containing
+ * directory, or stat() failed because
+ * the file that was in our way was
+ * just removed. Either way, inform
+ * the caller that it might be worth
+ * trying again:
+ */
+ ret = SCLD_VANISHED;
+ else
+ ret = SCLD_FAILED;
+ } else if (repo && adjust_shared_perm(repo, path)) {
+ ret = SCLD_PERMS;
+ }
+ *slash = slash_character;
+ }
+ return ret;
+}
+
+enum scld_error safe_create_leading_directories(struct repository *repo,
+ char *path)
+{
+ return safe_create_leading_directories_1(repo, path);
+}
+
+enum scld_error safe_create_leading_directories_no_share(char *path)
+{
+ return safe_create_leading_directories_1(NULL, path);
+}
+
+enum scld_error safe_create_leading_directories_const(struct repository *repo,
+ const char *path)
+{
+ int save_errno;
+ /* path points to cache entries, so xstrdup before messing with it */
+ char *buf = xstrdup(path);
+ enum scld_error result = safe_create_leading_directories(repo, buf);
+
+ save_errno = errno;
+ free(buf);
+ errno = save_errno;
+ return result;
+}
+
static int have_same_root(const char *path1, const char *path2)
{
int is_abs1, is_abs2;