[Cmake-commits] [cmake-commits] hoffman committed tarfilter.c NONE 1.1 untar.c NONE 1.1
cmake-commits at cmake.org
cmake-commits at cmake.org
Fri Oct 30 13:09:57 EDT 2009
Update of /cvsroot/CMake/CMake/Utilities/cmlibarchive/examples
In directory public:/mounts/ram/cvs-serv26614/Utilities/cmlibarchive/examples
Added Files:
tarfilter.c untar.c
Log Message:
Switch to using libarchive from libtar for cpack and cmake -E tar
This allows for a built in bzip and zip capability, so external tools
will not be needed for these packagers. The cmake -E tar xf should be
able to handle all compression types now as well.
--- NEW FILE: untar.c ---
/*
* This file is in the public domain.
* Use it as you wish.
*/
/*
* 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
*
* 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
* 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>
__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 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;
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)))
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)
fail("archive_read_next_header()",
archive_error_string(a), 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)
warn("archive_write_header()",
archive_error_string(ext));
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");
}
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)
return (ARCHIVE_OK);
if (r != ARCHIVE_OK)
return (r);
r = archive_write_data_block(aw, buff, size, offset);
if (r != ARCHIVE_OK) {
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)
{
write(1, m, strlen(m));
}
static void
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)
{
const char *m = "Usage: untar [-tvx] [-f file] [file]\n";
errmsg(m);
exit(1);
}
--- NEW FILE: tarfilter.c ---
/*
* This file is in the public domain.
*
* Feel free to use it as you wish.
*/
/*
* This example program reads an archive from stdin (which can be in
* any format recognized by libarchive) and writes certain entries to
* an uncompressed ustar archive on stdout. This is a template for
* many kinds of archive manipulation: converting formats, resetting
* ownership, inserting entries, removing entries, etc.
*
* To compile:
* gcc -Wall -o tarfilter tarfilter.c -larchive -lz -lbz2
*/
#include <sys/stat.h>
#include <archive.h>
#include <archive_entry.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
static void
die(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(1);
}
int
main(int argc, char **argv)
{
char buff[8192];
ssize_t len;
int r;
mode_t m;
struct archive *ina;
struct archive *outa;
struct archive_entry *entry;
/* Read an archive from stdin, with automatic format detection. */
ina = archive_read_new();
if (ina == NULL)
die("Couldn't create archive reader.");
if (archive_read_support_compression_all(ina) != ARCHIVE_OK)
die("Couldn't enable decompression");
if (archive_read_support_format_all(ina) != ARCHIVE_OK)
die("Couldn't enable read formats");
if (archive_read_open_fd(ina, 0, 10240) != ARCHIVE_OK)
die("Couldn't open input archive");
/* Write an uncompressed ustar archive to stdout. */
outa = archive_write_new();
if (outa == NULL)
die("Couldn't create archive writer.");
if (archive_write_set_compression_none(outa) != ARCHIVE_OK)
die("Couldn't enable compression");
if (archive_write_set_format_ustar(outa) != ARCHIVE_OK)
die("Couldn't set output format");
if (archive_write_open_fd(outa, 1) != ARCHIVE_OK)
die("Couldn't open output archive");
/* Examine each entry in the input archive. */
while ((r = archive_read_next_header(ina, &entry)) == ARCHIVE_OK) {
fprintf(stderr, "%s: ", archive_entry_pathname(entry));
/* Skip anything that isn't a regular file. */
if (!S_ISREG(archive_entry_mode(entry))) {
fprintf(stderr, "skipped\n");
continue;
}
/* Make everything owned by root/wheel. */
archive_entry_set_uid(entry, 0);
archive_entry_set_uname(entry, "root");
archive_entry_set_gid(entry, 0);
archive_entry_set_gname(entry, "wheel");
/* Make everything permission 0744, strip SUID, etc. */
m = archive_entry_mode(entry);
archive_entry_set_mode(entry, (m & ~07777) | 0744);
/* Copy input entries to output archive. */
if (archive_write_header(outa, entry) != ARCHIVE_OK)
die("Error writing output archive");
if (archive_entry_size(entry) > 0) {
len = archive_read_data(ina, buff, sizeof(buff));
while (len > 0) {
if (archive_write_data(outa, buff, len) != len)
die("Error writing output archive");
len = archive_read_data(ina, buff, sizeof(buff));
}
if (len < 0)
die("Error reading input archive");
}
fprintf(stderr, "copied\n");
}
if (r != ARCHIVE_EOF)
die("Error reading archive");
/* Close the archives. */
if (archive_read_finish(ina) != ARCHIVE_OK)
die("Error closing input archive");
if (archive_write_finish(outa) != ARCHIVE_OK)
die("Error closing output archive");
return (0);
}
More information about the Cmake-commits
mailing list