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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147#include <fnmatch.h>
148#include "libbb.h"
149#include "common_bufsiz.h"
150#include "bb_archive.h"
151
152#ifndef FNM_LEADING_DIR
153# define FNM_LEADING_DIR 0
154#endif
155
156#if 0
157# define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
158#else
159# define DBG(...) ((void)0)
160#endif
161#define DBG_OPTION_PARSING 0
162
163
164#define block_buf bb_common_bufsiz1
165#define INIT_G() do { setup_common_bufsiz(); } while (0)
166
167
168#if ENABLE_FEATURE_TAR_CREATE
169
170
171
172
173
174
175typedef struct HardLinkInfo {
176 struct HardLinkInfo *next;
177 dev_t dev;
178 ino_t ino;
179
180 char name[1];
181} HardLinkInfo;
182
183
184typedef struct TarBallInfo {
185 int tarFd;
186
187 int verboseFlag;
188 const llist_t *excludeList;
189 HardLinkInfo *hlInfoHead;
190 HardLinkInfo *hlInfo;
191
192 struct stat tarFileStatBuf;
193
194
195
196} TarBallInfo;
197
198
199enum {
200 REGTYPE = '0',
201 REGTYPE0 = '\0',
202 LNKTYPE = '1',
203 SYMTYPE = '2',
204 CHRTYPE = '3',
205 BLKTYPE = '4',
206 DIRTYPE = '5',
207 FIFOTYPE = '6',
208 CONTTYPE = '7',
209 GNULONGLINK = 'K',
210 GNULONGNAME = 'L',
211};
212
213
214static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr,
215 struct stat *statbuf,
216 const char *fileName)
217{
218
219 HardLinkInfo *hlInfo;
220
221 hlInfo = xmalloc(sizeof(HardLinkInfo) + strlen(fileName));
222 hlInfo->next = *hlInfoHeadPtr;
223 *hlInfoHeadPtr = hlInfo;
224 hlInfo->dev = statbuf->st_dev;
225 hlInfo->ino = statbuf->st_ino;
226
227 strcpy(hlInfo->name, fileName);
228}
229
230static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr)
231{
232 HardLinkInfo *hlInfo;
233 HardLinkInfo *hlInfoNext;
234
235 if (hlInfoHeadPtr) {
236 hlInfo = *hlInfoHeadPtr;
237 while (hlInfo) {
238 hlInfoNext = hlInfo->next;
239 free(hlInfo);
240 hlInfo = hlInfoNext;
241 }
242 *hlInfoHeadPtr = NULL;
243 }
244}
245
246
247static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf)
248{
249 while (hlInfo) {
250 if (statbuf->st_ino == hlInfo->ino
251 && statbuf->st_dev == hlInfo->dev
252 ) {
253 DBG("found hardlink:'%s'", hlInfo->name);
254 break;
255 }
256 hlInfo = hlInfo->next;
257 }
258 return hlInfo;
259}
260
261
262
263
264static void putOctal(char *cp, int len, off_t value)
265{
266 char tempBuffer[sizeof(off_t)*3 + 1];
267 char *tempString = tempBuffer;
268 int width;
269
270 width = sprintf(tempBuffer, "%0*"OFF_FMT"o", len, value);
271 tempString += (width - len);
272
273
274
275
276 if (tempString[0] == '0')
277 tempString++;
278
279
280 memcpy(cp, tempString, len);
281}
282#define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
283
284static void chksum_and_xwrite(int fd, struct tar_header_t* hp)
285{
286
287
288
289 const unsigned char *cp;
290 int chksum, size;
291
292 strcpy(hp->magic, "ustar ");
293
294
295
296
297
298
299 memset(hp->chksum, ' ', sizeof(hp->chksum));
300 cp = (const unsigned char *) hp;
301 chksum = 0;
302 size = sizeof(*hp);
303 do { chksum += *cp++; } while (--size);
304 putOctal(hp->chksum, sizeof(hp->chksum)-1, chksum);
305
306
307 xwrite(fd, hp, sizeof(*hp));
308}
309
310#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
311static void writeLongname(int fd, int type, const char *name, int dir)
312{
313 static const struct {
314 char mode[8];
315 char uid[8];
316 char gid[8];
317 char size[12];
318 char mtime[12];
319 } prefilled = {
320 "0000000",
321 "0000000",
322 "0000000",
323 "00000000000",
324 "00000000000",
325 };
326 struct tar_header_t header;
327 int size;
328
329 dir = !!dir;
330 size = strlen(name) + 1 + dir;
331
332
333 memset(&header, 0, sizeof(header));
334 strcpy(header.name, "././@LongLink");
335 memcpy(header.mode, prefilled.mode, sizeof(prefilled));
336 PUT_OCTAL(header.size, size);
337 header.typeflag = type;
338 chksum_and_xwrite(fd, &header);
339
340
341
342
343 dir *= 2;
344 xwrite(fd, name, size - dir);
345 xwrite(fd, "/", dir);
346 size = (-size) & (TAR_BLOCK_SIZE-1);
347 memset(&header, 0, size);
348 xwrite(fd, &header, size);
349}
350#endif
351
352
353static int writeTarHeader(struct TarBallInfo *tbInfo,
354 const char *header_name, const char *fileName, struct stat *statbuf)
355{
356 struct tar_header_t header;
357
358 memset(&header, 0, sizeof(header));
359
360 strncpy(header.name, header_name, sizeof(header.name));
361
362
363 PUT_OCTAL(header.mode, statbuf->st_mode & 07777);
364 PUT_OCTAL(header.uid, statbuf->st_uid);
365 PUT_OCTAL(header.gid, statbuf->st_gid);
366 memset(header.size, '0', sizeof(header.size)-1);
367
368 PUT_OCTAL(header.mtime, statbuf->st_mtime >= 0 ? statbuf->st_mtime : 0);
369
370
371 safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname));
372 safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname));
373
374 if (tbInfo->hlInfo) {
375
376 header.typeflag = LNKTYPE;
377 strncpy(header.linkname, tbInfo->hlInfo->name,
378 sizeof(header.linkname));
379#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
380
381 if (header.linkname[sizeof(header.linkname)-1])
382 writeLongname(tbInfo->tarFd, GNULONGLINK,
383 tbInfo->hlInfo->name, 0);
384#endif
385 } else if (S_ISLNK(statbuf->st_mode)) {
386 char *lpath = xmalloc_readlink_or_warn(fileName);
387 if (!lpath)
388 return FALSE;
389 header.typeflag = SYMTYPE;
390 strncpy(header.linkname, lpath, sizeof(header.linkname));
391#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
392
393 if (header.linkname[sizeof(header.linkname)-1])
394 writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0);
395#else
396
397 if (header.linkname[sizeof(header.linkname)-1]) {
398 free(lpath);
399 bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
400 return FALSE;
401 }
402#endif
403 free(lpath);
404 } else if (S_ISDIR(statbuf->st_mode)) {
405 header.typeflag = DIRTYPE;
406
407 if (!header.name[sizeof(header.name)-1])
408 header.name[strlen(header.name)] = '/';
409 } else if (S_ISCHR(statbuf->st_mode)) {
410 header.typeflag = CHRTYPE;
411 PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
412 PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
413 } else if (S_ISBLK(statbuf->st_mode)) {
414 header.typeflag = BLKTYPE;
415 PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
416 PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
417 } else if (S_ISFIFO(statbuf->st_mode)) {
418 header.typeflag = FIFOTYPE;
419 } else if (S_ISREG(statbuf->st_mode)) {
420
421
422 uoff_t filesize = statbuf->st_size;
423 if (sizeof(filesize) <= 4
424 || filesize <= (uoff_t)0777777777777LL
425 ) {
426 PUT_OCTAL(header.size, filesize);
427 }
428
429
430
431 else if (ENABLE_FEATURE_TAR_GNU_EXTENSIONS
432#if ULLONG_MAX > 0xffffffffffffffffLL
433 && (filesize <= 0x3fffffffffffffffffffffffLL)
434#endif
435 ) {
436
437
438
439
440
441
442
443
444 char *p8 = header.size + sizeof(header.size);
445 do {
446 *--p8 = (uint8_t)filesize;
447 filesize >>= 8;
448 } while (p8 != header.size);
449 *p8 |= 0x80;
450 } else {
451 bb_error_msg_and_die("can't store file '%s' "
452 "of size %"OFF_FMT"u, aborting",
453 fileName, statbuf->st_size);
454 }
455 header.typeflag = REGTYPE;
456 } else {
457 bb_error_msg("%s: unknown file type", fileName);
458 return FALSE;
459 }
460
461#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
462
463
464 if (header.name[sizeof(header.name)-1])
465 writeLongname(tbInfo->tarFd, GNULONGNAME,
466 header_name, S_ISDIR(statbuf->st_mode));
467#endif
468
469
470 chksum_and_xwrite(tbInfo->tarFd, &header);
471
472
473 if (tbInfo->verboseFlag) {
474 FILE *vbFd = stdout;
475
476
477 if (tbInfo->tarFd == STDOUT_FILENO)
478 vbFd = stderr;
479
480
481
482 fprintf(vbFd, "%s%s\n", header_name,
483 S_ISDIR(statbuf->st_mode) ? "/" : "");
484 }
485
486 return TRUE;
487}
488
489#if ENABLE_FEATURE_TAR_FROM
490static int exclude_file(const llist_t *excluded_files, const char *file)
491{
492 while (excluded_files) {
493 if (excluded_files->data[0] == '/') {
494 if (fnmatch(excluded_files->data, file,
495 FNM_PATHNAME | FNM_LEADING_DIR) == 0)
496 return 1;
497 } else {
498 const char *p;
499
500 for (p = file; p[0] != '\0'; p++) {
501 if ((p == file || p[-1] == '/')
502 && p[0] != '/'
503 && fnmatch(excluded_files->data, p,
504 FNM_PATHNAME | FNM_LEADING_DIR) == 0
505 ) {
506 return 1;
507 }
508 }
509 }
510 excluded_files = excluded_files->link;
511 }
512
513 return 0;
514}
515#else
516# define exclude_file(excluded_files, file) 0
517#endif
518
519static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
520 void *userData, int depth UNUSED_PARAM)
521{
522 struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
523 const char *header_name;
524 int inputFileFd = -1;
525
526 DBG("writeFileToTarball('%s')", fileName);
527
528
529 header_name = strip_unsafe_prefix(fileName);
530
531 if (header_name[0] == '\0')
532 return TRUE;
533
534
535 if (S_ISSOCK(statbuf->st_mode)) {
536 bb_error_msg("%s: socket ignored", fileName);
537 return TRUE;
538 }
539
540
541
542
543
544
545
546
547 tbInfo->hlInfo = NULL;
548 if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) {
549 DBG("'%s': st_nlink > 1", header_name);
550 tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
551 if (tbInfo->hlInfo == NULL) {
552 DBG("'%s': addHardLinkInfo", header_name);
553 addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
554 }
555 }
556
557
558
559
560 if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
561 && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
562 ) {
563 bb_error_msg("%s: file is the archive; skipping", fileName);
564 return TRUE;
565 }
566
567 if (exclude_file(tbInfo->excludeList, header_name))
568 return SKIP;
569
570#if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
571 if (strlen(header_name) >= NAME_SIZE) {
572 bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
573 return TRUE;
574 }
575#endif
576
577
578 if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
579
580 inputFileFd = open_or_warn(fileName, O_RDONLY);
581 if (inputFileFd < 0) {
582 return FALSE;
583 }
584 }
585
586
587 if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
588 return FALSE;
589 }
590
591
592 if (inputFileFd >= 0) {
593 size_t readSize;
594
595
596
597
598
599
600 bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
601
602
603
604
605
606
607
608
609
610 close(inputFileFd);
611
612
613
614 readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
615 memset(block_buf, 0, readSize);
616 xwrite(tbInfo->tarFd, block_buf, readSize);
617 }
618
619 return TRUE;
620}
621
622#if SEAMLESS_COMPRESSION
623
624static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
625{
626 pid_t gzipPid;
627
628
629
630# define WAIT_FOR_CHILD 0
631 volatile int vfork_exec_errno = 0;
632 struct fd_pair gzipDataPipe;
633# if WAIT_FOR_CHILD
634 struct fd_pair gzipStatusPipe;
635 xpiped_pair(gzipStatusPipe);
636# endif
637 xpiped_pair(gzipDataPipe);
638
639 signal(SIGPIPE, SIG_IGN);
640
641 gzipPid = xvfork();
642
643 if (gzipPid == 0) {
644
645
646 close(gzipDataPipe.wr);
647# if WAIT_FOR_CHILD
648 close(gzipStatusPipe.rd);
649
650
651 fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
652# endif
653 xmove_fd(gzipDataPipe.rd, 0);
654 xmove_fd(tar_fd, 1);
655
656 BB_EXECLP(gzip, gzip, "-f", (char *)0);
657 vfork_exec_errno = errno;
658 _exit(EXIT_FAILURE);
659 }
660
661
662 xmove_fd(gzipDataPipe.wr, tar_fd);
663 close(gzipDataPipe.rd);
664# if WAIT_FOR_CHILD
665 close(gzipStatusPipe.wr);
666 while (1) {
667 char buf;
668 int n;
669
670
671 n = full_read(gzipStatusPipe.rd, &buf, 1);
672 if (n < 0 )
673 continue;
674 }
675 close(gzipStatusPipe.rd);
676# endif
677 if (vfork_exec_errno) {
678 errno = vfork_exec_errno;
679 bb_perror_msg_and_die("can't execute '%s'", gzip);
680 }
681}
682#endif
683
684
685#if !SEAMLESS_COMPRESSION
686
687#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \
688 writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude)
689#endif
690
691static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
692 int recurseFlags, const llist_t *include,
693 const llist_t *exclude, const char *gzip)
694{
695 int errorFlag = FALSE;
696 struct TarBallInfo tbInfo;
697
698 tbInfo.hlInfoHead = NULL;
699 tbInfo.tarFd = tar_fd;
700 tbInfo.verboseFlag = verboseFlag;
701
702
703
704 xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file");
705
706#if SEAMLESS_COMPRESSION
707 if (gzip)
708 vfork_compressor(tbInfo.tarFd, gzip);
709#endif
710
711 tbInfo.excludeList = exclude;
712
713
714 while (include) {
715 if (!recursive_action(include->data, recurseFlags,
716 writeFileToTarball, writeFileToTarball, &tbInfo, 0)
717 ) {
718 errorFlag = TRUE;
719 }
720 include = include->link;
721 }
722
723 memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
724 xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE);
725
726
727
728
729
730
731
732 close(tbInfo.tarFd);
733
734
735 if (ENABLE_FEATURE_CLEAN_UP)
736 freeHardLinkInfo(&tbInfo.hlInfoHead);
737
738 if (errorFlag)
739 bb_error_msg("error exit delayed from previous errors");
740
741#if SEAMLESS_COMPRESSION
742 if (gzip) {
743 int status;
744 if (safe_waitpid(-1, &status, 0) == -1)
745 bb_perror_msg("waitpid");
746 else if (!WIFEXITED(status) || WEXITSTATUS(status))
747
748 errorFlag = TRUE;
749 }
750#endif
751 return errorFlag;
752}
753#else
754# define writeTarFile(...) 0
755#endif
756
757#if ENABLE_FEATURE_TAR_FROM
758static llist_t *append_file_list_to_list(llist_t *list)
759{
760 FILE *src_stream;
761 char *line;
762 llist_t *newlist = NULL;
763
764 while (list) {
765 src_stream = xfopen_stdin(llist_pop(&list));
766 while ((line = xmalloc_fgetline(src_stream)) != NULL) {
767
768 char *cp = last_char_is(line, '/');
769 if (cp > line)
770 *cp = '\0';
771 llist_add_to_end(&newlist, line);
772 }
773 fclose(src_stream);
774 }
775 return newlist;
776}
777#endif
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850enum {
851 OPTBIT_KEEP_OLD = 8,
852 IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,)
853 IF_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE ,)
854 IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2 ,)
855 IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA ,)
856 IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,)
857 IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,)
858 IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP ,)
859 IF_FEATURE_SEAMLESS_XZ( OPTBIT_XZ ,)
860 IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,)
861 IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
862#if ENABLE_FEATURE_TAR_LONG_OPTIONS
863 OPTBIT_STRIP_COMPONENTS,
864 OPTBIT_NORECURSION,
865 IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,)
866 OPTBIT_NUMERIC_OWNER,
867 OPTBIT_NOPRESERVE_PERM,
868 OPTBIT_OVERWRITE,
869#endif
870 OPT_TEST = 1 << 0,
871 OPT_EXTRACT = 1 << 1,
872 OPT_BASEDIR = 1 << 2,
873 OPT_TARNAME = 1 << 3,
874 OPT_2STDOUT = 1 << 4,
875 OPT_NOPRESERVE_OWNER = 1 << 5,
876 OPT_P = 1 << 6,
877 OPT_VERBOSE = 1 << 7,
878 OPT_KEEP_OLD = 1 << 8,
879 OPT_CREATE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_CREATE )) + 0,
880 OPT_DEREFERENCE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_DEREFERENCE )) + 0,
881 OPT_BZIP2 = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2 )) + 0,
882 OPT_LZMA = IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA )) + 0,
883 OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM)) + 0,
884 OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM)) + 0,
885 OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0,
886 OPT_XZ = IF_FEATURE_SEAMLESS_XZ( (1 << OPTBIT_XZ )) + 0,
887 OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0,
888 OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0,
889 OPT_STRIP_COMPONENTS = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_STRIP_COMPONENTS)) + 0,
890 OPT_NORECURSION = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION )) + 0,
891 OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0,
892 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0,
893 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0,
894 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0,
895
896 OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_XZ | OPT_COMPRESS),
897};
898#if ENABLE_FEATURE_TAR_LONG_OPTIONS
899static const char tar_longopts[] ALIGN1 =
900 "list\0" No_argument "t"
901 "extract\0" No_argument "x"
902 "directory\0" Required_argument "C"
903 "file\0" Required_argument "f"
904 "to-stdout\0" No_argument "O"
905
906
907
908 "no-same-owner\0" No_argument "o"
909 "same-permissions\0" No_argument "p"
910 "verbose\0" No_argument "v"
911 "keep-old\0" No_argument "k"
912# if ENABLE_FEATURE_TAR_CREATE
913 "create\0" No_argument "c"
914 "dereference\0" No_argument "h"
915# endif
916# if ENABLE_FEATURE_SEAMLESS_BZ2
917 "bzip2\0" No_argument "j"
918# endif
919# if ENABLE_FEATURE_SEAMLESS_LZMA
920 "lzma\0" No_argument "a"
921# endif
922# if ENABLE_FEATURE_TAR_FROM
923 "files-from\0" Required_argument "T"
924 "exclude-from\0" Required_argument "X"
925# endif
926# if ENABLE_FEATURE_SEAMLESS_GZ
927 "gzip\0" No_argument "z"
928# endif
929# if ENABLE_FEATURE_SEAMLESS_XZ
930 "xz\0" No_argument "J"
931# endif
932# if ENABLE_FEATURE_SEAMLESS_Z
933 "compress\0" No_argument "Z"
934# endif
935# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
936 "touch\0" No_argument "m"
937# endif
938 "strip-components\0" Required_argument "\xf9"
939 "no-recursion\0" No_argument "\xfa"
940# if ENABLE_FEATURE_TAR_TO_COMMAND
941 "to-command\0" Required_argument "\xfb"
942# endif
943
944 "numeric-owner\0" No_argument "\xfc"
945
946 "no-same-permissions\0" No_argument "\xfd"
947
948 "overwrite\0" No_argument "\xfe"
949
950
951# if ENABLE_FEATURE_TAR_FROM
952 "exclude\0" Required_argument "\xff"
953# endif
954 ;
955#endif
956
957int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
958int tar_main(int argc UNUSED_PARAM, char **argv)
959{
960 archive_handle_t *tar_handle;
961 char *base_dir = NULL;
962 const char *tar_filename = "-";
963 unsigned opt;
964 int verboseFlag = 0;
965#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
966 llist_t *excludes = NULL;
967#endif
968 INIT_G();
969
970
971 tar_handle = init_handle();
972 tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
973 | ARCHIVE_RESTORE_DATE
974 | ARCHIVE_UNLINK_OLD;
975
976
977 if (getuid() != 0)
978 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
979
980
981 opt_complementary = "--:"
982 "tt:vv:"
983#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
984 "\xff::"
985#endif
986 IF_FEATURE_TAR_CREATE("c:") "t:x:"
987 IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct")
988 IF_NOT_FEATURE_TAR_CREATE("t--x:x--t")
989#if ENABLE_FEATURE_TAR_LONG_OPTIONS
990 ":\xf9+"
991#endif
992 ;
993#if ENABLE_FEATURE_TAR_LONG_OPTIONS
994 applet_long_options = tar_longopts;
995#endif
996#if ENABLE_DESKTOP
997
998 if (argv[1] && strcmp(argv[1], "--version") == 0) {
999
1000
1001
1002
1003 puts("tar (busybox) " BB_VER);
1004 return 0;
1005 }
1006 if (argv[1] && argv[1][0] != '-') {
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022 char *f = strchr(argv[1], 'f');
1023 if (f) {
1024 while (f[1] != '\0') {
1025 *f = f[1];
1026 f++;
1027 }
1028 *f = 'f';
1029 }
1030 }
1031#endif
1032 opt = getopt32(argv,
1033 "txC:f:Oopvk"
1034 IF_FEATURE_TAR_CREATE( "ch" )
1035 IF_FEATURE_SEAMLESS_BZ2( "j" )
1036 IF_FEATURE_SEAMLESS_LZMA("a" )
1037 IF_FEATURE_TAR_FROM( "T:*X:*")
1038 IF_FEATURE_SEAMLESS_GZ( "z" )
1039 IF_FEATURE_SEAMLESS_XZ( "J" )
1040 IF_FEATURE_SEAMLESS_Z( "Z" )
1041 IF_FEATURE_TAR_NOPRESERVE_TIME("m")
1042 IF_FEATURE_TAR_LONG_OPTIONS("\xf9:")
1043 , &base_dir
1044 , &tar_filename
1045 IF_FEATURE_TAR_FROM(, &(tar_handle->accept))
1046 IF_FEATURE_TAR_FROM(, &(tar_handle->reject))
1047#if ENABLE_FEATURE_TAR_LONG_OPTIONS
1048 , &tar_handle->tar__strip_components
1049#endif
1050 IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command))
1051#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
1052 , &excludes
1053#endif
1054 , &verboseFlag
1055 , &verboseFlag
1056 );
1057#if DBG_OPTION_PARSING
1058 bb_error_msg("opt: 0x%08x", opt);
1059# define showopt(o) bb_error_msg("opt & %s(%x): %x", #o, o, opt & o);
1060 showopt(OPT_TEST );
1061 showopt(OPT_EXTRACT );
1062 showopt(OPT_BASEDIR );
1063 showopt(OPT_TARNAME );
1064 showopt(OPT_2STDOUT );
1065 showopt(OPT_NOPRESERVE_OWNER);
1066 showopt(OPT_P );
1067 showopt(OPT_VERBOSE );
1068 showopt(OPT_KEEP_OLD );
1069 showopt(OPT_CREATE );
1070 showopt(OPT_DEREFERENCE );
1071 showopt(OPT_BZIP2 );
1072 showopt(OPT_LZMA );
1073 showopt(OPT_INCLUDE_FROM );
1074 showopt(OPT_EXCLUDE_FROM );
1075 showopt(OPT_GZIP );
1076 showopt(OPT_XZ );
1077 showopt(OPT_COMPRESS );
1078 showopt(OPT_NOPRESERVE_TIME );
1079 showopt(OPT_STRIP_COMPONENTS);
1080 showopt(OPT_NORECURSION );
1081 showopt(OPT_2COMMAND );
1082 showopt(OPT_NUMERIC_OWNER );
1083 showopt(OPT_NOPRESERVE_PERM );
1084 showopt(OPT_OVERWRITE );
1085 showopt(OPT_ANY_COMPRESS );
1086 bb_error_msg("base_dir:'%s'", base_dir);
1087 bb_error_msg("tar_filename:'%s'", tar_filename);
1088 bb_error_msg("verboseFlag:%d", verboseFlag);
1089 bb_error_msg("tar_handle->tar__to_command:'%s'", tar_handle->tar__to_command);
1090 bb_error_msg("tar_handle->tar__strip_components:%u", tar_handle->tar__strip_components);
1091 return 0;
1092# undef showopt
1093#endif
1094 argv += optind;
1095
1096 if (verboseFlag)
1097 tar_handle->action_header = header_verbose_list;
1098 if (verboseFlag == 1)
1099 tar_handle->action_header = header_list;
1100
1101 if (opt & OPT_EXTRACT)
1102 tar_handle->action_data = data_extract_all;
1103
1104 if (opt & OPT_2STDOUT)
1105 tar_handle->action_data = data_extract_to_stdout;
1106
1107 if (opt & OPT_2COMMAND) {
1108 putenv((char*)"TAR_FILETYPE=f");
1109 signal(SIGPIPE, SIG_IGN);
1110 tar_handle->action_data = data_extract_to_command;
1111 IF_FEATURE_TAR_TO_COMMAND(tar_handle->tar__to_command_shell = xstrdup(get_shell_name());)
1112 }
1113
1114 if (opt & OPT_KEEP_OLD)
1115 tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
1116
1117 if (opt & OPT_NUMERIC_OWNER)
1118 tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER;
1119
1120 if (opt & OPT_NOPRESERVE_OWNER)
1121 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_OWNER;
1122
1123 if (opt & OPT_NOPRESERVE_PERM)
1124 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
1125
1126 if (opt & OPT_OVERWRITE) {
1127 tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
1128 tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
1129 }
1130
1131 if (opt & OPT_NOPRESERVE_TIME)
1132 tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE;
1133
1134#if ENABLE_FEATURE_TAR_FROM
1135 tar_handle->reject = append_file_list_to_list(tar_handle->reject);
1136# if ENABLE_FEATURE_TAR_LONG_OPTIONS
1137
1138 while (excludes) {
1139 llist_t *next = excludes->link;
1140 excludes->link = tar_handle->reject;
1141 tar_handle->reject = excludes;
1142 excludes = next;
1143 }
1144# endif
1145 tar_handle->accept = append_file_list_to_list(tar_handle->accept);
1146#endif
1147
1148
1149
1150 while (*argv) {
1151
1152 char *cp = last_char_is(*argv, '/');
1153 if (cp > *argv)
1154 *cp = '\0';
1155 llist_add_to_end(&tar_handle->accept, *argv);
1156 argv++;
1157 }
1158
1159 if (tar_handle->accept || tar_handle->reject)
1160 tar_handle->filter = filter_accept_reject_list;
1161
1162
1163 {
1164 int tar_fd = STDIN_FILENO;
1165 int flags = O_RDONLY;
1166
1167 if (opt & OPT_CREATE) {
1168
1169 if (tar_handle->accept == NULL)
1170 bb_error_msg_and_die("empty archive");
1171
1172 tar_fd = STDOUT_FILENO;
1173
1174 flags = O_WRONLY | O_CREAT | O_TRUNC;
1175 }
1176
1177 if (LONE_DASH(tar_filename)) {
1178 tar_handle->src_fd = tar_fd;
1179 tar_handle->seek = seek_by_read;
1180 } else {
1181 if (ENABLE_FEATURE_TAR_AUTODETECT
1182 && flags == O_RDONLY
1183 && !(opt & OPT_ANY_COMPRESS)
1184 ) {
1185 tar_handle->src_fd = open_zipped(tar_filename, 0);
1186 if (tar_handle->src_fd < 0)
1187 bb_perror_msg_and_die("can't open '%s'", tar_filename);
1188 } else {
1189 tar_handle->src_fd = xopen(tar_filename, flags);
1190 }
1191 }
1192 }
1193
1194 if (base_dir)
1195 xchdir(base_dir);
1196
1197
1198
1199
1200
1201#if ENABLE_FEATURE_TAR_CREATE
1202
1203 if (opt & OPT_CREATE) {
1204# if SEAMLESS_COMPRESSION
1205 const char *zipMode = NULL;
1206 if (opt & OPT_COMPRESS)
1207 zipMode = "compress";
1208 if (opt & OPT_GZIP)
1209 zipMode = "gzip";
1210 if (opt & OPT_BZIP2)
1211 zipMode = "bzip2";
1212 if (opt & OPT_LZMA)
1213 zipMode = "lzma";
1214 if (opt & OPT_XZ)
1215 zipMode = "xz";
1216# endif
1217
1218 return writeTarFile(tar_handle->src_fd, verboseFlag,
1219 (opt & OPT_DEREFERENCE ? ACTION_FOLLOWLINKS : 0)
1220 | (opt & OPT_NORECURSION ? 0 : ACTION_RECURSE),
1221 tar_handle->accept,
1222 tar_handle->reject, zipMode);
1223 }
1224#endif
1225
1226 if (opt & OPT_ANY_COMPRESS) {
1227 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate);)
1228 USE_FOR_NOMMU(const char *xformer_prog;)
1229
1230 if (opt & OPT_COMPRESS)
1231 USE_FOR_MMU(xformer = unpack_Z_stream;)
1232 USE_FOR_NOMMU(xformer_prog = "uncompress";)
1233 if (opt & OPT_GZIP)
1234 USE_FOR_MMU(xformer = unpack_gz_stream;)
1235 USE_FOR_NOMMU(xformer_prog = "gunzip";)
1236 if (opt & OPT_BZIP2)
1237 USE_FOR_MMU(xformer = unpack_bz2_stream;)
1238 USE_FOR_NOMMU(xformer_prog = "bunzip2";)
1239 if (opt & OPT_LZMA)
1240 USE_FOR_MMU(xformer = unpack_lzma_stream;)
1241 USE_FOR_NOMMU(xformer_prog = "unlzma";)
1242 if (opt & OPT_XZ)
1243 USE_FOR_MMU(xformer = unpack_xz_stream;)
1244 USE_FOR_NOMMU(xformer_prog = "unxz";)
1245
1246 fork_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog);
1247
1248 tar_handle->seek = seek_by_read;
1249
1250 }
1251
1252
1253
1254
1255
1256 bb_got_signal = EXIT_FAILURE;
1257
1258 while (get_header_tar(tar_handle) == EXIT_SUCCESS)
1259 bb_got_signal = EXIT_SUCCESS;
1260
1261
1262 while (tar_handle->accept) {
1263 if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
1264 && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
1265 ) {
1266 bb_error_msg_and_die("%s: not found in archive",
1267 tar_handle->accept->data);
1268 }
1269 tar_handle->accept = tar_handle->accept->link;
1270 }
1271 if (ENABLE_FEATURE_CLEAN_UP )
1272 close(tar_handle->src_fd);
1273
1274 if (SEAMLESS_COMPRESSION || OPT_COMPRESS) {
1275
1276 check_errors_in_children(0);
1277 }
1278
1279 return bb_got_signal;
1280}
1281