mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-28 15:32:35 +00:00
fileops: Make git_futils_mkdir_r() able to skip non-empty directories
This commit is contained in:
parent
731df57080
commit
555aa453ba
@ -298,13 +298,20 @@ int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
|
||||
|
||||
static int _rmdir_recurs_foreach(void *opaque, git_buf *path)
|
||||
{
|
||||
int force = *(int *)opaque;
|
||||
enum git_directory_removal_type removal_type = *(enum git_directory_removal_type *)opaque;
|
||||
|
||||
assert(removal_type == GIT_DIRREMOVAL_EMPTY_HIERARCHY
|
||||
|| removal_type == GIT_DIRREMOVAL_FILES_AND_DIRS
|
||||
|| removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS);
|
||||
|
||||
if (git_path_isdir(path->ptr) == true) {
|
||||
if (git_path_direach(path, _rmdir_recurs_foreach, opaque) < 0)
|
||||
return -1;
|
||||
|
||||
if (p_rmdir(path->ptr) < 0) {
|
||||
if (removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS && errno == ENOTEMPTY)
|
||||
return 0;
|
||||
|
||||
giterr_set(GITERR_OS, "Could not remove directory '%s'", path->ptr);
|
||||
return -1;
|
||||
}
|
||||
@ -312,7 +319,7 @@ static int _rmdir_recurs_foreach(void *opaque, git_buf *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (force) {
|
||||
if (removal_type == GIT_DIRREMOVAL_FILES_AND_DIRS) {
|
||||
if (p_unlink(path->ptr) < 0) {
|
||||
giterr_set(GITERR_OS, "Could not remove directory. File '%s' cannot be removed", path->ptr);
|
||||
return -1;
|
||||
@ -321,18 +328,22 @@ static int _rmdir_recurs_foreach(void *opaque, git_buf *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
giterr_set(GITERR_OS, "Could not remove directory. File '%s' still present", path->ptr);
|
||||
return -1;
|
||||
if (removal_type == GIT_DIRREMOVAL_EMPTY_HIERARCHY) {
|
||||
giterr_set(GITERR_OS, "Could not remove directory. File '%s' still present", path->ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_futils_rmdir_r(const char *path, int force)
|
||||
int git_futils_rmdir_r(const char *path, enum git_directory_removal_type removal_type)
|
||||
{
|
||||
int error;
|
||||
git_buf p = GIT_BUF_INIT;
|
||||
|
||||
error = git_buf_sets(&p, path);
|
||||
if (!error)
|
||||
error = _rmdir_recurs_foreach(&force, &p);
|
||||
error = _rmdir_recurs_foreach(&removal_type, &p);
|
||||
git_buf_free(&p);
|
||||
return error;
|
||||
}
|
||||
|
@ -58,10 +58,25 @@ extern int git_futils_mkdir_r(const char *path, const char *base, const mode_t m
|
||||
*/
|
||||
extern int git_futils_mkpath2file(const char *path, const mode_t mode);
|
||||
|
||||
typedef enum {
|
||||
GIT_DIRREMOVAL_EMPTY_HIERARCHY = 0,
|
||||
GIT_DIRREMOVAL_FILES_AND_DIRS = 1,
|
||||
GIT_DIRREMOVAL_ONLY_EMPTY_DIRS = 2,
|
||||
} git_directory_removal_type;
|
||||
|
||||
/**
|
||||
* Remove path and any files and directories beneath it.
|
||||
*
|
||||
* @param path Path to to top level directory to process.
|
||||
*
|
||||
* @param removal_type GIT_DIRREMOVAL_EMPTY_HIERARCHY to remove a hierarchy
|
||||
* of empty directories (will fail if any file is found), GIT_DIRREMOVAL_FILES_AND_DIRS
|
||||
* to remove a hierarchy of files and folders, GIT_DIRREMOVAL_ONLY_EMPTY_DIRS to only remove
|
||||
* empty directories (no failure on file encounter).
|
||||
*
|
||||
* @return 0 on success; -1 on error.
|
||||
*/
|
||||
extern int git_futils_rmdir_r(const char *path, int force);
|
||||
extern int git_futils_rmdir_r(const char *path, enum git_directory_removal_type removal_type);
|
||||
|
||||
/**
|
||||
* Create and open a temporary file with a `_git2_` suffix.
|
||||
|
@ -30,25 +30,39 @@ void test_core_rmdir__initialize(void)
|
||||
/* make sure empty dir can be deleted recusively */
|
||||
void test_core_rmdir__delete_recursive(void)
|
||||
{
|
||||
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, 0));
|
||||
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, GIT_DIRREMOVAL_EMPTY_HIERARCHY));
|
||||
}
|
||||
|
||||
/* make sure non-empty dir cannot be deleted recusively */
|
||||
void test_core_rmdir__fail_to_delete_non_empty_dir(void)
|
||||
{
|
||||
git_buf file = GIT_BUF_INIT;
|
||||
int fd;
|
||||
|
||||
cl_git_pass(git_buf_joinpath(&file, empty_tmp_dir, "/two/file.txt"));
|
||||
|
||||
fd = p_creat(file.ptr, 0666);
|
||||
cl_assert(fd >= 0);
|
||||
cl_git_mkfile(git_buf_cstr(&file), "dummy");
|
||||
|
||||
cl_must_pass(p_close(fd));
|
||||
cl_git_fail(git_futils_rmdir_r(empty_tmp_dir, 0));
|
||||
cl_git_fail(git_futils_rmdir_r(empty_tmp_dir, GIT_DIRREMOVAL_EMPTY_HIERARCHY));
|
||||
|
||||
cl_must_pass(p_unlink(file.ptr));
|
||||
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, 0));
|
||||
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, GIT_DIRREMOVAL_EMPTY_HIERARCHY));
|
||||
|
||||
git_buf_free(&file);
|
||||
}
|
||||
|
||||
void test_core_rmdir__can_skip__non_empty_dir(void)
|
||||
{
|
||||
git_buf file = GIT_BUF_INIT;
|
||||
|
||||
cl_git_pass(git_buf_joinpath(&file, empty_tmp_dir, "/two/file.txt"));
|
||||
|
||||
cl_git_mkfile(git_buf_cstr(&file), "dummy");
|
||||
|
||||
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, GIT_DIRREMOVAL_ONLY_EMPTY_DIRS));
|
||||
cl_assert(git_path_exists(git_buf_cstr(&file)) == true);
|
||||
|
||||
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, GIT_DIRREMOVAL_FILES_AND_DIRS));
|
||||
cl_assert(git_path_exists(empty_tmp_dir) == false);
|
||||
|
||||
git_buf_free(&file);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ static int remove_file_cb(void *data, git_buf *file)
|
||||
return 0;
|
||||
|
||||
if (git_path_isdir(filename))
|
||||
cl_git_pass(git_futils_rmdir_r(filename, 1));
|
||||
cl_git_pass(git_futils_rmdir_r(filename, GIT_DIRREMOVAL_FILES_AND_DIRS));
|
||||
else
|
||||
cl_git_pass(p_unlink(git_buf_cstr(file)));
|
||||
|
||||
@ -346,7 +346,7 @@ void test_status_worktree__issue_592_3(void)
|
||||
repo = cl_git_sandbox_init("issue_592");
|
||||
|
||||
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "c"));
|
||||
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), 1));
|
||||
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
|
||||
|
||||
cl_git_pass(git_status_foreach(repo, cb_status__check_592, "c/a.txt"));
|
||||
|
||||
@ -376,7 +376,7 @@ void test_status_worktree__issue_592_5(void)
|
||||
repo = cl_git_sandbox_init("issue_592");
|
||||
|
||||
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "t"));
|
||||
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), 1));
|
||||
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
|
||||
cl_git_pass(p_mkdir(git_buf_cstr(&path), 0777));
|
||||
|
||||
cl_git_pass(git_status_foreach(repo, cb_status__check_592, NULL));
|
||||
|
Loading…
Reference in New Issue
Block a user