~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

Viewing changes to erts/preloaded/src/erl_prim_loader.erl

  • Committer: Bazaar Package Importer
  • Author(s): Sergei Golovan
  • Date: 2010-03-09 17:34:57 UTC
  • mfrom: (10.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100309173457-4yd6hlcb2osfhx31
Tags: 1:13.b.4-dfsg-3
Manpages in section 1 are needed even if only arch-dependent packages are
built. So, re-enabled them.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
%%
2
2
%% %CopyrightBegin%
3
 
%% 
4
 
%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
5
 
%% 
 
3
%%
 
4
%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
 
5
%%
6
6
%% The contents of this file are subject to the Erlang Public License,
7
7
%% Version 1.1, (the "License"); you may not use this file except in
8
8
%% compliance with the License. You should have received a copy of the
9
9
%% Erlang Public License along with this software. If not, it can be
10
10
%% retrieved online at http://www.erlang.org/.
11
 
%% 
 
11
%%
12
12
%% Software distributed under the License is distributed on an "AS IS"
13
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
14
%% the License for the specific language governing rights and limitations
15
15
%% under the License.
16
 
%% 
 
16
%%
17
17
%% %CopyrightEnd%
18
18
%%
19
19
 
49
49
         prim_read_file_info/2, prim_get_cwd/2]).
50
50
 
51
51
%% Used by escript and code
52
 
-export([set_primary_archive/2, release_archives/0]).
53
 
 
54
 
%% Internal function. Exported to avoid dialyzer warnings
55
 
-export([concat/1]).
 
52
-export([set_primary_archive/3, release_archives/0]).
56
53
 
57
54
-include_lib("kernel/include/file.hrl").
58
55
 
59
56
-type host() :: atom().
60
57
 
 
58
-record(prim_state, {debug :: boolean(),
 
59
                     cache,
 
60
                     primary_archive}).
 
61
-type prim_state() :: #prim_state{}.
 
62
 
61
63
-record(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?
65
 
         data,                    % data port etc
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
70
73
 
71
74
-define(IDLE_TIMEOUT, 60000).  %% tear inet connection after 1 minutes
72
75
-define(N_TIMEOUTS, 6).        %% release efile archive after 6 minutes
89
92
                end
90
93
        end()).
91
94
 
92
 
-record(prim_state, {debug, cache, primary_archive}).
93
 
 
94
95
debug(#prim_state{debug = Deb}, Term) ->
95
96
    case Deb of
96
97
        false -> ok;
124
125
 
125
126
start_it("ose_inet"=Cmd, Id, Pid, Hosts) ->
126
127
    %% Setup reserved port for ose_inet driver (only OSE)
127
 
    case catch erlang:open_port({spawn,Cmd},[binary]) of
 
128
    case catch erlang:open_port({spawn,Cmd}, [binary]) of
128
129
        {'EXIT',Why} ->
129
130
            ?dbg(ose_inet_port_open_fail, Why),
130
131
            Why;
220
221
    check_file_result(get_cwd, Drive, request({get_cwd,[Drive]})).
221
222
 
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,_}.
225
227
 
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}).
231
233
 
232
234
-spec release_archives() -> 'ok' | {'error', _}.
233
235
 
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),
325
327
                        {ignore,State,Paths}
326
328
                end,
327
329
            if Resp =:= ignore -> ok;
328
 
               true -> Pid ! {self(),Resp}
 
330
               true -> Pid ! {self(),Resp}, ok
329
331
            end,
330
332
            if 
331
333
                is_record(State2, state) ->
334
336
                    exit({bad_state, Req, State2})          
335
337
            end;
336
338
        {'EXIT',Parent,W} ->
337
 
            handle_stop(State),
 
339
            _State1 = handle_stop(State),
338
340
            exit(W);
339
341
        {'EXIT',P,W} ->
340
342
            State1 = handle_exit(State, P, W),
356
358
handle_get_file(State = #state{loader = inet}, Paths, File) ->
357
359
    ?SAFE2(inet_get_file_from_port(State, File, Paths), State).
358
360
 
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).
361
363
 
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}.
483
485
 
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}}.
487
489
 
