aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoremtenet <[email protected]>2016-04-24 15:01:09 +1000
committerTino Breddin <[email protected]>2019-04-16 15:56:55 +0200
commit07943b1b41e8d1ffdf8b9f770e623212581b12cd (patch)
treefac0bb10c8bc06919605dd2b76dbdd3b6726df30
parent9d47ab01be9819e0f69f7da73c71c34903f5b911 (diff)
downloadrelx-07943b1b41e8d1ffdf8b9f770e623212581b12cd.tar.gz
relx-07943b1b41e8d1ffdf8b9f770e623212581b12cd.tar.bz2
relx-07943b1b41e8d1ffdf8b9f770e623212581b12cd.zip
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
-rw-r--r--src/rlx_util.erl59
1 files 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.