1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <fnmatch.h>
27#include "libbb.h"
28#include "archive.h"
29
30#ifndef FNM_LEADING_DIR
31# define FNM_LEADING_DIR 0
32#endif
33
34
35
36#define DBG(...) ((void)0)
37
38
39#define block_buf bb_common_bufsiz1
40
41
42#if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2
43
44#define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \
45 writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude)
46#endif
47
48
49#if ENABLE_FEATURE_TAR_CREATE
50
51
52
53
54
55
56typedef struct HardLinkInfo {
57 struct HardLinkInfo *next;
58 dev_t dev;
59 ino_t ino;
60
61 char name[1];
62} HardLinkInfo;
63
64
65typedef struct TarBallInfo {
66 int tarFd;
67
68 int verboseFlag;
69 const llist_t *excludeList;
70 HardLinkInfo *hlInfoHead;
71 HardLinkInfo *hlInfo;
72
73 struct stat tarFileStatBuf;
74
75
76
77} TarBallInfo;
78
79
80enum {
81 REGTYPE = '0',
82 REGTYPE0 = '\0',
83 LNKTYPE = '1',
84 SYMTYPE = '2',
85 CHRTYPE = '3',
86 BLKTYPE = '4',
87 DIRTYPE = '5',
88 FIFOTYPE = '6',
89 CONTTYPE = '7',
90 GNULONGLINK = 'K',
91 GNULONGNAME = 'L',
92};
93
94
95static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr,
96 struct stat *statbuf,
97 const char *fileName)
98{
99
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
108 strcpy(hlInfo->name, fileName);
109}
110
111static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr)
112{
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
128static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf)
129{
130 while (hlInfo) {
131 if (statbuf->st_ino == hlInfo->ino
132 && statbuf->st_dev == hlInfo->dev
133 ) {
134 DBG("found hardlink:'%s'", hlInfo->name);
135 break;
136 }
137 hlInfo = hlInfo->next;
138 }
139 return hlInfo;
140}
141
142
143
144
145static void putOctal(char *cp, int len, off_t value)
146{
147 char tempBuffer[sizeof(off_t)*3 + 1];
148 char *tempString = tempBuffer;
149 int width;
150
151 width = sprintf(tempBuffer, "%0*"OFF_FMT"o", len, value);
152 tempString += (width - len);
153
154
155
156
157 if (tempString[0] == '0')
158 tempString++;
159
160
161 memcpy(cp, tempString, len);
162}
163#define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
164
165static void chksum_and_xwrite(int fd, struct tar_header_t* hp)
166{
167
168
169
170 const unsigned char *cp;
171 int chksum, size;
172
173 strcpy(hp->magic, "ustar ");
174
175
176
177
178
179
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
188 xwrite(fd, hp, sizeof(*hp));
189}
190
191#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
192static void writeLongname(int fd, int type, const char *name, int dir)
193{
194 static const struct {
195 char mode[8];
196 char uid[8];
197 char gid[8];
198 char size[12];
199 char mtime[12];
200 } prefilled = {
201 "0000000",
202 "0000000",
203 "0000000",
204 "00000000000",
205 "00000000000",
206 };
207 struct tar_header_t header;
208 int size;
209
210 dir = !!dir;
211 size = strlen(name) + 1 + dir;
212
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
222
223
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
234static int writeTarHeader(struct TarBallInfo *tbInfo,
235 const char *header_name, const char *fileName, struct stat *statbuf)
236{
237 struct tar_header_t header;
238
239 memset(&header, 0, sizeof(header));
240
241 strncpy(header.name, header_name, sizeof(header.name));
242
243
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);
248 PUT_OCTAL(header.mtime, statbuf->st_mtime);
249
250
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
256 header.typeflag = LNKTYPE;
257 strncpy(header.linkname, tbInfo->hlInfo->name,
258 sizeof(header.linkname));
259#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
260
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 char *lpath = xmalloc_readlink_or_warn(fileName);
267 if (!lpath)
268 return FALSE;
269 header.typeflag = SYMTYPE;
270 strncpy(header.linkname, lpath, sizeof(header.linkname));
271#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
272
273 if (header.linkname[sizeof(header.linkname)-1])
274 writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0);
275#else
276
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
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 bb_error_msg_and_die("can't store file '%s' "
304 "of size %"OFF_FMT"u, aborting",
305 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
316
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
323 chksum_and_xwrite(tbInfo->tarFd, &header);
324
325
326 if (tbInfo->verboseFlag) {
327 FILE *vbFd = stdout;
328
329
330 if (tbInfo->tarFd == STDOUT_FILENO)
331 vbFd = stderr;
332
333
334
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
343static 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 FNM_PATHNAME | FNM_LEADING_DIR) == 0)
349 return 1;
350 } else {
351 const char *p;
352
353 for (p = file; p[0] != '\0'; p++) {
354 if ((p == file || p[-1] == '/')
355 && p[0] != '/'
356 && fnmatch(excluded_files->data, p,
357 FNM_PATHNAME | FNM_LEADING_DIR) == 0
358 ) {
359 return 1;
360 }
361 }
362 }
363 excluded_files = excluded_files->link;
364 }
365
366 return 0;
367}
368#else
369# define exclude_file(excluded_files, file) 0
370#endif
371
372static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
373 void *userData, int depth UNUSED_PARAM)
374{
375 struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
376 const char *header_name;
377 int inputFileFd = -1;
378
379 DBG("writeFileToTarball('%s')", fileName);
380
381
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
397 if (S_ISSOCK(statbuf->st_mode)) {
398 bb_error_msg("%s: socket ignored", fileName);
399 return TRUE;
400 }
401
402
403
404
405
406
407
408
409 tbInfo->hlInfo = NULL;
410 if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) {
411 DBG("'%s': st_nlink > 1", header_name);
412 tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
413 if (tbInfo->hlInfo == NULL) {
414 DBG("'%s': addHardLinkInfo", header_name);
415 addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
416 }
417 }
418
419
420
421
422 if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
423 && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
424 ) {
425 bb_error_msg("%s: file is the archive; skipping", fileName);
426 return TRUE;
427 }
428
429 if (exclude_file(tbInfo->excludeList, header_name))
430 return SKIP;
431
432#if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
433 if (strlen(header_name) >= NAME_SIZE) {
434 bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
435 return TRUE;
436 }
437#endif
438
439
440 if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
441
442 inputFileFd = open_or_warn(fileName, O_RDONLY);
443 if (inputFileFd < 0) {
444 return FALSE;
445 }
446 }
447
448
449 if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
450 return FALSE;
451 }
452
453
454 if (inputFileFd >= 0) {
455 size_t readSize;
456
457
458
459
460
461
462 bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
463
464
465
466
467
468
469
470
471
472 close(inputFileFd);
473
474
475
476 readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
477 memset(block_buf, 0, readSize);
478 xwrite(tbInfo->tarFd, block_buf, readSize);
479 }
480
481 return TRUE;
482}
483
484#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
485# if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
486# define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
487# endif
488
489static void NOINLINE vfork_compressor(int tar_fd, int gzip)
490{
491 pid_t gzipPid;
492# if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2
493 const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
494# elif ENABLE_FEATURE_SEAMLESS_GZ
495 const char *zip_exec = "gzip";
496# else
497 const char *zip_exec = "bzip2";
498# endif
499
500
501# define WAIT_FOR_CHILD 0
502 volatile int vfork_exec_errno = 0;
503 struct fd_pair gzipDataPipe;
504# if WAIT_FOR_CHILD
505 struct fd_pair gzipStatusPipe;
506 xpiped_pair(gzipStatusPipe);
507# endif
508 xpiped_pair(gzipDataPipe);
509
510 signal(SIGPIPE, SIG_IGN);
511
512# if defined(__GNUC__) && __GNUC__
513
514 (void) &zip_exec;
515# endif
516
517 gzipPid = xvfork();
518
519 if (gzipPid == 0) {
520
521
522 close(gzipDataPipe.wr);
523# if WAIT_FOR_CHILD
524 close(gzipStatusPipe.rd);
525
526
527 fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
528# endif
529 xmove_fd(gzipDataPipe.rd, 0);
530 xmove_fd(tar_fd, 1);
531
532 BB_EXECLP(zip_exec, zip_exec, "-f", NULL);
533 vfork_exec_errno = errno;
534 _exit(EXIT_FAILURE);
535 }
536
537
538 xmove_fd(gzipDataPipe.wr, tar_fd);
539 close(gzipDataPipe.rd);
540# if WAIT_FOR_CHILD
541 close(gzipStatusPipe.wr);
542 while (1) {
543 char buf;
544 int n;
545
546
547 n = full_read(gzipStatusPipe.rd, &buf, 1);
548 if (n < 0 )
549 continue;
550 }
551 close(gzipStatusPipe.rd);
552# endif
553 if (vfork_exec_errno) {
554 errno = vfork_exec_errno;
555 bb_perror_msg_and_die("can't execute '%s'", zip_exec);
556 }
557}
558#endif
559
560
561
562static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
563 int dereferenceFlag, const llist_t *include,
564 const llist_t *exclude, int gzip)
565{
566 int errorFlag = FALSE;
567 struct TarBallInfo tbInfo;
568
569 tbInfo.hlInfoHead = NULL;
570 tbInfo.tarFd = tar_fd;
571 tbInfo.verboseFlag = verboseFlag;
572
573
574
575 xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file");
576
577#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
578 if (gzip)
579 vfork_compressor(tbInfo.tarFd, gzip);
580#endif
581
582 tbInfo.excludeList = exclude;
583
584
585 while (include) {
586 if (!recursive_action(include->data, ACTION_RECURSE |
587 (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),
588 writeFileToTarball, writeFileToTarball, &tbInfo, 0)
589 ) {
590 errorFlag = TRUE;
591 }
592 include = include->link;
593 }
594
595 memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
596 xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE);
597
598
599
600
601
602
603
604 close(tbInfo.tarFd);
605
606
607 if (ENABLE_FEATURE_CLEAN_UP)
608 freeHardLinkInfo(&tbInfo.hlInfoHead);
609
610 if (errorFlag)
611 bb_error_msg("error exit delayed from previous errors");
612
613#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
614 if (gzip) {
615 int status;
616 if (safe_waitpid(-1, &status, 0) == -1)
617 bb_perror_msg("waitpid");
618 else if (!WIFEXITED(status) || WEXITSTATUS(status))
619
620 errorFlag = TRUE;
621 }
622#endif
623 return errorFlag;
624}
625#else
626int writeTarFile(int tar_fd, int verboseFlag,
627 int dereferenceFlag, const llist_t *include,
628 const llist_t *exclude, int gzip);
629#endif
630
631#if ENABLE_FEATURE_TAR_FROM
632static llist_t *append_file_list_to_list(llist_t *list)
633{
634 FILE *src_stream;
635 char *line;
636 llist_t *newlist = NULL;
637
638 while (list) {
639 src_stream = xfopen_for_read(llist_pop(&list));
640 while ((line = xmalloc_fgetline(src_stream)) != NULL) {
641
642 char *cp = last_char_is(line, '/');
643 if (cp > line)
644 *cp = '\0';
645 llist_add_to(&newlist, line);
646 }
647 fclose(src_stream);
648 }
649 return newlist;
650}
651#else
652# define append_file_list_to_list(x) 0
653#endif
654
655#if ENABLE_FEATURE_SEAMLESS_Z
656static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle)
657{
658
659 archive_handle->seek = seek_by_read;
660
661
662 if (xread_char(archive_handle->src_fd) != 0x1f
663 || xread_char(archive_handle->src_fd) != 0x9d
664 ) {
665 bb_error_msg_and_die("invalid magic");
666 }
667
668 open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress");
669 archive_handle->offset = 0;
670 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
671 continue;
672
673
674 return EXIT_FAILURE;
675}
676#else
677# define get_header_tar_Z NULL
678#endif
679
680#ifdef CHECK_FOR_CHILD_EXITCODE
681
682
683static int child_error;
684
685static void handle_SIGCHLD(int status)
686{
687
688
689
690 if (wait_any_nohang(&status) < 0)
691
692 return;
693
694 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
695
696 return;
697
698
699 child_error = 1;
700}
701#endif
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765enum {
766 OPTBIT_KEEP_OLD = 8,
767 IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,)
768 IF_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE ,)
769 IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2 ,)
770 IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA ,)
771 IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,)
772 IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,)
773 IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP ,)
774 IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,)
775 IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
776#if ENABLE_FEATURE_TAR_LONG_OPTIONS
777 IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,)
778 OPTBIT_NUMERIC_OWNER,
779 OPTBIT_NOPRESERVE_PERM,
780 OPTBIT_OVERWRITE,
781#endif
782 OPT_TEST = 1 << 0,
783 OPT_EXTRACT = 1 << 1,
784 OPT_BASEDIR = 1 << 2,
785 OPT_TARNAME = 1 << 3,
786 OPT_2STDOUT = 1 << 4,
787 OPT_NOPRESERVE_OWNER = 1 << 5,
788 OPT_P = 1 << 6,
789 OPT_VERBOSE = 1 << 7,
790 OPT_KEEP_OLD = 1 << 8,
791 OPT_CREATE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_CREATE )) + 0,
792 OPT_DEREFERENCE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_DEREFERENCE )) + 0,
793 OPT_BZIP2 = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2 )) + 0,
794 OPT_LZMA = IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA )) + 0,
795 OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM)) + 0,
796 OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM)) + 0,
797 OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0,
798 OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0,
799 OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0,
800 OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0,
801 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0,
802 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0,
803 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0,
804};
805#if ENABLE_FEATURE_TAR_LONG_OPTIONS
806static const char tar_longopts[] ALIGN1 =
807 "list\0" No_argument "t"
808 "extract\0" No_argument "x"
809 "directory\0" Required_argument "C"
810 "file\0" Required_argument "f"
811 "to-stdout\0" No_argument "O"
812
813
814
815 "no-same-owner\0" No_argument "o"
816 "same-permissions\0" No_argument "p"
817 "verbose\0" No_argument "v"
818 "keep-old\0" No_argument "k"
819# if ENABLE_FEATURE_TAR_CREATE
820 "create\0" No_argument "c"
821 "dereference\0" No_argument "h"
822# endif
823# if ENABLE_FEATURE_SEAMLESS_BZ2
824 "bzip2\0" No_argument "j"
825# endif
826# if ENABLE_FEATURE_SEAMLESS_LZMA
827 "lzma\0" No_argument "a"
828# endif
829# if ENABLE_FEATURE_TAR_FROM
830 "files-from\0" Required_argument "T"
831 "exclude-from\0" Required_argument "X"
832# endif
833# if ENABLE_FEATURE_SEAMLESS_GZ
834 "gzip\0" No_argument "z"
835# endif
836# if ENABLE_FEATURE_SEAMLESS_Z
837 "compress\0" No_argument "Z"
838# endif
839# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
840 "touch\0" No_argument "m"
841# endif
842# if ENABLE_FEATURE_TAR_TO_COMMAND
843 "to-command\0" Required_argument "\xfb"
844# endif
845
846 "numeric-owner\0" No_argument "\xfc"
847
848 "no-same-permissions\0" No_argument "\xfd"
849
850 "overwrite\0" No_argument "\xfe"
851
852
853# if ENABLE_FEATURE_TAR_FROM
854 "exclude\0" Required_argument "\xff"
855# endif
856 ;
857#endif
858
859int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
860int tar_main(int argc UNUSED_PARAM, char **argv)
861{
862 char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar;
863 archive_handle_t *tar_handle;
864 char *base_dir = NULL;
865 const char *tar_filename = "-";
866 unsigned opt;
867 int verboseFlag = 0;
868#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
869 llist_t *excludes = NULL;
870#endif
871
872
873 tar_handle = init_handle();
874 tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
875 | ARCHIVE_RESTORE_DATE
876 | ARCHIVE_UNLINK_OLD;
877
878
879 if (getuid() != 0)
880 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
881
882
883 opt_complementary = "--:"
884 "tt:vv:"
885 "?:"
886 "X::T::"
887#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
888 "\xff::"
889#endif
890 IF_FEATURE_TAR_CREATE("c:") "t:x:"
891 IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct")
892 IF_NOT_FEATURE_TAR_CREATE("t--x:x--t");
893#if ENABLE_FEATURE_TAR_LONG_OPTIONS
894 applet_long_options = tar_longopts;
895#endif
896#if ENABLE_DESKTOP
897 if (argv[1] && argv[1][0] != '-') {
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913 char *f = strchr(argv[1], 'f');
914 if (f) {
915 while (f[1] != '\0') {
916 *f = f[1];
917 f++;
918 }
919 *f = 'f';
920 }
921 }
922#endif
923 opt = getopt32(argv,
924 "txC:f:Oopvk"
925 IF_FEATURE_TAR_CREATE( "ch" )
926 IF_FEATURE_SEAMLESS_BZ2( "j" )
927 IF_FEATURE_SEAMLESS_LZMA("a" )
928 IF_FEATURE_TAR_FROM( "T:X:")
929 IF_FEATURE_SEAMLESS_GZ( "z" )
930 IF_FEATURE_SEAMLESS_Z( "Z" )
931 IF_FEATURE_TAR_NOPRESERVE_TIME("m")
932 , &base_dir
933 , &tar_filename
934 IF_FEATURE_TAR_FROM(, &(tar_handle->accept))
935 IF_FEATURE_TAR_FROM(, &(tar_handle->reject))
936 IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command))
937#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
938 , &excludes
939#endif
940 , &verboseFlag
941 , &verboseFlag
942 );
943
944 argv += optind;
945
946 if (verboseFlag) tar_handle->action_header = header_verbose_list;
947 if (verboseFlag == 1) tar_handle->action_header = header_list;
948
949 if (opt & OPT_EXTRACT)
950 tar_handle->action_data = data_extract_all;
951
952 if (opt & OPT_2STDOUT)
953 tar_handle->action_data = data_extract_to_stdout;
954
955 if (opt & OPT_2COMMAND) {
956 putenv((char*)"TAR_FILETYPE=f");
957 signal(SIGPIPE, SIG_IGN);
958 tar_handle->action_data = data_extract_to_command;
959 }
960
961 if (opt & OPT_KEEP_OLD)
962 tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
963
964 if (opt & OPT_NUMERIC_OWNER)
965 tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER;
966
967 if (opt & OPT_NOPRESERVE_OWNER)
968 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_OWNER;
969
970 if (opt & OPT_NOPRESERVE_PERM)
971 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
972
973 if (opt & OPT_OVERWRITE) {
974 tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
975 tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
976 }
977
978 if (opt & OPT_GZIP)
979 get_header_ptr = get_header_tar_gz;
980
981 if (opt & OPT_BZIP2)
982 get_header_ptr = get_header_tar_bz2;
983
984 if (opt & OPT_LZMA)
985 get_header_ptr = get_header_tar_lzma;
986
987 if (opt & OPT_COMPRESS)
988 get_header_ptr = get_header_tar_Z;
989
990 if (opt & OPT_NOPRESERVE_TIME)
991 tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE;
992
993#if ENABLE_FEATURE_TAR_FROM
994 tar_handle->reject = append_file_list_to_list(tar_handle->reject);
995# if ENABLE_FEATURE_TAR_LONG_OPTIONS
996
997 while (excludes) {
998 llist_t *next = excludes->link;
999 excludes->link = tar_handle->reject;
1000 tar_handle->reject = excludes;
1001 excludes = next;
1002 }
1003# endif
1004 tar_handle->accept = append_file_list_to_list(tar_handle->accept);
1005#endif
1006
1007
1008
1009 while (*argv) {
1010
1011 char *cp = last_char_is(*argv, '/');
1012 if (cp > *argv)
1013 *cp = '\0';
1014 llist_add_to_end(&tar_handle->accept, *argv);
1015 argv++;
1016 }
1017
1018 if (tar_handle->accept || tar_handle->reject)
1019 tar_handle->filter = filter_accept_reject_list;
1020
1021
1022 {
1023 int tar_fd = STDIN_FILENO;
1024 int flags = O_RDONLY;
1025
1026 if (opt & OPT_CREATE) {
1027
1028 if (tar_handle->accept == NULL)
1029 bb_error_msg_and_die("empty archive");
1030
1031 tar_fd = STDOUT_FILENO;
1032
1033 flags = O_WRONLY | O_CREAT | O_TRUNC;
1034 }
1035
1036 if (LONE_DASH(tar_filename)) {
1037 tar_handle->src_fd = tar_fd;
1038 tar_handle->seek = seek_by_read;
1039 } else {
1040 if (ENABLE_FEATURE_TAR_AUTODETECT
1041 && flags == O_RDONLY
1042 && get_header_ptr == get_header_tar
1043 ) {
1044 tar_handle->src_fd = open_zipped(tar_filename);
1045 if (tar_handle->src_fd < 0)
1046 bb_perror_msg_and_die("can't open '%s'", tar_filename);
1047 } else {
1048 tar_handle->src_fd = xopen(tar_filename, flags);
1049 }
1050 }
1051 }
1052
1053 if (base_dir)
1054 xchdir(base_dir);
1055
1056#ifdef CHECK_FOR_CHILD_EXITCODE
1057
1058 signal(SIGCHLD, handle_SIGCHLD);
1059#endif
1060
1061
1062 if (opt & OPT_CREATE) {
1063#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
1064 int zipMode = 0;
1065 if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP))
1066 zipMode = 1;
1067 if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2))
1068 zipMode = 2;
1069#endif
1070
1071 return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
1072 tar_handle->accept,
1073 tar_handle->reject, zipMode);
1074 }
1075
1076 while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
1077 continue;
1078
1079
1080 while (tar_handle->accept) {
1081 if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
1082 && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
1083 ) {
1084 bb_error_msg_and_die("%s: not found in archive",
1085 tar_handle->accept->data);
1086 }
1087 tar_handle->accept = tar_handle->accept->link;
1088 }
1089 if (ENABLE_FEATURE_CLEAN_UP )
1090 close(tar_handle->src_fd);
1091
1092 return EXIT_SUCCESS;
1093}
1094