49
49
prim_read_file_info/2, prim_get_cwd/2]).
51
51
%% Used by escript and code
52
-export([set_primary_archive/2, release_archives/0]).
54
%% Internal function. Exported to avoid dialyzer warnings
52
-export([set_primary_archive/3, release_archives/0]).
57
54
-include_lib("kernel/include/file.hrl").
59
56
-type host() :: atom().
58
-record(prim_state, {debug :: boolean(),
61
-type prim_state() :: #prim_state{}.
62
{loader :: 'efile' | 'inet',
63
hosts = [] :: [host()], % hosts list (to boot from)
64
{loader :: 'efile' | 'inet',
65
hosts = [] :: [host()], % hosts list (to boot from)
64
66
id, % not used any more?
66
timeout, % idle timeout
67
n_timeouts, % Number of timeouts before archives are released
68
multi_get = false :: boolean(),
69
prim_state}). % state for efile code loader
67
data :: 'noport' | port(), % data port etc
68
timeout :: timeout(), % idle timeout
69
%% Number of timeouts before archives are released
70
n_timeouts :: non_neg_integer(),
71
multi_get = false :: boolean(),
72
prim_state :: prim_state()}). % state for efile code loader
71
74
-define(IDLE_TIMEOUT, 60000). %% tear inet connection after 1 minutes
72
75
-define(N_TIMEOUTS, 6). %% release efile archive after 6 minutes
220
221
check_file_result(get_cwd, Drive, request({get_cwd,[Drive]})).
222
223
-spec set_primary_archive(File :: string() | 'undefined',
223
ArchiveBin :: binary() | 'undefined')
224
-> {ok, [string()]} | {error,_}.
224
ArchiveBin :: binary() | 'undefined',
225
FileInfo :: #file_info{} | 'undefined')
226
-> {ok, [string()]} | {error,_}.
226
set_primary_archive(undefined, undefined) ->
227
request({set_primary_archive, undefined, undefined});
228
set_primary_archive(File, ArchiveBin)
229
when is_list(File), is_binary(ArchiveBin) ->
230
request({set_primary_archive, File, ArchiveBin}).
228
set_primary_archive(undefined, undefined, undefined) ->
229
request({set_primary_archive, undefined, undefined, undefined});
230
set_primary_archive(File, ArchiveBin, FileInfo)
231
when is_list(File), is_binary(ArchiveBin), is_record(FileInfo, file_info) ->
232
request({set_primary_archive, File, ArchiveBin, FileInfo}).
232
234
-spec release_archives() -> 'ok' | {'error', _}.
315
317
{get_cwd,[_]=Args} ->
316
318
{Res,State1} = handle_get_cwd(State, Args),
317
319
{Res,State1,Paths};
318
{set_primary_archive,File,Bin} ->
319
{Res,State1} = handle_set_primary_archive(State, File, Bin),
320
{set_primary_archive,File,Bin,FileInfo} ->
321
{Res,State1} = handle_set_primary_archive(State, File, Bin, FileInfo),
320
322
{Res,State1,Paths};
321
323
release_archives ->
322
324
{Res,State1} = handle_release_archives(State),
356
358
handle_get_file(State = #state{loader = inet}, Paths, File) ->
357
359
?SAFE2(inet_get_file_from_port(State, File, Paths), State).
359
handle_set_primary_archive(State= #state{loader = efile}, File, Bin) ->
360
?SAFE2(efile_set_primary_archive(State, File, Bin), State).
361
handle_set_primary_archive(State= #state{loader = efile}, File, Bin, FileInfo) ->
362
?SAFE2(efile_set_primary_archive(State, File, Bin, FileInfo), State).
362
364
handle_release_archives(State= #state{loader = efile}) ->
363
365
?SAFE2(efile_release_archives(State), State).
481
483
efile_get_file_from_port3(State, _File, []) ->
482
484
{{error,enoent},State}.
484
efile_set_primary_archive(#state{prim_state = PS} = State, File, Bin) ->
485
{Res, PS2} = prim_set_primary_archive(PS, File, Bin),
486
efile_set_primary_archive(#state{prim_state = PS} = State, File, Bin, FileInfo) ->
487
{Res, PS2} = prim_set_primary_archive(PS, File, Bin, FileInfo),
486
488
{Res,State#state{prim_state = PS2}}.
488
490
efile_release_archives(#state{prim_state = PS} = State) ->
658
660
inet_send_and_rcv(Msg, Tag, State) when State#state.data =:= noport ->
659
661
{ok,Tcp} = find_master(State#state.hosts), %% reconnect
660
inet_send_and_rcv(Msg, Tag, State#state { data = Tcp,
661
timeout = ?IDLE_TIMEOUT });
662
inet_send_and_rcv(Msg, Tag, #state{data=Tcp,timeout=Timeout}=State) ->
662
inet_send_and_rcv(Msg, Tag, State#state{data = Tcp,
663
timeout = ?IDLE_TIMEOUT});
664
inet_send_and_rcv(Msg, Tag, #state{data = Tcp, timeout = Timeout} = State) ->
663
665
prim_inet:send(Tcp, term_to_binary(Msg)),
665
667
{tcp,Tcp,BinMsg} ->
779
782
cache_new(#prim_state{debug = Deb}).
781
784
prim_release_archives(PS) ->
782
785
debug(PS, release_archives),
783
{Res, PS2}= prim_do_release_archives(PS, get(), []),
786
{Res, PS2} = prim_do_release_archives(PS, get(), []),
784
787
debug(PS2, {return, Res}),
787
790
prim_do_release_archives(PS, [{ArchiveFile, DictVal} | KeyVals], Acc) ->
790
{primary, _PrimZip} ->
793
{primary, _PrimZip, _FI} ->
791
794
ok; % Keep primary archive
793
796
debug(PS, {release, cache, ArchiveFile}),
794
797
erase(ArchiveFile),
795
798
clear_cache(ArchiveFile, Cache)
813
816
debug(PS, {return, Res}),
816
{primary, PrimZip} = erase(ArchiveFile),
819
{primary, PrimZip, _FI} = erase(ArchiveFile),
817
820
ok = prim_zip:close(PrimZip),
818
821
PS2 = PS#prim_state{primary_archive = undefined},
820
823
debug(PS2, {return, Res}),
823
prim_set_primary_archive(PS, ArchiveFile, ArchiveBin)
826
prim_set_primary_archive(PS, ArchiveFile, ArchiveBin, #file_info{} = FileInfo)
824
827
when is_list(ArchiveFile), is_binary(ArchiveBin) ->
825
828
%% Try the archive file
826
829
debug(PS, {set_primary_archive, ArchiveFile, byte_size(ArchiveBin)}),
833
836
["", "nibe", RevApp] -> % Reverse ebin
834
837
%% Collect ebin directories in archive
835
838
Ebin = reverse(RevApp) ++ "/ebin",
841
844
Ebins0 = [ArchiveFile],
842
case open_archive({ArchiveFile, ArchiveBin}, Ebins0, Fun) of
843
{ok, PrimZip, RevEbins} ->
845
case open_archive({ArchiveFile, ArchiveBin}, FileInfo, Ebins0, Fun) of
846
{ok, PrimZip, {RevEbins, FI, _}} ->
844
847
Ebins = reverse(RevEbins),
845
848
debug(PS, {set_primary_archive, Ebins}),
846
put(ArchiveFile, {primary, PrimZip}),
849
put(ArchiveFile, {primary, PrimZip, FI}),
847
850
{{ok, Ebins}, PS#prim_state{primary_archive = ArchiveFile}};
849
852
debug(PS, {set_primary_archive, Error}),
852
855
OldArchiveFile ->
853
856
debug(PS, {set_primary_archive, clean}),
854
PrimZip = erase(OldArchiveFile),
857
{primary, PrimZip, _FI} = erase(OldArchiveFile),
855
858
ok = prim_zip:close(PrimZip),
856
859
PS2 = PS#prim_state{primary_archive = undefined},
857
prim_set_primary_archive(PS2, ArchiveFile, ArchiveBin)
860
prim_set_primary_archive(PS2, ArchiveFile, ArchiveBin, FileInfo)
859
862
debug(PS3, {return, Res3}),
865
-spec prim_get_file(prim_state(), file:filename()) -> {_, prim_state()}.
862
866
prim_get_file(PS, File) ->
863
867
debug(PS, {get_file, File}),
883
887
debug(PS, {return, Res2}),
886
%% -> {{ok,List},State} | {{error,Reason},State}
890
-spec prim_list_dir(prim_state(), file:filename()) ->
891
{{'ok', [file:filename()]}, prim_state()}
892
| {{'error', term()}, prim_state()}.
887
893
prim_list_dir(PS, Dir) ->
888
894
debug(PS, {list_dir, Dir}),
934
940
debug(PS, {return, Res2}),
937
%% -> {{ok,Info},State} | {{error,Reason},State}
943
-spec prim_read_file_info(prim_state(), file:filename()) ->
944
{{'ok', #file_info{}}, prim_state()}
945
| {{'error', term()}, prim_state()}.
938
946
prim_read_file_info(PS, File) ->
939
947
debug(PS, {read_file_info, File}),
990
1000
apply_archive(PS, Fun, Acc, Archive) ->
991
1001
case get(Archive) of
993
case prim_file:read_file_info(Archive) of
994
{ok, #file_info{mtime = Mtime}} ->
995
case open_archive(Archive, Acc, Fun) of
996
{ok, PrimZip, Acc2} ->
997
debug(PS, {cache, ok}),
998
put(Archive, {Mtime, {ok, PrimZip}}),
1001
debug(PS, {cache, Error}),
1002
put(Archive, {Mtime, Error}),
1006
debug(PS, {cache, Error}),
1009
{primary, PrimZip} ->
1010
case foldl_archive(PrimZip, Acc, Fun) of
1011
{ok, _PrimZip2, Acc2} ->
1014
debug(PS, {primary, Error}),
1018
case prim_file:read_file_info(Archive) of
1019
{ok, #file_info{mtime = Mtime2}} when Mtime2 =:= Mtime ->
1003
case open_archive(Archive, Acc, Fun) of
1004
{ok, PrimZip, {Acc2, FI, _}} ->
1005
debug(PS, {cache, ok}),
1006
put(Archive, {{ok, PrimZip}, FI}),
1009
debug(PS, {cache, Error}),
1010
%% put(Archive, {Error, FI}),
1013
{primary, PrimZip, FI} ->
1014
case prim_file:read_file_info(Archive) of
1016
when FI#file_info.mtime =:= FI2#file_info.mtime ->
1017
case foldl_archive(PrimZip, Acc, Fun) of
1018
{ok, _PrimZip2, Acc2} ->
1021
debug(PS, {primary, Error}),
1025
debug(PS, {cache, {clear, Error}}),
1026
clear_cache(Archive, {ok, PrimZip}),
1027
apply_archive(PS, Fun, Acc, Archive)
1030
case prim_file:read_file_info(Archive) of
1032
when FI#file_info.mtime =:= FI2#file_info.mtime ->
1021
1034
{ok, PrimZip} ->
1022
1035
case foldl_archive(PrimZip, Acc, Fun) of
1037
1051
debug(PS, {cache, {clear, Error}}),
1038
clear_cache(Archive, Cache),
1052
ok = clear_cache(Archive, Cache),
1039
1053
apply_archive(PS, Fun, Acc, Archive)
1043
1057
open_archive(Archive, Acc, Fun) ->
1058
case prim_file:read_file_info(Archive) of
1060
open_archive(Archive, FileInfo, Acc, Fun);
1065
open_archive(Archive, FileInfo, Acc, Fun) ->
1066
FakeFI = FileInfo#file_info{type = directory},
1045
fun({N, GI, GB}, A) ->
1046
%% Ensure full iteration at open
1047
Funny = funny_split(N, $/),
1048
{_Continue, A2} = Fun({Funny, GI, GB}, A),
1049
{true, {true, Funny}, A2}
1051
prim_zip:open(Wrapper, Acc, Archive).
1068
fun({N, GI, GB}, {A, I, FunnyDirs}) -> % Full iteration at open
1069
Funny = funny_split(N, $/),
1073
[FunnyDir | FunnyDirs];
1077
{Includes, FunnyDirs3, A2} =
1078
ensure_virtual_dirs(Funny, Fun, FakeFI, [{true, Funny}], FunnyDirs2, A),
1079
{_Continue, A3} = Fun({Funny, GI, GB}, A2),
1080
{true, Includes, {A3, I, FunnyDirs3}}
1082
prim_zip:open(Wrapper, {Acc, FakeFI, []}, Archive).
1084
ensure_virtual_dirs(Funny, Fun, FakeFI, Includes, FunnyDirs, Acc) ->
1087
case lists:member(FunnyDir, FunnyDirs) of % BIF
1089
GetInfo = fun() -> FakeFI end,
1090
GetBin = fun() -> <<>> end,
1091
VirtualDir = ["" | FunnyDir],
1092
Includes2 = [{true, VirtualDir, GetInfo, GetBin} | Includes],
1093
FunnyDirs2 = [FunnyDir | FunnyDirs],
1094
{I, F, Acc2} = ensure_virtual_dirs(FunnyDir, Fun, FakeFI, Includes2, FunnyDirs2, Acc),
1095
{_Continue, Acc3} = Fun({VirtualDir, GetInfo, GetBin}, Acc2),
1098
{reverse(Includes), FunnyDirs, Acc}
1101
{reverse(Includes), FunnyDirs, Acc}
1053
1104
foldl_archive(PrimZip, Acc, Fun) ->
1055
fun({N, GI, GB}, A) ->
1106
fun({Funny, GI, GB}, A) ->
1056
1107
%% Allow partial iteration at foldl
1057
{Continue, A2} = Fun({N, GI, GB}, A),
1108
{Continue, A2} = Fun({Funny, GI, GB}, A),
1058
1109
{Continue, true, A2}
1060
1111
prim_zip:foldl(Wrapper, Acc, PrimZip).