summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorTim Kientzle <kientzle@gmail.com>2009-08-28 23:42:55 -0400
committerTim Kientzle <kientzle@gmail.com>2009-08-28 23:42:55 -0400
commitddf552bb91d507c0fa8db16c84c43b31a272de47 (patch)
treeeb65a05ef4cad35b4bd9a4bbc0d618b5cb77acd0 /examples
parent95cfd8e4a7cc37f2fdc372b65e514f4eb75ace6c (diff)
downloadlibarchive-ddf552bb91d507c0fa8db16c84c43b31a272de47.tar.gz
Fix a handful of bugs in untar.c and significantly extend the opening
commentary, which hasn't really been updated since 2006 or so. In particular, I went back and rechecked the sizes on modern FreeBSD and found that things have bloated quite a bit: statically compiled, untar.c is now about 25% larger than hello.c, where it used to be almost 25% smaller. SVN-Revision: 1396
Diffstat (limited to 'examples')
-rw-r--r--examples/untar.c98
1 files changed, 74 insertions, 24 deletions
diff --git a/examples/untar.c b/examples/untar.c
index 468c1079..d6870de4 100644
--- a/examples/untar.c
+++ b/examples/untar.c
@@ -6,28 +6,50 @@
/*
* This is a compact tar extraction program using libarchive whose
* primary goal is small executable size. Statically linked, it can
- * be under 64k, depending on how cleanly factored your system
- * libraries are. Note that this uses the standard libarchive,
+ * 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. (Call
+ * 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.)
+ * 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 <stdio.h>
* 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 <sys/types.h>
@@ -45,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;
@@ -134,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)
@@ -155,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");
@@ -177,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)
{
@@ -204,6 +238,22 @@ errmsg(const char *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)
{
const char *m = "Usage: untar [-tvx] [-f file] [file]\n";