2 * Copyright (c) 2008-2012 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
25 static struct option long_options[] = {
26 {"create" , 0, NULL, 1},
27 {"extract" , 0, NULL, 2},
28 {"list" , 0, NULL, 3},
29 {"verbose" , 0, NULL, 4},
30 {"file" , 1, NULL, 5},
31 {"version" , 0, NULL, 6},
38 printf("Usage: amarchiver [--version|--create|--list|--extract] [--verbose]* [--file file]\n");
39 printf(" [filename]*\n");
43 error_exit(const char *action, GError *error)
45 const char *msg = error->message? error->message : "(unknown)";
46 g_fprintf(stderr, "%s: %s\n", action, msg);
51 do_create(char *opt_file, int opt_verbose, int argc, char **argv)
53 FILE *output = stdout;
56 amar_attr_t *attribute;
61 if (opt_file != NULL && strcmp(opt_file,"-") != 0) {
62 fd_out = open(opt_file, O_CREAT|O_WRONLY|O_TRUNC, 0660);
64 error("open of '%s' failed: %s\n", opt_file, strerror(errno));
67 fd_out = fileno(stdout);
70 archive = amar_new(fd_out, O_WRONLY, &error);
72 error_exit("amar_new", error);
76 fd_in = open(argv[i], O_RDONLY);
78 g_fprintf(stderr, "open of '%s' failed: %s\n", argv[i], strerror(errno));
83 file = amar_new_file(archive, argv[i], strlen(argv[i]), NULL, &error);
85 error_exit("amar_new_file", error);
86 attribute = amar_new_attr(file, AMAR_ATTR_GENERIC_DATA, &error);
88 error_exit("amar_new_attr", error);
90 filesize += amar_attr_add_data_fd(attribute, fd_in, 1, &error);
92 error_exit("amar_attr_add_data_fd", error);
94 if (!amar_attr_close(attribute, &error))
95 error_exit("amar_attr_close", error);
96 if (!amar_file_close(file, &error))
97 error_exit("amar_file_close", error);
99 if (opt_verbose == 1) {
100 g_fprintf(output,"%s\n", argv[i]);
101 } else if (opt_verbose > 1) {
102 g_fprintf(output,"%llu %s\n", (unsigned long long)filesize, argv[i]);
108 if (!amar_close(archive, &error))
109 error_exit("amar_close", error);
113 struct read_user_data {
120 extract_file_start_cb(
122 uint16_t filenum G_GNUC_UNUSED,
123 gpointer filename_buf,
125 gboolean *ignore G_GNUC_UNUSED,
128 struct read_user_data *ud = user_data;
131 /* keep the filename for later */
132 *file_data = g_strndup(filename_buf, filename_len);
136 for (i = 0; i < ud->argc; i++) {
137 if (strlen(ud->argv[i]) == filename_len
138 && 0 == strcmp(ud->argv[i], *file_data))
147 extract_file_finish_cb(
148 gpointer user_data G_GNUC_UNUSED,
149 uint16_t filenum G_GNUC_UNUSED,
154 g_fprintf(stderr, _("Data for '%s' may have been truncated\n"),
164 gpointer user_data G_GNUC_UNUSED,
165 uint16_t filenum G_GNUC_UNUSED,
168 gpointer attrid_data G_GNUC_UNUSED,
175 struct read_user_data *ud = user_data;
176 int fd = GPOINTER_TO_INT(*attr_data);
179 char *filename = g_strdup_printf("%s.%d", (char *)file_data, attrid);
180 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0660);
182 g_fprintf(stderr, _("Could not open '%s' for writing: %s"),
183 filename, strerror(errno));
186 g_fprintf(stderr, "%s\n", filename);
188 *attr_data = GINT_TO_POINTER(fd);
191 if (full_write(fd, data, datasize) != datasize) {
192 g_fprintf(stderr, _("while writing '%s.%d': %s"),
193 (char *)file_data, attrid, strerror(errno));
199 g_fprintf(stderr, _("'%s.%d' may be truncated\n"),
200 (char *)file_data, attrid);
216 GError *error = NULL;
218 amar_attr_handling_t handling[] = {
219 { 0, 0, extract_frag_cb, NULL },
221 struct read_user_data ud;
225 ud.verbose = opt_verbose;
227 if (opt_file && strcmp(opt_file,"-") != 0) {
228 fd_in = open(opt_file, O_RDONLY);
230 error("open of '%s' failed: %s\n", opt_file, strerror(errno));
233 fd_in = fileno(stdin);
236 archive = amar_new(fd_in, O_RDONLY, &error);
238 error_exit("amar_new", error);
240 if (!amar_read(archive, &ud, handling, extract_file_start_cb,
241 extract_file_finish_cb, &error)) {
243 error_exit("amar_read", error);
245 /* one of the callbacks already printed an error message */
252 gpointer user_data G_GNUC_UNUSED,
253 uint16_t filenum G_GNUC_UNUSED,
254 gpointer filename_buf,
257 gpointer *file_data G_GNUC_UNUSED)
259 g_printf("%.*s\n", (int)filename_len, (char *)filename_buf);
267 int opt_verbose G_GNUC_UNUSED)
270 GError *error = NULL;
272 amar_attr_handling_t handling[] = {
273 { 0, 0, NULL, NULL },
276 if (opt_file && strcmp(opt_file,"-") != 0) {
277 fd_in = open(opt_file, O_RDONLY);
279 error("open of '%s' failed: %s\n", opt_file, strerror(errno));
282 fd_in = fileno(stdin);
285 archive = amar_new(fd_in, O_RDONLY, &error);
287 error_exit("amar_new", error);
289 if (!amar_read(archive, NULL, handling, list_file_start_cb,
292 error_exit("amar_read", error);
294 /* one of the callbacks already printed an error message */
307 char *opt_file = NULL;
310 int option_index = 0;
311 int c = getopt_long (argc, argv, "", long_options, &option_index);
316 case 1: opt_create = 1;
318 case 2: opt_extract = 1;
320 case 3: opt_list = 1;
322 case 4: opt_verbose += 1;
324 case 5: opt_file = stralloc(optarg);
326 case 6: printf("amarchiver %s\n", VERSION);
334 /* check those arguments */
335 if (opt_create + opt_extract + opt_list == 0) {
336 g_fprintf(stderr,"--create, --list or --extract must be provided\n");
339 if (opt_create + opt_extract + opt_list > 1) {
340 g_fprintf(stderr,"Only one of --create, --list or --extract must be provided\n");
345 g_fprintf(stderr, "--list does not take any additional filenames\n");
351 do_create(opt_file, opt_verbose, argc, argv);
352 else if (opt_extract > 0)
353 do_extract(opt_file, opt_verbose, argc, argv);
354 else if (opt_list > 0)
355 do_list(opt_file, opt_verbose);