summaryrefslogtreecommitdiff
path: root/sha1_file.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2014-01-27 10:45:33 -0800
committerJunio C Hamano <gitster@pobox.com>2014-01-27 10:45:33 -0800
commitd0956cfa8ef8b3668ea6adc94b27f5dcdc93bde0 (patch)
tree188ea26d10feaf884b59423fdf8c8bafeb73e718 /sha1_file.c
parentc380cf85a79c78d9dceb9290c9d4017d30804521 (diff)
parent08f555cb82f92797ca0aa0d6ba32e6872f1331e5 (diff)
downloadgit-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.c67
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;
}