3 * dumpscan - routines for scanning and manipulating AFS volume dumps
5 * Copyright (c) 1998 Carnegie Mellon University
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie Mellon
26 * the rights to redistribute these changes.
29 /* afsdump_extract.c - Extract files from an AFS dump */
31 #include <sys/fcntl.h>
32 #include <sys/types.h>
39 #include "dumpscan_errs.h"
41 #define COPYBUFSIZE (256*1024)
47 static char **file_names;
48 static int *file_vnums, name_count, vnum_count;
50 static char *input_path, *target;
51 static int quiet, verbose, error_count, dirs_done, extract_all;
52 static int nomode, use_realpath, use_vnum;
53 static int do_acls, do_headers;
55 static path_hashinfo phi;
56 static dump_parser dp;
58 /* Print a usage message and exit */
59 static void usage(int status, char *msg)
61 if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
62 fprintf(stderr, "Usage: %s [options] dumpfile [dest [files...]]\n", argv0);
63 fprintf(stderr, " -A Save ACL's\n");
64 fprintf(stderr, " -H Save headers\n");
65 fprintf(stderr, " -h Print this help message\n");
66 fprintf(stderr, " -i Use vnode numbers\n");
67 fprintf(stderr, " -n Don't actually create files\n");
68 fprintf(stderr, " -p Use real pathnames internally\n");
69 fprintf(stderr, " -q Quiet mode (don't print errors)\n");
70 fprintf(stderr, " -v Verbose mode\n");
71 fprintf(stderr, "The destination directory defaults to .\n");
72 fprintf(stderr, "Files may be vnode numbers or volume-relative paths;\n");
73 fprintf(stderr, "If vnode numbers are used, files will be extracted\n");
74 fprintf(stderr, "a name generated from the vnode number and uniqifier.\n");
75 fprintf(stderr, "If paths are used, -p is implied and files will be\n");
76 fprintf(stderr, "into correctly-named files.\n");
81 /* Parse the command-line options */
82 static void parse_options(int argc, char **argv)
84 int c, i, i_name, i_vnum;
86 /* Set the program name */
87 if (argv0 = strrchr(argv[0], '/')) argv0++;
90 /* Initialize options */
92 quiet = verbose = nomode = 0;
93 use_realpath = use_vnum = do_acls = do_headers = extract_all = 0;
95 /* Initialize other stuff */
98 /* Parse the options */
99 while ((c = getopt(argc, argv, "AHhinpqv")) != EOF) {
101 case 'A': do_acls = 1; continue;
102 case 'H': do_headers = 1; continue;
103 case 'i': use_vnum = 1; continue;
104 case 'n': nomode = 1; continue;
105 case 'p': use_realpath = 1; continue;
106 case 'q': quiet = 1; continue;
107 case 'v': verbose = 1; continue;
108 case 'h': usage(0, 0);
109 default: usage(1, "Invalid option!");
113 if (quiet && verbose) usage(1, "Can't specify both -q and -v");
115 /* Parse non-option arguments */
116 if (argc - optind < 1) usage(1, "Dumpfile name required!");
117 input_path = argv[optind];
119 if (argc - optind < 2) target = ".";
120 target = argv[optind + 1];
122 vnum_count = name_count = 0;
123 if (argc - optind < 3) extract_all = 1;
127 for (i = 0; i < argc; i++) {
128 if (argv[i][0] == '/') name_count++;
131 file_names = (char **)malloc(name_count + sizeof(char *));
132 file_vnums = (afs_uint32 *)malloc(vnum_count + sizeof(afs_uint32));
133 if (name_count) use_realpath = 1;
136 for (i = 0; i < argc; i++) {
137 if (argv[i][0] == '/') file_names[i_name++] = argv[i];
138 else file_vnums[i_vnum++] = strtol(argv[i], 0, 0);
144 static int mkdirp(char *path)
146 char *x = path, slash;
150 while (*x && *x != '/') x++;
154 if (stat(path, &statbuf)) {
155 if (errno == ENOENT) {
156 if (verbose) printf("> mkdir %s\n", path);
157 if (!mkdir(path, 0755)) errno = 0;
162 if (errno) return errno;
169 static char *modestr(int mode)
174 strcpy(str, "rwxrwxrwx");
175 for (i = 0; i < 9; i++) {
176 if (!(mode & (1 << i)))
179 if (mode & 01000) str[8] = (str[8] == '-') ? 'T' : 't';
180 if (mode & 02000) str[5] = (str[5] == '-') ? 'S' : 's';
181 if (mode & 04000) str[2] = (str[2] == '-') ? 'S' : 's';
186 static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
187 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
188 static char *datestr(time_t date)
191 time_t clock = time(0);
192 struct tm *now, *then;
195 now = localtime(&clock);
196 then = localtime(&date);
198 diff = now->tm_mon - then->tm_mon;
199 if (then->tm_year == now->tm_year - 1) diff += 12;
200 if (then->tm_year == now->tm_year + 1) diff -= 12;
202 if (diff < 5 || diff > 5)
203 sprintf(str, "%3s %2d %4d", month[then->tm_mon], then->tm_mday,
204 then->tm_year + 1900);
206 sprintf(str, "%3s %2d %2d:%2d", month[then->tm_mon], then->tm_mday,
207 then->tm_hour, then->tm_min);
212 /* Should we use this vnode?
213 * Return 0 if no, non-0 if yes
215 static int usevnode(XFILE *X, afs_uint32 vnum, char *vnodepath)
220 if (extract_all || !strcmp(vnodepath, "/"))
223 for (i = 0; i < vnum_count; i++)
224 if (vnum == file_vnums[i]) return 2;
226 vl = strlen(vnodepath);
227 /*fprintf(stderr, "++ checking %s\n", vnodepath);*/
228 for (i = 0; i < name_count; i++) {
229 vpl = strlen(file_names[i]);
230 /* fprintf(stderr, " %s\n", file_names[i]);*/
233 r = !strncmp(file_names[i], vnodepath, vpl) && vnodepath[vpl] == '/';
234 } else if (vl < vpl) {
235 r = !strncmp(file_names[i], vnodepath, vl) && file_names[i][vl] == '/';
237 r = !strcmp(file_names[i], vnodepath);
245 static int copyfile(XFILE *in, XFILE *out, int size)
247 static char buf[COPYBUFSIZE];
251 nr = (size > COPYBUFSIZE) ? COPYBUFSIZE : size;
252 if (r = xfread(in, buf, nr)) return r;
253 if (r = xfwrite(out, buf, nr)) return r;
260 /* A callback to count and print errors */
261 static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
267 va_start(alist, msg);
268 com_err_va(argv0, code, msg, alist);
274 static afs_uint32 dumphdr_cb(afs_dump_header *hdr, XFILE *X, void *refcon)
280 static afs_uint32 volhdr_cb(afs_vol_header *hdr, XFILE *X, void *refcon)
286 static afs_uint32 directory_cb(afs_vnode *v, XFILE *X, void *refcon)
291 /* Should we even use this? */
293 if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
295 if (!(use = usevnode(X, v->vnode, vnodepath))) {
304 printf("d%s %3d %-11d %11d %s #%d:%d\n",
305 modestr(v->mode), v->nlinks, v->owner, v->size,
306 datestr(v->server_date), v->vnode, v->vuniq);
308 printf("d%s %3d %-11d %11d %s %s\n",
309 modestr(v->mode), v->nlinks, v->owner, v->size,
310 datestr(v->server_date), vnodepath);
312 else if (!quiet && !use_vnum)
313 printf("%s\n", vnodepath);
315 /* Make the directory, if needed */
316 if (!nomode && !use_vnum && use != 2) {
317 if (strcmp(vnodepath, "/")
318 && (r = mkdirp(vnodepath + 1))) {
323 /* XXX do ACL's later */
326 if (!use_vnum) free(vnodepath);
331 static afs_uint32 file_cb(afs_vnode *v, XFILE *X, void *refcon)
333 char *vnodepath, vnpx[30];
340 if (verbose) printf("* Extracting files...\n");
343 /* Should we even use this? */
345 if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
347 if (!(use = usevnode(X, v->vnode, vnodepath))) {
353 sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
357 sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
363 printf("-%s %3d %-11d %11d %s %s\n",
364 modestr(v->mode), v->nlinks, v->owner, v->size,
365 datestr(v->server_date), vnodepath);
367 printf("%s\n", vnodepath);
371 if ((r = xftell(X, &where))
372 || (r = xfseek(X, &v->d_offset))
373 || (r = xfopen_path(&OX, O_RDWR|O_CREAT|O_TRUNC, vnodepath + 1, 0644))) {
374 if (!use_vnum) free(vnodepath);
377 r = copyfile(X, &OX, v->size);
382 if (!use_vnum && use != 2) free(vnodepath);
387 static afs_uint32 symlink_cb(afs_vnode *v, XFILE *X, void *refcon)
389 char *vnodepath, *linktarget, vnpx[30];
395 if (verbose) printf("* Extracting files...\n");
398 /* Should we even use this? */
400 if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
402 if (!(use = usevnode(X, v->vnode, vnodepath))) {
408 sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
412 sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
416 if (!(linktarget = (char *)malloc(v->size + 1))) {
417 if (!use_vnum && use != 2) free(vnodepath);
420 if ((r = xftell(X, &where))
421 || (r = xfseek(X, &v->d_offset))
422 || (r = xfread(X, linktarget, v->size))) {
423 if (!use_vnum && use != 2) free(vnodepath);
428 linktarget[v->size] = 0;
432 printf("l%s %3d %-11d %11d %s %s -> %s\n",
433 modestr(v->mode), v->nlinks, v->owner, v->size,
434 datestr(v->server_date), vnodepath, linktarget);
436 printf("%s\n", vnodepath);
440 if (symlink(linktarget, vnodepath + 1))
445 if (!use_vnum && use != 2) free(vnodepath);
450 static afs_uint32 lose_cb(afs_vnode *v, XFILE *F, void *refcon)
456 if (verbose) printf("* Extracting files...\n");
464 void main(int argc, char **argv)
469 parse_options(argc, argv);
470 initialize_acfg_error_table();
471 initialize_AVds_error_table();
472 initialize_rxk_error_table();
473 initialize_u_error_table();
474 initialize_vl_error_table();
475 initialize_vols_error_table();
476 initialize_xFil_error_table();
477 r = xfopen(&input_file, O_RDONLY, input_path);
479 com_err(argv0, r, "opening %s", input_path);
483 memset(&dp, 0, sizeof(dp));
484 dp.cb_error = my_error_cb;
485 if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
491 memset(&phi, 0, sizeof(phi));
494 if (verbose) printf("* Building pathname info...\n");
495 if ((r = xftell(&input_file, &where))
496 || (r = Path_PreScan(&input_file, &phi, 1))
497 || (r = xfseek(&input_file, &where))) {
498 com_err(argv0, r, "- path initialization failed");
499 xfclose(&input_file);
504 dp.cb_vnode_dir = directory_cb;
505 dp.cb_vnode_file = file_cb;
506 dp.cb_vnode_link = symlink_cb;
507 dp.cb_vnode_empty = lose_cb;
508 dp.cb_vnode_wierd = lose_cb;
510 dp.cb_dumphdr = dumphdr_cb;
511 dp.cb_volhdr = volhdr_cb;
517 fprintf(stderr, "chdir %s failed: %s\n", target, strerror(errno));
521 r = ParseDumpFile(&input_file, &dp);
523 if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
524 if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));