summaryrefslogtreecommitdiff
path: root/examples/untar.c
diff options
context:
space:
mode:
authorTim Kientzle <kientzle@gmail.com>2008-04-30 18:11:33 -0400
committerTim Kientzle <kientzle@gmail.com>2008-04-30 18:11:33 -0400
commit6d04d9655f29085945526bc4f9921c4724895aa2 (patch)
treee17c677d005265f518cf7d40217d7f27027362d7 /examples/untar.c
parent1d718c3b69287bc706f6a9e0e25d92eb74bbe8cf (diff)
downloadlibarchive-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.c211
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);
+}