safe_create_leading_directories(): add new error value SCLD_VANISHED

Add a new possible error result that can be returned by safe_create_leading_directories() and safe_create_leading_directories_const(): SCLD_VANISHED. This value indicates that a file or directory on the path existed at one point (either it already existed or the function created it), but then it disappeared. This probably indicates that another process deleted the directory while we were working. If SCLD_VANISHED is returned, the caller might want to retry the function call, as there is a chance that a new attempt will succeed. Why doesn't safe_create_leading_directories() do the retrying internally? Because an empty directory isn't really ever safe until it holds a file. So even if safe_create_leading_directories() were absolutely sure that the directory existed before it returned, there would be no guarantee that the directory still existed when the caller tried to write something in it. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Jan 6, 2014 at 14:45 UTC 18d37e860dfb9a98fb93ea7bb517ec3c16f995c4
2 files changed +20 -1
cache.h
+9 -1
@@ -741,12 +741,20 @@ int adjust_shared_perm(const char *path);
741 * Create the directory containing the named path, using care to be
742 * somewhat safe against races. Return one of the scld_error values
743 * to indicate success/failure.
744 + *
745 + * SCLD_VANISHED indicates that one of the ancestor directories of the
746 + * path existed at one point during the function call and then
747 + * suddenly vanished, probably because another process pruned the
748 + * directory while we were working. To be robust against this kind of
749 + * race, callers might want to try invoking the function again when it
750 + * returns SCLD_VANISHED.
751 */
752 enum scld_error {
753 SCLD_OK = 0,
754 SCLD_FAILED = -1,
755 SCLD_PERMS = -2,
749 - SCLD_EXISTS = -3
756 + SCLD_EXISTS = -3,
757 + SCLD_VANISHED = -4
758 };
759 enum scld_error safe_create_leading_directories(char *path);
760 enum scld_error safe_create_leading_directories_const(const char *path);
sha1_file.c
+11
@@ -132,6 +132,17 @@ enum scld_error safe_create_leading_directories(char *path)
132 if (errno == EEXIST &&
133 !stat(path, &st) && S_ISDIR(st.st_mode))
134 ; /* somebody created it since we checked */
135 + else if (errno == ENOENT)
136 + /*
137 + * Either mkdir() failed because
138 + * somebody just pruned the containing
139 + * directory, or stat() failed because
140 + * the file that was in our way was
141 + * just removed. Either way, inform
142 + * the caller that it might be worth
143 + * trying again:
144 + */
145 + ret = SCLD_VANISHED;
146 else
147 ret = SCLD_FAILED;
148 } else if (adjust_shared_perm(path)) {