~sergei.glushchenko/+junk/page-scan-hack

« back to all changes in this revision

Viewing changes to src/libarchive/examples/minitar/minitar.c

merge parallel compression branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * This file is in the public domain.
 
3
 * Do with it as you will.
 
4
 */
 
5
 
 
6
/*-
 
7
 * This is a compact "tar" program whose primary goal is small size.
 
8
 * Statically linked, it can be very small indeed.  This serves a number
 
9
 * of goals:
 
10
 *   o a testbed for libarchive (to check for link pollution),
 
11
 *   o a useful tool for space-constrained systems (boot floppies, etc),
 
12
 *   o a place to experiment with new implementation ideas for bsdtar,
 
13
 *   o a small program to demonstrate libarchive usage.
 
14
 *
 
15
 * Use the following macros to suppress features:
 
16
 *   NO_BZIP2 - Implies NO_BZIP2_CREATE and NO_BZIP2_EXTRACT
 
17
 *   NO_BZIP2_CREATE - Suppress bzip2 compression support.
 
18
 *   NO_BZIP2_EXTRACT - Suppress bzip2 auto-detection and decompression.
 
19
 *   NO_COMPRESS - Implies NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT
 
20
 *   NO_COMPRESS_CREATE - Suppress compress(1) compression support
 
21
 *   NO_COMPRESS_EXTRACT - Suppress compress(1) auto-detect and decompression.
 
22
 *   NO_CREATE - Suppress all archive creation support.
 
23
 *   NO_CPIO_EXTRACT - Suppress auto-detect and dearchiving of cpio archives.
 
24
 *   NO_GZIP - Implies NO_GZIP_CREATE and NO_GZIP_EXTRACT
 
25
 *   NO_GZIP_CREATE - Suppress gzip compression support.
 
26
 *   NO_GZIP_EXTRACT - Suppress gzip auto-detection and decompression.
 
27
 *   NO_LOOKUP - Try to avoid getpw/getgr routines, which can be very large
 
28
 *   NO_TAR_EXTRACT - Suppress tar extraction
 
29
 *
 
30
 * With all of the above macros defined (except NO_TAR_EXTRACT), you
 
31
 * get a very small program that can recognize and extract essentially
 
32
 * any uncompressed tar archive.  On FreeBSD 5.1, this minimal program
 
33
 * is under 64k, statically linked, which compares rather favorably to
 
34
 *         main(){printf("hello, world");}
 
35
 * which is over 60k statically linked on the same operating system.
 
36
 * Without any of the above macros, you get a static executable of
 
37
 * about 180k with a lot of very sophisticated modern features.
 
38
 * Obviously, it's trivial to add support for ISO, Zip, mtree,
 
39
 * lzma/xz, etc.  Just fill in the appropriate setup calls.
 
40
 */
 
41
 
 
42
#include <sys/types.h>
 
43
__FBSDID("$FreeBSD$");
 
44
 
 
45
#include <sys/stat.h>
 
46
 
 
47
#include <archive.h>
 
48
#include <archive_entry.h>
 
49
#include <fcntl.h>
 
50
#include <stdio.h>
 
51
#include <stdlib.h>
 
52
#include <string.h>
 
53
#include <unistd.h>
 
54
 
 
55
#ifndef NO_CREATE
 
56
#include "tree.h"
 
57
#endif
 
58
 
 
59
/*
 
60
 * NO_CREATE implies NO_BZIP2_CREATE and NO_GZIP_CREATE and NO_COMPRESS_CREATE.
 
61
 */
 
62
#ifdef NO_CREATE
 
63
#undef NO_BZIP2_CREATE
 
64
#define NO_BZIP2_CREATE
 
65
#undef NO_COMPRESS_CREATE
 
66
#define NO_COMPRESS_CREATE
 
67
#undef NO_GZIP_CREATE
 
68
#define NO_GZIP_CREATE
 
69
#endif
 
70
 
 
71
/*
 
72
 * The combination of NO_BZIP2_CREATE and NO_BZIP2_EXTRACT is
 
73
 * equivalent to NO_BZIP2.
 
74
 */
 
75
#ifdef NO_BZIP2_CREATE
 
