mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 20:42:23 +00:00
allow checkout to proceed when a dir to be removed is in use (win32)
This commit is contained in:
parent
dfec726bba
commit
e09d18eed6
@ -134,6 +134,9 @@ typedef enum {
|
||||
/** Treat pathspec as simple list of exact match file paths */
|
||||
GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH = (1u << 13),
|
||||
|
||||
/** Ignore directories in use, they will be left empty */
|
||||
GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES = (1u << 18),
|
||||
|
||||
/**
|
||||
* THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
|
||||
*/
|
||||
|
@ -955,6 +955,9 @@ static int checkout_remove_the_old(
|
||||
uint32_t flg = GIT_RMDIR_EMPTY_PARENTS |
|
||||
GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS;
|
||||
|
||||
if (data->opts.checkout_strategy & GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES)
|
||||
flg |= GIT_RMDIR_SKIP_NONEMPTY;
|
||||
|
||||
git_buf_truncate(&data->path, data->workdir_len);
|
||||
|
||||
git_vector_foreach(&data->diff->deltas, i, delta) {
|
||||
|
@ -444,7 +444,7 @@ static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path)
|
||||
|
||||
if (data->error < 0) {
|
||||
if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 &&
|
||||
(errno == ENOTEMPTY || errno == EEXIST))
|
||||
(errno == ENOTEMPTY || errno == EEXIST || errno == EBUSY))
|
||||
data->error = 0;
|
||||
else
|
||||
futils__error_cannot_rmdir(path->ptr, NULL);
|
||||
@ -480,7 +480,7 @@ static int futils__rmdir_empty_parent(void *opaque, git_buf *path)
|
||||
if (en == ENOENT || en == ENOTDIR) {
|
||||
giterr_clear();
|
||||
error = 0;
|
||||
} else if (en == ENOTEMPTY || en == EEXIST) {
|
||||
} else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) {
|
||||
giterr_clear();
|
||||
error = GIT_ITEROVER;
|
||||
} else {
|
||||
|
@ -314,9 +314,20 @@ int p_chmod(const char* path, mode_t mode)
|
||||
|
||||
int p_rmdir(const char* path)
|
||||
{
|
||||
int error;
|
||||
wchar_t buf[GIT_WIN_PATH];
|
||||
git__utf8_to_16(buf, GIT_WIN_PATH, path);
|
||||
return _wrmdir(buf);
|
||||
|
||||
error = _wrmdir(buf);
|
||||
|
||||
/* _wrmdir() is documented to return EACCES if "A program has an open
|
||||
* handle to the directory." This sounds like what everybody else calls
|
||||
* EBUSY. Let's convert appropriate error codes.
|
||||
*/
|
||||
if (GetLastError() == ERROR_SHARING_VIOLATION)
|
||||
errno = EBUSY;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int p_hide_directory__w32(const char *path)
|
||||
|
@ -526,3 +526,66 @@ void test_checkout_tree__can_write_to_empty_dirs(void)
|
||||
|
||||
git_object_free(obj);
|
||||
}
|
||||
|
||||
void test_checkout_tree__fails_when_dir_in_use(void)
|
||||
{
|
||||
#ifdef GIT_WIN32
|
||||
git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
|
||||
git_oid oid;
|
||||
git_object *obj = NULL;
|
||||
|
||||
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
|
||||
cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir"));
|
||||
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
|
||||
|
||||
cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
|
||||
|
||||
cl_assert(git_path_isfile("testrepo/a/b.txt"));
|
||||
|
||||
git_object_free(obj);
|
||||
|
||||
cl_git_pass(p_chdir("testrepo/a"));
|
||||
|
||||
cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/master"));
|
||||
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
|
||||
|
||||
cl_git_fail(git_checkout_tree(g_repo, obj, &opts));
|
||||
|
||||
cl_git_pass(p_chdir("../.."));
|
||||
|
||||
cl_assert(git_path_is_empty_dir("testrepo/a"));
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_checkout_tree__can_continue_when_dir_in_use(void)
|
||||
{
|
||||
#ifdef GIT_WIN32
|
||||
git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
|
||||
git_oid oid;
|
||||
git_object *obj = NULL;
|
||||
|
||||
opts.checkout_strategy = GIT_CHECKOUT_FORCE |
|
||||
GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES;
|
||||
|
||||
cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir"));
|
||||
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
|
||||
|
||||
cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
|
||||
|
||||
cl_assert(git_path_isfile("testrepo/a/b.txt"));
|
||||
|
||||
git_object_free(obj);
|
||||
|
||||
cl_git_pass(p_chdir("testrepo/a"));
|
||||
|
||||
cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/master"));
|
||||
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
|
||||
|
||||
cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
|
||||
|
||||
cl_git_pass(p_chdir("../.."));
|
||||
|
||||
cl_assert(git_path_is_empty_dir("testrepo/a"));
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user