diff options
author | Junio C Hamano <gitster@pobox.com> | 2014-01-27 10:45:33 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2014-01-27 10:45:33 -0800 |
commit | d0956cfa8ef8b3668ea6adc94b27f5dcdc93bde0 (patch) | |
tree | 188ea26d10feaf884b59423fdf8c8bafeb73e718 /sha1_file.c | |
parent | c380cf85a79c78d9dceb9290c9d4017d30804521 (diff) | |
parent | 08f555cb82f92797ca0aa0d6ba32e6872f1331e5 (diff) | |
download | git-d0956cfa8ef8b3668ea6adc94b27f5dcdc93bde0.tar.gz |
Merge branch 'mh/safe-create-leading-directories'
Code clean-up and protection against concurrent write access to the
ref namespace.
* mh/safe-create-leading-directories:
rename_tmp_log(): on SCLD_VANISHED, retry
rename_tmp_log(): limit the number of remote_empty_directories() attempts
rename_tmp_log(): handle a possible mkdir/rmdir race
rename_ref(): extract function rename_tmp_log()
remove_dir_recurse(): handle disappearing files and directories
remove_dir_recurse(): tighten condition for removing unreadable dir
lock_ref_sha1_basic(): if locking fails with ENOENT, retry
lock_ref_sha1_basic(): on SCLD_VANISHED, retry
safe_create_leading_directories(): add new error value SCLD_VANISHED
cmd_init_db(): when creating directories, handle errors conservatively
safe_create_leading_directories(): introduce enum for return values
safe_create_leading_directories(): always restore slash at end of loop
safe_create_leading_directories(): split on first of multiple slashes
safe_create_leading_directories(): rename local variable
safe_create_leading_directories(): add explicit "slash" pointer
safe_create_leading_directories(): reduce scope of local variable
safe_create_leading_directories(): fix format of "if" chaining
Diffstat (limited to 'sha1_file.c')
-rw-r--r-- | sha1_file.c | 67 |
1 files changed, 38 insertions, 29 deletions
diff --git a/sha1_file.c b/sha1_file.c index e13bd2c3ee..8b0849f931 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -105,50 +105,59 @@ int mkdir_in_gitdir(const char *path) return adjust_shared_perm(path); } -int safe_create_leading_directories(char *path) +enum scld_error safe_create_leading_directories(char *path) { - char *pos = path + offset_1st_component(path); - struct stat st; + 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 = strchr(next_component, '/'); - while (pos) { - pos = strchr(pos, '/'); - if (!pos) + if (!slash) break; - while (*++pos == '/') - ; - if (!*pos) + + next_component = slash + 1; + while (*next_component == '/') + next_component++; + if (!*next_component) break; - *--pos = '\0'; + + *slash = '\0'; if (!stat(path, &st)) { /* path exists */ - if (!S_ISDIR(st.st_mode)) { - *pos = '/'; - return -3; - } - } - else if (mkdir(path, 0777)) { + if (!S_ISDIR(st.st_mode)) + ret = SCLD_EXISTS; + } else if (mkdir(path, 0777)) { if (errno == EEXIST && - !stat(path, &st) && S_ISDIR(st.st_mode)) { + !stat(path, &st) && S_ISDIR(st.st_mode)) ; /* somebody created it since we checked */ - } else { - *pos = '/'; - return -1; - } - } - else if (adjust_shared_perm(path)) { - *pos = '/'; - return -2; + 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 (adjust_shared_perm(path)) { + ret = SCLD_PERMS; } - *pos++ = '/'; + *slash = '/'; } - return 0; + return ret; } -int safe_create_leading_directories_const(const char *path) +enum scld_error safe_create_leading_directories_const(const char *path) { /* path points to cache entries, so xstrdup before messing with it */ char *buf = xstrdup(path); - int result = safe_create_leading_directories(buf); + enum scld_error result = safe_create_leading_directories(buf); free(buf); return result; } |