488
490
efile_release_archives(#state{prim_state = PS} = State) ->
572
574
    case find_loop(U, Retry, AL, ReqDelay, []) of
573
575
        [] ->                                   % no response from any server
574
576
            erlang:display({erl_prim_loader,'no server found'}), % lifesign
575
 
            Tries1 = if Tries > 0 ->
576
 
                             sleep(SReSleep),
577
 
                             Tries - 1;
578
 
                        true ->
579
 
                             sleep(LReSleep),
580
 
                             0
581
 
                     end,
 
577
            Tries1 =
 
578
                if Tries > 0 ->
 
579
                        sleep(SReSleep),
 
580
                        Tries - 1;
 
581
                   true ->
 
582
                        sleep(LReSleep),
 
583
                        0
 
584
                end,
582
585
            find_loop(U, Retry, AL, ReqDelay, SReSleep, Ignore, Tries1, LReSleep);
583
586
        Servers ->
584
587
            keysort(1, Servers -- Ignore)
603
606
        _Garbage ->
604
607
            ?dbg(collect_garbage, _Garbage),
605
608
            find_collect(U, Retry, AL, Delay, Acc)
606
 
            
607
609
    after Delay ->
608
610
            ?dbg(collected, Acc),
609
611
            case keymember(0, 1, Acc) of  %% got high priority server?
617
619
    receive after Time -> ok end.
618
620
 
619
621
inet_exit_port(State, Port, _Reason) when State#state.data =:= Port ->
620
 
    State#state { data = noport, timeout = infinity };
 
622
    State#state{data = noport, timeout = infinity};
621
623
inet_exit_port(State, _, _) ->
622
624
    State.
623
625
 
627
629
    if is_port(Tcp) -> ll_close(Tcp);
628
630
       true -> ok
629
631
    end,
630
 
    State#state { timeout = infinity, data = noport }.
 
632
    State#state{timeout = infinity, data = noport}.
631
633
 
632
634
%% -> {{ok,BinFile,Tag},State} | {{error,Reason},State}
633
635
inet_get_file_from_port(State, File, Paths) ->
657
659
 
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)),
664
666
    receive
665
667
        {tcp,Tcp,BinMsg} ->
677
679
            end;
678
680
        {tcp_closed,Tcp} ->
679
681
            %% Ok we must reconnect
680
 
            inet_send_and_rcv(Msg, Tag, State#state { data = noport });
 
682
            inet_send_and_rcv(Msg, Tag, State#state{data = noport});
681
683
        {tcp_error,Tcp,_Reason} ->
682
684
            %% Ok we must reconnect
683
685
            inet_send_and_rcv(Msg, Tag, inet_stop_port(State));
684
686
        {'EXIT', Tcp, _} -> 
685
687
            %% Ok we must reconnect
686
 
            inet_send_and_rcv(Msg, Tag, State#state { data = noport })
 
688
            inet_send_and_rcv(Msg, Tag, State#state{data = noport})
687
689
    after Timeout ->
688
690
            %% Ok we must reconnect
689
691
            inet_send_and_rcv(Msg, Tag, inet_stop_port(State))
770
772
    
771
773
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
772
774
 
 
775
-spec prim_init() -> prim_state().
773
776
prim_init() ->
774
777
    Deb =
775
778
        case init:get_argument(loader_debug) of
777
780
            error -> false
778
781
        end,
779
782
    cache_new(#prim_state{debug = Deb}).
780
 
    
 
783
 
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}),
785
788
    {Res, PS2}.
786
789
 
787
790
prim_do_release_archives(PS, [{ArchiveFile, DictVal} | KeyVals], Acc) ->
788
791
    Res = 
789
792
        case DictVal of
790
 
            {primary, _PrimZip} ->
 
793
            {primary, _PrimZip, _FI} ->
791
794
                ok; % Keep primary archive
792
 
            {_Mtime, Cache} ->
 
795
            {Cache, _FI} ->
793
796
                debug(PS, {release, cache, ArchiveFile}),
794
797
                erase(ArchiveFile),
795
798
                clear_cache(ArchiveFile, Cache)
805
808
prim_do_release_archives(PS, [], Errors) ->
806
809
    {{error, Errors}, PS#prim_state{primary_archive = undefined}}.
807
810
 
808
 
prim_set_primary_archive(PS, undefined, undefined) ->
 
811
prim_set_primary_archive(PS, undefined, undefined, undefined) ->
809
812
    debug(PS, {set_primary_archive, clean}),
810
813
    case PS#prim_state.primary_archive of
811
814
        undefined ->
813
816
            debug(PS, {return, Res}),
814
817
            {Res, PS};
815
818
        ArchiveFile ->
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},
819
822
            Res = {ok, []},
820
823
            debug(PS2, {return, Res}),
821
824
            {Res, PS2}
822
825
    end;
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",
836
 
                                    {true, [Ebin | A]};
 
839
                                    {true, [Ebin | A]};
837
840
                                _ ->
838
841
                                    {true, A}
839
842
                            end
840
843
                    end,
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}};
848
851
                    Error ->
849
852
                        debug(PS, {set_primary_archive, Error}),
851
854
                end;
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)
858
861
        end,
