Git fork

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>

authored by

Patrick Steinhardt and committed by
Junio C Hamano
1a99fe80 d1fa670d

+173 -167
+2 -2
builtin/bugreport.c
··· 4 4 #include "editor.h" 5 5 #include "gettext.h" 6 6 #include "parse-options.h" 7 + #include "path.h" 7 8 #include "strbuf.h" 8 9 #include "help.h" 9 10 #include "compat/compiler.h" 10 11 #include "hook.h" 11 12 #include "hook-list.h" 12 13 #include "diagnose.h" 13 - #include "object-file.h" 14 14 #include "setup.h" 15 15 #include "version.h" 16 16 ··· 141 141 } 142 142 strbuf_addstr(&report_path, ".txt"); 143 143 144 - switch (safe_create_leading_directories(report_path.buf)) { 144 + switch (safe_create_leading_directories(the_repository, report_path.buf)) { 145 145 case SCLD_OK: 146 146 case SCLD_EXISTS: 147 147 break;
+2 -2
builtin/clone.c
··· 1090 1090 sigchain_push_common(remove_junk_on_signal); 1091 1091 1092 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 1094 die_errno(_("could not create leading directories of '%s'"), 1095 1095 work_tree); 1096 1096 if (dest_exists) ··· 1111 1111 junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL; 1112 1112 junk_git_dir = git_dir; 1113 1113 } 1114 - if (safe_create_leading_directories_const(git_dir) < 0) 1114 + if (safe_create_leading_directories_const(the_repository, git_dir) < 0) 1115 1115 die(_("could not create leading directories of '%s'"), git_dir); 1116 1116 1117 1117 if (0 <= option_verbosity) {
+2 -2
builtin/credential-cache--daemon.c
··· 2 2 #include "builtin.h" 3 3 #include "abspath.h" 4 4 #include "gettext.h" 5 - #include "object-file.h" 6 5 #include "parse-options.h" 6 + #include "path.h" 7 7 8 8 #ifndef NO_UNIX_SOCKETS 9 9 ··· 271 271 * condition in which somebody can chdir to it, sleep, then try to open 272 272 * our protected socket. 273 273 */ 274 - if (safe_create_leading_directories_const(dir) < 0) 274 + if (safe_create_leading_directories_const(the_repository, dir) < 0) 275 275 die_errno("unable to create directories for '%s'", dir); 276 276 if (mkdir(dir, 0700) < 0) 277 277 die_errno("unable to mkdir '%s'", dir);
+2 -2
builtin/diagnose.c
··· 3 3 #include "builtin.h" 4 4 #include "abspath.h" 5 5 #include "gettext.h" 6 - #include "object-file.h" 7 6 #include "parse-options.h" 7 + #include "path.h" 8 8 #include "diagnose.h" 9 9 10 10 static const char * const diagnose_usage[] = { ··· 50 50 strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0); 51 51 strbuf_addstr(&zip_path, ".zip"); 52 52 53 - switch (safe_create_leading_directories(zip_path.buf)) { 53 + switch (safe_create_leading_directories(the_repository, zip_path.buf)) { 54 54 case SCLD_OK: 55 55 case SCLD_EXISTS: 56 56 break;
+16 -13
builtin/difftool.c
··· 22 22 #include "gettext.h" 23 23 #include "hex.h" 24 24 #include "parse-options.h" 25 + #include "path.h" 25 26 #include "read-cache-ll.h" 26 27 #include "repository.h" 27 28 #include "sparse-index.h" ··· 271 272 strbuf_release(&buf); 272 273 } 273 274 274 - static int ensure_leading_directories(char *path) 275 + static int ensure_leading_directories(struct repository *repo, char *path) 275 276 { 276 - switch (safe_create_leading_directories(path)) { 277 + switch (safe_create_leading_directories(repo, path)) { 277 278 case SCLD_OK: 278 279 case SCLD_EXISTS: 279 280 return 0; ··· 341 342 return ret; 342 343 } 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) 346 348 { 347 349 add_path(dir, dir_len, path); 348 - ensure_leading_directories(dir->buf); 350 + ensure_leading_directories(repo, dir->buf); 349 351 unlink(dir->buf); 350 352 write_file(dir->buf, "%s", content); 351 353 } ··· 356 358 * as text files, resulting in behavior that is analogous to what "git diff" 357 359 * displays for symlink and submodule diffs. 358 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) 362 365 { 363 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); 365 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); 367 370 } 368 371 369 372 static int run_dir_diff(struct repository *repo, ··· 533 536 ADD_CACHE_JUST_APPEND); 534 537 535 538 add_path(&rdir, rdir_len, dst_path); 536 - if (ensure_leading_directories(rdir.buf)) { 539 + if (ensure_leading_directories(repo, rdir.buf)) { 537 540 ret = error("could not create " 538 541 "directory for '%s'", 539 542 dst_path); ··· 576 579 */ 577 580 hashmap_for_each_entry(&submodules, &iter, entry, 578 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); 580 583 } 581 584 582 585 /* ··· 587 590 hashmap_for_each_entry(&symlinks2, &iter, entry, 588 591 entry /* member name */) { 589 592 590 - write_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len); 593 + write_standin_files(repo, entry, &ldir, ldir_len, &rdir, rdir_len); 591 594 } 592 595 593 596 strbuf_setlen(&ldir, ldir_len);
+1 -1
builtin/fast-import.c
··· 1720 1720 if (!export_marks_file || (import_marks_file && !import_marks_file_done)) 1721 1721 return; 1722 1722 1723 - if (safe_create_leading_directories_const(export_marks_file)) { 1723 + if (safe_create_leading_directories_const(the_repository, export_marks_file)) { 1724 1724 failure |= error_errno("unable to create leading directories of %s", 1725 1725 export_marks_file); 1726 1726 return;
+1 -1
builtin/fsck.c
··· 332 332 describe_object(&obj->oid)); 333 333 FILE *f; 334 334 335 - if (safe_create_leading_directories_const(filename)) { 335 + if (safe_create_leading_directories_const(the_repository, filename)) { 336 336 error(_("could not create lost-found")); 337 337 free(filename); 338 338 return;
+3 -4
builtin/gc.c
··· 28 28 #include "commit.h" 29 29 #include "commit-graph.h" 30 30 #include "packfile.h" 31 - #include "object-file.h" 32 31 #include "object-store-ll.h" 33 32 #include "pack.h" 34 33 #include "pack-objects.h" ··· 2099 2098 } 2100 2099 strbuf_addstr(&plist, "</array>\n</dict>\n</plist>\n"); 2101 2100 2102 - if (safe_create_leading_directories(filename)) 2101 + if (safe_create_leading_directories(the_repository, filename)) 2103 2102 die(_("failed to create directories for '%s'"), filename); 2104 2103 2105 2104 if ((long)lock_file_timeout_ms < 0 && ··· 2565 2564 2566 2565 filename = xdg_config_home_systemd(local_timer_name); 2567 2566 2568 - if (safe_create_leading_directories(filename)) { 2567 + if (safe_create_leading_directories(the_repository, filename)) { 2569 2568 error(_("failed to create directories for '%s'"), filename); 2570 2569 goto error; 2571 2570 } ··· 2638 2637 char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service"); 2639 2638 2640 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)) { 2642 2641 error(_("failed to create directories for '%s'"), filename); 2643 2642 goto error; 2644 2643 }
+1 -2
builtin/init-db.c
··· 8 8 #include "abspath.h" 9 9 #include "environment.h" 10 10 #include "gettext.h" 11 - #include "object-file.h" 12 11 #include "parse-options.h" 13 12 #include "path.h" 14 13 #include "refs.h" ··· 134 133 */ 135 134 saved = repo_settings_get_shared_repository(the_repository); 136 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])) { 138 137 case SCLD_OK: 139 138 case SCLD_PERMS: 140 139 break;
+2 -2
builtin/log.c
··· 14 14 #include "gettext.h" 15 15 #include "hex.h" 16 16 #include "refs.h" 17 - #include "object-file.h" 18 17 #include "object-name.h" 19 18 #include "object-store-ll.h" 20 19 #include "pager.h" ··· 29 28 #include "tag.h" 30 29 #include "reflog-walk.h" 31 30 #include "patch-ids.h" 31 + #include "path.h" 32 32 #include "shortlog.h" 33 33 #include "remote.h" 34 34 #include "string-list.h" ··· 2311 2311 */ 2312 2312 saved = repo_settings_get_shared_repository(the_repository); 2313 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 2315 case SCLD_OK: 2316 2316 case SCLD_EXISTS: 2317 2317 break;
+2 -1
builtin/mv.c
··· 15 15 #include "gettext.h" 16 16 #include "name-hash.h" 17 17 #include "object-file.h" 18 + #include "path.h" 18 19 #include "pathspec.h" 19 20 #include "lockfile.h" 20 21 #include "dir.h" ··· 555 556 */ 556 557 char *dst_dup = xstrdup(dst); 557 558 string_list_append(&dirty_paths, dst); 558 - safe_create_leading_directories(dst_dup); 559 + safe_create_leading_directories(the_repository, dst_dup); 559 560 FREE_AND_NULL(dst_dup); 560 561 rename(src, dst); 561 562 }
+3 -2
builtin/sparse-checkout.c
··· 9 9 #include "object-file.h" 10 10 #include "object-name.h" 11 11 #include "parse-options.h" 12 + #include "path.h" 12 13 #include "pathspec.h" 13 14 #include "strbuf.h" 14 15 #include "string-list.h" ··· 335 336 336 337 sparse_filename = get_sparse_checkout_filename(); 337 338 338 - if (safe_create_leading_directories(sparse_filename)) 339 + if (safe_create_leading_directories(the_repository, sparse_filename)) 339 340 die(_("failed to create directory for sparse-checkout file")); 340 341 341 342 hold_lock_file_for_update(&lk, sparse_filename, LOCK_DIE_ON_ERROR); ··· 491 492 FILE *fp; 492 493 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)) 495 496 die(_("unable to create leading directories of %s"), 496 497 sparse_filename); 497 498 fp = xfopen(sparse_filename, "w");
+2 -2
builtin/submodule--helper.c
··· 1739 1739 !is_empty_dir(clone_data_path)) 1740 1740 die(_("directory not empty: '%s'"), clone_data_path); 1741 1741 1742 - if (safe_create_leading_directories_const(sm_gitdir) < 0) 1742 + if (safe_create_leading_directories_const(the_repository, sm_gitdir) < 0) 1743 1743 die(_("could not create directory '%s'"), sm_gitdir); 1744 1744 1745 1745 prepare_possible_alternates(clone_data->name, reference); ··· 1800 1800 if (clone_data->require_init && !stat(clone_data_path, &st) && 1801 1801 !is_empty_dir(clone_data_path)) 1802 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 1804 die(_("could not create directory '%s'"), clone_data_path); 1805 1805 path = xstrfmt("%s/index", sm_gitdir); 1806 1806 unlink_or_warn(path);
+4 -4
builtin/worktree.c
··· 348 348 char *to_file = xstrfmt("%s/info/sparse-checkout", worktree_git_dir); 349 349 350 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 352 copy_file(to_file, from_file, 0666)) 353 353 error(_("failed to copy '%s' to '%s'; sparse-checkout may not work correctly"), 354 354 from_file, to_file); ··· 367 367 struct config_set cs = { { 0 } }; 368 368 int bare; 369 369 370 - if (safe_create_leading_directories(to_file) || 370 + if (safe_create_leading_directories(the_repository, to_file) || 371 371 copy_file(to_file, from_file, 0666)) { 372 372 error(_("failed to copy worktree config from '%s' to '%s'"), 373 373 from_file, to_file); ··· 466 466 name = sb_name.buf; 467 467 repo_git_path_replace(the_repository, &sb_repo, "worktrees/%s", name); 468 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 470 die_errno(_("could not create leading directories of '%s'"), 471 471 sb_repo.buf); 472 472 ··· 498 498 write_file(sb.buf, _("initializing")); 499 499 500 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 502 die_errno(_("could not create leading directories of '%s'"), 503 503 sb_git.buf); 504 504 junk_work_tree = xstrdup(path);
+1 -1
commit-graph.c
··· 2065 2065 ctx->graph_name = get_commit_graph_filename(ctx->odb); 2066 2066 } 2067 2067 2068 - if (safe_create_leading_directories(ctx->graph_name)) { 2068 + if (safe_create_leading_directories(the_repository, ctx->graph_name)) { 2069 2069 error(_("unable to create leading directories of %s"), 2070 2070 ctx->graph_name); 2071 2071 return -1;
+2 -3
dir.c
··· 17 17 #include "environment.h" 18 18 #include "gettext.h" 19 19 #include "name-hash.h" 20 - #include "object-file.h" 21 20 #include "object-store-ll.h" 22 21 #include "path.h" 23 22 #include "refs.h" ··· 4063 4062 4064 4063 /* Prepare .git file */ 4065 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)) 4067 4066 die(_("could not create directories for %s"), gitfile_sb.buf); 4068 4067 4069 4068 /* Prepare config file */ 4070 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)) 4072 4071 die(_("could not create directories for %s"), cfg_sb.buf); 4073 4072 4074 4073 git_dir = real_pathdup(git_dir_, 1);
+2 -2
merge-recursive.c
··· 910 910 } 911 911 912 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 914 if (status) { 915 915 if (status == SCLD_EXISTS) 916 916 /* something else exists */ ··· 1003 1003 close(fd); 1004 1004 } else if (S_ISLNK(contents->mode)) { 1005 1005 char *lnk = xmemdupz(buf, size); 1006 - safe_create_leading_directories_const(path); 1006 + safe_create_leading_directories_const(the_repository, path); 1007 1007 unlink(path); 1008 1008 if (symlink(lnk, path)) 1009 1009 ret = err(opt, _("failed to symlink '%s': %s"),
+1 -1
midx-write.c
··· 1086 1086 object_dir); 1087 1087 else 1088 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 1090 die_errno(_("unable to create leading directories of %s"), 1091 1091 midx_name.buf); 1092 1092
+2 -2
notes-merge.c
··· 296 296 "(%s exists)."), repo_git_path_replace(the_repository, &buf, "NOTES_MERGE_*")); 297 297 } 298 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 300 NOTES_MERGE_WORKTREE "/.test"))) 301 301 die_errno("unable to create directory %s", 302 302 repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE)); ··· 314 314 { 315 315 int fd; 316 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 318 die_errno("unable to create directory for '%s'", path); 319 319 320 320 fd = xopen(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
+2 -79
object-file.c
··· 90 90 return 0; 91 91 } 92 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 - 170 93 int odb_mkstemp(struct strbuf *temp_filename, const char *pattern) 171 94 { 172 95 int fd; ··· 183 106 /* slow path */ 184 107 /* some mkstemp implementations erase temp_filename on failure */ 185 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); 187 110 return xmkstemp_mode(temp_filename->buf, mode); 188 111 } 189 112 ··· 196 119 return fd; 197 120 198 121 /* slow path */ 199 - safe_create_leading_directories_const(name); 122 + safe_create_leading_directories_const(the_repository, name); 200 123 return open(name, O_RDWR|O_CREAT|O_EXCL, 0600); 201 124 } 202 125
-33
object-file.h
··· 21 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 22 int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags); 23 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 - 57 24 int git_open_cloexec(const char *name, int flags); 58 25 #define git_open(name) git_open_cloexec(name, O_RDONLY) 59 26
+80
path.c
··· 931 931 return adjust_shared_perm(repo, path); 932 932 } 933 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 + 934 1014 static int have_same_root(const char *path1, const char *path2) 935 1015 { 936 1016 int is_abs1, is_abs2;
+34
path.h
··· 232 232 */ 233 233 int safe_create_dir_in_gitdir(struct repository *repo, const char *path); 234 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 + 235 269 # ifdef USE_THE_REPOSITORY_VARIABLE 236 270 # include "strbuf.h" 237 271 # include "repository.h"
+2 -2
refs/files-backend.c
··· 705 705 files_ref_path(refs, &ref_file, refname); 706 706 707 707 retry: 708 - switch (safe_create_leading_directories(ref_file.buf)) { 708 + switch (safe_create_leading_directories(the_repository, ref_file.buf)) { 709 709 case SCLD_OK: 710 710 break; /* success */ 711 711 case SCLD_EXISTS: ··· 1109 1109 strbuf_addstr(&path_copy, path); 1110 1110 1111 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 1113 if (scld_result == SCLD_OK) 1114 1114 goto retry_fn; 1115 1115 } while (scld_result == SCLD_VANISHED && create_directories_remaining-- > 0);
+2 -2
sequencer.c
··· 4411 4411 goto cleanup; 4412 4412 } 4413 4413 4414 - if (safe_create_leading_directories(path)) { 4414 + if (safe_create_leading_directories(the_repository, path)) { 4415 4415 result = error(_("unable to create leading directories of %s"), 4416 4416 path); 4417 4417 goto cleanup; ··· 4677 4677 strbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV); 4678 4678 4679 4679 if (path) { 4680 - if (safe_create_leading_directories_const(path)) 4680 + if (safe_create_leading_directories_const(the_repository, path)) 4681 4681 die(_("Could not create directory for '%s'"), 4682 4682 path); 4683 4683 write_file(path, "%s", oid_to_hex(&oid));
+1 -1
server-info.c
··· 88 88 .old_sb = STRBUF_INIT 89 89 }; 90 90 91 - safe_create_leading_directories(path); 91 + safe_create_leading_directories(r, path); 92 92 f = mks_tempfile_m(tmp, 0666); 93 93 if (!f) 94 94 goto out;
+1 -1
submodule.c
··· 2384 2384 if (validate_submodule_git_dir(new_gitdir.buf, sub->name) < 0) 2385 2385 die(_("refusing to move '%s' into an existing git dir"), 2386 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 2388 die(_("could not create directory '%s'"), new_gitdir.buf); 2389 2389 real_new_git_dir = real_pathdup(new_gitdir.buf, 1); 2390 2390