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 <afsconfig.h>
32 #include <afs/param.h>
34 #include <sys/fcntl.h>
35 #include <sys/types.h>
41 #include <afs/com_err.h>
42 #include <afs/cellconfig.h>
43 #include <afs/vlserver.h>
44 #include <afs/volser.h>
48 #include "dumpscan_errs.h"
51 #define COPYBUFSIZE (256*1024)
57 static char **file_names;
58 static int *file_vnums, name_count, vnum_count;
60 static char *input_path, *target;
61 static int quiet, verbose, error_count, dirs_done, extract_all;
62 static int nomode, use_realpath, use_vnum;
63 static int do_acls, do_headers;
65 static path_hashinfo phi;
66 static dump_parser dp;
68 /* Print a usage message and exit */
70 usage(int status, char *msg)
73 fprintf(stderr, "%s: %s\n", argv0, msg);
74 fprintf(stderr, "Usage: %s [options] dumpfile [dest [files...]]\n",
76 fprintf(stderr, " -A Save ACL's\n");
77 fprintf(stderr, " -H Save headers\n");
78 fprintf(stderr, " -h Print this help message\n");
79 fprintf(stderr, " -i Use vnode numbers\n");
80 fprintf(stderr, " -n Don't actually create files\n");
81 fprintf(stderr, " -p Use real pathnames internally\n");
82 fprintf(stderr, " -q Quiet mode (don't print errors)\n");
83 fprintf(stderr, " -v Verbose mode\n");
84 fprintf(stderr, "The destination directory defaults to .\n");
85 fprintf(stderr, "Files may be vnode numbers or volume-relative paths;\n");
86 fprintf(stderr, "If vnode numbers are used, files will be extracted\n");
88 "a name generated from the vnode number and uniqifier.\n");
89 fprintf(stderr, "If paths are used, -p is implied and files will be\n");
90 fprintf(stderr, "into correctly-named files.\n");
95 /* Parse the command-line options */
97 parse_options(int argc, char **argv)
99 int c, i, i_name, i_vnum;
101 /* Set the program name */
102 if ((argv0 = strrchr(argv[0], '/')))
107 /* Initialize options */
109 quiet = verbose = nomode = 0;
110 use_realpath = use_vnum = do_acls = do_headers = extract_all = 0;
112 /* Initialize other stuff */
115 /* Parse the options */
116 while ((c = getopt(argc, argv, "AHhinpqv")) != EOF) {
142 usage(1, "Invalid option!");
146 if (quiet && verbose)
147 usage(1, "Can't specify both -q and -v");
149 /* Parse non-option arguments */
150 if (argc - optind < 1)
151 usage(1, "Dumpfile name required!");
152 input_path = argv[optind];
154 if (argc - optind < 2)
156 target = argv[optind + 1];
158 vnum_count = name_count = 0;
159 if (argc - optind < 3)
164 for (i = 0; i < argc; i++) {
165 if (argv[i][0] == '/')
170 file_names = (char **)malloc(name_count + sizeof(char *));
171 file_vnums = (afs_int32 *) malloc(vnum_count + sizeof(afs_uint32));
176 for (i = 0; i < argc; i++) {
177 if (argv[i][0] == '/')
178 file_names[i_name++] = argv[i];
180 file_vnums[i_vnum++] = strtol(argv[i], 0, 0);
189 char *x = path, slash;
193 while (*x && *x != '/')
198 if (stat(path, &statbuf)) {
199 if (errno == ENOENT) {
201 printf("> mkdir %s\n", path);
202 if (!mkdir(path, 0755))
223 strcpy(str, "rwxrwxrwx");
224 for (i = 0; i < 9; i++) {
225 if (!(mode & (1 << i)))
229 str[8] = (str[8] == '-') ? 'T' : 't';
231 str[5] = (str[5] == '-') ? 'S' : 's';
233 str[2] = (str[2] == '-') ? 'S' : 's';
238 static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
239 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
245 time_t clock = time(0);
246 struct tm *now, *then;
249 now = localtime(&clock);
250 then = localtime(&date);
252 diff = now->tm_mon - then->tm_mon;
253 if (then->tm_year == now->tm_year - 1)
255 if (then->tm_year == now->tm_year + 1)
258 if (diff < 5 || diff > 5)
259 sprintf(str, "%3s %2d %4d", month[then->tm_mon], then->tm_mday,
260 then->tm_year + 1900);
262 sprintf(str, "%3s %2d %2d:%2d", month[then->tm_mon], then->tm_mday,
263 then->tm_hour, then->tm_min);
268 /* Should we use this vnode?
269 * Return 0 if no, non-0 if yes
272 usevnode(XFILE * X, afs_uint32 vnum, char *vnodepath)
277 if (extract_all || !strcmp(vnodepath, "/"))
280 for (i = 0; i < vnum_count; i++)
281 if (vnum == file_vnums[i])
284 vl = strlen(vnodepath);
285 /*fprintf(stderr, "++ checking %s\n", vnodepath);*/
286 for (i = 0; i < name_count; i++) {
287 vpl = strlen(file_names[i]);
288 /* fprintf(stderr, " %s\n", file_names[i]);*/
291 r = !strncmp(file_names[i], vnodepath, vpl)
292 && vnodepath[vpl] == '/';
293 } else if (vl < vpl) {
294 r = !strncmp(file_names[i], vnodepath, vl)
295 && file_names[i][vl] == '/';
297 r = !strcmp(file_names[i], vnodepath);
307 copyfile(XFILE * in, XFILE * out, int size)
309 static char buf[COPYBUFSIZE];
313 nr = (size > COPYBUFSIZE) ? COPYBUFSIZE : size;
314 if ((r = xfread(in, buf, nr)))
316 if ((r = xfwrite(out, buf, nr)))
324 /* A callback to count and print errors */
326 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
332 va_start(alist, msg);
333 afs_com_err_va(argv0, code, msg, alist);
341 dumphdr_cb(afs_dump_header * hdr, XFILE * X, void *refcon)
348 volhdr_cb(afs_vol_header * hdr, XFILE * X, void *refcon)
355 directory_cb(afs_vnode * v, XFILE * X, void *refcon)
360 /* Should we even use this? */
362 if ((r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath)))
364 if (!(use = usevnode(X, v->vnode, vnodepath))) {
373 printf("d%s %3d %-11d %11d %s #%d:%d\n", modestr(v->mode),
374 v->nlinks, v->owner, v->size, datestr(v->server_date),
377 printf("d%s %3d %-11d %11d %s %s\n", modestr(v->mode), v->nlinks,
378 v->owner, v->size, datestr(v->server_date), vnodepath);
379 } else if (!quiet && !use_vnum)
380 printf("%s\n", vnodepath);
382 /* Make the directory, if needed */
383 if (!nomode && !use_vnum && use != 2) {
384 if (strcmp(vnodepath, "/")
385 && (r = mkdirp(vnodepath + 1))) {
390 /* XXX do ACL's later */
400 file_cb(afs_vnode * v, XFILE * X, void *refcon)
402 char *vnodepath, vnpx[30];
410 printf("* Extracting files...\n");
413 /* Should we even use this? */
415 if ((r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath)))
417 if (!(use = usevnode(X, v->vnode, vnodepath))) {
423 sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
427 sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
433 printf("-%s %3d %-11d %11d %s %s\n", modestr(v->mode), v->nlinks,
434 v->owner, v->size, datestr(v->server_date), vnodepath);
436 printf("%s\n", vnodepath);
440 if ((r = xftell(X, &where))
441 || (r = xfseek(X, &v->d_offset))
443 xfopen_path(&OX, O_RDWR | O_CREAT | O_TRUNC, vnodepath + 1,
449 r = copyfile(X, &OX, v->size);
455 if (!use_vnum && use != 2)
462 symlink_cb(afs_vnode * v, XFILE * X, void *refcon)
464 char *vnodepath, *linktarget, vnpx[30];
471 printf("* Extracting files...\n");
474 /* Should we even use this? */
476 if ((r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath)))
478 if (!(use = usevnode(X, v->vnode, vnodepath))) {
484 sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
488 sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
492 if (!(linktarget = (char *)malloc(v->size + 1))) {
493 if (!use_vnum && use != 2)
497 if ((r = xftell(X, &where))
498 || (r = xfseek(X, &v->d_offset))
499 || (r = xfread(X, linktarget, v->size))) {
500 if (!use_vnum && use != 2)
506 linktarget[v->size] = 0;
510 printf("l%s %3d %-11d %11d %s %s -> %s\n", modestr(v->mode),
511 v->nlinks, v->owner, v->size, datestr(v->server_date),
512 vnodepath, linktarget);
514 printf("%s\n", vnodepath);
518 if (symlink(linktarget, vnodepath + 1))
523 if (!use_vnum && use != 2)
530 lose_cb(afs_vnode * v, XFILE * F, void *refcon)
535 printf("* Extracting files...\n");
544 main(int argc, char **argv)
549 parse_options(argc, argv);
550 initialize_acfg_error_table();
551 initialize_AVds_error_table();
552 initialize_rxk_error_table();
553 initialize_u_error_table();
554 initialize_vl_error_table();
555 initialize_vols_error_table();
556 initialize_xFil_error_table();
557 r = xfopen(&input_file, O_RDONLY, input_path);
559 afs_com_err(argv0, r, "opening %s", input_path);
563 memset(&dp, 0, sizeof(dp));
564 dp.cb_error = my_error_cb;
565 if (input_file.is_seekable)
566 dp.flags |= DSFLAG_SEEK;
572 memset(&phi, 0, sizeof(phi));
576 printf("* Building pathname info...\n");
577 if ((r = xftell(&input_file, &where))
578 || (r = Path_PreScan(&input_file, &phi, 1))
579 || (r = xfseek(&input_file, &where))) {
580 afs_com_err(argv0, r, "- path initialization failed");
581 xfclose(&input_file);
586 dp.cb_vnode_dir = directory_cb;
587 dp.cb_vnode_file = file_cb;
588 dp.cb_vnode_link = symlink_cb;
589 dp.cb_vnode_empty = lose_cb;
590 dp.cb_vnode_wierd = lose_cb;
592 dp.cb_dumphdr = dumphdr_cb;
593 dp.cb_volhdr = volhdr_cb;
599 fprintf(stderr, "chdir %s failed: %s\n", target, strerror(errno));
603 r = ParseDumpFile(&input_file, &dp);
605 if (verbose && error_count)
606 fprintf(stderr, "*** %d errors\n", error_count);
608 fprintf(stderr, "*** FAILED: %s\n", afs_error_message(r));