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