aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/fileio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/fileio.c')
-rw-r--r--src/nvim/fileio.c109
1 files changed, 92 insertions, 17 deletions
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 29c29a2884..2037ba5f19 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -5204,38 +5204,113 @@ static void vim_maketempdir(void)
(void)umask(umask_save);
}
+// Evaluate "expr" for readdir().
+static varnumber_T readdir_checkitem(typval_T *expr, const char *name)
+{
+ typval_T save_val;
+ typval_T rettv;
+ typval_T argv[2];
+ varnumber_T retval = 0;
+ bool error = false;
+
+ prepare_vimvar(VV_VAL, &save_val);
+ set_vim_var_string(VV_VAL, name, -1);
+ argv[0].v_type = VAR_STRING;
+ argv[0].vval.v_string = (char_u *)name;
+
+ if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL) {
+ goto theend;
+ }
+
+ retval = tv_get_number_chk(&rettv, &error);
+ if (error) {
+ retval = -1;
+ }
+
+ tv_clear(&rettv);
+
+theend:
+ set_vim_var_string(VV_VAL, NULL, 0);
+ restore_vimvar(VV_VAL, &save_val);
+ return retval;
+}
+
+/// Core part of "readdir()" function.
+/// Retrieve the list of files/directories of "dirp" into "gap".
+void readdir_core(
+ garray_T *gap,
+ Directory *dirp,
+ typval_T *expr,
+ bool is_checkitem)
+{
+ ga_init(gap, (int)sizeof(char *), 20);
+
+ for (;;) {
+ bool ignore;
+
+ const char *path = os_scandir_next(dirp);
+ if (path == NULL) {
+ break;
+ }
+
+ ignore = (path[0] == '.'
+ && (path[1] == NUL || (path[1] == '.' && path[2] == NUL)));
+ if (!ignore && expr != NULL && expr->v_type != VAR_UNKNOWN
+ && is_checkitem) {
+ varnumber_T r = readdir_checkitem(expr, path);
+
+ if (r < 0) {
+ break;
+ }
+ if (r == 0) {
+ ignore = true;
+ }
+ }
+
+ if (!ignore) {
+ ga_grow(gap, 1);
+ ((char **)gap->ga_data)[gap->ga_len++] = xstrdup(path);
+ }
+ }
+
+ if (gap->ga_len > 0) {
+ sort_strings((char_u **)gap->ga_data, gap->ga_len);
+ }
+
+ os_closedir(dirp);
+}
+
/// Delete "name" and everything in it, recursively.
/// @param name The path which should be deleted.
/// @return 0 for success, -1 if some file was not deleted.
int delete_recursive(const char *name)
{
int result = 0;
+ char *exp = (char *)vim_strsave((char_u *)name);
+ Directory dir;
- if (os_isrealdir(name)) {
- snprintf((char *)NameBuff, MAXPATHL, "%s/*", name); // NOLINT
-
- char_u **files;
- int file_count;
- char_u *exp = vim_strsave(NameBuff);
- if (gen_expand_wildcards(1, &exp, &file_count, &files,
- EW_DIR | EW_FILE | EW_SILENT | EW_ALLLINKS
- | EW_DODOT | EW_EMPTYOK) == OK) {
- for (int i = 0; i < file_count; i++) {
- if (delete_recursive((const char *)files[i]) != 0) {
- result = -1;
- }
+ if (os_isrealdir(name) && os_scandir(&dir, exp)) {
+ garray_T ga;
+
+ readdir_core(&ga, &dir, NULL, false);
+
+ for (int i = 0; i < ga.ga_len; i++) {
+ vim_snprintf((char *)NameBuff, MAXPATHL, "%s/%s", exp,
+ ((char_u **)ga.ga_data)[i]);
+ if (delete_recursive((const char *)NameBuff) != 0) {
+ result = -1;
}
- FreeWild(file_count, files);
- } else {
- result = -1;
}
- xfree(exp);
+ ga_clear_strings(&ga);
+
os_rmdir(name);
} else {
result = os_remove(name) == 0 ? 0 : -1;
}
+ xfree(exp);
+
return result;
}