diff options
Diffstat (limited to 'src/nvim/fileio.c')
-rw-r--r-- | src/nvim/fileio.c | 109 |
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; } |