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>
36 #include <afs/com_err.h>
37 #include <afs/cellconfig.h>
38 #include <afs/vlserver.h>
39 #include <afs/afsint.h>
40 #include <afs/volser.h>
44 #include "dumpscan_errs.h"
47 #define COPYBUFSIZE (256*1024)
53 static char **file_names
;
54 static int *file_vnums
, name_count
, vnum_count
;
56 static char *input_path
, *target
;
57 static int quiet
, verbose
, error_count
, dirs_done
, extract_all
;
58 static int nomode
, use_realpath
, use_vnum
;
59 static int do_acls
, do_headers
;
61 static path_hashinfo phi
;
62 static dump_parser dp
;
64 /* Print a usage message and exit */
66 usage(int status
, char *msg
)
69 fprintf(stderr
, "%s: %s\n", argv0
, msg
);
70 fprintf(stderr
, "Usage: %s [options] dumpfile [dest [files...]]\n",
72 fprintf(stderr
, " -A Save ACL's\n");
73 fprintf(stderr
, " -H Save headers\n");
74 fprintf(stderr
, " -h Print this help message\n");
75 fprintf(stderr
, " -i Use vnode numbers\n");
76 fprintf(stderr
, " -n Don't actually create files\n");
77 fprintf(stderr
, " -p Use real pathnames internally\n");
78 fprintf(stderr
, " -q Quiet mode (don't print errors)\n");
79 fprintf(stderr
, " -v Verbose mode\n");
80 fprintf(stderr
, "The destination directory defaults to .\n");
81 fprintf(stderr
, "Files may be vnode numbers or volume-relative paths;\n");
82 fprintf(stderr
, "If vnode numbers are used, files will be extracted\n");
84 "a name generated from the vnode number and uniqifier.\n");
85 fprintf(stderr
, "If paths are used, -p is implied and files will be\n");
86 fprintf(stderr
, "into correctly-named files.\n");
91 /* Parse the command-line options */
93 parse_options(int argc
, char **argv
)
95 int c
, i
, i_name
, i_vnum
;
97 /* Set the program name */
98 if ((argv0
= strrchr(argv
[0], '/')))
103 /* Initialize options */
105 quiet
= verbose
= nomode
= 0;
106 use_realpath
= use_vnum
= do_acls
= do_headers
= extract_all
= 0;
108 /* Initialize other stuff */
111 /* Parse the options */
112 while ((c
= getopt(argc
, argv
, "AHhinpqv")) != EOF
) {
138 usage(1, "Invalid option!");
142 if (quiet
&& verbose
)
143 usage(1, "Can't specify both -q and -v");
145 /* Parse non-option arguments */
146 if (argc
- optind
< 1)
147 usage(1, "Dumpfile name required!");
148 input_path
= argv
[optind
];
150 if (argc
- optind
< 2)
152 target
= argv
[optind
+ 1];
154 vnum_count
= name_count
= 0;
155 if (argc
- optind
< 3)
160 for (i
= 0; i
< argc
; i
++) {
161 if (argv
[i
][0] == '/')
166 file_names
= malloc(name_count
+ sizeof(char *));
167 file_vnums
= malloc(vnum_count
+ sizeof(afs_uint32
));
172 for (i
= 0; i
< argc
; i
++) {
173 if (argv
[i
][0] == '/')
174 file_names
[i_name
++] = argv
[i
];
176 file_vnums
[i_vnum
++] = strtol(argv
[i
], 0, 0);
185 char *x
= path
, slash
;
189 while (*x
&& *x
!= '/')
194 if (stat(path
, &statbuf
)) {
195 if (errno
== ENOENT
) {
197 printf("> mkdir %s\n", path
);
198 if (!mkdir(path
, 0755))
219 strcpy(str
, "rwxrwxrwx");
220 for (i
= 0; i
< 9; i
++) {
221 if (!(mode
& (1 << i
)))
225 str
[8] = (str
[8] == '-') ? 'T' : 't';
227 str
[5] = (str
[5] == '-') ? 'S' : 's';
229 str
[2] = (str
[2] == '-') ? 'S' : 's';
234 static char *month
[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
235 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
241 time_t clock
= time(0);
242 struct tm
*now
, *then
;
245 now
= localtime(&clock
);
246 then
= localtime(&date
);
248 diff
= now
->tm_mon
- then
->tm_mon
;
249 if (then
->tm_year
== now
->tm_year
- 1)
251 if (then
->tm_year
== now
->tm_year
+ 1)
254 if (diff
< 5 || diff
> 5)
255 sprintf(str
, "%3s %2d %4d", month
[then
->tm_mon
], then
->tm_mday
,
256 then
->tm_year
+ 1900);
258 sprintf(str
, "%3s %2d %2d:%2d", month
[then
->tm_mon
], then
->tm_mday
,
259 then
->tm_hour
, then
->tm_min
);
264 /* Should we use this vnode?
265 * Return 0 if no, non-0 if yes
268 usevnode(XFILE
* X
, afs_uint32 vnum
, char *vnodepath
)
273 if (extract_all
|| !strcmp(vnodepath
, "/"))
276 for (i
= 0; i
< vnum_count
; i
++)
277 if (vnum
== file_vnums
[i
])
280 vl
= strlen(vnodepath
);
281 /*fprintf(stderr, "++ checking %s\n", vnodepath);*/
282 for (i
= 0; i
< name_count
; i
++) {
283 vpl
= strlen(file_names
[i
]);
284 /* fprintf(stderr, " %s\n", file_names[i]);*/
287 r
= !strncmp(file_names
[i
], vnodepath
, vpl
)
288 && vnodepath
[vpl
] == '/';
289 } else if (vl
< vpl
) {
290 r
= !strncmp(file_names
[i
], vnodepath
, vl
)
291 && file_names
[i
][vl
] == '/';
293 r
= !strcmp(file_names
[i
], vnodepath
);
303 copyfile(XFILE
* in
, XFILE
* out
, int size
)
305 static char buf
[COPYBUFSIZE
];
309 nr
= (size
> COPYBUFSIZE
) ? COPYBUFSIZE
: size
;
310 if ((r
= xfread(in
, buf
, nr
)))
312 if ((r
= xfwrite(out
, buf
, nr
)))
320 /* A callback to count and print errors */
322 my_error_cb(afs_uint32 code
, int fatal
, void *ref
, char *msg
, ...)
328 va_start(alist
, msg
);
329 afs_com_err_va(argv0
, code
, msg
, alist
);
337 dumphdr_cb(afs_dump_header
* hdr
, XFILE
* X
, void *refcon
)
344 volhdr_cb(afs_vol_header
* hdr
, XFILE
* X
, void *refcon
)
351 directory_cb(afs_vnode
* v
, XFILE
* X
, void *refcon
)
356 /* Should we even use this? */
358 if ((r
= Path_Build(X
, &phi
, v
->vnode
, &vnodepath
, !use_realpath
)))
360 if (!(use
= usevnode(X
, v
->vnode
, vnodepath
))) {
369 printf("d%s %3d %-11d %11d %s #%d:%d\n", modestr(v
->mode
),
370 v
->nlinks
, v
->owner
, v
->size
, datestr(v
->server_date
),
373 printf("d%s %3d %-11d %11d %s %s\n", modestr(v
->mode
), v
->nlinks
,
374 v
->owner
, v
->size
, datestr(v
->server_date
), vnodepath
);
375 } else if (!quiet
&& !use_vnum
)
376 printf("%s\n", vnodepath
);
378 /* Make the directory, if needed */
379 if (!nomode
&& !use_vnum
&& use
!= 2) {
380 if (strcmp(vnodepath
, "/")
381 && (r
= mkdirp(vnodepath
+ 1))) {
386 /* XXX do ACL's later */
396 file_cb(afs_vnode
* v
, XFILE
* X
, void *refcon
)
398 char *vnodepath
, vnpx
[30];
406 printf("* Extracting files...\n");
409 /* Should we even use this? */
411 if ((r
= Path_Build(X
, &phi
, v
->vnode
, &vnodepath
, !use_realpath
)))
413 if (!(use
= usevnode(X
, v
->vnode
, vnodepath
))) {
419 sprintf(vnpx
, "#%d:%d", v
->vnode
, v
->vuniq
);
423 sprintf(vnpx
, "#%d:%d", v
->vnode
, v
->vuniq
);
429 printf("-%s %3d %-11d %11d %s %s\n", modestr(v
->mode
), v
->nlinks
,
430 v
->owner
, v
->size
, datestr(v
->server_date
), vnodepath
);
432 printf("%s\n", vnodepath
);
436 if ((r
= xftell(X
, &where
))
437 || (r
= xfseek(X
, &v
->d_offset
))
439 xfopen_path(&OX
, O_RDWR
| O_CREAT
| O_TRUNC
, vnodepath
+ 1,
441 if (vnodepath
!= vnpx
)
445 r
= copyfile(X
, &OX
, v
->size
);
451 if (vnodepath
!= vnpx
)
458 symlink_cb(afs_vnode
* v
, XFILE
* X
, void *refcon
)
460 char *vnodepath
, *linktarget
, vnpx
[30];
467 printf("* Extracting files...\n");
470 /* Should we even use this? */
472 if ((r
= Path_Build(X
, &phi
, v
->vnode
, &vnodepath
, !use_realpath
)))
474 if (!(use
= usevnode(X
, v
->vnode
, vnodepath
))) {
480 sprintf(vnpx
, "#%d:%d", v
->vnode
, v
->vuniq
);
484 sprintf(vnpx
, "#%d:%d", v
->vnode
, v
->vuniq
);
488 if (!(linktarget
= malloc(v
->size
+ 1))) {
489 if (vnodepath
!= vnpx
)
493 if ((r
= xftell(X
, &where
))
494 || (r
= xfseek(X
, &v
->d_offset
))
495 || (r
= xfread(X
, linktarget
, v
->size
))) {
496 if (vnodepath
!= vnpx
)
502 linktarget
[v
->size
] = 0;
506 printf("l%s %3d %-11d %11d %s %s -> %s\n", modestr(v
->mode
),
507 v
->nlinks
, v
->owner
, v
->size
, datestr(v
->server_date
),
508 vnodepath
, linktarget
);
510 printf("%s\n", vnodepath
);
514 if (symlink(linktarget
, vnodepath
+ 1))
519 if (vnodepath
!= vnpx
)
526 lose_cb(afs_vnode
* v
, XFILE
* F
, void *refcon
)
531 printf("* Extracting files...\n");
540 main(int argc
, char **argv
)
545 parse_options(argc
, argv
);
546 initialize_acfg_error_table();
547 initialize_AVds_error_table();
548 initialize_rxk_error_table();
549 initialize_u_error_table();
550 initialize_vl_error_table();
551 initialize_vols_error_table();
552 initialize_xFil_error_table();
553 r
= xfopen(&input_file
, O_RDONLY
, input_path
);
555 afs_com_err(argv0
, r
, "opening %s", input_path
);
559 memset(&dp
, 0, sizeof(dp
));
560 dp
.cb_error
= my_error_cb
;
561 if (input_file
.is_seekable
)
562 dp
.flags
|= DSFLAG_SEEK
;
568 memset(&phi
, 0, sizeof(phi
));
572 printf("* Building pathname info...\n");
573 if ((r
= xftell(&input_file
, &where
))
574 || (r
= Path_PreScan(&input_file
, &phi
, 1))
575 || (r
= xfseek(&input_file
, &where
))) {
576 afs_com_err(argv0
, r
, "- path initialization failed");
577 xfclose(&input_file
);
582 dp
.cb_vnode_dir
= directory_cb
;
583 dp
.cb_vnode_file
= file_cb
;
584 dp
.cb_vnode_link
= symlink_cb
;
585 dp
.cb_vnode_empty
= lose_cb
;
586 dp
.cb_vnode_wierd
= lose_cb
;
588 dp
.cb_dumphdr
= dumphdr_cb
;
589 dp
.cb_volhdr
= volhdr_cb
;
595 fprintf(stderr
, "chdir %s failed: %s\n", target
, strerror(errno
));
599 r
= ParseDumpFile(&input_file
, &dp
);
601 if (verbose
&& error_count
)
602 fprintf(stderr
, "*** %d errors\n", error_count
);
604 fprintf(stderr
, "*** FAILED: %s\n", afs_error_message(r
));