diff options
author | Tim Kientzle <kientzle@gmail.com> | 2008-04-30 18:11:33 -0400 |
---|---|---|
committer | Tim Kientzle <kientzle@gmail.com> | 2008-04-30 18:11:33 -0400 |
commit | 6d04d9655f29085945526bc4f9921c4724895aa2 (patch) | |
tree | e17c677d005265f518cf7d40217d7f27027362d7 /examples/untar.c | |
parent | 1d718c3b69287bc706f6a9e0e25d92eb74bbe8cf (diff) | |
download | libarchive-6d04d9655f29085945526bc4f9921c4724895aa2.tar.gz |
Include 'examples' and 'contrib' dirs from libarchive portable distro.
SVN-Revision: 8
Diffstat (limited to 'examples/untar.c')
-rw-r--r-- | examples/untar.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/examples/untar.c b/examples/untar.c new file mode 100644 index 00000000..88f6dc26 --- /dev/null +++ b/examples/untar.c @@ -0,0 +1,211 @@ +/* + * This file is in the public domain. + * Use it as you wish. + */ + +/* + * This is a compact tar extraction program whose primary goal is + * small size. Statically linked, it can be under 64k, depending on + * how cleanly factored your system libraries are. Note that this + * uses the standard libarchive, without any special recompilation. + * The only functional concession is that this program uses the + * uid/gid from the archive instead of doing uname/gname lookups. + * (Call archive_write_disk_set_standard_lookup() to enable + * uname/gname lookups, but be aware that this can add 500k or more to + * a static executable, depending on the system libraries.) + * + * To build: + * gcc -static -Wall -o untar untar.c -larchive + * strip untar + * + * For fun, statically compile the following simple hello.c program + * and compare the size. (On my system, the result is 89k, untar is + * 69k.) + * + * #include <stdio.h> + * int main(int argc, char **argv) { + * printf("hello, world\n"); + * return(0); + * } + */ + +#include <sys/types.h> +__FBSDID("$FreeBSD$"); + +#include <sys/stat.h> + +#include <archive.h> +#include <archive_entry.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void errmsg(const char *); +static void extract(const char *filename, int do_extract, int flags); +static int copy_data(struct archive *, struct archive *); +static void msg(const char *); +static void usage(void); + +static int verbose = 0; + +int +main(int argc, const char **argv) +{ + const char *filename = NULL; + int compress, flags, mode, opt; + + (void)argc; + mode = 'x'; + verbose = 0; + compress = '\0'; + flags = ARCHIVE_EXTRACT_TIME; + + /* Among other sins, getopt(3) pulls in printf(3). */ + while (*++argv != NULL && **argv == '-') { + const char *p = *argv + 1; + + while ((opt = *p++) != '\0') { + switch (opt) { + case 'f': + if (*p != '\0') + filename = p; + else + filename = *++argv; + p += strlen(p); + break; + case 'p': + flags |= ARCHIVE_EXTRACT_PERM; + flags |= ARCHIVE_EXTRACT_ACL; + flags |= ARCHIVE_EXTRACT_FFLAGS; + break; + case 't': + mode = opt; + break; + case 'v': + verbose++; + break; + case 'x': + mode = opt; + break; + default: + usage(); + } + } + } + + switch (mode) { + case 't': + extract(filename, 0, flags); + break; + case 'x': + extract(filename, 1, flags); + break; + } + + return (0); +} + + +static void +extract(const char *filename, int do_extract, int flags) +{ + struct archive *a; + struct archive *ext; + struct archive_entry *entry; + int r; + + a = archive_read_new(); + ext = archive_write_disk_new(); + archive_write_disk_set_options(ext, flags); + /* + * Note: archive_write_disk_set_standard_lookup() is useful + * here, but it requires library routines that can add 500k or + * more to a static executable. + */ + archive_read_support_format_tar(a); + /* + * On my system, enabling other archive formats adds 20k-30k + * each. Enabling gzip decompression adds about 20k. + * Enabling bzip2 is more expensive because the libbz2 library + * isn't very well factored. + */ + if (filename != NULL && strcmp(filename, "-") == 0) + filename = NULL; + if ((r = archive_read_open_file(a, filename, 10240))) { + errmsg(archive_error_string(a)); + errmsg("\n"); + exit(r); + } + for (;;) { + r = archive_read_next_header(a, &entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) { + errmsg(archive_error_string(a)); + errmsg("\n"); + exit(1); + } + if (verbose && do_extract) + msg("x "); + if (verbose || !do_extract) + msg(archive_entry_pathname(entry)); + if (do_extract) { + r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) + errmsg(archive_error_string(a)); + else + copy_data(a, ext); + } + if (verbose || !do_extract) + msg("\n"); + } + archive_read_close(a); + archive_read_finish(a); + exit(0); +} + +static int +copy_data(struct archive *ar, struct archive *aw) +{ + int r; + const void *buff; + size_t size; + off_t offset; + + for (;;) { + r = archive_read_data_block(ar, &buff, &size, &offset); + if (r == ARCHIVE_EOF) { + errmsg(archive_error_string(ar)); + return (ARCHIVE_OK); + } + if (r != ARCHIVE_OK) + return (r); + r = archive_write_data_block(aw, buff, size, offset); + if (r != ARCHIVE_OK) { + errmsg(archive_error_string(ar)); + return (r); + } + } +} + +static void +msg(const char *m) +{ + write(1, m, strlen(m)); +} + +static void +errmsg(const char *m) +{ + write(2, m, strlen(m)); +} + +static void +usage(void) +{ + const char *m = "Usage: untar [-tvx] [-f file] [file]\n"; + errmsg(m); + exit(1); +} |