diff options
Diffstat (limited to 'lib/stdlib/src/erl_tar.erl')
-rw-r--r-- | lib/stdlib/src/erl_tar.erl | 76 |
1 files changed, 48 insertions, 28 deletions
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl index c689be30d8..da188c1bf1 100644 --- a/lib/stdlib/src/erl_tar.erl +++ b/lib/stdlib/src/erl_tar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2020. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -324,10 +324,17 @@ do_open(Name, Mode) when is_list(Mode) -> open1({binary,Bin0}=Handle, read, _Raw, Opts) when is_binary(Bin0) -> Bin = case lists:member(compressed, Opts) of true -> + %% emulate file:open with Modes = [compressed_one ...] + Z = zlib:open(), + zlib:inflateInit(Z, 31, cut), try - zlib:gunzip(Bin0) + IoList = zlib:inflate(Z, Bin0), + zlib:inflateEnd(Z), + iolist_to_binary(IoList) catch _:_ -> Bin0 + after + zlib:close(Z) end; false -> Bin0 @@ -354,7 +361,13 @@ open1({file, Fd}=Handle, read, [raw], Opts) -> end; open1({file, _Fd}=Handle, read, [], _Opts) -> {error, {Handle, {incompatible_option, cooked}}}; -open1(Name, Access, Raw, Opts) when is_list(Name) or is_binary(Name) -> +open1(Name, Access, Raw, Opts0) when is_list(Name); is_binary(Name) -> + Opts = case lists:member(compressed, Opts0) andalso Access == read of + true -> + [compressed_one | (Opts0 -- [compressed])]; + false -> + Opts0 + end, case file:open(Name, Raw ++ [binary, Access|Opts]) of {ok, File} -> {ok, #reader{handle=File,access=Access,func=fun file_op/2}}; @@ -1019,11 +1032,14 @@ do_get_format({error, _} = Err, _Bin) -> do_get_format(#header_v7{}=V7, Bin) when is_binary(Bin), byte_size(Bin) =:= ?BLOCK_SIZE -> Checksum = parse_octal(V7#header_v7.checksum), - Chk1 = compute_checksum(Bin), - Chk2 = compute_signed_checksum(Bin), - if Checksum =/= Chk1 andalso Checksum =/= Chk2 -> + IsBadChecksum = case compute_checksum(Bin) of + Checksum -> false; + _ -> compute_signed_checksum(Bin) =/= Checksum + end, + case IsBadChecksum of + true -> ?FORMAT_UNKNOWN; - true -> + false -> %% guess magic Ustar = to_ustar(V7, Bin), Star = to_star(V7, Bin), @@ -1203,6 +1219,9 @@ compute_signed_checksum(<<H1:?V7_CHKSUM/binary, %% Returns the checksum of a binary. checksum(Bin) -> checksum(Bin, 0). + +checksum(<<A/unsigned,B/unsigned,C/unsigned,D/unsigned,Rest/binary>>, Sum) -> + checksum(Rest, Sum+A+B+C+D); checksum(<<A/unsigned,Rest/binary>>, Sum) -> checksum(Rest, Sum+A); checksum(<<>>, Sum) -> Sum. @@ -1251,39 +1270,40 @@ parse_numeric(<<First, _/binary>> = Bin) -> parse_octal(Bin) end. -parse_octal(Bin) when is_binary(Bin) -> +parse_octal(<<Bin/binary>>) -> %% skip leading/trailing zero bytes and spaces - do_parse_octal(Bin, <<>>). -do_parse_octal(<<>>, <<>>) -> - 0; -do_parse_octal(<<>>, Acc) -> - case io_lib:fread("~8u", binary:bin_to_list(Acc)) of - {error, _} -> throw({error, invalid_tar_checksum}); - {ok, [Octal], []} -> Octal; - {ok, _, _} -> throw({error, invalid_tar_checksum}) - end; -do_parse_octal(<<$\s,Rest/binary>>, Acc) -> + do_parse_octal(Bin, 0). + +do_parse_octal(<<$\s, Rest/binary>>, Acc) -> do_parse_octal(Rest, Acc); do_parse_octal(<<0, Rest/binary>>, Acc) -> do_parse_octal(Rest, Acc); do_parse_octal(<<C, Rest/binary>>, Acc) -> - do_parse_octal(Rest, <<Acc/binary, C>>). + Digit = C - $0, + case Digit band 7 of + Digit -> + do_parse_octal(Rest, Acc bsl 3 bor Digit); + _ -> + throw({error, invalid_tar_checksum}) + end; +do_parse_octal(<<>>, Acc) -> + Acc. parse_string(Bin) when is_binary(Bin) -> - do_parse_string(Bin, <<>>). -do_parse_string(<<>>, Acc) -> - case unicode:characters_to_list(Acc) of + N = strlen(Bin, 0), + <<Prefix:N/binary,_/binary>> = Bin, + case unicode:characters_to_list(Prefix) of Str when is_list(Str) -> Str; {incomplete, _Str, _Rest} -> - binary:bin_to_list(Acc); + binary_to_list(Bin); {error, _Str, _Rest} -> throw({error, {bad_header, invalid_string}}) - end; -do_parse_string(<<0, _/binary>>, Acc) -> - do_parse_string(<<>>, Acc); -do_parse_string(<<C, Rest/binary>>, Acc) -> - do_parse_string(Rest, <<Acc/binary, C>>). + end. + +strlen(<<>>, N) -> N; +strlen(<<0, _/binary>>, N) -> N; +strlen(<<_, Rest/binary>>, N) -> strlen(Rest, N + 1). convert_header(Bin, #reader{pos=Pos}=Reader) when byte_size(Bin) =:= ?BLOCK_SIZE, (Pos rem ?BLOCK_SIZE) =:= 0 -> |