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 struct prefilled {
287 char mode[8];
288 char uid[8];
289 char gid[8];
290 char size[12];
291 char mtime[12];
292 };
293 struct tar_header_t header;
294 int size;
295
296 memset(&header, 0, sizeof(header));
297 header.typeflag = type;
298 strcpy(header.name, "././@LongLink");
299
300 memset((char*)&header + offsetof(struct tar_header_t, mode),
301 '0', sizeof(struct prefilled));
302 header.mode [sizeof(header.mode ) - 1] = '\0';
303 header.uid [sizeof(header.uid ) - 1] = '\0';
304 header.gid [sizeof(header.gid ) - 1] = '\0';
305
306 header.mtime[sizeof(header.mtime) - 1] = '\0';
307
308 dir = !!dir;
309 size = strlen(name) + 1 + dir;
310
311
312 PUT_OCTAL(header.size, size);
313 chksum_and_xwrite(fd, &header);
314
315
316
317
318 dir *= 2;
319 xwrite(fd, name, size - dir);
320 xwrite(fd, "/", dir);
321 size = (-size) & (TAR_BLOCK_SIZE-1);
322 memset(&header, 0, size);
323 xwrite(fd, &header, size);
324}
325# endif
326
327
328static int writeTarHeader(struct TarBallInfo *tbInfo,
329 const char *header_name, const char *fileName, struct stat *statbuf)
330{
331 struct tar_header_t header;
332
333 memset(&header, 0, sizeof(header));
334
335 strncpy(header.name, header_name, sizeof(header.name));
336
337
338 PUT_OCTAL(header.mode, statbuf->st_mode & 07777);
339 PUT_OCTAL(header.uid, statbuf->st_uid);
340 PUT_OCTAL(header.gid, statbuf->st_gid);
341 memset(header.size, '0', sizeof(header.size)-1);
342
343 PUT_OCTAL(header.mtime, statbuf->st_mtime >= 0 ? statbuf->st_mtime : 0);
344
345
346 safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname));
347 safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname));
348
349 if (tbInfo->hlInfo) {
350
351 header.typeflag = LNKTYPE;
352 strncpy(header.linkname, tbInfo->hlInfo->name,
353 sizeof(header.linkname));
354# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
355
356 if (header.linkname[sizeof(header.linkname)-1])
357 writeLongname(tbInfo->tarFd, GNULONGLINK,
358 tbInfo->hlInfo->name, 0);
359# endif
360 } else if (S_ISLNK(statbuf->st_mode)) {
361 char *lpath = xmalloc_readlink_or_warn(fileName);
362 if (!lpath)
363 return FALSE;
364 header.typeflag = SYMTYPE;
365 strncpy(header.linkname, lpath, sizeof(header.linkname));
366# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
367
368 if (header.linkname[sizeof(header.linkname)-1])
369 writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0);
370# else
371
372 if (header.linkname[sizeof(header.linkname)-1]) {
373 free(lpath);
374 bb_simple_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
375 return FALSE;
376 }
377# endif
378 free(lpath);
379 } else if (S_ISDIR(statbuf->st_mode)) {
380 header.typeflag = DIRTYPE;
381
382 if (!header.name[sizeof(header.name)-1])
383 header.name[strlen(header.name)] = '/';
384 } else if (S_ISCHR(statbuf->st_mode)) {
385 header.typeflag = CHRTYPE;
386 PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
387 PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
388 } else if (S_ISBLK(statbuf->st_mode)) {
389 header.typeflag = BLKTYPE;
390 PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
391 PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
392 } else if (S_ISFIFO(statbuf->st_mode)) {
393 header.typeflag = FIFOTYPE;
394 } else if (S_ISREG(statbuf->st_mode)) {
395
396
397 uoff_t filesize = statbuf->st_size;
398 if (sizeof(filesize) <= 4
399 || filesize <= (uoff_t)0777777777777LL
400 ) {
401 PUT_OCTAL(header.size, filesize);
402 }
403
404
405
406 else if (ENABLE_FEATURE_TAR_GNU_EXTENSIONS
407# if ULLONG_MAX > 0xffffffffffffffffLL
408 && (filesize <= 0x3fffffffffffffffffffffffLL)
409# endif
410 ) {
411
412
413
414
415
416
417
418
419 char *p8 = header.size + sizeof(header.size);
420 do {
421 *--p8 = (uint8_t)filesize;
422 filesize >>= 8;
423 } while (p8 != header.size);
424 *p8 |= 0x80;
425 } else {
426 bb_error_msg_and_die("can't store file '%s' "
427 "of size %"OFF_FMT"u, aborting",
428 fileName, statbuf->st_size);
429 }
430 header.typeflag = REGTYPE;
431 } else {
432 bb_error_msg("%s: unknown file type", fileName);
433 return FALSE;
434 }
435
436# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
437
438
439 if (header.name[sizeof(header.name)-1])
440 writeLongname(tbInfo->tarFd, GNULONGNAME,
441 header_name, S_ISDIR(statbuf->st_mode));
442# endif
443
444
445 chksum_and_xwrite(tbInfo->tarFd, &header);
446
447
448 if (tbInfo->verboseFlag) {
449 FILE *vbFd = stdout;
450
451
452 if (tbInfo->tarFd == STDOUT_FILENO)
453 vbFd = stderr;
454
455
456
457 fprintf(vbFd, "%s%s\n", header_name,
458 S_ISDIR(statbuf->st_mode) ? "/" : "");
459 }
460
461 return TRUE;
462}
463
464# if ENABLE_FEATURE_TAR_FROM
465static int exclude_file(const llist_t *excluded_files, const char *file)
466{
467 while (excluded_files) {
468 if (excluded_files->data[0] == '/') {
469 if (fnmatch(excluded_files->data, file,
470 FNM_PATHNAME | FNM_LEADING_DIR) == 0)
471 return 1;
472 } else {
473 const char *p;
474
475 for (p = file; p[0] != '\0'; p++) {
476 if ((p == file || p[-1] == '/')
477 && p[0] != '/'
478 && fnmatch(excluded_files->data, p,
479 FNM_PATHNAME | FNM_LEADING_DIR) == 0
480 ) {
481 return 1;
482 }
483 }
484 }
485 excluded_files = excluded_files->link;
486 }
487
488 return 0;
489}
490# else
491# define exclude_file(excluded_files, file) 0
492# endif
493
494static int FAST_FUNC writeFileToTarball(struct recursive_state *state,
495 const char *fileName,
496 struct stat *statbuf)
497{
498 struct TarBallInfo *tbInfo = (struct TarBallInfo *) state->userData;
499 const char *header_name;
500 int inputFileFd = -1;
501
502 DBG("writeFileToTarball('%s')", fileName);
503
504
505 header_name = strip_unsafe_prefix(fileName);
506
507 if (header_name[0] == '\0')
508 return TRUE;
509
510 if (exclude_file(tbInfo->excludeList, header_name))
511 return SKIP;
512
513
514 if (S_ISSOCK(statbuf->st_mode)) {
515 bb_error_msg("%s: socket ignored", fileName);
516 return TRUE;
517 }
518
519
520
521
522
523
524
525
526 tbInfo->hlInfo = NULL;
527 if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) {
528 DBG("'%s': st_nlink > 1", header_name);
529 tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
530 if (tbInfo->hlInfo == NULL) {
531 DBG("'%s': addHardLinkInfo", header_name);
532 addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
533 }
534 }
535
536
537
538
539 if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
540 && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
541 ) {
542 bb_error_msg("%s: file is the archive; skipping", fileName);
543 return TRUE;
544 }
545
546# if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
547 if (strlen(header_name) >= NAME_SIZE) {
548 bb_simple_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
549 return TRUE;
550 }
551# endif
552
553
554 if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
555
556 inputFileFd = open_or_warn(fileName, O_RDONLY);
557 if (inputFileFd < 0) {
558 return FALSE;
559 }
560 }
561
562
563 if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
564 return FALSE;
565 }
566
567
568 if (inputFileFd >= 0) {
569 size_t readSize;
570
571
572
573
574
575
576 bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
577
578
579
580
581
582
583
584
585
586 close(inputFileFd);
587
588
589
590 readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
591 memset(block_buf, 0, readSize);
592 xwrite(tbInfo->tarFd, block_buf, readSize);
593 }
594
595 return TRUE;
596}
597
598# if SEAMLESS_COMPRESSION
599
600static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
601{
602
603
604# define WAIT_FOR_CHILD 0
605 volatile int vfork_exec_errno = 0;
606 struct fd_pair data;
607# if WAIT_FOR_CHILD
608 struct fd_pair status;
609 xpiped_pair(status);
610# endif
611 xpiped_pair(data);
612
613 signal(SIGPIPE, SIG_IGN);
614
615 if (xvfork() == 0) {
616
617 int tfd;
618
619 close(data.wr);
620# if WAIT_FOR_CHILD
621 close(status.rd);
622
623
624 fcntl(status.wr, F_SETFD, FD_CLOEXEC);
625# endif
626
627 tfd = tar_fd;
628 if (tfd == 0) {
629
630
631
632
633
634
635
636
637
638 tfd = dup(tfd);
639 }
640 xmove_fd(data.rd, 0);
641 xmove_fd(tfd, 1);
642
643
644
645
646
647
648 execlp(gzip, gzip, "-f", (char *)0);
649
650 vfork_exec_errno = errno;
651 _exit(EXIT_FAILURE);
652 }
653
654
655 xmove_fd(data.wr, tar_fd);
656 close(data.rd);
657# if WAIT_FOR_CHILD
658 close(status.wr);
659 while (1) {
660
661 char buf;
662 int n = full_read(status.rd, &buf, 1);
663 if (n < 0 )
664 continue;
665 }
666 close(status.rd);
667# endif
668 if (vfork_exec_errno) {
669 errno = vfork_exec_errno;
670 bb_perror_msg_and_die("can't execute '%s'", gzip);
671 }
672}
673# endif
674
675
676# if !SEAMLESS_COMPRESSION
677
678#define writeTarFile(tbInfo, recurseFlags, filelist, gzip) \
679 writeTarFile(tbInfo, recurseFlags, filelist)
680# endif
681
682static NOINLINE int writeTarFile(
683 struct TarBallInfo *tbInfo,
684 int recurseFlags,
685 const llist_t *filelist,
686 const char *gzip)
687{
688 int errorFlag = FALSE;
689
690
691
692
693
694 xfstat(tbInfo->tarFd, &tbInfo->tarFileStatBuf, "can't stat tar file");
695
696# if SEAMLESS_COMPRESSION
697 if (gzip)
698 vfork_compressor(tbInfo->tarFd, gzip);
699# endif
700
701
702 while (filelist) {
703 if (!recursive_action(filelist->data, recurseFlags,
704 writeFileToTarball, writeFileToTarball, tbInfo)
705 ) {
706 errorFlag = TRUE;
707 }
708 filelist = filelist->link;
709 }
710
711 memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
712 xwrite(tbInfo->tarFd, block_buf, 2*TAR_BLOCK_SIZE);
713
714
715
716
717
718
719
720 close(tbInfo->tarFd);
721
722
723 if (ENABLE_FEATURE_CLEAN_UP)
724 freeHardLinkInfo(&tbInfo->hlInfoHead);
725
726 if (errorFlag)
727 bb_simple_error_msg("error exit delayed from previous errors");
728
729# if SEAMLESS_COMPRESSION
730 if (gzip) {
731 int status;
732 if (safe_waitpid(-1, &status, 0) == -1)
733 bb_simple_perror_msg("waitpid");
734 else if (!WIFEXITED(status) || WEXITSTATUS(status))
735
736 errorFlag = TRUE;
737 }
738# endif
739 return errorFlag;
740}
741
742#endif
743
744#if ENABLE_FEATURE_TAR_FROM
745static llist_t *append_file_list_to_list(llist_t *list)
746{
747 llist_t *newlist = NULL;
748
749 while (list) {
750 FILE *src_stream;
751 char *line;
752
753 src_stream = xfopen_stdin(llist_pop(&list));
754 while ((line = xmalloc_fgetline(src_stream)) != NULL) {
755
756 char *cp = last_char_is(line, '/');
757 if (cp > line)
758 *cp = '\0';
759 llist_add_to_end(&newlist, line);
760 }
761 fclose(src_stream);
762 }
763 return newlist;
764}
765#endif
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
830
831
832
833
834
835
836
837
838
839
840
841
842
843enum {
844 OPTBIT_KEEP_OLD = 8,
845 IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,)
846 IF_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE ,)
847 IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2 ,)
848 IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,)
849 IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,)
850 IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP ,)
851 IF_FEATURE_SEAMLESS_XZ( OPTBIT_XZ ,)
852 IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,)
853 OPTBIT_AUTOCOMPRESS_BY_EXT,
854 IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
855#if ENABLE_FEATURE_TAR_LONG_OPTIONS
856 OPTBIT_STRIP_COMPONENTS,
857 IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA ,)
858 OPTBIT_NORECURSION,
859 IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,)
860 OPTBIT_NUMERIC_OWNER,
861 OPTBIT_NOPRESERVE_PERM,
862 OPTBIT_OVERWRITE,
863#endif
864 OPT_TEST = 1 << 0,
865 OPT_EXTRACT = 1 << 1,
866 OPT_BASEDIR = 1 << 2,
867 OPT_TARNAME = 1 << 3,
868 OPT_2STDOUT = 1 << 4,
869 OPT_NOPRESERVE_OWNER = 1 << 5,
870 OPT_P = 1 << 6,
871 OPT_VERBOSE = 1 << 7,
872 OPT_KEEP_OLD = 1 << 8,
873 OPT_CREATE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_CREATE )) + 0,
874 OPT_DEREFERENCE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_DEREFERENCE )) + 0,
875 OPT_BZIP2 = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2 )) + 0,
876 OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM)) + 0,
877 OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM)) + 0,
878 OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0,
879 OPT_XZ = IF_FEATURE_SEAMLESS_XZ( (1 << OPTBIT_XZ )) + 0,
880 OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0,
881 OPT_AUTOCOMPRESS_BY_EXT = 1 << OPTBIT_AUTOCOMPRESS_BY_EXT,
882 OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0,
883 OPT_STRIP_COMPONENTS = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_STRIP_COMPONENTS)) + 0,
884 OPT_LZMA = IF_FEATURE_TAR_LONG_OPTIONS(IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA))) + 0,
885 OPT_NORECURSION = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION )) + 0,
886 OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0,
887 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0,
888 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0,
889 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0,
890
891 OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_XZ | OPT_COMPRESS),
892};
893#if ENABLE_FEATURE_TAR_LONG_OPTIONS
894static const char tar_longopts[] ALIGN1 =
895 "list\0" No_argument "t"
896 "extract\0" No_argument "x"
897 "directory\0" Required_argument "C"
898 "file\0" Required_argument "f"
899 "to-stdout\0" No_argument "O"
900
901
902
903 "no-same-owner\0" No_argument "o"
904 "same-permissions\0" No_argument "p"
905 "verbose\0" No_argument "v"
906 "keep-old\0" No_argument "k"
907# if ENABLE_FEATURE_TAR_CREATE
908 "create\0" No_argument "c"
909 "dereference\0" No_argument "h"
910# endif
911# if ENABLE_FEATURE_SEAMLESS_BZ2
912 "bzip2\0" No_argument "j"
913# endif
914# if ENABLE_FEATURE_TAR_FROM
915 "files-from\0" Required_argument "T"
916 "exclude-from\0" Required_argument "X"
917# endif
918# if ENABLE_FEATURE_SEAMLESS_GZ
919 "gzip\0" No_argument "z"
920# endif
921# if ENABLE_FEATURE_SEAMLESS_XZ
922 "xz\0" No_argument "J"
923# endif
924# if ENABLE_FEATURE_SEAMLESS_Z
925 "compress\0" No_argument "Z"
926# endif
927 "auto-compress\0" No_argument "a"
928# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
929 "touch\0" No_argument "m"
930# endif
931 "strip-components\0" Required_argument "\xf8"
932# if ENABLE_FEATURE_SEAMLESS_LZMA
933 "lzma\0" No_argument "\xf9"
934# endif
935 "no-recursion\0" No_argument "\xfa"
936# if ENABLE_FEATURE_TAR_TO_COMMAND
937 "to-command\0" Required_argument "\xfb"
938# endif
939
940 "numeric-owner\0" No_argument "\xfc"
941
942 "no-same-permissions\0" No_argument "\xfd"
943
944 "overwrite\0" No_argument "\xfe"
945
946
947# if ENABLE_FEATURE_TAR_FROM
948 "exclude\0" Required_argument "\xff"
949# endif
950 ;
951# define GETOPT32 getopt32long
952# define LONGOPTS ,tar_longopts
953#else
954# define GETOPT32 getopt32
955# define LONGOPTS
956#endif
957
958int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
959int tar_main(int argc UNUSED_PARAM, char **argv)
960{
961 archive_handle_t *tar_handle;
962 char *base_dir = NULL;
963 const char *tar_filename = "-";
964 unsigned opt;
965 int verboseFlag = 0;
966#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
967 llist_t *excludes = NULL;
968#endif
969 INIT_G();
970
971
972 tar_handle = init_handle();
973 tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
974 | ARCHIVE_RESTORE_DATE
975 | ARCHIVE_UNLINK_OLD;
976
977
978 if (getuid() != 0)
979 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
980
981#if ENABLE_DESKTOP
982
983 if (argv[1] && strcmp(argv[1], "--version") == 0) {
984
985
986
987
988 puts("tar (busybox) " BB_VER);
989 return 0;
990 }
991#endif
992 if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') {
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008 char *f = strchr(argv[1], 'f');
1009 if (f) {
1010 while (f[1] != '\0') {
1011 *f = f[1];
1012 f++;
1013 }
1014 *f = 'f';
1015 }
1016
1017 argv[1] = xasprintf("-%s", argv[1]);
1018 }
1019 opt = GETOPT32(argv, "^"
1020 "txC:f:Oopvk"
1021 IF_FEATURE_TAR_CREATE( "ch" )
1022 IF_FEATURE_SEAMLESS_BZ2( "j" )
1023 IF_FEATURE_TAR_FROM( "T:*X:*")
1024 IF_FEATURE_SEAMLESS_GZ( "z" )
1025 IF_FEATURE_SEAMLESS_XZ( "J" )
1026 IF_FEATURE_SEAMLESS_Z( "Z" )
1027 "a"
1028 IF_FEATURE_TAR_NOPRESERVE_TIME("m")
1029 IF_FEATURE_TAR_LONG_OPTIONS("\xf8:")
1030 "\0"
1031 "tt:vv:"
1032#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
1033 "\xff::"
1034#endif
1035 IF_FEATURE_TAR_CREATE("c:") "t:x:"
1036 IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct")
1037 IF_NOT_FEATURE_TAR_CREATE("t--x:x--t")
1038#if ENABLE_FEATURE_TAR_LONG_OPTIONS
1039 ":\xf8+"
1040#endif
1041 LONGOPTS
1042 , &base_dir
1043 , &tar_filename
1044 IF_FEATURE_TAR_FROM(, &(tar_handle->accept))
1045 IF_FEATURE_TAR_FROM(, &(tar_handle->reject))
1046#if ENABLE_FEATURE_TAR_LONG_OPTIONS
1047 , &tar_handle->tar__strip_components
1048#endif
1049 IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command))
1050#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
1051 , &excludes
1052#endif
1053 , &verboseFlag
1054 , &verboseFlag
1055 );
1056#if DBG_OPTION_PARSING
1057 bb_error_msg("opt: 0x%08x", opt);
1058# define showopt(o) bb_error_msg("opt & %s(%x):\t%x", #o, o, opt & o);
1059 showopt(OPT_TEST );
1060 showopt(OPT_EXTRACT );
1061 showopt(OPT_BASEDIR );
1062 showopt(OPT_TARNAME );
1063 showopt(OPT_2STDOUT );
1064 showopt(OPT_NOPRESERVE_OWNER);
1065 showopt(OPT_P );
1066 showopt(OPT_VERBOSE );
1067 showopt(OPT_KEEP_OLD );
1068 showopt(OPT_CREATE );
1069 showopt(OPT_DEREFERENCE );
1070 showopt(OPT_BZIP2 );
1071 showopt(OPT_INCLUDE_FROM );
1072 showopt(OPT_EXCLUDE_FROM );
1073 showopt(OPT_GZIP );
1074 showopt(OPT_XZ );
1075 showopt(OPT_COMPRESS );
1076 showopt(OPT_AUTOCOMPRESS_BY_EXT);
1077 showopt(OPT_NOPRESERVE_TIME );
1078 showopt(OPT_STRIP_COMPONENTS);
1079 showopt(OPT_LZMA );
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
1136 tar_handle->reject = append_file_list_to_list(tar_handle->reject);
1137# if ENABLE_FEATURE_TAR_LONG_OPTIONS
1138
1139 if (excludes) {
1140 llist_t **p2next = &tar_handle->reject;
1141 while (*p2next)
1142 p2next = &((*p2next)->link);
1143 *p2next = excludes;
1144 }
1145# endif
1146 tar_handle->accept = append_file_list_to_list(tar_handle->accept);
1147#endif
1148
1149
1150
1151 while (*argv) {
1152
1153 char *cp = last_char_is(*argv, '/');
1154 if (cp > *argv)
1155 *cp = '\0';
1156 llist_add_to_end(&tar_handle->accept, *argv);
1157 argv++;
1158 }
1159
1160 if (tar_handle->accept || tar_handle->reject)
1161 tar_handle->filter = filter_accept_reject_list;
1162
1163
1164 {
1165 int tar_fd = STDIN_FILENO;
1166 int flags = O_RDONLY;
1167
1168 if (opt & OPT_CREATE) {
1169
1170 if (tar_handle->accept == NULL)
1171 bb_simple_error_msg_and_die("empty archive");
1172
1173 tar_fd = STDOUT_FILENO;
1174
1175 flags = O_WRONLY | O_CREAT | O_TRUNC;
1176 }
1177
1178 if (LONE_DASH(tar_filename)) {
1179 tar_handle->src_fd = tar_fd;
1180 tar_handle->seek = seek_by_read;
1181 } else
1182 if (ENABLE_FEATURE_TAR_AUTODETECT
1183 && ENABLE_FEATURE_SEAMLESS_LZMA
1184 && flags == O_RDONLY
1185 && !(opt & OPT_ANY_COMPRESS)
1186 && is_suffixed_with(tar_filename, ".lzma")
1187
1188
1189
1190
1191
1192
1193 ) {
1194 tar_handle->src_fd = open_zipped(tar_filename, 0);
1195 if (tar_handle->src_fd < 0)
1196 bb_perror_msg_and_die("can't open '%s'", tar_filename);
1197 } else {
1198 tar_handle->src_fd = xopen(tar_filename, flags);
1199#if ENABLE_FEATURE_TAR_CREATE
1200 if ((OPT_GZIP | OPT_BZIP2 | OPT_XZ | OPT_LZMA) != 0
1201 && (opt & OPT_AUTOCOMPRESS_BY_EXT)
1202 && flags != O_RDONLY
1203 ) {
1204 if (OPT_GZIP != 0 && is_suffixed_with(tar_filename, "gz"))
1205 opt |= OPT_GZIP;
1206 if (OPT_BZIP2 != 0 && is_suffixed_with(tar_filename, "bz2"))
1207 opt |= OPT_BZIP2;
1208 if (OPT_XZ != 0 && is_suffixed_with(tar_filename, "xz"))
1209 opt |= OPT_XZ;
1210 if (OPT_LZMA != 0 && is_suffixed_with(tar_filename, "lzma"))
1211 opt |= OPT_LZMA;
1212 }
1213#endif
1214 }
1215 }
1216
1217 if (base_dir)
1218 xchdir(base_dir);
1219
1220#if ENABLE_FEATURE_TAR_CREATE
1221
1222 if (opt & OPT_CREATE) {
1223 struct TarBallInfo *tbInfo;
1224# if SEAMLESS_COMPRESSION
1225 const char *zipMode = NULL;
1226 if (opt & OPT_COMPRESS)
1227 zipMode = "compress";
1228 if (opt & OPT_GZIP)
1229 zipMode = "gzip";
1230 if (opt & OPT_BZIP2)
1231 zipMode = "bzip2";
1232 if (opt & OPT_LZMA)
1233 zipMode = "lzma";
1234 if (opt & OPT_XZ)
1235 zipMode = "xz";
1236# endif
1237 tbInfo = xzalloc(sizeof(*tbInfo));
1238 tbInfo->tarFd = tar_handle->src_fd;
1239 tbInfo->verboseFlag = verboseFlag;
1240# if ENABLE_FEATURE_TAR_FROM
1241 tbInfo->excludeList = tar_handle->reject;
1242# endif
1243
1244 return writeTarFile(tbInfo,
1245 (opt & OPT_DEREFERENCE ? ACTION_FOLLOWLINKS : 0)
1246 | (opt & OPT_NORECURSION ? 0 : ACTION_RECURSE),
1247 tar_handle->accept,
1248 zipMode);
1249 }
1250#endif
1251
1252 if (opt & OPT_ANY_COMPRESS) {
1253 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate);)
1254 USE_FOR_NOMMU(const char *xformer_prog;)
1255
1256 if (opt & OPT_COMPRESS) {
1257 USE_FOR_MMU(IF_FEATURE_SEAMLESS_Z(xformer = unpack_Z_stream;))
1258 USE_FOR_NOMMU(xformer_prog = "uncompress";)
1259 }
1260 if (opt & OPT_GZIP) {
1261 USE_FOR_MMU(IF_FEATURE_SEAMLESS_GZ(xformer = unpack_gz_stream;))
1262 USE_FOR_NOMMU(xformer_prog = "gunzip";)
1263 }
1264 if (opt & OPT_BZIP2) {
1265 USE_FOR_MMU(IF_FEATURE_SEAMLESS_BZ2(xformer = unpack_bz2_stream;))
1266 USE_FOR_NOMMU(xformer_prog = "bunzip2";)
1267 }
1268 if (opt & OPT_LZMA) {
1269 USE_FOR_MMU(IF_FEATURE_SEAMLESS_LZMA(xformer = unpack_lzma_stream;))
1270 USE_FOR_NOMMU(xformer_prog = "unlzma";)
1271 }
1272 if (opt & OPT_XZ) {
1273 USE_FOR_MMU(IF_FEATURE_SEAMLESS_XZ(xformer = unpack_xz_stream;))
1274 USE_FOR_NOMMU(xformer_prog = "unxz";)
1275 }
1276
1277 fork_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog);
1278
1279 tar_handle->seek = seek_by_read;
1280
1281 }
1282
1283
1284
1285
1286
1287 bb_got_signal = EXIT_FAILURE;
1288
1289 while (get_header_tar(tar_handle) == EXIT_SUCCESS)
1290 bb_got_signal = EXIT_SUCCESS;
1291
1292 create_links_from_list(tar_handle->link_placeholders);
1293
1294
1295 while (tar_handle->accept) {
1296 if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
1297 && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
1298 ) {
1299 bb_error_msg_and_die("%s: not found in archive",
1300 tar_handle->accept->data);
1301 }
1302 tar_handle->accept = tar_handle->accept->link;
1303 }
1304 if (ENABLE_FEATURE_CLEAN_UP )
1305 close(tar_handle->src_fd);
1306
1307 if (SEAMLESS_COMPRESSION || OPT_COMPRESS) {
1308
1309 check_errors_in_children(0);
1310 }
1311
1312 return bb_got_signal;
1313}
1314