erlang/otp — pull request #411 by lrascao (2014-06-27 17:11:51+00:00)
Title: fix escript archive symlinked across drives

TL;DR: escript archive files won't work on Windows when located in directory symlinks between different drives

impact:
rebar for instance will not work in these circumstances

requirements:

Windows machine, two different drives (eg. C: and J:)
folder J:\otp_bug\otp_bug, containging an .escript file (generation of .escript described below)
folder C:\tmp\otp_bug which is a folder symlink to J:\otp_bug (created with: cd c:\tmp, mklink /d otp_bug j:\otp_bug)
repro steps:

snip repro scripts below, copy demo.erl, build_demo.erl and bug.erl to J:\otp_bug\otp_bug
enter C:\tmp\otp_bug\otp_bug
generate demo.escript (run ./build_demo.erl)
run ./demo.script, it will fail with error undefined function demo:main
change directory to J:\otp_bug\otp_bug, run the same exact ./demo.script, it will succeed
run ./bug.erl for isolated problem cause (will print: path: C:/tmp/j:/otp_bug/otp_bug/demo.escript) with fix in place correct output will be j:/otp_bug/otp_bug/demo.escript
problem description:

problem is located in method real_path@erts/preloaded/src/erl_prim_loader.erl
real_path assumes that when a symlink is encountered when exploring the path only the last element of the path array can be replaced (with the symlink target)
this is fine for unix, however in windows there is the possibility that the last n elements have to be replaced, eg. C:\tmp\otp_bug (["gub_pto", "pmt", ":c"] should become ["gub_pto", ":j"])
repro scripts:
---------------- start demo.erl ---------------
%% Demo
-module(demo).
-mode(compile).

-export([main/1]).

main(_Args) ->
io:format("SMP support: ~p~n", [erlang:system_info(smp_support)]).
---------------- end demo.erl ---------------

---------------- start build_demo.erl ---------------
#!/usr/bin/env escript
%% This is an -*- erlang -*- file
%%!
main(_Args) ->
{ok, _, BeamCode} = compile:file("demo.erl", [binary, debug_info]),
{ok, SourceCode} = file:read_file("demo.erl"),
escript:create("demo.escript", [shebang, comment, {emu_args, ""}, {archive, [{"demo.erl", SourceCode}, {"demo.beam", BeamCode}], []}]),
escript:extract("demo.escript", []),
ok.
---------------- end build_demo.erl ---------------

---------------- start bug.erl ---------------
#!/usr/bin/env escript
%% This is an -*- erlang -*- file
%%!
main([]) ->
File = "./demo.escript",
{ok, ArchiveBin} = escript:parse_file(File),
{ok, FileInfo} = file:read_file_info(File),
{ok, Path} = erl_prim_loader:set_primary_archive(File, ArchiveBin, FileInfo, fun escript:parse_file/1),
io:format("path: ~s~n", [Path]).
---------------- end bug.erl ---------------