aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/beam/bif.tab1
-rw-r--r--erts/emulator/beam/erl_bif_re.c11
-rw-r--r--lib/sasl/test/systools_SUITE.erl16
-rw-r--r--lib/stdlib/doc/src/erl_tar.xml4
-rw-r--r--lib/stdlib/doc/src/re.xml10
-rw-r--r--lib/stdlib/src/erl_tar.erl59
-rw-r--r--lib/stdlib/src/re.erl7
-rw-r--r--lib/stdlib/test/re_SUITE.erl14
-rw-r--r--lib/stdlib/test/tar_SUITE.erl37
-rw-r--r--lib/tools/src/lcnt.erl39
-rw-r--r--lib/tools/test/xref_SUITE.erl8
11 files changed, 161 insertions, 45 deletions
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index 4140938210..66e5dc2988 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -393,6 +393,7 @@ bif erl_ddll:demonitor/1
#
# Bifs in the re module
#
+bif re:version/0
bif re:compile/1
bif re:compile/2
bif re:run/2
diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c
index 925d99e0de..a72697eb80 100644
--- a/erts/emulator/beam/erl_bif_re.c
+++ b/erts/emulator/beam/erl_bif_re.c
@@ -512,6 +512,17 @@ build_compile_result(Process *p, Eterm error_tag, pcre *result, int errcode, con
* Compile BIFs
*/
+BIF_RETTYPE
+re_version_0(BIF_ALIST_0)
+{
+ Eterm ret;
+ size_t version_size = 0;
+ byte *version = (byte *) erts_pcre_version();
+ version_size = strlen((const char *) version);
+ ret = new_binary(BIF_P, version, version_size);
+ BIF_RET(ret);
+}
+
static BIF_RETTYPE
re_compile(Process* p, Eterm arg1, Eterm arg2)
{
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index 0c98232467..1a8bd3f607 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -87,25 +87,25 @@ end_per_group(_GroupName, Config) ->
init_per_suite(Config) when is_list(Config) ->
+ %% To use in end_per_testcase
+ Path = code:get_path(),
+ {ok,Cwd} = file:get_cwd(),
+
%% Make of copy of the data directory.
DataDir = ?datadir,
PrivDir = ?privdir,
CopyDir = fname(PrivDir, "datacopy"),
+ ok = file:make_dir(CopyDir),
TarFile = fname(PrivDir, "datacopy.tgz"),
- {ok, Tar} = erl_tar:open(TarFile, [write, compressed]),
- ok = erl_tar:add(Tar, DataDir, CopyDir, [compressed]),
- ok = erl_tar:close(Tar),
- ok = erl_tar:extract(TarFile, [compressed]),
+ ok = file:set_cwd(DataDir),
+ ok = erl_tar:create(TarFile, ["."], [compressed]),
+ ok = erl_tar:extract(TarFile, [compressed, {cwd,CopyDir}]),
ok = file:delete(TarFile),
%% Compile source files in the copy directory.
Sources = filelib:wildcard(fname([CopyDir,'*','*','*','*','*.erl'])),
lists:foreach(fun compile_source/1, Sources),
- %% To use in end_per_testcase
- Path = code:get_path(),
- {ok,Cwd} = file:get_cwd(),
-
[{copy_dir, CopyDir}, {cwd,Cwd}, {path,Path} | Config].
compile_source(File) ->
diff --git a/lib/stdlib/doc/src/erl_tar.xml b/lib/stdlib/doc/src/erl_tar.xml
index f28d8b425b..fab7c832d5 100644
--- a/lib/stdlib/doc/src/erl_tar.xml
+++ b/lib/stdlib/doc/src/erl_tar.xml
@@ -292,6 +292,10 @@
<c>Fd</c> is assumed to be a file descriptor returned from function
<c>file:open/2</c>.</p>
<p>Otherwise, <c>Name</c> is to be a filename.</p>
+ <note><p>Leading slashes in tar member names will be removed before
+ writing the file. That is, absolute paths will be turned into
+ relative paths. There will be an info message written to the error
+ logger when paths are changed in this way.</p></note>
</desc>
</func>
diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml
index aadb5beaba..078ca0e38c 100644
--- a/lib/stdlib/doc/src/re.xml
+++ b/lib/stdlib/doc/src/re.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2007</year>
- <year>2016</year>
+ <year>2017</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -79,6 +79,14 @@
<funcs>
<func>
+ <name name="version" arity="0"/>
+ <fsummary>Gives the PCRE version of the system in a string format</fsummary>
+ <desc>
+ <p>The return of this function is a string with the PCRE version of the system that was used in the Erlang/OTP compilation.</p>
+ </desc>
+ </func>
+
+ <func>
<name name="compile" arity="1"/>
<fsummary>Compile a regular expression into a match program</fsummary>
<desc>
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index a54df939bf..168ea4002c 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -69,6 +69,8 @@ format_error(invalid_gnu_1_0_sparsemap) ->
"Invalid GNU sparse map (version 1.0)";
format_error({invalid_gnu_0_1_sparsemap, Format}) ->
lists:flatten(io_lib:format("Invalid GNU sparse map (version ~s)", [Format]));
+format_error(unsafe_path) ->
+ "The path points above the current working directory";
format_error({Name,Reason}) ->
lists:flatten(io_lib:format("~ts: ~ts", [Name,format_error(Reason)]));
format_error(Atom) when is_atom(Atom) ->
@@ -120,26 +122,38 @@ do_extract(Handle, Opts) when is_list(Opts) ->
extract1(eof, Reader, _, Acc) when is_list(Acc) ->
{ok, {ok, lists:reverse(Acc)}, Reader};
+extract1(eof, Reader, _, leading_slash) ->
+ error_logger:info_msg("erl_tar: removed leading '/' from member names\n"),
+ {ok, ok, Reader};
extract1(eof, Reader, _, Acc) ->
{ok, Acc, Reader};
-extract1(#tar_header{name=Name,size=Size}=Header, Reader, Opts, Acc) ->
+extract1(#tar_header{name=Name,size=Size}=Header, Reader0, Opts, Acc0) ->
case check_extract(Name, Opts) of
true ->
- case do_read(Reader, Size) of
- {ok, Bin, Reader2} ->
- case write_extracted_element(Header, Bin, Opts) of
- ok ->
- {ok, Acc, Reader2};
- {ok, NameBin} when is_list(Acc) ->
- {ok, [NameBin | Acc], Reader2};
- {error, _} = Err ->
- throw(Err)
- end;
+ case do_read(Reader0, Size) of
+ {ok, Bin, Reader1} ->
+ Acc = extract2(Header, Bin, Opts, Acc0),
+ {ok, Acc, Reader1};
{error, _} = Err ->
throw(Err)
end;
false ->
- {ok, Acc, skip_file(Reader)}
+ {ok, Acc0, skip_file(Reader0)}
+ end.
+
+extract2(Header, Bin, Opts, Acc) ->
+ case write_extracted_element(Header, Bin, Opts) of
+ ok ->
+ case Header of
+ #tar_header{name="/"++_} ->
+ leading_slash;
+ #tar_header{} ->
+ Acc
+ end;
+ {ok, NameBin} when is_list(Acc) ->
+ [NameBin | Acc];
+ {error, _} = Err ->
+ throw(Err)
end.
%% Checks if the file Name should be extracted.
@@ -1052,14 +1066,11 @@ unpack_modern(Format, #header_v7{}=V7, Bin, #tar_header{}=Header0)
safe_join_path([], Name) ->
- strip_slashes(Name, both);
+ filename:join([Name]);
safe_join_path(Prefix, []) ->
- strip_slashes(Prefix, right);
+ filename:join([Prefix]);
safe_join_path(Prefix, Name) ->
- filename:join(strip_slashes(Prefix, right), strip_slashes(Name, both)).
-
-strip_slashes(Str, Direction) ->
- string:strip(Str, Direction, $/).
+ filename:join(Prefix, Name).
new_sparse_file_reader(Reader, Sparsemap, RealSize) ->
true = validate_sparse_entries(Sparsemap, RealSize),
@@ -1557,7 +1568,7 @@ write_extracted_element(#tar_header{name=Name,typeflag=Type},
ok
end;
write_extracted_element(#tar_header{name=Name0}=Header, Bin, Opts) ->
- Name1 = filename:absname(Name0, Opts#read_opts.cwd),
+ Name1 = make_safe_path(Name0, Opts),
Created =
case typeflag(Header#tar_header.typeflag) of
regular ->
@@ -1585,6 +1596,16 @@ write_extracted_element(#tar_header{name=Name0}=Header, Bin, Opts) ->
not_written -> ok
end.
+make_safe_path([$/|Path], Opts) ->
+ make_safe_path(Path, Opts);
+make_safe_path(Path, #read_opts{cwd=Cwd}) ->
+ case filename:safe_relative_path(Path) of
+ unsafe ->
+ throw({error,{Path,unsafe_path}});
+ SafePath ->
+ filename:absname(SafePath, Cwd)
+ end.
+
create_regular(Name, NameInArchive, Bin, Opts) ->
case write_extracted_file(Name, Bin, Opts) of
not_written ->
diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl
index 52d3c35608..28aab7b590 100644
--- a/lib/stdlib/src/re.erl
+++ b/lib/stdlib/src/re.erl
@@ -33,7 +33,12 @@
%%% BIFs
--export([compile/1, compile/2, run/2, run/3, inspect/2]).
+-export([version/0, compile/1, compile/2, run/2, run/3, inspect/2]).
+
+-spec version() -> binary().
+
+version() ->
+ erlang:nif_error(undef).
-spec compile(Regexp) -> {ok, MP} | {error, ErrSpec} when
Regexp :: iodata(),
diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl
index a76ded5f60..71f86e32e5 100644
--- a/lib/stdlib/test/re_SUITE.erl
+++ b/lib/stdlib/test/re_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
run_options/1,combined_options/1,replace_autogen/1,
global_capture/1,replace_input_types/1,replace_return/1,
split_autogen/1,split_options/1,split_specials/1,
- error_handling/1,pcre_cve_2008_2371/1,
+ error_handling/1,pcre_cve_2008_2371/1,re_version/1,
pcre_compile_workspace_overflow/1,re_infinite_loop/1,
re_backwards_accented/1,opt_dupnames/1,opt_all_names/1,inspect/1,
opt_no_start_optimize/1,opt_never_utf/1,opt_ucp/1,
@@ -45,7 +45,7 @@ all() ->
pcre_compile_workspace_overflow, re_infinite_loop,
re_backwards_accented, opt_dupnames, opt_all_names,
inspect, opt_no_start_optimize,opt_never_utf,opt_ucp,
- match_limit, sub_binaries].
+ match_limit, sub_binaries, re_version].
groups() ->
[].
@@ -194,6 +194,14 @@ run_options(Config) when is_list(Config) ->
+%% Test the version is retorned correctly
+re_version(_Config) ->
+ Version = re:version(),
+ {match,[Version]} = re:run(Version,"^[0-9]\\.[0-9]{2} 20[0-9]{2}-[0-9]{2}-[0-9]{2}",[{capture,all,binary}]),
+ ok.
+
+
+
%% Test compile options given directly to run.
combined_options(Config) when is_list(Config) ->
ok = crtest("ABDabcdABCD","abcd",[],true,{match,[{3,4}]}),
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index 2e1ae7bcff..76fa760fa8 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -27,7 +27,7 @@
extract_from_binary_compressed/1, extract_filtered/1,
extract_from_open_file/1, symlinks/1, open_add_close/1, cooked_compressed/1,
memory/1,unicode/1,read_other_implementations/1,
- sparse/1, init/1]).
+ sparse/1, init/1, leading_slash/1, dotdot/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/file.hrl").
@@ -41,7 +41,7 @@ all() ->
extract_filtered,
symlinks, open_add_close, cooked_compressed, memory, unicode,
read_other_implementations,
- sparse,init].
+ sparse,init,leading_slash,dotdot].
groups() ->
[].
@@ -920,6 +920,39 @@ unicode_create_files() ->
[]
end].
+leading_slash(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Dir = filename:join(PrivDir, ?FUNCTION_NAME),
+ TarFile = filename:join(Dir, "leading_slash.tar"),
+ ok = filelib:ensure_dir(TarFile),
+ {ok,Fd} = erl_tar:open(TarFile, [write]),
+ TarMemberName = "e/d/c/b/a_member",
+ TarMemberNameAbs = "/" ++ TarMemberName,
+ Contents = <<"contents\n">>,
+ ok = erl_tar:add(Fd, Contents, TarMemberNameAbs, [verbose]),
+ ok = erl_tar:close(Fd),
+
+ ok = erl_tar:extract(TarFile, [{cwd,Dir}]),
+
+ {ok,Contents} = file:read_file(filename:join(Dir, TarMemberName)),
+ ok.
+
+dotdot(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Dir = filename:join(PrivDir, ?FUNCTION_NAME),
+ ok = file:make_dir(Dir),
+ Tar = filename:join(Dir, "dotdot.tar"),
+ {ok,Fd} = erl_tar:open(Tar, [write]),
+ BeamFile = code:which(?MODULE),
+ ok = erl_tar:add(Fd, BeamFile, "a/./../../some_file", []),
+ ok = erl_tar:close(Fd),
+
+ {error,{_,unsafe_path=Error}} = erl_tar:extract(Tar, [{cwd,Dir}]),
+ false = filelib:is_regular(filename:join(PrivDir, "some_file")),
+ io:format("~s\n", [erl_tar:format_error(Error)]),
+
+ ok.
+
%% Delete the given list of files.
delete_files([]) -> ok;
delete_files([Item|Rest]) ->
diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl
index 22db947e7a..864d62f6c5 100644
--- a/lib/tools/src/lcnt.erl
+++ b/lib/tools/src/lcnt.erl
@@ -698,19 +698,47 @@ stats2record([{{File,Line},{Tries,Colls,{S,Ns,N}}}|Stats]) ->
nt = N} | stats2record(Stats)];
stats2record([]) -> [].
+
clean_id_creation(Id) when is_pid(Id) ->
Bin = term_to_binary(Id),
- <<H:3/binary, L:16, Node:L/binary, Ids:8/binary, _Creation/binary>> = Bin,
- Bin2 = list_to_binary([H, bytes16(L), Node, Ids, 0]),
+ <<H:3/binary, Rest/binary>> = Bin,
+ <<131, PidTag, AtomTag>> = H,
+ LL = atomlen_bits(AtomTag),
+ CL = creation_bits(PidTag),
+ <<L:LL, Node:L/binary, Ids:8/binary, _Creation/binary>> = Rest,
+ Bin2 = list_to_binary([H, <<L:LL>>, Node, Ids, <<0:CL>>]),
binary_to_term(Bin2);
clean_id_creation(Id) when is_port(Id) ->
Bin = term_to_binary(Id),
- <<H:3/binary, L:16, Node:L/binary, Ids:4/binary, _Creation/binary>> = Bin,
- Bin2 = list_to_binary([H, bytes16(L), Node, Ids, 0]),
+ <<H:3/binary, Rest/binary>> = Bin,
+ <<131, PortTag, AtomTag>> = H,
+ LL = atomlen_bits(AtomTag),
+ CL = creation_bits(PortTag),
+ <<L:LL, Node:L/binary, Ids:4/binary, _Creation/binary>> = Rest,
+ Bin2 = list_to_binary([H, <<L:LL>>, Node, Ids, <<0:CL>>]),
binary_to_term(Bin2);
clean_id_creation(Id) ->
Id.
+-define(PID_EXT, $g).
+-define(NEW_PID_EXT, $X).
+-define(PORT_EXT, $f).
+-define(NEW_PORT_EXT, $Y).
+-define(ATOM_EXT, $d).
+-define(SMALL_ATOM_EXT, $s).
+-define(ATOM_UTF8_EXT, $v).
+-define(SMALL_ATOM_UTF8_EXT, $w).
+
+atomlen_bits(?ATOM_EXT) -> 16;
+atomlen_bits(?SMALL_ATOM_EXT) -> 8;
+atomlen_bits(?ATOM_UTF8_EXT) -> 16;
+atomlen_bits(?SMALL_ATOM_UTF8_EXT) -> 8.
+
+creation_bits(?PID_EXT) -> 8;
+creation_bits(?NEW_PID_EXT) -> 32;
+creation_bits(?PORT_EXT) -> 8;
+creation_bits(?NEW_PORT_EXT) -> 32.
+
%% serializer
state_default(Field) -> proplists:get_value(Field, state2list(#state{})).
@@ -932,9 +960,6 @@ strings([{space, N, S} | Ss], Out) -> strings(Ss, Out ++ term2string(term2
strings([{left, N, S} | Ss], Out) -> strings(Ss, Out ++ term2string(term2string(" ~~s~~~ws", [N]), [S,""]));
strings([S|Ss], Out) -> strings(Ss, Out ++ term2string("~ts", [S])).
--define(SMALL_ATOM_UTF8_EXT, $w).
--define(ATOM_UTF8_EXT, $v).
--define(ATOM_EXT, $d).
term2string({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) -> term2string("~p:~p/~p", [M,F,A]);
term2string(Term) when is_port(Term) ->
diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl
index f308ea1204..b8e7113595 100644
--- a/lib/tools/test/xref_SUITE.erl
+++ b/lib/tools/test/xref_SUITE.erl
@@ -89,11 +89,11 @@ init_per_suite(Conf) when is_list(Conf) ->
DataDir = ?datadir,
PrivDir = ?privdir,
CopyDir = fname(PrivDir, "datacopy"),
+ ok = file:make_dir(CopyDir),
TarFile = fname(PrivDir, "datacopy.tgz"),
- {ok, Tar} = erl_tar:open(TarFile, [write, compressed]),
- ok = erl_tar:add(Tar, DataDir, CopyDir, [compressed]),
- ok = erl_tar:close(Tar),
- ok = erl_tar:extract(TarFile, [compressed]),
+ ok = file:set_cwd(DataDir),
+ ok = erl_tar:create(TarFile, ["."], [compressed]),
+ ok = erl_tar:extract(TarFile, [compressed, {cwd,CopyDir}]),
ok = file:delete(TarFile),
[{copy_dir, CopyDir}|Conf].