76
#ifdef NO_BZIP2_EXTRACT
 
77
#undef NO_BZIP2
 
78
#define NO_BZIP2
 
79
#endif
 
80
#endif
 
81
 
 
82
#ifdef NO_BZIP2
 
83
#undef NO_BZIP2_EXTRACT
 
84
#define NO_BZIP2_EXTRACT
 
85
#undef NO_BZIP2_CREATE
 
86
#define NO_BZIP2_CREATE
 
87
#endif
 
88
 
 
89
/*
 
90
 * The combination of NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT is
 
91
 * equivalent to NO_COMPRESS.
 
92
 */
 
93
#ifdef NO_COMPRESS_CREATE
 
94
#ifdef NO_COMPRESS_EXTRACT
 
95
#undef NO_COMPRESS
 
96
#define NO_COMPRESS
 
97
#endif
 
98
#endif
 
99
 
 
100
#ifdef NO_COMPRESS
 
101
#undef NO_COMPRESS_EXTRACT
 
102
#define NO_COMPRESS_EXTRACT
 
103
#undef NO_COMPRESS_CREATE
 
104
#define NO_COMPRESS_CREATE
 
105
#endif
 
106
 
 
107
/*
 
108
 * The combination of NO_GZIP_CREATE and NO_GZIP_EXTRACT is
 
109
 * equivalent to NO_GZIP.
 
110
 */
 
111
#ifdef NO_GZIP_CREATE
 
112
#ifdef NO_GZIP_EXTRACT
 
113
#undef NO_GZIP
 
114
#define NO_GZIP
 
115
#endif
 
116
#endif
 
117
 
 
118
#ifdef NO_GZIP
 
119
#undef NO_GZIP_EXTRACT
 
120
#define NO_GZIP_EXTRACT
 
121
#undef NO_GZIP_CREATE
 
122
#define NO_GZIP_CREATE
 
123
#endif
 
124
 
 
125
#ifndef NO_CREATE
 
126
static void     create(const char *filename, int compress, const char **argv);
 
127
#endif
 
128
static void     errmsg(const char *);
 
129
static void     extract(const char *filename, int do_extract, int flags);
 
130
static int      copy_data(struct archive *, struct archive *);
 
131
static void     msg(const char *);
 
132
static void     usage(void);
 
133
 
 
134
static int verbose = 0;
 
135
 
 
136
int
 
137
main(int argc, const char **argv)
 
138
{
 
139
        const char *filename = NULL;
 
140
        int compress, flags, mode, opt;
 
141
 
 
142
        (void)argc;
 
143
        mode = 'x';
 
144
        verbose = 0;
 
145
        compress = '\0';
 
146
        flags = ARCHIVE_EXTRACT_TIME;
 
147
 
 
148
        /* Among other sins, getopt(3) pulls in printf(3). */
 
149
        while (*++argv != NULL && **argv == '-') {
 
150
                const char *p = *argv + 1;
 
151
 
 
152
                while ((opt = *p++) != '\0') {
 
153
                        switch (opt) {
 
154
#ifndef NO_CREATE
 
155
                        case 'c':
 
156
                                mode = opt;
 
157
                                break;
 
158
#endif
 
159
                        case 'f':
 
160
                                if (*p != '\0')
 
161
                                        filename = p;
 
162
                                else
 
163
                                        filename = *++argv;
 
164
                                p += strlen(p);
 
165
                                break;
 
166
#ifndef NO_BZIP2_CREATE
 
167
                        case 'j':
 
168
                                compress = opt;
 
169
                                break;
 
170
#endif
 
171
                        case 'p':
 
172
                                flags |= ARCHIVE_EXTRACT_PERM;
 
173
                                flags |= ARCHIVE_EXTRACT_ACL;
 
174
                                flags |= ARCHIVE_EXTRACT_FFLAGS;
 
175
                                break;
 
176
                        case 't':
 
177
                                mode = opt;
 
178
                                break;
 
179
                        case 'v':
 
180
                                verbose++;
 
181
                                break;
 
182
                        case 'x':
 
183
                                mode = opt;
 
184
                                break;
 
185
#ifndef NO_BZIP2_CREATE
 
186
                        case 'y':
 
187
                                compress = opt;
 
188
                                break;
 
189
#endif
 
190
#ifndef NO_COMPRESS_CREATE
 
191
                        case 'Z':
 
192
                                compress = opt;
 
193
                                break;
 
194
#endif
 
195
#ifndef NO_GZIP_CREATE
 
196
                        case 'z':
 
197
                                compress = opt;
 
198
                                break;
 
199
#endif
 
200
                        default:
 
201
                                usage();
 
202
                        }
 
203
                }
 
204
        }
 
205
 
 
206
        switch (mode) {
 
207
#ifndef NO_CREATE
 
208
        case 'c':
 
209
                create(filename, compress, argv);
 
210
                break;
 
211
#endif
 
212
        case 't':
 
213
                extract(filename, 0, flags);
 
214
                break;
 
215
        case 'x':
 
216
                extract(filename, 1, flags);
 
217
                break;
 
218
        }
 
219
 
 
220
        return (0);
 
221
}
 
