refs file backend: move raceproof_create_file() here
Move the raceproof_create_file() API added to cache.h and
object-file.c in 177978f56a
(raceproof_create_file(): new function,
2017-01-06) to its only user, refs/files-backend.c.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
48cdcd9ca0
commit
3fa2e91d17
43
cache.h
43
cache.h
@ -1202,49 +1202,6 @@ enum scld_error safe_create_leading_directories(char *path);
|
|||||||
enum scld_error safe_create_leading_directories_const(const char *path);
|
enum scld_error safe_create_leading_directories_const(const char *path);
|
||||||
enum scld_error safe_create_leading_directories_no_share(char *path);
|
enum scld_error safe_create_leading_directories_no_share(char *path);
|
||||||
|
|
||||||
/*
|
|
||||||
* Callback function for raceproof_create_file(). This function is
|
|
||||||
* expected to do something that makes dirname(path) permanent despite
|
|
||||||
* the fact that other processes might be cleaning up empty
|
|
||||||
* directories at the same time. Usually it will create a file named
|
|
||||||
* path, but alternatively it could create another file in that
|
|
||||||
* directory, or even chdir() into that directory. The function should
|
|
||||||
* return 0 if the action was completed successfully. On error, it
|
|
||||||
* should return a nonzero result and set errno.
|
|
||||||
* raceproof_create_file() treats two errno values specially:
|
|
||||||
*
|
|
||||||
* - ENOENT -- dirname(path) does not exist. In this case,
|
|
||||||
* raceproof_create_file() tries creating dirname(path)
|
|
||||||
* (and any parent directories, if necessary) and calls
|
|
||||||
* the function again.
|
|
||||||
*
|
|
||||||
* - EISDIR -- the file already exists and is a directory. In this
|
|
||||||
* case, raceproof_create_file() removes the directory if
|
|
||||||
* it is empty (and recursively any empty directories that
|
|
||||||
* it contains) and calls the function again.
|
|
||||||
*
|
|
||||||
* Any other errno causes raceproof_create_file() to fail with the
|
|
||||||
* callback's return value and errno.
|
|
||||||
*
|
|
||||||
* Obviously, this function should be OK with being called again if it
|
|
||||||
* fails with ENOENT or EISDIR. In other scenarios it will not be
|
|
||||||
* called again.
|
|
||||||
*/
|
|
||||||
typedef int create_file_fn(const char *path, void *cb);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a file in dirname(path) by calling fn, creating leading
|
|
||||||
* directories if necessary. Retry a few times in case we are racing
|
|
||||||
* with another process that is trying to clean up the directory that
|
|
||||||
* contains path. See the documentation for create_file_fn for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* Return the value and set the errno that resulted from the most
|
|
||||||
* recent call of fn. fn is always called at least once, and will be
|
|
||||||
* called more than once if it returns ENOENT or EISDIR.
|
|
||||||
*/
|
|
||||||
int raceproof_create_file(const char *path, create_file_fn fn, void *cb);
|
|
||||||
|
|
||||||
int mkdir_in_gitdir(const char *path);
|
int mkdir_in_gitdir(const char *path);
|
||||||
char *expand_user_path(const char *path, int real_home);
|
char *expand_user_path(const char *path, int real_home);
|
||||||
const char *enter_repo(const char *path, int strict);
|
const char *enter_repo(const char *path, int strict);
|
||||||
|
@ -414,74 +414,6 @@ enum scld_error safe_create_leading_directories_const(const char *path)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int raceproof_create_file(const char *path, create_file_fn fn, void *cb)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* The number of times we will try to remove empty directories
|
|
||||||
* in the way of path. This is only 1 because if another
|
|
||||||
* process is racily creating directories that conflict with
|
|
||||||
* us, we don't want to fight against them.
|
|
||||||
*/
|
|
||||||
int remove_directories_remaining = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The number of times that we will try to create the
|
|
||||||
* directories containing path. We are willing to attempt this
|
|
||||||
* more than once, because another process could be trying to
|
|
||||||
* clean up empty directories at the same time as we are
|
|
||||||
* trying to create them.
|
|
||||||
*/
|
|
||||||
int create_directories_remaining = 3;
|
|
||||||
|
|
||||||
/* A scratch copy of path, filled lazily if we need it: */
|
|
||||||
struct strbuf path_copy = STRBUF_INIT;
|
|
||||||
|
|
||||||
int ret, save_errno;
|
|
||||||
|
|
||||||
/* Sanity check: */
|
|
||||||
assert(*path);
|
|
||||||
|
|
||||||
retry_fn:
|
|
||||||
ret = fn(path, cb);
|
|
||||||
save_errno = errno;
|
|
||||||
if (!ret)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (errno == EISDIR && remove_directories_remaining-- > 0) {
|
|
||||||
/*
|
|
||||||
* A directory is in the way. Maybe it is empty; try
|
|
||||||
* to remove it:
|
|
||||||
*/
|
|
||||||
if (!path_copy.len)
|
|
||||||
strbuf_addstr(&path_copy, path);
|
|
||||||
|
|
||||||
if (!remove_dir_recursively(&path_copy, REMOVE_DIR_EMPTY_ONLY))
|
|
||||||
goto retry_fn;
|
|
||||||
} else if (errno == ENOENT && create_directories_remaining-- > 0) {
|
|
||||||
/*
|
|
||||||
* Maybe the containing directory didn't exist, or
|
|
||||||
* maybe it was just deleted by a process that is
|
|
||||||
* racing with us to clean up empty directories. Try
|
|
||||||
* to create it:
|
|
||||||
*/
|
|
||||||
enum scld_error scld_result;
|
|
||||||
|
|
||||||
if (!path_copy.len)
|
|
||||||
strbuf_addstr(&path_copy, path);
|
|
||||||
|
|
||||||
do {
|
|
||||||
scld_result = safe_create_leading_directories(path_copy.buf);
|
|
||||||
if (scld_result == SCLD_OK)
|
|
||||||
goto retry_fn;
|
|
||||||
} while (scld_result == SCLD_VANISHED && create_directories_remaining-- > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
strbuf_release(&path_copy);
|
|
||||||
errno = save_errno;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fill_loose_path(struct strbuf *buf, const struct object_id *oid)
|
static void fill_loose_path(struct strbuf *buf, const struct object_id *oid)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -852,6 +852,115 @@ static struct ref_iterator *files_ref_iterator_begin(
|
|||||||
return ref_iterator;
|
return ref_iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback function for raceproof_create_file(). This function is
|
||||||
|
* expected to do something that makes dirname(path) permanent despite
|
||||||
|
* the fact that other processes might be cleaning up empty
|
||||||
|
* directories at the same time. Usually it will create a file named
|
||||||
|
* path, but alternatively it could create another file in that
|
||||||
|
* directory, or even chdir() into that directory. The function should
|
||||||
|
* return 0 if the action was completed successfully. On error, it
|
||||||
|
* should return a nonzero result and set errno.
|
||||||
|
* raceproof_create_file() treats two errno values specially:
|
||||||
|
*
|
||||||
|
* - ENOENT -- dirname(path) does not exist. In this case,
|
||||||
|
* raceproof_create_file() tries creating dirname(path)
|
||||||
|
* (and any parent directories, if necessary) and calls
|
||||||
|
* the function again.
|
||||||
|
*
|
||||||
|
* - EISDIR -- the file already exists and is a directory. In this
|
||||||
|
* case, raceproof_create_file() removes the directory if
|
||||||
|
* it is empty (and recursively any empty directories that
|
||||||
|
* it contains) and calls the function again.
|
||||||
|
*
|
||||||
|
* Any other errno causes raceproof_create_file() to fail with the
|
||||||
|
* callback's return value and errno.
|
||||||
|
*
|
||||||
|
* Obviously, this function should be OK with being called again if it
|
||||||
|
* fails with ENOENT or EISDIR. In other scenarios it will not be
|
||||||
|
* called again.
|
||||||
|
*/
|
||||||
|
typedef int create_file_fn(const char *path, void *cb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a file in dirname(path) by calling fn, creating leading
|
||||||
|
* directories if necessary. Retry a few times in case we are racing
|
||||||
|
* with another process that is trying to clean up the directory that
|
||||||
|
* contains path. See the documentation for create_file_fn for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* Return the value and set the errno that resulted from the most
|
||||||
|
* recent call of fn. fn is always called at least once, and will be
|
||||||
|
* called more than once if it returns ENOENT or EISDIR.
|
||||||
|
*/
|
||||||
|
static int raceproof_create_file(const char *path, create_file_fn fn, void *cb)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The number of times we will try to remove empty directories
|
||||||
|
* in the way of path. This is only 1 because if another
|
||||||
|
* process is racily creating directories that conflict with
|
||||||
|
* us, we don't want to fight against them.
|
||||||
|
*/
|
||||||
|
int remove_directories_remaining = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The number of times that we will try to create the
|
||||||
|
* directories containing path. We are willing to attempt this
|
||||||
|
* more than once, because another process could be trying to
|
||||||
|
* clean up empty directories at the same time as we are
|
||||||
|
* trying to create them.
|
||||||
|
*/
|
||||||
|
int create_directories_remaining = 3;
|
||||||
|
|
||||||
|
/* A scratch copy of path, filled lazily if we need it: */
|
||||||
|
struct strbuf path_copy = STRBUF_INIT;
|
||||||
|
|
||||||
|
int ret, save_errno;
|
||||||
|
|
||||||
|
/* Sanity check: */
|
||||||
|
assert(*path);
|
||||||
|
|
||||||
|
retry_fn:
|
||||||
|
ret = fn(path, cb);
|
||||||
|
save_errno = errno;
|
||||||
|
if (!ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (errno == EISDIR && remove_directories_remaining-- > 0) {
|
||||||
|
/*
|
||||||
|
* A directory is in the way. Maybe it is empty; try
|
||||||
|
* to remove it:
|
||||||
|
*/
|
||||||
|
if (!path_copy.len)
|
||||||
|
strbuf_addstr(&path_copy, path);
|
||||||
|
|
||||||
|
if (!remove_dir_recursively(&path_copy, REMOVE_DIR_EMPTY_ONLY))
|
||||||
|
goto retry_fn;
|
||||||
|
} else if (errno == ENOENT && create_directories_remaining-- > 0) {
|
||||||
|
/*
|
||||||
|
* Maybe the containing directory didn't exist, or
|
||||||
|
* maybe it was just deleted by a process that is
|
||||||
|
* racing with us to clean up empty directories. Try
|
||||||
|
* to create it:
|
||||||
|
*/
|
||||||
|
enum scld_error scld_result;
|
||||||
|
|
||||||
|
if (!path_copy.len)
|
||||||
|
strbuf_addstr(&path_copy, path);
|
||||||
|
|
||||||
|
do {
|
||||||
|
scld_result = safe_create_leading_directories(path_copy.buf);
|
||||||
|
if (scld_result == SCLD_OK)
|
||||||
|
goto retry_fn;
|
||||||
|
} while (scld_result == SCLD_VANISHED && create_directories_remaining-- > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
strbuf_release(&path_copy);
|
||||||
|
errno = save_errno;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int remove_empty_directories(struct strbuf *path)
|
static int remove_empty_directories(struct strbuf *path)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user