Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/archival/tar.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1123 - (hide annotations) (download)
Wed Aug 18 21:56:57 2010 UTC (13 years, 8 months ago) by niro
File MIME type: text/plain
File size: 34472 byte(s)
-updated to busybox-1.17.1
1 niro 532 /* 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
6 niro 816 * by Glenn McGrath
7 niro 532 *
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.
18     * Permission to distribute sash derived code under the GPL has been granted.
19     *
20     * Based in part on the tar implementation from busybox-0.28
21     * Copyright (C) 1995 Bruce Perens
22     *
23     * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
24     */
25    
26     #include <fnmatch.h>
27 niro 816 #include "libbb.h"
28 niro 532 #include "unarchive.h"
29 niro 816 /* FIXME: Stop using this non-standard feature */
30     #ifndef FNM_LEADING_DIR
31 niro 984 # define FNM_LEADING_DIR 0
32 niro 816 #endif
33    
34    
35 niro 984 //#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
36     #define DBG(...) ((void)0)
37    
38    
39 niro 816 #define block_buf bb_common_bufsiz1
40    
41    
42     #if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2
43     /* Do not pass gzip flag to writeTarFile() */
44     #define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \
45     writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude)
46     #endif
47    
48    
49 niro 532 #if ENABLE_FEATURE_TAR_CREATE
50    
51     /*
52     ** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
53     ** the only functions that deal with the HardLinkInfo structure.
54     ** Even these functions use the xxxHardLinkInfo() functions.
55     */
56 niro 984 typedef struct HardLinkInfo {
57     struct HardLinkInfo *next; /* Next entry in list */
58     dev_t dev; /* Device number */
59     ino_t ino; /* Inode number */
60     // short linkCount; /* (Hard) Link Count */
61     char name[1]; /* Start of filename (must be last) */
62     } HardLinkInfo;
63 niro 532
64     /* Some info to be carried along when creating a new tarball */
65 niro 984 typedef struct TarBallInfo {
66 niro 816 int tarFd; /* Open-for-write file descriptor
67     * for the tarball */
68     int verboseFlag; /* Whether to print extra stuff or not */
69     const llist_t *excludeList; /* List of files to not include */
70     HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
71     HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
72 niro 984 //TODO: save only st_dev + st_ino
73     struct stat tarFileStatBuf; /* Stat info for the tarball, letting
74     * us know the inode and device that the
75     * tarball lives, so we can avoid trying
76     * to include the tarball into itself */
77     } TarBallInfo;
78 niro 532
79     /* A nice enum with all the possible tar file content types */
80 niro 984 enum {
81 niro 532 REGTYPE = '0', /* regular file */
82     REGTYPE0 = '\0', /* regular file (ancient bug compat) */
83     LNKTYPE = '1', /* hard link */
84     SYMTYPE = '2', /* symbolic link */
85     CHRTYPE = '3', /* character special */
86     BLKTYPE = '4', /* block special */
87     DIRTYPE = '5', /* directory */
88     FIFOTYPE = '6', /* FIFO special */
89     CONTTYPE = '7', /* reserved */
90     GNULONGLINK = 'K', /* GNU long (>100 chars) link name */
91     GNULONGNAME = 'L', /* GNU long (>100 chars) file name */
92     };
93    
94     /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
95 niro 816 static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr,
96 niro 532 struct stat *statbuf,
97     const char *fileName)
98     {
99     /* Note: hlInfoHeadPtr can never be NULL! */
100     HardLinkInfo *hlInfo;
101    
102     hlInfo = xmalloc(sizeof(HardLinkInfo) + strlen(fileName));
103     hlInfo->next = *hlInfoHeadPtr;
104     *hlInfoHeadPtr = hlInfo;
105     hlInfo->dev = statbuf->st_dev;
106     hlInfo->ino = statbuf->st_ino;
107 niro 984 // hlInfo->linkCount = statbuf->st_nlink;
108 niro 532 strcpy(hlInfo->name, fileName);
109     }
110    
111 niro 816 static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr)
112 niro 532 {
113     HardLinkInfo *hlInfo;
114     HardLinkInfo *hlInfoNext;
115    
116     if (hlInfoHeadPtr) {
117     hlInfo = *hlInfoHeadPtr;
118     while (hlInfo) {
119     hlInfoNext = hlInfo->next;
120     free(hlInfo);
121     hlInfo = hlInfoNext;
122     }
123     *hlInfoHeadPtr = NULL;
124     }
125     }
126    
127 niro 984 /* Might be faster (and bigger) if the dev/ino were stored in numeric order ;) */
128 niro 816 static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf)
129 niro 532 {
130     while (hlInfo) {
131 niro 984 if (statbuf->st_ino == hlInfo->ino
132     && statbuf->st_dev == hlInfo->dev
133     ) {
134     DBG("found hardlink:'%s'", hlInfo->name);
135 niro 532 break;
136 niro 984 }
137 niro 532 hlInfo = hlInfo->next;
138     }
139     return hlInfo;
140     }
141    
142     /* Put an octal string into the specified buffer.
143     * The number is zero padded and possibly null terminated.
144     * Stores low-order bits only if whole value does not fit. */
145     static void putOctal(char *cp, int len, off_t value)
146     {
147 niro 984 char tempBuffer[sizeof(off_t)*3 + 1];
148 niro 532 char *tempString = tempBuffer;
149     int width;
150    
151     width = sprintf(tempBuffer, "%0*"OFF_FMT"o", len, value);
152     tempString += (width - len);
153    
154     /* If string has leading zeroes, we can drop one */
155     /* and field will have trailing '\0' */
156     /* (increases chances of compat with other tars) */
157     if (tempString[0] == '0')
158     tempString++;
159    
160     /* Copy the string to the field */
161     memcpy(cp, tempString, len);
162     }
163     #define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
164    
165 niro 1123 static void chksum_and_xwrite(int fd, struct tar_header_t* hp)
166 niro 532 {
167 niro 816 /* POSIX says that checksum is done on unsigned bytes
168     * (Sun and HP-UX gets it wrong... more details in
169     * GNU tar source) */
170 niro 532 const unsigned char *cp;
171     int chksum, size;
172    
173     strcpy(hp->magic, "ustar ");
174    
175     /* Calculate and store the checksum (i.e., the sum of all of the bytes of
176     * the header). The checksum field must be filled with blanks for the
177     * calculation. The checksum field is formatted differently from the
178     * other fields: it has 6 digits, a null, then a space -- rather than
179     * digits, followed by a null like the other fields... */
180     memset(hp->chksum, ' ', sizeof(hp->chksum));
181     cp = (const unsigned char *) hp;
182     chksum = 0;
183     size = sizeof(*hp);
184     do { chksum += *cp++; } while (--size);
185     putOctal(hp->chksum, sizeof(hp->chksum)-1, chksum);
186    
187     /* Now write the header out to disk */
188     xwrite(fd, hp, sizeof(*hp));
189     }
190    
191     #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
192     static void writeLongname(int fd, int type, const char *name, int dir)
193     {
194     static const struct {
195     char mode[8]; /* 100-107 */
196     char uid[8]; /* 108-115 */
197     char gid[8]; /* 116-123 */
198     char size[12]; /* 124-135 */
199     char mtime[12]; /* 136-147 */
200     } prefilled = {
201     "0000000",
202     "0000000",
203     "0000000",
204     "00000000000",
205     "00000000000",
206     };
207 niro 1123 struct tar_header_t header;
208 niro 532 int size;
209    
210     dir = !!dir; /* normalize: 0/1 */
211     size = strlen(name) + 1 + dir; /* GNU tar uses strlen+1 */
212     /* + dir: account for possible '/' */
213    
214     memset(&header, 0, sizeof(header));
215     strcpy(header.name, "././@LongLink");
216     memcpy(header.mode, prefilled.mode, sizeof(prefilled));
217     PUT_OCTAL(header.size, size);
218     header.typeflag = type;
219     chksum_and_xwrite(fd, &header);
220    
221     /* Write filename[/] and pad the block. */
222     /* dir=0: writes 'name<NUL>', pads */
223     /* dir=1: writes 'name', writes '/<NUL>', pads */
224     dir *= 2;
225     xwrite(fd, name, size - dir);
226     xwrite(fd, "/", dir);
227     size = (-size) & (TAR_BLOCK_SIZE-1);
228     memset(&header, 0, size);
229     xwrite(fd, &header, size);
230     }
231     #endif
232    
233     /* Write out a tar header for the specified file/directory/whatever */
234     static int writeTarHeader(struct TarBallInfo *tbInfo,
235     const char *header_name, const char *fileName, struct stat *statbuf)
236     {
237 niro 1123 struct tar_header_t header;
238 niro 532
239 niro 1123 memset(&header, 0, sizeof(header));
240 niro 532
241     strncpy(header.name, header_name, sizeof(header.name));
242    
243     /* POSIX says to mask mode with 07777. */
244     PUT_OCTAL(header.mode, statbuf->st_mode & 07777);
245     PUT_OCTAL(header.uid, statbuf->st_uid);
246     PUT_OCTAL(header.gid, statbuf->st_gid);
247     memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */
248     PUT_OCTAL(header.mtime, statbuf->st_mtime);
249    
250     /* Enter the user and group names */
251     safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname));
252     safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname));
253    
254     if (tbInfo->hlInfo) {
255     /* This is a hard link */
256     header.typeflag = LNKTYPE;
257     strncpy(header.linkname, tbInfo->hlInfo->name,
258     sizeof(header.linkname));
259     #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
260     /* Write out long linkname if needed */
261     if (header.linkname[sizeof(header.linkname)-1])
262     writeLongname(tbInfo->tarFd, GNULONGLINK,
263     tbInfo->hlInfo->name, 0);
264     #endif
265     } else if (S_ISLNK(statbuf->st_mode)) {
266 niro 816 char *lpath = xmalloc_readlink_or_warn(fileName);
267     if (!lpath)
268 niro 532 return FALSE;
269     header.typeflag = SYMTYPE;
270     strncpy(header.linkname, lpath, sizeof(header.linkname));
271     #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
272     /* Write out long linkname if needed */
273     if (header.linkname[sizeof(header.linkname)-1])
274     writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0);
275     #else
276     /* If it is larger than 100 bytes, bail out */
277     if (header.linkname[sizeof(header.linkname)-1]) {
278     free(lpath);
279     bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
280     return FALSE;
281     }
282     #endif
283     free(lpath);
284     } else if (S_ISDIR(statbuf->st_mode)) {
285     header.typeflag = DIRTYPE;
286     /* Append '/' only if there is a space for it */
287     if (!header.name[sizeof(header.name)-1])
288     header.name[strlen(header.name)] = '/';
289     } else if (S_ISCHR(statbuf->st_mode)) {
290     header.typeflag = CHRTYPE;
291     PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
292     PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
293     } else if (S_ISBLK(statbuf->st_mode)) {
294     header.typeflag = BLKTYPE;
295     PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
296     PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
297     } else if (S_ISFIFO(statbuf->st_mode)) {
298     header.typeflag = FIFOTYPE;
299     } else if (S_ISREG(statbuf->st_mode)) {
300     if (sizeof(statbuf->st_size) > 4
301     && statbuf->st_size > (off_t)0777777777777LL
302     ) {
303 niro 984 bb_error_msg_and_die("can't store file '%s' "
304     "of size %"OFF_FMT"u, aborting",
305 niro 532 fileName, statbuf->st_size);
306     }
307     header.typeflag = REGTYPE;
308     PUT_OCTAL(header.size, statbuf->st_size);
309     } else {
310     bb_error_msg("%s: unknown file type", fileName);
311     return FALSE;
312     }
313    
314     #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
315     /* Write out long name if needed */
316     /* (we, like GNU tar, output long linkname *before* long name) */
317     if (header.name[sizeof(header.name)-1])
318     writeLongname(tbInfo->tarFd, GNULONGNAME,
319     header_name, S_ISDIR(statbuf->st_mode));
320     #endif
321    
322     /* Now write the header out to disk */
323     chksum_and_xwrite(tbInfo->tarFd, &header);
324    
325     /* Now do the verbose thing (or not) */
326     if (tbInfo->verboseFlag) {
327     FILE *vbFd = stdout;
328    
329 niro 984 /* If archive goes to stdout, verbose goes to stderr */
330     if (tbInfo->tarFd == STDOUT_FILENO)
331 niro 532 vbFd = stderr;
332     /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
333     /* We don't have such excesses here: for us "v" == "vv" */
334     /* '/' is probably a GNUism */
335     fprintf(vbFd, "%s%s\n", header_name,
336     S_ISDIR(statbuf->st_mode) ? "/" : "");
337     }
338    
339     return TRUE;
340     }
341    
342     #if ENABLE_FEATURE_TAR_FROM
343     static int exclude_file(const llist_t *excluded_files, const char *file)
344     {
345     while (excluded_files) {
346     if (excluded_files->data[0] == '/') {
347     if (fnmatch(excluded_files->data, file,
348 niro 984 FNM_PATHNAME | FNM_LEADING_DIR) == 0)
349 niro 532 return 1;
350     } else {
351     const char *p;
352    
353     for (p = file; p[0] != '\0'; p++) {
354 niro 984 if ((p == file || p[-1] == '/')
355     && p[0] != '/'
356     && fnmatch(excluded_files->data, p,
357     FNM_PATHNAME | FNM_LEADING_DIR) == 0
358     ) {
359 niro 532 return 1;
360 niro 984 }
361 niro 532 }
362     }
363     excluded_files = excluded_files->link;
364     }
365    
366     return 0;
367     }
368     #else
369 niro 984 # define exclude_file(excluded_files, file) 0
370 niro 532 #endif
371    
372 niro 816 static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
373     void *userData, int depth UNUSED_PARAM)
374 niro 532 {
375     struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
376     const char *header_name;
377     int inputFileFd = -1;
378    
379 niro 984 DBG("writeFileToTarball('%s')", fileName);
380    
381 niro 816 /* Strip leading '/' (must be before memorizing hardlink's name) */
382     header_name = fileName;
383     while (header_name[0] == '/') {
384     static smallint warned;
385    
386     if (!warned) {
387     bb_error_msg("removing leading '/' from member names");
388     warned = 1;
389     }
390     header_name++;
391     }
392    
393     if (header_name[0] == '\0')
394     return TRUE;
395    
396     /* It is against the rules to archive a socket */
397     if (S_ISSOCK(statbuf->st_mode)) {
398     bb_error_msg("%s: socket ignored", fileName);
399     return TRUE;
400     }
401    
402 niro 532 /*
403     * Check to see if we are dealing with a hard link.
404     * If so -
405     * Treat the first occurance of a given dev/inode as a file while
406     * treating any additional occurances as hard links. This is done
407     * by adding the file information to the HardLinkInfo linked list.
408     */
409     tbInfo->hlInfo = NULL;
410 niro 984 if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) {
411     DBG("'%s': st_nlink > 1", header_name);
412 niro 532 tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
413 niro 984 if (tbInfo->hlInfo == NULL) {
414     DBG("'%s': addHardLinkInfo", header_name);
415 niro 816 addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
416 niro 984 }
417 niro 532 }
418    
419     /* It is a bad idea to store the archive we are in the process of creating,
420     * so check the device and inode to be sure that this particular file isn't
421     * the new tarball */
422 niro 984 if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
423     && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
424 niro 816 ) {
425 niro 532 bb_error_msg("%s: file is the archive; skipping", fileName);
426     return TRUE;
427     }
428    
429 niro 816 if (exclude_file(tbInfo->excludeList, header_name))
430     return SKIP;
431 niro 532
432     #if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
433 niro 816 if (strlen(header_name) >= NAME_SIZE) {
434 niro 532 bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
435     return TRUE;
436     }
437     #endif
438    
439     /* Is this a regular file? */
440     if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
441     /* open the file we want to archive, and make sure all is well */
442 niro 816 inputFileFd = open_or_warn(fileName, O_RDONLY);
443 niro 532 if (inputFileFd < 0) {
444     return FALSE;
445     }
446     }
447    
448     /* Add an entry to the tarball */
449     if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
450     return FALSE;
451     }
452    
453     /* If it was a regular file, write out the body */
454     if (inputFileFd >= 0) {
455     size_t readSize;
456 niro 816 /* Write the file to the archive. */
457 niro 532 /* We record size into header first, */
458     /* and then write out file. If file shrinks in between, */
459     /* tar will be corrupted. So we don't allow for that. */
460     /* NB: GNU tar 1.16 warns and pads with zeroes */
461     /* or even seeks back and updates header */
462     bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
463     ////off_t readSize;
464     ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
465     ////if (readSize != statbuf->st_size && readSize >= 0) {
466     //// bb_error_msg_and_die("short read from %s, aborting", fileName);
467     ////}
468    
469     /* Check that file did not grow in between? */
470     /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */
471    
472     close(inputFileFd);
473    
474     /* Pad the file up to the tar block size */
475     /* (a few tricks here in the name of code size) */
476     readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
477 niro 816 memset(block_buf, 0, readSize);
478     xwrite(tbInfo->tarFd, block_buf, readSize);
479 niro 532 }
480    
481     return TRUE;
482     }
483    
484 niro 816 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
485 niro 984 # if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
486     # define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
487     # endif
488 niro 816 /* Don't inline: vfork scares gcc and pessimizes code */
489     static void NOINLINE vfork_compressor(int tar_fd, int gzip)
490 niro 532 {
491 niro 816 pid_t gzipPid;
492 niro 984 # if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2
493 niro 816 const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
494 niro 984 # elif ENABLE_FEATURE_SEAMLESS_GZ
495 niro 816 const char *zip_exec = "gzip";
496 niro 984 # else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */
497 niro 816 const char *zip_exec = "bzip2";
498 niro 984 # endif
499 niro 816 // On Linux, vfork never unpauses parent early, although standard
500     // allows for that. Do we want to waste bytes checking for it?
501 niro 984 # define WAIT_FOR_CHILD 0
502 niro 816 volatile int vfork_exec_errno = 0;
503     struct fd_pair gzipDataPipe;
504 niro 984 # if WAIT_FOR_CHILD
505 niro 816 struct fd_pair gzipStatusPipe;
506     xpiped_pair(gzipStatusPipe);
507 niro 984 # endif
508 niro 816 xpiped_pair(gzipDataPipe);
509    
510     signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
511    
512 niro 984 # if defined(__GNUC__) && __GNUC__
513 niro 816 /* Avoid vfork clobbering */
514     (void) &zip_exec;
515 niro 984 # endif
516 niro 816
517 niro 1123 gzipPid = xvfork();
518 niro 816
519     if (gzipPid == 0) {
520     /* child */
521     /* NB: close _first_, then move fds! */
522     close(gzipDataPipe.wr);
523 niro 984 # if WAIT_FOR_CHILD
524 niro 816 close(gzipStatusPipe.rd);
525     /* gzipStatusPipe.wr will close only on exec -
526     * parent waits for this close to happen */
527     fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
528 niro 984 # endif
529 niro 816 xmove_fd(gzipDataPipe.rd, 0);
530     xmove_fd(tar_fd, 1);
531     /* exec gzip/bzip2 program/applet */
532     BB_EXECLP(zip_exec, zip_exec, "-f", NULL);
533     vfork_exec_errno = errno;
534     _exit(EXIT_FAILURE);
535     }
536    
537     /* parent */
538     xmove_fd(gzipDataPipe.wr, tar_fd);
539     close(gzipDataPipe.rd);
540 niro 984 # if WAIT_FOR_CHILD
541 niro 816 close(gzipStatusPipe.wr);
542     while (1) {
543     char buf;
544     int n;
545    
546     /* Wait until child execs (or fails to) */
547     n = full_read(gzipStatusPipe.rd, &buf, 1);
548     if (n < 0 /* && errno == EAGAIN */)
549     continue; /* try it again */
550     }
551     close(gzipStatusPipe.rd);
552 niro 984 # endif
553 niro 816 if (vfork_exec_errno) {
554     errno = vfork_exec_errno;
555 niro 984 bb_perror_msg_and_die("can't execute '%s'", zip_exec);
556 niro 816 }
557     }
558     #endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */
559    
560    
561     /* gcc 4.2.1 inlines it, making code bigger */
562     static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
563     int dereferenceFlag, const llist_t *include,
564     const llist_t *exclude, int gzip)
565     {
566 niro 532 int errorFlag = FALSE;
567     struct TarBallInfo tbInfo;
568    
569     tbInfo.hlInfoHead = NULL;
570     tbInfo.tarFd = tar_fd;
571     tbInfo.verboseFlag = verboseFlag;
572    
573     /* Store the stat info for the tarball's file, so
574     * can avoid including the tarball into itself.... */
575 niro 984 if (fstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf) < 0)
576     bb_perror_msg_and_die("can't stat tar file");
577 niro 532
578 niro 816 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
579     if (gzip)
580     vfork_compressor(tbInfo.tarFd, gzip);
581 niro 532 #endif
582    
583     tbInfo.excludeList = exclude;
584    
585     /* Read the directory/files and iterate over them one at a time */
586     while (include) {
587 niro 816 if (!recursive_action(include->data, ACTION_RECURSE |
588     (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),
589 niro 984 writeFileToTarball, writeFileToTarball, &tbInfo, 0)
590     ) {
591 niro 532 errorFlag = TRUE;
592     }
593     include = include->link;
594     }
595     /* Write two empty blocks to the end of the archive */
596 niro 816 memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
597     xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE);
598 niro 532
599     /* To be pedantically correct, we would check if the tarball
600     * is smaller than 20 tar blocks, and pad it if it was smaller,
601     * but that isn't necessary for GNU tar interoperability, and
602     * so is considered a waste of space */
603    
604     /* Close so the child process (if any) will exit */
605     close(tbInfo.tarFd);
606    
607     /* Hang up the tools, close up shop, head home */
608     if (ENABLE_FEATURE_CLEAN_UP)
609     freeHardLinkInfo(&tbInfo.hlInfoHead);
610    
611     if (errorFlag)
612     bb_error_msg("error exit delayed from previous errors");
613    
614 niro 816 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
615     if (gzip) {
616 niro 532 int status;
617 niro 816 if (safe_waitpid(-1, &status, 0) == -1)
618 niro 532 bb_perror_msg("waitpid");
619     else if (!WIFEXITED(status) || WEXITSTATUS(status))
620     /* gzip was killed or has exited with nonzero! */
621     errorFlag = TRUE;
622     }
623 niro 816 #endif
624 niro 532 return errorFlag;
625     }
626     #else
627 niro 816 int writeTarFile(int tar_fd, int verboseFlag,
628     int dereferenceFlag, const llist_t *include,
629     const llist_t *exclude, int gzip);
630 niro 532 #endif /* FEATURE_TAR_CREATE */
631    
632     #if ENABLE_FEATURE_TAR_FROM
633     static llist_t *append_file_list_to_list(llist_t *list)
634     {
635     FILE *src_stream;
636     char *line;
637     llist_t *newlist = NULL;
638    
639 niro 816 while (list) {
640     src_stream = xfopen_for_read(llist_pop(&list));
641     while ((line = xmalloc_fgetline(src_stream)) != NULL) {
642 niro 532 /* kill trailing '/' unless the string is just "/" */
643     char *cp = last_char_is(line, '/');
644     if (cp > line)
645     *cp = '\0';
646     llist_add_to(&newlist, line);
647     }
648     fclose(src_stream);
649     }
650     return newlist;
651     }
652     #else
653 niro 984 # define append_file_list_to_list(x) 0
654 niro 532 #endif
655    
656 niro 816 #if ENABLE_FEATURE_SEAMLESS_Z
657     static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle)
658 niro 532 {
659     /* Can't lseek over pipes */
660     archive_handle->seek = seek_by_read;
661    
662     /* do the decompression, and cleanup */
663     if (xread_char(archive_handle->src_fd) != 0x1f
664     || xread_char(archive_handle->src_fd) != 0x9d
665     ) {
666     bb_error_msg_and_die("invalid magic");
667     }
668    
669 niro 816 open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress");
670 niro 532 archive_handle->offset = 0;
671     while (get_header_tar(archive_handle) == EXIT_SUCCESS)
672 niro 816 continue;
673 niro 532
674     /* Can only do one file at a time */
675     return EXIT_FAILURE;
676     }
677     #else
678 niro 984 # define get_header_tar_Z NULL
679 niro 532 #endif
680    
681     #ifdef CHECK_FOR_CHILD_EXITCODE
682     /* Looks like it isn't needed - tar detects malformed (truncated)
683     * archive if e.g. bunzip2 fails */
684     static int child_error;
685    
686     static void handle_SIGCHLD(int status)
687     {
688     /* Actually, 'status' is a signo. We reuse it for other needs */
689    
690     /* Wait for any child without blocking */
691 niro 816 if (wait_any_nohang(&status) < 0)
692 niro 532 /* wait failed?! I'm confused... */
693     return;
694    
695 niro 984 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
696 niro 532 /* child exited with 0 */
697     return;
698     /* Cannot happen?
699 niro 816 if (!WIFSIGNALED(status) && !WIFEXITED(status)) return; */
700 niro 532 child_error = 1;
701     }
702     #endif
703    
704 niro 1123 //usage:#define tar_trivial_usage
705     //usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" IF_FEATURE_SEAMLESS_GZ("z")
706     //usage: IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a")
707     //usage: IF_FEATURE_SEAMLESS_Z("Z") IF_FEATURE_TAR_NOPRESERVE_TIME("m") "vO] "
708     //usage: IF_FEATURE_TAR_FROM("[-X FILE] ")
709     //usage: "[-f TARFILE] [-C DIR] [FILE]..."
710     //usage:#define tar_full_usage "\n\n"
711     //usage: IF_FEATURE_TAR_CREATE("Create, extract, ")
712     //usage: IF_NOT_FEATURE_TAR_CREATE("Extract ")
713     //usage: "or list files from a tar file\n"
714     //usage: "\nOperation:"
715     //usage: IF_FEATURE_TAR_CREATE(
716     //usage: "\n c Create"
717     //usage: )
718     //usage: "\n x Extract"
719     //usage: "\n t List"
720     //usage: "\nOptions:"
721     //usage: "\n f Name of TARFILE ('-' for stdin/out)"
722     //usage: "\n C Change to DIR before operation"
723     //usage: "\n v Verbose"
724     //usage: IF_FEATURE_SEAMLESS_GZ(
725     //usage: "\n z (De)compress using gzip"
726     //usage: )
727     //usage: IF_FEATURE_SEAMLESS_BZ2(
728     //usage: "\n j (De)compress using bzip2"
729     //usage: )
730     //usage: IF_FEATURE_SEAMLESS_LZMA(
731     //usage: "\n a (De)compress using lzma"
732     //usage: )
733     //usage: IF_FEATURE_SEAMLESS_Z(
734     //usage: "\n Z (De)compress using compress"
735     //usage: )
736     //usage: "\n O Extract to stdout"
737     //usage: IF_FEATURE_TAR_CREATE(
738     //usage: "\n h Follow symlinks"
739     //usage: )
740     //usage: IF_FEATURE_TAR_NOPRESERVE_TIME(
741     //usage: "\n m Don't restore mtime"
742     //usage: )
743     //usage: IF_FEATURE_TAR_FROM(
744     //usage: IF_FEATURE_TAR_LONG_OPTIONS(
745     //usage: "\n exclude File to exclude"
746     //usage: )
747     //usage: "\n X File with names to exclude"
748     //usage: "\n T File with names to include"
749     //usage: )
750     //usage:
751     //usage:#define tar_example_usage
752     //usage: "$ zcat /tmp/tarball.tar.gz | tar -xf -\n"
753     //usage: "$ tar -cf /tmp/tarball.tar /usr/local\n"
754    
755     // Supported but aren't in --help:
756     // o no-same-owner
757     // p same-permissions
758     // k keep-old
759     // numeric-owner
760     // no-same-permissions
761     // overwrite
762     //IF_FEATURE_TAR_TO_COMMAND(
763     // to-command
764     //)
765    
766 niro 532 enum {
767 niro 984 OPTBIT_KEEP_OLD = 8,
768     IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,)
769     IF_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE ,)
770     IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2 ,)
771     IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA ,)
772     IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,)
773     IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,)
774     IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP ,)
775     IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,) // 16th bit
776     IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
777     #if ENABLE_FEATURE_TAR_LONG_OPTIONS
778 niro 1123 IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,)
779 niro 984 OPTBIT_NUMERIC_OWNER,
780 niro 532 OPTBIT_NOPRESERVE_PERM,
781 niro 984 OPTBIT_OVERWRITE,
782     #endif
783 niro 532 OPT_TEST = 1 << 0, // t
784     OPT_EXTRACT = 1 << 1, // x
785     OPT_BASEDIR = 1 << 2, // C
786     OPT_TARNAME = 1 << 3, // f
787     OPT_2STDOUT = 1 << 4, // O
788 niro 984 OPT_NOPRESERVE_OWNER = 1 << 5, // o == no-same-owner
789     OPT_P = 1 << 6, // p
790     OPT_VERBOSE = 1 << 7, // v
791     OPT_KEEP_OLD = 1 << 8, // k
792     OPT_CREATE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_CREATE )) + 0, // c
793     OPT_DEREFERENCE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_DEREFERENCE )) + 0, // h
794     OPT_BZIP2 = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2 )) + 0, // j
795     OPT_LZMA = IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA )) + 0, // a
796     OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM)) + 0, // T
797     OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
798     OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0, // z
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 niro 1123 OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0, // to-command
802 niro 984 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner
803     OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions
804     OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite
805 niro 532 };
806     #if ENABLE_FEATURE_TAR_LONG_OPTIONS
807 niro 816 static const char tar_longopts[] ALIGN1 =
808     "list\0" No_argument "t"
809     "extract\0" No_argument "x"
810     "directory\0" Required_argument "C"
811     "file\0" Required_argument "f"
812     "to-stdout\0" No_argument "O"
813 niro 984 /* do not restore owner */
814     /* Note: GNU tar handles 'o' as no-same-owner only on extract,
815     * on create, 'o' is --old-archive. We do not support --old-archive. */
816     "no-same-owner\0" No_argument "o"
817 niro 816 "same-permissions\0" No_argument "p"
818     "verbose\0" No_argument "v"
819     "keep-old\0" No_argument "k"
820 niro 532 # if ENABLE_FEATURE_TAR_CREATE
821 niro 816 "create\0" No_argument "c"
822     "dereference\0" No_argument "h"
823 niro 532 # endif
824 niro 816 # if ENABLE_FEATURE_SEAMLESS_BZ2
825     "bzip2\0" No_argument "j"
826 niro 532 # endif
827 niro 816 # if ENABLE_FEATURE_SEAMLESS_LZMA
828     "lzma\0" No_argument "a"
829 niro 532 # endif
830     # if ENABLE_FEATURE_TAR_FROM
831 niro 816 "files-from\0" Required_argument "T"
832     "exclude-from\0" Required_argument "X"
833 niro 532 # endif
834 niro 816 # if ENABLE_FEATURE_SEAMLESS_GZ
835     "gzip\0" No_argument "z"
836 niro 532 # endif
837 niro 816 # if ENABLE_FEATURE_SEAMLESS_Z
838     "compress\0" No_argument "Z"
839 niro 532 # endif
840 niro 984 # if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
841     "touch\0" No_argument "m"
842     # endif
843 niro 1123 # if ENABLE_FEATURE_TAR_TO_COMMAND
844     "to-command\0" Required_argument "\xfb"
845     # endif
846 niro 984 /* use numeric uid/gid from tar header, not textual */
847     "numeric-owner\0" No_argument "\xfc"
848     /* do not restore mode */
849     "no-same-permissions\0" No_argument "\xfd"
850     /* on unpack, open with O_TRUNC and !O_EXCL */
851     "overwrite\0" No_argument "\xfe"
852 niro 532 /* --exclude takes next bit position in option mask, */
853 niro 984 /* therefore we have to put it _after_ --no-same-permissions */
854 niro 532 # if ENABLE_FEATURE_TAR_FROM
855 niro 816 "exclude\0" Required_argument "\xff"
856 niro 532 # endif
857 niro 816 ;
858 niro 532 #endif
859    
860 niro 816 int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
861     int tar_main(int argc UNUSED_PARAM, char **argv)
862 niro 532 {
863 niro 816 char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar;
864 niro 532 archive_handle_t *tar_handle;
865     char *base_dir = NULL;
866     const char *tar_filename = "-";
867     unsigned opt;
868     int verboseFlag = 0;
869     #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
870     llist_t *excludes = NULL;
871     #endif
872    
873     /* Initialise default values */
874     tar_handle = init_handle();
875 niro 816 tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
876 niro 984 | ARCHIVE_RESTORE_DATE
877     | ARCHIVE_UNLINK_OLD;
878 niro 532
879 niro 816 /* Apparently only root's tar preserves perms (see bug 3844) */
880     if (getuid() != 0)
881 niro 984 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
882 niro 816
883 niro 532 /* Prepend '-' to the first argument if required */
884     opt_complementary = "--:" // first arg is options
885     "tt:vv:" // count -t,-v
886     "?:" // bail out with usage instead of error return
887     "X::T::" // cumulative lists
888     #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
889     "\xff::" // cumulative lists for --exclude
890     #endif
891 niro 984 IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
892     IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
893     IF_NOT_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
894 niro 532 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
895 niro 816 applet_long_options = tar_longopts;
896 niro 532 #endif
897 niro 984 #if ENABLE_DESKTOP
898     if (argv[1] && argv[1][0] != '-') {
899     /* Compat:
900     * 1st argument without dash handles options with parameters
901     * differently from dashed one: it takes *next argv[i]*
902     * as paramenter even if there are more chars in 1st argument:
903     * "tar fx TARFILE" - "x" is not taken as f's param
904     * but is interpreted as -x option
905     * "tar -xf TARFILE" - dashed equivalent of the above
906     * "tar -fx ..." - "x" is taken as f's param
907     * getopt32 wouldn't handle 1st command correctly.
908     * Unfortunately, people do use such commands.
909     * We massage argv[1] to work around it by moving 'f'
910     * to the end of the string.
911     * More contrived "tar fCx TARFILE DIR" still fails,
912     * but such commands are much less likely to be used.
913     */
914     char *f = strchr(argv[1], 'f');
915     if (f) {
916     while (f[1] != '\0') {
917     *f = f[1];
918     f++;
919     }
920     *f = 'f';
921     }
922     }
923     #endif
924 niro 816 opt = getopt32(argv,
925 niro 984 "txC:f:Oopvk"
926     IF_FEATURE_TAR_CREATE( "ch" )
927     IF_FEATURE_SEAMLESS_BZ2( "j" )
928     IF_FEATURE_SEAMLESS_LZMA("a" )
929     IF_FEATURE_TAR_FROM( "T:X:")
930     IF_FEATURE_SEAMLESS_GZ( "z" )
931     IF_FEATURE_SEAMLESS_Z( "Z" )
932     IF_FEATURE_TAR_NOPRESERVE_TIME("m")
933 niro 532 , &base_dir // -C dir
934     , &tar_filename // -f filename
935 niro 984 IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
936     IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
937 niro 1123 IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command
938 niro 532 #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
939     , &excludes // --exclude
940     #endif
941     , &verboseFlag // combined count for -t and -v
942     , &verboseFlag // combined count for -t and -v
943     );
944 niro 984 //bb_error_msg("opt:%08x", opt);
945 niro 816 argv += optind;
946 niro 532
947     if (verboseFlag) tar_handle->action_header = header_verbose_list;
948     if (verboseFlag == 1) tar_handle->action_header = header_list;
949    
950     if (opt & OPT_EXTRACT)
951     tar_handle->action_data = data_extract_all;
952    
953     if (opt & OPT_2STDOUT)
954     tar_handle->action_data = data_extract_to_stdout;
955    
956 niro 1123 if (opt & OPT_2COMMAND) {
957     putenv((char*)"TAR_FILETYPE=f");
958     signal(SIGPIPE, SIG_IGN);
959     tar_handle->action_data = data_extract_to_command;
960     }
961    
962 niro 532 if (opt & OPT_KEEP_OLD)
963 niro 984 tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
964 niro 532
965 niro 984 if (opt & OPT_NUMERIC_OWNER)
966     tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER;
967 niro 532
968 niro 984 if (opt & OPT_NOPRESERVE_OWNER)
969     tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_OWNER;
970    
971 niro 532 if (opt & OPT_NOPRESERVE_PERM)
972 niro 984 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
973 niro 532
974 niro 984 if (opt & OPT_OVERWRITE) {
975     tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
976     tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
977     }
978    
979 niro 532 if (opt & OPT_GZIP)
980     get_header_ptr = get_header_tar_gz;
981    
982     if (opt & OPT_BZIP2)
983     get_header_ptr = get_header_tar_bz2;
984    
985     if (opt & OPT_LZMA)
986     get_header_ptr = get_header_tar_lzma;
987    
988     if (opt & OPT_COMPRESS)
989     get_header_ptr = get_header_tar_Z;
990    
991 niro 984 if (opt & OPT_NOPRESERVE_TIME)
992     tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE;
993    
994 niro 532 #if ENABLE_FEATURE_TAR_FROM
995     tar_handle->reject = append_file_list_to_list(tar_handle->reject);
996 niro 984 # if ENABLE_FEATURE_TAR_LONG_OPTIONS
997 niro 532 /* Append excludes to reject */
998     while (excludes) {
999     llist_t *next = excludes->link;
1000     excludes->link = tar_handle->reject;
1001     tar_handle->reject = excludes;
1002     excludes = next;
1003     }
1004 niro 984 # endif
1005 niro 532 tar_handle->accept = append_file_list_to_list(tar_handle->accept);
1006     #endif
1007    
1008     /* Setup an array of filenames to work with */
1009 niro 984 /* TODO: This is the same as in ar, make a separate function? */
1010 niro 816 while (*argv) {
1011 niro 532 /* kill trailing '/' unless the string is just "/" */
1012 niro 816 char *cp = last_char_is(*argv, '/');
1013     if (cp > *argv)
1014 niro 532 *cp = '\0';
1015 niro 816 llist_add_to_end(&tar_handle->accept, *argv);
1016     argv++;
1017 niro 532 }
1018    
1019     if (tar_handle->accept || tar_handle->reject)
1020     tar_handle->filter = filter_accept_reject_list;
1021    
1022     /* Open the tar file */
1023     {
1024 niro 984 int tar_fd = STDIN_FILENO;
1025     int flags = O_RDONLY;
1026 niro 532
1027     if (opt & OPT_CREATE) {
1028 niro 984 /* Make sure there is at least one file to tar up */
1029 niro 532 if (tar_handle->accept == NULL)
1030     bb_error_msg_and_die("empty archive");
1031    
1032 niro 984 tar_fd = STDOUT_FILENO;
1033 niro 532 /* Mimicking GNU tar 1.15.1: */
1034 niro 816 flags = O_WRONLY | O_CREAT | O_TRUNC;
1035 niro 532 }
1036    
1037     if (LONE_DASH(tar_filename)) {
1038 niro 984 tar_handle->src_fd = tar_fd;
1039 niro 532 tar_handle->seek = seek_by_read;
1040     } else {
1041 niro 984 if (ENABLE_FEATURE_TAR_AUTODETECT && flags == O_RDONLY) {
1042     get_header_ptr = get_header_tar;
1043 niro 816 tar_handle->src_fd = open_zipped(tar_filename);
1044     if (tar_handle->src_fd < 0)
1045     bb_perror_msg_and_die("can't open '%s'", tar_filename);
1046     } else {
1047     tar_handle->src_fd = xopen(tar_filename, flags);
1048     }
1049 niro 532 }
1050     }
1051    
1052     if (base_dir)
1053     xchdir(base_dir);
1054    
1055     #ifdef CHECK_FOR_CHILD_EXITCODE
1056     /* We need to know whether child (gzip/bzip/etc) exits abnormally */
1057     signal(SIGCHLD, handle_SIGCHLD);
1058     #endif
1059    
1060 niro 984 /* Create an archive */
1061 niro 532 if (opt & OPT_CREATE) {
1062 niro 816 #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
1063 niro 532 int zipMode = 0;
1064 niro 816 if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP))
1065 niro 532 zipMode = 1;
1066 niro 816 if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2))
1067 niro 532 zipMode = 2;
1068 niro 816 #endif
1069 niro 532 /* NB: writeTarFile() closes tar_handle->src_fd */
1070     return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
1071     tar_handle->accept,
1072     tar_handle->reject, zipMode);
1073     }
1074    
1075     while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
1076 niro 816 continue;
1077 niro 532
1078     /* Check that every file that should have been extracted was */
1079     while (tar_handle->accept) {
1080     if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
1081     && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
1082     ) {
1083     bb_error_msg_and_die("%s: not found in archive",
1084     tar_handle->accept->data);
1085     }
1086     tar_handle->accept = tar_handle->accept->link;
1087     }
1088     if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */)
1089     close(tar_handle->src_fd);
1090    
1091     return EXIT_SUCCESS;
1092     }