Commit 331e7de9 by Russell Belfer

Extensions to rmdir and mkdir utilities

* Rework GIT_DIRREMOVAL values to GIT_RMDIR flags, allowing
  combinations of flags
* Add GIT_RMDIR_EMPTY_PARENTS flag to remove parent dirs that
  are left empty after removal
* Add GIT_MKDIR_VERIFY_DIR to give an error if item is a file,
  not a dir (previously an EEXISTS error was ignored, even for
  files) and enable this flag for git_futils_mkpath2file call
* Improve accuracy of error messages from git_futils_mkdir
parent 8a328cf4
...@@ -213,7 +213,7 @@ static int checkout_remove_the_old( ...@@ -213,7 +213,7 @@ static int checkout_remove_the_old(
data->error = git_futils_rmdir_r( data->error = git_futils_rmdir_r(
delta->new_file.path, delta->new_file.path,
git_repository_workdir(data->owner), git_repository_workdir(data->owner),
GIT_DIRREMOVAL_FILES_AND_DIRS); GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_EMPTY_PARENTS);
data->completed_steps++; data->completed_steps++;
report_progress(data, delta->new_file.path); report_progress(data, delta->new_file.path);
......
...@@ -338,7 +338,7 @@ static int clone_internal( ...@@ -338,7 +338,7 @@ static int clone_internal(
fetch_progress_cb, fetch_progress_payload)) < 0) { fetch_progress_cb, fetch_progress_payload)) < 0) {
/* Failed to fetch; clean up */ /* Failed to fetch; clean up */
git_repository_free(repo); git_repository_free(repo);
git_futils_rmdir_r(path, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS); git_futils_rmdir_r(path, NULL, GIT_RMDIR_REMOVE_FILES);
} else { } else {
*out = repo; *out = repo;
retcode = 0; retcode = 0;
......
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
int git_futils_mkpath2file(const char *file_path, const mode_t mode) int git_futils_mkpath2file(const char *file_path, const mode_t mode)
{ {
return git_futils_mkdir( return git_futils_mkdir(
file_path, NULL, mode, GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST); file_path, NULL, mode,
GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR);
} }
int git_futils_mktmp(git_buf *path_out, const char *filename) int git_futils_mktmp(git_buf *path_out, const char *filename)
...@@ -250,6 +251,7 @@ int git_futils_mkdir( ...@@ -250,6 +251,7 @@ int git_futils_mkdir(
mode_t mode, mode_t mode,
uint32_t flags) uint32_t flags)
{ {
int error = -1;
git_buf make_path = GIT_BUF_INIT; git_buf make_path = GIT_BUF_INIT;
ssize_t root = 0; ssize_t root = 0;
char lastch, *tail; char lastch, *tail;
...@@ -297,12 +299,28 @@ int git_futils_mkdir( ...@@ -297,12 +299,28 @@ int git_futils_mkdir(
*tail = '\0'; *tail = '\0';
/* make directory */ /* make directory */
if (p_mkdir(make_path.ptr, mode) < 0 && if (p_mkdir(make_path.ptr, mode) < 0) {
(errno != EEXIST || (flags & GIT_MKDIR_EXCL) != 0)) if (errno == EEXIST) {
{ if (!lastch && (flags & GIT_MKDIR_VERIFY_DIR) != 0) {
giterr_set(GITERR_OS, "Failed to make directory '%s'", if (!git_path_isdir(make_path.ptr)) {
make_path.ptr); giterr_set(
goto fail; GITERR_OS, "Existing path is not a directory '%s'",
make_path.ptr);
error = GIT_ENOTFOUND;
goto fail;
}
}
if ((flags & GIT_MKDIR_EXCL) != 0) {
giterr_set(GITERR_OS, "Directory already exists '%s'",
make_path.ptr);
error = GIT_EEXISTS;
goto fail;
}
} else {
giterr_set(GITERR_OS, "Failed to make directory '%s'",
make_path.ptr);
goto fail;
}
} }
/* chmod if requested */ /* chmod if requested */
...@@ -324,7 +342,7 @@ int git_futils_mkdir( ...@@ -324,7 +342,7 @@ int git_futils_mkdir(
fail: fail:
git_buf_free(&make_path); git_buf_free(&make_path);
return -1; return error;
} }
int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode) int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
...@@ -332,57 +350,103 @@ int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode) ...@@ -332,57 +350,103 @@ int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
return git_futils_mkdir(path, base, mode, GIT_MKDIR_PATH); return git_futils_mkdir(path, base, mode, GIT_MKDIR_PATH);
} }
static int _rmdir_recurs_foreach(void *opaque, git_buf *path) typedef struct {
uint32_t flags;
int error;
} futils__rmdir_data;
static int futils__error_cannot_rmdir(const char *path, const char *filemsg)
{ {
git_directory_removal_type removal_type = *(git_directory_removal_type *)opaque; if (filemsg)
giterr_set(GITERR_OS, "Could not remove directory. File '%s' %s",
path, filemsg);
else
giterr_set(GITERR_OS, "Could not remove directory '%s'", path);
if (git_path_isdir(path->ptr) == true) { return -1;
if (git_path_direach(path, _rmdir_recurs_foreach, opaque) < 0) }
return -1;
if (p_rmdir(path->ptr) < 0) { static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path)
if (removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS && (errno == ENOTEMPTY || errno == EEXIST)) {
return 0; futils__rmdir_data *data = opaque;
giterr_set(GITERR_OS, "Could not remove directory '%s'", path->ptr); if (git_path_isdir(path->ptr) == true) {
return -1; int error = git_path_direach(path, futils__rmdir_recurs_foreach, data);
if (error < 0)
return (error == GIT_EUSER) ? data->error : error;
data->error = p_rmdir(path->ptr);
if (data->error < 0) {
if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 &&
(errno == ENOTEMPTY || errno == EEXIST))
data->error = 0;
else
futils__error_cannot_rmdir(path->ptr, NULL);
} }
return 0;
} }
if (removal_type == GIT_DIRREMOVAL_FILES_AND_DIRS) { else if ((data->flags & GIT_RMDIR_REMOVE_FILES) != 0) {
if (p_unlink(path->ptr) < 0) { data->error = p_unlink(path->ptr);
giterr_set(GITERR_OS, "Could not remove directory. File '%s' cannot be removed", path->ptr);
return -1;
}
return 0; if (data->error < 0)
futils__error_cannot_rmdir(path->ptr, "cannot be removed");
} }
if (removal_type == GIT_DIRREMOVAL_EMPTY_HIERARCHY) { else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0) {
giterr_set(GITERR_OS, "Could not remove directory. File '%s' still present", path->ptr); data->error = futils__error_cannot_rmdir(path->ptr, "still present");
return -1;
} }
return 0; return data->error;
}
static int futils__rmdir_empty_parent(void *opaque, git_buf *path)
{
int error = p_rmdir(path->ptr);
GIT_UNUSED(opaque);
if (error) {
int en = errno;
if (en == ENOENT || en == ENOTDIR) {
giterr_clear();
error = 0;
} else if (en == ENOTEMPTY || en == EEXIST) {
giterr_clear();
error = GIT_ITEROVER;
} else {
futils__error_cannot_rmdir(path->ptr, NULL);
}
}
return error;
} }
int git_futils_rmdir_r( int git_futils_rmdir_r(
const char *path, const char *base, git_directory_removal_type removal_type) const char *path, const char *base, uint32_t flags)
{ {
int error; int error;
git_buf fullpath = GIT_BUF_INIT; git_buf fullpath = GIT_BUF_INIT;
futils__rmdir_data data;
assert(removal_type == GIT_DIRREMOVAL_EMPTY_HIERARCHY
|| removal_type == GIT_DIRREMOVAL_FILES_AND_DIRS
|| removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS);
/* build path and find "root" where we should start calling mkdir */ /* build path and find "root" where we should start calling mkdir */
if (git_path_join_unrooted(&fullpath, path, base, NULL) < 0) if (git_path_join_unrooted(&fullpath, path, base, NULL) < 0)
return -1; return -1;
error = _rmdir_recurs_foreach(&removal_type, &fullpath); data.flags = flags;
data.error = 0;
error = futils__rmdir_recurs_foreach(&data, &fullpath);
/* remove now-empty parents if requested */
if (!error && (flags & GIT_RMDIR_EMPTY_PARENTS) != 0) {
error = git_path_walk_up(
&fullpath, base, futils__rmdir_empty_parent, &data);
if (error == GIT_ITEROVER)
error = 0;
}
git_buf_free(&fullpath); git_buf_free(&fullpath);
......
...@@ -65,6 +65,7 @@ extern int git_futils_mkdir_r(const char *path, const char *base, const mode_t m ...@@ -65,6 +65,7 @@ extern int git_futils_mkdir_r(const char *path, const char *base, const mode_t m
* * GIT_MKDIR_CHMOD says to chmod the final directory entry after creation * * GIT_MKDIR_CHMOD says to chmod the final directory entry after creation
* * GIT_MKDIR_CHMOD_PATH says to chmod each directory component in the path * * GIT_MKDIR_CHMOD_PATH says to chmod each directory component in the path
* * GIT_MKDIR_SKIP_LAST says to leave off the last element of the path * * GIT_MKDIR_SKIP_LAST says to leave off the last element of the path
* * GIT_MKDIR_VERIFY_DIR says confirm final item is a dir, not just EEXIST
* *
* Note that the chmod options will be executed even if the directory already * Note that the chmod options will be executed even if the directory already
* exists, unless GIT_MKDIR_EXCL is given. * exists, unless GIT_MKDIR_EXCL is given.
...@@ -74,7 +75,8 @@ typedef enum { ...@@ -74,7 +75,8 @@ typedef enum {
GIT_MKDIR_PATH = 2, GIT_MKDIR_PATH = 2,
GIT_MKDIR_CHMOD = 4, GIT_MKDIR_CHMOD = 4,
GIT_MKDIR_CHMOD_PATH = 8, GIT_MKDIR_CHMOD_PATH = 8,
GIT_MKDIR_SKIP_LAST = 16 GIT_MKDIR_SKIP_LAST = 16,
GIT_MKDIR_VERIFY_DIR = 32,
} git_futils_mkdir_flags; } git_futils_mkdir_flags;
/** /**
...@@ -98,27 +100,38 @@ extern int git_futils_mkdir(const char *path, const char *base, mode_t mode, uin ...@@ -98,27 +100,38 @@ extern int git_futils_mkdir(const char *path, const char *base, mode_t mode, uin
*/ */
extern int git_futils_mkpath2file(const char *path, const mode_t mode); extern int git_futils_mkpath2file(const char *path, const mode_t mode);
/**
* Flags to pass to `git_futils_rmdir_r`.
*
* * GIT_RMDIR_EMPTY_HIERARCHY - the default; remove hierarchy of empty
* dirs and generate error if any files are found.
* * GIT_RMDIR_REMOVE_FILES - attempt to remove files in the hierarchy.
* * GIT_RMDIR_SKIP_NONEMPTY - skip non-empty directories with no error.
* * GIT_RMDIR_EMPTY_PARENTS - remove containing directories up to base
* if removing this item leaves them empty
*
* The old values translate into the new as follows:
*
* * GIT_DIRREMOVAL_EMPTY_HIERARCHY == GIT_RMDIR_EMPTY_HIERARCHY
* * GIT_DIRREMOVAL_FILES_AND_DIRS ~= GIT_RMDIR_REMOVE_FILES
* * GIT_DIRREMOVAL_ONLY_EMPTY_DIRS == GIT_RMDIR_SKIP_NONEMPTY
*/
typedef enum { typedef enum {
GIT_DIRREMOVAL_EMPTY_HIERARCHY = 0, GIT_RMDIR_EMPTY_HIERARCHY = 0,
GIT_DIRREMOVAL_FILES_AND_DIRS = 1, GIT_RMDIR_REMOVE_FILES = (1 << 0),
GIT_DIRREMOVAL_ONLY_EMPTY_DIRS = 2, GIT_RMDIR_SKIP_NONEMPTY = (1 << 1),
} git_directory_removal_type; GIT_RMDIR_EMPTY_PARENTS = (1 << 2),
} git_futils_rmdir_flags;
/** /**
* Remove path and any files and directories beneath it. * Remove path and any files and directories beneath it.
* *
* @param path Path to to top level directory to process. * @param path Path to to top level directory to process.
* @param base Root for relative path. * @param base Root for relative path.
* @param removal_type GIT_DIRREMOVAL_EMPTY_HIERARCHY to remove a hierarchy * @param flags Combination of git_futils_rmdir_flags values
* 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. * @return 0 on success; -1 on error.
*/ */
extern int git_futils_rmdir_r(const char *path, const char *base, git_directory_removal_type removal_type); extern int git_futils_rmdir_r(const char *path, const char *base, uint32_t flags);
/** /**
* Create and open a temporary file with a `_git2_` suffix. * Create and open a temporary file with a `_git2_` suffix.
......
...@@ -378,7 +378,7 @@ int git_reflog_rename(git_reference *ref, const char *new_name) ...@@ -378,7 +378,7 @@ int git_reflog_rename(git_reference *ref, const char *new_name)
goto cleanup; goto cleanup;
if (git_path_isdir(git_buf_cstr(&new_path)) && if (git_path_isdir(git_buf_cstr(&new_path)) &&
(git_futils_rmdir_r(git_buf_cstr(&new_path), NULL, GIT_DIRREMOVAL_ONLY_EMPTY_DIRS) < 0)) (git_futils_rmdir_r(git_buf_cstr(&new_path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0))
goto cleanup; goto cleanup;
if (git_futils_mkpath2file(git_buf_cstr(&new_path), GIT_REFLOG_DIR_MODE) < 0) if (git_futils_mkpath2file(git_buf_cstr(&new_path), GIT_REFLOG_DIR_MODE) < 0)
......
...@@ -274,18 +274,15 @@ static int loose_write(git_reference *ref) ...@@ -274,18 +274,15 @@ static int loose_write(git_reference *ref)
git_buf ref_path = GIT_BUF_INIT; git_buf ref_path = GIT_BUF_INIT;
struct stat st; struct stat st;
if (git_buf_joinpath(&ref_path, ref->owner->path_repository, ref->name) < 0)
return -1;
/* Remove a possibly existing empty directory hierarchy /* Remove a possibly existing empty directory hierarchy
* which name would collide with the reference name * which name would collide with the reference name
*/ */
if (git_path_isdir(git_buf_cstr(&ref_path)) && if (git_futils_rmdir_r(ref->name, ref->owner->path_repository,
git_futils_rmdir_r(git_buf_cstr(&ref_path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)
GIT_DIRREMOVAL_ONLY_EMPTY_DIRS) < 0) { return -1;
git_buf_free(&ref_path);
if (git_buf_joinpath(&ref_path, ref->owner->path_repository, ref->name) < 0)
return -1; return -1;
}
if (git_filebuf_open(&file, ref_path.ptr, GIT_FILEBUF_FORCE) < 0) { if (git_filebuf_open(&file, ref_path.ptr, GIT_FILEBUF_FORCE) < 0) {
git_buf_free(&ref_path); git_buf_free(&ref_path);
......
...@@ -41,7 +41,7 @@ void test_core_copy__file_in_dir(void) ...@@ -41,7 +41,7 @@ void test_core_copy__file_in_dir(void)
cl_assert(S_ISREG(st.st_mode)); cl_assert(S_ISREG(st.st_mode));
cl_assert(strlen(content) == (size_t)st.st_size); cl_assert(strlen(content) == (size_t)st.st_size);
cl_git_pass(git_futils_rmdir_r("an_dir", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r("an_dir", NULL, GIT_RMDIR_REMOVE_FILES));
cl_assert(!git_path_isdir("an_dir")); cl_assert(!git_path_isdir("an_dir"));
} }
...@@ -95,7 +95,7 @@ void test_core_copy__tree(void) ...@@ -95,7 +95,7 @@ void test_core_copy__tree(void)
cl_assert(S_ISLNK(st.st_mode)); cl_assert(S_ISLNK(st.st_mode));
#endif #endif
cl_git_pass(git_futils_rmdir_r("t1", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r("t1", NULL, GIT_RMDIR_REMOVE_FILES));
cl_assert(!git_path_isdir("t1")); cl_assert(!git_path_isdir("t1"));
/* copy with empty dirs, no links, yes dotfiles, no overwrite */ /* copy with empty dirs, no links, yes dotfiles, no overwrite */
...@@ -119,8 +119,8 @@ void test_core_copy__tree(void) ...@@ -119,8 +119,8 @@ void test_core_copy__tree(void)
cl_git_fail(git_path_lstat("t2/c/d/l1", &st)); cl_git_fail(git_path_lstat("t2/c/d/l1", &st));
#endif #endif
cl_git_pass(git_futils_rmdir_r("t2", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r("t2", NULL, GIT_RMDIR_REMOVE_FILES));
cl_assert(!git_path_isdir("t2")); cl_assert(!git_path_isdir("t2"));
cl_git_pass(git_futils_rmdir_r("src", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r("src", NULL, GIT_RMDIR_REMOVE_FILES));
} }
...@@ -6,11 +6,11 @@ ...@@ -6,11 +6,11 @@
static void cleanup_basic_dirs(void *ref) static void cleanup_basic_dirs(void *ref)
{ {
GIT_UNUSED(ref); GIT_UNUSED(ref);
git_futils_rmdir_r("d0", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY); git_futils_rmdir_r("d0", NULL, GIT_RMDIR_EMPTY_HIERARCHY);
git_futils_rmdir_r("d1", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY); git_futils_rmdir_r("d1", NULL, GIT_RMDIR_EMPTY_HIERARCHY);
git_futils_rmdir_r("d2", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY); git_futils_rmdir_r("d2", NULL, GIT_RMDIR_EMPTY_HIERARCHY);
git_futils_rmdir_r("d3", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY); git_futils_rmdir_r("d3", NULL, GIT_RMDIR_EMPTY_HIERARCHY);
git_futils_rmdir_r("d4", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY); git_futils_rmdir_r("d4", NULL, GIT_RMDIR_EMPTY_HIERARCHY);
} }
void test_core_mkdir__basic(void) void test_core_mkdir__basic(void)
...@@ -56,7 +56,7 @@ void test_core_mkdir__basic(void) ...@@ -56,7 +56,7 @@ void test_core_mkdir__basic(void)
static void cleanup_basedir(void *ref) static void cleanup_basedir(void *ref)
{ {
GIT_UNUSED(ref); GIT_UNUSED(ref);
git_futils_rmdir_r("base", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY); git_futils_rmdir_r("base", NULL, GIT_RMDIR_EMPTY_HIERARCHY);
} }
void test_core_mkdir__with_base(void) void test_core_mkdir__with_base(void)
...@@ -108,7 +108,7 @@ static void cleanup_chmod_root(void *ref) ...@@ -108,7 +108,7 @@ static void cleanup_chmod_root(void *ref)
git__free(mode); git__free(mode);
} }
git_futils_rmdir_r("r", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY); git_futils_rmdir_r("r", NULL, GIT_RMDIR_EMPTY_HIERARCHY);
} }
static void check_mode(mode_t expected, mode_t actual) static void check_mode(mode_t expected, mode_t actual)
......
...@@ -30,7 +30,7 @@ void test_core_rmdir__initialize(void) ...@@ -30,7 +30,7 @@ void test_core_rmdir__initialize(void)
/* make sure empty dir can be deleted recusively */ /* make sure empty dir can be deleted recusively */
void test_core_rmdir__delete_recursive(void) void test_core_rmdir__delete_recursive(void)
{ {
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY)); cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY));
} }
/* make sure non-empty dir cannot be deleted recusively */ /* make sure non-empty dir cannot be deleted recusively */
...@@ -42,15 +42,15 @@ void test_core_rmdir__fail_to_delete_non_empty_dir(void) ...@@ -42,15 +42,15 @@ void test_core_rmdir__fail_to_delete_non_empty_dir(void)
cl_git_mkfile(git_buf_cstr(&file), "dummy"); cl_git_mkfile(git_buf_cstr(&file), "dummy");
cl_git_fail(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY)); cl_git_fail(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY));
cl_must_pass(p_unlink(file.ptr)); cl_must_pass(p_unlink(file.ptr));
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY)); cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY));
git_buf_free(&file); git_buf_free(&file);
} }
void test_core_rmdir__can_skip__non_empty_dir(void) void test_core_rmdir__can_skip_non_empty_dir(void)
{ {
git_buf file = GIT_BUF_INIT; git_buf file = GIT_BUF_INIT;
...@@ -58,11 +58,41 @@ void test_core_rmdir__can_skip__non_empty_dir(void) ...@@ -58,11 +58,41 @@ void test_core_rmdir__can_skip__non_empty_dir(void)
cl_git_mkfile(git_buf_cstr(&file), "dummy"); cl_git_mkfile(git_buf_cstr(&file), "dummy");
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_DIRREMOVAL_ONLY_EMPTY_DIRS)); cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_SKIP_NONEMPTY));
cl_assert(git_path_exists(git_buf_cstr(&file)) == true); cl_assert(git_path_exists(git_buf_cstr(&file)) == true);
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_REMOVE_FILES));
cl_assert(git_path_exists(empty_tmp_dir) == false); cl_assert(git_path_exists(empty_tmp_dir) == false);
git_buf_free(&file); git_buf_free(&file);
} }
void test_core_rmdir__can_remove_empty_parents(void)
{
git_buf file = GIT_BUF_INIT;
cl_git_pass(
git_buf_joinpath(&file, empty_tmp_dir, "/one/two_two/three/file.txt"));
cl_git_mkfile(git_buf_cstr(&file), "dummy");
cl_assert(git_path_isfile(git_buf_cstr(&file)));
cl_git_pass(git_futils_rmdir_r("one/two_two/three/file.txt", empty_tmp_dir,
GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_EMPTY_PARENTS));
cl_assert(!git_path_exists(git_buf_cstr(&file)));
git_buf_rtruncate_at_char(&file, '/'); /* three (only contained file.txt) */
cl_assert(!git_path_exists(git_buf_cstr(&file)));
git_buf_rtruncate_at_char(&file, '/'); /* two_two (only contained three) */
cl_assert(!git_path_exists(git_buf_cstr(&file)));
git_buf_rtruncate_at_char(&file, '/'); /* one (contained two_one also) */
cl_assert(git_path_exists(git_buf_cstr(&file)));
cl_assert(git_path_exists(empty_tmp_dir) == true);
git_buf_free(&file);
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY));
}
...@@ -49,7 +49,7 @@ void test_object_blob_write__can_create_a_blob_in_a_standard_repo_from_a_absolut ...@@ -49,7 +49,7 @@ void test_object_blob_write__can_create_a_blob_in_a_standard_repo_from_a_absolut
assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk); assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk);
git_buf_free(&full_path); git_buf_free(&full_path);
cl_must_pass(git_futils_rmdir_r(ELSEWHERE, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_must_pass(git_futils_rmdir_r(ELSEWHERE, NULL, GIT_RMDIR_REMOVE_FILES));
} }
void test_object_blob_write__can_create_a_blob_in_a_bare_repo_from_a_absolute_filepath(void) void test_object_blob_write__can_create_a_blob_in_a_bare_repo_from_a_absolute_filepath(void)
...@@ -65,5 +65,5 @@ void test_object_blob_write__can_create_a_blob_in_a_bare_repo_from_a_absolute_fi ...@@ -65,5 +65,5 @@ void test_object_blob_write__can_create_a_blob_in_a_bare_repo_from_a_absolute_fi
assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk); assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk);
git_buf_free(&full_path); git_buf_free(&full_path);
cl_must_pass(git_futils_rmdir_r(ELSEWHERE, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_must_pass(git_futils_rmdir_r(ELSEWHERE, NULL, GIT_RMDIR_REMOVE_FILES));
} }
...@@ -135,7 +135,7 @@ void test_repo_discover__0(void) ...@@ -135,7 +135,7 @@ void test_repo_discover__0(void)
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path);
cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, NULL, GIT_RMDIR_REMOVE_FILES));
git_repository_free(repo); git_repository_free(repo);
git_buf_free(&ceiling_dirs_buf); git_buf_free(&ceiling_dirs_buf);
} }
......
...@@ -7,7 +7,7 @@ void test_repo_open__cleanup(void) ...@@ -7,7 +7,7 @@ void test_repo_open__cleanup(void)
cl_git_sandbox_cleanup(); cl_git_sandbox_cleanup();
if (git_path_isdir("alternate")) if (git_path_isdir("alternate"))
git_futils_rmdir_r("alternate", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS); git_futils_rmdir_r("alternate", NULL, GIT_RMDIR_REMOVE_FILES);
} }
void test_repo_open__bare_empty_repo(void) void test_repo_open__bare_empty_repo(void)
...@@ -202,8 +202,8 @@ void test_repo_open__bad_gitlinks(void) ...@@ -202,8 +202,8 @@ void test_repo_open__bad_gitlinks(void)
cl_git_fail(git_repository_open_ext(&repo, "alternate", 0, NULL)); cl_git_fail(git_repository_open_ext(&repo, "alternate", 0, NULL));
} }
git_futils_rmdir_r("invalid", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS); git_futils_rmdir_r("invalid", NULL, GIT_RMDIR_REMOVE_FILES);
git_futils_rmdir_r("invalid2", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS); git_futils_rmdir_r("invalid2", NULL, GIT_RMDIR_REMOVE_FILES);
} }
#ifdef GIT_WIN32 #ifdef GIT_WIN32
......
...@@ -71,7 +71,7 @@ static int remove_file_cb(void *data, git_buf *file) ...@@ -71,7 +71,7 @@ static int remove_file_cb(void *data, git_buf *file)
return 0; return 0;
if (git_path_isdir(filename)) if (git_path_isdir(filename))
cl_git_pass(git_futils_rmdir_r(filename, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r(filename, NULL, GIT_RMDIR_REMOVE_FILES));
else else
cl_git_pass(p_unlink(git_buf_cstr(file))); cl_git_pass(p_unlink(git_buf_cstr(file)));
...@@ -314,7 +314,7 @@ void test_status_worktree__issue_592_3(void) ...@@ -314,7 +314,7 @@ void test_status_worktree__issue_592_3(void)
repo = cl_git_sandbox_init("issue_592"); repo = cl_git_sandbox_init("issue_592");
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "c")); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "c"));
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(git_status_foreach(repo, cb_status__check_592, "c/a.txt")); cl_git_pass(git_status_foreach(repo, cb_status__check_592, "c/a.txt"));
...@@ -344,7 +344,7 @@ void test_status_worktree__issue_592_5(void) ...@@ -344,7 +344,7 @@ void test_status_worktree__issue_592_5(void)
repo = cl_git_sandbox_init("issue_592"); repo = cl_git_sandbox_init("issue_592");
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "t")); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "t"));
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(p_mkdir(git_buf_cstr(&path), 0777)); cl_git_pass(p_mkdir(git_buf_cstr(&path), 0777));
cl_git_pass(git_status_foreach(repo, cb_status__check_592, NULL)); cl_git_pass(git_status_foreach(repo, cb_status__check_592, NULL));
......
...@@ -50,7 +50,7 @@ void test_submodule_status__ignore_none(void) ...@@ -50,7 +50,7 @@ void test_submodule_status__ignore_none(void)
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged")); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_fail(git_submodule_lookup(&sm, g_repo, "not_submodule")); cl_git_fail(git_submodule_lookup(&sm, g_repo, "not_submodule"));
...@@ -135,7 +135,7 @@ void test_submodule_status__ignore_untracked(void) ...@@ -135,7 +135,7 @@ void test_submodule_status__ignore_untracked(void)
git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_UNTRACKED; git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_UNTRACKED;
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged")); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign)); cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
...@@ -195,7 +195,7 @@ void test_submodule_status__ignore_dirty(void) ...@@ -195,7 +195,7 @@ void test_submodule_status__ignore_dirty(void)
git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_DIRTY; git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_DIRTY;
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged")); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign)); cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
...@@ -255,7 +255,7 @@ void test_submodule_status__ignore_all(void) ...@@ -255,7 +255,7 @@ void test_submodule_status__ignore_all(void)
git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_ALL; git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_ALL;
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged")); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS)); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign)); cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment