From 1176ee064223309e7459e6ee3ad53e787deae89b Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Sat, 29 Aug 2009 00:08:13 -0400 Subject: [PATCH] Merge r1396 from libarchive/trunk: significant rework of examples/untar.c, the minimal libarchive-based untar.c program. (Not to be confused with contrib/untar.c which is an even more minimal untar program that doesn't use libarchive. I have got to rename one of them someday....) SVN-Revision: 1397 --- examples/untar.c | 109 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 29 deletions(-) diff --git a/examples/untar.c b/examples/untar.c index 88f6dc26d..d6870de45 100644 --- a/examples/untar.c +++ b/examples/untar.c @@ -4,29 +4,52 @@ */ /* - * 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.) + * This is a compact tar extraction program using libarchive whose + * primary goal is small executable size. Statically linked, it can + * be very small, depending in large part 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. (Add a call to + * 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, since user/group + * lookups frequently pull in password, YP/LDAP, networking, and DNS + * resolver libraries.) * * To build: - * gcc -static -Wall -o untar untar.c -larchive - * strip untar + * $ gcc -static -Wall -o untar untar.c -larchive + * $ strip untar + * + * NOTE: On some systems, you may need to add additional flags + * to ensure that untar.c is compiled the same way as libarchive + * was compiled. In particular, Linux users will probably + * have to add -D_FILE_OFFSET_BITS=64 to the command line above. * * For fun, statically compile the following simple hello.c program - * and compare the size. (On my system, the result is 89k, untar is - * 69k.) + * using the same flags as for untar and compare the size: * * #include * int main(int argc, char **argv) { * printf("hello, world\n"); * return(0); * } + * + * You may be even more surprised by the compiled size of true.c listed here: + * + * int main(int argc, char **argv) { + * return (0); + * } + * + * On a slightly customized FreeBSD 5 system that I used around + * 2005, hello above compiled to 89k compared to untar of 69k. So at + * that time, libarchive's tar reader and extract-to-disk routines + * compiled to less code than printf(). + * + * On my FreeBSD development system today (August, 2009): + * hello: 195024 bytes + * true: 194912 bytes + * untar: 259924 bytes */ #include @@ -44,9 +67,11 @@ __FBSDID("$FreeBSD$"); static void errmsg(const char *); static void extract(const char *filename, int do_extract, int flags); +static void fail(const char *, const char *, int); static int copy_data(struct archive *, struct archive *); static void msg(const char *); static void usage(void); +static void warn(const char *, const char *); static int verbose = 0; @@ -133,20 +158,16 @@ extract(const char *filename, int do_extract, int flags) */ 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); - } + if ((r = archive_read_open_file(a, filename, 10240))) + fail("archive_read_open_file()", + archive_error_string(a), 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 (r != ARCHIVE_OK) + fail("archive_read_next_header()", + archive_error_string(a), 1); if (verbose && do_extract) msg("x "); if (verbose || !do_extract) @@ -154,9 +175,16 @@ extract(const char *filename, int do_extract, int flags) if (do_extract) { r = archive_write_header(ext, entry); if (r != ARCHIVE_OK) - errmsg(archive_error_string(a)); - else + warn("archive_write_header()", + archive_error_string(a)); + else { copy_data(a, ext); + r = archive_write_finish_entry(ext); + if (r != ARCHIVE_OK) + fail("archive_write_finish_entry()", + archive_error_string(ext), 1); + } + } if (verbose || !do_extract) msg("\n"); @@ -176,20 +204,27 @@ copy_data(struct archive *ar, struct archive *aw) for (;;) { r = archive_read_data_block(ar, &buff, &size, &offset); - if (r == ARCHIVE_EOF) { - errmsg(archive_error_string(ar)); + if (r == ARCHIVE_EOF) 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)); + warn("archive_write_data_block()", + archive_error_string(aw)); return (r); } } } +/* + * These reporting functions use low-level I/O; on some systems, this + * is a significant code reduction. Of course, on many server and + * desktop operating systems, malloc() and even crt rely on printf(), + * which in turn pulls in most of the rest of stdio, so this is not an + * optimization at all there. (If you're going to pay 100k or more + * for printf() anyway, you may as well use it!) + */ static void msg(const char *m) { @@ -202,6 +237,22 @@ errmsg(const char *m) write(2, m, strlen(m)); } +static void +warn(const char *f, const char *m) +{ + errmsg(f); + errmsg(" failed: "); + errmsg(m); + errmsg("\n"); +} + +static void +fail(const char *f, const char *m, int r) +{ + warn(f, m); + exit(r); +} + static void usage(void) { -- 2.47.3