source: MondoRescue/branches/3.3/mindi-busybox/archival/tar.c@ 3803

Last change on this file since 3803 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 40.7 KB
RevLine 
[821]1/* vi: set sw=4 ts=4: */
2/*
3 * Mini tar implementation for busybox
4 *
5 * Modified to use common extraction code used by ar, cpio, dpkg-deb, dpkg
[2725]6 * by Glenn McGrath
[821]7 *
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.)
11 *
12 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
13 *
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.
[2725]18 * Permission to distribute sash derived code under GPL has been granted.
[821]19 *
20 * Based in part on the tar implementation from busybox-0.28
21 * Copyright (C) 1995 Bruce Perens
22 *
[2725]23 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
[821]24 */
[3232]25/* TODO: security with -C DESTDIR option can be enhanced.
26 * Consider tar file created via:
27 * $ tar cvf bug.tar anything.txt
28 * $ ln -s /tmp symlink
29 * $ tar --append -f bug.tar symlink
30 * $ rm symlink
31 * $ mkdir symlink
32 * $ tar --append -f bug.tar symlink/evil.py
33 *
34 * This will result in an archive which contains:
35 * $ tar --list -f bug.tar
36 * anything.txt
37 * symlink
38 * symlink/evil.py
39 *
40 * Untarring it puts evil.py in '/tmp' even if the -C DESTDIR is given.
41 * This doesn't feel right, and IIRC GNU tar doesn't do that.
42 */
43
[3621]44//config:config TAR
45//config: bool "tar"
46//config: default y
47//config: help
48//config: tar is an archiving program. It's commonly used with gzip to
49//config: create compressed archives. It's probably the most widely used
50//config: UNIX archive program.
51//config:
52//config:config FEATURE_TAR_CREATE
53//config: bool "Enable archive creation"
54//config: default y
55//config: depends on TAR
56//config: help
57//config: If you enable this option you'll be able to create
58//config: tar archives using the `-c' option.
59//config:
60//config:config FEATURE_TAR_AUTODETECT
61//config: bool "Autodetect compressed tarballs"
62//config: default y
63//config: depends on TAR && (FEATURE_SEAMLESS_Z || FEATURE_SEAMLESS_GZ || FEATURE_SEAMLESS_BZ2 || FEATURE_SEAMLESS_LZMA || FEATURE_SEAMLESS_XZ)
64//config: help
65//config: With this option tar can automatically detect compressed
66//config: tarballs. Currently it works only on files (not pipes etc).
67//config:
68//config:config FEATURE_TAR_FROM
69//config: bool "Enable -X (exclude from) and -T (include from) options)"
70//config: default y
71//config: depends on TAR
72//config: help
73//config: If you enable this option you'll be able to specify
74//config: a list of files to include or exclude from an archive.
75//config:
76//config:config FEATURE_TAR_OLDGNU_COMPATIBILITY
77//config: bool "Support for old tar header format"
78//config: default y
79//config: depends on TAR || DPKG
80//config: help
81//config: This option is required to unpack archives created in
82//config: the old GNU format; help to kill this old format by
83//config: repacking your ancient archives with the new format.
84//config:
85//config:config FEATURE_TAR_OLDSUN_COMPATIBILITY
86//config: bool "Enable untarring of tarballs with checksums produced by buggy Sun tar"
87//config: default y
88//config: depends on TAR || DPKG
89//config: help
90//config: This option is required to unpack archives created by some old
91//config: version of Sun's tar (it was calculating checksum using signed
92//config: arithmetic). It is said to be fixed in newer Sun tar, but "old"
93//config: tarballs still exist.
94//config:
95//config:config FEATURE_TAR_GNU_EXTENSIONS
96//config: bool "Support for GNU tar extensions (long filenames)"
97//config: default y
98//config: depends on TAR || DPKG
99//config: help
100//config: With this option busybox supports GNU long filenames and
101//config: linknames.
102//config:
103//config:config FEATURE_TAR_LONG_OPTIONS
104//config: bool "Enable long options"
105//config: default y
106//config: depends on TAR && LONG_OPTS
107//config: help
108//config: Enable use of long options, increases size by about 400 Bytes
109//config:
110//config:config FEATURE_TAR_TO_COMMAND
111//config: bool "Support for writing to an external program"
112//config: default y
113//config: depends on TAR && FEATURE_TAR_LONG_OPTIONS
114//config: help
115//config: If you enable this option you'll be able to instruct tar to send
116//config: the contents of each extracted file to the standard input of an
117//config: external program.
118//config:
119//config:config FEATURE_TAR_UNAME_GNAME
120//config: bool "Enable use of user and group names"
121//config: default y
122//config: depends on TAR
123//config: help
124//config: Enables use of user and group names in tar. This affects contents
125//config: listings (-t) and preserving permissions when unpacking (-p).
126//config: +200 bytes.
127//config:
128//config:config FEATURE_TAR_NOPRESERVE_TIME
129//config: bool "Enable -m (do not preserve time) option"
130//config: default y
131//config: depends on TAR
132//config: help
133//config: With this option busybox supports GNU tar -m
134//config: (do not preserve time) option.
135//config:
136//config:config FEATURE_TAR_SELINUX
137//config: bool "Support for extracting SELinux labels"
138//config: default n
139//config: depends on TAR && SELINUX
140//config: help
141//config: With this option busybox supports restoring SELinux labels
142//config: when extracting files from tar archives.
143
144//applet:IF_TAR(APPLET(tar, BB_DIR_BIN, BB_SUID_DROP))
145//kbuild:lib-$(CONFIG_TAR) += tar.o
146
[1765]147#include <fnmatch.h>
148#include "libbb.h"
[3621]149#include "common_bufsiz.h"
[3232]150#include "bb_archive.h"
[2725]151/* FIXME: Stop using this non-standard feature */
152#ifndef FNM_LEADING_DIR
153# define FNM_LEADING_DIR 0
154#endif
[821]155
[3621]156#if 0
157# define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
158#else
159# define DBG(...) ((void)0)
160#endif
161#define DBG_OPTION_PARSING 0
[2725]162
163
[1765]164#define block_buf bb_common_bufsiz1
[3621]165#define INIT_G() do { setup_common_bufsiz(); } while (0)
[821]166
[1765]167
[2725]168#if ENABLE_FEATURE_TAR_CREATE
[821]169
170/*
[1765]171** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
[821]172** the only functions that deal with the HardLinkInfo structure.
173** Even these functions use the xxxHardLinkInfo() functions.
174*/
[2725]175typedef struct HardLinkInfo {
176 struct HardLinkInfo *next; /* Next entry in list */
177 dev_t dev; /* Device number */
178 ino_t ino; /* Inode number */
179// short linkCount; /* (Hard) Link Count */
180 char name[1]; /* Start of filename (must be last) */
181} HardLinkInfo;
[821]182
183/* Some info to be carried along when creating a new tarball */
[2725]184typedef struct TarBallInfo {
185 int tarFd; /* Open-for-write file descriptor
186 * for the tarball */
187 int verboseFlag; /* Whether to print extra stuff or not */
188 const llist_t *excludeList; /* List of files to not include */
189 HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
190 HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
191//TODO: save only st_dev + st_ino
192 struct stat tarFileStatBuf; /* Stat info for the tarball, letting
193 * us know the inode and device that the
194 * tarball lives, so we can avoid trying
195 * to include the tarball into itself */
196} TarBallInfo;
[821]197
198/* A nice enum with all the possible tar file content types */
[2725]199enum {
[821]200 REGTYPE = '0', /* regular file */
201 REGTYPE0 = '\0', /* regular file (ancient bug compat) */
202 LNKTYPE = '1', /* hard link */
203 SYMTYPE = '2', /* symbolic link */
204 CHRTYPE = '3', /* character special */
205 BLKTYPE = '4', /* block special */
206 DIRTYPE = '5', /* directory */
207 FIFOTYPE = '6', /* FIFO special */
208 CONTTYPE = '7', /* reserved */
209 GNULONGLINK = 'K', /* GNU long (>100 chars) link name */
210 GNULONGNAME = 'L', /* GNU long (>100 chars) file name */
211};
212
213/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
[2725]214static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr,
[821]215 struct stat *statbuf,
[1765]216 const char *fileName)
[821]217{
218 /* Note: hlInfoHeadPtr can never be NULL! */
219 HardLinkInfo *hlInfo;
220
[1765]221 hlInfo = xmalloc(sizeof(HardLinkInfo) + strlen(fileName));
[821]222 hlInfo->next = *hlInfoHeadPtr;
223 *hlInfoHeadPtr = hlInfo;
224 hlInfo->dev = statbuf->st_dev;
225 hlInfo->ino = statbuf->st_ino;
[2725]226// hlInfo->linkCount = statbuf->st_nlink;
[1765]227 strcpy(hlInfo->name, fileName);
[821]228}
229
[2725]230static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr)
[821]231{
[1765]232 HardLinkInfo *hlInfo;
233 HardLinkInfo *hlInfoNext;
[821]234
235 if (hlInfoHeadPtr) {
236 hlInfo = *hlInfoHeadPtr;
237 while (hlInfo) {
238 hlInfoNext = hlInfo->next;
239 free(hlInfo);
240 hlInfo = hlInfoNext;
241 }
242 *hlInfoHeadPtr = NULL;
243 }
244}
245
[2725]246/* Might be faster (and bigger) if the dev/ino were stored in numeric order ;) */
247static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf)
[821]248{
249 while (hlInfo) {
[2725]250 if (statbuf->st_ino == hlInfo->ino
251 && statbuf->st_dev == hlInfo->dev
252 ) {
253 DBG("found hardlink:'%s'", hlInfo->name);
[821]254 break;
[2725]255 }
[821]256 hlInfo = hlInfo->next;
257 }
[1765]258 return hlInfo;
[821]259}
260
261/* Put an octal string into the specified buffer.
[1765]262 * The number is zero padded and possibly null terminated.
263 * Stores low-order bits only if whole value does not fit. */
264static void putOctal(char *cp, int len, off_t value)
[821]265{
[2725]266 char tempBuffer[sizeof(off_t)*3 + 1];
[821]267 char *tempString = tempBuffer;
[1765]268 int width;
[821]269
[1765]270 width = sprintf(tempBuffer, "%0*"OFF_FMT"o", len, value);
271 tempString += (width - len);
[821]272
[1765]273 /* If string has leading zeroes, we can drop one */
274 /* and field will have trailing '\0' */
275 /* (increases chances of compat with other tars) */
276 if (tempString[0] == '0')
[821]277 tempString++;
278
[1765]279 /* Copy the string to the field */
280 memcpy(cp, tempString, len);
281}
282#define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
[821]283
[2725]284static void chksum_and_xwrite(int fd, struct tar_header_t* hp)
[1765]285{
286 /* POSIX says that checksum is done on unsigned bytes
287 * (Sun and HP-UX gets it wrong... more details in
288 * GNU tar source) */
289 const unsigned char *cp;
290 int chksum, size;
[821]291
[1765]292 strcpy(hp->magic, "ustar ");
[821]293
[1765]294 /* Calculate and store the checksum (i.e., the sum of all of the bytes of
295 * the header). The checksum field must be filled with blanks for the
296 * calculation. The checksum field is formatted differently from the
297 * other fields: it has 6 digits, a null, then a space -- rather than
298 * digits, followed by a null like the other fields... */
299 memset(hp->chksum, ' ', sizeof(hp->chksum));
300 cp = (const unsigned char *) hp;
301 chksum = 0;
302 size = sizeof(*hp);
303 do { chksum += *cp++; } while (--size);
304 putOctal(hp->chksum, sizeof(hp->chksum)-1, chksum);
305
306 /* Now write the header out to disk */
307 xwrite(fd, hp, sizeof(*hp));
[821]308}
309
[1765]310#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
311static void writeLongname(int fd, int type, const char *name, int dir)
[821]312{
[1765]313 static const struct {
314 char mode[8]; /* 100-107 */
315 char uid[8]; /* 108-115 */
316 char gid[8]; /* 116-123 */
317 char size[12]; /* 124-135 */
318 char mtime[12]; /* 136-147 */
319 } prefilled = {
320 "0000000",
321 "0000000",
322 "0000000",
323 "00000000000",
324 "00000000000",
325 };
[2725]326 struct tar_header_t header;
[1765]327 int size;
[821]328
[1765]329 dir = !!dir; /* normalize: 0/1 */
330 size = strlen(name) + 1 + dir; /* GNU tar uses strlen+1 */
331 /* + dir: account for possible '/' */
332
333 memset(&header, 0, sizeof(header));
334 strcpy(header.name, "././@LongLink");
335 memcpy(header.mode, prefilled.mode, sizeof(prefilled));
336 PUT_OCTAL(header.size, size);
337 header.typeflag = type;
338 chksum_and_xwrite(fd, &header);
339
340 /* Write filename[/] and pad the block. */
341 /* dir=0: writes 'name<NUL>', pads */
342 /* dir=1: writes 'name', writes '/<NUL>', pads */
343 dir *= 2;
344 xwrite(fd, name, size - dir);
345 xwrite(fd, "/", dir);
346 size = (-size) & (TAR_BLOCK_SIZE-1);
[821]347 memset(&header, 0, size);
[1765]348 xwrite(fd, &header, size);
349}
350#endif
[821]351
[1765]352/* Write out a tar header for the specified file/directory/whatever */
353static int writeTarHeader(struct TarBallInfo *tbInfo,
354 const char *header_name, const char *fileName, struct stat *statbuf)
355{
[2725]356 struct tar_header_t header;
[821]357
[2725]358 memset(&header, 0, sizeof(header));
[821]359
[1765]360 strncpy(header.name, header_name, sizeof(header.name));
361
362 /* POSIX says to mask mode with 07777. */
363 PUT_OCTAL(header.mode, statbuf->st_mode & 07777);
364 PUT_OCTAL(header.uid, statbuf->st_uid);
365 PUT_OCTAL(header.gid, statbuf->st_gid);
366 memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */
[3232]367 /* users report that files with negative st_mtime cause trouble, so: */
368 PUT_OCTAL(header.mtime, statbuf->st_mtime >= 0 ? statbuf->st_mtime : 0);
[1765]369
370 /* Enter the user and group names */
371 safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname));
372 safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname));
373
[821]374 if (tbInfo->hlInfo) {
375 /* This is a hard link */
376 header.typeflag = LNKTYPE;
377 strncpy(header.linkname, tbInfo->hlInfo->name,
378 sizeof(header.linkname));
[1765]379#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
380 /* Write out long linkname if needed */
381 if (header.linkname[sizeof(header.linkname)-1])
382 writeLongname(tbInfo->tarFd, GNULONGLINK,
383 tbInfo->hlInfo->name, 0);
384#endif
[821]385 } else if (S_ISLNK(statbuf->st_mode)) {
[1765]386 char *lpath = xmalloc_readlink_or_warn(fileName);
387 if (!lpath)
388 return FALSE;
[821]389 header.typeflag = SYMTYPE;
390 strncpy(header.linkname, lpath, sizeof(header.linkname));
[1765]391#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
392 /* Write out long linkname if needed */
393 if (header.linkname[sizeof(header.linkname)-1])
394 writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0);
395#else
396 /* If it is larger than 100 bytes, bail out */
397 if (header.linkname[sizeof(header.linkname)-1]) {
398 free(lpath);
399 bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
400 return FALSE;
401 }
402#endif
[821]403 free(lpath);
404 } else if (S_ISDIR(statbuf->st_mode)) {
405 header.typeflag = DIRTYPE;
[1765]406 /* Append '/' only if there is a space for it */
407 if (!header.name[sizeof(header.name)-1])
408 header.name[strlen(header.name)] = '/';
[821]409 } else if (S_ISCHR(statbuf->st_mode)) {
410 header.typeflag = CHRTYPE;
[1765]411 PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
412 PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
[821]413 } else if (S_ISBLK(statbuf->st_mode)) {
414 header.typeflag = BLKTYPE;
[1765]415 PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
416 PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
[821]417 } else if (S_ISFIFO(statbuf->st_mode)) {
418 header.typeflag = FIFOTYPE;
419 } else if (S_ISREG(statbuf->st_mode)) {
[3232]420 /* header.size field is 12 bytes long */
421 /* Does octal-encoded size fit? */
422 uoff_t filesize = statbuf->st_size;
423 if (sizeof(filesize) <= 4
424 || filesize <= (uoff_t)0777777777777LL
[1765]425 ) {
[3232]426 PUT_OCTAL(header.size, filesize);
427 }
428 /* Does base256-encoded size fit?
429 * It always does unless off_t is wider than 64 bits.
430 */
431 else if (ENABLE_FEATURE_TAR_GNU_EXTENSIONS
432#if ULLONG_MAX > 0xffffffffffffffffLL /* 2^64-1 */
433 && (filesize <= 0x3fffffffffffffffffffffffLL)
434#endif
435 ) {
436 /* GNU tar uses "base-256 encoding" for very large numbers.
437 * Encoding is binary, with highest bit always set as a marker
438 * and sign in next-highest bit:
439 * 80 00 .. 00 - zero
440 * bf ff .. ff - largest positive number
441 * ff ff .. ff - minus 1
442 * c0 00 .. 00 - smallest negative number
443 */
444 char *p8 = header.size + sizeof(header.size);
445 do {
446 *--p8 = (uint8_t)filesize;
447 filesize >>= 8;
448 } while (p8 != header.size);
449 *p8 |= 0x80;
450 } else {
[2725]451 bb_error_msg_and_die("can't store file '%s' "
452 "of size %"OFF_FMT"u, aborting",
[1765]453 fileName, statbuf->st_size);
454 }
[821]455 header.typeflag = REGTYPE;
456 } else {
[1765]457 bb_error_msg("%s: unknown file type", fileName);
458 return FALSE;
[821]459 }
460
[1765]461#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
462 /* Write out long name if needed */
463 /* (we, like GNU tar, output long linkname *before* long name) */
464 if (header.name[sizeof(header.name)-1])
465 writeLongname(tbInfo->tarFd, GNULONGNAME,
466 header_name, S_ISDIR(statbuf->st_mode));
467#endif
[821]468
469 /* Now write the header out to disk */
[1765]470 chksum_and_xwrite(tbInfo->tarFd, &header);
471
[821]472 /* Now do the verbose thing (or not) */
473 if (tbInfo->verboseFlag) {
474 FILE *vbFd = stdout;
475
[2725]476 /* If archive goes to stdout, verbose goes to stderr */
477 if (tbInfo->tarFd == STDOUT_FILENO)
[821]478 vbFd = stderr;
[1765]479 /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
480 /* We don't have such excesses here: for us "v" == "vv" */
481 /* '/' is probably a GNUism */
482 fprintf(vbFd, "%s%s\n", header_name,
483 S_ISDIR(statbuf->st_mode) ? "/" : "");
[821]484 }
485
[1765]486 return TRUE;
[821]487}
488
[1765]489#if ENABLE_FEATURE_TAR_FROM
490static int exclude_file(const llist_t *excluded_files, const char *file)
[821]491{
492 while (excluded_files) {
493 if (excluded_files->data[0] == '/') {
494 if (fnmatch(excluded_files->data, file,
[2725]495 FNM_PATHNAME | FNM_LEADING_DIR) == 0)
[821]496 return 1;
497 } else {
498 const char *p;
499
500 for (p = file; p[0] != '\0'; p++) {
[2725]501 if ((p == file || p[-1] == '/')
502 && p[0] != '/'
503 && fnmatch(excluded_files->data, p,
504 FNM_PATHNAME | FNM_LEADING_DIR) == 0
505 ) {
[821]506 return 1;
[2725]507 }
[821]508 }
509 }
510 excluded_files = excluded_files->link;
511 }
512
513 return 0;
514}
[1765]515#else
[2725]516# define exclude_file(excluded_files, file) 0
[1765]517#endif
[821]518
[2725]519static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
520 void *userData, int depth UNUSED_PARAM)
[821]521{
522 struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
523 const char *header_name;
524 int inputFileFd = -1;
525
[2725]526 DBG("writeFileToTarball('%s')", fileName);
527
[3232]528 /* Strip leading '/' and such (must be before memorizing hardlink's name) */
529 header_name = strip_unsafe_prefix(fileName);
[2725]530
531 if (header_name[0] == '\0')
532 return TRUE;
533
534 /* It is against the rules to archive a socket */
535 if (S_ISSOCK(statbuf->st_mode)) {
536 bb_error_msg("%s: socket ignored", fileName);
537 return TRUE;
538 }
539
[821]540 /*
[1765]541 * Check to see if we are dealing with a hard link.
542 * If so -
543 * Treat the first occurance of a given dev/inode as a file while
544 * treating any additional occurances as hard links. This is done
545 * by adding the file information to the HardLinkInfo linked list.
[821]546 */
547 tbInfo->hlInfo = NULL;
[2725]548 if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) {
549 DBG("'%s': st_nlink > 1", header_name);
[821]550 tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
[2725]551 if (tbInfo->hlInfo == NULL) {
552 DBG("'%s': addHardLinkInfo", header_name);
553 addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
554 }
[821]555 }
556
557 /* It is a bad idea to store the archive we are in the process of creating,
558 * so check the device and inode to be sure that this particular file isn't
559 * the new tarball */
[2725]560 if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
561 && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
562 ) {
[821]563 bb_error_msg("%s: file is the archive; skipping", fileName);
[1765]564 return TRUE;
[821]565 }
566
[2725]567 if (exclude_file(tbInfo->excludeList, header_name))
568 return SKIP;
[821]569
[1765]570#if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
[2725]571 if (strlen(header_name) >= NAME_SIZE) {
[1765]572 bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
573 return TRUE;
[821]574 }
[1765]575#endif
[821]576
577 /* Is this a regular file? */
[1765]578 if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
[821]579 /* open the file we want to archive, and make sure all is well */
[1765]580 inputFileFd = open_or_warn(fileName, O_RDONLY);
581 if (inputFileFd < 0) {
582 return FALSE;
[821]583 }
584 }
585
586 /* Add an entry to the tarball */
587 if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
[1765]588 return FALSE;
[821]589 }
590
591 /* If it was a regular file, write out the body */
[1765]592 if (inputFileFd >= 0) {
593 size_t readSize;
594 /* Write the file to the archive. */
595 /* We record size into header first, */
596 /* and then write out file. If file shrinks in between, */
597 /* tar will be corrupted. So we don't allow for that. */
598 /* NB: GNU tar 1.16 warns and pads with zeroes */
599 /* or even seeks back and updates header */
600 bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
601 ////off_t readSize;
602 ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
603 ////if (readSize != statbuf->st_size && readSize >= 0) {
604 //// bb_error_msg_and_die("short read from %s, aborting", fileName);
605 ////}
[821]606
[1765]607 /* Check that file did not grow in between? */
608 /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */
609
[821]610 close(inputFileFd);
611
612 /* Pad the file up to the tar block size */
[1765]613 /* (a few tricks here in the name of code size) */
614 readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
615 memset(block_buf, 0, readSize);
616 xwrite(tbInfo->tarFd, block_buf, readSize);
[821]617 }
618
[1765]619 return TRUE;
[821]620}
621
[3621]622#if SEAMLESS_COMPRESSION
[2725]623/* Don't inline: vfork scares gcc and pessimizes code */
[3621]624static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
[821]625{
[2725]626 pid_t gzipPid;
[3621]627
[2725]628 // On Linux, vfork never unpauses parent early, although standard
629 // allows for that. Do we want to waste bytes checking for it?
630# define WAIT_FOR_CHILD 0
631 volatile int vfork_exec_errno = 0;
632 struct fd_pair gzipDataPipe;
633# if WAIT_FOR_CHILD
634 struct fd_pair gzipStatusPipe;
635 xpiped_pair(gzipStatusPipe);
636# endif
637 xpiped_pair(gzipDataPipe);
638
639 signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
640
641 gzipPid = xvfork();
642
643 if (gzipPid == 0) {
644 /* child */
645 /* NB: close _first_, then move fds! */
646 close(gzipDataPipe.wr);
647# if WAIT_FOR_CHILD
648 close(gzipStatusPipe.rd);
649 /* gzipStatusPipe.wr will close only on exec -
650 * parent waits for this close to happen */
651 fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
652# endif
653 xmove_fd(gzipDataPipe.rd, 0);
654 xmove_fd(tar_fd, 1);
655 /* exec gzip/bzip2 program/applet */
[3621]656 BB_EXECLP(gzip, gzip, "-f", (char *)0);
[2725]657 vfork_exec_errno = errno;
658 _exit(EXIT_FAILURE);
659 }
660
661 /* parent */
662 xmove_fd(gzipDataPipe.wr, tar_fd);
663 close(gzipDataPipe.rd);
664# if WAIT_FOR_CHILD
665 close(gzipStatusPipe.wr);
666 while (1) {
667 char buf;
668 int n;
669
670 /* Wait until child execs (or fails to) */
671 n = full_read(gzipStatusPipe.rd, &buf, 1);
672 if (n < 0 /* && errno == EAGAIN */)
673 continue; /* try it again */
674 }
675 close(gzipStatusPipe.rd);
676# endif
677 if (vfork_exec_errno) {
678 errno = vfork_exec_errno;
[3621]679 bb_perror_msg_and_die("can't execute '%s'", gzip);
[2725]680 }
681}
[3621]682#endif /* SEAMLESS_COMPRESSION */
[2725]683
684
[3621]685#if !SEAMLESS_COMPRESSION
686/* Do not pass gzip flag to writeTarFile() */
687#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \
688 writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude)
689#endif
[2725]690/* gcc 4.2.1 inlines it, making code bigger */
691static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
[3232]692 int recurseFlags, const llist_t *include,
[3621]693 const llist_t *exclude, const char *gzip)
[2725]694{
[821]695 int errorFlag = FALSE;
696 struct TarBallInfo tbInfo;
697
698 tbInfo.hlInfoHead = NULL;
699 tbInfo.tarFd = tar_fd;
700 tbInfo.verboseFlag = verboseFlag;
701
702 /* Store the stat info for the tarball's file, so
703 * can avoid including the tarball into itself.... */
[2725]704 xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file");
[821]705
[3621]706#if SEAMLESS_COMPRESSION
[2725]707 if (gzip)
708 vfork_compressor(tbInfo.tarFd, gzip);
[1765]709#endif
[821]710
711 tbInfo.excludeList = exclude;
712
713 /* Read the directory/files and iterate over them one at a time */
714 while (include) {
[3232]715 if (!recursive_action(include->data, recurseFlags,
[2725]716 writeFileToTarball, writeFileToTarball, &tbInfo, 0)
717 ) {
[821]718 errorFlag = TRUE;
719 }
720 include = include->link;
721 }
722 /* Write two empty blocks to the end of the archive */
[1765]723 memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
724 xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE);
[821]725
726 /* To be pedantically correct, we would check if the tarball
727 * is smaller than 20 tar blocks, and pad it if it was smaller,
728 * but that isn't necessary for GNU tar interoperability, and
729 * so is considered a waste of space */
730
731 /* Close so the child process (if any) will exit */
732 close(tbInfo.tarFd);
733
734 /* Hang up the tools, close up shop, head home */
735 if (ENABLE_FEATURE_CLEAN_UP)
736 freeHardLinkInfo(&tbInfo.hlInfoHead);
737
738 if (errorFlag)
[1765]739 bb_error_msg("error exit delayed from previous errors");
[821]740
[3621]741#if SEAMLESS_COMPRESSION
[2725]742 if (gzip) {
[1765]743 int status;
[2725]744 if (safe_waitpid(-1, &status, 0) == -1)
[1765]745 bb_perror_msg("waitpid");
746 else if (!WIFEXITED(status) || WEXITSTATUS(status))
747 /* gzip was killed or has exited with nonzero! */
748 errorFlag = TRUE;
749 }
[2725]750#endif
[1765]751 return errorFlag;
[821]752}
[3621]753#else /* !FEATURE_TAR_CREATE */
754# define writeTarFile(...) 0
755#endif
[821]756
[1765]757#if ENABLE_FEATURE_TAR_FROM
[821]758static llist_t *append_file_list_to_list(llist_t *list)
759{
760 FILE *src_stream;
761 char *line;
762 llist_t *newlist = NULL;
763
[2725]764 while (list) {
[3232]765 src_stream = xfopen_stdin(llist_pop(&list));
[2725]766 while ((line = xmalloc_fgetline(src_stream)) != NULL) {
[1765]767 /* kill trailing '/' unless the string is just "/" */
768 char *cp = last_char_is(line, '/');
769 if (cp > line)
770 *cp = '\0';
[3621]771 llist_add_to_end(&newlist, line);
[1765]772 }
[821]773 fclose(src_stream);
774 }
775 return newlist;
776}
777#endif
778
[2725]779//usage:#define tar_trivial_usage
[3232]780//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt"
781//usage: IF_FEATURE_SEAMLESS_Z("Z")
782//usage: IF_FEATURE_SEAMLESS_GZ("z")
783//usage: IF_FEATURE_SEAMLESS_XZ("J")
784//usage: IF_FEATURE_SEAMLESS_BZ2("j")
785//usage: IF_FEATURE_SEAMLESS_LZMA("a")
786//usage: IF_FEATURE_TAR_CREATE("h")
787//usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m")
788//usage: "vO] "
789//usage: IF_FEATURE_TAR_FROM("[-X FILE] [-T FILE] ")
790//usage: "[-f TARFILE] [-C DIR] [FILE]..."
[2725]791//usage:#define tar_full_usage "\n\n"
792//usage: IF_FEATURE_TAR_CREATE("Create, extract, ")
793//usage: IF_NOT_FEATURE_TAR_CREATE("Extract ")
794//usage: "or list files from a tar file\n"
795//usage: "\nOperation:"
796//usage: IF_FEATURE_TAR_CREATE(
797//usage: "\n c Create"
798//usage: )
799//usage: "\n x Extract"
800//usage: "\n t List"
801//usage: "\n f Name of TARFILE ('-' for stdin/out)"
802//usage: "\n C Change to DIR before operation"
803//usage: "\n v Verbose"
[3232]804//usage: IF_FEATURE_SEAMLESS_Z(
805//usage: "\n Z (De)compress using compress"
806//usage: )
[2725]807//usage: IF_FEATURE_SEAMLESS_GZ(
808//usage: "\n z (De)compress using gzip"
809//usage: )
[3232]810//usage: IF_FEATURE_SEAMLESS_XZ(
811//usage: "\n J (De)compress using xz"
812//usage: )
[2725]813//usage: IF_FEATURE_SEAMLESS_BZ2(
814//usage: "\n j (De)compress using bzip2"
815//usage: )
816//usage: IF_FEATURE_SEAMLESS_LZMA(
817//usage: "\n a (De)compress using lzma"
818//usage: )
819//usage: "\n O Extract to stdout"
820//usage: IF_FEATURE_TAR_CREATE(
821//usage: "\n h Follow symlinks"
822//usage: )
823//usage: IF_FEATURE_TAR_NOPRESERVE_TIME(
824//usage: "\n m Don't restore mtime"
825//usage: )
826//usage: IF_FEATURE_TAR_FROM(
827//usage: IF_FEATURE_TAR_LONG_OPTIONS(
828//usage: "\n exclude File to exclude"
829//usage: )
830//usage: "\n X File with names to exclude"
831//usage: "\n T File with names to include"
832//usage: )
833//usage:
834//usage:#define tar_example_usage
835//usage: "$ zcat /tmp/tarball.tar.gz | tar -xf -\n"
836//usage: "$ tar -cf /tmp/tarball.tar /usr/local\n"
837
838// Supported but aren't in --help:
839// o no-same-owner
840// p same-permissions
841// k keep-old
[3232]842// no-recursion
[2725]843// numeric-owner
844// no-same-permissions
845// overwrite
846//IF_FEATURE_TAR_TO_COMMAND(
847// to-command
848//)
849
[1765]850enum {
[2725]851 OPTBIT_KEEP_OLD = 8,
852 IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,)
853 IF_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE ,)
854 IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2 ,)
855 IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA ,)
856 IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,)
857 IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,)
858 IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP ,)
[3232]859 IF_FEATURE_SEAMLESS_XZ( OPTBIT_XZ ,) // 16th bit
860 IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,)
[2725]861 IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
862#if ENABLE_FEATURE_TAR_LONG_OPTIONS
[3621]863 OPTBIT_STRIP_COMPONENTS,
[3232]864 OPTBIT_NORECURSION,
[2725]865 IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,)
866 OPTBIT_NUMERIC_OWNER,
[1765]867 OPTBIT_NOPRESERVE_PERM,
[2725]868 OPTBIT_OVERWRITE,
869#endif
[1765]870 OPT_TEST = 1 << 0, // t
871 OPT_EXTRACT = 1 << 1, // x
872 OPT_BASEDIR = 1 << 2, // C
873 OPT_TARNAME = 1 << 3, // f
874 OPT_2STDOUT = 1 << 4, // O
[2725]875 OPT_NOPRESERVE_OWNER = 1 << 5, // o == no-same-owner
876 OPT_P = 1 << 6, // p
877 OPT_VERBOSE = 1 << 7, // v
878 OPT_KEEP_OLD = 1 << 8, // k
879 OPT_CREATE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_CREATE )) + 0, // c
880 OPT_DEREFERENCE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_DEREFERENCE )) + 0, // h
881 OPT_BZIP2 = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2 )) + 0, // j
882 OPT_LZMA = IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA )) + 0, // a
883 OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM)) + 0, // T
884 OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
885 OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0, // z
[3232]886 OPT_XZ = IF_FEATURE_SEAMLESS_XZ( (1 << OPTBIT_XZ )) + 0, // J
[2725]887 OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0, // Z
[3621]888 OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m
889 OPT_STRIP_COMPONENTS = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_STRIP_COMPONENTS)) + 0, // strip-components
890 OPT_NORECURSION = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION )) + 0, // no-recursion
891 OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0, // to-command
892 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner
893 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions
894 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite
[3232]895
896 OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_XZ | OPT_COMPRESS),
[1765]897};
898#if ENABLE_FEATURE_TAR_LONG_OPTIONS
899static const char tar_longopts[] ALIGN1 =
900 "list\0" No_argument "t"
901 "extract\0" No_argument "x"
902 "directory\0" Required_argument "C"
903 "file\0" Required_argument "f"
904 "to-stdout\0" No_argument "O"
[2725]905 /* do not restore owner */
906 /* Note: GNU tar handles 'o' as no-same-owner only on extract,
907 * on create, 'o' is --old-archive. We do not support --old-archive. */
908 "no-same-owner\0" No_argument "o"
[1765]909 "same-permissions\0" No_argument "p"
910 "verbose\0" No_argument "v"
911 "keep-old\0" No_argument "k"
912# if ENABLE_FEATURE_TAR_CREATE
913 "create\0" No_argument "c"
914 "dereference\0" No_argument "h"
[821]915# endif
[2725]916# if ENABLE_FEATURE_SEAMLESS_BZ2
[1765]917 "bzip2\0" No_argument "j"
[821]918# endif
[2725]919# if ENABLE_FEATURE_SEAMLESS_LZMA
[1765]920 "lzma\0" No_argument "a"
[821]921# endif
[1765]922# if ENABLE_FEATURE_TAR_FROM
923 "files-from\0" Required_argument "T"
924 "exclude-from\0" Required_argument "X"
[821]925# endif
[2725]926# if ENABLE_FEATURE_SEAMLESS_GZ
[1765]927 "gzip\0" No_argument "z"
[821]928# endif
[3232]929# if ENABLE_FEATURE_SEAMLESS_XZ
930 "xz\0" No_argument "J"
931# endif
[2725]932# if ENABLE_FEATURE_SEAMLESS_Z
[1765]933 "compress\0" No_argument "Z"
[821]934# endif
[2725]935# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
936 "touch\0" No_argument "m"
937# endif
[3621]938 "strip-components\0" Required_argument "\xf9"
[3232]939 "no-recursion\0" No_argument "\xfa"
[2725]940# if ENABLE_FEATURE_TAR_TO_COMMAND
941 "to-command\0" Required_argument "\xfb"
942# endif
943 /* use numeric uid/gid from tar header, not textual */
944 "numeric-owner\0" No_argument "\xfc"
945 /* do not restore mode */
946 "no-same-permissions\0" No_argument "\xfd"
947 /* on unpack, open with O_TRUNC and !O_EXCL */
948 "overwrite\0" No_argument "\xfe"
[1765]949 /* --exclude takes next bit position in option mask, */
[2725]950 /* therefore we have to put it _after_ --no-same-permissions */
[1765]951# if ENABLE_FEATURE_TAR_FROM
952 "exclude\0" Required_argument "\xff"
953# endif
954 ;
[821]955#endif
956
[2725]957int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
958int tar_main(int argc UNUSED_PARAM, char **argv)
[821]959{
960 archive_handle_t *tar_handle;
961 char *base_dir = NULL;
962 const char *tar_filename = "-";
[1765]963 unsigned opt;
964 int verboseFlag = 0;
965#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
[821]966 llist_t *excludes = NULL;
[1765]967#endif
[3621]968 INIT_G();
[821]969
970 /* Initialise default values */
971 tar_handle = init_handle();
[2725]972 tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
973 | ARCHIVE_RESTORE_DATE
974 | ARCHIVE_UNLINK_OLD;
[821]975
[2725]976 /* Apparently only root's tar preserves perms (see bug 3844) */
977 if (getuid() != 0)
978 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
979
[821]980 /* Prepend '-' to the first argument if required */
[1765]981 opt_complementary = "--:" // first arg is options
982 "tt:vv:" // count -t,-v
[3232]983 IF_FEATURE_TAR_FROM("X::T::") // cumulative lists
[1765]984#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
[3621]985 "\xff::" // --exclude=PATTERN is a list
[821]986#endif
[2725]987 IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
988 IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
[3621]989 IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive
[1765]990#if ENABLE_FEATURE_TAR_LONG_OPTIONS
[3621]991 ":\xf9+" // --strip-components=NUM
992#endif
993 ;
994#if ENABLE_FEATURE_TAR_LONG_OPTIONS
[1765]995 applet_long_options = tar_longopts;
996#endif
[2725]997#if ENABLE_DESKTOP
[3621]998 /* Lie to buildroot when it starts asking stupid questions. */
999 if (argv[1] && strcmp(argv[1], "--version") == 0) {
1000 // Output of 'tar --version' examples:
1001 // tar (GNU tar) 1.15.1
1002 // tar (GNU tar) 1.25
1003 // bsdtar 2.8.3 - libarchive 2.8.3
1004 puts("tar (busybox) " BB_VER);
1005 return 0;
1006 }
[2725]1007 if (argv[1] && argv[1][0] != '-') {
1008 /* Compat:
1009 * 1st argument without dash handles options with parameters
1010 * differently from dashed one: it takes *next argv[i]*
1011 * as paramenter even if there are more chars in 1st argument:
1012 * "tar fx TARFILE" - "x" is not taken as f's param
1013 * but is interpreted as -x option
1014 * "tar -xf TARFILE" - dashed equivalent of the above
1015 * "tar -fx ..." - "x" is taken as f's param
1016 * getopt32 wouldn't handle 1st command correctly.
1017 * Unfortunately, people do use such commands.
1018 * We massage argv[1] to work around it by moving 'f'
1019 * to the end of the string.
1020 * More contrived "tar fCx TARFILE DIR" still fails,
1021 * but such commands are much less likely to be used.
1022 */
1023 char *f = strchr(argv[1], 'f');
1024 if (f) {
1025 while (f[1] != '\0') {
1026 *f = f[1];
1027 f++;
1028 }
1029 *f = 'f';
1030 }
1031 }
1032#endif
[1765]1033 opt = getopt32(argv,
[2725]1034 "txC:f:Oopvk"
1035 IF_FEATURE_TAR_CREATE( "ch" )
1036 IF_FEATURE_SEAMLESS_BZ2( "j" )
1037 IF_FEATURE_SEAMLESS_LZMA("a" )
1038 IF_FEATURE_TAR_FROM( "T:X:")
1039 IF_FEATURE_SEAMLESS_GZ( "z" )
[3232]1040 IF_FEATURE_SEAMLESS_XZ( "J" )
[2725]1041 IF_FEATURE_SEAMLESS_Z( "Z" )
1042 IF_FEATURE_TAR_NOPRESERVE_TIME("m")
[3621]1043 IF_FEATURE_TAR_LONG_OPTIONS("\xf9:") // --strip-components
[1765]1044 , &base_dir // -C dir
1045 , &tar_filename // -f filename
[2725]1046 IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
1047 IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
[3621]1048#if ENABLE_FEATURE_TAR_LONG_OPTIONS
1049 , &tar_handle->tar__strip_components // --strip-components
1050#endif
[2725]1051 IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command
[1765]1052#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
1053 , &excludes // --exclude
1054#endif
1055 , &verboseFlag // combined count for -t and -v
1056 , &verboseFlag // combined count for -t and -v
1057 );
[3621]1058#if DBG_OPTION_PARSING
1059 bb_error_msg("opt: 0x%08x", opt);
1060# define showopt(o) bb_error_msg("opt & %s(%x): %x", #o, o, opt & o);
1061 showopt(OPT_TEST );
1062 showopt(OPT_EXTRACT );
1063 showopt(OPT_BASEDIR );
1064 showopt(OPT_TARNAME );
1065 showopt(OPT_2STDOUT );
1066 showopt(OPT_NOPRESERVE_OWNER);
1067 showopt(OPT_P );
1068 showopt(OPT_VERBOSE );
1069 showopt(OPT_KEEP_OLD );
1070 showopt(OPT_CREATE );
1071 showopt(OPT_DEREFERENCE );
1072 showopt(OPT_BZIP2 );
1073 showopt(OPT_LZMA );
1074 showopt(OPT_INCLUDE_FROM );
1075 showopt(OPT_EXCLUDE_FROM );
1076 showopt(OPT_GZIP );
1077 showopt(OPT_XZ );
1078 showopt(OPT_COMPRESS );
1079 showopt(OPT_NOPRESERVE_TIME );
1080 showopt(OPT_STRIP_COMPONENTS);
1081 showopt(OPT_NORECURSION );
1082 showopt(OPT_2COMMAND );
1083 showopt(OPT_NUMERIC_OWNER );
1084 showopt(OPT_NOPRESERVE_PERM );
1085 showopt(OPT_OVERWRITE );
1086 showopt(OPT_ANY_COMPRESS );
1087 bb_error_msg("base_dir:'%s'", base_dir);
1088 bb_error_msg("tar_filename:'%s'", tar_filename);
1089 bb_error_msg("verboseFlag:%d", verboseFlag);
1090 bb_error_msg("tar_handle->tar__to_command:'%s'", tar_handle->tar__to_command);
1091 bb_error_msg("tar_handle->tar__strip_components:%u", tar_handle->tar__strip_components);
1092 return 0;
1093# undef showopt
1094#endif
[2725]1095 argv += optind;
[821]1096
[3621]1097 if (verboseFlag)
1098 tar_handle->action_header = header_verbose_list;
1099 if (verboseFlag == 1)
1100 tar_handle->action_header = header_list;
[1765]1101
1102 if (opt & OPT_EXTRACT)
[821]1103 tar_handle->action_data = data_extract_all;
1104
[1765]1105 if (opt & OPT_2STDOUT)
[821]1106 tar_handle->action_data = data_extract_to_stdout;
1107
[2725]1108 if (opt & OPT_2COMMAND) {
1109 putenv((char*)"TAR_FILETYPE=f");
1110 signal(SIGPIPE, SIG_IGN);
1111 tar_handle->action_data = data_extract_to_command;
[3232]1112 IF_FEATURE_TAR_TO_COMMAND(tar_handle->tar__to_command_shell = xstrdup(get_shell_name());)
[2725]1113 }
1114
[1765]1115 if (opt & OPT_KEEP_OLD)
[2725]1116 tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
[821]1117
[2725]1118 if (opt & OPT_NUMERIC_OWNER)
1119 tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER;
[821]1120
[2725]1121 if (opt & OPT_NOPRESERVE_OWNER)
1122 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_OWNER;
1123
[1765]1124 if (opt & OPT_NOPRESERVE_PERM)
[2725]1125 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
[821]1126
[2725]1127 if (opt & OPT_OVERWRITE) {
1128 tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
1129 tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
1130 }
1131
1132 if (opt & OPT_NOPRESERVE_TIME)
1133 tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE;
1134
[1765]1135#if ENABLE_FEATURE_TAR_FROM
1136 tar_handle->reject = append_file_list_to_list(tar_handle->reject);
[2725]1137# if ENABLE_FEATURE_TAR_LONG_OPTIONS
[1765]1138 /* Append excludes to reject */
1139 while (excludes) {
1140 llist_t *next = excludes->link;
1141 excludes->link = tar_handle->reject;
1142 tar_handle->reject = excludes;
1143 excludes = next;
[821]1144 }
[2725]1145# endif
[1765]1146 tar_handle->accept = append_file_list_to_list(tar_handle->accept);
1147#endif
[821]1148
1149 /* Setup an array of filenames to work with */
[2725]1150 /* TODO: This is the same as in ar, make a separate function? */
1151 while (*argv) {
[1765]1152 /* kill trailing '/' unless the string is just "/" */
[2725]1153 char *cp = last_char_is(*argv, '/');
1154 if (cp > *argv)
[1765]1155 *cp = '\0';
[2725]1156 llist_add_to_end(&tar_handle->accept, *argv);
1157 argv++;
[821]1158 }
1159
[1765]1160 if (tar_handle->accept || tar_handle->reject)
[821]1161 tar_handle->filter = filter_accept_reject_list;
1162
1163 /* Open the tar file */
1164 {
[2725]1165 int tar_fd = STDIN_FILENO;
1166 int flags = O_RDONLY;
[821]1167
[1765]1168 if (opt & OPT_CREATE) {
[2725]1169 /* Make sure there is at least one file to tar up */
[821]1170 if (tar_handle->accept == NULL)
1171 bb_error_msg_and_die("empty archive");
1172
[2725]1173 tar_fd = STDOUT_FILENO;
[1765]1174 /* Mimicking GNU tar 1.15.1: */
[2725]1175 flags = O_WRONLY | O_CREAT | O_TRUNC;
[821]1176 }
1177
[1765]1178 if (LONE_DASH(tar_filename)) {
[2725]1179 tar_handle->src_fd = tar_fd;
[1765]1180 tar_handle->seek = seek_by_read;
[821]1181 } else {
[2725]1182 if (ENABLE_FEATURE_TAR_AUTODETECT
1183 && flags == O_RDONLY
[3232]1184 && !(opt & OPT_ANY_COMPRESS)
[2725]1185 ) {
[3621]1186 tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0);
[2725]1187 if (tar_handle->src_fd < 0)
1188 bb_perror_msg_and_die("can't open '%s'", tar_filename);
1189 } else {
1190 tar_handle->src_fd = xopen(tar_filename, flags);
1191 }
[821]1192 }
1193 }
1194
1195 if (base_dir)
[1765]1196 xchdir(base_dir);
[821]1197
[3621]1198 //if (SEAMLESS_COMPRESSION)
[3232]1199 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */
1200 // signal(SIGCHLD, check_errors_in_children);
[1765]1201
[3621]1202#if ENABLE_FEATURE_TAR_CREATE
[2725]1203 /* Create an archive */
[1765]1204 if (opt & OPT_CREATE) {
[3621]1205# if SEAMLESS_COMPRESSION
1206 const char *zipMode = NULL;
1207 if (opt & OPT_COMPRESS)
1208 zipMode = "compress";
1209 if (opt & OPT_GZIP)
1210 zipMode = "gzip";
1211 if (opt & OPT_BZIP2)
1212 zipMode = "bzip2";
1213 if (opt & OPT_LZMA)
1214 zipMode = "lzma";
1215 if (opt & OPT_XZ)
1216 zipMode = "xz";
1217# endif
[1765]1218 /* NB: writeTarFile() closes tar_handle->src_fd */
[3232]1219 return writeTarFile(tar_handle->src_fd, verboseFlag,
1220 (opt & OPT_DEREFERENCE ? ACTION_FOLLOWLINKS : 0)
1221 | (opt & OPT_NORECURSION ? 0 : ACTION_RECURSE),
[821]1222 tar_handle->accept,
[1765]1223 tar_handle->reject, zipMode);
1224 }
[3621]1225#endif
[821]1226
[3232]1227 if (opt & OPT_ANY_COMPRESS) {
[3621]1228 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate);)
[3232]1229 USE_FOR_NOMMU(const char *xformer_prog;)
1230
1231 if (opt & OPT_COMPRESS)
1232 USE_FOR_MMU(xformer = unpack_Z_stream;)
1233 USE_FOR_NOMMU(xformer_prog = "uncompress";)
1234 if (opt & OPT_GZIP)
1235 USE_FOR_MMU(xformer = unpack_gz_stream;)
1236 USE_FOR_NOMMU(xformer_prog = "gunzip";)
1237 if (opt & OPT_BZIP2)
1238 USE_FOR_MMU(xformer = unpack_bz2_stream;)
1239 USE_FOR_NOMMU(xformer_prog = "bunzip2";)
1240 if (opt & OPT_LZMA)
1241 USE_FOR_MMU(xformer = unpack_lzma_stream;)
1242 USE_FOR_NOMMU(xformer_prog = "unlzma";)
1243 if (opt & OPT_XZ)
1244 USE_FOR_MMU(xformer = unpack_xz_stream;)
1245 USE_FOR_NOMMU(xformer_prog = "unxz";)
1246
[3621]1247 fork_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog);
[3232]1248 /* Can't lseek over pipes */
1249 tar_handle->seek = seek_by_read;
1250 /*tar_handle->offset = 0; - already is */
1251 }
1252
[3621]1253 /* Zero processed headers (== empty file) is not a valid tarball.
1254 * We (ab)use bb_got_signal as exitcode here,
1255 * because check_errors_in_children() uses _it_ as error indicator.
1256 */
1257 bb_got_signal = EXIT_FAILURE;
1258
[3232]1259 while (get_header_tar(tar_handle) == EXIT_SUCCESS)
[3621]1260 bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */
[1765]1261
1262 /* Check that every file that should have been extracted was */
1263 while (tar_handle->accept) {
1264 if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
1265 && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
1266 ) {
1267 bb_error_msg_and_die("%s: not found in archive",
1268 tar_handle->accept->data);
[821]1269 }
[1765]1270 tar_handle->accept = tar_handle->accept->link;
[821]1271 }
[1765]1272 if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */)
[821]1273 close(tar_handle->src_fd);
1274
[3232]1275 if (SEAMLESS_COMPRESSION || OPT_COMPRESS) {
[3621]1276 /* Set bb_got_signal to 1 if a child died with !0 exitcode */
[3232]1277 check_errors_in_children(0);
1278 }
[3621]1279
1280 return bb_got_signal;
[821]1281}
Note: See TracBrowser for help on using the repository browser.