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>

Patrick Steinhardt committed Apr 15, 2025 at 11:38 UTC 1a99fe8010642a71063536510c578c1543d763b4
27 files changed +173 -167
builtin/bugreport.c
+2 -2
@@ -4,13 +4,13 @@
4 #include "editor.h"
5 #include "gettext.h"
6 #include "parse-options.h"
7 +#include "path.h"
8 #include "strbuf.h"
9 #include "help.h"
10 #include "compat/compiler.h"
11 #include "hook.h"
12 #include "hook-list.h"
13 #include "diagnose.h"
13 -#include "object-file.h"
14 #include "setup.h"
15 #include "version.h"
16
@@ -141,7 +141,7 @@ int cmd_bugreport(int argc,
141 }
142 strbuf_addstr(&report_path, ".txt");
143
144 - switch (safe_create_leading_directories(report_path.buf)) {
144 + switch (safe_create_leading_directories(the_repository, report_path.buf)) {
145 case SCLD_OK:
146 case SCLD_EXISTS:
147 break;
builtin/clone.c
+2 -2
@@ -1090,7 +1090,7 @@ int cmd_clone(int argc,
1090 sigchain_push_common(remove_junk_on_signal);
1091
1092 if (!option_bare) {
1093 - if (safe_create_leading_directories_const(work_tree) < 0)
1093 + if (safe_create_leading_directories_const(the_repository, work_tree) < 0)
1094 die_errno(_("could not create leading directories of '%s'"),
1095 work_tree);
1096 if (dest_exists)
@@ -1111,7 +1111,7 @@ int cmd_clone(int argc,
1111 junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
1112 junk_git_dir = git_dir;
1113 }
1114 - if (safe_create_leading_directories_const(git_dir) < 0)
1114 + if (safe_create_leading_directories_const(the_repository, git_dir) < 0)
1115 die(_("could not create leading directories of '%s'"), git_dir);
1116
1117 if (0 <= option_verbosity) {
builtin/credential-cache--daemon.c
+2 -2
@@ -2,8 +2,8 @@
2 #include "builtin.h"
3 #include "abspath.h"
4 #include "gettext.h"
5 -#include "object-file.h"
5 #include "parse-options.h"
6 +#include "path.h"
7
8 #ifndef NO_UNIX_SOCKETS
9
@@ -271,7 +271,7 @@ static void init_socket_directory(const char *path)
271 * condition in which somebody can chdir to it, sleep, then try to open
272 * our protected socket.
273 */
274 - if (safe_create_leading_directories_const(dir) < 0)
274 + if (safe_create_leading_directories_const(the_repository, dir) < 0)
275 die_errno("unable to create directories for '%s'", dir);
276 if (mkdir(dir, 0700) < 0)
277 die_errno("unable to mkdir '%s'", dir);
builtin/diagnose.c
+2 -2
@@ -3,8 +3,8 @@
3 #include "builtin.h"
4 #include "abspath.h"
5 #include "gettext.h"
6 -#include "object-file.h"
6 #include "parse-options.h"
7 +#include "path.h"
8 #include "diagnose.h"
9
10 static const char * const diagnose_usage[] = {
@@ -50,7 +50,7 @@ int cmd_diagnose(int argc,
50 strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
51 strbuf_addstr(&zip_path, ".zip");
52
53 - switch (safe_create_leading_directories(zip_path.buf)) {
53 + switch (safe_create_leading_directories(the_repository, zip_path.buf)) {
54 case SCLD_OK:
55 case SCLD_EXISTS:
56 break;
builtin/difftool.c
+16 -13
@@ -22,6 +22,7 @@
22 #include "gettext.h"
23 #include "hex.h"
24 #include "parse-options.h"
25 +#include "path.h"
26 #include "read-cache-ll.h"
27 #include "repository.h"
28 #include "sparse-index.h"
@@ -271,9 +272,9 @@ static void changed_files(struct repository *repo,
272 strbuf_release(&buf);
273 }
274
274 -static int ensure_leading_directories(char *path)
275 +static int ensure_leading_directories(struct repository *repo, char *path)
276 {
276 - switch (safe_create_leading_directories(path)) {
277 + switch (safe_create_leading_directories(repo, path)) {
278 case SCLD_OK:
279 case SCLD_EXISTS:
280 return 0;
@@ -341,11 +342,12 @@ static int checkout_path(unsigned mode, struct object_id *oid,
342 return ret;
343 }
344
344 -static void write_file_in_directory(struct strbuf *dir, size_t dir_len,
345 - const char *path, const char *content)
345 +static void write_file_in_directory(struct repository *repo,
346 + struct strbuf *dir, size_t dir_len,
347 + const char *path, const char *content)
348 {
349 add_path(dir, dir_len, path);
348 - ensure_leading_directories(dir->buf);
350 + ensure_leading_directories(repo, dir->buf);
351 unlink(dir->buf);
352 write_file(dir->buf, "%s", content);
353 }
@@ -356,14 +358,15 @@ static void write_file_in_directory(struct strbuf *dir, size_t dir_len,
358 * as text files, resulting in behavior that is analogous to what "git diff"
359 * displays for symlink and submodule diffs.
360 */
359 -static void write_standin_files(struct pair_entry *entry,
360 - struct strbuf *ldir, size_t ldir_len,
361 - struct strbuf *rdir, size_t rdir_len)
361 +static void write_standin_files(struct repository *repo,
362 + struct pair_entry *entry,
363 + struct strbuf *ldir, size_t ldir_len,
364 + struct strbuf *rdir, size_t rdir_len)
365 {
366 if (*entry->left)
364 - write_file_in_directory(ldir, ldir_len, entry->path, entry->left);
367 + write_file_in_directory(repo, ldir, ldir_len, entry->path, entry->left);
368 if (*entry->right)
366 - write_file_in_directory(rdir, rdir_len, entry->path, entry->right);
369 + write_file_in_directory(repo, rdir, rdir_len, entry->path, entry->right);
370 }
371
372 static int run_dir_diff(struct repository *repo,
@@ -533,7 +536,7 @@ static int run_dir_diff(struct repository *repo,
536 ADD_CACHE_JUST_APPEND);
537
538 add_path(&rdir, rdir_len, dst_path);
536 - if (ensure_leading_directories(rdir.buf)) {
539 + if (ensure_leading_directories(repo, rdir.buf)) {
540 ret = error("could not create "
541 "directory for '%s'",
542 dst_path);
@@ -576,7 +579,7 @@ static int run_dir_diff(struct repository *repo,
579 */
580 hashmap_for_each_entry(&submodules, &iter, entry,
581 entry /* member name */) {
579 - write_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);
582 + write_standin_files(repo, entry, &ldir, ldir_len, &rdir, rdir_len);
583 }
584
585 /*
@@ -587,7 +590,7 @@ static int run_dir_diff(struct repository *repo,
590 hashmap_for_each_entry(&symlinks2, &iter, entry,
591 entry /* member name */) {
592
590 - write_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);
593 + write_standin_files(repo, entry, &ldir, ldir_len, &rdir, rdir_len);
594 }
595
596 strbuf_setlen(&ldir, ldir_len);
builtin/fast-import.c
+1 -1
@@ -1720,7 +1720,7 @@ static void dump_marks(void)
1720 if (!export_marks_file || (import_marks_file && !import_marks_file_done))
1721 return;
1722
1723 - if (safe_create_leading_directories_const(export_marks_file)) {
1723 + if (safe_create_leading_directories_const(the_repository, export_marks_file)) {
1724 failure |= error_errno("unable to create leading directories of %s",
1725 export_marks_file);
1726 return;
builtin/fsck.c
+1 -1
@@ -332,7 +332,7 @@ static void check_unreachable_object(struct object *obj)
332 describe_object(&obj->oid));
333 FILE *f;
334
335 - if (safe_create_leading_directories_const(filename)) {
335 + if (safe_create_leading_directories_const(the_repository, filename)) {
336 error(_("could not create lost-found"));
337 free(filename);
338 return;
builtin/gc.c
+3 -4
@@ -28,7 +28,6 @@
28 #include "commit.h"
29 #include "commit-graph.h"
30 #include "packfile.h"
31 -#include "object-file.h"
31 #include "object-store-ll.h"
32 #include "pack.h"
33 #include "pack-objects.h"
@@ -2099,7 +2098,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
2098 }
2099 strbuf_addstr(&plist, "</array>\n</dict>\n</plist>\n");
2100
2102 - if (safe_create_leading_directories(filename))
2101 + if (safe_create_leading_directories(the_repository, filename))
2102 die(_("failed to create directories for '%s'"), filename);
2103
2104 if ((long)lock_file_timeout_ms < 0 &&
@@ -2565,7 +2564,7 @@ static int systemd_timer_write_timer_file(enum schedule_priority schedule,
2564
2565 filename = xdg_config_home_systemd(local_timer_name);
2566
2568 - if (safe_create_leading_directories(filename)) {
2567 + if (safe_create_leading_directories(the_repository, filename)) {
2568 error(_("failed to create directories for '%s'"), filename);
2569 goto error;
2570 }
@@ -2638,7 +2637,7 @@ static int systemd_timer_write_service_template(const char *exec_path)
2637 char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service");
2638
2639 filename = xdg_config_home_systemd(local_service_name);
2641 - if (safe_create_leading_directories(filename)) {
2640 + if (safe_create_leading_directories(the_repository, filename)) {
2641 error(_("failed to create directories for '%s'"), filename);
2642 goto error;
2643 }
builtin/init-db.c
+1 -2
@@ -8,7 +8,6 @@
8 #include "abspath.h"
9 #include "environment.h"
10 #include "gettext.h"
11 -#include "object-file.h"
11 #include "parse-options.h"
12 #include "path.h"
13 #include "refs.h"
@@ -134,7 +133,7 @@ int cmd_init_db(int argc,
133 */
134 saved = repo_settings_get_shared_repository(the_repository);
135 repo_settings_set_shared_repository(the_repository, 0);
137 - switch (safe_create_leading_directories_const(argv[0])) {
136 + switch (safe_create_leading_directories_const(the_repository, argv[0])) {
137 case SCLD_OK:
138 case SCLD_PERMS:
139 break;
builtin/log.c
+2 -2
@@ -14,7 +14,6 @@
14 #include "gettext.h"
15 #include "hex.h"
16 #include "refs.h"
17 -#include "object-file.h"
17 #include "object-name.h"
18 #include "object-store-ll.h"
19 #include "pager.h"
@@ -29,6 +28,7 @@
28 #include "tag.h"
29 #include "reflog-walk.h"
30 #include "patch-ids.h"
31 +#include "path.h"
32 #include "shortlog.h"
33 #include "remote.h"
34 #include "string-list.h"
@@ -2311,7 +2311,7 @@ int cmd_format_patch(int argc,
2311 */
2312 saved = repo_settings_get_shared_repository(the_repository);
2313 repo_settings_set_shared_repository(the_repository, 0);
2314 - switch (safe_create_leading_directories_const(output_directory)) {
2314 + switch (safe_create_leading_directories_const(the_repository, output_directory)) {
2315 case SCLD_OK:
2316 case SCLD_EXISTS:
2317 break;
builtin/mv.c
+2 -1
@@ -15,6 +15,7 @@
15 #include "gettext.h"
16 #include "name-hash.h"
17 #include "object-file.h"
18 +#include "path.h"
19 #include "pathspec.h"
20 #include "lockfile.h"
21 #include "dir.h"
@@ -555,7 +556,7 @@ remove_entry:
556 */
557 char *dst_dup = xstrdup(dst);
558 string_list_append(&dirty_paths, dst);
558 - safe_create_leading_directories(dst_dup);
559 + safe_create_leading_directories(the_repository, dst_dup);
560 FREE_AND_NULL(dst_dup);
561 rename(src, dst);
562 }
builtin/sparse-checkout.c
+3 -2
@@ -9,6 +9,7 @@
9 #include "object-file.h"
10 #include "object-name.h"
11 #include "parse-options.h"
12 +#include "path.h"
13 #include "pathspec.h"
14 #include "strbuf.h"
15 #include "string-list.h"
@@ -335,7 +336,7 @@ static int write_patterns_and_update(struct pattern_list *pl)
336
337 sparse_filename = get_sparse_checkout_filename();
338
338 - if (safe_create_leading_directories(sparse_filename))
339 + if (safe_create_leading_directories(the_repository, sparse_filename))
340 die(_("failed to create directory for sparse-checkout file"));
341
342 hold_lock_file_for_update(&lk, sparse_filename, LOCK_DIE_ON_ERROR);
@@ -491,7 +492,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix,
492 FILE *fp;
493
494 /* assume we are in a fresh repo, but update the sparse-checkout file */
494 - if (safe_create_leading_directories(sparse_filename))
495 + if (safe_create_leading_directories(the_repository, sparse_filename))
496 die(_("unable to create leading directories of %s"),
497 sparse_filename);
498 fp = xfopen(sparse_filename, "w");
builtin/submodule--helper.c
+2 -2
@@ -1739,7 +1739,7 @@ static int clone_submodule(const struct module_clone_data *clone_data,
1739 !is_empty_dir(clone_data_path))
1740 die(_("directory not empty: '%s'"), clone_data_path);
1741
1742 - if (safe_create_leading_directories_const(sm_gitdir) < 0)
1742 + if (safe_create_leading_directories_const(the_repository, sm_gitdir) < 0)
1743 die(_("could not create directory '%s'"), sm_gitdir);
1744
1745 prepare_possible_alternates(clone_data->name, reference);
@@ -1800,7 +1800,7 @@ static int clone_submodule(const struct module_clone_data *clone_data,
1800 if (clone_data->require_init && !stat(clone_data_path, &st) &&
1801 !is_empty_dir(clone_data_path))
1802 die(_("directory not empty: '%s'"), clone_data_path);
1803 - if (safe_create_leading_directories_const(clone_data_path) < 0)
1803 + if (safe_create_leading_directories_const(the_repository, clone_data_path) < 0)
1804 die(_("could not create directory '%s'"), clone_data_path);
1805 path = xstrfmt("%s/index", sm_gitdir);
1806 unlink_or_warn(path);
builtin/worktree.c
+4 -4
@@ -348,7 +348,7 @@ static void copy_sparse_checkout(const char *worktree_git_dir)
348 char *to_file = xstrfmt("%s/info/sparse-checkout", worktree_git_dir);
349
350 if (file_exists(from_file)) {
351 - if (safe_create_leading_directories(to_file) ||
351 + if (safe_create_leading_directories(the_repository, to_file) ||
352 copy_file(to_file, from_file, 0666))
353 error(_("failed to copy '%s' to '%s'; sparse-checkout may not work correctly"),
354 from_file, to_file);
@@ -367,7 +367,7 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
367 struct config_set cs = { { 0 } };
368 int bare;
369
370 - if (safe_create_leading_directories(to_file) ||
370 + if (safe_create_leading_directories(the_repository, to_file) ||
371 copy_file(to_file, from_file, 0666)) {
372 error(_("failed to copy worktree config from '%s' to '%s'"),
373 from_file, to_file);
@@ -466,7 +466,7 @@ static int add_worktree(const char *path, const char *refname,
466 name = sb_name.buf;
467 repo_git_path_replace(the_repository, &sb_repo, "worktrees/%s", name);
468 len = sb_repo.len;
469 - if (safe_create_leading_directories_const(sb_repo.buf))
469 + if (safe_create_leading_directories_const(the_repository, sb_repo.buf))
470 die_errno(_("could not create leading directories of '%s'"),
471 sb_repo.buf);
472
@@ -498,7 +498,7 @@ static int add_worktree(const char *path, const char *refname,
498 write_file(sb.buf, _("initializing"));
499
500 strbuf_addf(&sb_git, "%s/.git", path);
501 - if (safe_create_leading_directories_const(sb_git.buf))
501 + if (safe_create_leading_directories_const(the_repository, sb_git.buf))
502 die_errno(_("could not create leading directories of '%s'"),
503 sb_git.buf);
504 junk_work_tree = xstrdup(path);
commit-graph.c
+1 -1
@@ -2065,7 +2065,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
2065 ctx->graph_name = get_commit_graph_filename(ctx->odb);
2066 }
2067
2068 - if (safe_create_leading_directories(ctx->graph_name)) {
2068 + if (safe_create_leading_directories(the_repository, ctx->graph_name)) {
2069 error(_("unable to create leading directories of %s"),
2070 ctx->graph_name);
2071 return -1;
dir.c
+2 -3
@@ -17,7 +17,6 @@
17 #include "environment.h"
18 #include "gettext.h"
19 #include "name-hash.h"
20 -#include "object-file.h"
20 #include "object-store-ll.h"
21 #include "path.h"
22 #include "refs.h"
@@ -4063,12 +4062,12 @@ void connect_work_tree_and_git_dir(const char *work_tree_,
4062
4063 /* Prepare .git file */
4064 strbuf_addf(&gitfile_sb, "%s/.git", work_tree_);
4066 - if (safe_create_leading_directories_const(gitfile_sb.buf))
4065 + if (safe_create_leading_directories_const(the_repository, gitfile_sb.buf))
4066 die(_("could not create directories for %s"), gitfile_sb.buf);
4067
4068 /* Prepare config file */
4069 strbuf_addf(&cfg_sb, "%s/config", git_dir_);
4071 - if (safe_create_leading_directories_const(cfg_sb.buf))
4070 + if (safe_create_leading_directories_const(the_repository, cfg_sb.buf))
4071 die(_("could not create directories for %s"), cfg_sb.buf);
4072
4073 git_dir = real_pathdup(git_dir_, 1);
merge-recursive.c
+2 -2
@@ -910,7 +910,7 @@ static int make_room_for_path(struct merge_options *opt, const char *path)
910 }
911
912 /* Make sure leading directories are created */
913 - status = safe_create_leading_directories_const(path);
913 + status = safe_create_leading_directories_const(the_repository, path);
914 if (status) {
915 if (status == SCLD_EXISTS)
916 /* something else exists */
@@ -1003,7 +1003,7 @@ static int update_file_flags(struct merge_options *opt,
1003 close(fd);
1004 } else if (S_ISLNK(contents->mode)) {
1005 char *lnk = xmemdupz(buf, size);
1006 - safe_create_leading_directories_const(path);
1006 + safe_create_leading_directories_const(the_repository, path);
1007 unlink(path);
1008 if (symlink(lnk, path))
1009 ret = err(opt, _("failed to symlink '%s': %s"),
midx-write.c
+1 -1
@@ -1086,7 +1086,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
1086 object_dir);
1087 else
1088 get_midx_filename(r->hash_algo, &midx_name, object_dir);
1089 - if (safe_create_leading_directories(midx_name.buf))
1089 + if (safe_create_leading_directories(r, midx_name.buf))
1090 die_errno(_("unable to create leading directories of %s"),
1091 midx_name.buf);
1092
notes-merge.c
+2 -2
@@ -296,7 +296,7 @@ static void check_notes_merge_worktree(struct notes_merge_options *o)
296 "(%s exists)."), repo_git_path_replace(the_repository, &buf, "NOTES_MERGE_*"));
297 }
298
299 - if (safe_create_leading_directories_const(repo_git_path_replace(the_repository, &buf,
299 + if (safe_create_leading_directories_const(the_repository, repo_git_path_replace(the_repository, &buf,
300 NOTES_MERGE_WORKTREE "/.test")))
301 die_errno("unable to create directory %s",
302 repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE));
@@ -314,7 +314,7 @@ static void write_buf_to_worktree(const struct object_id *obj,
314 {
315 int fd;
316 char *path = repo_git_path(the_repository, NOTES_MERGE_WORKTREE "/%s", oid_to_hex(obj));
317 - if (safe_create_leading_directories_const(path))
317 + if (safe_create_leading_directories_const(the_repository, path))
318 die_errno("unable to create directory for '%s'", path);
319
320 fd = xopen(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
object-file.c
+2 -79
@@ -90,83 +90,6 @@ static int get_conv_flags(unsigned flags)
90 return 0;
91 }
92
93 -static enum scld_error safe_create_leading_directories_1(char *path, int share)
94 -{
95 - char *next_component = path + offset_1st_component(path);
96 - enum scld_error ret = SCLD_OK;
97 -
98 - while (ret == SCLD_OK && next_component) {
99 - struct stat st;
100 - char *slash = next_component, slash_character;
101 -
102 - while (*slash && !is_dir_sep(*slash))
103 - slash++;
104 -
105 - if (!*slash)
106 - break;
107 -
108 - next_component = slash + 1;
109 - while (is_dir_sep(*next_component))
110 - next_component++;
111 - if (!*next_component)
112 - break;
113 -
114 - slash_character = *slash;
115 - *slash = '\0';
116 - if (!stat(path, &st)) {
117 - /* path exists */
118 - if (!S_ISDIR(st.st_mode)) {
119 - errno = ENOTDIR;
120 - ret = SCLD_EXISTS;
121 - }
122 - } else if (mkdir(path, 0777)) {
123 - if (errno == EEXIST &&
124 - !stat(path, &st) && S_ISDIR(st.st_mode))
125 - ; /* somebody created it since we checked */
126 - else if (errno == ENOENT)
127 - /*
128 - * Either mkdir() failed because
129 - * somebody just pruned the containing
130 - * directory, or stat() failed because
131 - * the file that was in our way was
132 - * just removed. Either way, inform
133 - * the caller that it might be worth
134 - * trying again:
135 - */
136 - ret = SCLD_VANISHED;
137 - else
138 - ret = SCLD_FAILED;
139 - } else if (share && adjust_shared_perm(the_repository, path)) {
140 - ret = SCLD_PERMS;
141 - }
142 - *slash = slash_character;
143 - }
144 - return ret;
145 -}
146 -
147 -enum scld_error safe_create_leading_directories(char *path)
148 -{
149 - return safe_create_leading_directories_1(path, 1);
150 -}
151 -
152 -enum scld_error safe_create_leading_directories_no_share(char *path)
153 -{
154 - return safe_create_leading_directories_1(path, 0);
155 -}
156 -
157 -enum scld_error safe_create_leading_directories_const(const char *path)
158 -{
159 - int save_errno;
160 - /* path points to cache entries, so xstrdup before messing with it */
161 - char *buf = xstrdup(path);
162 - enum scld_error result = safe_create_leading_directories(buf);
163 -
164 - save_errno = errno;
165 - free(buf);
166 - errno = save_errno;
167 - return result;
168 -}
169 -
93 int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
94 {
95 int fd;
@@ -183,7 +106,7 @@ int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
106 /* slow path */
107 /* some mkstemp implementations erase temp_filename on failure */
108 repo_git_path_replace(the_repository, temp_filename, "objects/%s", pattern);
186 - safe_create_leading_directories(temp_filename->buf);
109 + safe_create_leading_directories(the_repository, temp_filename->buf);
110 return xmkstemp_mode(temp_filename->buf, mode);
111 }
112
@@ -196,7 +119,7 @@ int odb_pack_keep(const char *name)
119 return fd;
120
121 /* slow path */
199 - safe_create_leading_directories_const(name);
122 + safe_create_leading_directories_const(the_repository, name);
123 return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
124 }
125
object-file.h
-33
@@ -21,39 +21,6 @@ extern int fetch_if_missing;
21 int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
22 int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags);
23
24 -/*
25 - * Create the directory containing the named path, using care to be
26 - * somewhat safe against races. Return one of the scld_error values to
27 - * indicate success/failure. On error, set errno to describe the
28 - * problem.
29 - *
30 - * SCLD_VANISHED indicates that one of the ancestor directories of the
31 - * path existed at one point during the function call and then
32 - * suddenly vanished, probably because another process pruned the
33 - * directory while we were working. To be robust against this kind of
34 - * race, callers might want to try invoking the function again when it
35 - * returns SCLD_VANISHED.
36 - *
37 - * safe_create_leading_directories() temporarily changes path while it
38 - * is working but restores it before returning.
39 - * safe_create_leading_directories_const() doesn't modify path, even
40 - * temporarily. Both these variants adjust the permissions of the
41 - * created directories to honor core.sharedRepository, so they are best
42 - * suited for files inside the git dir. For working tree files, use
43 - * safe_create_leading_directories_no_share() instead, as it ignores
44 - * the core.sharedRepository setting.
45 - */
46 -enum scld_error {
47 - SCLD_OK = 0,
48 - SCLD_FAILED = -1,
49 - SCLD_PERMS = -2,
50 - SCLD_EXISTS = -3,
51 - SCLD_VANISHED = -4
52 -};
53 -enum scld_error safe_create_leading_directories(char *path);
54 -enum scld_error safe_create_leading_directories_const(const char *path);
55 -enum scld_error safe_create_leading_directories_no_share(char *path);
56 -
24 int git_open_cloexec(const char *name, int flags);
25 #define git_open(name) git_open_cloexec(name, O_RDONLY)
26
path.c
+80
@@ -931,6 +931,86 @@ int safe_create_dir_in_gitdir(struct repository *repo, const char *path)
931 return adjust_shared_perm(repo, path);
932 }
933
934 +static enum scld_error safe_create_leading_directories_1(struct repository *repo,
935 + char *path)
936 +{
937 + char *next_component = path + offset_1st_component(path);
938 + enum scld_error ret = SCLD_OK;
939 +
940 + while (ret == SCLD_OK && next_component) {
941 + struct stat st;
942 + char *slash = next_component, slash_character;
943 +
944 + while (*slash && !is_dir_sep(*slash))
945 + slash++;
946 +
947 + if (!*slash)
948 + break;
949 +
950 + next_component = slash + 1;
951 + while (is_dir_sep(*next_component))
952 + next_component++;
953 + if (!*next_component)
954 + break;
955 +
956 + slash_character = *slash;
957 + *slash = '\0';
958 + if (!stat(path, &st)) {
959 + /* path exists */
960 + if (!S_ISDIR(st.st_mode)) {
961 + errno = ENOTDIR;
962 + ret = SCLD_EXISTS;
963 + }
964 + } else if (mkdir(path, 0777)) {
965 + if (errno == EEXIST &&
966 + !stat(path, &st) && S_ISDIR(st.st_mode))
967 + ; /* somebody created it since we checked */
968 + else if (errno == ENOENT)
969 + /*
970 + * Either mkdir() failed because
971 + * somebody just pruned the containing
972 + * directory, or stat() failed because
973 + * the file that was in our way was
974 + * just removed. Either way, inform
975 + * the caller that it might be worth
976 + * trying again:
977 + */
978 + ret = SCLD_VANISHED;
979 + else
980 + ret = SCLD_FAILED;
981 + } else if (repo && adjust_shared_perm(repo, path)) {
982 + ret = SCLD_PERMS;
983 + }
984 + *slash = slash_character;
985 + }
986 + return ret;
987 +}
988 +
989 +enum scld_error safe_create_leading_directories(struct repository *repo,
990 + char *path)
991 +{
992 + return safe_create_leading_directories_1(repo, path);
993 +}
994 +
995 +enum scld_error safe_create_leading_directories_no_share(char *path)
996 +{
997 + return safe_create_leading_directories_1(NULL, path);
998 +}
999 +
1000 +enum scld_error safe_create_leading_directories_const(struct repository *repo,
1001 + const char *path)
1002 +{
1003 + int save_errno;
1004 + /* path points to cache entries, so xstrdup before messing with it */
1005 + char *buf = xstrdup(path);
1006 + enum scld_error result = safe_create_leading_directories(repo, buf);
1007 +
1008 + save_errno = errno;
1009 + free(buf);
1010 + errno = save_errno;
1011 + return result;
1012 +}
1013 +
1014 static int have_same_root(const char *path1, const char *path2)
1015 {
1016 int is_abs1, is_abs2;
path.h
+34
@@ -232,6 +232,40 @@ void safe_create_dir(struct repository *repo, const char *dir, int share);
232 */
233 int safe_create_dir_in_gitdir(struct repository *repo, const char *path);
234
235 +/*
236 + * Create the directory containing the named path, using care to be
237 + * somewhat safe against races. Return one of the scld_error values to
238 + * indicate success/failure. On error, set errno to describe the
239 + * problem.
240 + *
241 + * SCLD_VANISHED indicates that one of the ancestor directories of the
242 + * path existed at one point during the function call and then
243 + * suddenly vanished, probably because another process pruned the
244 + * directory while we were working. To be robust against this kind of
245 + * race, callers might want to try invoking the function again when it
246 + * returns SCLD_VANISHED.
247 + *
248 + * safe_create_leading_directories() temporarily changes path while it
249 + * is working but restores it before returning.
250 + * safe_create_leading_directories_const() doesn't modify path, even
251 + * temporarily. Both these variants adjust the permissions of the
252 + * created directories to honor core.sharedRepository, so they are best
253 + * suited for files inside the git dir. For working tree files, use
254 + * safe_create_leading_directories_no_share() instead, as it ignores
255 + * the core.sharedRepository setting.
256 + */
257 +enum scld_error {
258 + SCLD_OK = 0,
259 + SCLD_FAILED = -1,
260 + SCLD_PERMS = -2,
261 + SCLD_EXISTS = -3,
262 + SCLD_VANISHED = -4
263 +};
264 +enum scld_error safe_create_leading_directories(struct repository *repo, char *path);
265 +enum scld_error safe_create_leading_directories_const(struct repository *repo,
266 + const char *path);
267 +enum scld_error safe_create_leading_directories_no_share(char *path);
268 +
269 # ifdef USE_THE_REPOSITORY_VARIABLE
270 # include "strbuf.h"
271 # include "repository.h"
refs/files-backend.c
+2 -2
@@ -705,7 +705,7 @@ static int lock_raw_ref(struct files_ref_store *refs,
705 files_ref_path(refs, &ref_file, refname);
706
707 retry:
708 - switch (safe_create_leading_directories(ref_file.buf)) {
708 + switch (safe_create_leading_directories(the_repository, ref_file.buf)) {
709 case SCLD_OK:
710 break; /* success */
711 case SCLD_EXISTS:
@@ -1109,7 +1109,7 @@ retry_fn:
1109 strbuf_addstr(&path_copy, path);
1110
1111 do {
1112 - scld_result = safe_create_leading_directories(path_copy.buf);
1112 + scld_result = safe_create_leading_directories(the_repository, path_copy.buf);
1113 if (scld_result == SCLD_OK)
1114 goto retry_fn;
1115 } while (scld_result == SCLD_VANISHED && create_directories_remaining-- > 0);
sequencer.c
+2 -2
@@ -4411,7 +4411,7 @@ static int write_update_refs_state(struct string_list *refs_to_oids)
4411 goto cleanup;
4412 }
4413
4414 - if (safe_create_leading_directories(path)) {
4414 + if (safe_create_leading_directories(the_repository, path)) {
4415 result = error(_("unable to create leading directories of %s"),
4416 path);
4417 goto cleanup;
@@ -4677,7 +4677,7 @@ static void create_autostash_internal(struct repository *r,
4677 strbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV);
4678
4679 if (path) {
4680 - if (safe_create_leading_directories_const(path))
4680 + if (safe_create_leading_directories_const(the_repository, path))
4681 die(_("Could not create directory for '%s'"),
4682 path);
4683 write_file(path, "%s", oid_to_hex(&oid));
server-info.c
+1 -1
@@ -88,7 +88,7 @@ static int update_info_file(struct repository *r, char *path,
88 .old_sb = STRBUF_INIT
89 };
90
91 - safe_create_leading_directories(path);
91 + safe_create_leading_directories(r, path);
92 f = mks_tempfile_m(tmp, 0666);
93 if (!f)
94 goto out;
submodule.c
+1 -1
@@ -2384,7 +2384,7 @@ static void relocate_single_git_dir_into_superproject(const char *path,
2384 if (validate_submodule_git_dir(new_gitdir.buf, sub->name) < 0)
2385 die(_("refusing to move '%s' into an existing git dir"),
2386 real_old_git_dir);
2387 - if (safe_create_leading_directories_const(new_gitdir.buf) < 0)
2387 + if (safe_create_leading_directories_const(the_repository, new_gitdir.buf) < 0)
2388 die(_("could not create directory '%s'"), new_gitdir.buf);
2389 real_new_git_dir = real_pathdup(new_gitdir.buf, 1);
2390