From e029c2d8920b356adfb71786c838f43f6b44f99a Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Mon, 9 Jul 2012 15:30:48 +0200 Subject: Fix erl_prim_loader errors in handling of primary archive The following errors have been corrected: * If primary archive was named "xxx", then a file in the same directory named "xxxyyy" would be interpreted as a file named yyy inside the archive. * erl_prim_loader did not correctly create and normalize absolute paths for primary archive and files inside it, so unless given with exact same path files inside the archive would not be found. E.g. if escript was started as /full/path/to/xxx then "./xxx/file" would not be found since erl_prim_loader would try to match /full/path/to/xxx with /full/path/to/./xxx. Same problem with ../. * Depending on how the primary archive was built, erl_prim_loader:list_dir/1 would sometimes return an empty string inside the file list. This was a virtual element representing the top directory of the archive. This has been removed. Thanks to Tuncer Ayaz and Shunichi Shinohara for reporting and co-authoring corrections. --- erts/preloaded/src/erl_prim_loader.erl | 109 ++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 51 deletions(-) (limited to 'erts') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 14a7a2bf20..f820d6226d 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -824,10 +824,11 @@ prim_set_primary_archive(PS, undefined, undefined, undefined) -> debug(PS2, {return, Res}), {Res, PS2} end; -prim_set_primary_archive(PS, ArchiveFile, ArchiveBin, #file_info{} = FileInfo) - when is_list(ArchiveFile), is_binary(ArchiveBin) -> +prim_set_primary_archive(PS, ArchiveFile0, ArchiveBin, #file_info{} = FileInfo) + when is_list(ArchiveFile0), is_binary(ArchiveBin) -> %% Try the archive file - debug(PS, {set_primary_archive, ArchiveFile, byte_size(ArchiveBin)}), + debug(PS, {set_primary_archive, ArchiveFile0, byte_size(ArchiveBin)}), + ArchiveFile = absname(ArchiveFile0), {Res3, PS3} = case PS#prim_state.primary_archive of undefined -> @@ -1084,6 +1085,8 @@ open_archive(Archive, FileInfo, Acc, Fun) -> ensure_virtual_dirs(Funny, Fun, FakeFI, Includes, FunnyDirs, Acc) -> case Funny of + [_] -> + {Includes, FunnyDirs, Acc}; [_ | FunnyDir] -> case lists:member(FunnyDir, FunnyDirs) of % BIF false -> @@ -1096,11 +1099,9 @@ ensure_virtual_dirs(Funny, Fun, FakeFI, Includes, FunnyDirs, Acc) -> {_Continue, Acc3} = Fun({VirtualDir, GetInfo, GetBin}, Acc2), {I, F, Acc3}; true -> - {reverse(Includes), FunnyDirs, Acc} - end; - [] -> - {reverse(Includes), FunnyDirs, Acc} - end. + ensure_virtual_dirs(FunnyDir,Fun,FakeFI,Includes,FunnyDirs,Acc) + end + end. foldl_archive(PrimZip, Acc, Fun) -> Wrapper = @@ -1235,26 +1236,22 @@ do_name_split(undefined, File) -> %% False match. Assume plain file {file, File} end; -do_name_split(ArchiveFile0, File) -> +do_name_split(ArchiveFile, File) -> %% Look first in primary archive - ArchiveFile = absname(ArchiveFile0), case string_match(File, ArchiveFile, []) of no_match -> %% Archive or plain file do_name_split(undefined, File); {match, _RevPrimArchiveFile, FileInArchive} -> %% Primary archive - case FileInArchive of - [$/ | FileInArchive2] -> - {archive, ArchiveFile, FileInArchive2}; - _ -> - {archive, ArchiveFile, FileInArchive} - end + {archive, ArchiveFile, FileInArchive} end. string_match([Char | File], [Char | Archive], RevTop) -> string_match(File, Archive, [Char | RevTop]); -string_match(File, [], RevTop) -> +string_match([] = File, [], RevTop) -> + {match, RevTop, File}; +string_match([$/ | File], [], RevTop) -> {match, RevTop, File}; string_match(_File, _Archive, _RevTop) -> no_match. @@ -1307,24 +1304,26 @@ ipv4_addr([], D, [C,B,A]) when D < 256 -> {A,B,C,D}. %% A simplified version of filename:absname/1 absname(Name) -> Name2 = normalize(Name, []), - case pathtype(Name2) of - absolute -> - Name2; - relative -> - case prim_file:get_cwd() of - {ok, Cwd} -> - Cwd ++ "/" ++ Name2; - {error, _} -> - Name2 - end; - volumerelative -> - case prim_file:get_cwd() of - {ok, Cwd} -> - absname_vr(Name2, Cwd); - {error, _} -> - Name2 - end - end. + Name3 = + case pathtype(Name2) of + absolute -> + Name2; + relative -> + case prim_file:get_cwd() of + {ok, Cwd} -> + Cwd ++ "/" ++ Name2; + {error, _} -> + Name2 + end; + volumerelative -> + case prim_file:get_cwd() of + {ok, Cwd} -> + absname_vr(Name2, Cwd); + {error, _} -> + Name2 + end + end, + path_flatten(Name3). %% Assumes normalized name absname_vr([$/ | NameRest], [Drive, $\: | _]) -> @@ -1380,22 +1379,12 @@ win32_pathtype(Name) -> win32_pathtype([Char | List++Rest]); [$/, $/|_] -> absolute; - [$\\, $/|_] -> - absolute; - [$/, $\\|_] -> - absolute; - [$\\, $\\|_] -> - absolute; [$/|_] -> volumerelative; - [$\\|_] -> - volumerelative; [C1, C2, List | Rest] when is_list(List) -> - pathtype([C1, C2|List ++ Rest]); + win32_pathtype([C1, C2|List ++ Rest]); [_Letter, $:, $/|_] -> absolute; - [_Letter, $:, $\\|_] -> - absolute; [_Letter, $:|_] -> volumerelative; _ -> @@ -1408,8 +1397,6 @@ vxworks_first(Name) -> {not_device, [], []}; [$/ | T] -> vxworks_first2(device, T, [$/]); - [$\\ | T] -> - vxworks_first2(device, T, [$/]); [H | T] when is_list(H) -> vxworks_first(H ++ T); [H | T] -> @@ -1422,8 +1409,6 @@ vxworks_first2(Devicep, Name, FirstComp) -> {Devicep, [], FirstComp}; [$/ |T ] -> {Devicep, [$/ | T], FirstComp}; - [$\\ | T] -> - {Devicep, [$/ | T], FirstComp}; [$: | T]-> {device, T, [$: | FirstComp]}; [H | T] when is_list(H) -> @@ -1445,3 +1430,25 @@ normalize(Name, Acc) -> [] -> reverse(Acc) end. + +%% Remove .. and . from the path, e.g. +%% /path/./to/this/../file -> /path/to/file +path_flatten(Name) -> + path_flatten(Name,[],[]). + +path_flatten([$/,$.,$.,$/|Rest],_RevLast,RevTop) -> + path_flatten(Rest,[],RevTop); +path_flatten([$/,$.,$/|Rest],RevLast,RevTop) -> + path_flatten([$/|Rest],RevLast,RevTop); +path_flatten([$/,$.,$.],_RevLast,RevTop) -> + path_flatten([],[],RevTop); +path_flatten([$/,$.],RevLast,RevTop) -> + path_flatten([],RevLast,RevTop); +path_flatten([$/],RevLast,RevTop) -> + path_flatten([],RevLast,RevTop); +path_flatten([$/|Rest],RevLast,RevTop) -> + path_flatten(Rest,[],[$/|RevLast++RevTop]); +path_flatten([Ch|Rest],RevLast,RevTop) -> + path_flatten(Rest,[Ch|RevLast],RevTop); +path_flatten([],RevLast,RevTop) -> + reverse(RevLast++RevTop). -- cgit v1.2.3 From 13d135515cabfe4e741a4350cfe294e041c06158 Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Mon, 9 Jul 2012 16:21:57 +0200 Subject: Add comments to make erl_prim_loader primary archive handling more readable This commit introduces no functional change. It only adds comments and changes some function/variable names. --- erts/preloaded/src/erl_prim_loader.erl | 126 +++++++++++++++++++-------------- 1 file changed, 74 insertions(+), 52 deletions(-) (limited to 'erts') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index f820d6226d..eb59cbe6f6 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -833,8 +833,8 @@ prim_set_primary_archive(PS, ArchiveFile0, ArchiveBin, #file_info{} = FileInfo) case PS#prim_state.primary_archive of undefined -> Fun = - fun({Funny, _GI, _GB}, A) -> - case Funny of + fun({Components, _GI, _GB}, A) -> + case Components of ["", "nibe", RevApp] -> % Reverse ebin %% Collect ebin directories in archive Ebin = reverse(RevApp) ++ "/ebin", @@ -874,11 +874,11 @@ prim_get_file(PS, File) -> {Res, PS}; {archive, ArchiveFile, FileInArchive} -> debug(PS, {archive_get_file, ArchiveFile, FileInArchive}), - FunnyFile = funny_split(FileInArchive, $/), + FileComponents = path_split(FileInArchive), Fun = - fun({Funny, _GetInfo, GetBin}, Acc) -> + fun({Components, _GetInfo, GetBin}, Acc) -> if - Funny =:= FunnyFile -> + Components =:= FileComponents -> {false, {ok, GetBin()}}; true -> {true, Acc} @@ -901,11 +901,11 @@ prim_list_dir(PS, Dir) -> {Res, PS}; {archive, ArchiveFile, FileInArchive} -> debug(PS, {archive_list_dir, ArchiveFile, FileInArchive}), - FunnyDir = funny_split(FileInArchive, $/), + DirComponents = path_split(FileInArchive), Fun = - fun({Funny, _GetInfo, _GetBin}, {Status, Names} = Acc) -> - case Funny of - [RevName | FD] when FD =:= FunnyDir -> + fun({Components, _GetInfo, _GetBin}, {Status, Names} = Acc) -> + case Components of + [RevName | DC] when DC =:= DirComponents -> case RevName of "" -> %% The listed directory @@ -915,16 +915,16 @@ prim_list_dir(PS, Dir) -> Name = reverse(RevName), {true, {Status, [Name | Names]}} end; - ["", RevName | FD] when FD =:= FunnyDir -> + ["", RevName | DC] when DC =:= DirComponents -> %% Directory Name = reverse(RevName), {true, {Status, [Name | Names]}}; - [RevName] when FunnyDir =:= [""] -> - %% Top file + [RevName] when DirComponents =:= [""] -> + %% File in top directory Name = reverse(RevName), {true, {ok, [Name | Names]}}; - ["", RevName] when FunnyDir =:= [""] -> - %% Top file + ["", RevName] when DirComponents =:= [""] -> + %% Directory in top directory Name = reverse(RevName), {true, {ok, [Name | Names]}}; _ -> @@ -963,15 +963,14 @@ prim_read_file_info(PS, File) -> end; {archive, ArchiveFile, FileInArchive} -> debug(PS, {archive_read_file_info, File}), - FunnyFile = funny_split(FileInArchive, $/), + FileComponents = path_split(FileInArchive), Fun = - fun({Funny, GetInfo, _GetBin}, Acc) -> - case Funny of - [H | T] when H =:= "", - T =:= FunnyFile -> + fun({Components, GetInfo, _GetBin}, Acc) -> + case Components of + ["" | F] when F =:= FileComponents -> %% Directory {false, {ok, GetInfo()}}; - F when F =:= FunnyFile -> + F when F =:= FileComponents -> %% Plain file {false, {ok, GetInfo()}}; _ -> @@ -1064,50 +1063,69 @@ open_archive(Archive, Acc, Fun) -> {error, Reason} end. +%% Open the given archive and iterate through all files with an own +%% wrapper fun in order to identify each file as a component list as +%% returned from path_split/1. +%% +%% In the archive (zip) file, directory elements might or might not be +%% present. To ensure consistency, a directory element is added if it +%% does not already exist (ensure_virual_dir/6). NOTE that there will +%% be no such directory element for the top directory of the archive. open_archive(Archive, FileInfo, Acc, Fun) -> FakeFI = FileInfo#file_info{type = directory}, Wrapper = - fun({N, GI, GB}, {A, I, FunnyDirs}) -> % Full iteration at open - Funny = funny_split(N, $/), - FunnyDirs2 = - case Funny of - ["" | FunnyDir] -> - [FunnyDir | FunnyDirs]; + fun({N, GI, GB}, {A, I, Dirs}) -> + Components = path_split(N), + Dirs2 = + case Components of + ["" | Dir] -> + %% This is a directory + [Dir | Dirs]; _ -> - FunnyDirs + %% This is a regular file + Dirs end, - {Includes, FunnyDirs3, A2} = - ensure_virtual_dirs(Funny, Fun, FakeFI, [{true, Funny}], FunnyDirs2, A), - {_Continue, A3} = Fun({Funny, GI, GB}, A2), - {true, Includes, {A3, I, FunnyDirs3}} + {Includes, Dirs3, A2} = + ensure_virtual_dirs(Components, Fun, FakeFI, + [{true, Components}], Dirs2, A), + {_Continue, A3} = Fun({Components, GI, GB}, A2), + {true, Includes, {A3, I, Dirs3}} end, prim_zip:open(Wrapper, {Acc, FakeFI, []}, Archive). -ensure_virtual_dirs(Funny, Fun, FakeFI, Includes, FunnyDirs, Acc) -> - case Funny of +ensure_virtual_dirs(Components, Fun, FakeFI, Includes, Dirs, Acc) -> + case Components of [_] -> - {Includes, FunnyDirs, Acc}; - [_ | FunnyDir] -> - case lists:member(FunnyDir, FunnyDirs) of % BIF + %% Don't add virtual dir for top directory + {Includes, Dirs, Acc}; + [_ | Dir] -> + case lists:member(Dir, Dirs) of % BIF false -> + %% The directory does not yet exist - add it GetInfo = fun() -> FakeFI end, GetBin = fun() -> <<>> end, - VirtualDir = ["" | FunnyDir], + VirtualDir = ["" | Dir], Includes2 = [{true, VirtualDir, GetInfo, GetBin} | Includes], - FunnyDirs2 = [FunnyDir | FunnyDirs], - {I, F, Acc2} = ensure_virtual_dirs(FunnyDir, Fun, FakeFI, Includes2, FunnyDirs2, Acc), + Dirs2 = [Dir | Dirs], + + %% Recursively ensure dir elements on all levels + {I, F, Acc2} = ensure_virtual_dirs(Dir, Fun, FakeFI, + Includes2, Dirs2, Acc), + {_Continue, Acc3} = Fun({VirtualDir, GetInfo, GetBin}, Acc2), {I, F, Acc3}; true -> - ensure_virtual_dirs(FunnyDir,Fun,FakeFI,Includes,FunnyDirs,Acc) + %% The directory element does already exist + %% Recursivly ensure dir elements on all levels + ensure_virtual_dirs(Dir,Fun,FakeFI,Includes,Dirs,Acc) end - end. + end. foldl_archive(PrimZip, Acc, Fun) -> Wrapper = - fun({Funny, GI, GB}, A) -> + fun({Components, GI, GB}, A) -> %% Allow partial iteration at foldl - {Continue, A2} = Fun({Funny, GI, GB}, A), + {Continue, A2} = Fun({Components, GI, GB}, A), {Continue, true, A2} end, prim_zip:foldl(Wrapper, Acc, PrimZip). @@ -1203,15 +1221,19 @@ reverse([A, B]) -> reverse([A, B | L]) -> lists:reverse(L, [B, A]). % BIF -%% Returns all lists in reverse order -funny_split(List, Sep) -> - funny_split(List, Sep, [], []). - -funny_split([Sep | Tail], Sep, Path, Paths) -> - funny_split(Tail, Sep, [], [Path | Paths]); -funny_split([Head | Tail], Sep, Path, Paths) -> - funny_split(Tail, Sep, [Head | Path], Paths); -funny_split([], _Sep, Path, Paths) -> +%% Returns a reversed list of path components, each component itself a +%% reversed list (string), e.g. +%% /path/to/file -> ["elif","ot","htap",""] +%% /path/to/dir/ -> ["","rid","ot","htap",""] +%% Note the "" marking leading and trailing / (slash). +path_split(List) -> + path_split(List, [], []). + +path_split([$/ | Tail], Path, Paths) -> + path_split(Tail, [], [Path | Paths]); +path_split([Head | Tail], Path, Paths) -> + path_split(Tail, [Head | Path], Paths); +path_split([], Path, Paths) -> [Path | Paths]. name_split(ArchiveFile, File0) -> -- cgit v1.2.3 From 4a79bc79e0ff4b39fc28b0f9ac154e8070534e21 Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Mon, 9 Jul 2012 18:19:18 +0200 Subject: Update preloaded erl_prim_loader.beam --- erts/preloaded/ebin/erl_prim_loader.beam | Bin 52904 -> 53320 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'erts') diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam index df1831f340..8c6cc1100d 100644 Binary files a/erts/preloaded/ebin/erl_prim_loader.beam and b/erts/preloaded/ebin/erl_prim_loader.beam differ -- cgit v1.2.3 From 23307be619f0768d84464d13d94c8180d806ec49 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Mon, 9 Jul 2012 12:38:00 +0200 Subject: erts: add space before '*' in some function prototypes --- erts/doc/src/erl_driver.xml | 10 +++++----- erts/doc/src/erl_nif.xml | 26 +++++++++++++------------- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'erts') diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index 4fd74b783e..187c263b60 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -4,7 +4,7 @@
- 20012011 + 20012012 Ericsson AB. All Rights Reserved. @@ -1067,7 +1067,7 @@ typedef struct ErlIOVec { - ErlDrvBinary*driver_alloc_binary(ErlDrvSizeT size) + ErlDrvBinary *driver_alloc_binary(ErlDrvSizeT size) Allocate a driver binary @@ -1087,7 +1087,7 @@ typedef struct ErlIOVec { - ErlDrvBinary*driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size) + ErlDrvBinary *driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size) Resize a driver binary @@ -1277,7 +1277,7 @@ typedef struct ErlIOVec { - SysIOVec*driver_peekq(ErlDrvPort port, int *vlen) + SysIOVec *driver_peekq(ErlDrvPort port, int *vlen) Get the driver queue as a vector @@ -1481,7 +1481,7 @@ typedef struct ErlIOVec { - char*erl_errno_id(int error) + char *erl_errno_id(int error) Get erlang error atom name from error number diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 5fc6508aad..f484e9eaf7 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -4,7 +4,7 @@
- 20012011 + 20012012 Ericsson AB. All Rights Reserved. @@ -472,7 +472,7 @@ typedef enum { - void*enif_alloc(size_t size) + void *enif_alloc(size_t size) Allocate dynamic memory.

Allocate memory of size bytes. Return NULL if allocation failed.

@@ -489,7 +489,7 @@ typedef enum {

Return true on success or false if allocation failed.

- ErlNifEnv*enif_alloc_env() + ErlNifEnv *enif_alloc_env() Create a new environment

Allocate a new process independent environment. The environment can be used to hold terms that is not bound to any process. Such terms can @@ -499,7 +499,7 @@ typedef enum {

Return pointer to the new environment.

- void*enif_alloc_resource(ErlNifResourceType* type, unsigned size) + void *enif_alloc_resource(ErlNifResourceType* type, unsigned size) Allocate a memory managed resource object

Allocate a memory managed resource object of type type and size size bytes.

@@ -522,7 +522,7 @@ typedef enum {

Same as erl_drv_cond_broadcast.

- ErlNifCond*enif_cond_create(char *name) + ErlNifCond *enif_cond_create(char *name)

Same as erl_drv_cond_create.

@@ -840,7 +840,7 @@ typedef enum { Create an integer term from a long int

Create an integer term from a long int.

- unsigned char*enif_make_new_binary(ErlNifEnv* env, size_t size, ERL_NIF_TERM* termp) + unsigned char *enif_make_new_binary(ErlNifEnv* env, size_t size, ERL_NIF_TERM* termp) Allocate and create a new binary term

Allocate a binary of size size bytes and create an owning term. The binary data is mutable until the calling NIF returns. This is a @@ -951,7 +951,7 @@ typedef enum { Create an integer term from an unsigned long int

Create an integer term from an unsigned long int.

- ErlNifMutex*enif_mutex_create(char *name) + ErlNifMutex *enif_mutex_create(char *name)

Same as erl_drv_mutex_create.

@@ -976,7 +976,7 @@ typedef enum {

Same as erl_drv_mutex_unlock.

- ErlNifResourceType*enif_open_resource_type(ErlNifEnv* env, + ErlNifResourceType *enif_open_resource_type(ErlNifEnv* env, const char* module_str, const char* name, ErlNifResourceDtor* dtor, ErlNifResourceFlags flags, ErlNifResourceFlags* tried) Create or takeover a resource type @@ -1005,7 +1005,7 @@ typedef enum { and upgrade.

- void*enif_priv_data(ErlNifEnv* env) + void *enif_priv_data(ErlNifEnv* env) Get the private data of a NIF library

Return the pointer to the private data that was set by load, reload or upgrade.

@@ -1033,7 +1033,7 @@ typedef enum { References made by enif_make_resource can only be removed by the garbage collector.

- ErlNifRWLock*enif_rwlock_create(char *name) + ErlNifRWLock *enif_rwlock_create(char *name)

Same as erl_drv_rwlock_create.

@@ -1073,7 +1073,7 @@ typedef enum {

Same as erl_drv_rwlock_tryrwlock.

- ErlNifPid*enif_self(ErlNifEnv* caller_env, ErlNifPid* pid) + ErlNifPid *enif_self(ErlNifEnv* caller_env, ErlNifPid* pid) Get the pid of the calling process.

Initialize the pid variable *pid to represent the calling process. Return pid.

@@ -1129,7 +1129,7 @@ typedef enum {

Same as erl_drv_thread_join .

- ErlNifThreadOpts*enif_thread_opts_create(char *name) + ErlNifThreadOpts *enif_thread_opts_create(char *name)

Same as erl_drv_thread_opts_create.

@@ -1154,7 +1154,7 @@ typedef enum {

Same as erl_drv_tsd_key_destroy.

- void*enif_tsd_get(ErlNifTSDKey key) + void *enif_tsd_get(ErlNifTSDKey key)

Same as erl_drv_tsd_get.

-- cgit v1.2.3