1 /* vi: set sw=4 ts=4: */
2 /* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
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 "unarchive.h"
17 /* NB: _DESTROYS_ str[len] character! */
18 static unsigned long long getOctal(char *str
, int len
)
21 /* NB: leading spaces are allowed. Using strtoull to handle that.
22 * The downside is that we accept e.g. "-123" too :)
25 v
= strtoull(str
, &str
, 8);
26 if (*str
&& (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
|| *str
!= ' '))
27 bb_error_msg_and_die("corrupted octal value in tar header");
30 #define GET_OCTAL(a) getOctal((a), sizeof(a))
32 void BUG_tar_header_size(void);
33 char FAST_FUNC
get_header_tar(archive_handle_t
*archive_handle
)
35 file_header_t
*file_header
= archive_handle
->file_header
;
37 /* ustar header, Posix 1003.1 */
38 char name
[100]; /* 0-99 */
39 char mode
[8]; /* 100-107 */
40 char uid
[8]; /* 108-115 */
41 char gid
[8]; /* 116-123 */
42 char size
[12]; /* 124-135 */
43 char mtime
[12]; /* 136-147 */
44 char chksum
[8]; /* 148-155 */
45 char typeflag
; /* 156-156 */
46 char linkname
[100]; /* 157-256 */
47 /* POSIX: "ustar" NUL "00" */
48 /* GNU tar: "ustar " NUL */
49 /* Normally it's defined as magic[6] followed by
50 * version[2], but we put them together to simplify code
52 char magic
[8]; /* 257-264 */
53 char uname
[32]; /* 265-296 */
54 char gname
[32]; /* 297-328 */
55 char devmajor
[8]; /* 329-336 */
56 char devminor
[8]; /* 337-344 */
57 char prefix
[155]; /* 345-499 */
58 char padding
[12]; /* 500-512 */
62 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
67 /* Our "private data" */
68 #define p_end (*(smallint *)(&archive_handle->ah_priv[0]))
69 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
70 #define p_longname (*(char* *)(&archive_handle->ah_priv[1]))
71 #define p_linkname (*(char* *)(&archive_handle->ah_priv[2]))
76 // if (!archive_handle->ah_priv_inited) {
77 // archive_handle->ah_priv_inited = 1;
79 // USE_FEATURE_TAR_GNU_EXTENSIONS(p_longname = NULL;)
80 // USE_FEATURE_TAR_GNU_EXTENSIONS(p_linkname = NULL;)
83 if (sizeof(tar
) != 512)
84 BUG_tar_header_size();
86 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
90 data_align(archive_handle
, 512);
95 /* to prevent misdetection of bz2 sig */
96 *(uint32_t*)(&tar
) = 0;
97 i
= full_read(archive_handle
->src_fd
, &tar
, 512);
98 /* If GNU tar sees EOF in above read, it says:
99 * "tar: A lone zero block at N", where N = kilobyte
100 * where EOF was met (not EOF block, actual EOF!),
101 * and exits with EXIT_SUCCESS.
102 * We will mimic exit(EXIT_SUCCESS), although we will not mimic
103 * the message and we don't check whether we indeed
104 * saw zero block directly before this. */
106 xfunc_error_retval
= 0;
108 bb_error_msg_and_die("short read");
111 USE_FEATURE_TAR_AUTODETECT(goto autodetect
;)
117 xread(archive_handle
->src_fd
, &tar
, i
);
119 archive_handle
->offset
+= i
;
121 /* If there is no filename its an empty header */
122 if (tar
.name
[0] == 0 && tar
.prefix
[0] == 0) {
124 /* Second consecutive empty header - end of archive.
125 * Read until the end to empty the pipe from gz or bz2
127 while (full_read(archive_handle
->src_fd
, &tar
, 512) == 512)
136 /* Check header has valid magic, "ustar" is for the proper tar,
137 * five NULs are for the old tar format */
138 if (strncmp(tar
.magic
, "ustar", 5) != 0
139 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
140 || memcmp(tar
.magic
, "\0\0\0\0", 5) != 0)
142 #if ENABLE_FEATURE_TAR_AUTODETECT
143 char FAST_FUNC (*get_header_ptr
)(archive_handle_t
*);
145 USE_DESKTOP(autodetect
:)
146 /* tar gz/bz autodetect: check for gz/bz2 magic.
147 * If we see the magic, and it is the very first block,
148 * we can switch to get_header_tar_gz/bz2/lzma().
149 * Needs seekable fd. I wish recv(MSG_PEEK) works
151 #if ENABLE_FEATURE_SEAMLESS_GZ
152 if (tar
.name
[0] == 0x1f && tar
.name
[1] == (char)0x8b) { /* gzip */
153 get_header_ptr
= get_header_tar_gz
;
156 #if ENABLE_FEATURE_SEAMLESS_BZ2
157 if (tar
.name
[0] == 'B' && tar
.name
[1] == 'Z'
158 && tar
.name
[2] == 'h' && isdigit(tar
.name
[3])
160 get_header_ptr
= get_header_tar_bz2
;
164 /* Two different causes for lseek() != 0:
165 * unseekable fd (would like to support that too, but...),
166 * or not first block (false positive, it's not .gz/.bz2!) */
167 if (lseek(archive_handle
->src_fd
, -i
, SEEK_CUR
) != 0)
169 while (get_header_ptr(archive_handle
) == EXIT_SUCCESS
)
173 #endif /* FEATURE_TAR_AUTODETECT */
174 bb_error_msg_and_die("invalid tar magic");
177 /* Do checksum on headers.
178 * POSIX says that checksum is done on unsigned bytes, but
179 * Sun and HP-UX gets it wrong... more details in
181 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
182 sum_s
= ' ' * sizeof(tar
.chksum
);
184 sum_u
= ' ' * sizeof(tar
.chksum
);
185 for (i
= 0; i
< 148; i
++) {
186 sum_u
+= ((unsigned char*)&tar
)[i
];
187 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
188 sum_s
+= ((signed char*)&tar
)[i
];
191 for (i
= 156; i
< 512; i
++) {
192 sum_u
+= ((unsigned char*)&tar
)[i
];
193 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
194 sum_s
+= ((signed char*)&tar
)[i
];
197 #if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
198 sum
= strtoul(tar
.chksum
, &cp
, 8);
199 if ((*cp
&& *cp
!= ' ')
200 || (sum_u
!= sum
USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s
!= sum
))
202 bb_error_msg_and_die("invalid tar header checksum");
205 /* This field does not need special treatment (getOctal) */
206 sum
= xstrtoul(tar
.chksum
, 8);
207 if (sum_u
!= sum
USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s
!= sum
)) {
208 bb_error_msg_and_die("invalid tar header checksum");
212 /* 0 is reserved for high perf file, treat as normal file */
213 if (!tar
.typeflag
) tar
.typeflag
= '0';
214 parse_names
= (tar
.typeflag
>= '0' && tar
.typeflag
<= '7');
216 /* getOctal trashes subsequent field, therefore we call it
217 * on fields in reverse order */
218 if (tar
.devmajor
[0]) {
219 char t
= tar
.prefix
[0];
220 /* we trash prefix[0] here, but we DO need it later! */
221 unsigned minor
= GET_OCTAL(tar
.devminor
);
222 unsigned major
= GET_OCTAL(tar
.devmajor
);
223 file_header
->device
= makedev(major
, minor
);
226 file_header
->link_target
= NULL
;
227 if (!p_linkname
&& parse_names
&& tar
.linkname
[0]) {
228 file_header
->link_target
= xstrndup(tar
.linkname
, sizeof(tar
.linkname
));
229 /* FIXME: what if we have non-link object with link_target? */
230 /* Will link_target be free()ed? */
232 #if ENABLE_FEATURE_TAR_UNAME_GNAME
233 file_header
->uname
= tar
.uname
[0] ? xstrndup(tar
.uname
, sizeof(tar
.uname
)) : NULL
;
234 file_header
->gname
= tar
.gname
[0] ? xstrndup(tar
.gname
, sizeof(tar
.gname
)) : NULL
;
236 file_header
->mtime
= GET_OCTAL(tar
.mtime
);
237 file_header
->size
= GET_OCTAL(tar
.size
);
238 file_header
->gid
= GET_OCTAL(tar
.gid
);
239 file_header
->uid
= GET_OCTAL(tar
.uid
);
240 /* Set bits 0-11 of the files mode */
241 file_header
->mode
= 07777 & GET_OCTAL(tar
.mode
);
243 file_header
->name
= NULL
;
244 if (!p_longname
&& parse_names
) {
245 /* we trash mode[0] here, it's ok */
246 //tar.name[sizeof(tar.name)] = '\0'; - gcc 4.3.0 would complain
250 //tar.prefix[sizeof(tar.prefix)] = '\0'; - gcc 4.3.0 would complain
251 tar
.padding
[0] = '\0';
252 file_header
->name
= concat_path_file(tar
.prefix
, tar
.name
);
254 file_header
->name
= xstrdup(tar
.name
);
257 /* Set bits 12-15 of the files mode */
258 /* (typeflag was not trashed because chksum does not use getOctal) */
259 switch (tar
.typeflag
) {
260 /* busybox identifies hard links as being regular files with 0 size and a link name */
262 file_header
->mode
|= S_IFREG
;
267 #if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
268 if (last_char_is(file_header
->name
, '/')) {
272 file_header
->mode
|= S_IFREG
;
275 file_header
->mode
|= S_IFLNK
;
276 /* have seen tarballs with size field containing
277 * the size of the link target's name */
279 file_header
->size
= 0;
282 file_header
->mode
|= S_IFCHR
;
283 goto size0
; /* paranoia */
285 file_header
->mode
|= S_IFBLK
;
288 USE_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir
:)
289 file_header
->mode
|= S_IFDIR
;
292 file_header
->mode
|= S_IFIFO
;
294 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
296 /* free: paranoia: tar with several consecutive longnames */
298 /* For paranoia reasons we allocate extra NUL char */
299 p_longname
= xzalloc(file_header
->size
+ 1);
300 /* We read ASCIZ string, including NUL */
301 xread(archive_handle
->src_fd
, p_longname
, file_header
->size
);
302 archive_handle
->offset
+= file_header
->size
;
303 /* return get_header_tar(archive_handle); */
304 /* gcc 4.1.1 didn't optimize it into jump */
305 /* so we will do it ourself, this also saves stack */
309 p_linkname
= xzalloc(file_header
->size
+ 1);
310 xread(archive_handle
->src_fd
, p_linkname
, file_header
->size
);
311 archive_handle
->offset
+= file_header
->size
;
312 /* return get_header_tar(archive_handle); */
314 case 'D': /* GNU dump dir */
315 case 'M': /* Continuation of multi volume archive */
316 case 'N': /* Old GNU for names > 100 characters */
317 case 'S': /* Sparse file */
318 case 'V': /* Volume header */
320 case 'g': /* pax global header */
321 case 'x': { /* pax extended header */
323 bb_error_msg("warning: skipping header '%c'", tar
.typeflag
);
324 sz
= (file_header
->size
+ 511) & ~(off_t
)511;
325 archive_handle
->offset
+= sz
;
326 sz
>>= 9; /* sz /= 512 but w/o contortions for signed div */
328 xread(archive_handle
->src_fd
, &tar
, 512);
329 /* return get_header_tar(archive_handle); */
330 goto again_after_align
;
333 bb_error_msg_and_die("unknown typeflag: 0x%x", tar
.typeflag
);
336 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
338 file_header
->name
= p_longname
;
342 file_header
->link_target
= p_linkname
;
346 if (strncmp(file_header
->name
, "/../"+1, 3) == 0
347 || strstr(file_header
->name
, "/../")
349 bb_error_msg_and_die("name with '..' encountered: '%s'",
353 /* Strip trailing '/' in directories */
354 /* Must be done after mode is set as '/' is used to check if it's a directory */
355 cp
= last_char_is(file_header
->name
, '/');
357 if (archive_handle
->filter(archive_handle
) == EXIT_SUCCESS
) {
358 archive_handle
->action_header(/*archive_handle->*/ file_header
);
359 /* Note that we kill the '/' only after action_header() */
360 /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */
362 archive_handle
->ah_flags
|= ARCHIVE_EXTRACT_QUIET
;
363 archive_handle
->action_data(archive_handle
);
364 llist_add_to(&(archive_handle
->passed
), file_header
->name
);
366 data_skip(archive_handle
);
367 free(file_header
->name
);
369 archive_handle
->offset
+= file_header
->size
;
371 free(file_header
->link_target
);
372 /* Do not free(file_header->name)! (why?) */
373 #if ENABLE_FEATURE_TAR_UNAME_GNAME
374 free(file_header
->uname
);
375 free(file_header
->gname
);