1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // clang-format off
16 /*-
17  * This is a compact "tar" program whose primary goal is small size.
18  * Statically linked, it can be very small indeed.  This serves a number
19  * of goals:
20  *   o a testbed for libarchive (to check for link pollution),
21  *   o a useful tool for space-constrained systems (boot floppies, etc),
22  *   o a place to experiment with new implementation ideas for bsdtar,
23  *   o a small program to demonstrate libarchive usage.
24  *
25  * Use the following macros to suppress features:
26  *   NO_BZIP2 - Implies NO_BZIP2_CREATE and NO_BZIP2_EXTRACT
27  *   NO_BZIP2_CREATE - Suppress bzip2 compression support.
28  *   NO_BZIP2_EXTRACT - Suppress bzip2 auto-detection and decompression.
29  *   NO_COMPRESS - Implies NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT
30  *   NO_COMPRESS_CREATE - Suppress compress(1) compression support
31  *   NO_COMPRESS_EXTRACT - Suppress compress(1) auto-detect and decompression.
32  *   NO_CREATE - Suppress all archive creation support.
33  *   NO_CPIO_EXTRACT - Suppress auto-detect and dearchiving of cpio archives.
34  *   NO_GZIP - Implies NO_GZIP_CREATE and NO_GZIP_EXTRACT
35  *   NO_GZIP_CREATE - Suppress gzip compression support.
36  *   NO_GZIP_EXTRACT - Suppress gzip auto-detection and decompression.
37  *   NO_LOOKUP - Try to avoid getpw/getgr routines, which can be very large
38  *   NO_TAR_EXTRACT - Suppress tar extraction
39  *
40  * With all of the above macros defined (except NO_TAR_EXTRACT), you
41  * get a very small program that can recognize and extract essentially
42  * any uncompressed tar archive.  On FreeBSD 5.1, this minimal program
43  * is under 64k, statically linked, which compares rather favorably to
44  *         main(){printf("hello, world");}
45  * which is over 60k statically linked on the same operating system.
46  * Without any of the above macros, you get a static executable of
47  * about 180k with a lot of very sophisticated modern features.
48  * Obviously, it's trivial to add support for ISO, Zip, mtree,
49  * lzma/xz, etc.  Just fill in the appropriate setup calls.
50  */
51 
52 #include "minitar.h"  // NOLINT(build/include)
53 
54 /*
55  * NO_CREATE implies NO_BZIP2_CREATE and NO_GZIP_CREATE and NO_COMPRESS_CREATE.
56  */
57 #ifdef NO_CREATE
58 #undef NO_BZIP2_CREATE
59 #define NO_BZIP2_CREATE
60 #undef NO_COMPRESS_CREATE
61 #define NO_COMPRESS_CREATE
62 #undef NO_GZIP_CREATE
63 #define NO_GZIP_CREATE
64 #endif
65 
66 /*
67  * The combination of NO_BZIP2_CREATE and NO_BZIP2_EXTRACT is
68  * equivalent to NO_BZIP2.
69  */
70 #ifdef NO_BZIP2_CREATE
71 #ifdef NO_BZIP2_EXTRACT
72 #undef NO_BZIP2
73 #define NO_BZIP2
74 #endif
75 #endif
76 
77 #ifdef NO_BZIP2
78 #undef NO_BZIP2_EXTRACT
79 #define NO_BZIP2_EXTRACT
80 #undef NO_BZIP2_CREATE
81 #define NO_BZIP2_CREATE
82 #endif
83 
84 /*
85  * The combination of NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT is
86  * equivalent to NO_COMPRESS.
87  */
88 #ifdef NO_COMPRESS_CREATE
89 #ifdef NO_COMPRESS_EXTRACT
90 #undef NO_COMPRESS
91 #define NO_COMPRESS
92 #endif
93 #endif
94 
95 #ifdef NO_COMPRESS
96 #undef NO_COMPRESS_EXTRACT
97 #define NO_COMPRESS_EXTRACT
98 #undef NO_COMPRESS_CREATE
99 #define NO_COMPRESS_CREATE
100 #endif
101 
102 /*
103  * The combination of NO_GZIP_CREATE and NO_GZIP_EXTRACT is
104  * equivalent to NO_GZIP.
105  */
106 #ifdef NO_GZIP_CREATE
107 #ifdef NO_GZIP_EXTRACT
108 #undef NO_GZIP
109 #define NO_GZIP
110 #endif
111 #endif
112 
113 #ifdef NO_GZIP
114 #undef NO_GZIP_EXTRACT
115 #define NO_GZIP_EXTRACT
116 #undef NO_GZIP_CREATE
117 #define NO_GZIP_CREATE
118 #endif
119 
main(int unused_argc,char * argv[])120 int main(int unused_argc, char* argv[]) {
121   const char* filename = nullptr;
122   int compress;
123   int flags;
124   int mode;
125   int opt;
126 
127   mode = 'x';
128   int verbose = 0;
129   compress = '\0';
130   flags = ARCHIVE_EXTRACT_TIME;
131 
132   /* Among other sins, getopt(3) pulls in printf(3). */
133   while (*++argv != nullptr && **argv == '-') {
134     const char* p = *argv + 1;
135 
136     while ((opt = *p++) != '\0') {
137       switch (opt) {
138 #ifndef NO_CREATE
139         case 'c':
140           mode = opt;
141           break;
142 #endif
143         case 'f':
144           if (*p != '\0')
145             filename = p;
146           else
147             filename = *++argv;
148           p += strlen(p);
149           break;
150 #ifndef NO_BZIP2_CREATE
151         case 'j':
152           compress = opt;
153           break;
154 #endif
155         case 'p':
156           flags |= ARCHIVE_EXTRACT_PERM;
157           flags |= ARCHIVE_EXTRACT_ACL;
158           flags |= ARCHIVE_EXTRACT_FFLAGS;
159           break;
160         case 't':
161           mode = opt;
162           break;
163         case 'v':
164           verbose++;
165           break;
166         case 'x':
167           mode = opt;
168           break;
169 #ifndef NO_BZIP2_CREATE
170         case 'y':
171           compress = opt;
172           break;
173 #endif
174 #ifndef NO_COMPRESS_CREATE
175         case 'Z':
176           compress = opt;
177           break;
178 #endif
179 #ifndef NO_GZIP_CREATE
180         case 'z':
181           compress = opt;
182           break;
183 #endif
184         default:
185           usage();
186       }
187     }
188   }
189 
190   switch (mode) {
191 #ifndef NO_CREATE
192     case 'c':
193       create(filename, compress, argv, verbose);
194       break;
195 #endif
196     case 't':
197       extract(filename, 0, flags, verbose);
198       break;
199     case 'x':
200       extract(filename, 1, flags, verbose);
201       break;
202   }
203 
204   return (0);
205 }
206 
207 // clang-format on
208