Merge pull request #135 from tsloughter/copy-file-info
support more fine grained file info copy levels
This commit is contained in:
commit
1bd107113b
1 changed files with 64 additions and 19 deletions
|
@ -11,6 +11,7 @@
|
||||||
exists/1,
|
exists/1,
|
||||||
copy/2,
|
copy/2,
|
||||||
copy/3,
|
copy/3,
|
||||||
|
copy_file_info/3,
|
||||||
insecure_mkdtemp/0,
|
insecure_mkdtemp/0,
|
||||||
mkdir_path/1,
|
mkdir_path/1,
|
||||||
mkdir_p/1,
|
mkdir_p/1,
|
||||||
|
@ -40,7 +41,8 @@
|
||||||
%%============================================================================
|
%%============================================================================
|
||||||
%% Types
|
%% Types
|
||||||
%%============================================================================
|
%%============================================================================
|
||||||
-type option() :: recursive.
|
-type file_info() :: mode | time | owner | group.
|
||||||
|
-type option() :: recursive | {file_info, [file_info()]}.
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
|
@ -57,36 +59,79 @@ exists(Filename) ->
|
||||||
%% @doc copy an entire directory to another location.
|
%% @doc copy an entire directory to another location.
|
||||||
-spec copy(file:name(), file:name(), Options::[option()]) -> ok | {error, Reason::term()}.
|
-spec copy(file:name(), file:name(), Options::[option()]) -> ok | {error, Reason::term()}.
|
||||||
copy(From, To, []) ->
|
copy(From, To, []) ->
|
||||||
copy(From, To);
|
copy_(From, To, []);
|
||||||
copy(From, To, [recursive] = Options) ->
|
copy(From, To, Options) ->
|
||||||
case is_dir(From) of
|
case proplists:get_value(recursive, Options, false) of
|
||||||
false ->
|
|
||||||
copy(From, To);
|
|
||||||
true ->
|
true ->
|
||||||
make_dir_if_dir(To),
|
case is_dir(From) of
|
||||||
copy_subfiles(From, To, Options)
|
false ->
|
||||||
|
copy_(From, To, Options);
|
||||||
|
true ->
|
||||||
|
make_dir_if_dir(To),
|
||||||
|
copy_subfiles(From, To, Options)
|
||||||
|
end;
|
||||||
|
false ->
|
||||||
|
copy_(From, To, Options)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @doc copy a file including timestamps,ownership and mode etc.
|
%% @doc copy a file including timestamps,ownership and mode etc.
|
||||||
-spec copy(From::file:filename(), To::file:filename()) -> ok | {error, Reason::term()}.
|
-spec copy(From::file:filename(), To::file:filename()) -> ok | {error, Reason::term()}.
|
||||||
copy(From, To) ->
|
copy(From, To) ->
|
||||||
|
copy_(From, To, [{file_info, [mode, time, owner, group]}]).
|
||||||
|
|
||||||
|
copy_(From, To, Options) ->
|
||||||
case file:copy(From, To) of
|
case file:copy(From, To) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
case file:read_file_info(From) of
|
copy_file_info(To, From, proplists:get_value(file_info, Options, []));
|
||||||
{ok, FileInfo} ->
|
|
||||||
case file:write_file_info(To, FileInfo) of
|
|
||||||
ok ->
|
|
||||||
ok;
|
|
||||||
{error, WFError} ->
|
|
||||||
{error, {write_file_info_failed, WFError}}
|
|
||||||
end;
|
|
||||||
{error, RFError} ->
|
|
||||||
{error, {read_file_info_failed, RFError}}
|
|
||||||
end;
|
|
||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
{error, {copy_failed, Error}}
|
{error, {copy_failed, Error}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
copy_file_info(To, From, FileInfoToKeep) ->
|
||||||
|
case file:read_file_info(From) of
|
||||||
|
{ok, FileInfo} ->
|
||||||
|
case write_file_info(To, FileInfo, FileInfoToKeep) of
|
||||||
|
[] ->
|
||||||
|
ok;
|
||||||
|
Errors ->
|
||||||
|
{error, {write_file_info_failed_for, Errors}}
|
||||||
|
end;
|
||||||
|
{error, RFError} ->
|
||||||
|
{error, {read_file_info_failed, RFError}}
|
||||||
|
end.
|
||||||
|
|
||||||
|
write_file_info(To, FileInfo, FileInfoToKeep) ->
|
||||||
|
WriteInfoFuns = [{mode, fun try_write_mode/2},
|
||||||
|
{time, fun try_write_time/2},
|
||||||
|
{group, fun try_write_group/2},
|
||||||
|
{owner, fun try_write_owner/2}],
|
||||||
|
lists:foldl(fun(Info, Acc) ->
|
||||||
|
case proplists:get_value(Info, WriteInfoFuns, undefined) of
|
||||||
|
undefined ->
|
||||||
|
Acc;
|
||||||
|
F ->
|
||||||
|
case F(To, FileInfo) of
|
||||||
|
ok ->
|
||||||
|
Acc;
|
||||||
|
{error, Reason} ->
|
||||||
|
[{Info, Reason} | Acc]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end, [], FileInfoToKeep).
|
||||||
|
|
||||||
|
|
||||||
|
try_write_mode(To, #file_info{mode=Mode}) ->
|
||||||
|
file:write_file_info(To, #file_info{mode=Mode}).
|
||||||
|
|
||||||
|
try_write_time(To, #file_info{atime=Atime, mtime=Mtime}) ->
|
||||||
|
file:write_file_info(To, #file_info{atime=Atime, mtime=Mtime}).
|
||||||
|
|
||||||
|
try_write_owner(To, #file_info{uid=OwnerId}) ->
|
||||||
|
file:write_file_info(To, #file_info{uid=OwnerId}).
|
||||||
|
|
||||||
|
try_write_group(To, #file_info{gid=OwnerId}) ->
|
||||||
|
file:write_file_info(To, #file_info{gid=OwnerId}).
|
||||||
|
|
||||||
%% @doc return an md5 checksum string or a binary. Same as unix utility of
|
%% @doc return an md5 checksum string or a binary. Same as unix utility of
|
||||||
%% same name.
|
%% same name.
|
||||||
-spec md5sum(string() | binary()) -> string().
|
-spec md5sum(string() | binary()) -> string().
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue