| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- %%--------------------------------------------------------------------
- %% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
- %%
- %% Licensed under the Apache License, Version 2.0 (the "License");
- %% you may not use this file except in compliance with the License.
- %% You may obtain a copy of the License at
- %%
- %% http://www.apache.org/licenses/LICENSE-2.0
- %%
- %% Unless required by applicable law or agreed to in writing, software
- %% distributed under the License is distributed on an "AS IS" BASIS,
- %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- %% See the License for the specific language governing permissions and
- %% limitations under the License.
- %%--------------------------------------------------------------------
- -module(emqx_utils_fs).
- -include_lib("kernel/include/file.hrl").
- -export([traverse_dir/3]).
- -export([read_info/1]).
- -export([canonicalize/1]).
- -type fileinfo() :: #file_info{}.
- -type foldfun(Acc) ::
- fun((_Filepath :: file:name(), fileinfo() | {error, file:posix()}, Acc) -> Acc).
- %% @doc Traverse a directory recursively and apply a fold function to each file.
- %%
- %% This is a safer version of `filelib:fold_files/5` which does not follow symlinks
- %% and reports errors to the fold function, giving the user more control over the
- %% traversal.
- %% It's not an error if `Dirpath` is not a directory, in which case the fold function
- %% will be called once with the file info of `Dirpath`.
- -spec traverse_dir(foldfun(Acc), Acc, _Dirpath :: file:name()) ->
- Acc.
- traverse_dir(FoldFun, Acc, Dirpath) ->
- traverse_dir(FoldFun, Acc, Dirpath, read_info(Dirpath)).
- traverse_dir(FoldFun, AccIn, DirPath, {ok, #file_info{type = directory}}) ->
- case file:list_dir(DirPath) of
- {ok, Filenames} ->
- lists:foldl(
- fun(Filename, Acc) ->
- AbsPath = filename:join(DirPath, Filename),
- traverse_dir(FoldFun, Acc, AbsPath)
- end,
- AccIn,
- Filenames
- );
- {error, Reason} ->
- FoldFun(DirPath, {error, Reason}, AccIn)
- end;
- traverse_dir(FoldFun, Acc, AbsPath, {ok, Info}) ->
- FoldFun(AbsPath, Info, Acc);
- traverse_dir(FoldFun, Acc, AbsPath, {error, Reason}) ->
- FoldFun(AbsPath, {error, Reason}, Acc).
- -spec read_info(file:name()) ->
- {ok, fileinfo()} | {error, file:posix() | badarg}.
- read_info(AbsPath) ->
- file:read_link_info(AbsPath, [{time, posix}, raw]).
- %% @doc Canonicalize a file path.
- %% Removes stray slashes and converts to a string.
- -spec canonicalize(file:name()) ->
- string().
- canonicalize(Filename) ->
- case filename:split(str(Filename)) of
- Components = [_ | _] ->
- filename:join(Components);
- [] ->
- ""
- end.
- str(Value) ->
- case unicode:characters_to_list(Value, unicode) of
- Str when is_list(Str) ->
- Str;
- {error, _, _} ->
- erlang:error(badarg, [Value])
- end.
|