222
 
 
223
 
 
224
#ifndef NO_CREATE
 
225
static char buff[16384];
 
226
 
 
227
static void
 
228
create(const char *filename, int compress, const char **argv)
 
229
{
 
230
        struct archive *a;
 
231
        struct archive *disk;
 
232
        struct archive_entry *entry;
 
233
        ssize_t len;
 
234
        int fd;
 
235
 
 
236
        a = archive_write_new();
 
237
        switch (compress) {
 
238
#ifndef NO_BZIP2_CREATE
 
239
        case 'j': case 'y':
 
240
                archive_write_set_compression_bzip2(a);
 
241
                break;
 
242
#endif
 
243
#ifndef NO_COMPRESS_CREATE
 
244
        case 'Z':
 
245
                archive_write_set_compression_compress(a);
 
246
                break;
 
247
#endif
 
248
#ifndef NO_GZIP_CREATE
 
249
        case 'z':
 
250
                archive_write_set_compression_gzip(a);
 
251
                break;
 
252
#endif
 
253
        default:
 
254
                archive_write_set_compression_none(a);
 
255
                break;
 
256
        }
 
257
        archive_write_set_format_ustar(a);
 
258
        if (strcmp(filename, "-") == 0)
 
259
                filename = NULL;
 
260
        archive_write_open_file(a, filename);
 
261
 
 
262
        disk = archive_read_disk_new();
 
263
#ifndef NO_LOOKUP
 
264
        archive_read_disk_set_standard_lookup(disk);
 
265
#endif
 
266
        while (*argv != NULL) {
 
267
                struct tree *t = tree_open(*argv);
 
268
                while (tree_next(t)) {
 
269
                        entry = archive_entry_new();
 
270
                        archive_entry_set_pathname(entry, tree_current_path(t));
 
271
                        archive_read_disk_entry_from_file(disk, entry, -1,
 
272
                            tree_current_stat(t));
 
273
                        if (verbose) {
 
274
                                msg("a ");
 
275
                                msg(tree_current_path(t));
 
276
                        }
 
277
                        archive_write_header(a, entry);
 
278
                        fd = open(tree_current_access_path(t), O_RDONLY);
 
279
                        len = read(fd, buff, sizeof(buff));
 
280
                        while (len > 0) {
 
281
                                archive_write_data(a, buff, len);
 
282
                                len = read(fd, buff, sizeof(buff));
 
283
                        }
 
284
                        close(fd);
 
285
                        archive_entry_free(entry);
 
286
                        if (verbose)
 
287
                                msg("\n");
 
288
                }
 
289
                argv++;
 
290
        }
 
291
        archive_write_close(a);
 
292
        archive_write_finish(a);
 
293
}
 
294
#endif
 
295
 
 
296
static void
 
297
extract(const char *filename, int do_extract, int flags)
 
