1/*
2 * This file is in the public domain.
3 *
4 * Feel free to use it as you wish.
5 */
6
7/*
8 * This example program reads an archive from stdin (which can be in
9 * any format recognized by libarchive) and writes certain entries to
10 * an uncompressed ustar archive on stdout.  This is a template for
11 * many kinds of archive manipulation: converting formats, resetting
12 * ownership, inserting entries, removing entries, etc.
13 *
14 * To compile:
15 * gcc -Wall -o tarfilter tarfilter.c -larchive -lz -lbz2
16 */
17
18#include <sys/stat.h>
19#include <archive.h>
20#include <archive_entry.h>
21#include <stdarg.h>
22#include <stdio.h>
23#include <stdlib.h>
24
25static void
26die(char *fmt, ...)
27{
28	va_list ap;
29
30	va_start(ap, fmt);
31	vfprintf(stderr, fmt, ap);
32	va_end(ap);
33	fprintf(stderr, "\n");
34	exit(1);
35}
36
37int
38main(int argc, char **argv)
39{
40	char buff[8192];
41	ssize_t len;
42	int r;
43	mode_t m;
44	struct archive *ina;
45	struct archive *outa;
46	struct archive_entry *entry;
47
48	/* Read an archive from stdin, with automatic format detection. */
49	ina = archive_read_new();
50	if (ina == NULL)
51		die("Couldn't create archive reader.");
52	if (archive_read_support_compression_all(ina) != ARCHIVE_OK)
53		die("Couldn't enable decompression");
54	if (archive_read_support_format_all(ina) != ARCHIVE_OK)
55		die("Couldn't enable read formats");
56	if (archive_read_open_fd(ina, 0, 10240) != ARCHIVE_OK)
57		die("Couldn't open input archive");
58
59	/* Write an uncompressed ustar archive to stdout. */
60	outa = archive_write_new();
61	if (outa == NULL)
62		die("Couldn't create archive writer.");
63	if (archive_write_set_compression_none(outa) != ARCHIVE_OK)
64		die("Couldn't enable compression");
65	if (archive_write_set_format_ustar(outa) != ARCHIVE_OK)
66		die("Couldn't set output format");
67	if (archive_write_open_fd(outa, 1) != ARCHIVE_OK)
68		die("Couldn't open output archive");
69
70	/* Examine each entry in the input archive. */
71	while ((r = archive_read_next_header(ina, &entry)) == ARCHIVE_OK) {
72		fprintf(stderr, "%s: ", archive_entry_pathname(entry));
73
74		/* Skip anything that isn't a regular file. */
75		if (!S_ISREG(archive_entry_mode(entry))) {
76			fprintf(stderr, "skipped\n");
77			continue;
78		}
79
80		/* Make everything owned by root/wheel. */
81		archive_entry_set_uid(entry, 0);
82		archive_entry_set_uname(entry, "root");
83		archive_entry_set_gid(entry, 0);
84		archive_entry_set_gname(entry, "wheel");
85
86		/* Make everything permission 0744, strip SUID, etc. */
87		m = archive_entry_mode(entry);
88		archive_entry_set_mode(entry, (m & ~07777) | 0744);
89
90		/* Copy input entries to output archive. */
91		if (archive_write_header(outa, entry) != ARCHIVE_OK)
92			die("Error writing output archive");
93		if (archive_entry_size(entry) > 0) {
94			len = archive_read_data(ina, buff, sizeof(buff));
95			while (len > 0) {
96				if (archive_write_data(outa, buff, len) != len)
97					die("Error writing output archive");
98				len = archive_read_data(ina, buff, sizeof(buff));
99			}
100			if (len < 0)
101				die("Error reading input archive");
102		}
103		fprintf(stderr, "copied\n");
104	}
105	if (r != ARCHIVE_EOF)
106		die("Error reading archive");
107	/* Close the archives.  */
108	if (archive_read_finish(ina) != ARCHIVE_OK)
109		die("Error closing input archive");
110	if (archive_write_finish(outa) != ARCHIVE_OK)
111		die("Error closing output archive");
112	return (0);
113}
114