1 /* vi: set sw=4 ts=4: */
2 /* Licensed under GPLv2 or later, see file LICENSE in this source tree.
5 * In privileged mode if uname and gname map to a uid and gid then use the
6 * mapped value instead of the uid/gid values in tar header
9 * GNU tar and star man pages,
10 * Opengroup's ustar interchange format,
11 * http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html
15 #include "bb_archive.h"
17 typedef uint32_t aliased_uint32_t FIX_ALIASING
;
18 typedef off_t aliased_off_t FIX_ALIASING
;
21 const char* FAST_FUNC
strip_unsafe_prefix(const char *str
)
30 if (strncmp(cp
, "/../"+1, 3) == 0) {
34 cp2
= strstr(cp
, "/../");
40 static smallint warned
= 0;
43 bb_error_msg("removing leading '%.*s' from member names",
44 (int)(cp
- str
), str
);
50 /* NB: _DESTROYS_ str[len] character! */
51 static unsigned long long getOctal(char *str
, int len
)
55 /* NB: leading spaces are allowed. Using strtoull to handle that.
56 * The downside is that we accept e.g. "-123" too :(
59 v
= strtoull(str
, &end
, 8);
60 /* std: "Each numeric field is terminated by one or more
61 * <space> or NUL characters". We must support ' '! */
62 if (*end
!= '\0' && *end
!= ' ') {
63 int8_t first
= str
[0];
65 bb_error_msg_and_die("corrupted octal value in tar header");
67 * GNU tar uses "base-256 encoding" for very large numbers.
68 * Encoding is binary, with highest bit always set as a marker
69 * and sign in next-highest bit:
71 * bf ff .. ff - largest positive number
72 * ff ff .. ff - minus 1
73 * c0 00 .. 00 - smallest negative number
75 * Example of tar file with 8914993153 (0x213600001) byte file.
76 * Field starts at offset 7c:
77 * 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....|
78 * 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336|
80 * NB: tarballs with NEGATIVE unix times encoded that way were seen!
82 /* Sign-extend 7bit 'first' to 64bit 'v' (that is, using 6th bit as sign): */
84 first
>>= 1; /* now 7th bit = 6th bit */
85 v
= first
; /* sign-extend 8 bits to 64 */
87 v
= (v
<< 8) + (uint8_t) *++str
;
91 #define GET_OCTAL(a) getOctal((a), sizeof(a))
93 /* "global" is 0 or 1 */
94 static void process_pax_hdr(archive_handle_t
*archive_handle
, unsigned sz
, int global
)
99 blk_sz
= (sz
+ 511) & (~511);
100 p
= buf
= xmalloc(blk_sz
+ 1);
101 xread(archive_handle
->src_fd
, buf
, blk_sz
);
102 archive_handle
->offset
+= blk_sz
;
104 /* prevent bb_strtou from running off the buffer */
111 /* Every record has this format: "LEN NAME=VALUE\n" */
112 len
= bb_strtou(p
, &end
, 10);
113 /* expect errno to be EINVAL, because the character
114 * following the digits should be a space
123 bb_error_msg("malformed extended header, skipped");
124 // More verbose version:
125 //bb_error_msg("malformed extended header at %"OFF_FMT"d, skipped",
126 // archive_handle->offset - (sz + len));
129 /* overwrite the terminating newline with NUL
130 * (we do not bother to check that it *was* a newline)
135 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
136 if (!global
&& strncmp(value
, "path=", sizeof("path=") - 1) == 0) {
137 value
+= sizeof("path=") - 1;
138 free(archive_handle
->tar__longname
);
139 archive_handle
->tar__longname
= xstrdup(value
);
144 #if ENABLE_FEATURE_TAR_SELINUX
145 /* Scan for SELinux contexts, via "RHT.security.selinux" keyword.
146 * This is what Red Hat's patched version of tar uses.
148 # define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
149 if (strncmp(value
, SELINUX_CONTEXT_KEYWORD
"=", sizeof(SELINUX_CONTEXT_KEYWORD
"=") - 1) == 0) {
150 value
+= sizeof(SELINUX_CONTEXT_KEYWORD
"=") - 1;
151 free(archive_handle
->tar__sctx
[global
]);
152 archive_handle
->tar__sctx
[global
] = xstrdup(value
);
161 char FAST_FUNC
get_header_tar(archive_handle_t
*archive_handle
)
163 file_header_t
*file_header
= archive_handle
->file_header
;
164 struct tar_header_t tar
;
167 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
172 /* Our "private data" */
173 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
174 # define p_longname (archive_handle->tar__longname)
175 # define p_linkname (archive_handle->tar__linkname)
177 # define p_longname 0
178 # define p_linkname 0
181 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX
185 data_align(archive_handle
, 512);
189 #if ENABLE_DESKTOP || ENABLE_FEATURE_TAR_AUTODETECT
190 /* to prevent misdetection of bz2 sig */
191 *(aliased_uint32_t
*)&tar
= 0;
192 i
= full_read(archive_handle
->src_fd
, &tar
, 512);
193 /* If GNU tar sees EOF in above read, it says:
194 * "tar: A lone zero block at N", where N = kilobyte
195 * where EOF was met (not EOF block, actual EOF!),
196 * and exits with EXIT_SUCCESS.
197 * We will mimic exit(EXIT_SUCCESS), although we will not mimic
198 * the message and we don't check whether we indeed
199 * saw zero block directly before this. */
201 xfunc_error_retval
= 0;
203 bb_error_msg_and_die("short read");
206 IF_FEATURE_TAR_AUTODETECT(goto autodetect
;)
212 xread(archive_handle
->src_fd
, &tar
, i
);
214 archive_handle
->offset
+= i
;
216 /* If there is no filename its an empty header */
217 if (tar
.name
[0] == 0 && tar
.prefix
[0] == 0) {
218 if (archive_handle
->tar__end
) {
219 /* Second consecutive empty header - end of archive.
220 * Read until the end to empty the pipe from gz or bz2
222 while (full_read(archive_handle
->src_fd
, &tar
, 512) == 512)
226 archive_handle
->tar__end
= 1;
229 archive_handle
->tar__end
= 0;
231 /* Check header has valid magic, "ustar" is for the proper tar,
232 * five NULs are for the old tar format */
233 if (strncmp(tar
.magic
, "ustar", 5) != 0
234 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
235 || memcmp(tar
.magic
, "\0\0\0\0", 5) != 0)
237 #if ENABLE_FEATURE_TAR_AUTODETECT
239 /* Two different causes for lseek() != 0:
240 * unseekable fd (would like to support that too, but...),
241 * or not first block (false positive, it's not .gz/.bz2!) */
242 if (lseek(archive_handle
->src_fd
, -i
, SEEK_CUR
) != 0)
244 if (setup_unzip_on_fd(archive_handle
->src_fd
, /*fail_if_not_detected:*/ 0) != 0)
246 bb_error_msg_and_die("invalid tar magic");
247 archive_handle
->offset
= 0;
248 goto again_after_align
;
250 bb_error_msg_and_die("invalid tar magic");
253 /* Do checksum on headers.
254 * POSIX says that checksum is done on unsigned bytes, but
255 * Sun and HP-UX gets it wrong... more details in
257 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
258 sum_s
= ' ' * sizeof(tar
.chksum
);
260 sum_u
= ' ' * sizeof(tar
.chksum
);
261 for (i
= 0; i
< 148; i
++) {
262 sum_u
+= ((unsigned char*)&tar
)[i
];
263 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
264 sum_s
+= ((signed char*)&tar
)[i
];
267 for (i
= 156; i
< 512; i
++) {
268 sum_u
+= ((unsigned char*)&tar
)[i
];
269 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
270 sum_s
+= ((signed char*)&tar
)[i
];
273 /* This field does not need special treatment (getOctal) */
275 char *endp
; /* gcc likes temp var for &endp */
276 sum
= strtoul(tar
.chksum
, &endp
, 8);
277 if ((*endp
!= '\0' && *endp
!= ' ')
278 || (sum_u
!= sum
IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s
!= sum
))
280 bb_error_msg_and_die("invalid tar header checksum");
283 /* don't use xstrtoul, tar.chksum may have leading spaces */
284 sum
= strtoul(tar
.chksum
, NULL
, 8);
285 if (sum_u
!= sum
IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s
!= sum
)) {
286 bb_error_msg_and_die("invalid tar header checksum");
289 /* 0 is reserved for high perf file, treat as normal file */
290 if (!tar
.typeflag
) tar
.typeflag
= '0';
291 parse_names
= (tar
.typeflag
>= '0' && tar
.typeflag
<= '7');
293 /* getOctal trashes subsequent field, therefore we call it
294 * on fields in reverse order */
295 if (tar
.devmajor
[0]) {
296 char t
= tar
.prefix
[0];
297 /* we trash prefix[0] here, but we DO need it later! */
298 unsigned minor
= GET_OCTAL(tar
.devminor
);
299 unsigned major
= GET_OCTAL(tar
.devmajor
);
300 file_header
->device
= makedev(major
, minor
);
303 file_header
->link_target
= NULL
;
304 if (!p_linkname
&& parse_names
&& tar
.linkname
[0]) {
305 file_header
->link_target
= xstrndup(tar
.linkname
, sizeof(tar
.linkname
));
306 /* FIXME: what if we have non-link object with link_target? */
307 /* Will link_target be free()ed? */
309 #if ENABLE_FEATURE_TAR_UNAME_GNAME
310 file_header
->tar__uname
= tar
.uname
[0] ? xstrndup(tar
.uname
, sizeof(tar
.uname
)) : NULL
;
311 file_header
->tar__gname
= tar
.gname
[0] ? xstrndup(tar
.gname
, sizeof(tar
.gname
)) : NULL
;
313 file_header
->mtime
= GET_OCTAL(tar
.mtime
);
314 file_header
->size
= GET_OCTAL(tar
.size
);
315 file_header
->gid
= GET_OCTAL(tar
.gid
);
316 file_header
->uid
= GET_OCTAL(tar
.uid
);
317 /* Set bits 0-11 of the files mode */
318 file_header
->mode
= 07777 & GET_OCTAL(tar
.mode
);
320 file_header
->name
= NULL
;
321 if (!p_longname
&& parse_names
) {
322 /* we trash mode[0] here, it's ok */
323 //tar.name[sizeof(tar.name)] = '\0'; - gcc 4.3.0 would complain
327 //tar.prefix[sizeof(tar.prefix)] = '\0'; - gcc 4.3.0 would complain
328 tar
.padding
[0] = '\0';
329 file_header
->name
= concat_path_file(tar
.prefix
, tar
.name
);
331 file_header
->name
= xstrdup(tar
.name
);
334 /* Set bits 12-15 of the files mode */
335 /* (typeflag was not trashed because chksum does not use getOctal) */
336 switch (tar
.typeflag
) {
337 case '1': /* hardlink */
338 /* we mark hardlinks as regular files with zero size and a link name */
339 file_header
->mode
|= S_IFREG
;
340 /* on size of link fields from star(4)
341 * ... For tar archives written by pre POSIX.1-1988
342 * implementations, the size field usually contains the size of
343 * the file and needs to be ignored as no data may follow this
344 * header type. For POSIX.1- 1988 compliant archives, the size
345 * field needs to be 0. For POSIX.1-2001 compliant archives,
346 * the size field may be non zero, indicating that file data is
347 * included in the archive.
348 * i.e; always assume this is zero for safety.
354 #if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
355 if (last_char_is(file_header
->name
, '/')) {
359 file_header
->mode
|= S_IFREG
;
362 file_header
->mode
|= S_IFLNK
;
363 /* have seen tarballs with size field containing
364 * the size of the link target's name */
366 file_header
->size
= 0;
369 file_header
->mode
|= S_IFCHR
;
370 goto size0
; /* paranoia */
372 file_header
->mode
|= S_IFBLK
;
375 IF_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir
:)
376 file_header
->mode
|= S_IFDIR
;
379 file_header
->mode
|= S_IFIFO
;
381 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
383 /* free: paranoia: tar with several consecutive longnames */
385 /* For paranoia reasons we allocate extra NUL char */
386 p_longname
= xzalloc(file_header
->size
+ 1);
387 /* We read ASCIZ string, including NUL */
388 xread(archive_handle
->src_fd
, p_longname
, file_header
->size
);
389 archive_handle
->offset
+= file_header
->size
;
390 /* return get_header_tar(archive_handle); */
391 /* gcc 4.1.1 didn't optimize it into jump */
392 /* so we will do it ourself, this also saves stack */
396 p_linkname
= xzalloc(file_header
->size
+ 1);
397 xread(archive_handle
->src_fd
, p_linkname
, file_header
->size
);
398 archive_handle
->offset
+= file_header
->size
;
399 /* return get_header_tar(archive_handle); */
401 case 'D': /* GNU dump dir */
402 case 'M': /* Continuation of multi volume archive */
403 case 'N': /* Old GNU for names > 100 characters */
404 case 'S': /* Sparse file */
405 case 'V': /* Volume header */
407 case 'g': /* pax global header */
408 case 'x': { /* pax extended header */
409 if ((uoff_t
)file_header
->size
> 0xfffff) /* paranoia */
411 process_pax_hdr(archive_handle
, file_header
->size
, (tar
.typeflag
== 'g'));
412 goto again_after_align
;
417 bb_error_msg("warning: skipping header '%c'", tar
.typeflag
);
418 sz
= (file_header
->size
+ 511) & ~(off_t
)511;
419 archive_handle
->offset
+= sz
;
420 sz
>>= 9; /* sz /= 512 but w/o contortions for signed div */
422 xread(archive_handle
->src_fd
, &tar
, 512);
423 /* return get_header_tar(archive_handle); */
424 goto again_after_align
;
427 bb_error_msg_and_die("unknown typeflag: 0x%x", tar
.typeflag
);
430 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
432 file_header
->name
= p_longname
;
436 file_header
->link_target
= p_linkname
;
441 /* Everything up to and including last ".." component is stripped */
442 overlapping_strcpy(file_header
->name
, strip_unsafe_prefix(file_header
->name
));
444 /* Strip trailing '/' in directories */
445 /* Must be done after mode is set as '/' is used to check if it's a directory */
446 cp
= last_char_is(file_header
->name
, '/');
448 if (archive_handle
->filter(archive_handle
) == EXIT_SUCCESS
) {
449 archive_handle
->action_header(/*archive_handle->*/ file_header
);
450 /* Note that we kill the '/' only after action_header() */
451 /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */
454 archive_handle
->action_data(archive_handle
);
455 if (archive_handle
->accept
|| archive_handle
->reject
456 || (archive_handle
->ah_flags
& ARCHIVE_REMEMBER_NAMES
)
458 llist_add_to(&archive_handle
->passed
, file_header
->name
);
459 } else /* Caller isn't interested in list of unpacked files */
460 free(file_header
->name
);
462 data_skip(archive_handle
);
463 free(file_header
->name
);
465 archive_handle
->offset
+= file_header
->size
;
467 free(file_header
->link_target
);
468 /* Do not free(file_header->name)!
469 * It might be inserted in archive_handle->passed - see above */
470 #if ENABLE_FEATURE_TAR_UNAME_GNAME
471 free(file_header
->tar__uname
);
472 free(file_header
->tar__gname
);