859
862
    debug(PS3, {return, Res3}),
860
863
    {Res3, PS3}.
861
864
 
 
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}),
864
868
    {Res2, PS2} =
883
887
    debug(PS, {return, Res2}),
884
888
    {Res2, PS2}.    
885
889
 
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}),
889
895
    {Res2, PS3} =
934
940
    debug(PS, {return, Res2}),
935
941
    {Res2, PS3}.
936
942
 
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}),
940
948
    {Res2, PS2} =
956
964
                FunnyFile = funny_split(FileInArchive, $/),
957
965
                Fun =
958
966
                    fun({Funny, GetInfo, _GetBin}, Acc)  ->
959
 
                            if
960
 
                                hd(Funny) =:= "",
961
 
                                tl(Funny) =:= FunnyFile ->
 
967
                            case Funny of
 
968
                                [H | T] when  H =:= "",
 
969
                                              T =:= FunnyFile ->
962
970
                                    %% Directory
963
971
                                    {false, {ok, GetInfo()}};
964
 
                                Funny =:= FunnyFile ->
 
972
                                F when F =:= FunnyFile ->
965
973
                                    %% Plain file
966
974
                                    {false, {ok, GetInfo()}};
967
 
                                true ->
 
975
                                _ ->
968
976
                                    %% No match
969
977
                                    {true, Acc}
970
978
                            end
974
982
    debug(PS2, {return, Res2}),
975
983
    {Res2, PS2}.
976
984
 
 
985
-spec prim_get_cwd(prim_state(), [file:filename()]) ->
 
986
        {{'error', term()} | {'ok', _}, prim_state()}.
977
987
prim_get_cwd(PS, []) ->
978
988
    debug(PS, {get_cwd, []}),
979
989
    Res = prim_file:get_cwd(),
990
1000
apply_archive(PS, Fun, Acc, Archive) ->
991
1001
    case get(Archive) of
992
1002
        undefined ->
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}}),
999
 
                            {Acc2, PS};
1000
 
                        Error ->
1001
 
                            debug(PS, {cache, Error}),
1002
 
                            put(Archive, {Mtime, Error}),
1003
 
                            {Error, PS}
1004
 
                    end;
1005
 
                Error ->
1006
 
                    debug(PS, {cache, Error}),
1007
 
                    {Error, PS}
1008
 
            end;
1009
 
        {primary, PrimZip} ->
1010
 
            case foldl_archive(PrimZip, Acc, Fun) of
1011
 
                {ok, _PrimZip2, Acc2} ->
1012
 
                    {Acc2, PS};
1013
 
                Error ->
1014
 
                    debug(PS, {primary, Error}),
1015
 
                    {Error, PS}
1016
 
            end;
1017
 
        {Mtime, Cache} ->
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}),
 
1007
                    {Acc2, PS};
 
1008
                Error ->
 
1009
                    debug(PS, {cache, Error}),
 
1010
                    %% put(Archive, {Error, FI}),
 
1011
                    {Error, PS}
 
1012
            end;
 
1013
        {primary, PrimZip, FI} ->
 
1014
            case prim_file:read_file_info(Archive) of
 
1015
                {ok, FI2} 
 
1016
                  when FI#file_info.mtime =:= FI2#file_info.mtime ->
 
1017
                    case foldl_archive(PrimZip, Acc, Fun) of
 
1018
                        {ok, _PrimZip2, Acc2} ->
 
1019
                            {Acc2, PS};
 
