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 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 source tree.
26 /* TODO: security with -C DESTDIR option can be enhanced.
27 * Consider tar file created via:
28 * $ tar cvf bug.tar anything.txt
29 * $ ln -s /tmp symlink
30 * $ tar --append -f bug.tar symlink
33 * $ tar --append -f bug.tar symlink/evil.py
35 * This will result in an archive which contains:
36 * $ tar --list -f bug.tar
41 * Untarring it puts evil.py in '/tmp' even if the -C DESTDIR is given.
42 * This doesn't feel right, and IIRC GNU tar doesn't do that.
47 #include "bb_archive.h"
48 /* FIXME: Stop using this non-standard feature */
49 #ifndef FNM_LEADING_DIR
50 # define FNM_LEADING_DIR 0
54 //#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
55 #define DBG(...) ((void)0)
58 #define block_buf bb_common_bufsiz1
61 #if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2
62 /* Do not pass gzip flag to writeTarFile() */
63 #define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \
64 writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude)
68 #if ENABLE_FEATURE_TAR_CREATE
71 ** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
72 ** the only functions that deal with the HardLinkInfo structure.
73 ** Even these functions use the xxxHardLinkInfo() functions.
75 typedef struct HardLinkInfo
{
76 struct HardLinkInfo
*next
; /* Next entry in list */
77 dev_t dev
; /* Device number */
78 ino_t ino
; /* Inode number */
79 // short linkCount; /* (Hard) Link Count */
80 char name
[1]; /* Start of filename (must be last) */
83 /* Some info to be carried along when creating a new tarball */
84 typedef struct TarBallInfo
{
85 int tarFd
; /* Open-for-write file descriptor
87 int verboseFlag
; /* Whether to print extra stuff or not */
88 const llist_t
*excludeList
; /* List of files to not include */
89 HardLinkInfo
*hlInfoHead
; /* Hard Link Tracking Information */
90 HardLinkInfo
*hlInfo
; /* Hard Link Info for the current file */
91 //TODO: save only st_dev + st_ino
92 struct stat tarFileStatBuf
; /* Stat info for the tarball, letting
93 * us know the inode and device that the
94 * tarball lives, so we can avoid trying
95 * to include the tarball into itself */
98 /* A nice enum with all the possible tar file content types */
100 REGTYPE
= '0', /* regular file */
101 REGTYPE0
= '\0', /* regular file (ancient bug compat) */
102 LNKTYPE
= '1', /* hard link */
103 SYMTYPE
= '2', /* symbolic link */
104 CHRTYPE
= '3', /* character special */
105 BLKTYPE
= '4', /* block special */
106 DIRTYPE
= '5', /* directory */
107 FIFOTYPE
= '6', /* FIFO special */
108 CONTTYPE
= '7', /* reserved */
109 GNULONGLINK
= 'K', /* GNU long (>100 chars) link name */
110 GNULONGNAME
= 'L', /* GNU long (>100 chars) file name */
113 /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
114 static void addHardLinkInfo(HardLinkInfo
**hlInfoHeadPtr
,
115 struct stat
*statbuf
,
116 const char *fileName
)
118 /* Note: hlInfoHeadPtr can never be NULL! */
119 HardLinkInfo
*hlInfo
;
121 hlInfo
= xmalloc(sizeof(HardLinkInfo
) + strlen(fileName
));
122 hlInfo
->next
= *hlInfoHeadPtr
;
123 *hlInfoHeadPtr
= hlInfo
;
124 hlInfo
->dev
= statbuf
->st_dev
;
125 hlInfo
->ino
= statbuf
->st_ino
;
126 // hlInfo->linkCount = statbuf->st_nlink;
127 strcpy(hlInfo
->name
, fileName
);
130 static void freeHardLinkInfo(HardLinkInfo
**hlInfoHeadPtr
)
132 HardLinkInfo
*hlInfo
;
133 HardLinkInfo
*hlInfoNext
;
136 hlInfo
= *hlInfoHeadPtr
;
138 hlInfoNext
= hlInfo
->next
;
142 *hlInfoHeadPtr
= NULL
;
146 /* Might be faster (and bigger) if the dev/ino were stored in numeric order ;) */
147 static HardLinkInfo
*findHardLinkInfo(HardLinkInfo
*hlInfo
, struct stat
*statbuf
)
150 if (statbuf
->st_ino
== hlInfo
->ino
151 && statbuf
->st_dev
== hlInfo
->dev
153 DBG("found hardlink:'%s'", hlInfo
->name
);
156 hlInfo
= hlInfo
->next
;
161 /* Put an octal string into the specified buffer.
162 * The number is zero padded and possibly null terminated.
163 * Stores low-order bits only if whole value does not fit. */
164 static void putOctal(char *cp
, int len
, off_t value
)
166 char tempBuffer
[sizeof(off_t
)*3 + 1];
167 char *tempString
= tempBuffer
;
170 width
= sprintf(tempBuffer
, "%0*"OFF_FMT
"o", len
, value
);
171 tempString
+= (width
- len
);
173 /* If string has leading zeroes, we can drop one */
174 /* and field will have trailing '\0' */
175 /* (increases chances of compat with other tars) */
176 if (tempString
[0] == '0')
179 /* Copy the string to the field */
180 memcpy(cp
, tempString
, len
);
182 #define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
184 static void chksum_and_xwrite(int fd
, struct tar_header_t
* hp
)
186 /* POSIX says that checksum is done on unsigned bytes
187 * (Sun and HP-UX gets it wrong... more details in
189 const unsigned char *cp
;
192 strcpy(hp
->magic
, "ustar ");
194 /* Calculate and store the checksum (i.e., the sum of all of the bytes of
195 * the header). The checksum field must be filled with blanks for the
196 * calculation. The checksum field is formatted differently from the
197 * other fields: it has 6 digits, a null, then a space -- rather than
198 * digits, followed by a null like the other fields... */
199 memset(hp
->chksum
, ' ', sizeof(hp
->chksum
));
200 cp
= (const unsigned char *) hp
;
203 do { chksum
+= *cp
++; } while (--size
);
204 putOctal(hp
->chksum
, sizeof(hp
->chksum
)-1, chksum
);
206 /* Now write the header out to disk */
207 xwrite(fd
, hp
, sizeof(*hp
));
210 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
211 static void writeLongname(int fd
, int type
, const char *name
, int dir
)
213 static const struct {
214 char mode
[8]; /* 100-107 */
215 char uid
[8]; /* 108-115 */
216 char gid
[8]; /* 116-123 */
217 char size
[12]; /* 124-135 */
218 char mtime
[12]; /* 136-147 */
226 struct tar_header_t header
;
229 dir
= !!dir
; /* normalize: 0/1 */
230 size
= strlen(name
) + 1 + dir
; /* GNU tar uses strlen+1 */
231 /* + dir: account for possible '/' */
233 memset(&header
, 0, sizeof(header
));
234 strcpy(header
.name
, "././@LongLink");
235 memcpy(header
.mode
, prefilled
.mode
, sizeof(prefilled
));
236 PUT_OCTAL(header
.size
, size
);
237 header
.typeflag
= type
;
238 chksum_and_xwrite(fd
, &header
);
240 /* Write filename[/] and pad the block. */
241 /* dir=0: writes 'name<NUL>', pads */
242 /* dir=1: writes 'name', writes '/<NUL>', pads */
244 xwrite(fd
, name
, size
- dir
);
245 xwrite(fd
, "/", dir
);
246 size
= (-size
) & (TAR_BLOCK_SIZE
-1);
247 memset(&header
, 0, size
);
248 xwrite(fd
, &header
, size
);
252 /* Write out a tar header for the specified file/directory/whatever */
253 static int writeTarHeader(struct TarBallInfo
*tbInfo
,
254 const char *header_name
, const char *fileName
, struct stat
*statbuf
)
256 struct tar_header_t header
;
258 memset(&header
, 0, sizeof(header
));
260 strncpy(header
.name
, header_name
, sizeof(header
.name
));
262 /* POSIX says to mask mode with 07777. */
263 PUT_OCTAL(header
.mode
, statbuf
->st_mode
& 07777);
264 PUT_OCTAL(header
.uid
, statbuf
->st_uid
);
265 PUT_OCTAL(header
.gid
, statbuf
->st_gid
);
266 memset(header
.size
, '0', sizeof(header
.size
)-1); /* Regular file size is handled later */
267 /* users report that files with negative st_mtime cause trouble, so: */
268 PUT_OCTAL(header
.mtime
, statbuf
->st_mtime
>= 0 ? statbuf
->st_mtime
: 0);
270 /* Enter the user and group names */
271 safe_strncpy(header
.uname
, get_cached_username(statbuf
->st_uid
), sizeof(header
.uname
));
272 safe_strncpy(header
.gname
, get_cached_groupname(statbuf
->st_gid
), sizeof(header
.gname
));
274 if (tbInfo
->hlInfo
) {
275 /* This is a hard link */
276 header
.typeflag
= LNKTYPE
;
277 strncpy(header
.linkname
, tbInfo
->hlInfo
->name
,
278 sizeof(header
.linkname
));
279 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
280 /* Write out long linkname if needed */
281 if (header
.linkname
[sizeof(header
.linkname
)-1])
282 writeLongname(tbInfo
->tarFd
, GNULONGLINK
,
283 tbInfo
->hlInfo
->name
, 0);
285 } else if (S_ISLNK(statbuf
->st_mode
)) {
286 char *lpath
= xmalloc_readlink_or_warn(fileName
);
289 header
.typeflag
= SYMTYPE
;
290 strncpy(header
.linkname
, lpath
, sizeof(header
.linkname
));
291 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
292 /* Write out long linkname if needed */
293 if (header
.linkname
[sizeof(header
.linkname
)-1])
294 writeLongname(tbInfo
->tarFd
, GNULONGLINK
, lpath
, 0);
296 /* If it is larger than 100 bytes, bail out */
297 if (header
.linkname
[sizeof(header
.linkname
)-1]) {
299 bb_error_msg("names longer than "NAME_SIZE_STR
" chars not supported");
304 } else if (S_ISDIR(statbuf
->st_mode
)) {
305 header
.typeflag
= DIRTYPE
;
306 /* Append '/' only if there is a space for it */
307 if (!header
.name
[sizeof(header
.name
)-1])
308 header
.name
[strlen(header
.name
)] = '/';
309 } else if (S_ISCHR(statbuf
->st_mode
)) {
310 header
.typeflag
= CHRTYPE
;
311 PUT_OCTAL(header
.devmajor
, major(statbuf
->st_rdev
));
312 PUT_OCTAL(header
.devminor
, minor(statbuf
->st_rdev
));
313 } else if (S_ISBLK(statbuf
->st_mode
)) {
314 header
.typeflag
= BLKTYPE
;
315 PUT_OCTAL(header
.devmajor
, major(statbuf
->st_rdev
));
316 PUT_OCTAL(header
.devminor
, minor(statbuf
->st_rdev
));
317 } else if (S_ISFIFO(statbuf
->st_mode
)) {
318 header
.typeflag
= FIFOTYPE
;
319 } else if (S_ISREG(statbuf
->st_mode
)) {
320 /* header.size field is 12 bytes long */
321 /* Does octal-encoded size fit? */
322 uoff_t filesize
= statbuf
->st_size
;
323 if (sizeof(filesize
) <= 4
324 || filesize
<= (uoff_t
)0777777777777LL
326 PUT_OCTAL(header
.size
, filesize
);
328 /* Does base256-encoded size fit?
329 * It always does unless off_t is wider than 64 bits.
331 else if (ENABLE_FEATURE_TAR_GNU_EXTENSIONS
332 #if ULLONG_MAX > 0xffffffffffffffffLL /* 2^64-1 */
333 && (filesize
<= 0x3fffffffffffffffffffffffLL
)
336 /* GNU tar uses "base-256 encoding" for very large numbers.
337 * Encoding is binary, with highest bit always set as a marker
338 * and sign in next-highest bit:
340 * bf ff .. ff - largest positive number
341 * ff ff .. ff - minus 1
342 * c0 00 .. 00 - smallest negative number
344 char *p8
= header
.size
+ sizeof(header
.size
);
346 *--p8
= (uint8_t)filesize
;
348 } while (p8
!= header
.size
);
351 bb_error_msg_and_die("can't store file '%s' "
352 "of size %"OFF_FMT
"u, aborting",
353 fileName
, statbuf
->st_size
);
355 header
.typeflag
= REGTYPE
;
357 bb_error_msg("%s: unknown file type", fileName
);
361 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
362 /* Write out long name if needed */
363 /* (we, like GNU tar, output long linkname *before* long name) */
364 if (header
.name
[sizeof(header
.name
)-1])
365 writeLongname(tbInfo
->tarFd
, GNULONGNAME
,
366 header_name
, S_ISDIR(statbuf
->st_mode
));
369 /* Now write the header out to disk */
370 chksum_and_xwrite(tbInfo
->tarFd
, &header
);
372 /* Now do the verbose thing (or not) */
373 if (tbInfo
->verboseFlag
) {
376 /* If archive goes to stdout, verbose goes to stderr */
377 if (tbInfo
->tarFd
== STDOUT_FILENO
)
379 /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
380 /* We don't have such excesses here: for us "v" == "vv" */
381 /* '/' is probably a GNUism */
382 fprintf(vbFd
, "%s%s\n", header_name
,
383 S_ISDIR(statbuf
->st_mode
) ? "/" : "");
389 #if ENABLE_FEATURE_TAR_FROM
390 static int exclude_file(const llist_t
*excluded_files
, const char *file
)
392 while (excluded_files
) {
393 if (excluded_files
->data
[0] == '/') {
394 if (fnmatch(excluded_files
->data
, file
,
395 FNM_PATHNAME
| FNM_LEADING_DIR
) == 0)
400 for (p
= file
; p
[0] != '\0'; p
++) {
401 if ((p
== file
|| p
[-1] == '/')
403 && fnmatch(excluded_files
->data
, p
,
404 FNM_PATHNAME
| FNM_LEADING_DIR
) == 0
410 excluded_files
= excluded_files
->link
;
416 # define exclude_file(excluded_files, file) 0
419 static int FAST_FUNC
writeFileToTarball(const char *fileName
, struct stat
*statbuf
,
420 void *userData
, int depth UNUSED_PARAM
)
422 struct TarBallInfo
*tbInfo
= (struct TarBallInfo
*) userData
;
423 const char *header_name
;
424 int inputFileFd
= -1;
426 DBG("writeFileToTarball('%s')", fileName
);
428 /* Strip leading '/' and such (must be before memorizing hardlink's name) */
429 header_name
= strip_unsafe_prefix(fileName
);
431 if (header_name
[0] == '\0')
434 /* It is against the rules to archive a socket */
435 if (S_ISSOCK(statbuf
->st_mode
)) {
436 bb_error_msg("%s: socket ignored", fileName
);
441 * Check to see if we are dealing with a hard link.
443 * Treat the first occurance of a given dev/inode as a file while
444 * treating any additional occurances as hard links. This is done
445 * by adding the file information to the HardLinkInfo linked list.
447 tbInfo
->hlInfo
= NULL
;
448 if (!S_ISDIR(statbuf
->st_mode
) && statbuf
->st_nlink
> 1) {
449 DBG("'%s': st_nlink > 1", header_name
);
450 tbInfo
->hlInfo
= findHardLinkInfo(tbInfo
->hlInfoHead
, statbuf
);
451 if (tbInfo
->hlInfo
== NULL
) {
452 DBG("'%s': addHardLinkInfo", header_name
);
453 addHardLinkInfo(&tbInfo
->hlInfoHead
, statbuf
, header_name
);
457 /* It is a bad idea to store the archive we are in the process of creating,
458 * so check the device and inode to be sure that this particular file isn't
460 if (tbInfo
->tarFileStatBuf
.st_dev
== statbuf
->st_dev
461 && tbInfo
->tarFileStatBuf
.st_ino
== statbuf
->st_ino
463 bb_error_msg("%s: file is the archive; skipping", fileName
);
467 if (exclude_file(tbInfo
->excludeList
, header_name
))
470 #if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
471 if (strlen(header_name
) >= NAME_SIZE
) {
472 bb_error_msg("names longer than "NAME_SIZE_STR
" chars not supported");
477 /* Is this a regular file? */
478 if (tbInfo
->hlInfo
== NULL
&& S_ISREG(statbuf
->st_mode
)) {
479 /* open the file we want to archive, and make sure all is well */
480 inputFileFd
= open_or_warn(fileName
, O_RDONLY
);
481 if (inputFileFd
< 0) {
486 /* Add an entry to the tarball */
487 if (writeTarHeader(tbInfo
, header_name
, fileName
, statbuf
) == FALSE
) {
491 /* If it was a regular file, write out the body */
492 if (inputFileFd
>= 0) {
494 /* Write the file to the archive. */
495 /* We record size into header first, */
496 /* and then write out file. If file shrinks in between, */
497 /* tar will be corrupted. So we don't allow for that. */
498 /* NB: GNU tar 1.16 warns and pads with zeroes */
499 /* or even seeks back and updates header */
500 bb_copyfd_exact_size(inputFileFd
, tbInfo
->tarFd
, statbuf
->st_size
);
502 ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
503 ////if (readSize != statbuf->st_size && readSize >= 0) {
504 //// bb_error_msg_and_die("short read from %s, aborting", fileName);
507 /* Check that file did not grow in between? */
508 /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */
512 /* Pad the file up to the tar block size */
513 /* (a few tricks here in the name of code size) */
514 readSize
= (-(int)statbuf
->st_size
) & (TAR_BLOCK_SIZE
-1);
515 memset(block_buf
, 0, readSize
);
516 xwrite(tbInfo
->tarFd
, block_buf
, readSize
);
522 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
523 # if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
524 # define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
526 /* Don't inline: vfork scares gcc and pessimizes code */
527 static void NOINLINE
vfork_compressor(int tar_fd
, int gzip
)
530 # if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2
531 const char *zip_exec
= (gzip
== 1) ? "gzip" : "bzip2";
532 # elif ENABLE_FEATURE_SEAMLESS_GZ
533 const char *zip_exec
= "gzip";
534 # else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */
535 const char *zip_exec
= "bzip2";
537 // On Linux, vfork never unpauses parent early, although standard
538 // allows for that. Do we want to waste bytes checking for it?
539 # define WAIT_FOR_CHILD 0
540 volatile int vfork_exec_errno
= 0;
541 struct fd_pair gzipDataPipe
;
543 struct fd_pair gzipStatusPipe
;
544 xpiped_pair(gzipStatusPipe
);
546 xpiped_pair(gzipDataPipe
);
548 signal(SIGPIPE
, SIG_IGN
); /* we only want EPIPE on errors */
550 # if defined(__GNUC__) && __GNUC__
551 /* Avoid vfork clobbering */
559 /* NB: close _first_, then move fds! */
560 close(gzipDataPipe
.wr
);
562 close(gzipStatusPipe
.rd
);
563 /* gzipStatusPipe.wr will close only on exec -
564 * parent waits for this close to happen */
565 fcntl(gzipStatusPipe
.wr
, F_SETFD
, FD_CLOEXEC
);
567 xmove_fd(gzipDataPipe
.rd
, 0);
569 /* exec gzip/bzip2 program/applet */
570 BB_EXECLP(zip_exec
, zip_exec
, "-f", NULL
);
571 vfork_exec_errno
= errno
;
576 xmove_fd(gzipDataPipe
.wr
, tar_fd
);
577 close(gzipDataPipe
.rd
);
579 close(gzipStatusPipe
.wr
);
584 /* Wait until child execs (or fails to) */
585 n
= full_read(gzipStatusPipe
.rd
, &buf
, 1);
586 if (n
< 0 /* && errno == EAGAIN */)
587 continue; /* try it again */
589 close(gzipStatusPipe
.rd
);
591 if (vfork_exec_errno
) {
592 errno
= vfork_exec_errno
;
593 bb_perror_msg_and_die("can't execute '%s'", zip_exec
);
596 #endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */
599 /* gcc 4.2.1 inlines it, making code bigger */
600 static NOINLINE
int writeTarFile(int tar_fd
, int verboseFlag
,
601 int recurseFlags
, const llist_t
*include
,
602 const llist_t
*exclude
, int gzip
)
604 int errorFlag
= FALSE
;
605 struct TarBallInfo tbInfo
;
607 tbInfo
.hlInfoHead
= NULL
;
608 tbInfo
.tarFd
= tar_fd
;
609 tbInfo
.verboseFlag
= verboseFlag
;
611 /* Store the stat info for the tarball's file, so
612 * can avoid including the tarball into itself.... */
613 xfstat(tbInfo
.tarFd
, &tbInfo
.tarFileStatBuf
, "can't stat tar file");
615 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
617 vfork_compressor(tbInfo
.tarFd
, gzip
);
620 tbInfo
.excludeList
= exclude
;
622 /* Read the directory/files and iterate over them one at a time */
624 if (!recursive_action(include
->data
, recurseFlags
,
625 writeFileToTarball
, writeFileToTarball
, &tbInfo
, 0)
629 include
= include
->link
;
631 /* Write two empty blocks to the end of the archive */
632 memset(block_buf
, 0, 2*TAR_BLOCK_SIZE
);
633 xwrite(tbInfo
.tarFd
, block_buf
, 2*TAR_BLOCK_SIZE
);
635 /* To be pedantically correct, we would check if the tarball
636 * is smaller than 20 tar blocks, and pad it if it was smaller,
637 * but that isn't necessary for GNU tar interoperability, and
638 * so is considered a waste of space */
640 /* Close so the child process (if any) will exit */
643 /* Hang up the tools, close up shop, head home */
644 if (ENABLE_FEATURE_CLEAN_UP
)
645 freeHardLinkInfo(&tbInfo
.hlInfoHead
);
648 bb_error_msg("error exit delayed from previous errors");
650 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
653 if (safe_waitpid(-1, &status
, 0) == -1)
654 bb_perror_msg("waitpid");
655 else if (!WIFEXITED(status
) || WEXITSTATUS(status
))
656 /* gzip was killed or has exited with nonzero! */
663 int writeTarFile(int tar_fd
, int verboseFlag
,
664 int recurseFlags
, const llist_t
*include
,
665 const llist_t
*exclude
, int gzip
);
666 #endif /* FEATURE_TAR_CREATE */
668 #if ENABLE_FEATURE_TAR_FROM
669 static llist_t
*append_file_list_to_list(llist_t
*list
)
673 llist_t
*newlist
= NULL
;
676 src_stream
= xfopen_stdin(llist_pop(&list
));
677 while ((line
= xmalloc_fgetline(src_stream
)) != NULL
) {
678 /* kill trailing '/' unless the string is just "/" */
679 char *cp
= last_char_is(line
, '/');
682 llist_add_to(&newlist
, line
);
689 # define append_file_list_to_list(x) 0
692 //usage:#define tar_trivial_usage
693 //usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt"
694 //usage: IF_FEATURE_SEAMLESS_Z("Z")
695 //usage: IF_FEATURE_SEAMLESS_GZ("z")
696 //usage: IF_FEATURE_SEAMLESS_XZ("J")
697 //usage: IF_FEATURE_SEAMLESS_BZ2("j")
698 //usage: IF_FEATURE_SEAMLESS_LZMA("a")
699 //usage: IF_FEATURE_TAR_CREATE("h")
700 //usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m")
702 //usage: IF_FEATURE_TAR_FROM("[-X FILE] [-T FILE] ")
703 //usage: "[-f TARFILE] [-C DIR] [FILE]..."
704 //usage:#define tar_full_usage "\n\n"
705 //usage: IF_FEATURE_TAR_CREATE("Create, extract, ")
706 //usage: IF_NOT_FEATURE_TAR_CREATE("Extract ")
707 //usage: "or list files from a tar file\n"
708 //usage: "\nOperation:"
709 //usage: IF_FEATURE_TAR_CREATE(
710 //usage: "\n c Create"
712 //usage: "\n x Extract"
714 //usage: "\n f Name of TARFILE ('-' for stdin/out)"
715 //usage: "\n C Change to DIR before operation"
716 //usage: "\n v Verbose"
717 //usage: IF_FEATURE_SEAMLESS_Z(
718 //usage: "\n Z (De)compress using compress"
720 //usage: IF_FEATURE_SEAMLESS_GZ(
721 //usage: "\n z (De)compress using gzip"
723 //usage: IF_FEATURE_SEAMLESS_XZ(
724 //usage: "\n J (De)compress using xz"
726 //usage: IF_FEATURE_SEAMLESS_BZ2(
727 //usage: "\n j (De)compress using bzip2"
729 //usage: IF_FEATURE_SEAMLESS_LZMA(
730 //usage: "\n a (De)compress using lzma"
732 //usage: "\n O Extract to stdout"
733 //usage: IF_FEATURE_TAR_CREATE(
734 //usage: "\n h Follow symlinks"
736 //usage: IF_FEATURE_TAR_NOPRESERVE_TIME(
737 //usage: "\n m Don't restore mtime"
739 //usage: IF_FEATURE_TAR_FROM(
740 //usage: IF_FEATURE_TAR_LONG_OPTIONS(
741 //usage: "\n exclude File to exclude"
743 //usage: "\n X File with names to exclude"
744 //usage: "\n T File with names to include"
747 //usage:#define tar_example_usage
748 //usage: "$ zcat /tmp/tarball.tar.gz | tar -xf -\n"
749 //usage: "$ tar -cf /tmp/tarball.tar /usr/local\n"
751 // Supported but aren't in --help:
753 // p same-permissions
757 // no-same-permissions
759 //IF_FEATURE_TAR_TO_COMMAND(
765 IF_FEATURE_TAR_CREATE( OPTBIT_CREATE
,)
766 IF_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE
,)
767 IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2
,)
768 IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA
,)
769 IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM
,)
770 IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM
,)
771 IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP
,)
772 IF_FEATURE_SEAMLESS_XZ( OPTBIT_XZ
,) // 16th bit
773 IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS
,)
774 IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME
,)
775 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
777 IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND
,)
778 OPTBIT_NUMERIC_OWNER
,
779 OPTBIT_NOPRESERVE_PERM
,
782 OPT_TEST
= 1 << 0, // t
783 OPT_EXTRACT
= 1 << 1, // x
784 OPT_BASEDIR
= 1 << 2, // C
785 OPT_TARNAME
= 1 << 3, // f
786 OPT_2STDOUT
= 1 << 4, // O
787 OPT_NOPRESERVE_OWNER
= 1 << 5, // o == no-same-owner
789 OPT_VERBOSE
= 1 << 7, // v
790 OPT_KEEP_OLD
= 1 << 8, // k
791 OPT_CREATE
= IF_FEATURE_TAR_CREATE( (1 << OPTBIT_CREATE
)) + 0, // c
792 OPT_DEREFERENCE
= IF_FEATURE_TAR_CREATE( (1 << OPTBIT_DEREFERENCE
)) + 0, // h
793 OPT_BZIP2
= IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2
)) + 0, // j
794 OPT_LZMA
= IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA
)) + 0, // a
795 OPT_INCLUDE_FROM
= IF_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM
)) + 0, // T
796 OPT_EXCLUDE_FROM
= IF_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM
)) + 0, // X
797 OPT_GZIP
= IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP
)) + 0, // z
798 OPT_XZ
= IF_FEATURE_SEAMLESS_XZ( (1 << OPTBIT_XZ
)) + 0, // J
799 OPT_COMPRESS
= IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS
)) + 0, // Z
800 OPT_NOPRESERVE_TIME
= IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME
)) + 0, // m
801 OPT_NORECURSION
= IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION
)) + 0, // no-recursion
802 OPT_2COMMAND
= IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND
)) + 0, // to-command
803 OPT_NUMERIC_OWNER
= IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER
)) + 0, // numeric-owner
804 OPT_NOPRESERVE_PERM
= IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM
)) + 0, // no-same-permissions
805 OPT_OVERWRITE
= IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE
)) + 0, // overwrite
807 OPT_ANY_COMPRESS
= (OPT_BZIP2
| OPT_LZMA
| OPT_GZIP
| OPT_XZ
| OPT_COMPRESS
),
809 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
810 static const char tar_longopts
[] ALIGN1
=
811 "list\0" No_argument
"t"
812 "extract\0" No_argument
"x"
813 "directory\0" Required_argument
"C"
814 "file\0" Required_argument
"f"
815 "to-stdout\0" No_argument
"O"
816 /* do not restore owner */
817 /* Note: GNU tar handles 'o' as no-same-owner only on extract,
818 * on create, 'o' is --old-archive. We do not support --old-archive. */
819 "no-same-owner\0" No_argument
"o"
820 "same-permissions\0" No_argument
"p"
821 "verbose\0" No_argument
"v"
822 "keep-old\0" No_argument
"k"
823 # if ENABLE_FEATURE_TAR_CREATE
824 "create\0" No_argument
"c"
825 "dereference\0" No_argument
"h"
827 # if ENABLE_FEATURE_SEAMLESS_BZ2
828 "bzip2\0" No_argument
"j"
830 # if ENABLE_FEATURE_SEAMLESS_LZMA
831 "lzma\0" No_argument
"a"
833 # if ENABLE_FEATURE_TAR_FROM
834 "files-from\0" Required_argument
"T"
835 "exclude-from\0" Required_argument
"X"
837 # if ENABLE_FEATURE_SEAMLESS_GZ
838 "gzip\0" No_argument
"z"
840 # if ENABLE_FEATURE_SEAMLESS_XZ
841 "xz\0" No_argument
"J"
843 # if ENABLE_FEATURE_SEAMLESS_Z
844 "compress\0" No_argument
"Z"
846 # if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
847 "touch\0" No_argument
"m"
849 "no-recursion\0" No_argument
"\xfa"
850 # if ENABLE_FEATURE_TAR_TO_COMMAND
851 "to-command\0" Required_argument
"\xfb"
853 /* use numeric uid/gid from tar header, not textual */
854 "numeric-owner\0" No_argument
"\xfc"
855 /* do not restore mode */
856 "no-same-permissions\0" No_argument
"\xfd"
857 /* on unpack, open with O_TRUNC and !O_EXCL */
858 "overwrite\0" No_argument
"\xfe"
859 /* --exclude takes next bit position in option mask, */
860 /* therefore we have to put it _after_ --no-same-permissions */
861 # if ENABLE_FEATURE_TAR_FROM
862 "exclude\0" Required_argument
"\xff"
867 int tar_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
868 int tar_main(int argc UNUSED_PARAM
, char **argv
)
870 archive_handle_t
*tar_handle
;
871 char *base_dir
= NULL
;
872 const char *tar_filename
= "-";
875 #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
876 llist_t
*excludes
= NULL
;
879 /* Initialise default values */
880 tar_handle
= init_handle();
881 tar_handle
->ah_flags
= ARCHIVE_CREATE_LEADING_DIRS
882 | ARCHIVE_RESTORE_DATE
883 | ARCHIVE_UNLINK_OLD
;
885 /* Apparently only root's tar preserves perms (see bug 3844) */
887 tar_handle
->ah_flags
|= ARCHIVE_DONT_RESTORE_PERM
;
889 /* Prepend '-' to the first argument if required */
890 opt_complementary
= "--:" // first arg is options
891 "tt:vv:" // count -t,-v
892 IF_FEATURE_TAR_FROM("X::T::") // cumulative lists
893 #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
894 "\xff::" // cumulative lists for --exclude
896 IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
897 IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
898 IF_NOT_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
899 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
900 applet_long_options
= tar_longopts
;
903 if (argv
[1] && argv
[1][0] != '-') {
905 * 1st argument without dash handles options with parameters
906 * differently from dashed one: it takes *next argv[i]*
907 * as paramenter even if there are more chars in 1st argument:
908 * "tar fx TARFILE" - "x" is not taken as f's param
909 * but is interpreted as -x option
910 * "tar -xf TARFILE" - dashed equivalent of the above
911 * "tar -fx ..." - "x" is taken as f's param
912 * getopt32 wouldn't handle 1st command correctly.
913 * Unfortunately, people do use such commands.
914 * We massage argv[1] to work around it by moving 'f'
915 * to the end of the string.
916 * More contrived "tar fCx TARFILE DIR" still fails,
917 * but such commands are much less likely to be used.
919 char *f
= strchr(argv
[1], 'f');
921 while (f
[1] != '\0') {
931 IF_FEATURE_TAR_CREATE( "ch" )
932 IF_FEATURE_SEAMLESS_BZ2( "j" )
933 IF_FEATURE_SEAMLESS_LZMA("a" )
934 IF_FEATURE_TAR_FROM( "T:X:")
935 IF_FEATURE_SEAMLESS_GZ( "z" )
936 IF_FEATURE_SEAMLESS_XZ( "J" )
937 IF_FEATURE_SEAMLESS_Z( "Z" )
938 IF_FEATURE_TAR_NOPRESERVE_TIME("m")
939 , &base_dir
// -C dir
940 , &tar_filename
// -f filename
941 IF_FEATURE_TAR_FROM(, &(tar_handle
->accept
)) // T
942 IF_FEATURE_TAR_FROM(, &(tar_handle
->reject
)) // X
943 IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle
->tar__to_command
)) // --to-command
944 #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
945 , &excludes
// --exclude
947 , &verboseFlag
// combined count for -t and -v
948 , &verboseFlag
// combined count for -t and -v
950 //bb_error_msg("opt:%08x", opt);
953 if (verboseFlag
) tar_handle
->action_header
= header_verbose_list
;
954 if (verboseFlag
== 1) tar_handle
->action_header
= header_list
;
956 if (opt
& OPT_EXTRACT
)
957 tar_handle
->action_data
= data_extract_all
;
959 if (opt
& OPT_2STDOUT
)
960 tar_handle
->action_data
= data_extract_to_stdout
;
962 if (opt
& OPT_2COMMAND
) {
963 putenv((char*)"TAR_FILETYPE=f");
964 signal(SIGPIPE
, SIG_IGN
);
965 tar_handle
->action_data
= data_extract_to_command
;
966 IF_FEATURE_TAR_TO_COMMAND(tar_handle
->tar__to_command_shell
= xstrdup(get_shell_name());)
969 if (opt
& OPT_KEEP_OLD
)
970 tar_handle
->ah_flags
&= ~ARCHIVE_UNLINK_OLD
;
972 if (opt
& OPT_NUMERIC_OWNER
)
973 tar_handle
->ah_flags
|= ARCHIVE_NUMERIC_OWNER
;
975 if (opt
& OPT_NOPRESERVE_OWNER
)
976 tar_handle
->ah_flags
|= ARCHIVE_DONT_RESTORE_OWNER
;
978 if (opt
& OPT_NOPRESERVE_PERM
)
979 tar_handle
->ah_flags
|= ARCHIVE_DONT_RESTORE_PERM
;
981 if (opt
& OPT_OVERWRITE
) {
982 tar_handle
->ah_flags
&= ~ARCHIVE_UNLINK_OLD
;
983 tar_handle
->ah_flags
|= ARCHIVE_O_TRUNC
;
986 if (opt
& OPT_NOPRESERVE_TIME
)
987 tar_handle
->ah_flags
&= ~ARCHIVE_RESTORE_DATE
;
989 #if ENABLE_FEATURE_TAR_FROM
990 tar_handle
->reject
= append_file_list_to_list(tar_handle
->reject
);
991 # if ENABLE_FEATURE_TAR_LONG_OPTIONS
992 /* Append excludes to reject */
994 llist_t
*next
= excludes
->link
;
995 excludes
->link
= tar_handle
->reject
;
996 tar_handle
->reject
= excludes
;
1000 tar_handle
->accept
= append_file_list_to_list(tar_handle
->accept
);
1003 /* Setup an array of filenames to work with */
1004 /* TODO: This is the same as in ar, make a separate function? */
1006 /* kill trailing '/' unless the string is just "/" */
1007 char *cp
= last_char_is(*argv
, '/');
1010 llist_add_to_end(&tar_handle
->accept
, *argv
);
1014 if (tar_handle
->accept
|| tar_handle
->reject
)
1015 tar_handle
->filter
= filter_accept_reject_list
;
1017 /* Open the tar file */
1019 int tar_fd
= STDIN_FILENO
;
1020 int flags
= O_RDONLY
;
1022 if (opt
& OPT_CREATE
) {
1023 /* Make sure there is at least one file to tar up */
1024 if (tar_handle
->accept
== NULL
)
1025 bb_error_msg_and_die("empty archive");
1027 tar_fd
= STDOUT_FILENO
;
1028 /* Mimicking GNU tar 1.15.1: */
1029 flags
= O_WRONLY
| O_CREAT
| O_TRUNC
;
1032 if (LONE_DASH(tar_filename
)) {
1033 tar_handle
->src_fd
= tar_fd
;
1034 tar_handle
->seek
= seek_by_read
;
1036 if (ENABLE_FEATURE_TAR_AUTODETECT
1037 && flags
== O_RDONLY
1038 && !(opt
& OPT_ANY_COMPRESS
)
1040 tar_handle
->src_fd
= open_zipped(tar_filename
);
1041 if (tar_handle
->src_fd
< 0)
1042 bb_perror_msg_and_die("can't open '%s'", tar_filename
);
1044 tar_handle
->src_fd
= xopen(tar_filename
, flags
);
1052 //if (SEAMLESS_COMPRESSION || OPT_COMPRESS)
1053 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */
1054 // signal(SIGCHLD, check_errors_in_children);
1056 /* Create an archive */
1057 if (opt
& OPT_CREATE
) {
1058 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
1060 if (ENABLE_FEATURE_SEAMLESS_GZ
&& (opt
& OPT_GZIP
))
1062 if (ENABLE_FEATURE_SEAMLESS_BZ2
&& (opt
& OPT_BZIP2
))
1065 /* NB: writeTarFile() closes tar_handle->src_fd */
1066 return writeTarFile(tar_handle
->src_fd
, verboseFlag
,
1067 (opt
& OPT_DEREFERENCE
? ACTION_FOLLOWLINKS
: 0)
1068 | (opt
& OPT_NORECURSION
? 0 : ACTION_RECURSE
),
1070 tar_handle
->reject
, zipMode
);
1073 if (opt
& OPT_ANY_COMPRESS
) {
1074 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer
)(transformer_aux_data_t
*aux
, int src_fd
, int dst_fd
);)
1075 USE_FOR_NOMMU(const char *xformer_prog
;)
1077 if (opt
& OPT_COMPRESS
)
1078 USE_FOR_MMU(xformer
= unpack_Z_stream
;)
1079 USE_FOR_NOMMU(xformer_prog
= "uncompress";)
1081 USE_FOR_MMU(xformer
= unpack_gz_stream
;)
1082 USE_FOR_NOMMU(xformer_prog
= "gunzip";)
1083 if (opt
& OPT_BZIP2
)
1084 USE_FOR_MMU(xformer
= unpack_bz2_stream
;)
1085 USE_FOR_NOMMU(xformer_prog
= "bunzip2";)
1087 USE_FOR_MMU(xformer
= unpack_lzma_stream
;)
1088 USE_FOR_NOMMU(xformer_prog
= "unlzma";)
1090 USE_FOR_MMU(xformer
= unpack_xz_stream
;)
1091 USE_FOR_NOMMU(xformer_prog
= "unxz";)
1093 open_transformer_with_sig(tar_handle
->src_fd
, xformer
, xformer_prog
);
1094 /* Can't lseek over pipes */
1095 tar_handle
->seek
= seek_by_read
;
1096 /*tar_handle->offset = 0; - already is */
1099 while (get_header_tar(tar_handle
) == EXIT_SUCCESS
)
1102 /* Check that every file that should have been extracted was */
1103 while (tar_handle
->accept
) {
1104 if (!find_list_entry(tar_handle
->reject
, tar_handle
->accept
->data
)
1105 && !find_list_entry(tar_handle
->passed
, tar_handle
->accept
->data
)
1107 bb_error_msg_and_die("%s: not found in archive",
1108 tar_handle
->accept
->data
);
1110 tar_handle
->accept
= tar_handle
->accept
->link
;
1112 if (ENABLE_FEATURE_CLEAN_UP
/* && tar_handle->src_fd != STDIN_FILENO */)
1113 close(tar_handle
->src_fd
);
1115 if (SEAMLESS_COMPRESSION
|| OPT_COMPRESS
) {
1116 check_errors_in_children(0);
1117 return bb_got_signal
;
1119 return EXIT_SUCCESS
;