diff options
| author | Patrick Steinhardt <ps@pks.im> | 2025-04-15 11:38:15 +0200 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2025-04-15 08:24:35 -0700 |
| commit | 1a99fe8010642a71063536510c578c1543d763b4 (patch) | |
| tree | 1151da975bf092257d71b0c4420056265e9be0f8 /path.c | |
| parent | object-file: move `mkdir_in_gitdir()` into "path.c" (diff) | |
| download | git-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.c | 80 |
1 files changed, 80 insertions, 0 deletions
@@ -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; |