1020
                        Error ->
 
1021
                            debug(PS, {primary, Error}),
 
1022
                            {Error, PS}
 
1023
                    end;
 
1024
                Error ->
 
1025
                    debug(PS, {cache, {clear, Error}}),
 
1026
                    clear_cache(Archive, {ok, PrimZip}),
 
1027
                    apply_archive(PS, Fun, Acc, Archive)
 
1028
            end;
 
1029
        {Cache, FI} ->
 
1030
            case prim_file:read_file_info(Archive) of
 
1031
                {ok, FI2} 
 
1032
                  when FI#file_info.mtime =:= FI2#file_info.mtime ->
1020
1033
                    case Cache of
1021
1034
                        {ok, PrimZip} ->
1022
1035
                            case foldl_archive(PrimZip, Acc, Fun) of
1024
1037
                                    {Acc2, PS};
1025
1038
                                Error ->
1026
1039
                                    debug(PS, {cache, {clear, Error}}),
1027
 
                                    clear_cache(Archive, Cache),
 
1040
                                    ok = clear_cache(Archive, Cache),
1028
1041
                                    debug(PS, {cache, Error}),
1029
 
                                    put(Archive, {Mtime, Error}),
 
1042
                                    erase(Archive),
 
1043
                                    %% put(Archive, {Error, FI}),
1030
1044
                                    {Error, PS}
1031
1045
                            end;
1032
1046
                        Error ->
1035
1049
                    end;
1036
1050
                Error ->
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)
1040
1054
            end
1041
1055
    end.
1042
1056
 
1043
1057
open_archive(Archive, Acc, Fun) ->
 
1058
    case prim_file:read_file_info(Archive) of
 
1059
        {ok, FileInfo} ->
 
1060
            open_archive(Archive, FileInfo, Acc, Fun);
 
1061
        {error, Reason} ->
 
1062
            {error, Reason}
 
1063
    end.
 
1064
 
 
1065
open_archive(Archive, FileInfo, Acc, Fun) ->
 
1066
    FakeFI = FileInfo#file_info{type = directory},
1044
1067
    Wrapper =
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}
1050
 
        end,
1051
 
    prim_zip:open(Wrapper, Acc, Archive).
 
1068
        fun({N, GI, GB}, {A, I, FunnyDirs}) -> % Full iteration at open
 
1069
                Funny = funny_split(N, $/),
 
1070
                FunnyDirs2 =
 
1071
                    case Funny of
 
1072
                        ["" | FunnyDir] ->
 
1073
                            [FunnyDir | FunnyDirs];
 
1074
                        _ ->
 
1075
                            FunnyDirs
 
1076
                    end,
 
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}}
 
1081
        end,
 
1082
    prim_zip:open(Wrapper, {Acc, FakeFI, []}, Archive).
 
1083
 
 
1084
ensure_virtual_dirs(Funny, Fun, FakeFI, Includes, FunnyDirs, Acc) ->
 
1085
    case Funny of
 
1086
        [_ | FunnyDir] ->
 
1087
            case lists:member(FunnyDir, FunnyDirs) of % BIF
 
1088
                false ->
 
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),
 
1096
                    {I, F, Acc3};
 
1097
                true ->
 
1098
                    {reverse(Includes), FunnyDirs, Acc}
 
1099
            end;
 
1100
        [] ->
 
1101
            {reverse(Includes), FunnyDirs, Acc}
 
1102
    end.
1052
1103
 
1053
1104
foldl_archive(PrimZip, Acc, Fun) ->
1054
1105
    Wrapper =
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}
1059
1110
        end,                        
1060
1111
    prim_zip:foldl(Wrapper, Acc, PrimZip).
1100
1151
    send_all(U, AL, Cmd);
1101
1152
send_all(_U, [], _) -> ok.
1102
1153
 
1103
 
concat([A|T]) when is_atom(A) ->                        %Atom
1104
 
    atom_to_list(A) ++ concat(T);
 
1154
%%concat([A|T]) when is_atom(A) ->              %Atom
 
1155
%%    atom_to_list(A) ++ concat(T);
1105
1156
concat([C|T]) when C >= 0, C =< 255 ->
1106
1157
    [C|concat(T)];
1107
1158
concat([S|T]) ->                                %String