From 9d47ab01be9819e0f69f7da73c71c34903f5b911 Mon Sep 17 00:00:00 2001 From: emtenet Date: Sun, 24 Apr 2016 13:41:17 +1000 Subject: Remove dead code of cp_r/2, xcopy_win32/2 and cp_r_win32/2. The bulk of the code is hidden behind opposite checks: * os:type() /= {win32, _} in symlink_or_copy/2 * os:type() == {win32, _} in cp_r/2 symlink_or_copy/2 is always using win32_symlink/2 when file:make_symlink/2 fails. --- src/rlx_util.erl | 64 ++------------------------------------------------------ 1 file changed, 2 insertions(+), 62 deletions(-) diff --git a/src/rlx_util.erl b/src/rlx_util.erl index b3fc2b7..f68c291 100644 --- a/src/rlx_util.erl +++ b/src/rlx_util.erl @@ -233,18 +233,14 @@ symlink_or_copy(Source, Target) -> ok; {error, eexist} -> {error, eexist}; - {error, _} -> + {error, _} = Error -> case os:type() of {win32, _} -> S = unicode:characters_to_list(Source), T = unicode:characters_to_list(Target), win32_symlink(filename:nativename(S), filename:nativename(T)); _ -> - case filelib:is_dir(Target) of - true -> ok; - false -> - cp_r([Source], Target) - end + Error end end. @@ -253,62 +249,6 @@ win32_symlink(Source, Target) -> os:cmd("cmd /c mklink /j " ++ Target ++ " " ++ Source), ok. --spec cp_r(list(string()), file:filename()) -> 'ok'. -cp_r(Sources, Dest) -> - case os:type() of - {unix, _} -> - ok; - {win32, _} -> - lists:foreach(fun(Src) -> ok = cp_r_win32(Src,Dest) end, Sources), - ok - end. - -xcopy_win32(Source,Dest)-> - %% "xcopy \"~s\" \"~s\" /q /y /e 2> nul", Chanegd to robocopy to - %% handle long names. May have issues with older windows. - os:cmd("robocopy " ++ Source ++ " " ++ Dest ++ " /e /is"), - ok. - -cp_r_win32({true, SourceDir}, {true, DestDir}) -> - %% from directory to directory - ok = case file:make_dir(DestDir) of - {error, eexist} -> ok; - Other -> Other - end, - ok = xcopy_win32(SourceDir, DestDir); -cp_r_win32({false, Source} = S,{true, DestDir}) -> - %% from file to directory - cp_r_win32(S, {false, filename:join(DestDir, filename:basename(Source))}); -cp_r_win32({false, Source},{false, Dest}) -> - %% from file to file - {ok,_} = file:copy(Source, Dest), - ok; -cp_r_win32({true, SourceDir}, {false, DestDir}) -> - case filelib:is_regular(DestDir) of - true -> - %% From directory to file? This shouldn't happen - {error, lists:flatten( - io_lib:format("Cannot copy dir (~p) to file (~p)\n", - [SourceDir, DestDir]))}; - false -> - %% Specifying a target directory that doesn't currently exist. - %% So let's attempt to create this directory - case filelib:ensure_dir(filename:join(DestDir, "dummy")) of - ok -> - ok = xcopy_win32(SourceDir, DestDir); - {error, Reason} -> - {error, lists:flatten( - io_lib:format("Unable to create dir ~p: ~p\n", - [DestDir, Reason]))} - end - end; -cp_r_win32(Source,Dest) -> - Dst = {filelib:is_dir(Dest), Dest}, - lists:foreach(fun(Src) -> - ok = cp_r_win32({filelib:is_dir(Src), Src}, Dst) - end, filelib:wildcard(Source)), - ok. - %% @doc Returns the color intensity, we first check the application envorinment %% if that is not set we check the environment variable RELX_COLOR. intensity() -> -- cgit v1.2.3 From 07943b1b41e8d1ffdf8b9f770e623212581b12cd Mon Sep 17 00:00:00 2001 From: emtenet Date: Sun, 24 Apr 2016 15:01:09 +1000 Subject: Do not create a junction (soft link) for files When symlink_or_copy/2 cannot use file:make_symlink/2 on Windows due to the user lacking SeCreateSymbolicLinkPrivilege it tries a fall back. Detect the source type and use an appropriate fall back: * junction for directories and, * copy for files. Improve error detection in win32_make_junction/2 and make it repeatable when the target exists --- src/rlx_util.erl | 59 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/src/rlx_util.erl b/src/rlx_util.erl index f68c291..1893353 100644 --- a/src/rlx_util.erl +++ b/src/rlx_util.erl @@ -45,6 +45,8 @@ -define(DFLT_INTENSITY, high). -define(ONE_LEVEL_INDENT, " "). + +-include_lib("kernel/include/file.hrl"). %%============================================================================ %% types %%============================================================================ @@ -233,21 +235,62 @@ symlink_or_copy(Source, Target) -> ok; {error, eexist} -> {error, eexist}; - {error, _} = Error -> + {error, eperm} = Error -> + % We get eperm on Windows if we do not have + % SeCreateSymbolicLinkPrivilege + % Try the next alternative case os:type() of {win32, _} -> - S = unicode:characters_to_list(Source), - T = unicode:characters_to_list(Target), - win32_symlink(filename:nativename(S), filename:nativename(T)); + win32_make_junction_or_copy(Source, Target); _ -> Error - end + end; + {error, _} = Error -> + Error + end. + +win32_make_junction_or_copy(Source, Target) -> + case filelib:is_dir(Source) of + true -> + win32_make_junction(Source, Target); + _ -> + ec_file:copy(Source, Target) end. +win32_make_junction(Source, Target) -> + % The mklink will fail if the target already exists, check for that first + case file:read_link_info(Target) of + {error, enoent} -> + win32_make_junction_cmd(Source, Target); + {ok, #file_info{type = symlink}} -> + case file:read_link(Target) of + {ok, Source} -> + ok; + {ok, _} -> + ok = file:del_dir(Target), + win32_make_junction_cmd(Source, Target); + {error, Reason} -> + {error, {readlink, Reason}} + end; + {ok, #file_info{type = Type}} -> + {error, {mklink_cannot_replace_existing, Type, Target}}; + Error -> + Error + end. -win32_symlink(Source, Target) -> - os:cmd("cmd /c mklink /j " ++ Target ++ " " ++ Source), - ok. +win32_make_junction_cmd(Source, Target) -> + S = unicode:characters_to_list(Source), + T = unicode:characters_to_list(Target), + Cmd = "cmd /c mklink /j " ++ filename:nativename(T) ++ " " ++ filename:nativename(S), + case os:cmd(Cmd) of + "Junction created " ++ _ -> + ok; + [] -> + % When mklink fails it prints the error message to stderr which + % is not picked up by os:cmd() hence this case switch is for + % an empty message + {error, make_junction_failed} + end. %% @doc Returns the color intensity, we first check the application envorinment %% if that is not set we check the environment variable RELX_COLOR. -- cgit v1.2.3 From 476b439de0077b6f7a60622d2498b85e6f52698a Mon Sep 17 00:00:00 2001 From: Tino Breddin Date: Tue, 16 Apr 2019 16:17:10 +0200 Subject: Use recursive copy as last fallback on all platforms --- src/rlx_util.erl | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/rlx_util.erl b/src/rlx_util.erl index 1893353..5d3744d 100644 --- a/src/rlx_util.erl +++ b/src/rlx_util.erl @@ -235,26 +235,28 @@ symlink_or_copy(Source, Target) -> ok; {error, eexist} -> {error, eexist}; - {error, eperm} = Error -> - % We get eperm on Windows if we do not have - % SeCreateSymbolicLinkPrivilege - % Try the next alternative - case os:type() of - {win32, _} -> + {error, Err} -> + case {os:type(), Err} of + {{win32, _}, eperm} -> + % We get eperm on Windows if we do not have + % SeCreateSymbolicLinkPrivilege + % Try the next alternative win32_make_junction_or_copy(Source, Target); _ -> - Error - end; - {error, _} = Error -> - Error + % On other systems we try to copy next + cp_r(Source, Target) + end end. +cp_r(Source, Target) -> + ec_file:copy(Source, Target, [{recursive, true}, {fileinfo, [mode, time, owner, group]}]). + win32_make_junction_or_copy(Source, Target) -> case filelib:is_dir(Source) of true -> win32_make_junction(Source, Target); _ -> - ec_file:copy(Source, Target) + cp_r(Source, Target) end. win32_make_junction(Source, Target) -> @@ -272,8 +274,9 @@ win32_make_junction(Source, Target) -> {error, Reason} -> {error, {readlink, Reason}} end; - {ok, #file_info{type = Type}} -> - {error, {mklink_cannot_replace_existing, Type, Target}}; + {ok, #file_info{type = _Type}} -> + % Directory already exists, so we overwrite the copy + cp_r(Source, Target); Error -> Error end. @@ -289,7 +292,7 @@ win32_make_junction_cmd(Source, Target) -> % When mklink fails it prints the error message to stderr which % is not picked up by os:cmd() hence this case switch is for % an empty message - {error, make_junction_failed} + cp_r(Source, Target) end. %% @doc Returns the color intensity, we first check the application envorinment -- cgit v1.2.3