File 4391-file-implement-del_dir_r-1-for-recursive-deletes.patch of Package erlang
From 51269f062091dabd58631822d3145a573ea2d2f8 Mon Sep 17 00:00:00 2001
From: Mikael Pettersson <mikpelinux@gmail.com>
Date: Mon, 23 Mar 2020 18:16:10 +0100
Subject: [PATCH] file: implement del_dir_r/1 for recursive deletes file_SUITE:
add basic tests of file:del_dir_r/1 file_SUITE: use file:del_dir_r/1 instead
of local rm_rf/2 file.xml: add documentation for file:del_dir_r/1
---
lib/kernel/doc/src/file.xml | 22 +++++++++++++++++
lib/kernel/src/file.erl | 21 +++++++++++++++-
lib/kernel/test/file_SUITE.erl | 56 ++++++++++++++++++++++++++++--------------
3 files changed, 80 insertions(+), 19 deletions(-)
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index c4073f13a2..e1191ced52 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -401,6 +401,28 @@ f.txt: {person, "kalle", 25}.
</taglist>
</desc>
</func>
+ <func>
+ <name name="del_dir_r" arity="1" since="OTP 23.0"/>
+ <fsummary>Delete a file or directory.</fsummary>
+ <desc>
+ <p>Deletes file or directory <c><anno>File</anno></c>.
+ If <c><anno>File</anno></c> is a directory, its contents
+ is first recursively deleted. Returns:</p>
+ <taglist>
+ <tag><c>ok</c></tag>
+ <item>
+ <p>The operation completed without errors.</p>
+ </item>
+ <tag><c>{error, posix()}</c></tag>
+ <item>
+ <p>An error occurred when accessing or deleting <c><anno>File</anno></c>.
+ If some file or directory under <c><anno>File</anno></c> could not be
+ deleted, <c><anno>File</anno></c> cannot be deleted as it is non-empty,
+ and <c>{error, eexist}</c> is returned.</p>
+ </item>
+ </taglist>
+ </desc>
+ </func>
<func>
<name name="delete" arity="1" since=""/>
<fsummary>Delete a file.</fsummary>
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index cde03ce1c4..8abfb3ef35 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -28,7 +28,7 @@
-export([format_error/1]).
%% File system and metadata.
-export([get_cwd/0, get_cwd/1, set_cwd/1, delete/1, rename/2,
- make_dir/1, del_dir/1, list_dir/1, list_dir_all/1,
+ make_dir/1, del_dir/1, del_dir_r/1, list_dir/1, list_dir_all/1,
read_file_info/1, read_file_info/2,
write_file_info/2, write_file_info/3,
altname/1,
@@ -239,6 +239,25 @@ make_dir(Name) ->
del_dir(Name) ->
check_and_call(del_dir, [file_name(Name)]).
+-spec del_dir_r(File) -> ok | {error, Reason} when
+ File :: name_all(),
+ Reason :: posix() | badarg.
+
+del_dir_r(File) -> % rm -rf File
+ case read_link_info(File) of
+ {ok, #file_info{type = directory}} ->
+ case list_dir_all(File) of
+ {ok, Names} ->
+ lists:foreach(fun(Name) ->
+ del_dir_r(filename:join(File, Name))
+ end, Names);
+ {error, _Reason} -> ok
+ end,
+ del_dir(File);
+ {ok, _FileInfo} -> delete(File);
+ {error, _Reason} = Error -> Error
+ end.
+
-spec read_file_info(Filename) -> {ok, FileInfo} | {error, Reason} when
Filename :: name_all(),
FileInfo :: file_info(),
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index a73c5e9753..52ef711008 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -47,7 +47,7 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2, end_per_testcase/2,
read_write_file/1, names/1]).
--export([cur_dir_0/1, cur_dir_1/1, make_del_dir/1,
+-export([cur_dir_0/1, cur_dir_1/1, make_del_dir/1, make_del_dir_r/1,
list_dir/1,list_dir_error/1,
untranslatable_names/1, untranslatable_names_error/1,
pos1/1, pos2/1, pos3/1]).
@@ -143,7 +143,7 @@ all() ->
].
groups() ->
- [{dirs, [], [make_del_dir, cur_dir_0, cur_dir_1,
+ [{dirs, [], [make_del_dir, make_del_dir_r, cur_dir_0, cur_dir_1,
list_dir, list_dir_error, untranslatable_names,
untranslatable_names_error]},
{files, [],
@@ -637,6 +637,41 @@ make_del_dir(Config) when is_list(Config) ->
end,
ok.
+make_del_dir_r(Config) when is_list(Config) ->
+ RootDir = proplists:get_value(priv_dir, Config),
+ NewDir = filename:join(RootDir, ?MODULE_STRING ++ "_make_del_dir_r"),
+ ok = ?FILE_MODULE:make_dir(NewDir),
+
+ %% Create:
+ %% newdir/
+ %% file1
+ %% dir/
+ %% file2
+ %% link -> /newdir/file1
+ File1 = test_server:temp_name(filename:join(NewDir, "file1")),
+ ok = ?FILE_MODULE:write_file(File1, <<"file1">>),
+ Dir = test_server:temp_name(filename:join(NewDir, "dir")),
+ ok = ?FILE_MODULE:make_dir(Dir),
+ File2 = test_server:temp_name(filename:join(Dir, "file2")),
+ ok = ?FILE_MODULE:write_file(File2, <<"file2">>),
+ Link = test_server:temp_name(filename:join(Dir, "link")),
+ case ?FILE_MODULE:make_symlink(File1, Link) of
+ {error, enotsup} -> ok; % symlinks not supported
+ {error, eperm} -> {win32, _} = os:type(), ok; % not allowed to make symlinks
+ ok -> ok
+ end,
+
+ %% check that del_dir_r/1 succeeds on non-empty dir
+ ok = ?FILE_MODULE:del_dir_r(Dir),
+ {error, enoent} = ?FILE_MODULE:read_file_info(Dir),
+ %% check that the symlink wasn't followed
+ {ok, _} = ?FILE_MODULE:read_file_info(File1),
+
+ %% clean up
+ ?FILE_MODULE:del_dir_r(NewDir),
+ [] = flush(),
+ ok.
+
cur_dir_0(Config) when is_list(Config) ->
%% Find out the current dir, and cd to it ;-)
{ok,BaseDir} = ?FILE_MODULE:get_cwd(),
@@ -3093,7 +3128,7 @@ symlinks(Config) when is_list(Config) ->
{ok, Name} = ?FILE_MODULE:read_link(Alias),
{ok, Name} = ?FILE_MODULE:read_link_all(Alias),
%% If all is good, delete dir again (avoid hanging dir on windows)
- rm_rf(?FILE_MODULE,NewDir),
+ file:del_dir_r(NewDir),
ok
end,
@@ -4799,18 +4834,3 @@ disc_free(Path) ->
memsize() ->
{Tot,_Used,_} = memsup:get_memory_data(),
Tot.
-
-%%%-----------------------------------------------------------------
-%%% Utilities
-rm_rf(Mod,Dir) ->
- case Mod:read_link_info(Dir) of
- {ok, #file_info{type = directory}} ->
- {ok, Content} = Mod:list_dir_all(Dir),
- [ rm_rf(Mod,filename:join(Dir,C)) || C <- Content ],
- Mod:del_dir(Dir),
- ok;
- {ok, #file_info{}} ->
- Mod:delete(Dir);
- _ ->
- ok
- end.
--
2.16.4