1 /* vi: set sw=4 ts=4: */
3 * Mini tar implementation for busybox
5 * Modified to use common extraction code used by ar, cpio, dpkg-deb, dpkg
8 * Note, that as of BusyBox-0.43, tar has been completely rewritten from the
9 * ground up. It still has remnants of the old code lying about, but it is
10 * very different now (i.e., cleaner, less global variables, etc.)
12 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
14 * Based in part in the tar implementation in sash
15 * Copyright (c) 1999 by David I. Bell
16 * Permission is granted to use, distribute, or modify this source,
17 * provided that this copyright notice remains intact.
18 * Permission to distribute sash derived code under the GPL has been granted.
20 * Based in part on the tar implementation from busybox-0.28
21 * Copyright (C) 1995 Bruce Perens
23 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
28 #include "unarchive.h"
30 /* FIXME: Stop using this non-standard feature */
31 #ifndef FNM_LEADING_DIR
32 #define FNM_LEADING_DIR 0
36 #define block_buf bb_common_bufsiz1
39 #if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2
40 /* Do not pass gzip flag to writeTarFile() */
41 #define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \
42 writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude)
46 #if ENABLE_FEATURE_TAR_CREATE
48 /* Tar file constants */
50 #define TAR_BLOCK_SIZE 512
52 /* POSIX tar Header Block, from POSIX 1003.1-1990 */
54 #define NAME_SIZE_STR "100"
55 typedef struct TarHeader TarHeader
;
56 struct TarHeader
{ /* byte offset */
57 char name
[NAME_SIZE
]; /* 0-99 */
58 char mode
[8]; /* 100-107 */
59 char uid
[8]; /* 108-115 */
60 char gid
[8]; /* 116-123 */
61 char size
[12]; /* 124-135 */
62 char mtime
[12]; /* 136-147 */
63 char chksum
[8]; /* 148-155 */
64 char typeflag
; /* 156-156 */
65 char linkname
[NAME_SIZE
]; /* 157-256 */
66 /* POSIX: "ustar" NUL "00" */
67 /* GNU tar: "ustar " NUL */
68 /* Normally it's defined as magic[6] followed by
69 * version[2], but we put them together to save code.
71 char magic
[8]; /* 257-264 */
72 char uname
[32]; /* 265-296 */
73 char gname
[32]; /* 297-328 */
74 char devmajor
[8]; /* 329-336 */
75 char devminor
[8]; /* 337-344 */
76 char prefix
[155]; /* 345-499 */
77 char padding
[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */
81 ** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
82 ** the only functions that deal with the HardLinkInfo structure.
83 ** Even these functions use the xxxHardLinkInfo() functions.
85 typedef struct HardLinkInfo HardLinkInfo
;
87 HardLinkInfo
*next
; /* Next entry in list */
88 dev_t dev
; /* Device number */
89 ino_t ino
; /* Inode number */
90 short linkCount
; /* (Hard) Link Count */
91 char name
[1]; /* Start of filename (must be last) */
94 /* Some info to be carried along when creating a new tarball */
95 typedef struct TarBallInfo TarBallInfo
;
97 int tarFd
; /* Open-for-write file descriptor
99 struct stat statBuf
; /* Stat info for the tarball, letting
100 * us know the inode and device that the
101 * tarball lives, so we can avoid trying
102 * to include the tarball into itself */
103 int verboseFlag
; /* Whether to print extra stuff or not */
104 const llist_t
*excludeList
; /* List of files to not include */
105 HardLinkInfo
*hlInfoHead
; /* Hard Link Tracking Information */
106 HardLinkInfo
*hlInfo
; /* Hard Link Info for the current file */
109 /* A nice enum with all the possible tar file content types */
111 REGTYPE
= '0', /* regular file */
112 REGTYPE0
= '\0', /* regular file (ancient bug compat) */
113 LNKTYPE
= '1', /* hard link */
114 SYMTYPE
= '2', /* symbolic link */
115 CHRTYPE
= '3', /* character special */
116 BLKTYPE
= '4', /* block special */
117 DIRTYPE
= '5', /* directory */
118 FIFOTYPE
= '6', /* FIFO special */
119 CONTTYPE
= '7', /* reserved */
120 GNULONGLINK
= 'K', /* GNU long (>100 chars) link name */
121 GNULONGNAME
= 'L', /* GNU long (>100 chars) file name */
123 typedef enum TarFileType TarFileType
;
125 /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
126 static void addHardLinkInfo(HardLinkInfo
**hlInfoHeadPtr
,
127 struct stat
*statbuf
,
128 const char *fileName
)
130 /* Note: hlInfoHeadPtr can never be NULL! */
131 HardLinkInfo
*hlInfo
;
133 hlInfo
= xmalloc(sizeof(HardLinkInfo
) + strlen(fileName
));
134 hlInfo
->next
= *hlInfoHeadPtr
;
135 *hlInfoHeadPtr
= hlInfo
;
136 hlInfo
->dev
= statbuf
->st_dev
;
137 hlInfo
->ino
= statbuf
->st_ino
;
138 hlInfo
->linkCount
= statbuf
->st_nlink
;
139 strcpy(hlInfo
->name
, fileName
);
142 static void freeHardLinkInfo(HardLinkInfo
**hlInfoHeadPtr
)
144 HardLinkInfo
*hlInfo
;
145 HardLinkInfo
*hlInfoNext
;
148 hlInfo
= *hlInfoHeadPtr
;
150 hlInfoNext
= hlInfo
->next
;
154 *hlInfoHeadPtr
= NULL
;
158 /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
159 static HardLinkInfo
*findHardLinkInfo(HardLinkInfo
*hlInfo
, struct stat
*statbuf
)
162 if ((statbuf
->st_ino
== hlInfo
->ino
) && (statbuf
->st_dev
== hlInfo
->dev
))
164 hlInfo
= hlInfo
->next
;
169 /* Put an octal string into the specified buffer.
170 * The number is zero padded and possibly null terminated.
171 * Stores low-order bits only if whole value does not fit. */
172 static void putOctal(char *cp
, int len
, off_t value
)
174 char tempBuffer
[sizeof(off_t
)*3+1];
175 char *tempString
= tempBuffer
;
178 width
= sprintf(tempBuffer
, "%0*"OFF_FMT
"o", len
, value
);
179 tempString
+= (width
- len
);
181 /* If string has leading zeroes, we can drop one */
182 /* and field will have trailing '\0' */
183 /* (increases chances of compat with other tars) */
184 if (tempString
[0] == '0')
187 /* Copy the string to the field */
188 memcpy(cp
, tempString
, len
);
190 #define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
192 static void chksum_and_xwrite(int fd
, struct TarHeader
* hp
)
194 /* POSIX says that checksum is done on unsigned bytes
195 * (Sun and HP-UX gets it wrong... more details in
197 const unsigned char *cp
;
200 strcpy(hp
->magic
, "ustar ");
202 /* Calculate and store the checksum (i.e., the sum of all of the bytes of
203 * the header). The checksum field must be filled with blanks for the
204 * calculation. The checksum field is formatted differently from the
205 * other fields: it has 6 digits, a null, then a space -- rather than
206 * digits, followed by a null like the other fields... */
207 memset(hp
->chksum
, ' ', sizeof(hp
->chksum
));
208 cp
= (const unsigned char *) hp
;
211 do { chksum
+= *cp
++; } while (--size
);
212 putOctal(hp
->chksum
, sizeof(hp
->chksum
)-1, chksum
);
214 /* Now write the header out to disk */
215 xwrite(fd
, hp
, sizeof(*hp
));
218 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
219 static void writeLongname(int fd
, int type
, const char *name
, int dir
)
221 static const struct {
222 char mode
[8]; /* 100-107 */
223 char uid
[8]; /* 108-115 */
224 char gid
[8]; /* 116-123 */
225 char size
[12]; /* 124-135 */
226 char mtime
[12]; /* 136-147 */
234 struct TarHeader header
;
237 dir
= !!dir
; /* normalize: 0/1 */
238 size
= strlen(name
) + 1 + dir
; /* GNU tar uses strlen+1 */
239 /* + dir: account for possible '/' */
241 memset(&header
, 0, sizeof(header
));
242 strcpy(header
.name
, "././@LongLink");
243 memcpy(header
.mode
, prefilled
.mode
, sizeof(prefilled
));
244 PUT_OCTAL(header
.size
, size
);
245 header
.typeflag
= type
;
246 chksum_and_xwrite(fd
, &header
);
248 /* Write filename[/] and pad the block. */
249 /* dir=0: writes 'name<NUL>', pads */
250 /* dir=1: writes 'name', writes '/<NUL>', pads */
252 xwrite(fd
, name
, size
- dir
);
253 xwrite(fd
, "/", dir
);
254 size
= (-size
) & (TAR_BLOCK_SIZE
-1);
255 memset(&header
, 0, size
);
256 xwrite(fd
, &header
, size
);
260 /* Write out a tar header for the specified file/directory/whatever */
261 void BUG_tar_header_size(void);
262 static int writeTarHeader(struct TarBallInfo
*tbInfo
,
263 const char *header_name
, const char *fileName
, struct stat
*statbuf
)
265 struct TarHeader header
;
267 if (sizeof(header
) != 512)
268 BUG_tar_header_size();
270 memset(&header
, 0, sizeof(struct TarHeader
));
272 strncpy(header
.name
, header_name
, sizeof(header
.name
));
274 /* POSIX says to mask mode with 07777. */
275 PUT_OCTAL(header
.mode
, statbuf
->st_mode
& 07777);
276 PUT_OCTAL(header
.uid
, statbuf
->st_uid
);
277 PUT_OCTAL(header
.gid
, statbuf
->st_gid
);
278 memset(header
.size
, '0', sizeof(header
.size
)-1); /* Regular file size is handled later */
279 PUT_OCTAL(header
.mtime
, statbuf
->st_mtime
);
281 /* Enter the user and group names */
282 safe_strncpy(header
.uname
, get_cached_username(statbuf
->st_uid
), sizeof(header
.uname
));
283 safe_strncpy(header
.gname
, get_cached_groupname(statbuf
->st_gid
), sizeof(header
.gname
));
285 if (tbInfo
->hlInfo
) {
286 /* This is a hard link */
287 header
.typeflag
= LNKTYPE
;
288 strncpy(header
.linkname
, tbInfo
->hlInfo
->name
,
289 sizeof(header
.linkname
));
290 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
291 /* Write out long linkname if needed */
292 if (header
.linkname
[sizeof(header
.linkname
)-1])
293 writeLongname(tbInfo
->tarFd
, GNULONGLINK
,
294 tbInfo
->hlInfo
->name
, 0);
296 } else if (S_ISLNK(statbuf
->st_mode
)) {
297 char *lpath
= xmalloc_readlink_or_warn(fileName
);
300 header
.typeflag
= SYMTYPE
;
301 strncpy(header
.linkname
, lpath
, sizeof(header
.linkname
));
302 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
303 /* Write out long linkname if needed */
304 if (header
.linkname
[sizeof(header
.linkname
)-1])
305 writeLongname(tbInfo
->tarFd
, GNULONGLINK
, lpath
, 0);
307 /* If it is larger than 100 bytes, bail out */
308 if (header
.linkname
[sizeof(header
.linkname
)-1]) {
310 bb_error_msg("names longer than "NAME_SIZE_STR
" chars not supported");
315 } else if (S_ISDIR(statbuf
->st_mode
)) {
316 header
.typeflag
= DIRTYPE
;
317 /* Append '/' only if there is a space for it */
318 if (!header
.name
[sizeof(header
.name
)-1])
319 header
.name
[strlen(header
.name
)] = '/';
320 } else if (S_ISCHR(statbuf
->st_mode
)) {
321 header
.typeflag
= CHRTYPE
;
322 PUT_OCTAL(header
.devmajor
, major(statbuf
->st_rdev
));
323 PUT_OCTAL(header
.devminor
, minor(statbuf
->st_rdev
));
324 } else if (S_ISBLK(statbuf
->st_mode
)) {
325 header
.typeflag
= BLKTYPE
;
326 PUT_OCTAL(header
.devmajor
, major(statbuf
->st_rdev
));
327 PUT_OCTAL(header
.devminor
, minor(statbuf
->st_rdev
));
328 } else if (S_ISFIFO(statbuf
->st_mode
)) {
329 header
.typeflag
= FIFOTYPE
;
330 } else if (S_ISREG(statbuf
->st_mode
)) {
331 if (sizeof(statbuf
->st_size
) > 4
332 && statbuf
->st_size
> (off_t
)0777777777777LL
334 bb_error_msg_and_die("cannot store file '%s' "
335 "of size %"OFF_FMT
"d, aborting",
336 fileName
, statbuf
->st_size
);
338 header
.typeflag
= REGTYPE
;
339 PUT_OCTAL(header
.size
, statbuf
->st_size
);
341 bb_error_msg("%s: unknown file type", fileName
);
345 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
346 /* Write out long name if needed */
347 /* (we, like GNU tar, output long linkname *before* long name) */
348 if (header
.name
[sizeof(header
.name
)-1])
349 writeLongname(tbInfo
->tarFd
, GNULONGNAME
,
350 header_name
, S_ISDIR(statbuf
->st_mode
));
353 /* Now write the header out to disk */
354 chksum_and_xwrite(tbInfo
->tarFd
, &header
);
356 /* Now do the verbose thing (or not) */
357 if (tbInfo
->verboseFlag
) {
360 /* If archive goes to stdout, verbose goes to stderr */
361 if (tbInfo
->tarFd
== STDOUT_FILENO
)
363 /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
364 /* We don't have such excesses here: for us "v" == "vv" */
365 /* '/' is probably a GNUism */
366 fprintf(vbFd
, "%s%s\n", header_name
,
367 S_ISDIR(statbuf
->st_mode
) ? "/" : "");
373 #if ENABLE_FEATURE_TAR_FROM
374 static int exclude_file(const llist_t
*excluded_files
, const char *file
)
376 while (excluded_files
) {
377 if (excluded_files
->data
[0] == '/') {
378 if (fnmatch(excluded_files
->data
, file
,
379 FNM_PATHNAME
| FNM_LEADING_DIR
) == 0)
384 for (p
= file
; p
[0] != '\0'; p
++) {
385 if ((p
== file
|| p
[-1] == '/') && p
[0] != '/' &&
386 fnmatch(excluded_files
->data
, p
,
387 FNM_PATHNAME
| FNM_LEADING_DIR
) == 0)
391 excluded_files
= excluded_files
->link
;
397 #define exclude_file(excluded_files, file) 0
400 static int FAST_FUNC
writeFileToTarball(const char *fileName
, struct stat
*statbuf
,
401 void *userData
, int depth UNUSED_PARAM
)
403 struct TarBallInfo
*tbInfo
= (struct TarBallInfo
*) userData
;
404 const char *header_name
;
405 int inputFileFd
= -1;
407 /* Strip leading '/' (must be before memorizing hardlink's name) */
408 header_name
= fileName
;
409 while (header_name
[0] == '/') {
410 static smallint warned
;
413 bb_error_msg("removing leading '/' from member names");
419 if (header_name
[0] == '\0')
422 /* It is against the rules to archive a socket */
423 if (S_ISSOCK(statbuf
->st_mode
)) {
424 bb_error_msg("%s: socket ignored", fileName
);
429 * Check to see if we are dealing with a hard link.
431 * Treat the first occurance of a given dev/inode as a file while
432 * treating any additional occurances as hard links. This is done
433 * by adding the file information to the HardLinkInfo linked list.
435 tbInfo
->hlInfo
= NULL
;
436 if (statbuf
->st_nlink
> 1) {
437 tbInfo
->hlInfo
= findHardLinkInfo(tbInfo
->hlInfoHead
, statbuf
);
438 if (tbInfo
->hlInfo
== NULL
)
439 addHardLinkInfo(&tbInfo
->hlInfoHead
, statbuf
, header_name
);
442 /* It is a bad idea to store the archive we are in the process of creating,
443 * so check the device and inode to be sure that this particular file isn't
445 if (tbInfo
->statBuf
.st_dev
== statbuf
->st_dev
446 && tbInfo
->statBuf
.st_ino
== statbuf
->st_ino
448 bb_error_msg("%s: file is the archive; skipping", fileName
);
452 if (exclude_file(tbInfo
->excludeList
, header_name
))
455 #if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
456 if (strlen(header_name
) >= NAME_SIZE
) {
457 bb_error_msg("names longer than "NAME_SIZE_STR
" chars not supported");
462 /* Is this a regular file? */
463 if (tbInfo
->hlInfo
== NULL
&& S_ISREG(statbuf
->st_mode
)) {
464 /* open the file we want to archive, and make sure all is well */
465 inputFileFd
= open_or_warn(fileName
, O_RDONLY
);
466 if (inputFileFd
< 0) {
471 /* Add an entry to the tarball */
472 if (writeTarHeader(tbInfo
, header_name
, fileName
, statbuf
) == FALSE
) {
476 /* If it was a regular file, write out the body */
477 if (inputFileFd
>= 0) {
479 /* Write the file to the archive. */
480 /* We record size into header first, */
481 /* and then write out file. If file shrinks in between, */
482 /* tar will be corrupted. So we don't allow for that. */
483 /* NB: GNU tar 1.16 warns and pads with zeroes */
484 /* or even seeks back and updates header */
485 bb_copyfd_exact_size(inputFileFd
, tbInfo
->tarFd
, statbuf
->st_size
);
487 ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
488 ////if (readSize != statbuf->st_size && readSize >= 0) {
489 //// bb_error_msg_and_die("short read from %s, aborting", fileName);
492 /* Check that file did not grow in between? */
493 /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */
497 /* Pad the file up to the tar block size */
498 /* (a few tricks here in the name of code size) */
499 readSize
= (-(int)statbuf
->st_size
) & (TAR_BLOCK_SIZE
-1);
500 memset(block_buf
, 0, readSize
);
501 xwrite(tbInfo
->tarFd
, block_buf
, readSize
);
507 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
508 #if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
509 #define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
511 /* Don't inline: vfork scares gcc and pessimizes code */
512 static void NOINLINE
vfork_compressor(int tar_fd
, int gzip
)
515 #if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2
516 const char *zip_exec
= (gzip
== 1) ? "gzip" : "bzip2";
517 #elif ENABLE_FEATURE_SEAMLESS_GZ
518 const char *zip_exec
= "gzip";
519 #else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */
520 const char *zip_exec
= "bzip2";
522 // On Linux, vfork never unpauses parent early, although standard
523 // allows for that. Do we want to waste bytes checking for it?
524 #define WAIT_FOR_CHILD 0
525 volatile int vfork_exec_errno
= 0;
526 struct fd_pair gzipDataPipe
;
528 struct fd_pair gzipStatusPipe
;
529 xpiped_pair(gzipStatusPipe
);
531 xpiped_pair(gzipDataPipe
);
533 signal(SIGPIPE
, SIG_IGN
); /* we only want EPIPE on errors */
535 #if defined(__GNUC__) && __GNUC__
536 /* Avoid vfork clobbering */
542 bb_perror_msg_and_die("vfork");
546 /* NB: close _first_, then move fds! */
547 close(gzipDataPipe
.wr
);
549 close(gzipStatusPipe
.rd
);
550 /* gzipStatusPipe.wr will close only on exec -
551 * parent waits for this close to happen */
552 fcntl(gzipStatusPipe
.wr
, F_SETFD
, FD_CLOEXEC
);
554 xmove_fd(gzipDataPipe
.rd
, 0);
556 /* exec gzip/bzip2 program/applet */
557 BB_EXECLP(zip_exec
, zip_exec
, "-f", NULL
);
558 vfork_exec_errno
= errno
;
563 xmove_fd(gzipDataPipe
.wr
, tar_fd
);
564 close(gzipDataPipe
.rd
);
566 close(gzipStatusPipe
.wr
);
571 /* Wait until child execs (or fails to) */
572 n
= full_read(gzipStatusPipe
.rd
, &buf
, 1);
573 if (n
< 0 /* && errno == EAGAIN */)
574 continue; /* try it again */
576 close(gzipStatusPipe
.rd
);
578 if (vfork_exec_errno
) {
579 errno
= vfork_exec_errno
;
580 bb_perror_msg_and_die("cannot exec %s", zip_exec
);
583 #endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */
586 /* gcc 4.2.1 inlines it, making code bigger */
587 static NOINLINE
int writeTarFile(int tar_fd
, int verboseFlag
,
588 int dereferenceFlag
, const llist_t
*include
,
589 const llist_t
*exclude
, int gzip
)
591 int errorFlag
= FALSE
;
592 struct TarBallInfo tbInfo
;
594 tbInfo
.hlInfoHead
= NULL
;
595 tbInfo
.tarFd
= tar_fd
;
596 tbInfo
.verboseFlag
= verboseFlag
;
598 /* Store the stat info for the tarball's file, so
599 * can avoid including the tarball into itself.... */
600 if (fstat(tbInfo
.tarFd
, &tbInfo
.statBuf
) < 0)
601 bb_perror_msg_and_die("cannot stat tar file");
603 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
605 vfork_compressor(tbInfo
.tarFd
, gzip
);
608 tbInfo
.excludeList
= exclude
;
610 /* Read the directory/files and iterate over them one at a time */
612 if (!recursive_action(include
->data
, ACTION_RECURSE
|
613 (dereferenceFlag
? ACTION_FOLLOWLINKS
: 0),
614 writeFileToTarball
, writeFileToTarball
, &tbInfo
, 0))
618 include
= include
->link
;
620 /* Write two empty blocks to the end of the archive */
621 memset(block_buf
, 0, 2*TAR_BLOCK_SIZE
);
622 xwrite(tbInfo
.tarFd
, block_buf
, 2*TAR_BLOCK_SIZE
);
624 /* To be pedantically correct, we would check if the tarball
625 * is smaller than 20 tar blocks, and pad it if it was smaller,
626 * but that isn't necessary for GNU tar interoperability, and
627 * so is considered a waste of space */
629 /* Close so the child process (if any) will exit */
632 /* Hang up the tools, close up shop, head home */
633 if (ENABLE_FEATURE_CLEAN_UP
)
634 freeHardLinkInfo(&tbInfo
.hlInfoHead
);
637 bb_error_msg("error exit delayed from previous errors");
639 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
642 if (safe_waitpid(-1, &status
, 0) == -1)
643 bb_perror_msg("waitpid");
644 else if (!WIFEXITED(status
) || WEXITSTATUS(status
))
645 /* gzip was killed or has exited with nonzero! */
652 int writeTarFile(int tar_fd
, int verboseFlag
,
653 int dereferenceFlag
, const llist_t
*include
,
654 const llist_t
*exclude
, int gzip
);
655 #endif /* FEATURE_TAR_CREATE */
657 #if ENABLE_FEATURE_TAR_FROM
658 static llist_t
*append_file_list_to_list(llist_t
*list
)
662 llist_t
*newlist
= NULL
;
665 src_stream
= xfopen_for_read(llist_pop(&list
));
666 while ((line
= xmalloc_fgetline(src_stream
)) != NULL
) {
667 /* kill trailing '/' unless the string is just "/" */
668 char *cp
= last_char_is(line
, '/');
671 llist_add_to(&newlist
, line
);
678 #define append_file_list_to_list(x) 0
681 #if ENABLE_FEATURE_SEAMLESS_Z
682 static char FAST_FUNC
get_header_tar_Z(archive_handle_t
*archive_handle
)
684 /* Can't lseek over pipes */
685 archive_handle
->seek
= seek_by_read
;
687 /* do the decompression, and cleanup */
688 if (xread_char(archive_handle
->src_fd
) != 0x1f
689 || xread_char(archive_handle
->src_fd
) != 0x9d
691 bb_error_msg_and_die("invalid magic");
694 open_transformer(archive_handle
->src_fd
, unpack_Z_stream
, "uncompress");
695 archive_handle
->offset
= 0;
696 while (get_header_tar(archive_handle
) == EXIT_SUCCESS
)
699 /* Can only do one file at a time */
703 #define get_header_tar_Z NULL
706 #ifdef CHECK_FOR_CHILD_EXITCODE
707 /* Looks like it isn't needed - tar detects malformed (truncated)
708 * archive if e.g. bunzip2 fails */
709 static int child_error
;
711 static void handle_SIGCHLD(int status
)
713 /* Actually, 'status' is a signo. We reuse it for other needs */
715 /* Wait for any child without blocking */
716 if (wait_any_nohang(&status
) < 0)
717 /* wait failed?! I'm confused... */
720 if (WIFEXITED(status
) && WEXITSTATUS(status
)==0)
721 /* child exited with 0 */
724 if (!WIFSIGNALED(status) && !WIFEXITED(status)) return; */
731 USE_FEATURE_TAR_CREATE( OPTBIT_CREATE
,)
732 USE_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE
,)
733 USE_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2
,)
734 USE_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA
,)
735 USE_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM
,)
736 USE_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM
,)
737 USE_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP
,)
738 USE_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS
,)
739 OPTBIT_NOPRESERVE_OWN
,
740 OPTBIT_NOPRESERVE_PERM
,
741 OPT_TEST
= 1 << 0, // t
742 OPT_EXTRACT
= 1 << 1, // x
743 OPT_BASEDIR
= 1 << 2, // C
744 OPT_TARNAME
= 1 << 3, // f
745 OPT_2STDOUT
= 1 << 4, // O
747 OPT_VERBOSE
= 1 << 6, // v
748 OPT_KEEP_OLD
= 1 << 7, // k
749 OPT_CREATE
= USE_FEATURE_TAR_CREATE( (1 << OPTBIT_CREATE
)) + 0, // c
750 OPT_DEREFERENCE
= USE_FEATURE_TAR_CREATE( (1 << OPTBIT_DEREFERENCE
)) + 0, // h
751 OPT_BZIP2
= USE_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2
)) + 0, // j
752 OPT_LZMA
= USE_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA
)) + 0, // a
753 OPT_INCLUDE_FROM
= USE_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM
)) + 0, // T
754 OPT_EXCLUDE_FROM
= USE_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM
)) + 0, // X
755 OPT_GZIP
= USE_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP
)) + 0, // z
756 OPT_COMPRESS
= USE_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS
)) + 0, // Z
757 OPT_NOPRESERVE_OWN
= 1 << OPTBIT_NOPRESERVE_OWN
, // no-same-owner
758 OPT_NOPRESERVE_PERM
= 1 << OPTBIT_NOPRESERVE_PERM
, // no-same-permissions
760 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
761 static const char tar_longopts
[] ALIGN1
=
762 "list\0" No_argument
"t"
763 "extract\0" No_argument
"x"
764 "directory\0" Required_argument
"C"
765 "file\0" Required_argument
"f"
766 "to-stdout\0" No_argument
"O"
767 "same-permissions\0" No_argument
"p"
768 "verbose\0" No_argument
"v"
769 "keep-old\0" No_argument
"k"
770 # if ENABLE_FEATURE_TAR_CREATE
771 "create\0" No_argument
"c"
772 "dereference\0" No_argument
"h"
774 # if ENABLE_FEATURE_SEAMLESS_BZ2
775 "bzip2\0" No_argument
"j"
777 # if ENABLE_FEATURE_SEAMLESS_LZMA
778 "lzma\0" No_argument
"a"
780 # if ENABLE_FEATURE_TAR_FROM
781 "files-from\0" Required_argument
"T"
782 "exclude-from\0" Required_argument
"X"
784 # if ENABLE_FEATURE_SEAMLESS_GZ
785 "gzip\0" No_argument
"z"
787 # if ENABLE_FEATURE_SEAMLESS_Z
788 "compress\0" No_argument
"Z"
790 "no-same-owner\0" No_argument
"\xfd"
791 "no-same-permissions\0" No_argument
"\xfe"
792 /* --exclude takes next bit position in option mask, */
793 /* therefore we have to either put it _after_ --no-same-perm */
794 /* or add OPT[BIT]_EXCLUDE before OPT[BIT]_NOPRESERVE_OWN */
795 # if ENABLE_FEATURE_TAR_FROM
796 "exclude\0" Required_argument
"\xff"
801 int tar_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
802 int tar_main(int argc UNUSED_PARAM
, char **argv
)
804 char FAST_FUNC (*get_header_ptr
)(archive_handle_t
*) = get_header_tar
;
805 archive_handle_t
*tar_handle
;
806 char *base_dir
= NULL
;
807 const char *tar_filename
= "-";
810 #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
811 llist_t
*excludes
= NULL
;
814 /* Initialise default values */
815 tar_handle
= init_handle();
816 tar_handle
->ah_flags
= ARCHIVE_CREATE_LEADING_DIRS
817 | ARCHIVE_PRESERVE_DATE
818 | ARCHIVE_EXTRACT_UNCONDITIONAL
;
820 /* Apparently only root's tar preserves perms (see bug 3844) */
822 tar_handle
->ah_flags
|= ARCHIVE_NOPRESERVE_PERM
;
824 /* Prepend '-' to the first argument if required */
825 opt_complementary
= "--:" // first arg is options
826 "tt:vv:" // count -t,-v
827 "?:" // bail out with usage instead of error return
828 "X::T::" // cumulative lists
829 #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
830 "\xff::" // cumulative lists for --exclude
832 USE_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
833 USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
834 SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
835 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
836 applet_long_options
= tar_longopts
;
840 USE_FEATURE_TAR_CREATE( "ch" )
841 USE_FEATURE_SEAMLESS_BZ2( "j" )
842 USE_FEATURE_SEAMLESS_LZMA("a" )
843 USE_FEATURE_TAR_FROM( "T:X:")
844 USE_FEATURE_SEAMLESS_GZ( "z" )
845 USE_FEATURE_SEAMLESS_Z( "Z" )
846 , &base_dir
// -C dir
847 , &tar_filename
// -f filename
848 USE_FEATURE_TAR_FROM(, &(tar_handle
->accept
)) // T
849 USE_FEATURE_TAR_FROM(, &(tar_handle
->reject
)) // X
850 #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
851 , &excludes
// --exclude
853 , &verboseFlag
// combined count for -t and -v
854 , &verboseFlag
// combined count for -t and -v
858 if (verboseFlag
) tar_handle
->action_header
= header_verbose_list
;
859 if (verboseFlag
== 1) tar_handle
->action_header
= header_list
;
861 if (opt
& OPT_EXTRACT
)
862 tar_handle
->action_data
= data_extract_all
;
864 if (opt
& OPT_2STDOUT
)
865 tar_handle
->action_data
= data_extract_to_stdout
;
867 if (opt
& OPT_KEEP_OLD
)
868 tar_handle
->ah_flags
&= ~ARCHIVE_EXTRACT_UNCONDITIONAL
;
870 if (opt
& OPT_NOPRESERVE_OWN
)
871 tar_handle
->ah_flags
|= ARCHIVE_NOPRESERVE_OWN
;
873 if (opt
& OPT_NOPRESERVE_PERM
)
874 tar_handle
->ah_flags
|= ARCHIVE_NOPRESERVE_PERM
;
877 get_header_ptr
= get_header_tar_gz
;
880 get_header_ptr
= get_header_tar_bz2
;
883 get_header_ptr
= get_header_tar_lzma
;
885 if (opt
& OPT_COMPRESS
)
886 get_header_ptr
= get_header_tar_Z
;
888 #if ENABLE_FEATURE_TAR_FROM
889 tar_handle
->reject
= append_file_list_to_list(tar_handle
->reject
);
890 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
891 /* Append excludes to reject */
893 llist_t
*next
= excludes
->link
;
894 excludes
->link
= tar_handle
->reject
;
895 tar_handle
->reject
= excludes
;
899 tar_handle
->accept
= append_file_list_to_list(tar_handle
->accept
);
902 /* Setup an array of filenames to work with */
903 /* TODO: This is the same as in ar, separate function ? */
905 /* kill trailing '/' unless the string is just "/" */
906 char *cp
= last_char_is(*argv
, '/');
909 llist_add_to_end(&tar_handle
->accept
, *argv
);
913 if (tar_handle
->accept
|| tar_handle
->reject
)
914 tar_handle
->filter
= filter_accept_reject_list
;
916 /* Open the tar file */
921 if (opt
& OPT_CREATE
) {
922 /* Make sure there is at least one file to tar up. */
923 if (tar_handle
->accept
== NULL
)
924 bb_error_msg_and_die("empty archive");
927 /* Mimicking GNU tar 1.15.1: */
928 flags
= O_WRONLY
| O_CREAT
| O_TRUNC
;
934 if (LONE_DASH(tar_filename
)) {
935 tar_handle
->src_fd
= fileno(tar_stream
);
936 tar_handle
->seek
= seek_by_read
;
938 if (ENABLE_FEATURE_TAR_AUTODETECT
&& flags
== O_RDONLY
) {
939 get_header_ptr
= get_header_tar
;
940 tar_handle
->src_fd
= open_zipped(tar_filename
);
941 if (tar_handle
->src_fd
< 0)
942 bb_perror_msg_and_die("can't open '%s'", tar_filename
);
944 tar_handle
->src_fd
= xopen(tar_filename
, flags
);
952 #ifdef CHECK_FOR_CHILD_EXITCODE
953 /* We need to know whether child (gzip/bzip/etc) exits abnormally */
954 signal(SIGCHLD
, handle_SIGCHLD
);
957 /* create an archive */
958 if (opt
& OPT_CREATE
) {
959 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
961 if (ENABLE_FEATURE_SEAMLESS_GZ
&& (opt
& OPT_GZIP
))
963 if (ENABLE_FEATURE_SEAMLESS_BZ2
&& (opt
& OPT_BZIP2
))
966 /* NB: writeTarFile() closes tar_handle->src_fd */
967 return writeTarFile(tar_handle
->src_fd
, verboseFlag
, opt
& OPT_DEREFERENCE
,
969 tar_handle
->reject
, zipMode
);
972 while (get_header_ptr(tar_handle
) == EXIT_SUCCESS
)
975 /* Check that every file that should have been extracted was */
976 while (tar_handle
->accept
) {
977 if (!find_list_entry(tar_handle
->reject
, tar_handle
->accept
->data
)
978 && !find_list_entry(tar_handle
->passed
, tar_handle
->accept
->data
)
980 bb_error_msg_and_die("%s: not found in archive",
981 tar_handle
->accept
->data
);
983 tar_handle
->accept
= tar_handle
->accept
->link
;
985 if (ENABLE_FEATURE_CLEAN_UP
/* && tar_handle->src_fd != STDIN_FILENO */)
986 close(tar_handle
->src_fd
);