mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 10:03:43 +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 */
|
/** Treat pathspec as simple list of exact match file paths */
|
||||||
GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH = (1u << 13),
|
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
|
* THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
|
||||||
*/
|
*/
|
||||||
|
@ -955,6 +955,9 @@ static int checkout_remove_the_old(
|
|||||||
uint32_t flg = GIT_RMDIR_EMPTY_PARENTS |
|
uint32_t flg = GIT_RMDIR_EMPTY_PARENTS |
|
||||||
GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS;
|
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_buf_truncate(&data->path, data->workdir_len);
|
||||||
|
|
||||||
git_vector_foreach(&data->diff->deltas, i, delta) {
|
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->error < 0) {
|
||||||
if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 &&
|
if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 &&
|
||||||
(errno == ENOTEMPTY || errno == EEXIST))
|
(errno == ENOTEMPTY || errno == EEXIST || errno == EBUSY))
|
||||||
data->error = 0;
|
data->error = 0;
|
||||||
else
|
else
|
||||||
futils__error_cannot_rmdir(path->ptr, NULL);
|
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) {
|
if (en == ENOENT || en == ENOTDIR) {
|
||||||
giterr_clear();
|
giterr_clear();
|
||||||
error = 0;
|
error = 0;
|
||||||
} else if (en == ENOTEMPTY || en == EEXIST) {
|
} else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) {
|
||||||
giterr_clear();
|
giterr_clear();
|
||||||
error = GIT_ITEROVER;
|
error = GIT_ITEROVER;
|
||||||
} else {
|
} else {
|
||||||
|
@ -314,9 +314,20 @@ int p_chmod(const char* path, mode_t mode)
|
|||||||
|
|
||||||
int p_rmdir(const char* path)
|
int p_rmdir(const char* path)
|
||||||
{
|
{
|
||||||
|
int error;
|
||||||
wchar_t buf[GIT_WIN_PATH];
|
wchar_t buf[GIT_WIN_PATH];
|
||||||
git__utf8_to_16(buf, GIT_WIN_PATH, 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)
|
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);
|
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