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