1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1997-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19 20%% Options used when adding files to a tar archive. 21-record(add_opts, { 22 read_info, %% Fun to use for read file/link info. 23 chunk_size = 0, %% For file reading when sending to sftp. 0=do not chunk 24 verbose = false, %% Verbose on/off. 25 atime = undefined, 26 mtime = undefined, 27 ctime = undefined, 28 uid = 0, 29 gid = 0}). 30-type add_opts() :: #add_opts{}. 31 32%% Options used when reading a tar archive. 33-record(read_opts, { 34 cwd :: string(), %% Current working directory. 35 keep_old_files = false :: boolean(), %% Owerwrite or not. 36 files = all, %% Set of files to extract (or all) 37 output = file :: 'file' | 'memory', 38 open_mode = [], %% Open mode options. 39 verbose = false :: boolean()}). %% Verbose on/off. 40-type read_opts() :: #read_opts{}. 41 42-type add_opt() :: dereference | 43 verbose | 44 {chunks, pos_integer()} | 45 {atime, non_neg_integer()} | 46 {mtime, non_neg_integer()} | 47 {ctime, non_neg_integer()} | 48 {uid, non_neg_integer()} | 49 {gid, non_neg_integer()}. 50 51-type name_in_archive() :: string(). 52 53-type extract_opt() :: {cwd, string()} | 54 {files, [name_in_archive()]} | 55 compressed | 56 cooked | 57 memory | 58 keep_old_files | 59 verbose. 60 61-type create_opt() :: compressed | 62 cooked | 63 dereference | 64 verbose. 65 66-type filelist() :: [file:filename() | 67 {name_in_archive(), file:filename_all()}]. 68 69-type tar_time() :: non_neg_integer(). 70 71%% The tar header, once fully parsed. 72-record(tar_header, { 73 name = "" :: name_in_archive(), %% name of header file entry 74 mode = 8#100644 :: non_neg_integer(), %% permission and mode bits 75 uid = 0 :: non_neg_integer(), %% user id of owner 76 gid = 0 :: non_neg_integer(), %% group id of owner 77 size = 0 :: non_neg_integer(), %% length in bytes 78 mtime :: tar_time(), %% modified time 79 typeflag :: char(), %% type of header entry 80 linkname = "" :: name_in_archive(), %% target name of link 81 uname = "" :: string(), %% user name of owner 82 gname = "" :: string(), %% group name of owner 83 devmajor = 0 :: non_neg_integer(), %% major number of character or block device 84 devminor = 0 :: non_neg_integer(), %% minor number of character or block device 85 atime :: tar_time(), %% access time 86 ctime :: tar_time() %% status change time 87 }). 88-type tar_header() :: #tar_header{}. 89 90%% Metadata for a sparse file fragment 91-record(sparse_entry, { 92 offset = 0 :: non_neg_integer(), 93 num_bytes = 0 :: non_neg_integer()}). 94-type sparse_entry() :: #sparse_entry{}. 95%% Contains metadata about fragments of a sparse file 96-record(sparse_array, { 97 entries = [] :: [sparse_entry()], 98 is_extended = false :: boolean(), 99 max_entries = 0 :: non_neg_integer()}). 100-type sparse_array() :: #sparse_array{}. 101%% A subset of tar header fields common to all tar implementations 102-record(header_v7, { 103 name :: binary(), 104 mode :: binary(), %% octal 105 uid :: binary(), %% integer 106 gid :: binary(), %% integer 107 size :: binary(), %% integer 108 mtime :: binary(), %% integer 109 checksum :: binary(), %% integer 110 typeflag :: byte(), %% char 111 linkname :: binary()}). 112-type header_v7() :: #header_v7{}. 113%% The set of fields specific to GNU tar formatted archives 114-record(header_gnu, { 115 header_v7 :: header_v7(), 116 magic :: binary(), 117 version :: binary(), 118 uname :: binary(), 119 gname :: binary(), 120 devmajor :: binary(), %% integer 121 devminor :: binary(), %% integer 122 atime :: binary(), %% integer 123 ctime :: binary(), %% integer 124 sparse :: sparse_array(), 125 real_size :: binary()}). %% integer 126-type header_gnu() :: #header_gnu{}. 127%% The set of fields specific to STAR-formatted archives 128-record(header_star, { 129 header_v7 :: header_v7(), 130 magic :: binary(), 131 version :: binary(), 132 uname :: binary(), 133 gname :: binary(), 134 devmajor :: binary(), %% integer 135 devminor :: binary(), %% integer 136 prefix :: binary(), 137 atime :: binary(), %% integer 138 ctime :: binary(), %% integer 139 trailer :: binary()}). 140-type header_star() :: #header_star{}. 141%% The set of fields specific to USTAR-formatted archives 142-record(header_ustar, { 143 header_v7 :: header_v7(), 144 magic :: binary(), 145 version :: binary(), 146 uname :: binary(), 147 gname :: binary(), 148 devmajor :: binary(), %% integer 149 devminor :: binary(), %% integer 150 prefix :: binary()}). 151-type header_ustar() :: #header_ustar{}. 152 153-type header_fields() :: header_v7() | 154 header_gnu() | 155 header_star() | 156 header_ustar(). 157 158%% The overall tar reader, it holds the low-level file handle, 159%% its access, position, and the I/O primitives wrapper. 160-record(reader, { 161 handle :: user_data(), 162 access :: read | write | ram, 163 pos = 0 :: non_neg_integer(), 164 func :: file_op() 165 }). 166-opaque tar_descriptor() :: #reader{}. 167-export_type([tar_descriptor/0]). 168 169%% A reader for a regular file within the tar archive, 170%% It tracks its current state relative to that file. 171-record(reg_file_reader, { 172 handle :: tar_descriptor(), 173 num_bytes = 0, 174 pos = 0, 175 size = 0 176 }). 177-type reg_file_reader() :: #reg_file_reader{}. 178%% A reader for a sparse file within the tar archive, 179%% It tracks its current state relative to that file. 180-record(sparse_file_reader, { 181 handle :: tar_descriptor(), 182 num_bytes = 0, %% bytes remaining 183 pos = 0, %% pos 184 size = 0, %% total size of file 185 sparse_map = #sparse_array{} 186 }). 187-type sparse_file_reader() :: #sparse_file_reader{}. 188 189%% Types for the readers 190-type descriptor_type() :: tar_descriptor() | reg_file_reader() | sparse_file_reader(). 191-type user_data() :: term(). 192 193%% Type for the I/O primitive wrapper function 194-type file_op() :: fun((write | close | read2 | position, 195 {user_data(), iodata()} | user_data() | {user_data(), non_neg_integer()} 196 | {user_data(), non_neg_integer()}) -> 197 ok | eof | {ok, string() | binary()} | {ok, non_neg_integer()} 198 | {error, term()}). 199 200%% These constants (except S_IFMT) are 201%% used to determine what type of device 202%% a file is. Namely, `S_IFMT band file_info.mode` 203%% will equal one of these contants, and tells us 204%% which type it is. The stdlib file_info record 205%% does not differentiate between device types, and 206%% will not allow us to differentiate between sockets 207%% and named pipes. These constants are pulled from libc. 208-define(S_IFMT, 61440). 209-define(S_IFSOCK, 49152). %% socket 210-define(S_FIFO, 4096). %% fifo/named pipe 211-define(S_IFBLK, 24576). %% block device 212-define(S_IFCHR, 8192). %% character device 213 214%% Typeflag constants for the tar header 215-define(TYPE_REGULAR, $0). %% regular file 216-define(TYPE_REGULAR_A, 0). %% regular file 217-define(TYPE_LINK, $1). %% hard link 218-define(TYPE_SYMLINK, $2). %% symbolic link 219-define(TYPE_CHAR, $3). %% character device node 220-define(TYPE_BLOCK, $4). %% block device node 221-define(TYPE_DIR, $5). %% directory 222-define(TYPE_FIFO, $6). %% fifo node 223-define(TYPE_CONT, $7). %% reserved 224-define(TYPE_X_HEADER, $x). %% extended header 225-define(TYPE_X_GLOBAL_HEADER, $g). %% global extended header 226-define(TYPE_GNU_LONGNAME, $L). %% next file has a long name 227-define(TYPE_GNU_LONGLINK, $K). %% next file symlinks to a file with a long name 228-define(TYPE_GNU_SPARSE, $S). %% sparse file 229 230%% Mode constants from tar spec 231-define(MODE_ISUID, 4000). %% set uid 232-define(MODE_ISGID, 2000). %% set gid 233-define(MODE_ISVTX, 1000). %% save text (sticky bit) 234-define(MODE_ISDIR, 40000). %% directory 235-define(MODE_ISFIFO, 10000). %% fifo 236-define(MODE_ISREG, 100000). %% regular file 237-define(MODE_ISLNK, 120000). %% symbolic link 238-define(MODE_ISBLK, 60000). %% block special file 239-define(MODE_ISCHR, 20000). %% character special file 240-define(MODE_ISSOCK, 140000). %% socket 241 242%% Keywords for PAX extended header 243-define(PAX_ATIME, <<"atime">>). 244-define(PAX_CHARSET, <<"charset">>). 245-define(PAX_COMMENT, <<"comment">>). 246-define(PAX_CTIME, <<"ctime">>). %% ctime is not a valid pax header 247-define(PAX_GID, <<"gid">>). 248-define(PAX_GNAME, <<"gname">>). 249-define(PAX_LINKPATH, <<"linkpath">>). 250-define(PAX_MTIME, <<"mtime">>). 251-define(PAX_PATH, <<"path">>). 252-define(PAX_SIZE, <<"size">>). 253-define(PAX_UID, <<"uid">>). 254-define(PAX_UNAME, <<"uname">>). 255-define(PAX_XATTR, <<"SCHILY.xattr.">>). 256-define(PAX_XATTR_STR, "SCHILY.xattr."). 257-define(PAX_NONE, <<"">>). 258 259%% Tar format constants 260%% Unknown format 261-define(FORMAT_UNKNOWN, 0). 262%% The format of the original Unix V7 tar tool prior to standardization 263-define(FORMAT_V7, 1). 264%% The old and new GNU formats, incompatible with USTAR. 265%% This covers the old GNU sparse extension, but it does 266%% not cover the GNU sparse extensions using PAX headers, 267%% versions 0.0, 0.1, and 1.0; these fall under the PAX format. 268-define(FORMAT_GNU, 2). 269%% Schily's tar format, which is incompatible with USTAR. 270%% This does not cover STAR extensions to the PAX format; these 271%% fall under the PAX format. 272-define(FORMAT_STAR, 3). 273%% USTAR is the former standardization of tar defined in POSIX.1-1988, 274%% it is incompatible with the GNU and STAR formats. 275-define(FORMAT_USTAR, 4). 276%% PAX is the latest standardization of tar defined in POSIX.1-2001. 277%% This is an extension of USTAR and is "backwards compatible" with it. 278%% 279%% Some newer formats add their own extensions to PAX, such as GNU sparse 280%% files and SCHILY extended attributes. Since they are backwards compatible 281%% with PAX, they will be labelled as "PAX". 282-define(FORMAT_PAX, 5). 283 284%% Magic constants 285-define(MAGIC_GNU, <<"ustar ">>). 286-define(VERSION_GNU, <<" \x00">>). 287-define(MAGIC_USTAR, <<"ustar\x00">>). 288-define(VERSION_USTAR, <<"00">>). 289-define(TRAILER_STAR, <<"tar\x00">>). 290 291%% Size constants 292-define(BLOCK_SIZE, 512). %% size of each block in a tar stream 293-define(NAME_SIZE, 100). %% max length of the name field in USTAR format 294-define(PREFIX_SIZE, 155). %% max length of the prefix field in USTAR format 295 296%% Maximum size of a nanosecond value as an integer 297-define(MAX_NANO_INT_SIZE, 9). 298%% Maximum size of a 64-bit signed integer 299-define(MAX_INT64, (1 bsl 63 - 1)). 300 301-define(PAX_GNU_SPARSE_NUMBLOCKS, <<"GNU.sparse.numblocks">>). 302-define(PAX_GNU_SPARSE_OFFSET, <<"GNU.sparse.offset">>). 303-define(PAX_GNU_SPARSE_NUMBYTES, <<"GNU.sparse.numbytes">>). 304-define(PAX_GNU_SPARSE_MAP, <<"GNU.sparse.map">>). 305-define(PAX_GNU_SPARSE_NAME, <<"GNU.sparse.name">>). 306-define(PAX_GNU_SPARSE_MAJOR, <<"GNU.sparse.major">>). 307-define(PAX_GNU_SPARSE_MINOR, <<"GNU.sparse.minor">>). 308-define(PAX_GNU_SPARSE_SIZE, <<"GNU.sparse.size">>). 309-define(PAX_GNU_SPARSE_REALSIZE, <<"GNU.sparse.realsize">>). 310 311-define(V7_NAME, 0). 312-define(V7_NAME_LEN, 100). 313-define(V7_MODE, 100). 314-define(V7_MODE_LEN, 8). 315-define(V7_UID, 108). 316-define(V7_UID_LEN, 8). 317-define(V7_GID, 116). 318-define(V7_GID_LEN, 8). 319-define(V7_SIZE, 124). 320-define(V7_SIZE_LEN, 12). 321-define(V7_MTIME, 136). 322-define(V7_MTIME_LEN, 12). 323-define(V7_CHKSUM, 148). 324-define(V7_CHKSUM_LEN, 8). 325-define(V7_TYPE, 156). 326-define(V7_TYPE_LEN, 1). 327-define(V7_LINKNAME, 157). 328-define(V7_LINKNAME_LEN, 100). 329 330-define(STAR_TRAILER, 508). 331-define(STAR_TRAILER_LEN, 4). 332 333-define(USTAR_MAGIC, 257). 334-define(USTAR_MAGIC_LEN, 6). 335-define(USTAR_VERSION, 263). 336-define(USTAR_VERSION_LEN, 2). 337-define(USTAR_UNAME, 265). 338-define(USTAR_UNAME_LEN, 32). 339-define(USTAR_GNAME, 297). 340-define(USTAR_GNAME_LEN, 32). 341-define(USTAR_DEVMAJ, 329). 342-define(USTAR_DEVMAJ_LEN, 8). 343-define(USTAR_DEVMIN, 337). 344-define(USTAR_DEVMIN_LEN, 8). 345-define(USTAR_PREFIX, 345). 346-define(USTAR_PREFIX_LEN, 155). 347 348-define(GNU_MAGIC, 257). 349-define(GNU_MAGIC_LEN, 6). 350-define(GNU_VERSION, 263). 351-define(GNU_VERSION_LEN, 2). 352 353%% ?BLOCK_SIZE of zero-bytes. 354%% Two of these in a row mark the end of an archive. 355-define(ZERO_BLOCK, <<0,0,0,0,0,0,0,0,0,0, 356 0,0,0,0,0,0,0,0,0,0, 357 0,0,0,0,0,0,0,0,0,0, 358 0,0,0,0,0,0,0,0,0,0, 359 0,0,0,0,0,0,0,0,0,0, 360 0,0,0,0,0,0,0,0,0,0, 361 0,0,0,0,0,0,0,0,0,0, 362 0,0,0,0,0,0,0,0,0,0, 363 0,0,0,0,0,0,0,0,0,0, 364 0,0,0,0,0,0,0,0,0,0, 365 0,0,0,0,0,0,0,0,0,0, 366 0,0,0,0,0,0,0,0,0,0, 367 0,0,0,0,0,0,0,0,0,0, 368 0,0,0,0,0,0,0,0,0,0, 369 0,0,0,0,0,0,0,0,0,0, 370 0,0,0,0,0,0,0,0,0,0, 371 0,0,0,0,0,0,0,0,0,0, 372 0,0,0,0,0,0,0,0,0,0, 373 0,0,0,0,0,0,0,0,0,0, 374 0,0,0,0,0,0,0,0,0,0, 375 0,0,0,0,0,0,0,0,0,0, 376 0,0,0,0,0,0,0,0,0,0, 377 0,0,0,0,0,0,0,0,0,0, 378 0,0,0,0,0,0,0,0,0,0, 379 0,0,0,0,0,0,0,0,0,0, 380 0,0,0,0,0,0,0,0,0,0, 381 0,0,0,0,0,0,0,0,0,0, 382 0,0,0,0,0,0,0,0,0,0, 383 0,0,0,0,0,0,0,0,0,0, 384 0,0,0,0,0,0,0,0,0,0, 385 0,0,0,0,0,0,0,0,0,0, 386 0,0,0,0,0,0,0,0,0,0, 387 0,0,0,0,0,0,0,0,0,0, 388 0,0,0,0,0,0,0,0,0,0, 389 0,0,0,0,0,0,0,0,0,0, 390 0,0,0,0,0,0,0,0,0,0, 391 0,0,0,0,0,0,0,0,0,0, 392 0,0,0,0,0,0,0,0,0,0, 393 0,0,0,0,0,0,0,0,0,0, 394 0,0,0,0,0,0,0,0,0,0, 395 0,0,0,0,0,0,0,0,0,0, 396 0,0,0,0,0,0,0,0,0,0, 397 0,0,0,0,0,0,0,0,0,0, 398 0,0,0,0,0,0,0,0,0,0, 399 0,0,0,0,0,0,0,0,0,0, 400 0,0,0,0,0,0,0,0,0,0, 401 0,0,0,0,0,0,0,0,0,0, 402 0,0,0,0,0,0,0,0,0,0, 403 0,0,0,0,0,0,0,0,0,0, 404 0,0,0,0,0,0,0,0,0,0, 405 0,0,0,0,0,0,0,0,0,0,0,0>>). 406 407-define(BILLION, 1000000000). 408 409-define(EPOCH, {{1970,1,1}, {0,0,0}}). 410