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 pid_t gzipPid;
600
601
602
603# define WAIT_FOR_CHILD 0
604 volatile int vfork_exec_errno = 0;
605 struct fd_pair gzipDataPipe;
606# if WAIT_FOR_CHILD
607 struct fd_pair gzipStatusPipe;
608 xpiped_pair(gzipStatusPipe);
609# endif
610 xpiped_pair(gzipDataPipe);
611
612 signal(SIGPIPE, SIG_IGN);
613
614 gzipPid = xvfork();
615
616 if (gzipPid == 0) {
617
618
619 close(gzipDataPipe.wr);
620# if WAIT_FOR_CHILD
621 close(gzipStatusPipe.rd);
622
623
624 fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
625# endif
626 xmove_fd(gzipDataPipe.rd, 0);
627 xmove_fd(tar_fd, 1);
628
629 BB_EXECLP(gzip, gzip, "-f", (char *)0);
630 vfork_exec_errno = errno;
631 _exit(EXIT_FAILURE);
632 }
633
634
635 xmove_fd(gzipDataPipe.wr, tar_fd);
636 close(gzipDataPipe.rd);
637# if WAIT_FOR_CHILD
638 close(gzipStatusPipe.wr);
639 while (1) {
640 char buf;
641 int n;
642
643
644 n = full_read(gzipStatusPipe.rd, &buf, 1);
645 if (n < 0 )
646 continue;
647 }
648 close(gzipStatusPipe.rd);
649# endif
650 if (vfork_exec_errno) {
651 errno = vfork_exec_errno;
652 bb_perror_msg_and_die("can't execute '%s'", gzip);
653 }
654}
655# endif
656
657
658# if !SEAMLESS_COMPRESSION
659
660#define writeTarFile(tbInfo, recurseFlags, filelist, gzip) \
661 writeTarFile(tbInfo, recurseFlags, filelist)
662# endif
663
664static NOINLINE int writeTarFile(
665 struct TarBallInfo *tbInfo,
666 int recurseFlags,
667 const llist_t *filelist,
668 const char *gzip)
669{
670 int errorFlag = FALSE;
671
672
673
674
675
676 xfstat(tbInfo->tarFd, &tbInfo->tarFileStatBuf, "can't stat tar file");
677
678# if SEAMLESS_COMPRESSION
679 if (gzip)
680 vfork_compressor(tbInfo->tarFd, gzip);
681# endif
682
683
684 while (filelist) {
685 if (!recursive_action(filelist->data, recurseFlags,
686 writeFileToTarball, writeFileToTarball, tbInfo, 0)
687 ) {
688 errorFlag = TRUE;
689 }
690 filelist = filelist->link;
691 }
692
693 memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
694 xwrite(tbInfo->tarFd, block_buf, 2*TAR_BLOCK_SIZE);
695
696
697
698
699
700
701
702 close(tbInfo->tarFd);
703
704
705 if (ENABLE_FEATURE_CLEAN_UP)
706 freeHardLinkInfo(&tbInfo->hlInfoHead);
707
708 if (errorFlag)
709 bb_error_msg("error exit delayed from previous errors");
710
711# if SEAMLESS_COMPRESSION
712 if (gzip) {
713 int status;
714 if (safe_waitpid(-1, &status, 0) == -1)
715 bb_perror_msg("waitpid");
716 else if (!WIFEXITED(status) || WEXITSTATUS(status))
717
718 errorFlag = TRUE;
719 }
720# endif
721 return errorFlag;
722}
723
724#else
725
726# define writeTarFile(...) 0
727
728#endif
729
730#if ENABLE_FEATURE_TAR_FROM
731static llist_t *append_file_list_to_list(llist_t *list)
732{
733 llist_t *newlist = NULL;
734
735 while (list) {
736 FILE *src_stream;
737 char *line;
738
739 src_stream = xfopen_stdin(llist_pop(&list));
740 while ((line = xmalloc_fgetline(src_stream)) != NULL) {
741
742 char *cp = last_char_is(line, '/');
743 if (cp > line)
744 *cp = '\0';
745 llist_add_to_end(&newlist, line);
746 }
747 fclose(src_stream);
748 }
749 return newlist;
750}
751#endif
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
816
817
818
819
820
821
822
823
824
825enum {
826 OPTBIT_KEEP_OLD = 8,
827 IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,)
828 IF_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE ,)
829 IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2 ,)
830 IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA ,)
831 IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,)
832 IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,)
833 IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP ,)
834 IF_FEATURE_SEAMLESS_XZ( OPTBIT_XZ ,)
835 IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,)
836 IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
837#if ENABLE_FEATURE_TAR_LONG_OPTIONS
838 OPTBIT_STRIP_COMPONENTS,
839 OPTBIT_NORECURSION,
840 IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,)
841 OPTBIT_NUMERIC_OWNER,
842 OPTBIT_NOPRESERVE_PERM,
843 OPTBIT_OVERWRITE,
844#endif
845 OPT_TEST = 1 << 0,
846 OPT_EXTRACT = 1 << 1,
847 OPT_BASEDIR = 1 << 2,
848 OPT_TARNAME = 1 << 3,
849 OPT_2STDOUT = 1 << 4,
850 OPT_NOPRESERVE_OWNER = 1 << 5,
851 OPT_P = 1 << 6,
852 OPT_VERBOSE = 1 << 7,
853 OPT_KEEP_OLD = 1 << 8,
854 OPT_CREATE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_CREATE )) + 0,
855 OPT_DEREFERENCE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_DEREFERENCE )) + 0,
856 OPT_BZIP2 = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2 )) + 0,
857 OPT_LZMA = IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA )) + 0,
858 OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM)) + 0,
859 OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM)) + 0,
860 OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0,
861 OPT_XZ = IF_FEATURE_SEAMLESS_XZ( (1 << OPTBIT_XZ )) + 0,
862 OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0,
863 OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0,
864 OPT_STRIP_COMPONENTS = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_STRIP_COMPONENTS)) + 0,
865 OPT_NORECURSION = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION )) + 0,
866 OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0,
867 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0,
868 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0,
869 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0,
870
871 OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_XZ | OPT_COMPRESS),
872};
873#if ENABLE_FEATURE_TAR_LONG_OPTIONS
874static const char tar_longopts[] ALIGN1 =
875 "list\0" No_argument "t"
876 "extract\0" No_argument "x"
877 "directory\0" Required_argument "C"
878 "file\0" Required_argument "f"
879 "to-stdout\0" No_argument "O"
880
881
882
883 "no-same-owner\0" No_argument "o"
884 "same-permissions\0" No_argument "p"
885 "verbose\0" No_argument "v"
886 "keep-old\0" No_argument "k"
887# if ENABLE_FEATURE_TAR_CREATE
888 "create\0" No_argument "c"
889 "dereference\0" No_argument "h"
890# endif
891# if ENABLE_FEATURE_SEAMLESS_BZ2
892 "bzip2\0" No_argument "j"
893# endif
894# if ENABLE_FEATURE_SEAMLESS_LZMA
895 "lzma\0" No_argument "a"
896# endif
897# if ENABLE_FEATURE_TAR_FROM
898 "files-from\0" Required_argument "T"
899 "exclude-from\0" Required_argument "X"
900# endif
901# if ENABLE_FEATURE_SEAMLESS_GZ
902 "gzip\0" No_argument "z"
903# endif
904# if ENABLE_FEATURE_SEAMLESS_XZ
905 "xz\0" No_argument "J"
906# endif
907# if ENABLE_FEATURE_SEAMLESS_Z
908 "compress\0" No_argument "Z"
909# endif
910# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
911 "touch\0" No_argument "m"
912# endif
913 "strip-components\0" Required_argument "\xf9"
914 "no-recursion\0" No_argument "\xfa"
915# if ENABLE_FEATURE_TAR_TO_COMMAND
916 "to-command\0" Required_argument "\xfb"
917# endif
918
919 "numeric-owner\0" No_argument "\xfc"
920
921 "no-same-permissions\0" No_argument "\xfd"
922
923 "overwrite\0" No_argument "\xfe"
924
925
926# if ENABLE_FEATURE_TAR_FROM
927 "exclude\0" Required_argument "\xff"
928# endif
929 ;
930# define GETOPT32 getopt32long
931# define LONGOPTS ,tar_longopts
932#else
933# define GETOPT32 getopt32
934# define LONGOPTS
935#endif
936
937int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
938int tar_main(int argc UNUSED_PARAM, char **argv)
939{
940 archive_handle_t *tar_handle;
941 char *base_dir = NULL;
942 const char *tar_filename = "-";
943 unsigned opt;
944 int verboseFlag = 0;
945#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
946 llist_t *excludes = NULL;
947#endif
948 INIT_G();
949
950
951 tar_handle = init_handle();
952 tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
953 | ARCHIVE_RESTORE_DATE
954 | ARCHIVE_UNLINK_OLD;
955
956
957 if (getuid() != 0)
958 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
959
960#if ENABLE_DESKTOP
961
962 if (argv[1] && strcmp(argv[1], "--version") == 0) {
963
964
965
966
967 puts("tar (busybox) " BB_VER);
968 return 0;
969 }
970#endif
971 if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') {
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987 char *f = strchr(argv[1], 'f');
988 if (f) {
989 while (f[1] != '\0') {
990 *f = f[1];
991 f++;
992 }
993 *f = 'f';
994 }
995
996 argv[1] = xasprintf("-%s", argv[1]);
997 }
998 opt = GETOPT32(argv, "^"
999 "txC:f:Oopvk"
1000 IF_FEATURE_TAR_CREATE( "ch" )
1001 IF_FEATURE_SEAMLESS_BZ2( "j" )
1002 IF_FEATURE_SEAMLESS_LZMA("a" )
1003 IF_FEATURE_TAR_FROM( "T:*X:*")
1004 IF_FEATURE_SEAMLESS_GZ( "z" )
1005 IF_FEATURE_SEAMLESS_XZ( "J" )
1006 IF_FEATURE_SEAMLESS_Z( "Z" )
1007 IF_FEATURE_TAR_NOPRESERVE_TIME("m")
1008 IF_FEATURE_TAR_LONG_OPTIONS("\xf9:")
1009 "\0"
1010 "tt:vv:"
1011#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
1012 "\xff::"
1013#endif
1014 IF_FEATURE_TAR_CREATE("c:") "t:x:"
1015 IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct")
1016 IF_NOT_FEATURE_TAR_CREATE("t--x:x--t")
1017#if ENABLE_FEATURE_TAR_LONG_OPTIONS
1018 ":\xf9+"
1019#endif
1020 LONGOPTS
1021 , &base_dir
1022 , &tar_filename
1023 IF_FEATURE_TAR_FROM(, &(tar_handle->accept))
1024 IF_FEATURE_TAR_FROM(, &(tar_handle->reject))
1025#if ENABLE_FEATURE_TAR_LONG_OPTIONS
1026 , &tar_handle->tar__strip_components
1027#endif
1028 IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command))
1029#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
1030 , &excludes
1031#endif
1032 , &verboseFlag
1033 , &verboseFlag
1034 );
1035#if DBG_OPTION_PARSING
1036 bb_error_msg("opt: 0x%08x", opt);
1037# define showopt(o) bb_error_msg("opt & %s(%x): %x", #o, o, opt & o);
1038 showopt(OPT_TEST );
1039 showopt(OPT_EXTRACT );
1040 showopt(OPT_BASEDIR );
1041 showopt(OPT_TARNAME );
1042 showopt(OPT_2STDOUT );
1043 showopt(OPT_NOPRESERVE_OWNER);
1044 showopt(OPT_P );
1045 showopt(OPT_VERBOSE );
1046 showopt(OPT_KEEP_OLD );
1047 showopt(OPT_CREATE );
1048 showopt(OPT_DEREFERENCE );
1049 showopt(OPT_BZIP2 );
1050 showopt(OPT_LZMA );
1051 showopt(OPT_INCLUDE_FROM );
1052 showopt(OPT_EXCLUDE_FROM );
1053 showopt(OPT_GZIP );
1054 showopt(OPT_XZ );
1055 showopt(OPT_COMPRESS );
1056 showopt(OPT_NOPRESERVE_TIME );
1057 showopt(OPT_STRIP_COMPONENTS);
1058 showopt(OPT_NORECURSION );
1059 showopt(OPT_2COMMAND );
1060 showopt(OPT_NUMERIC_OWNER );
1061 showopt(OPT_NOPRESERVE_PERM );
1062 showopt(OPT_OVERWRITE );
1063 showopt(OPT_ANY_COMPRESS );
1064 bb_error_msg("base_dir:'%s'", base_dir);
1065 bb_error_msg("tar_filename:'%s'", tar_filename);
1066 bb_error_msg("verboseFlag:%d", verboseFlag);
1067 bb_error_msg("tar_handle->tar__to_command:'%s'", tar_handle->tar__to_command);
1068 bb_error_msg("tar_handle->tar__strip_components:%u", tar_handle->tar__strip_components);
1069 return 0;
1070# undef showopt
1071#endif
1072 argv += optind;
1073
1074 if (verboseFlag)
1075 tar_handle->action_header = header_verbose_list;
1076 if (verboseFlag == 1)
1077 tar_handle->action_header = header_list;
1078
1079 if (opt & OPT_EXTRACT)
1080 tar_handle->action_data = data_extract_all;
1081
1082 if (opt & OPT_2STDOUT)
1083 tar_handle->action_data = data_extract_to_stdout;
1084
1085 if (opt & OPT_2COMMAND) {
1086 putenv((char*)"TAR_FILETYPE=f");
1087 signal(SIGPIPE, SIG_IGN);
1088 tar_handle->action_data = data_extract_to_command;
1089 IF_FEATURE_TAR_TO_COMMAND(tar_handle->tar__to_command_shell = xstrdup(get_shell_name());)
1090 }
1091
1092 if (opt & OPT_KEEP_OLD)
1093 tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
1094
1095 if (opt & OPT_NUMERIC_OWNER)
1096 tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER;
1097
1098 if (opt & OPT_NOPRESERVE_OWNER)
1099 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_OWNER;
1100
1101 if (opt & OPT_NOPRESERVE_PERM)
1102 tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
1103
1104 if (opt & OPT_OVERWRITE) {
1105 tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
1106 tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
1107 }
1108
1109 if (opt & OPT_NOPRESERVE_TIME)
1110 tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE;
1111
1112#if ENABLE_FEATURE_TAR_FROM
1113 tar_handle->reject = append_file_list_to_list(tar_handle->reject);
1114# if ENABLE_FEATURE_TAR_LONG_OPTIONS
1115
1116 while (excludes) {
1117 llist_t *next = excludes->link;
1118 excludes->link = tar_handle->reject;
1119 tar_handle->reject = excludes;
1120 excludes = next;
1121 }
1122# endif
1123 tar_handle->accept = append_file_list_to_list(tar_handle->accept);
1124#endif
1125
1126
1127
1128 while (*argv) {
1129
1130 char *cp = last_char_is(*argv, '/');
1131 if (cp > *argv)
1132 *cp = '\0';
1133 llist_add_to_end(&tar_handle->accept, *argv);
1134 argv++;
1135 }
1136
1137 if (tar_handle->accept || tar_handle->reject)
1138 tar_handle->filter = filter_accept_reject_list;
1139
1140
1141 {
1142 int tar_fd = STDIN_FILENO;
1143 int flags = O_RDONLY;
1144
1145 if (opt & OPT_CREATE) {
1146
1147 if (tar_handle->accept == NULL)
1148 bb_error_msg_and_die("empty archive");
1149
1150 tar_fd = STDOUT_FILENO;
1151
1152 flags = O_WRONLY | O_CREAT | O_TRUNC;
1153 }
1154
1155 if (LONE_DASH(tar_filename)) {
1156 tar_handle->src_fd = tar_fd;
1157 tar_handle->seek = seek_by_read;
1158 } else {
1159 if (ENABLE_FEATURE_TAR_AUTODETECT
1160 && flags == O_RDONLY
1161 && !(opt & OPT_ANY_COMPRESS)
1162 ) {
1163 tar_handle->src_fd = open_zipped(tar_filename, 0);
1164 if (tar_handle->src_fd < 0)
1165 bb_perror_msg_and_die("can't open '%s'", tar_filename);
1166 } else {
1167 tar_handle->src_fd = xopen(tar_filename, flags);
1168 }
1169 }
1170 }
1171
1172 if (base_dir)
1173 xchdir(base_dir);
1174
1175#if ENABLE_FEATURE_TAR_CREATE
1176
1177 if (opt & OPT_CREATE) {
1178 struct TarBallInfo *tbInfo;
1179# if SEAMLESS_COMPRESSION
1180 const char *zipMode = NULL;
1181 if (opt & OPT_COMPRESS)
1182 zipMode = "compress";
1183 if (opt & OPT_GZIP)
1184 zipMode = "gzip";
1185 if (opt & OPT_BZIP2)
1186 zipMode = "bzip2";
1187 if (opt & OPT_LZMA)
1188 zipMode = "lzma";
1189 if (opt & OPT_XZ)
1190 zipMode = "xz";
1191# endif
1192 tbInfo = xzalloc(sizeof(*tbInfo));
1193 tbInfo->tarFd = tar_handle->src_fd;
1194 tbInfo->verboseFlag = verboseFlag;
1195# if ENABLE_FEATURE_TAR_FROM
1196 tbInfo->excludeList = tar_handle->reject;
1197# endif
1198
1199 return writeTarFile(tbInfo,
1200 (opt & OPT_DEREFERENCE ? ACTION_FOLLOWLINKS : 0)
1201 | (opt & OPT_NORECURSION ? 0 : ACTION_RECURSE),
1202 tar_handle->accept,
1203 zipMode);
1204 }
1205#endif
1206
1207 if (opt & OPT_ANY_COMPRESS) {
1208 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate);)
1209 USE_FOR_NOMMU(const char *xformer_prog;)
1210
1211 if (opt & OPT_COMPRESS) {
1212 USE_FOR_MMU(IF_FEATURE_SEAMLESS_Z(xformer = unpack_Z_stream;))
1213 USE_FOR_NOMMU(xformer_prog = "uncompress";)
1214 }
1215 if (opt & OPT_GZIP) {
1216 USE_FOR_MMU(IF_FEATURE_SEAMLESS_GZ(xformer = unpack_gz_stream;))
1217 USE_FOR_NOMMU(xformer_prog = "gunzip";)
1218 }
1219 if (opt & OPT_BZIP2) {
1220 USE_FOR_MMU(IF_FEATURE_SEAMLESS_BZ2(xformer = unpack_bz2_stream;))
1221 USE_FOR_NOMMU(xformer_prog = "bunzip2";)
1222 }
1223 if (opt & OPT_LZMA) {
1224 USE_FOR_MMU(IF_FEATURE_SEAMLESS_LZMA(xformer = unpack_lzma_stream;))
1225 USE_FOR_NOMMU(xformer_prog = "unlzma";)
1226 }
1227 if (opt & OPT_XZ) {
1228 USE_FOR_MMU(IF_FEATURE_SEAMLESS_XZ(xformer = unpack_xz_stream;))
1229 USE_FOR_NOMMU(xformer_prog = "unxz";)
1230 }
1231
1232 fork_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog);
1233
1234 tar_handle->seek = seek_by_read;
1235
1236 }
1237
1238
1239
1240
1241
1242 bb_got_signal = EXIT_FAILURE;
1243
1244 while (get_header_tar(tar_handle) == EXIT_SUCCESS)
1245 bb_got_signal = EXIT_SUCCESS;
1246
1247 create_links_from_list(tar_handle->link_placeholders);
1248
1249
1250 while (tar_handle->accept) {
1251 if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
1252 && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
1253 ) {
1254 bb_error_msg_and_die("%s: not found in archive",
1255 tar_handle->accept->data);
1256 }
1257 tar_handle->accept = tar_handle->accept->link;
1258 }
1259 if (ENABLE_FEATURE_CLEAN_UP )
1260 close(tar_handle->src_fd);
1261
1262 if (SEAMLESS_COMPRESSION || OPT_COMPRESS) {
1263
1264 check_errors_in_children(0);
1265 }
1266
1267 return bb_got_signal;
1268}
1269