6aaa4227393d26284008f0b713f3404d88b919bb
[oweals/busybox.git] / archival / tar.c
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
6  *  Glenn McGrath <bug1@iinet.net.au>
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.
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 "busybox.h"
27 #include "unarchive.h"
28 #include <fnmatch.h>
29 #include <getopt.h>
30
31 #ifdef CONFIG_FEATURE_TAR_CREATE
32
33 /* Tar file constants  */
34
35 #define TAR_BLOCK_SIZE          512
36
37 /* POSIX tar Header Block, from POSIX 1003.1-1990  */
38 #define NAME_SIZE      100
39 #define NAME_SIZE_STR "100"
40 struct TarHeader {                /* byte offset */
41         char name[NAME_SIZE];     /*   0-99 */
42         char mode[8];             /* 100-107 */
43         char uid[8];              /* 108-115 */
44         char gid[8];              /* 116-123 */
45         char size[12];            /* 124-135 */
46         char mtime[12];           /* 136-147 */
47         char chksum[8];           /* 148-155 */
48         char typeflag;            /* 156-156 */
49         char linkname[NAME_SIZE]; /* 157-256 */
50         char magic[6];            /* 257-262 */
51         char version[2];          /* 263-264 */
52         char uname[32];           /* 265-296 */
53         char gname[32];           /* 297-328 */
54         char devmajor[8];         /* 329-336 */
55         char devminor[8];         /* 337-344 */
56         char prefix[155];         /* 345-499 */
57         char padding[12];         /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */
58 };
59 typedef struct TarHeader TarHeader;
60
61 /*
62 ** writeTarFile(),  writeFileToTarball(), and writeTarHeader() are
63 ** the only functions that deal with the HardLinkInfo structure.
64 ** Even these functions use the xxxHardLinkInfo() functions.
65 */
66 typedef struct HardLinkInfo HardLinkInfo;
67 struct HardLinkInfo {
68         HardLinkInfo *next;     /* Next entry in list */
69         dev_t dev;                      /* Device number */
70         ino_t ino;                      /* Inode number */
71         short linkCount;        /* (Hard) Link Count */
72         char name[1];           /* Start of filename (must be last) */
73 };
74
75 /* Some info to be carried along when creating a new tarball */
76 struct TarBallInfo {
77         int tarFd;                              /* Open-for-write file descriptor
78                                                            for the tarball */
79         struct stat statBuf;    /* Stat info for the tarball, letting
80                                                            us know the inode and device that the
81                                                            tarball lives, so we can avoid trying
82                                                            to include the tarball into itself */
83         int verboseFlag;                /* Whether to print extra stuff or not */
84         const llist_t *excludeList;     /* List of files to not include */
85         HardLinkInfo *hlInfoHead;       /* Hard Link Tracking Information */
86         HardLinkInfo *hlInfo;   /* Hard Link Info for the current file */
87 };
88 typedef struct TarBallInfo TarBallInfo;
89
90 /* A nice enum with all the possible tar file content types */
91 enum TarFileType {
92         REGTYPE = '0',          /* regular file */
93         REGTYPE0 = '\0',        /* regular file (ancient bug compat) */
94         LNKTYPE = '1',          /* hard link */
95         SYMTYPE = '2',          /* symbolic link */
96         CHRTYPE = '3',          /* character special */
97         BLKTYPE = '4',          /* block special */
98         DIRTYPE = '5',          /* directory */
99         FIFOTYPE = '6',         /* FIFO special */
100         CONTTYPE = '7',         /* reserved */
101         GNULONGLINK = 'K',      /* GNU long (>100 chars) link name */
102         GNULONGNAME = 'L',      /* GNU long (>100 chars) file name */
103 };
104 typedef enum TarFileType TarFileType;
105
106 /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
107 static void addHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr,
108                                         struct stat *statbuf,
109                                         const char *fileName)
110 {
111         /* Note: hlInfoHeadPtr can never be NULL! */
112         HardLinkInfo *hlInfo;
113
114         hlInfo = xmalloc(sizeof(HardLinkInfo) + strlen(fileName));
115         hlInfo->next = *hlInfoHeadPtr;
116         *hlInfoHeadPtr = hlInfo;
117         hlInfo->dev = statbuf->st_dev;
118         hlInfo->ino = statbuf->st_ino;
119         hlInfo->linkCount = statbuf->st_nlink;
120         strcpy(hlInfo->name, fileName);
121 }
122
123 static void freeHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr)
124 {
125         HardLinkInfo *hlInfo;
126         HardLinkInfo *hlInfoNext;
127
128         if (hlInfoHeadPtr) {
129                 hlInfo = *hlInfoHeadPtr;
130                 while (hlInfo) {
131                         hlInfoNext = hlInfo->next;
132                         free(hlInfo);
133                         hlInfo = hlInfoNext;
134                 }
135                 *hlInfoHeadPtr = NULL;
136         }
137         return;
138 }
139
140 /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
141 static HardLinkInfo *findHardLinkInfo(HardLinkInfo * hlInfo, struct stat *statbuf)
142 {
143         while (hlInfo) {
144                 if ((statbuf->st_ino == hlInfo->ino) && (statbuf->st_dev == hlInfo->dev))
145                         break;
146                 hlInfo = hlInfo->next;
147         }
148         return hlInfo;
149 }
150
151 /* Put an octal string into the specified buffer.
152  * The number is zero padded and possibly null terminated.
153  * Returns TRUE if successful. - DISABLED (no caller ever checked)  */
154 static void putOctal(char *cp, int len, long long value)
155 {
156         int tempLength;
157         /* long long for the sake of storing lengths of 4Gb+ files */
158         /* (we are bust anyway after 64Gb: it doesn't fit into the field) */
159         char tempBuffer[sizeof(long long)*3+1];
160         char *tempString = tempBuffer;
161
162         /* Create a string of the specified length with
163          * leading zeroes and the octal number, and a trailing null.  */
164         tempLength = sprintf(tempBuffer, "%0*llo", len - 1, value);
165
166         /* If the string is too large, suppress leading 0's.  */
167         /* If that is not enough, drop trailing null.  */
168         tempLength -= len; /* easier to do checks */
169         while (tempLength >= 0) {
170                 if (tempString[0] != '0') {
171                         if (!tempLength) {
172                                 /* 1234 barely fits in 4 chars (w/o EOL '\0') */
173                                 break;
174                         }
175                         /* 12345 doesn't fit into 4 chars */
176                         return /*FALSE*/;
177                 }
178                 tempLength--; /* still have leading '0', */
179                 tempString++; /* can afford to drop it but retain EOL '\0' */
180         }
181
182         /* Copy the string to the field.  */
183         memcpy(cp, tempString, len);
184         /*return TRUE;*/
185 }
186
187 /* Write out a tar header for the specified file/directory/whatever */
188 void BUG_tar_header_size(void);
189 static int writeTarHeader(struct TarBallInfo *tbInfo,
190                 const char *header_name, const char *fileName, struct stat *statbuf)
191 {
192         struct TarHeader header;
193         const unsigned char *cp;
194         int chksum;
195         int size;
196
197         if (sizeof(header) != 512)
198                 BUG_tar_header_size();
199
200         bzero(&header, sizeof(struct TarHeader));
201
202         safe_strncpy(header.name, header_name, sizeof(header.name));
203
204         /* POSIX says to mask mode with 07777. */
205         putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 07777);
206         putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
207         putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
208         if (sizeof(header.size) != sizeof("00000000000"))
209                 BUG_tar_header_size();
210         strcpy(header.size, "00000000000"); /* Regular file size is handled later */
211         putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
212         strcpy(header.magic, "ustar  ");
213
214         /* Enter the user and group names (default to root if it fails) */
215 //cache!!!
216         if (bb_getpwuid(header.uname, statbuf->st_uid, sizeof(header.uname)) == NULL)
217                 strcpy(header.uname, "root");
218         if (bb_getgrgid(header.gname, statbuf->st_gid, sizeof(header.gname)) == NULL)
219                 strcpy(header.gname, "root");
220
221         if (tbInfo->hlInfo) {
222                 /* This is a hard link */
223                 header.typeflag = LNKTYPE;
224                 strncpy(header.linkname, tbInfo->hlInfo->name,
225                                 sizeof(header.linkname));
226         } else if (S_ISLNK(statbuf->st_mode)) {
227                 char *lpath = xreadlink(fileName);
228                 if (!lpath)             /* Already printed err msg inside xreadlink() */
229                         return FALSE;
230                 header.typeflag = SYMTYPE;
231                 strncpy(header.linkname, lpath, sizeof(header.linkname));
232                 /* If it is larger than 100 bytes, bail out */
233                 if (header.linkname[sizeof(header.linkname)-1] /* at least 100? */
234                  && lpath[sizeof(header.linkname)] /* and 101th is also not zero */
235                 ) {
236                         free(lpath);
237                         bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
238                         return FALSE;
239                 }
240                 free(lpath);
241         } else if (S_ISDIR(statbuf->st_mode)) {
242                 header.typeflag = DIRTYPE;
243                 strncat(header.name, "/", sizeof(header.name));
244         } else if (S_ISCHR(statbuf->st_mode)) {
245                 header.typeflag = CHRTYPE;
246                 putOctal(header.devmajor, sizeof(header.devmajor),
247                                  major(statbuf->st_rdev));
248                 putOctal(header.devminor, sizeof(header.devminor),
249                                  minor(statbuf->st_rdev));
250         } else if (S_ISBLK(statbuf->st_mode)) {
251                 header.typeflag = BLKTYPE;
252                 putOctal(header.devmajor, sizeof(header.devmajor),
253                                  major(statbuf->st_rdev));
254                 putOctal(header.devminor, sizeof(header.devminor),
255                                  minor(statbuf->st_rdev));
256         } else if (S_ISFIFO(statbuf->st_mode)) {
257                 header.typeflag = FIFOTYPE;
258         } else if (S_ISREG(statbuf->st_mode)) {
259                 header.typeflag = REGTYPE;
260                 putOctal(header.size, sizeof(header.size), statbuf->st_size);
261         } else {
262                 bb_error_msg("%s: unknown file type", fileName);
263                 return FALSE;
264         }
265
266         /* Calculate and store the checksum (i.e., the sum of all of the bytes of
267          * the header).  The checksum field must be filled with blanks for the
268          * calculation.  The checksum field is formatted differently from the
269          * other fields: it has [6] digits, a null, then a space -- rather than
270          * digits, followed by a null like the other fields... */
271         memset(header.chksum, ' ', sizeof(header.chksum));
272         cp = (const unsigned char *) &header;
273         chksum = 0;
274         size = sizeof(struct TarHeader);
275         do { chksum += *cp++; } while (--size);
276         putOctal(header.chksum, sizeof(header.chksum)-1, chksum);
277
278         /* Now write the header out to disk */
279         xwrite(tbInfo->tarFd, &header, sizeof(struct TarHeader));
280
281         /* Now do the verbose thing (or not) */
282
283         if (tbInfo->verboseFlag) {
284                 FILE *vbFd = stdout;
285
286                 if (tbInfo->tarFd == STDOUT_FILENO)     /* If the archive goes to stdout, verbose to stderr */
287                         vbFd = stderr;
288
289                 fprintf(vbFd, "%s\n", header.name);
290         }
291
292         return TRUE;
293 }
294
295 # ifdef CONFIG_FEATURE_TAR_FROM
296 static int exclude_file(const llist_t *excluded_files, const char *file)
297 {
298         while (excluded_files) {
299                 if (excluded_files->data[0] == '/') {
300                         if (fnmatch(excluded_files->data, file,
301                                                 FNM_PATHNAME | FNM_LEADING_DIR) == 0)
302                                 return 1;
303                 } else {
304                         const char *p;
305
306                         for (p = file; p[0] != '\0'; p++) {
307                                 if ((p == file || p[-1] == '/') && p[0] != '/' &&
308                                         fnmatch(excluded_files->data, p,
309                                                         FNM_PATHNAME | FNM_LEADING_DIR) == 0)
310                                         return 1;
311                         }
312                 }
313                 excluded_files = excluded_files->link;
314         }
315
316         return 0;
317 }
318 # else
319 #define exclude_file(excluded_files, file) 0
320 # endif
321
322 static int writeFileToTarball(const char *fileName, struct stat *statbuf,
323                         void *userData, int depth)
324 {
325         struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
326         const char *header_name;
327         int inputFileFd = -1;
328
329         /*
330          * Check to see if we are dealing with a hard link.
331          * If so -
332          * Treat the first occurance of a given dev/inode as a file while
333          * treating any additional occurances as hard links.  This is done
334          * by adding the file information to the HardLinkInfo linked list.
335          */
336         tbInfo->hlInfo = NULL;
337         if (statbuf->st_nlink > 1) {
338                 tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
339                 if (tbInfo->hlInfo == NULL)
340                         addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, fileName);
341         }
342
343         /* It is against the rules to archive a socket */
344         if (S_ISSOCK(statbuf->st_mode)) {
345                 bb_error_msg("%s: socket ignored", fileName);
346                 return TRUE;
347         }
348
349         /* It is a bad idea to store the archive we are in the process of creating,
350          * so check the device and inode to be sure that this particular file isn't
351          * the new tarball */
352         if (tbInfo->statBuf.st_dev == statbuf->st_dev &&
353                 tbInfo->statBuf.st_ino == statbuf->st_ino) {
354                 bb_error_msg("%s: file is the archive; skipping", fileName);
355                 return TRUE;
356         }
357
358         header_name = fileName;
359         while (header_name[0] == '/') {
360                 static int alreadyWarned = FALSE;
361
362                 if (alreadyWarned == FALSE) {
363                         bb_error_msg("removing leading '/' from member names");
364                         alreadyWarned = TRUE;
365                 }
366                 header_name++;
367         }
368
369         if (strlen(fileName) >= NAME_SIZE) {
370                 bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
371                 return TRUE;
372         }
373
374         if (header_name[0] == '\0')
375                 return TRUE;
376
377         if (exclude_file(tbInfo->excludeList, header_name))
378                 return SKIP;
379
380         /* Is this a regular file? */
381         if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
382                 /* open the file we want to archive, and make sure all is well */
383                 inputFileFd = open(fileName, O_RDONLY);
384                 if (inputFileFd < 0) {
385                         bb_perror_msg("%s: cannot open", fileName);
386                         return FALSE;
387                 }
388         }
389
390         /* Add an entry to the tarball */
391         if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
392                 return FALSE;
393         }
394
395         /* If it was a regular file, write out the body */
396         if (inputFileFd >= 0) {
397                 off_t readSize = 0;
398
399                 /* write the file to the archive */
400                 readSize = bb_copyfd_eof(inputFileFd, tbInfo->tarFd);
401                 close(inputFileFd);
402
403                 /* Pad the file up to the tar block size */
404                 /* (a few tricks here in the name of code size) */
405                 readSize = (-(int)readSize) & (TAR_BLOCK_SIZE-1);
406                 bzero(bb_common_bufsiz1, readSize);
407                 xwrite(tbInfo->tarFd, bb_common_bufsiz1, readSize);
408         }
409
410         return TRUE;
411 }
412
413 static int writeTarFile(const int tar_fd, const int verboseFlag,
414         const unsigned long dereferenceFlag, const llist_t *include,
415         const llist_t *exclude, const int gzip)
416 {
417         pid_t gzipPid = 0;
418         int errorFlag = FALSE;
419         struct TarBallInfo tbInfo;
420
421         tbInfo.hlInfoHead = NULL;
422
423         fchmod(tar_fd, 0644);
424         tbInfo.tarFd = tar_fd;
425         tbInfo.verboseFlag = verboseFlag;
426
427         /* Store the stat info for the tarball's file, so
428          * can avoid including the tarball into itself....  */
429         if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
430                 bb_perror_msg_and_die("cannot stat tar file");
431
432         if ((ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2) && gzip) {
433                 int gzipDataPipe[2] = { -1, -1 };
434                 int gzipStatusPipe[2] = { -1, -1 };
435                 volatile int vfork_exec_errno = 0;
436                 char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
437
438
439                 if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0)
440                         bb_perror_msg_and_die("pipe");
441
442                 signal(SIGPIPE, SIG_IGN);       /* we only want EPIPE on errors */
443
444 # if __GNUC__
445                 /* Avoid vfork clobbering */
446                 (void) &include;
447                 (void) &errorFlag;
448                 (void) &zip_exec;
449 # endif
450
451                 gzipPid = vfork();
452
453                 if (gzipPid == 0) {
454                         dup2(gzipDataPipe[0], 0);
455                         close(gzipDataPipe[1]);
456
457                         if (tbInfo.tarFd != 1)
458                                 dup2(tbInfo.tarFd, 1);
459
460                         close(gzipStatusPipe[0]);
461                         fcntl(gzipStatusPipe[1], F_SETFD, FD_CLOEXEC);  /* close on exec shows success */
462
463                         execlp(zip_exec, zip_exec, "-f", NULL);
464                         vfork_exec_errno = errno;
465
466                         close(gzipStatusPipe[1]);
467                         exit(-1);
468                 } else if (gzipPid > 0) {
469                         close(gzipDataPipe[0]);
470                         close(gzipStatusPipe[1]);
471
472                         while (1) {
473                                 char buf;
474
475                                 int n = full_read(gzipStatusPipe[0], &buf, 1);
476
477                                 if (n == 0 && vfork_exec_errno != 0) {
478                                         errno = vfork_exec_errno;
479                                         bb_perror_msg_and_die("cannot exec %s", zip_exec);
480                                 } else if ((n < 0) && (errno == EAGAIN || errno == EINTR))
481                                         continue;       /* try it again */
482                                 break;
483                         }
484                         close(gzipStatusPipe[0]);
485
486                         tbInfo.tarFd = gzipDataPipe[1];
487                 } else bb_perror_msg_and_die("vfork gzip");
488         }
489
490         tbInfo.excludeList = exclude;
491
492         /* Read the directory/files and iterate over them one at a time */
493         while (include) {
494                 if (!recursive_action(include->data, TRUE, dereferenceFlag,
495                                 FALSE, writeFileToTarball, writeFileToTarball, &tbInfo, 0))
496                 {
497                         errorFlag = TRUE;
498                 }
499                 include = include->link;
500         }
501         /* Write two empty blocks to the end of the archive */
502         bzero(bb_common_bufsiz1, 2*TAR_BLOCK_SIZE);
503         xwrite(tbInfo.tarFd, bb_common_bufsiz1, 2*TAR_BLOCK_SIZE);
504
505         /* To be pedantically correct, we would check if the tarball
506          * is smaller than 20 tar blocks, and pad it if it was smaller,
507          * but that isn't necessary for GNU tar interoperability, and
508          * so is considered a waste of space */
509
510         /* Close so the child process (if any) will exit */
511         close(tbInfo.tarFd);
512
513         /* Hang up the tools, close up shop, head home */
514         if (ENABLE_FEATURE_CLEAN_UP)
515                 freeHardLinkInfo(&tbInfo.hlInfoHead);
516
517         if (errorFlag)
518                 bb_error_msg("error exit delayed from previous errors");
519
520         if (gzipPid && waitpid(gzipPid, NULL, 0) == -1)
521                 bb_error_msg("waitpid failed");
522
523         return !errorFlag;
524 }
525 #else
526 int writeTarFile(const int tar_fd, const int verboseFlag,
527         const unsigned long dereferenceFlag, const llist_t *include,
528         const llist_t *exclude, const int gzip);
529 #endif  /* tar_create */
530
531 #ifdef CONFIG_FEATURE_TAR_FROM
532 static llist_t *append_file_list_to_list(llist_t *list)
533 {
534         FILE *src_stream;
535         llist_t *cur = list;
536         llist_t *tmp;
537         char *line;
538         llist_t *newlist = NULL;
539
540         while (cur) {
541                 src_stream = xfopen(cur->data, "r");
542                 tmp = cur;
543                 cur = cur->link;
544                 free(tmp);
545                 while ((line = xmalloc_getline(src_stream)) != NULL) {
546                         char *filename_ptr = last_char_is(line, '/');
547                         if (filename_ptr > line)
548                                 *filename_ptr = '\0';
549                         llist_add_to(&newlist, line);
550                 }
551                 fclose(src_stream);
552         }
553         return newlist;
554 }
555 #else
556 #define append_file_list_to_list(x)     0
557 #endif
558
559 #ifdef CONFIG_FEATURE_TAR_COMPRESS
560 static char get_header_tar_Z(archive_handle_t *archive_handle)
561 {
562         /* Can't lseek over pipes */
563         archive_handle->seek = seek_by_read;
564
565         /* do the decompression, and cleanup */
566         if (xread_char(archive_handle->src_fd) != 0x1f
567          || xread_char(archive_handle->src_fd) != 0x9d
568         ) {
569                 bb_error_msg_and_die("invalid magic");
570         }
571
572         archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompress);
573         archive_handle->offset = 0;
574         while (get_header_tar(archive_handle) == EXIT_SUCCESS)
575                 /* nothing */;
576
577         /* Can only do one file at a time */
578         return EXIT_FAILURE;
579 }
580 #else
581 #define get_header_tar_Z        0
582 #endif
583
584 #define CTX_TEST                          (1 << 0)
585 #define CTX_EXTRACT                       (1 << 1)
586 #define TAR_OPT_BASEDIR                   (1 << 2)
587 #define TAR_OPT_TARNAME                   (1 << 3)
588 #define TAR_OPT_2STDOUT                   (1 << 4)
589 #define TAR_OPT_P                         (1 << 5)
590 #define TAR_OPT_VERBOSE                   (1 << 6)
591 #define TAR_OPT_KEEP_OLD                  (1 << 7)
592
593 #define TAR_OPT_AFTER_START               8
594
595 #define CTX_CREATE                        (1 << (TAR_OPT_AFTER_START))
596 #define TAR_OPT_DEREFERENCE               (1 << (TAR_OPT_AFTER_START + 1))
597 #ifdef CONFIG_FEATURE_TAR_CREATE
598 # define TAR_OPT_STR_CREATE               "ch"
599 # define TAR_OPT_AFTER_CREATE             TAR_OPT_AFTER_START + 2
600 #else
601 # define TAR_OPT_STR_CREATE               ""
602 # define TAR_OPT_AFTER_CREATE             TAR_OPT_AFTER_START
603 #endif
604
605 #define TAR_OPT_BZIP2                     (1 << (TAR_OPT_AFTER_CREATE))
606 #ifdef CONFIG_FEATURE_TAR_BZIP2
607 # define TAR_OPT_STR_BZIP2                "j"
608 # define TAR_OPT_AFTER_BZIP2              TAR_OPT_AFTER_CREATE + 1
609 #else
610 # define TAR_OPT_STR_BZIP2                ""
611 # define TAR_OPT_AFTER_BZIP2              TAR_OPT_AFTER_CREATE
612 #endif
613
614 #define TAR_OPT_LZMA                      (1 << (TAR_OPT_AFTER_BZIP2))
615 #ifdef CONFIG_FEATURE_TAR_LZMA
616 # define TAR_OPT_STR_LZMA                 "a"
617 # define TAR_OPT_AFTER_LZMA               TAR_OPT_AFTER_BZIP2 + 1
618 #else
619 # define TAR_OPT_STR_LZMA                 ""
620 # define TAR_OPT_AFTER_LZMA               TAR_OPT_AFTER_BZIP2
621 #endif
622
623 #define TAR_OPT_INCLUDE_FROM              (1 << (TAR_OPT_AFTER_LZMA))
624 #define TAR_OPT_EXCLUDE_FROM              (1 << (TAR_OPT_AFTER_LZMA + 1))
625 #ifdef CONFIG_FEATURE_TAR_FROM
626 # define TAR_OPT_STR_FROM                 "T:X:"
627 # define TAR_OPT_AFTER_FROM               TAR_OPT_AFTER_LZMA + 2
628 #else
629 # define TAR_OPT_STR_FROM                 ""
630 # define TAR_OPT_AFTER_FROM               TAR_OPT_AFTER_LZMA
631 #endif
632
633 #define TAR_OPT_GZIP                      (1 << (TAR_OPT_AFTER_FROM))
634 #ifdef CONFIG_FEATURE_TAR_GZIP
635 # define TAR_OPT_STR_GZIP                 "z"
636 # define TAR_OPT_AFTER_GZIP               TAR_OPT_AFTER_FROM + 1
637 #else
638 # define TAR_OPT_STR_GZIP                 ""
639 # define TAR_OPT_AFTER_GZIP               TAR_OPT_AFTER_FROM
640 #endif
641
642 #define TAR_OPT_UNCOMPRESS                (1 << (TAR_OPT_AFTER_GZIP))
643 #ifdef CONFIG_FEATURE_TAR_COMPRESS
644 # define TAR_OPT_STR_COMPRESS             "Z"
645 # define TAR_OPT_AFTER_COMPRESS           TAR_OPT_AFTER_GZIP + 1
646 #else
647 # define TAR_OPT_STR_COMPRESS             ""
648 # define TAR_OPT_AFTER_COMPRESS           TAR_OPT_AFTER_GZIP
649 #endif
650
651 #define TAR_OPT_NOPRESERVE_OWN            (1 << (TAR_OPT_AFTER_COMPRESS))
652 #define TAR_OPT_NOPRESERVE_PERM           (1 << (TAR_OPT_AFTER_COMPRESS + 1))
653 #define TAR_OPT_STR_NOPRESERVE            "\203\213"
654 #define TAR_OPT_AFTER_NOPRESERVE          TAR_OPT_AFTER_COMPRESS + 2
655
656 static const char tar_options[] = "txC:f:Opvk" \
657         TAR_OPT_STR_CREATE \
658         TAR_OPT_STR_BZIP2 \
659         TAR_OPT_STR_LZMA \
660         TAR_OPT_STR_FROM \
661         TAR_OPT_STR_GZIP \
662         TAR_OPT_STR_COMPRESS \
663         TAR_OPT_STR_NOPRESERVE;
664
665 #ifdef CONFIG_FEATURE_TAR_LONG_OPTIONS
666 static const struct option tar_long_options[] = {
667         { "list",               0,  NULL,   't' },
668         { "extract",            0,  NULL,   'x' },
669         { "directory",          1,  NULL,   'C' },
670         { "file",               1,  NULL,   'f' },
671         { "to-stdout",          0,  NULL,   'O' },
672         { "same-permissions",   0,  NULL,   'p' },
673         { "verbose",            0,  NULL,   'v' },
674         { "keep-old",           0,  NULL,   'k' },
675         { "no-same-owner",      0,  NULL,   '\203' },
676         { "no-same-permissions",0,  NULL,   '\213' },
677 # ifdef CONFIG_FEATURE_TAR_CREATE
678         { "create",             0,  NULL,   'c' },
679         { "dereference",        0,  NULL,   'h' },
680 # endif
681 # ifdef CONFIG_FEATURE_TAR_BZIP2
682         { "bzip2",              0,  NULL,   'j' },
683 # endif
684 # ifdef CONFIG_FEATURE_TAR_LZMA
685         { "lzma",               0,  NULL,   'a' },
686 # endif
687 # ifdef CONFIG_FEATURE_TAR_FROM
688         { "files-from",         1,  NULL,   'T' },
689         { "exclude-from",       1,  NULL,   'X' },
690         { "exclude",            1,  NULL,   '\n' },
691 # endif
692 # ifdef CONFIG_FEATURE_TAR_GZIP
693         { "gzip",               0,  NULL,   'z' },
694 # endif
695 # ifdef CONFIG_FEATURE_TAR_COMPRESS
696         { "compress",           0,  NULL,   'Z' },
697 # endif
698         { 0,                    0, 0, 0 }
699 };
700 #else
701 #define tar_long_options        0
702 #endif
703
704 int tar_main(int argc, char **argv)
705 {
706         char (*get_header_ptr)(archive_handle_t *) = get_header_tar;
707         archive_handle_t *tar_handle;
708         char *base_dir = NULL;
709         const char *tar_filename = "-";
710         unsigned opt;
711         llist_t *excludes = NULL;
712
713         /* Initialise default values */
714         tar_handle = init_handle();
715         tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL;
716
717         /* Prepend '-' to the first argument if required */
718         opt_complementary = ENABLE_FEATURE_TAR_CREATE ?
719                 "--:X::T::\n::c:t:x:?:c--tx:t--cx:x--ct" :
720                 "--:X::T::\n::t:x:?:t--x:x--t";
721         if (ENABLE_FEATURE_TAR_LONG_OPTIONS)
722                 applet_long_options = tar_long_options;
723         opt = getopt32(argc, argv, tar_options,
724                                 &base_dir,      /* Change to dir <optarg> */
725                                 &tar_filename /* archive filename */
726 #ifdef CONFIG_FEATURE_TAR_FROM
727                                 , &(tar_handle->accept),
728                                 &(tar_handle->reject),
729                                 &excludes
730 #endif
731                                 );
732
733         if (opt & CTX_TEST) {
734                 if (tar_handle->action_header == header_list
735                  || tar_handle->action_header == header_verbose_list
736                 ) {
737                         tar_handle->action_header = header_verbose_list;
738                 } else
739                         tar_handle->action_header = header_list;
740         }
741         if ((opt & CTX_EXTRACT) && tar_handle->action_data != data_extract_to_stdout)
742                 tar_handle->action_data = data_extract_all;
743
744         if (opt & TAR_OPT_2STDOUT)
745                 tar_handle->action_data = data_extract_to_stdout;
746
747         if (opt & TAR_OPT_VERBOSE) {
748                 if (tar_handle->action_header == header_list
749                  || tar_handle->action_header == header_verbose_list
750                 ) {
751                         tar_handle->action_header = header_verbose_list;
752                 } else
753                         tar_handle->action_header = header_list;
754         }
755         if (opt & TAR_OPT_KEEP_OLD)
756                 tar_handle->flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL;
757
758         if (opt & TAR_OPT_NOPRESERVE_OWN)
759                 tar_handle->flags |= ARCHIVE_NOPRESERVE_OWN;
760
761         if (opt & TAR_OPT_NOPRESERVE_PERM)
762                 tar_handle->flags |= ARCHIVE_NOPRESERVE_PERM;
763
764         if (ENABLE_FEATURE_TAR_GZIP && (opt & TAR_OPT_GZIP))
765                 get_header_ptr = get_header_tar_gz;
766
767         if (ENABLE_FEATURE_TAR_BZIP2 && (opt & TAR_OPT_BZIP2))
768                 get_header_ptr = get_header_tar_bz2;
769
770         if (ENABLE_FEATURE_TAR_LZMA && (opt & TAR_OPT_LZMA))
771                 get_header_ptr = get_header_tar_lzma;
772
773         if (ENABLE_FEATURE_TAR_COMPRESS && (opt & TAR_OPT_UNCOMPRESS))
774                 get_header_ptr = get_header_tar_Z;
775
776         if (ENABLE_FEATURE_TAR_FROM) {
777                 tar_handle->reject = append_file_list_to_list(tar_handle->reject);
778                 /* Append excludes to reject */
779                 while (excludes) {
780                         llist_t *temp = excludes->link;
781                         excludes->link = tar_handle->reject;
782                         tar_handle->reject = excludes;
783                         excludes = temp;
784                 }
785                 tar_handle->accept = append_file_list_to_list(tar_handle->accept);
786         }
787
788         /* Check if we are reading from stdin */
789         if (argv[optind] && *argv[optind] == '-') {
790                 /* Default is to read from stdin, so just skip to next arg */
791                 optind++;
792         }
793
794         /* Setup an array of filenames to work with */
795         /* TODO: This is the same as in ar, separate function ? */
796         while (optind < argc) {
797                 char *filename_ptr = last_char_is(argv[optind], '/');
798                 if (filename_ptr > argv[optind])
799                         *filename_ptr = '\0';
800
801                 llist_add_to(&(tar_handle->accept), argv[optind]);
802                 optind++;
803         }
804
805         if (tar_handle->accept || tar_handle->reject)
806                 tar_handle->filter = filter_accept_reject_list;
807
808         /* Open the tar file */
809         {
810                 FILE *tar_stream;
811                 int flags;
812
813                 if (ENABLE_FEATURE_TAR_CREATE && (opt & CTX_CREATE)) {
814                         /* Make sure there is at least one file to tar up.  */
815                         if (tar_handle->accept == NULL)
816                                 bb_error_msg_and_die("empty archive");
817
818                         tar_stream = stdout;
819                         /* Mimicking GNU tar 1.15.1: */
820                         flags = O_WRONLY|O_CREAT|O_TRUNC;
821                 /* was doing unlink; open(O_WRONLY|O_CREAT|O_EXCL); why? */
822                 } else {
823                         tar_stream = stdin;
824                         flags = O_RDONLY;
825                 }
826
827                 if ((tar_filename[0] == '-') && (tar_filename[1] == '\0')) {
828                         tar_handle->src_fd = fileno(tar_stream);
829                         tar_handle->seek = seek_by_read;
830                 } else {
831                         tar_handle->src_fd = xopen3(tar_filename, flags, 0666);
832                 }
833         }
834
835         if (base_dir)
836                 xchdir(base_dir);
837
838         /* create an archive */
839         if (ENABLE_FEATURE_TAR_CREATE && (opt & CTX_CREATE)) {
840                 int verboseFlag = FALSE;
841                 int zipMode = 0;
842
843                 if (ENABLE_FEATURE_TAR_GZIP && get_header_ptr == get_header_tar_gz)
844                         zipMode = 1;
845                 if (ENABLE_FEATURE_TAR_BZIP2 && get_header_ptr == get_header_tar_bz2)
846                         zipMode = 2;
847
848                 if (tar_handle->action_header == header_list
849                  || tar_handle->action_header == header_verbose_list
850                 ) {
851                         verboseFlag = TRUE;
852                 }
853                 writeTarFile(tar_handle->src_fd, verboseFlag, opt & TAR_OPT_DEREFERENCE,
854                                 tar_handle->accept,
855                         tar_handle->reject, zipMode);
856         } else {
857                 while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
858                         /* nothing */;
859
860                 /* Check that every file that should have been extracted was */
861                 while (tar_handle->accept) {
862                         if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
863                          && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
864                         ) {
865                                 bb_error_msg_and_die("%s: not found in archive",
866                                         tar_handle->accept->data);
867                         }
868                         tar_handle->accept = tar_handle->accept->link;
869                 }
870         }
871
872         if (ENABLE_FEATURE_CLEAN_UP && tar_handle->src_fd != STDIN_FILENO)
873                 close(tar_handle->src_fd);
874
875         return EXIT_SUCCESS;
876 }