298
{
 
299
        struct archive *a;
 
300
        struct archive *ext;
 
301
        struct archive_entry *entry;
 
302
        int r;
 
303
 
 
304
        a = archive_read_new();
 
305
        ext = archive_write_disk_new();
 
306
        archive_write_disk_set_options(ext, flags);
 
307
#ifndef NO_BZIP2_EXTRACT
 
308
        archive_read_support_compression_bzip2(a);
 
309
#endif
 
310
#ifndef NO_GZIP_EXTRACT
 
311
        archive_read_support_compression_gzip(a);
 
312
#endif
 
313
#ifndef NO_COMPRESS_EXTRACT
 
314
        archive_read_support_compression_compress(a);
 
315
#endif
 
316
#ifndef NO_TAR_EXTRACT
 
317
        archive_read_support_format_tar(a);
 
318
#endif
 
319
#ifndef NO_CPIO_EXTRACT
 
320
        archive_read_support_format_cpio(a);
 
321
#endif
 
322
#ifndef NO_LOOKUP
 
323
        archive_write_disk_set_standard_lookup(ext);
 
324
#endif
 
325
        if (filename != NULL && strcmp(filename, "-") == 0)
 
326
                filename = NULL;
 
327
        if ((r = archive_read_open_file(a, filename, 10240))) {
 
328
                errmsg(archive_error_string(a));
 
329
                errmsg("\n");
 
330
                exit(r);
 
331
        }
 
332
        for (;;) {
 
333
                r = archive_read_next_header(a, &entry);
 
334
                if (r == ARCHIVE_EOF)
 
335
                        break;
 
336
                if (r != ARCHIVE_OK) {
 
337
                        errmsg(archive_error_string(a));
 
338
                        errmsg("\n");
 
339
                        exit(1);
 
340
                }
 
341
                if (verbose && do_extract)
 
342
                        msg("x ");
 
343
                if (verbose || !do_extract)
 
344
                        msg(archive_entry_pathname(entry));
 
345
                if (do_extract) {
 
346
                        r = archive_write_header(ext, entry);
 
347
                        if (r != ARCHIVE_OK)
 
348
                                errmsg(archive_error_string(a));
 
349
                        else
 
350
                                copy_data(a, ext);
 
351
                }
 
352
                if (verbose || !do_extract)
 
353
                        msg("\n");
 
354
        }
 
355
        archive_read_close(a);
 
356
        archive_read_finish(a);
 
357
        exit(0);
 
358
}
 
359
 
 
360
static int
 
361
copy_data(struct archive *ar, struct archive *aw)
 
362
{
 
363
        int r;
 
364
        const void *buff;
 
365
        size_t size;
 
366
        off_t offset;
 
367
 
 
368
        for (;;) {
 
369
                r = archive_read_data_block(ar, &buff, &size, &offset);
 
370
                if (r == ARCHIVE_EOF) {
 
371
                        errmsg(archive_error_string(ar));
 
372
                        return (ARCHIVE_OK);
 
373
                }
 
374
                if (r != ARCHIVE_OK)
 
375
                        return (r);
 
376
                r = archive_write_data_block(aw, buff, size, offset);
 
377
                if (r != ARCHIVE_OK) {
 
378
                        errmsg(archive_error_string(ar));
 
379
                        return (r);
 
380
                }
 
381
        }
 
382
}
 
383
 
 
384
static void
 
385
msg(const char *m)
 
386
{
 
387
        write(1, m, strlen(m));
 
388
}
 
389
 
 
390
static void
 
391
errmsg(const char *m)
 
392
{
 
393
        write(2, m, strlen(m));
 
394
}
 
395
 
 
396
static void
 
397
usage(void)
 
398
{
 
399
/* Many program options depend on compile options. */
 
400
        const char *m = "Usage: minitar [-"
 
401
#ifndef NO_CREATE
 
402
            "c"
 
403
#endif
 
404
#ifndef NO_BZIP2
 
405
            "j"
 
406
#endif
 
407
            "tvx"
 
408
#ifndef NO_BZIP2
 
409
            "y"
 
410
#endif
 
411
#ifndef NO_COMPRESS
 
412
            "Z"
 
413
#endif
 
414
#ifndef NO_GZIP
 
415
            "z"
 
416
#endif
 
417
            "] [-f file] [file]\n";
 
418
 
 
419
        errmsg(m);
 
420
        exit(1);
 
421
}