commit_ref(): if there is an empty dir in the way, delete it

Part of the bug revealed in the last commit is that resolve_ref_unsafe()
incorrectly returns EISDIR if it finds a directory in the place where it
is looking for a loose reference, even if the corresponding packed
reference exists. lock_ref_sha1_basic() notices the bogus EISDIR, and
use it as an indication that it should call remove_empty_directories()
and call resolve_ref_unsafe() again.

But resolve_ref_unsafe() shouldn't report EISDIR in this case. If we
would simply make that change, then remove_empty_directories() wouldn't
get called anymore, and the empty directory would get in the way when
commit_ref() calls commit_lock_file() to rename the lockfile into place.

So instead of relying on lock_ref_sha1_basic() to delete empty
directories, teach commit_ref(), just before calling commit_lock_file(),
to check whether a directory is in the way, and if so, try to delete it.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
This commit is contained in:
Michael Haggerty 2016-05-05 15:33:03 +02:00
parent 19dd7d06e5
commit 5387c0d883

View File

@ -2457,6 +2457,30 @@ static int close_ref(struct ref_lock *lock)
static int commit_ref(struct ref_lock *lock)
{
char *path = get_locked_file_path(lock->lk);
struct stat st;
if (!lstat(path, &st) && S_ISDIR(st.st_mode)) {
/*
* There is a directory at the path we want to rename
* the lockfile to. Hopefully it is empty; try to
* delete it.
*/
size_t len = strlen(path);
struct strbuf sb_path = STRBUF_INIT;
strbuf_attach(&sb_path, path, len, len);
/*
* If this fails, commit_lock_file() will also fail
* and will report the problem.
*/
remove_empty_directories(&sb_path);
strbuf_release(&sb_path);
} else {
free(path);
}
if (commit_lock_file(lock->lk))
return -1;
return 0;