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