mirror of
https://github.com/git/git.git
synced 2024-11-27 12:03:55 +08:00
rename_tmp_log(): handle a possible mkdir/rmdir race
If a directory vanishes while renaming the temporary reflog file, retry (up to 3 times). This could happen if another process deletes the directory created by safe_create_leading_directories() just before we rename the file into the directory. As far as I can tell, this race could not occur internal to git. The only time that a directory under $GIT_DIR/logs is deleted is if room has to be made for a log file for a reference with the same name; for example, in the following sequence: git branch foo/bar # Creates file .git/logs/refs/heads/foo/bar git branch -d foo/bar # Deletes file but leaves .git/logs/refs/heads/foo/ git branch foo # Deletes .git/logs/refs/heads/foo/ But the only reason the last command deletes the directory is because it wants to create a file with the same name. So if another process (e.g., git branch foo/baz ) wants to create that directory, one of the two is doomed to failure anyway because of a D/F conflict. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
fa59ae7971
commit
ae4a283e3b
11
refs.c
11
refs.c
@ -2530,12 +2530,14 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
|
||||
|
||||
static int rename_tmp_log(const char *newrefname)
|
||||
{
|
||||
int attempts_remaining = 3;
|
||||
|
||||
retry:
|
||||
if (safe_create_leading_directories(git_path("logs/%s", newrefname))) {
|
||||
error("unable to create directory for %s", newrefname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
retry:
|
||||
if (rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newrefname))) {
|
||||
if (errno==EISDIR || errno==ENOTDIR) {
|
||||
/*
|
||||
@ -2548,6 +2550,13 @@ static int rename_tmp_log(const char *newrefname)
|
||||
return -1;
|
||||
}
|
||||
goto retry;
|
||||
} else if (errno == ENOENT && --attempts_remaining > 0) {
|
||||
/*
|
||||
* Maybe another process just deleted one of
|
||||
* the directories in the path to newrefname.
|
||||
* Try again from the beginning.
|
||||
*/
|
||||
goto retry;
|
||||
} else {
|
||||
error("unable to move logfile "TMP_RENAMED_LOG" to logs/%s: %s",
|
||||
newrefname, strerror(errno));
|
||||
|
Loading…
Reference in New Issue
Block a user