test-suite-pull-tools-directly-in-20020114

move dump tools directly into test suite as that is their intended use

canonical versions of these tools will be distributed otherwise
and may be updated but these provide the minimum functionality
This commit is contained in:
Derrick Brashear 2002-01-15 04:14:51 +00:00
parent f1964d2cf8
commit fcb32c07ed
37 changed files with 10003 additions and 12 deletions

View File

@ -215,9 +215,6 @@ tviced: project viced vlserver libafsrpc libafsauthent
volser: project tviced usd kauth audit
${COMPILE_PART1} volser ${COMPILE_PART2}
tools: volser
${COMPILE_PART1} tools ${COMPILE_PART2}
venus: project volser ptserver
${COMPILE_PART1} venus ${COMPILE_PART2}
${COMPILE_PART1} venus/test ${COMPILE_PART2}
@ -439,13 +436,13 @@ libadmin: libafsauthent bozo
finale: project cmd comerr afsd allrcmds butc tbutc @ENABLE_KERNEL_MODULE@ libuafs audit kauth log package \
ptserver scout bu_utils ubik uss bozo vfsck volser \
venus update xstat afsmonitor dauth tools rxdebug libafsrpc \
venus update xstat afsmonitor dauth rxdebug libafsrpc \
libafsauthent libadmin
${COMPILE_PART1} finale ${COMPILE_PART2}
finale_nolibafs: project cmd comerr afsd allrcmds butc tbutc libuafs audit kauth log package \
ptserver scout bu_utils ubik uss bozo vfsck volser \
venus update xstat afsmonitor dauth tools rxdebug libafsrpc \
venus update xstat afsmonitor dauth rxdebug libafsrpc \
libafsauthent libadmin
${COMPILE_PART1} finale ${COMPILE_PART2}
@ -536,7 +533,7 @@ clean2:
-${COMPILE_PART1} bucoord ${COMPILE_CLEAN}
-${COMPILE_PART1} xstat ${COMPILE_CLEAN}
-${COMPILE_PART1} afsmonitor ${COMPILE_CLEAN}
-${COMPILE_PART1} tools ${COMPILE_CLEAN}
-${COMPILE_PART1} tests ${COMPILE_CLEAN}
-${COMPILE_PART1} rxdebug ${COMPILE_CLEAN}
-${COMPILE_PART1} libafsrpc ${COMPILE_CLEAN}
-${COMPILE_PART1} libafsauthent ${COMPILE_CLEAN}
@ -665,7 +662,8 @@ distclean: clean
src/sia/Makefile \
src/sys/Makefile \
src/tbutc/Makefile \
src/tools/Makefile \
src/tests/Makefile \
src/tests/Dirpath.pm \
src/tsm41/Makefile \
src/tviced/Makefile \
src/ubik/Makefile \

View File

@ -107,7 +107,6 @@ src/sys/Makefile \
src/tbutc/Makefile \
src/tests/Makefile \
src/tests/Dirpath.pm \
src/tools/Makefile \
src/tsm41/Makefile \
src/tviced/Makefile \
src/ubik/Makefile \

View File

@ -6,6 +6,105 @@ SHELL = /bin/sh
CFLAGS = -I. -I${srcdir} ${DBG} ${OPTMZ} -I${TOP_OBJDIR}/src/config -I${TOP_INCDIR} ${XCFLAGS}
LDFLAGS=${DBG} ${OPTMZ} ${XLDFLAGS}
INCDIRS=-I${TOP_OBJDIR}/src/config -I${TOP_INCDIR}/afs -I${TOP_INCDIR}
INCLIBS=-L${SRCDIR}/lib/afs -L${TOP_LIBDIR}
LIBS=\
${TOP_LIBDIR}/libdumpscan.a \
${TOP_LIBDIR}/libxfiles.a \
${TOP_LIBDIR}/libauth.a \
${TOP_LIBDIR}/libaudit.a \
${TOP_LIBDIR}/libvolser.a \
${TOP_LIBDIR}/libvldb.a \
${TOP_LIBDIR}/libubik.a \
${TOP_LIBDIR}/librxkad.a \
${TOP_LIBDIR}/libsys.a \
${TOP_LIBDIR}/librx.a \
${TOP_LIBDIR}/liblwp.a \
${TOP_LIBDIR}/util.a \
${TOP_LIBDIR}/libcom_err.a \
${XLIBS}
OBJS_afsdump_scan = afsdump_scan.o repair.o
OBJS_afsdump_xsed = afsdump_xsed.o repair.o
OBJS_libxfiles.a = xfiles.o xf_errs.o xf_printf.o int64.o \
xf_files.o xf_rxcall.o xf_profile.o
OBJS_libdumpscan.a = primitive.o util.o dumpscan_errs.o parsetag.o \
parsedump.o parsevol.o parsevnode.o dump.o \
directory.o pathname.o backuphdr.o stagehdr.o
TARGETS = libxfiles.a libdumpscan.a \
afsdump_scan afsdump_dirlist afsdump_extract dumptool
afsdump_scan: libxfiles.a libdumpscan.a $(OBJS_afsdump_scan)
$(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_scan $(OBJS_afsdump_scan) $(LIBS)
afsdump_xsed: libxfiles.a libdumpscan.a $(OBJS_afsdump_xsed)
$(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_xsed $(OBJS_afsdump_xsed) $(LIBS)
afsdump_dirlist: libxfiles.a libdumpscan.a afsdump_dirlist.o
$(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_dirlist afsdump_dirlist.o $(LIBS)
afsdump_extract: libxfiles.a libdumpscan.a afsdump_extract.o
$(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_extract afsdump_extract.o $(LIBS)
null-search: libxfiles.a libdumpscan.a null-search.c
$(CC) $(CFLAGS) $(LDFLAGS) -o null-search null-search.c $(LIBS)
dumptool: dumptool.c
$(CC) $(CFLAGS) $(LDFLAGS) -o dumptool dumptool.c
libxfiles.a: $(OBJS_libxfiles.a)
-rm -f libxfiles.a
$(AR) r libxfiles.a $(OBJS_libxfiles.a)
$(RANLIB) libxfiles.a
libdumpscan.a: $(OBJS_libdumpscan.a)
-rm -f libdumpscan.a
$(AR) r libdumpscan.a $(OBJS_libdumpscan.a)
$(RANLIB) libdumpscan.a
xf_errs.c xf_errs.h: xf_errs.et
$(COMPILE_ET) xf_errs.et
dumpscan_errs.c dumpscan_errs.h: dumpscan_errs.et
$(COMPILE_ET) dumpscan_errs.et
util.o xfiles.o xf_files.o: xf_errs.h
backuphdr.o directory.o parsedump.o parsetag.o: dumpscan_errs.h
parsevnode.o parsevol.o pathname.o repair.o: dumpscan_errs.h
stagehdr.o util.o: dumpscan_errs.h
${DEST}/etc/afsdump_scan: afsdump_scan
${INSTALL} $? $@
${DEST}/etc/afsdump_dirlist: afsdump_dirlist
${INSTALL} $? $@
${DEST}/etc/afsdump_extract: afsdump_extract
${INSTALL} $? $@
${DEST}/etc/dumptool: dumptool
${INSTALL} $? $@
${DESTDIR}${sbindir}/afsdump_scan: afsdump_scan
${INSTALL} $? $@
${DESTDIR}${sbindir}/afsdump_dirlist: afsdump_dirlist
${INSTALL} $? $@
${DESTDIR}${sbindir}/afsdump_extract: afsdump_extract
${INSTALL} $? $@
${DESTDIR}${sbindir}/dumptool: dumptool
${INSTALL} $? $@
${TOP_LIBDIR}/libxfiles.a: libxfiles.a
${INSTALL} $? $@
${TOP_LIBDIR}/libdumpscan.a: libdumpscan.a
${INSTALL} $? $@
SYS_LIBS = ${TOP_LIBDIR}/libsys.a ${TOP_LIBDIR}/librx.a ${TOP_LIBDIR}/liblwp.a ${TOP_LIBDIR}/util.a
AUTH_LIBS = ${TOP_LIBDIR}/libauth.a ${SYS_LIBS}
@ -65,8 +164,6 @@ TEST_SRCS = write-ro-file.c read-vs-mmap.c read-vs-mmap2.c \
EXTRA_OBJS = err.o errx.o warn.o warnx.o
all: run-tests $(TEST_PROGRAMS) OS.pm
OS.pm: OS-$(MKAFS_OSTYPE).pm
$(CP) OS-$(MKAFS_OSTYPE).pm OS.pm
@ -256,13 +353,21 @@ mountpoint: mountpoint.in
sed -e "s!%bindir%!$(bindir)!" $(srcdir)/mountpoint.in > $@
chmod +x mountpoint
clean:
rm -f run-tests $(TEST_PROGRAMS) *.o *~ OS.pm
dest:
install:
uninstall:
all: run-tests $(TEST_PROGRAMS) OS.pm ${TOP_LIBDIR}/libxfiles.a \
${TOP_LIBDIR}/libdumpscan.a \
afsdump_scan afsdump_dirlist afsdump_extract dumptool
clean:
-rm xf_errs.c xf_errs.h dumpscan_errs.c dumpscan_errs.h *.o \
$(TARGETS) run-tests $(TEST_PROGRAMS) OS.pm
include ../config/Makefile.version
TAGS: $(TEST_SRCS)
etags $(TEST_SRCS)

152
src/tests/README.dumptool Normal file
View File

@ -0,0 +1,152 @@
$Id$
This is the README for dumptool, a program to interactively restore
AFS volume dump files.
INTRODUCTION
Dumptool arose out of a need here at NRL to perform maintenance of
MR-AFS (Multi-Resident AFS) volumes. After it was written, we found
that it worked great on standard AFS volumes as well, and relatively
few changes were required to make it compile with a standard AFS
installation.
Dumptool provides an interface similar to the interactive Unix restore;
given a dump file, a user can navigate through the filesystem inside
the dump using familiar commands such as "cd" and "ls". Also provided
is a "cp" command to copy individual files out of the dump into a
normal filesystem space. This eliminates the need to restore an
entire volume just to retrieve a single file.
Dumptool was written at the Naval Research Laboratory by Ken Hornstein
<kenh@cmf.nrl.navy.mil>. The latest and greatest version of dumptool
can always be found in the AFS contrib directory at:
/afs/transarc.com/public/afs-contrib/dumptool/
INSTALLATION & OPERATION
The standard Makefile target will build a dumptool for a vanilla AFS
installation. The "mrafs" target will build a dumptool that can
operate on MR-AFS dumps. In either case, you may need to change some
of the Makefile variables to reflect your site; see the Makefile for
more information.
Once dumptool is built successfully, you can run it on any AFS dump
file. Without any additional arguments, dumptool will scan the dump file,
build indexes of all listed vnodes, and present a prompt (">") that
accepts the following commands:
ls Lists files in the current directory. Filename globbing
(e.g., wildcards such as * ?) are supported via the system
fnmatch() function. Accepts the following flags:
-l Generates a "long" listing, similar to the -l switch for
the Unix ls. Displays Unix mode mask, owner, group,
and file size.
-i Displays volume, vnode, and uniquifier for each matching
file in the format volume.vnode.uniquifier. Note that
the volume displayed is that of the _parent_ volume,
which in the case of a backup volume is the _original_
volume from which it was generated.
-F Append / to filenames for directories, @ for symlinks,
and * for files which have the execute bits set.
-R Recurse through all subdirectories.
cd Change the current directory
cp Copy a file from the dump. Note that globbing is NOT
supported, and you must give a filename (the Unix
idiom of just giving a destination directory for the
second argument to cp will NOT work).
vcp Copy a file from the dump, by the vnode. The first
argument is the vnode number, optionally followed by
the uniqifier. E.g:
vcp 126278 /tmp/file1
vcp 126278.43289 /tmp/file2
quit Exits dumptool.
exit
ADDITIONAL OPTIONS TO DUMPTOOL
Dumptool supports a number of command-line options. They are detailed
below:
-v Verbose mode. Output additional information during dump
processing. Each -v will increate output.
-f Force dump processing. Attempt to continue processing
a dump even when some errors are detected. Not completely
tested.
-i Inode dump. Dump a list of all files in the volume,
with their volume/vnode/uniqifier information.
SUPPORT FOR MR-AFS
Dumptool also supports the extra information in MR-AFS dumps, and
provides some extra commands/options for dealing with MR-AFS dumps:
Additional command line options:
-d Dump all residency filenames in the dump file to standard
output.
-t Residency tag information. Allows a user to specify the
tag of a residency if the rsserver is not available.
Format of option is Residency/Tag
-r Residency filesystem information. Allows a user to specify
the residency filesystem information if dumptool is not
run on the same host as the residency in the dump. Format
of option is Residency/Type/Size/Algorithm.
Additional commands:
file Displays to standard output the residency filename of a
given dump filename. All residencies available are shown.
CAVEATS
The user interface needs some work. "ls" doesn't support nearly as many
options as the standard Unix one. "cp" also doesn't have all of the features
found in common Unix variants.
Right now two passes are done through the dump file to scan all vnodes.
With some clever work this could be sped up somewhat and changed to only
do a single scan.
MODIFYING DUMPTOOL
I welcome changes to dumptool, but I have some guidelines.
First, I DEMAND that the changes be sent in context diff format. I prefer
unidiff (diff -u), but standard context diffs are okay. It's extremely
difficult to deal with new code in any other way.
If the changes you want to do require some significant
rearchitecturing, it might be a good idea to contact me first. That
way we can coordinate the modifications in a meaningful way (I might
have made changes since the last released version).
If you're making MR-AFS specific changes, please follow the example
I've set and protect them with #ifdef RESIDENCY.
And please ... follow my code style, okay? I always try to follow
whatever wacky code style I find in source code that I modify, and I
think it's only polite for you to do the same.
CONTACT INFORMATION
As always, please send comments, suggestions, or new features to me,
Ken Hornstein <kenh@cmf.nrl.navy.mil>. Shar and enjoy.

27
src/tests/TEMPLATE Normal file
View File

@ -0,0 +1,27 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/

140
src/tests/afsdump_dirlist.c Normal file
View File

@ -0,0 +1,140 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* afsdump_dirlist.c - List an AFS directory file */
#include <sys/fcntl.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "dumpscan.h"
extern int optind;
extern char *optarg;
char *argv0;
static char *input_path;
static int quiet, verbose, error_count;
static path_hashinfo phi;
static dump_parser dp;
/* Print a usage message and exit */
static void usage(int status, char *msg)
{
if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
fprintf(stderr, " -h Print this help message\n");
fprintf(stderr, " -q Quiet mode (don't print errors)\n");
fprintf(stderr, " -v Verbose mode\n");
exit(status);
}
/* Parse the command-line options */
static void parse_options(int argc, char **argv)
{
int c;
/* Set the program name */
if (argv0 = strrchr(argv[0], '/')) argv0++;
else argv0 = argv[0];
/* Initialize options */
input_path = 0;
quiet = verbose = 0;
/* Initialize other stuff */
error_count = 0;
/* Parse the options */
while ((c = getopt(argc, argv, "hqv")) != EOF) {
switch (c) {
case 'q': quiet = 1; continue;
case 'v': verbose = 1; continue;
case 'h': usage(0, 0);
default: usage(1, "Invalid option!");
}
}
if (quiet && verbose) usage(1, "Can't specify both -q and -v");
/* Parse non-option arguments */
if (argc - optind > 1) usage(1, "Too many arguments!");
input_path = (argc == optind) ? "-" : argv[optind];
}
/* A callback to count and print errors */
static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
{
va_list alist;
error_count++;
if (!quiet) {
va_start(alist, msg);
com_err_va(argv0, code, msg, alist);
va_end(alist);
}
}
/* Main program */
void main(int argc, char **argv)
{
XFILE input_file;
afs_uint32 r;
parse_options(argc, argv);
initialize_acfg_error_table();
initialize_AVds_error_table();
initialize_rxk_error_table();
initialize_u_error_table();
initialize_vl_error_table();
initialize_vols_error_table();
initialize_xFil_error_table();
r = xfopen(&input_file, O_RDONLY, input_path);
if (r) {
com_err(argv0, r, "opening %s", input_path);
exit(2);
}
memset(&dp, 0, sizeof(dp));
dp.cb_error = my_error_cb;
dp.print_flags = DSPRINT_DIR;
if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
r = ParseDirectory(&input_file, &dp, 0, 1);
xfclose(&input_file);
if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
exit(0);
}

526
src/tests/afsdump_extract.c Normal file
View File

@ -0,0 +1,526 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* afsdump_extract.c - Extract files from an AFS dump */
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "dumpscan.h"
#include "dumpscan_errs.h"
#define COPYBUFSIZE (256*1024)
extern int optind;
extern char *optarg;
char *argv0;
static char **file_names;
static int *file_vnums, name_count, vnum_count;
static char *input_path, *target;
static int quiet, verbose, error_count, dirs_done, extract_all;
static int nomode, use_realpath, use_vnum;
static int do_acls, do_headers;
static path_hashinfo phi;
static dump_parser dp;
/* Print a usage message and exit */
static void usage(int status, char *msg)
{
if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
fprintf(stderr, "Usage: %s [options] dumpfile [dest [files...]]\n", argv0);
fprintf(stderr, " -A Save ACL's\n");
fprintf(stderr, " -H Save headers\n");
fprintf(stderr, " -h Print this help message\n");
fprintf(stderr, " -i Use vnode numbers\n");
fprintf(stderr, " -n Don't actually create files\n");
fprintf(stderr, " -p Use real pathnames internally\n");
fprintf(stderr, " -q Quiet mode (don't print errors)\n");
fprintf(stderr, " -v Verbose mode\n");
fprintf(stderr, "The destination directory defaults to .\n");
fprintf(stderr, "Files may be vnode numbers or volume-relative paths;\n");
fprintf(stderr, "If vnode numbers are used, files will be extracted\n");
fprintf(stderr, "a name generated from the vnode number and uniqifier.\n");
fprintf(stderr, "If paths are used, -p is implied and files will be\n");
fprintf(stderr, "into correctly-named files.\n");
exit(status);
}
/* Parse the command-line options */
static void parse_options(int argc, char **argv)
{
int c, i, i_name, i_vnum;
/* Set the program name */
if (argv0 = strrchr(argv[0], '/')) argv0++;
else argv0 = argv[0];
/* Initialize options */
input_path = 0;
quiet = verbose = nomode = 0;
use_realpath = use_vnum = do_acls = do_headers = extract_all = 0;
/* Initialize other stuff */
error_count = 0;
/* Parse the options */
while ((c = getopt(argc, argv, "AHhinpqv")) != EOF) {
switch (c) {
case 'A': do_acls = 1; continue;
case 'H': do_headers = 1; continue;
case 'i': use_vnum = 1; continue;
case 'n': nomode = 1; continue;
case 'p': use_realpath = 1; continue;
case 'q': quiet = 1; continue;
case 'v': verbose = 1; continue;
case 'h': usage(0, 0);
default: usage(1, "Invalid option!");
}
}
if (quiet && verbose) usage(1, "Can't specify both -q and -v");
/* Parse non-option arguments */
if (argc - optind < 1) usage(1, "Dumpfile name required!");
input_path = argv[optind];
if (argc - optind < 2) target = ".";
target = argv[optind + 1];
vnum_count = name_count = 0;
if (argc - optind < 3) extract_all = 1;
else {
argv += optind + 2;
argc -= optind + 2;
for (i = 0; i < argc; i++) {
if (argv[i][0] == '/') name_count++;
else vnum_count++;
}
file_names = (char **)malloc(name_count + sizeof(char *));
file_vnums = (afs_uint32 *)malloc(vnum_count + sizeof(afs_uint32));
if (name_count) use_realpath = 1;
i_name = i_vnum = 0;
for (i = 0; i < argc; i++) {
if (argv[i][0] == '/') file_names[i_name++] = argv[i];
else file_vnums[i_vnum++] = strtol(argv[i], 0, 0);
}
}
}
static int mkdirp(char *path)
{
char *x = path, slash;
struct stat statbuf;
for (;;) {
while (*x && *x != '/') x++;
slash = *x;
*x = 0;
if (stat(path, &statbuf)) {
if (errno == ENOENT) {
if (verbose) printf("> mkdir %s\n", path);
if (!mkdir(path, 0755)) errno = 0;
}
}
if (!slash) break;
*x++ = '/';
if (errno) return errno;
}
return 0;
}
static char *modestr(int mode)
{
static char str[10];
int i;
strcpy(str, "rwxrwxrwx");
for (i = 0; i < 9; i++) {
if (!(mode & (1 << i)))
str[8 - i] = '-';
}
if (mode & 01000) str[8] = (str[8] == '-') ? 'T' : 't';
if (mode & 02000) str[5] = (str[5] == '-') ? 'S' : 's';
if (mode & 04000) str[2] = (str[2] == '-') ? 'S' : 's';
return str;
}
static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static char *datestr(time_t date)
{
static char str[13];
time_t clock = time(0);
struct tm *now, *then;
int diff;
now = localtime(&clock);
then = localtime(&date);
diff = now->tm_mon - then->tm_mon;
if (then->tm_year == now->tm_year - 1) diff += 12;
if (then->tm_year == now->tm_year + 1) diff -= 12;
if (diff < 5 || diff > 5)
sprintf(str, "%3s %2d %4d", month[then->tm_mon], then->tm_mday,
then->tm_year + 1900);
else
sprintf(str, "%3s %2d %2d:%2d", month[then->tm_mon], then->tm_mday,
then->tm_hour, then->tm_min);
return str;
}
/* Should we use this vnode?
* Return 0 if no, non-0 if yes
*/
static int usevnode(XFILE *X, afs_uint32 vnum, char *vnodepath)
{
int vl, vpl, r, i;
/* Special case */
if (extract_all || !strcmp(vnodepath, "/"))
return 1;
for (i = 0; i < vnum_count; i++)
if (vnum == file_vnums[i]) return 2;
vl = strlen(vnodepath);
/*fprintf(stderr, "++ checking %s\n", vnodepath);*/
for (i = 0; i < name_count; i++) {
vpl = strlen(file_names[i]);
/* fprintf(stderr, " %s\n", file_names[i]);*/
if (vl > vpl) {
r = !strncmp(file_names[i], vnodepath, vpl) && vnodepath[vpl] == '/';
} else if (vl < vpl) {
r = !strncmp(file_names[i], vnodepath, vl) && file_names[i][vl] == '/';
} else {
r = !strcmp(file_names[i], vnodepath);
}
if (r) return 1;
}
return 0;
}
static int copyfile(XFILE *in, XFILE *out, int size)
{
static char buf[COPYBUFSIZE];
int nr, nw, r;
while (size) {
nr = (size > COPYBUFSIZE) ? COPYBUFSIZE : size;
if (r = xfread(in, buf, nr)) return r;
if (r = xfwrite(out, buf, nr)) return r;
size -= nr;
}
return 0;
}
/* A callback to count and print errors */
static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
{
va_list alist;
error_count++;
if (!quiet) {
va_start(alist, msg);
com_err_va(argv0, code, msg, alist);
va_end(alist);
}
}
static afs_uint32 dumphdr_cb(afs_dump_header *hdr, XFILE *X, void *refcon)
{
return 0;
}
static afs_uint32 volhdr_cb(afs_vol_header *hdr, XFILE *X, void *refcon)
{
return 0;
}
static afs_uint32 directory_cb(afs_vnode *v, XFILE *X, void *refcon)
{
char *vnodepath;
int r, use;
/* Should we even use this? */
if (!use_vnum) {
if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
return r;
if (!(use = usevnode(X, v->vnode, vnodepath))) {
free(vnodepath);
return 0;
}
}
/* Print it out */
if (verbose) {
if (use_vnum)
printf("d%s %3d %-11d %11d %s #%d:%d\n",
modestr(v->mode), v->nlinks, v->owner, v->size,
datestr(v->server_date), v->vnode, v->vuniq);
else
printf("d%s %3d %-11d %11d %s %s\n",
modestr(v->mode), v->nlinks, v->owner, v->size,
datestr(v->server_date), vnodepath);
}
else if (!quiet && !use_vnum)
printf("%s\n", vnodepath);
/* Make the directory, if needed */
if (!nomode && !use_vnum && use != 2) {
if (strcmp(vnodepath, "/")
&& (r = mkdirp(vnodepath + 1))) {
free(vnodepath);
return r;
}
if (do_acls) {
/* XXX do ACL's later */
}
}
if (!use_vnum) free(vnodepath);
return 0;
}
static afs_uint32 file_cb(afs_vnode *v, XFILE *X, void *refcon)
{
char *vnodepath, vnpx[30];
u_int64 where;
XFILE OX;
int r, use;
if (!dirs_done) {
dirs_done = 1;
if (verbose) printf("* Extracting files...\n");
}
/* Should we even use this? */
if (!use_vnum) {
if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
return r;
if (!(use = usevnode(X, v->vnode, vnodepath))) {
free(vnodepath);
return 0;
}
if (use == 2) {
free(vnodepath);
sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
vnodepath = vnpx;
}
} else {
sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
vnodepath = vnpx;
}
/* Print it out */
if (verbose) {
printf("-%s %3d %-11d %11d %s %s\n",
modestr(v->mode), v->nlinks, v->owner, v->size,
datestr(v->server_date), vnodepath);
} else if (!quiet) {
printf("%s\n", vnodepath);
}
if (!nomode) {
if ((r = xftell(X, &where))
|| (r = xfseek(X, &v->d_offset))
|| (r = xfopen_path(&OX, O_RDWR|O_CREAT|O_TRUNC, vnodepath + 1, 0644))) {
if (!use_vnum) free(vnodepath);
return r;
}
r = copyfile(X, &OX, v->size);
xfclose(&OX);
xfseek(X, &where);
} else r = 0;
if (!use_vnum && use != 2) free(vnodepath);
return r;
}
static afs_uint32 symlink_cb(afs_vnode *v, XFILE *X, void *refcon)
{
char *vnodepath, *linktarget, vnpx[30];
u_int64 where;
int r, use;
if (!dirs_done) {
dirs_done = 1;
if (verbose) printf("* Extracting files...\n");
}
/* Should we even use this? */
if (!use_vnum) {
if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
return r;
if (!(use = usevnode(X, v->vnode, vnodepath))) {
free(vnodepath);
return 0;
}
if (use == 2) {
free(vnodepath);
sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
vnodepath = vnpx;
}
} else {
sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
vnodepath = vnpx;
}
if (!(linktarget = (char *)malloc(v->size + 1))) {
if (!use_vnum && use != 2) free(vnodepath);
return DSERR_MEM;
}
if ((r = xftell(X, &where))
|| (r = xfseek(X, &v->d_offset))
|| (r = xfread(X, linktarget, v->size))) {
if (!use_vnum && use != 2) free(vnodepath);
free(linktarget);
return r;
}
xfseek(X, &where);
linktarget[v->size] = 0;
/* Print it out */
if (verbose)
printf("l%s %3d %-11d %11d %s %s -> %s\n",
modestr(v->mode), v->nlinks, v->owner, v->size,
datestr(v->server_date), vnodepath, linktarget);
else if (!quiet)
printf("%s\n", vnodepath);
r = 0;
if (!nomode) {
if (symlink(linktarget, vnodepath + 1))
r = errno;
}
free(linktarget);
if (!use_vnum && use != 2) free(vnodepath);
return r;
}
static afs_uint32 lose_cb(afs_vnode *v, XFILE *F, void *refcon)
{
int r;
if (!dirs_done) {
dirs_done = 1;
if (verbose) printf("* Extracting files...\n");
}
return 0;
}
/* Main program */
void main(int argc, char **argv)
{
XFILE input_file;
afs_uint32 r;
parse_options(argc, argv);
initialize_acfg_error_table();
initialize_AVds_error_table();
initialize_rxk_error_table();
initialize_u_error_table();
initialize_vl_error_table();
initialize_vols_error_table();
initialize_xFil_error_table();
r = xfopen(&input_file, O_RDONLY, input_path);
if (r) {
com_err(argv0, r, "opening %s", input_path);
exit(2);
}
memset(&dp, 0, sizeof(dp));
dp.cb_error = my_error_cb;
if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
dirs_done = 0;
if (!use_vnum) {
u_int64 where;
memset(&phi, 0, sizeof(phi));
phi.p = &dp;
if (verbose) printf("* Building pathname info...\n");
if ((r = xftell(&input_file, &where))
|| (r = Path_PreScan(&input_file, &phi, 1))
|| (r = xfseek(&input_file, &where))) {
com_err(argv0, r, "- path initialization failed");
xfclose(&input_file);
exit(1);
}
}
dp.cb_vnode_dir = directory_cb;
dp.cb_vnode_file = file_cb;
dp.cb_vnode_link = symlink_cb;
dp.cb_vnode_empty = lose_cb;
dp.cb_vnode_wierd = lose_cb;
if (do_headers) {
dp.cb_dumphdr = dumphdr_cb;
dp.cb_volhdr = volhdr_cb;
}
if (!nomode) {
mkdir(target, 0755);
if (chdir(target)) {
fprintf(stderr, "chdir %s failed: %s\n", target, strerror(errno));
exit(1);
}
}
r = ParseDumpFile(&input_file, &dp);
if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
exit(0);
}

293
src/tests/afsdump_scan.c Normal file
View File

@ -0,0 +1,293 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* afsdump_scan.c - General-purpose dump scanner */
#include <sys/fcntl.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "dumpscan.h"
extern int optind;
extern char *optarg;
extern XFILE repair_output;
extern afs_uint32 repair_dumphdr_cb(afs_dump_header *, XFILE *, void *);
extern afs_uint32 repair_volhdr_cb(afs_vol_header *, XFILE *, void *);
extern afs_uint32 repair_vnode_cb(afs_vnode *, XFILE *, void *);
char *argv0;
static char *input_path, *gendump_path;
static afs_uint32 printflags, repairflags;
static int quiet, verbose, error_count;
static path_hashinfo phi;
static dump_parser dp;
/* Print a usage message and exit */
static void usage(int status, char *msg)
{
if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
fprintf(stderr, " -Pxxx Set print options:\n");
fprintf(stderr, " B = Print backup system header (if any)\n");
fprintf(stderr, " H = Print AFS dump header\n");
fprintf(stderr, " V = Print AFS volume header\n");
fprintf(stderr, " v = List vnodes\n");
fprintf(stderr, " p = Include path to each vnode\n");
fprintf(stderr, " i = Include info for each vnode\n");
fprintf(stderr, " d = List directory contents\n");
fprintf(stderr, " a = List access control lists\n");
fprintf(stderr, " g = Print debugging info\n");
fprintf(stderr, " -Rxxx Set repair options:\n");
fprintf(stderr, " 0 = Skip null tags\n");
fprintf(stderr, " b = Seek backward to find skipped tags\n");
fprintf(stderr, " d = Resync after vnode data\n");
fprintf(stderr, " v = Resync after corrupted vnodes\n");
fprintf(stderr, " -h Print this help message\n");
fprintf(stderr, " -gxxx Generate a new dump in file xxx\n");
fprintf(stderr, " -q Quiet mode (don't print errors)\n");
fprintf(stderr, " -v Verbose mode\n");
exit(status);
}
/* Parse the argument given to the -P option.
* Returns the resulting * dumpscan print flags (DSPRINT_*).
* If an unrecognized flag is used, prints an error message and exits.
*/
static afs_uint32 parse_printflags(char *flags)
{
afs_uint32 result = 0;
char *x;
for (x = flags; *x; x++) switch (*x) {
case 'B': result |= DSPRINT_BCKHDR; continue;
case 'H': result |= DSPRINT_DUMPHDR; continue;
case 'V': result |= DSPRINT_VOLHDR; continue;
case 'v': result |= DSPRINT_ITEM; continue;
case 'p': result |= DSPRINT_PATH; continue;
case 'i': result |= DSPRINT_VNODE; continue;
case 'd': result |= DSPRINT_DIR; continue;
case 'a': result |= DSPRINT_ACL; continue;
case 'g': result |= DSPRINT_DEBUG; continue;
default: usage(1, "Invalid print options!");
}
return result;
}
/* Parse the argument given to the -R option.
* Returns the resulting * dumpscan repair flags (DSFIX_*).
* If an unrecognized flag is used, prints an error message and exits.
*/
static afs_uint32 parse_repairflags(char *flags)
{
afs_uint32 result = 0;
char *x;
for (x = flags; *x; x++) switch (*x) {
case '0': result |= DSFIX_SKIP; continue;
case 'b': result |= DSFIX_RSKIP; continue;
case 'd': result |= DSFIX_VDSYNC; continue;
case 'v': result |= DSFIX_VFSYNC; continue;
default: usage(1, "Invalid repair options!");
}
return result;
}
/* Parse the command-line options */
static void parse_options(int argc, char **argv)
{
int c;
/* Set the program name */
if (argv0 = strrchr(argv[0], '/')) argv0++;
else argv0 = argv[0];
/* Initialize options */
input_path = gendump_path = 0;
printflags = repairflags = 0;
quiet = verbose = 0;
/* Initialize other stuff */
error_count = 0;
/* Parse the options */
while ((c = getopt(argc, argv, "P:R:g:hqv")) != EOF) {
switch (c) {
case 'P': printflags = parse_printflags(optarg); continue;
case 'R': repairflags = parse_repairflags(optarg); continue;
case 'g': gendump_path = optarg; continue;
case 'q': quiet = 1; continue;
case 'v': verbose = 1; continue;
case 'h': usage(0, 0);
default: usage(1, "Invalid option!");
}
}
if (quiet && verbose) usage(1, "Can't specify both -q and -v");
/* Parse non-option arguments */
if (argc - optind > 1) usage(1, "Too many arguments!");
input_path = (argc == optind) ? "-" : argv[optind];
}
/* A callback to count and print errors */
static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
{
va_list alist;
error_count++;
if (!quiet) {
va_start(alist, msg);
com_err_va(argv0, code, msg, alist);
va_end(alist);
}
}
/* A callback to print the path of a vnode. */
static afs_uint32 print_vnode_path(afs_vnode *v, XFILE *X, void *refcon)
{
afs_uint32 r;
char *name = 0;
/* Do repair, but only for known vnode types */
if (gendump_path
&& (!(v->field_mask & F_VNODE_TYPE)
|| v->type != vFile
|| v->type != vDirectory
|| v->type != vSymlink)) {
r = repair_vnode_cb(v, X, refcon);
if (r) return r;
}
r = Path_Build(X, &phi, v->vnode, &name, 0);
if (!r && name) printf(" Path: %s\n", name);
if (name) free(name);
return r;
}
/* Setup for generating a repaired dump */
static afs_uint32 setup_repair(void)
{
afs_uint32 r;
r = xfopen(&repair_output, O_RDWR|O_CREAT|O_TRUNC, gendump_path);
if (r) return r;
dp.cb_dumphdr = repair_dumphdr_cb;
dp.cb_volhdr = repair_volhdr_cb;
dp.cb_vnode_dir = repair_vnode_cb;
dp.cb_vnode_file = repair_vnode_cb;
dp.cb_vnode_link = repair_vnode_cb;
dp.cb_vnode_empty = repair_vnode_cb;
return 0;
}
/* Main program */
void main(int argc, char **argv)
{
XFILE input_file;
afs_uint32 r;
parse_options(argc, argv);
initialize_acfg_error_table();
initialize_AVds_error_table();
initialize_rxk_error_table();
initialize_u_error_table();
initialize_vl_error_table();
initialize_vols_error_table();
initialize_xFil_error_table();
r = xfopen(&input_file, O_RDONLY, input_path);
if (r) {
com_err(argv0, r, "opening %s", input_path);
exit(2);
}
memset(&dp, 0, sizeof(dp));
dp.cb_error = my_error_cb;
dp.repair_flags = repairflags;
if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
else {
if (repairflags)
fprintf(stderr, "Repair modes available only for seekable dumps\n");
if (printflags & DSPRINT_PATH)
fprintf(stderr, "Path-printing available only for seekable dumps\n");
if (repairflags || (printflags & DSPRINT_PATH))
exit(1);
}
if (gendump_path && (r = setup_repair())) {
com_err(argv0, r, "setting up repair output");
xfclose(&input_file);
exit(2);
}
if (printflags & DSPRINT_PATH) {
u_int64 where;
dp.print_flags = printflags & DSPRINT_DEBUG;
memset(&phi, 0, sizeof(phi));
phi.p = &dp;
if ((r = xftell(&input_file, &where))
|| (r = Path_PreScan(&input_file, &phi, 0))
|| (r = xfseek(&input_file, &where))) {
com_err(argv0, r, "- path initialization failed");
xfclose(&input_file);
exit(2);
}
dp.cb_vnode_dir = print_vnode_path;
dp.cb_vnode_file = print_vnode_path;
dp.cb_vnode_link = print_vnode_path;
dp.cb_vnode_empty = print_vnode_path;
dp.cb_vnode_wierd = print_vnode_path;
}
dp.print_flags = printflags;
r = ParseDumpFile(&input_file, &dp);
xfclose(&input_file);
if (gendump_path) {
if (!r) r = DumpDumpEnd(&repair_output);
if (!r) r = xfclose(&repair_output);
else xfclose(&repair_output);
}
if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
exit(0);
}

333
src/tests/afsdump_xsed.c Normal file
View File

@ -0,0 +1,333 @@
/*
* COPYRIGHT NOTICE
* Copyright (c) 1997 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* UB - Unified Backups */
/* methods/afs/dumpscan/afsdump_scan.c - General-purpose dump scanner */
#include "dumpscan.h"
#include <sys/fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
extern int opterr, optind;
extern char *optarg;
extern XFILE repair_output;
extern afs_uint32 repair_dumphdr_cb(afs_dump_header *, XFILE *, void *);
extern afs_uint32 repair_volhdr_cb(afs_vol_header *, XFILE *, void *);
extern afs_uint32 repair_vnode_cb(afs_vnode *, XFILE *, void *);
char *argv0;
static char *input_path, *gendump_path;
static afs_uint32 printflags, repairflags, add_admin;
static int quiet, verbose, error_count;
static path_hashinfo phi;
static dump_parser dp;
/* Print a usage message and exit */
static void usage(int status, char *msg)
{
if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
fprintf(stderr, " -Pxxx Set print options:\n");
fprintf(stderr, " B = Print backup system header (if any)\n");
fprintf(stderr, " H = Print AFS dump header\n");
fprintf(stderr, " V = Print AFS volume header\n");
fprintf(stderr, " v = List vnodes\n");
fprintf(stderr, " p = Include path to each vnode\n");
fprintf(stderr, " i = Include info for each vnode\n");
fprintf(stderr, " d = List directory contents\n");
fprintf(stderr, " a = List access control lists\n");
fprintf(stderr, " g = Print debugging info\n");
fprintf(stderr, " -Rxxx Set repair options:\n");
fprintf(stderr, " 0 = Skip null tags\n");
fprintf(stderr, " b = Seek backward to find skipped tags\n");
fprintf(stderr, " d = Resync after vnode data\n");
fprintf(stderr, " v = Resync after corrupted vnodes\n");
fprintf(stderr, " -Annn Add all rights for ID nnn to every directory\n");
fprintf(stderr, " -h Print this help message\n");
fprintf(stderr, " -gxxx Generate a new dump in file xxx\n");
fprintf(stderr, " -q Quiet mode (don't print errors)\n");
fprintf(stderr, " -v Verbose mode\n");
exit(status);
}
/* Parse the argument given to the -P option.
* Returns the resulting * dumpscan print flags (DSPRINT_*).
* If an unrecognized flag is used, prints an error message and exits.
*/
static afs_uint32 parse_printflags(char *flags)
{
afs_uint32 result = 0;
char *x;
for (x = flags; *x; x++) switch (*x) {
case 'B': result |= DSPRINT_BCKHDR; continue;
case 'H': result |= DSPRINT_DUMPHDR; continue;
case 'V': result |= DSPRINT_VOLHDR; continue;
case 'v': result |= DSPRINT_ITEM; continue;
case 'p': result |= DSPRINT_PATH; continue;
case 'i': result |= DSPRINT_VNODE; continue;
case 'd': result |= DSPRINT_DIR; continue;
case 'a': result |= DSPRINT_ACL; continue;
case 'g': result |= DSPRINT_DEBUG; continue;
default: usage(1, "Invalid print options!");
}
return result;
}
/* Parse the argument given to the -R option.
* Returns the resulting * dumpscan repair flags (DSFIX_*).
* If an unrecognized flag is used, prints an error message and exits.
*/
static afs_uint32 parse_repairflags(char *flags)
{
afs_uint32 result = 0;
char *x;
for (x = flags; *x; x++) switch (*x) {
case '0': result |= DSFIX_SKIP; continue;
case 'b': result |= DSFIX_RSKIP; continue;
case 'd': result |= DSFIX_VDSYNC; continue;
case 'v': result |= DSFIX_VFSYNC; continue;
default: usage(1, "Invalid repair options!");
}
return result;
}
/* Parse the command-line options */
static void parse_options(int argc, char **argv)
{
int c;
/* Set the program name */
if (argv0 = strrchr(argv[0], '/')) argv0++;
else argv0 = argv[0];
/* Initialize options */
input_path = gendump_path = 0;
printflags = repairflags = add_admin = 0;
quiet = verbose = 0;
/* Initialize other stuff */
error_count = 0;
/* Parse the options */
while ((c = getopt(argc, argv, "A:P:R:g:hv")) != EOF) {
switch (c) {
case 'A': add_admin = atoi(optarg); continue;
case 'P': printflags = parse_printflags(optarg); continue;
case 'R': repairflags = parse_repairflags(optarg); continue;
case 'g': gendump_path = optarg; continue;
case 'q': quiet = 1; continue;
case 'v': verbose = 1; continue;
case 'h': usage(0, 0);
default: usage(1, "Invalid option!");
}
}
if (quiet && verbose) usage(1, "Can't specify both -q and -v");
/* Parse non-option arguments */
if (argc - optind > 1) usage(1, "Too many arguments!");
input_path = (argc == optind) ? "-" : argv[optind];
if (add_admin && !gendump_path) add_admin = 0;
}
/* A callback to count and print errors */
static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
{
va_list alist;
error_count++;
if (!quiet) {
va_start(alist, msg);
com_err_va(argv0, code, msg, alist);
va_end(alist);
}
}
/* A callback to print the path of a vnode. */
static afs_uint32 print_vnode_path(afs_vnode *v, XFILE *X, void *refcon)
{
afs_uint32 r;
char *name = 0;
/* Do repair, but only for known vnode types */
if (gendump_path
&& (!(v->field_mask & F_VNODE_TYPE)
|| v->type != vFile
|| v->type != vDirectory
|| v->type != vSymlink)) {
r = repair_vnode_cb(v, X, refcon);
if (r) return r;
}
r = Path_Build(X, &phi, v->vnode, &name, 0);
if (!r && name) printf(" Path: %s\n", name);
if (name) free(name);
return r;
}
static afs_uint32 munge_admin_acl(afs_vnode *v, XFILE *X, void *refcon)
{
struct acl_accessList *acl;
int add_entry = 1, remove_entry = -1;
int i, o, n;
acl = (struct acl_accessList *)(v->acl);
o = n = ntohl(acl->positive);
for (i = 0; i < n; i++)
if (ntohl(acl->entries[i].id) == add_admin) add_entry = 0;
n = ntohl(acl->negative);
for (i = o; i < n + o; i++)
if (ntohl(acl->entries[i].id) == add_admin) remove_entry = i;
if (add_entry) {
for (i = (remove_entry < 0) ? o + n : remove_entry; i > o; i--) {
acl->entries[i].id = acl->entries[i-1].id;
acl->entries[i].rights = acl->entries[i-1].rights;
}
acl->entries[o].id = htonl(add_admin);
acl->entries[o].rights = htonl((PRSFS_READ | PRSFS_LOOKUP
| PRSFS_INSERT | PRSFS_DELETE
| PRSFS_WRITE | PRSFS_LOCK
| PRSFS_ADMINISTER));
acl->positive = htonl(o + 1);
if (remove_entry < 0) acl->total = htonl(o + n + 1);
else acl->negative = htonl(n - 1);
} else if (remove_entry >= 0) {
for (i = remove_entry; i < o + n - 1; i++) {
acl->entries[i].id = acl->entries[i+1].id;
acl->entries[i].rights = acl->entries[i+1].rights;
}
acl->negative = htonl(n - 1);
acl->total = htonl(o + n - 1);
}
return repair_vnode_cb(v, X, refcon);
}
/* Setup for generating a repaired dump */
static afs_uint32 setup_repair(void)
{
afs_uint32 r;
r = xfopen(&repair_output, gendump_path, O_RDWR, 0644);
if (r) return r;
dp.cb_dumphdr = repair_dumphdr_cb;
dp.cb_volhdr = repair_volhdr_cb;
dp.cb_vnode_dir = repair_vnode_cb;
dp.cb_vnode_file = repair_vnode_cb;
dp.cb_vnode_link = repair_vnode_cb;
dp.cb_vnode_empty = repair_vnode_cb;
return 0;
}
/* Main program */
void main(int argc, char **argv)
{
XFILE *X;
afs_uint32 r;
parse_options(argc, argv);
initialize_UB_error_table();
initialize_UBsp_error_table();
initialize_AVds_error_table();
r = xfopen(&X, input_path, O_RDONLY, 0);
if (r) {
com_err(argv0, r, "opening %s", input_path);
exit(2);
}
bzero(&dp, sizeof(dp));
dp.cb_error = my_error_cb;
dp.repair_flags = repairflags;
if (X->is_seekable) dp.flags |= DSFLAG_SEEK;
else {
if (repairflags)
fprintf(stderr, "Repair modes available only for seekable dumps\n");
if (printflags & DSPRINT_PATH)
fprintf(stderr, "Path-printing available only for seekable dumps\n");
if (repairflags || (printflags & DSPRINT_PATH))
exit(1);
}
if (gendump_path && (r = setup_repair())) {
com_err(argv0, r, "setting up repair output");
xfclose(X);
exit(2);
}
if (printflags & DSPRINT_PATH) {
u_int64 where;
dp.print_flags = printflags & DSPRINT_DEBUG;
bzero(&phi, sizeof(phi));
phi.p = &dp;
if ((r = xftell(X, &where))
|| (r = Path_PreScan(X, &phi, 0))
|| (r = xfseek(X, &where))) {
com_err(argv0, r, "- path initialization failed");
xfclose(X);
exit(2);
}
dp.cb_vnode_dir = print_vnode_path;
dp.cb_vnode_file = print_vnode_path;
dp.cb_vnode_link = print_vnode_path;
dp.cb_vnode_empty = print_vnode_path;
dp.cb_vnode_wierd = print_vnode_path;
}
if (add_admin) {
dp.cb_vnode_dir = munge_admin_acl;
}
dp.print_flags = printflags;
r = ParseDumpFile(X, &dp);
if (gendump_path) {
if (!r) r = DumpDumpEnd(&repair_output);
if (!r) r = xfclose(&repair_output);
else xfclose(&repair_output);
}
if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
exit(0);
}

87
src/tests/backuphdr.c Normal file
View File

@ -0,0 +1,87 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* backuphdr.c - Parse and print backup system headers */
#include <stdlib.h>
#include "dumpscan.h"
#include "dumpscan_errs.h"
#include "stagehdr.h"
afs_uint32 try_backuphdr(XFILE *X, char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
dump_parser *p = (dump_parser *)g_refcon;
backup_system_header bh;
u_int64 where;
afs_uint32 r;
/* Which header should we try (if any)? */
switch (*tag) {
case STAGE_VERSMIN: r = ParseStageHdr(X, tag, &bh); break;
default: return DSERR_MAGIC;
}
if (r) return r;
/* Do something with it... */
if (p->print_flags & DSPRINT_BCKHDR) PrintBackupHdr(&bh);
if (p->cb_bckhdr) {
r = xftell(X, &where);
if (!r && p->cb_bckhdr)
r = (p->cb_bckhdr)(&bh, X, p->refcon);
if (p->flags & DSFLAG_SEEK) {
if (!r) r = xfseek(X, &where);
else xfseek(X, &where);
}
}
if (bh.server) free(bh.server);
if (bh.part) free(bh.part);
if (bh.volname) free(bh.volname);
return r;
}
void PrintBackupHdr(backup_system_header *hdr)
{
time_t from = hdr->from_date, to = hdr->to_date, dd = hdr->dump_date;
printf("* BACKUP SYSTEM HEADER\n");
printf(" Version: %d\n", hdr->version);
printf(" Volume: %s (%d)\n", hdr->volname, hdr->volid);
printf(" Location: %s %s\n", hdr->server, hdr->part);
printf(" Level: %d\n", hdr->level);
printf(" Range: %d => %d\n", hdr->from_date, hdr->to_date);
printf(" == %s", ctime(&from));
printf(" => %s", ctime(&to));
printf(" Dump Time: %d == %s", hdr->dump_date, ctime(&dd));
printf(" Dump Flags: 0x%08x\n", hdr->flags);
printf(" Length: %d\n", hdr->dumplen);
printf(" File Num: %d\n", hdr->filenum);
}

254
src/tests/directory.c Normal file
View File

@ -0,0 +1,254 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* directory.c - Parse an AFS directory */
/* See the end of this file for a description of the directory format */
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "dumpscan.h"
#include "dumpscan_errs.h"
#include "xf_errs.h"
#include "dumpfmt.h"
#include "internal.h"
#include <afs/dir.h>
static afs_dir_page page;
#define allocbit(x) (page.header.freebitmap[(x)>>3] & (1 << ((x) & 7)))
#define DPHE (DHE + 1)
static void fixup(char *name, int l)
{
name += 16;
l -= 15;
while (l-- > 0) {
name[0] = name[4];
name++;
}
}
afs_uint32 parse_directory(XFILE *X, dump_parser *p, afs_vnode *v,
afs_uint32 size, int toeof)
{
afs_dir_entry de;
int pgno, i, j, l, n;
afs_uint32 r;
u_int64 where;
if (p->print_flags & DSPRINT_DIR) {
printf(" VNode Uniqifier Name\n");
printf(" ========== ========== ==============================\n");
}
if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) return r;
for (pgno = 0; toeof || size; pgno++, size -= (toeof ? 0 : AFS_PAGESIZE)) {
if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) return r;
if (r = xfread(X, &page, AFS_PAGESIZE)) {
if (toeof && r == ERROR_XFILE_EOF) break;
return r;
}
if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) return r;
if (page.header.tag != htons(1234)) {
if (p->cb_error)
(p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
"Invalid page tag (%d) in page %d",
ntohs(page.header.tag), pgno);
return DSERR_MAGIC;
}
for (i = (pgno ? 1 : DPHE); i < EPP; i++) {
if (!allocbit(i)) continue;
if (page.entry[i].flag != FFIRST) {
if (p->cb_error)
(p->cb_error)(DSERR_MAGIC, 0, p->err_refcon,
"Invalid entry flag %d in entry %d/%d; skipping...",
page.entry[i].flag, pgno, i);
continue;
}
n = (EPP - i - 1) * 32 + 16;
for (l = 0; n && page.entry[i].name[l]; l++, n--);
if (page.entry[i].name[l]) {
if (p->cb_error)
(p->cb_error)(DSERR_FMT, 0, p->err_refcon,
"Filename too long in entry %d/%d; skipping page",
pgno, i);
break;
}
/* fixup(page.entry[i].name, l); */
if (pgno) de.slot = i - 1 + (pgno - 1) * (EPP - 1) + (EPP - DPHE);
else de.slot = i - DPHE;
de.name = page.entry[i].name;
de.vnode = ntohl(page.entry[i].vnode);
de.uniq = ntohl(page.entry[i].vunique);
if (p->print_flags & DSPRINT_DIR)
printf(" %10d %10d %s\n", de.vnode, de.uniq, de.name);
if (p->cb_dirent) {
r = (p->cb_dirent)(v, &de, X, p->refcon);
}
if (p->cb_dirent && (r = (p->cb_dirent)(v, &de, X, p->refcon)))
return r;
i += ((l + 16) >> 5);
}
}
if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) return r;
return 0;
}
afs_uint32 ParseDirectory(XFILE *X, dump_parser *p, afs_uint32 size, int toeof)
{
afs_uint32 r;
r = parse_directory(X, p, 0, size, toeof);
}
typedef struct {
char **name;
afs_uint32 *vnode;
afs_uint32 *vuniq;
} dirlookup_stat;
static afs_uint32 dirlookup_cb(afs_vnode *v, afs_dir_entry *de,
XFILE *X, void *refcon)
{
dirlookup_stat *s = (dirlookup_stat *)refcon;
if (s->name && s->name[0]) { /* Search by filename */
if (strcmp(de->name, s->name[0])) return 0; /* Not it! */
if (s->vnode) s->vnode[0] = de->vnode;
if (s->vuniq) s->vuniq[0] = de->uniq;
} else if (s->vnode) { /* Search by vnode */
if (de->vnode != s->vnode[0]) return 0; /* Not it! */
if (s->name) {
s->name[0] = (char *)malloc(strlen(de->name) + 1);
if (!s->name[0]) return ENOMEM;
strcpy(s->name[0], de->name);
}
if (s->vuniq) s->vuniq[0] = de->uniq;
}
return DSERR_DONE;
}
/* Look up an entry in a directory, by name or vnode.
* If *name is NULL, we are looking up by vnode.
* Otherwise, we are looking for a filename.
* In any event, any of name, vnode, vuniq that are
* neither NULL nor the search key are filled in on
* success.
*
* Call this with X pointing to the start of the directory,
* and size set to the length of the directory.
* Returns 0 on success, whether or not the entry is found.
*/
afs_uint32 DirectoryLookup(XFILE *X, dump_parser *p, afs_uint32 size,
char **name, afs_uint32 *vnode, afs_uint32 *vuniq)
{
dump_parser my_p;
dirlookup_stat my_s;
afs_uint32 r;
memset(&my_s, 0, sizeof(my_s));
my_s.name = name;
my_s.vnode = vnode;
my_s.vuniq = vuniq;
memset(&my_p, 0, sizeof(my_p));
my_p.refcon = (void *)&my_s;
my_p.err_refcon = p->err_refcon;
my_p.cb_error = p->cb_error;
my_p.cb_dirent = dirlookup_cb;
r = parse_directory(X, &my_p, 0, size, 0);
if (!r) r = DSERR_DONE;
return handle_return(r, X, 0, p);
}
/* AFS directory format:
* AFS directories are stored in volume dumps in exactly the same format
* that is used on disk, which makes them relatively easy to dump and restore,
* but means we have to do some work to interpret them.
*
* The ACL for a directory is stored on disk in the last part of a "large"
* (directory) vnode. This part of the vnode, which has fixed size
* SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE, is copied directly into
* the dump file with a tag of 'A' (VTAG_ACL). The structure of this
* section is described in <afs/acl.h>.
*
* The name-to-vnode mappings are also stored exactly as they appear on
* disk, using the file data ('f') attribute. As usual, this attribute
* consists of a 32-bit number containing the size, immediately followed
* by the data itself. The interesting structures and constants are
* defined in <afs/dir.h>
*
* A directory consists of one or more 'pages', each of which is 2K
* (AFS_PAGESIZE). Each page contains EPP (currently 64) 'entries', each
* of which is 32 bytes. The first page begins with a DirHeader, which
* is DHE entries long, and includes a PageHeader. All other pages begin
* with just a PageHeader, which is 1 entry long. Every other entry is
* a DirEntry, a DirXEntry (name extension), or unused.
*
* A Page Header contains the following elements:
* - pgcount contains a count of the number of pages in the directory,
* if the directory is new-style (>128 pages), or 0 if it is
* old-style. This field is meaningful only in the Dir Header.
* - tag a magic number, which must be 1234
* - freecount apparently unused
* - freebitmap A bitmap of free entries. Each byte corresponds to 8
* entries, with the least significant bit referring to the
* first of those. Each bit is set iff the corresponding
* entry is allocated. Entries used by the page and dir
* headers are considered allocated.
*
* A Dir Header consists of a Page Header, followed by an allocation map
* and hash table. The allocation map contains one byte for each of the
* first 128 pages; that byte contains the number of entries in that page
* that are allocated. Every page that actually exists has at peast one
* entry allocated (the Page Header); if a byte in this map is 0, it means
* that the page does not yet exist.
*
* Each bucket in the hash table is a linked list, using 'blob numbers'
* as pointers. A blob number is defined as (page# * EPP) + entry#.
* The head of each chain is kept in the hash table, and the next pointers
* are kept in the 'next' entry of each directory.
*
* Directory entries themselves contain the following elements:
* - flag Set to FFIRST iff this is the first blob in an entry
* (otherwise it will be a name continuation). This is
* probably not reliable.
* - length Unused
* - next Pointer to the next element in this hash chain
* - fid FileID (vnode and uniquifier)
* - name Filename (null-terminated)
*/

229
src/tests/dump.c Normal file
View File

@ -0,0 +1,229 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* dump.c - Write out parts of a volume dump */
#include "dumpscan.h"
#include "dumpfmt.h"
#define COPYBUFSIZE 65536
afs_uint32 DumpDumpHeader(XFILE *OX, afs_dump_header *hdr)
{
afs_uint32 r;
if (r = WriteTagInt32Pair(OX, TAG_DUMPHEADER, hdr->magic, hdr->version))
return r;
if (hdr->field_mask & F_DUMPHDR_VOLID) {
if (r = WriteTagInt32(OX, DHTAG_VOLID, hdr->volid)) return r;
}
if (hdr->field_mask & F_DUMPHDR_VOLNAME) {
if (r = WriteByte(OX, DHTAG_VOLNAME)) return r;
if (r = WriteString(OX, hdr->volname)) return r;
}
if (hdr->field_mask & (F_DUMPHDR_FROM | F_DUMPHDR_TO)) {
if (r = WriteTagInt16(OX, DHTAG_DUMPTIMES, 2))
return r;
if (r = WriteInt32(OX, (hdr->field_mask & F_DUMPHDR_FROM)
? hdr->from_date : 0))
return r;
if (r = WriteInt32(OX, (hdr->field_mask & F_DUMPHDR_TO)
? hdr->to_date : time(0)))
return r;
}
return 0;
}
afs_uint32 DumpVolumeHeader(XFILE *OX, afs_vol_header *hdr)
{
afs_uint32 r;
int i;
if (r = WriteByte(OX, TAG_VOLHEADER)) return r;
if (hdr->field_mask & F_VOLHDR_VOLID) {
if (r = WriteTagInt32(OX, VHTAG_VOLID, hdr->volid)) return r;
}
if (hdr->field_mask & F_VOLHDR_VOLVERS) {
if (r = WriteTagInt32(OX, VHTAG_VERS, hdr->volvers)) return r;
}
if (hdr->field_mask & F_VOLHDR_VOLNAME) {
if (r = WriteByte(OX, VHTAG_VOLNAME)) return r;
if (r = WriteString(OX, hdr->volname)) return r;
}
if (hdr->field_mask & F_VOLHDR_INSERV) {
if (r = WriteTagByte(OX, VHTAG_INSERV, hdr->flag_inservice)) return r;
}
if (hdr->field_mask & F_VOLHDR_BLESSED) {
if (r = WriteTagByte(OX, VHTAG_BLESSED, hdr->flag_blessed)) return r;
}
if (hdr->field_mask & F_VOLHDR_VOLUNIQ) {
if (r = WriteTagInt32(OX, VHTAG_VUNIQ, hdr->voluniq)) return r;
}
if (hdr->field_mask & F_VOLHDR_VOLTYPE) {
if (r = WriteTagByte(OX, VHTAG_TYPE, hdr->voltype)) return r;
}
if (hdr->field_mask & F_VOLHDR_PARENT) {
if (r = WriteTagInt32(OX, VHTAG_PARENT, hdr->parent_volid)) return r;
}
if (hdr->field_mask & F_VOLHDR_CLONE) {
if (r = WriteTagInt32(OX, VHTAG_CLONE, hdr->clone_volid)) return r;
}
if (hdr->field_mask & F_VOLHDR_MAXQ) {
if (r = WriteTagInt32(OX, VHTAG_MAXQUOTA, hdr->maxquota)) return r;
}
if (hdr->field_mask & F_VOLHDR_MINQ) {
if (r = WriteTagInt32(OX, VHTAG_MINQUOTA, hdr->minquota)) return r;
}
if (hdr->field_mask & F_VOLHDR_DISKUSED) {
if (r = WriteTagInt32(OX, VHTAG_DISKUSED, hdr->diskused)) return r;
}
if (hdr->field_mask & F_VOLHDR_NFILES) {
if (r = WriteTagInt32(OX, VHTAG_FILECNT, hdr->nfiles)) return r;
}
if (hdr->field_mask & F_VOLHDR_ACCOUNT) {
if (r = WriteTagInt32(OX, VHTAG_ACCOUNT, hdr->account_no)) return r;
}
if (hdr->field_mask & F_VOLHDR_OWNER) {
if (r = WriteTagInt32(OX, VHTAG_OWNER, hdr->owner)) return r;
}
if (hdr->field_mask & F_VOLHDR_CREATE_DATE) {
if (r = WriteTagInt32(OX, VHTAG_CREAT, hdr->create_date)) return r;
}
if (hdr->field_mask & F_VOLHDR_ACCESS_DATE) {
if (r = WriteTagInt32(OX, VHTAG_ACCESS, hdr->access_date)) return r;
}
if (hdr->field_mask & F_VOLHDR_UPDATE_DATE) {
if (r = WriteTagInt32(OX, VHTAG_UPDATE, hdr->update_date)) return r;
}
if (hdr->field_mask & F_VOLHDR_EXPIRE_DATE) {
if (r = WriteTagInt32(OX, VHTAG_EXPIRE, hdr->expire_date)) return r;
}
if (hdr->field_mask & F_VOLHDR_BACKUP_DATE) {
if (r = WriteTagInt32(OX, VHTAG_BACKUP, hdr->backup_date)) return r;
}
if (hdr->field_mask & F_VOLHDR_OFFLINE_MSG) {
if (r = WriteTagInt32(OX, VHTAG_OFFLINE, hdr->offline_msg)) return r;
}
if (hdr->field_mask & F_VOLHDR_MOTD) {
if (r = WriteTagInt32(OX, VHTAG_MOTD, hdr->motd_msg)) return r;
}
if (hdr->field_mask & F_VOLHDR_WEEKUSE) {
if (r = WriteTagInt16(OX, VHTAG_WEEKUSE, 7)) return r;
for (i = 0; i < 7; i++)
if (r = WriteInt32(OX, hdr->weekuse[i])) return r;
}
if (hdr->field_mask & F_VOLHDR_DAYUSE_DATE) {
if (r = WriteTagInt32(OX, VHTAG_DUDATE, hdr->dayuse_date)) return r;
}
if (hdr->field_mask & F_VOLHDR_DAYUSE) {
if (r = WriteTagInt32(OX, VHTAG_DAYUSE, hdr->dayuse)) return r;
}
return 0;
}
afs_uint32 DumpVNode(XFILE *OX, afs_vnode *v)
{
afs_uint32 r;
if (r = WriteTagInt32Pair(OX, TAG_VNODE, v->vnode, v->vuniq)) return r;
if (v->field_mask & F_VNODE_TYPE) {
if (r = WriteTagByte(OX, VTAG_TYPE, v->type)) return r;
}
if (v->field_mask & F_VNODE_NLINKS) {
if (r = WriteTagInt16(OX, VTAG_NLINKS, v->nlinks)) return r;
}
if (v->field_mask & F_VNODE_DVERS) {
if (r = WriteTagInt32(OX, VTAG_DVERS, v->datavers)) return r;
}
if (v->field_mask & F_VNODE_SDATE) {
if (r = WriteTagInt32(OX, VTAG_SERVER_DATE, v->server_date)) return r;
}
if (v->field_mask & F_VNODE_AUTHOR) {
if (r = WriteTagInt32(OX, VTAG_AUTHOR, v->author)) return r;
}
if (v->field_mask & F_VNODE_OWNER) {
if (r = WriteTagInt32(OX, VTAG_OWNER, v->owner)) return r;
}
if (v->field_mask & F_VNODE_GROUP) {
if (r = WriteTagInt32(OX, VTAG_GROUP, v->group)) return r;
}
if (v->field_mask & F_VNODE_MODE) {
if (r = WriteTagInt16(OX, VTAG_MODE, v->mode)) return r;
}
if (v->field_mask & F_VNODE_PARENT) {
if (r = WriteTagInt32(OX, VTAG_PARENT, v->parent)) return r;
}
if (v->field_mask & F_VNODE_CDATE) {
if (r = WriteTagInt32(OX, VTAG_CLIENT_DATE, v->client_date)) return r;
}
if (v->field_mask & F_VNODE_ACL) {
if (r = WriteByte(OX, VTAG_ACL)) return r;
if (r = xfwrite(OX, v->acl, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE))
return r;
}
return 0;
}
afs_uint32 DumpVNodeData(XFILE *OX, char *buf, afs_uint32 size)
{
afs_uint32 r;
if (r = WriteTagInt32(OX, VTAG_DATA, size)) return r;
if (r = xfwrite(OX, buf, size)) return r;
return 0;
}
afs_uint32 CopyVNodeData(XFILE *OX, XFILE *X, afs_uint32 size)
{
afs_uint32 r, n;
static char buf[COPYBUFSIZE];
if (r = WriteTagInt32(OX, VTAG_DATA, size)) return r;
while (size) {
n = (size > COPYBUFSIZE) ? COPYBUFSIZE : size;
if (r = xfread(X, buf, n)) return r;
if (r = xfwrite(OX, buf, n)) return r;
size -= n;
}
return 0;
}
afs_uint32 DumpDumpEnd(XFILE *OX) {
afs_uint32 r;
if (r = WriteTagInt32(OX, TAG_DUMPEND, DUMPENDMAGIC)) return r;
return 0;
}

150
src/tests/dumpfmt.h Normal file
View File

@ -0,0 +1,150 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* dumpfmt.h - Description of AFS dump format */
#ifndef _DUMPFMT_H_
#define _DUMPFMT_H_
#include "intNN.h"
/* AFS dump file format:
* All data in AFS dumps is tagged; that is, each data item is preceeded
* by a 1-byte tag which identifies what the data item is. There is no
* explicit mention of what the data type is, but the type of each possible
* data item (and thus, each possible tag) is fixed. Usually this is
* a relatively simple, fixed amount of data (byte, short, word), but
* sometimes it is more complex.
*
* There is some amount of structure to an AFS volume dump. Basically,
* you get a dump header, followed by a volume header, followed by some
* vnodes, followed by a dump end. Each of these items (header, vnode,
* dump end) consists of a tag, a fixed amount of required information,
* and 0 or more tagged attributes (except dump-end, which has no attributes).
*
* Vnodes, in turn, are usually listed in a particular order. First, we
* list all the directory vnodes in the volume, in increasing order by
* vnode. Then, we list all the file vnodes, again in increasing order.
* Directory vnodes must have a complete set of attributes and data, but
* in an incremental dump, file vnodes may have no attributes if the vnode
* has not changed since the reference date.
*
* The primary purpose of this file is to define the tags and some magic
* numbers. There is also some information that is defined in the Transarc
* provided header files.
*/
/** MAGIC NUMBERS **/
#define DUMPVERSION 1
#define DUMPBEGINMAGIC 0xb3a11322
#define DUMPENDMAGIC 0x3a214b6e
/** TOP-LEVEL TAGS **/
#define TAG_DUMPHEADER 1
#define TAG_VOLHEADER 2
#define TAG_VNODE 3
#define TAG_DUMPEND 4
/** DUMP HEADER TAGS **/
#define DHTAG_VOLNAME 'n'
#define DHTAG_VOLID 'v'
#define DHTAG_DUMPTIMES 't'
/** VOLUME HEADER TAGS **/
#define VHTAG_VOLID 'i'
#define VHTAG_VERS 'v'
#define VHTAG_VOLNAME 'n'
#define VHTAG_INSERV 's'
#define VHTAG_BLESSED 'b'
#define VHTAG_VUNIQ 'u'
#define VHTAG_TYPE 't'
#define VHTAG_PARENT 'p'
#define VHTAG_CLONE 'c'
#define VHTAG_MAXQUOTA 'q'
#define VHTAG_MINQUOTA 'm'
#define VHTAG_DISKUSED 'd'
#define VHTAG_FILECNT 'f'
#define VHTAG_ACCOUNT 'a'
#define VHTAG_OWNER 'o'
#define VHTAG_CREAT 'C'
#define VHTAG_ACCESS 'A'
#define VHTAG_UPDATE 'U'
#define VHTAG_EXPIRE 'E'
#define VHTAG_BACKUP 'B'
#define VHTAG_OFFLINE 'O'
#define VHTAG_MOTD 'M'
#define VHTAG_WEEKUSE 'W'
#define VHTAG_DUDATE 'D'
#define VHTAG_DAYUSE 'Z'
/** VNODE TAGS **/
#define VTAG_TYPE 't'
#define VTAG_NLINKS 'l'
#define VTAG_DVERS 'v'
#define VTAG_CLIENT_DATE 'm'
#define VTAG_AUTHOR 'a'
#define VTAG_OWNER 'o'
#define VTAG_GROUP 'g'
#define VTAG_MODE 'b'
#define VTAG_PARENT 'p'
#define VTAG_SERVER_DATE 's'
#define VTAG_ACL 'A'
#define VTAG_DATA 'f'
#define AFS_DIR_EPP 64
typedef struct {
afs_uint16 pgcount;
afs_uint16 tag;
char freecount;
char freebitmap[AFS_DIR_EPP/8];
char padding[32 - (5 + AFS_DIR_EPP/8)];
} afs_dir_pagehdr;
typedef struct {
char flag;
char length;
afs_uint16 next;
afs_uint32 vnode;
afs_uint32 vunique;
char name[16];
char padding[4];
} afs_dir_direntry;
typedef union {
afs_dir_pagehdr header;
afs_dir_direntry entry[AFS_DIR_EPP];
} afs_dir_page;
#endif /* _DUMPFMT_H_ */

379
src/tests/dumpscan.h Normal file
View File

@ -0,0 +1,379 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* dumpscan.h - Public interface */
#ifndef _DUMPSCAN_H_
#define _DUMPSCAN_H_
#include "intNN.h"
#include "xfiles.h"
#include <lock.h>
#include <afs/afsint.h>
#include <afs/nfs.h>
#include <afs/ihandle.h>
#include <afs/vnode.h>
#include <afs/cmd.h>
#include <afs/auth.h>
#include <afs/bnode.h>
#include <afs/cellconfig.h>
#include <afs/kautils.h>
#include <afs/pterror.h>
#include <afs/vlserver.h>
#include <afs/volser.h>
#include <ubik.h>
/* Random useful types */
typedef struct tagged_field tagged_field;
typedef struct tag_parse_info tag_parse_info;
typedef afs_uint32 (*tag_parser)(XFILE *, unsigned char *, tagged_field *,
afs_uint32, tag_parse_info *, void *, void *);
/* Error codes used within dumpscan.
* Any of the routines declared below, or callbacks used by them,
* may signal a system error by returning the error number, or
* some other error by returning a com_err code. Note that
* ParseTaggedData does _not_ return DSERR_TAG; instead, it returns
* 0, assuming the tag will be handled at a higher level.
*
* In addition, these errors may be reported to the caller of
* ParseDumpFile using the error callback. Such reports will be
* issued whether or not error recovery is possible or attempted.
*
* NB: These errors are now in dumpscan_errs.h
*/
/* Backup system dump header */
/* Right now, this looks a lot like an old stage header. Eventually, it
* should contain enough fields to fully represent headers from old or
* new stage, Transarc, or other backup systems, and the appropriate read
* functions should extract as much data as possible from the actual file
* to fill this in. */
typedef struct {
afs_uint32 version;
afs_uint32 from_date;
afs_uint32 to_date;
afs_uint32 dump_date;
afs_uint32 filenum;
unsigned char *server;
unsigned char *part;
unsigned char *volname;
afs_uint32 volid;
afs_uint32 dumplen;
afs_uint32 level;
afs_uint32 magic;
afs_uint32 cksum;
afs_uint32 flags;
} backup_system_header;
/** AFS dump header **/
#define F_DUMPHDR_VOLID 0x00000001
#define F_DUMPHDR_VOLNAME 0x00000002
#define F_DUMPHDR_FROM 0x00000004
#define F_DUMPHDR_TO 0x00000008
typedef struct {
u_int64 offset; /* Where in the file is it? */
afs_uint32 field_mask; /* What fields are present? */
afs_uint32 magic; /* Magic number */
afs_uint32 version; /* Dump format version */
afs_uint32 volid; /* VolID of volume in dump */
unsigned char *volname; /* Name of volume in dump */
afs_uint32 from_date; /* Reference date */
afs_uint32 to_date; /* Date of dump */
} afs_dump_header;
/** AFS volume header **/
#define F_VOLHDR_VOLID 0x00000001
#define F_VOLHDR_VOLVERS 0x00000002
#define F_VOLHDR_VOLNAME 0x00000004
#define F_VOLHDR_INSERV 0x00000008
#define F_VOLHDR_BLESSED 0x00000010
#define F_VOLHDR_VOLUNIQ 0x00000020
#define F_VOLHDR_VOLTYPE 0x00000040
#define F_VOLHDR_PARENT 0x00000080
#define F_VOLHDR_CLONE 0x00000100
#define F_VOLHDR_MAXQ 0x00000200
#define F_VOLHDR_MINQ 0x00000400
#define F_VOLHDR_DISKUSED 0x00000800
#define F_VOLHDR_NFILES 0x00001000
#define F_VOLHDR_ACCOUNT 0x00002000
#define F_VOLHDR_OWNER 0x00004000
#define F_VOLHDR_CREATE_DATE 0x00008000
#define F_VOLHDR_ACCESS_DATE 0x00010000
#define F_VOLHDR_UPDATE_DATE 0x00020000
#define F_VOLHDR_EXPIRE_DATE 0x00040000
#define F_VOLHDR_BACKUP_DATE 0x00080000
#define F_VOLHDR_OFFLINE_MSG 0x00100000
#define F_VOLHDR_MOTD 0x00200000
#define F_VOLHDR_WEEKUSE 0x00400000
#define F_VOLHDR_DAYUSE 0x00800000
#define F_VOLHDR_DAYUSE_DATE 0x01000000
typedef struct {
u_int64 offset; /* Where in the file is it? */
afs_uint32 field_mask; /* What fields are present? */
afs_uint32 volid; /* Volume ID */
afs_uint32 volvers; /* ?? */
unsigned char *volname; /* Volume Name */
int flag_inservice; /* Inservice flag (0 or not) */
int flag_blessed; /* Blessed to come online (0 or not) */
afs_uint32 voluniq; /* Volume uniquifier */
int voltype; /* Volume type */
afs_uint32 parent_volid; /* Parent volume ID */
afs_uint32 clone_volid; /* Clone volume ID */
afs_uint32 maxquota; /* Max quota */
afs_uint32 minquota; /* Min quota (obsolete) */
afs_uint32 diskused; /* Disk blocks used */
afs_uint32 nfiles; /* Number of files in volume */
afs_uint32 account_no; /* Account number (unused) */
afs_uint32 owner; /* Volume owner */
afs_uint32 create_date; /* Creation date of this copy */
afs_uint32 access_date; /* Last access */
afs_uint32 update_date; /* Last modification */
afs_uint32 expire_date; /* Expiration (unused) */
afs_uint32 backup_date; /* Last backup clone */
unsigned char *offline_msg; /* Offline message */
unsigned char *motd_msg; /* Volume MOTD */
afs_uint32 weekuse[7]; /* Weekuse data */
afs_uint32 dayuse; /* # accesses in last day */
afs_uint32 dayuse_date; /* Date for which dayuse is valid */
} afs_vol_header;
/** AFS vnode **/
#define F_VNODE_TYPE 0x00000001
#define F_VNODE_NLINKS 0x00000002
#define F_VNODE_PARENT 0x00000004
#define F_VNODE_DVERS 0x00000008
#define F_VNODE_AUTHOR 0x00000010
#define F_VNODE_OWNER 0x00000020
#define F_VNODE_GROUP 0x00000040
#define F_VNODE_MODE 0x00000080
#define F_VNODE_CDATE 0x00000100
#define F_VNODE_SDATE 0x00000200
#define F_VNODE_SIZE 0x00000800
#define F_VNODE_DATA 0x00001000
#define F_VNODE_ACL 0x00000400
typedef struct {
u_int64 offset; /* Where in the file is it? */
afs_uint32 field_mask; /* What fields are present? */
afs_uint32 vnode; /* Vnode number */
afs_uint32 vuniq; /* Uniquifier */
int type; /* Vnode type */
afs_uint16 nlinks; /* Number of links (should be in 1 dir!) */
afs_uint32 parent; /* Parent vnode */
afs_uint32 datavers; /* Data version */
afs_uint32 author; /* Last writer */
afs_uint32 owner; /* Owner UID */
afs_uint32 group; /* Owning group */
afs_uint16 mode; /* UNIX mode bits */
afs_uint32 client_date; /* Last modified date from client */
afs_uint32 server_date; /* Last modified date on server */
afs_uint32 size; /* Size of data */
u_int64 d_offset; /* Where in the file is the data? */
unsigned char acl[SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE];
} afs_vnode;
/** AFS directory entry **/
typedef struct {
int slot; /* Directory slot # (info only) */
char *name; /* Name of entry */
afs_uint32 vnode; /* Vnode number */
afs_uint32 uniq; /* Uniquifier */
} afs_dir_entry;
/** Tagged field definitions **/
#define DKIND_NOOP 0x00 /* No data */
#define DKIND_BYTE 0x10 /* 1 byte - decimal */
#define DKIND_HEX8 0x11 /* 1 byte - hex */
#define DKIND_CHAR 0x12 /* 1 byte - character */
#define DKIND_FLAG 0x13 /* 1 byte - true/false */
#define DKIND_INT16 0x20 /* 2 bytes - decimal */
#define DKIND_HEX16 0x21 /* 2 bytes - hex */
#define DKIND_INT32 0x30 /* 4 bytes - decimal */
#define DKIND_HEX32 0x31 /* 4 bytes - hex */
#define DKIND_TIME 0x32 /* 4 bytes - time */
#define DKIND_STRING 0x40 /* ASCIIZ string */
#define DKIND_SPECIAL 0x50 /* Custom parser */
#define DKIND_MASK (~0x0f)
struct tag_parse_info {
void *err_refcon;
afs_uint32 (*cb_error)(afs_uint32, int, void *, char *, ...);
afs_uint32 flags;
#define TPFLAG_SKIP 0x0001
#define TPFLAG_RSKIP 0x0002
int shift_offset;
u_int64 shift_start;
};
struct tagged_field {
char tag; /* Tag character */
int kind; /* Kind of object */
char *label; /* Label to use (for debugging) */
tag_parser func; /* Parser function (for DKIND_SPECIAL) */
void *refptr; /* Reference pointer (for parser's use) */
int refarg; /* Reference argument (for parser's use) */
};
/** Control structure for parsing volume dumps **/
typedef struct {
/* Callback functions:
* Whenever a "complex" object is parsed, we call a callback function.
* The callback gets a pointer to the complex object, the file pointer
* for the dump we're parsing, and the value of refcon in this structure.
* Callbacks should return 0 if all is well, non-0 to abort the dump.
* By convention, positive numbers should be errno values, and negative
* numbers can be used for other things. It is OK to _try_ to seek anywhere
* in the file. Beware, though, that the input is not always seekable.
* Also, note that the structures passed to these callbacks are going to
* go away after the callback returns. There is no way to prevent this;
* make a copy if you want one.
*/
void *refcon;
afs_uint32 (*cb_bckhdr)(backup_system_header *, XFILE *, void *); /* Backup */
afs_uint32 (*cb_dumphdr)(afs_dump_header *, XFILE *, void *); /* Dump hdr */
afs_uint32 (*cb_volhdr)(afs_vol_header *, XFILE *, void *); /* Volume hdr */
afs_uint32 (*cb_vnode_dir)(afs_vnode *, XFILE *, void *); /* Directory */
afs_uint32 (*cb_vnode_file)(afs_vnode *, XFILE *, void *); /* File */
afs_uint32 (*cb_vnode_link)(afs_vnode *, XFILE *, void *); /* Symlink */
afs_uint32 (*cb_vnode_empty)(afs_vnode *, XFILE *, void *); /* vnode+uniq */
afs_uint32 (*cb_vnode_wierd)(afs_vnode *, XFILE *, void *); /* Unknown type */
/* This function is called when there is an error in the dump. */
/* (cb_error)(errno, fatal, refcon, msg_fmt, msg_args...) */
void *err_refcon; /* If set, use instead of refcon for dir entries */
afs_uint32 (*cb_error)(afs_uint32, int, void *, char *, ...);
/* This function is called for each directory entry, if set */
afs_uint32 (*cb_dirent)(afs_vnode *, afs_dir_entry *, XFILE *, void *);
int flags; /* Flags and options */
#define DSFLAG_SEEK 0x0001 /* Input file is seekable */
int print_flags; /* Flags to control what is printed */
#define DSPRINT_BCKHDR 0x0001 /* Print backup system header */
#define DSPRINT_DUMPHDR 0x0002 /* Print AFS dump header */
#define DSPRINT_VOLHDR 0x0004 /* Print AFS volume header */
#define DSPRINT_ITEM 0x0010 /* Print top-level tags */
#define DSPRINT_VNODE 0x0020 /* Print vnode attributes */
#define DSPRINT_ACL 0x0040 /* Print directory ACL's */
#define DSPRINT_DIR 0x0080 /* Print directory contents */
#define DSPRINT_DEBUG 0x0100 /* Print debugging info */
#define DSPRINT_PATH 0x0200 /* Print vnode paths */
int repair_flags; /* Flags to control what is repaired.
* Most of these _require_ DSFLAG_SEEK */
#define DSFIX_SKIP 0x0001 /* Try to skip null tags */
#define DSFIX_RSKIP 0x0002 /* Seek back to fing skipped tags */
#define DSFIX_VDSYNC 0x0004 /* Resync location after vnode data */
#define DSFIX_VFSYNC 0x0008 /* Try to resync after bad vnode */
/** Things below this point for internal use only **/
afs_uint32 vol_uniquifier;
} dump_parser;
/** Hash table and control info for pathname manipulation **/
typedef struct vhash_ent {
struct vhash_ent *next; /* Pointer to next entry */
afs_uint32 vnode; /* VNode number */
afs_uint32 parent; /* Parent VNode number */
u_int64 v_offset; /* Offset to start of vnode */
u_int64 d_offset; /* Offset to data (0 if none) */
afs_uint32 d_size; /* Size of data */
} vhash_ent;
typedef struct {
afs_uint32 n_vnodes; /* Number of vnodes in volume */
afs_uint32 n_dirs; /* Number of file vnodes */
afs_uint32 n_files; /* Number of directory vnodes */
int hash_size; /* Hash table size (bits) */
vhash_ent **hash_table; /* Hash table */
dump_parser *p; /* Dump parser to use */
} path_hashinfo;
/** Function prototypes **/
/** Only the functions declared below are public interfaces **/
/** Maybe someday, I'll write man pages for these **/
/* primitive.c - I/O primitives */
extern afs_uint32 ReadByte(XFILE *, unsigned char *);
extern afs_uint32 ReadInt16(XFILE *, afs_uint16 *);
extern afs_uint32 ReadInt32(XFILE *, afs_uint32 *);
extern afs_uint32 ReadString(XFILE *, unsigned char **);
extern afs_uint32 WriteByte(XFILE *, unsigned char);
extern afs_uint32 WriteInt16(XFILE *, afs_uint16);
extern afs_uint32 WriteInt32(XFILE *, afs_uint32);
extern afs_uint32 WriteString(XFILE *, unsigned char *);
extern afs_uint32 WriteTagByte(XFILE *, unsigned char, unsigned char);
extern afs_uint32 WriteTagInt16(XFILE *, unsigned char, afs_uint16);
extern afs_uint32 WriteTagInt32(XFILE *, unsigned char, afs_uint32);
extern afs_uint32 WriteTagInt32Pair(XFILE *, unsigned char, afs_uint32, afs_uint32);
/* parsetag.c - Parse tagged data */
extern afs_uint32 ParseTaggedData(XFILE *, tagged_field *, unsigned char *,
tag_parse_info *, void *, void *);
/* stagehdr.c - Parse and dump Stage dump headers */
extern afs_uint32 ParseStageHdr(XFILE *, unsigned char *, backup_system_header *);
extern afs_uint32 DumpStagehdr(XFILE *, backup_system_header *);
/* backuphdr.c - Parse and print backup system headers */
extern void PrintBackupHdr(backup_system_header *);
/* parsedump.c - Parse all or part of a volume dump */
extern afs_uint32 ParseDumpFile(XFILE *, dump_parser *);
extern afs_uint32 ParseDumpHeader(XFILE *, dump_parser *);
extern afs_uint32 ParseVolumeHeader(XFILE *, dump_parser *);
extern afs_uint32 ParseVNode(XFILE *, dump_parser *);
/* directory.c - Directory parsing and lookup */
extern afs_uint32 ParseDirectory(XFILE *, dump_parser *, afs_uint32, int);
extern afs_uint32 DirectoryLookup(XFILE *, dump_parser *, afs_uint32,
char **, afs_uint32 *, afs_uint32 *);
/* dump.c - Dump parts of a volume dump */
extern afs_uint32 DumpDumpHeader(XFILE *, afs_dump_header *);
extern afs_uint32 DumpVolumeHeader(XFILE *, afs_vol_header *);
extern afs_uint32 DumpVNode(XFILE *, afs_vnode *);
extern afs_uint32 DumpVnodeData(XFILE *, char *, afs_uint32);
extern afs_uint32 CopyVnodeData(XFILE *, XFILE *, afs_uint32);
/* pathname.c - Follow and construct pathnames */
extern afs_uint32 Path_PreScan(XFILE *, path_hashinfo *, int);
extern void Path_FreeHashTable(path_hashinfo *);
extern afs_uint32 Path_Follow(XFILE *, path_hashinfo *, char *, vhash_ent *);
extern afs_uint32 Path_Build(XFILE *, path_hashinfo *, afs_uint32, char **, int);
#endif

View File

@ -0,0 +1,37 @@
# COPYRIGHT NOTICE
# Copyright (c) 1997 Carnegie Mellon University
# All Rights Reserved.
#
# Permission to use, copy, modify and distribute this software and its
# documentation is hereby granted, provided that both the copyright
# notice and this permission notice appear in all copies of the
# software, derivative works or modified versions, and any portions
# thereof, and that both notices appear in supporting documentation.
#
# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
# CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
#
# Carnegie Mellon requests users of this software to return to
#
# Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
# School of Computer Science
# Carnegie Mellon University
# Pittsburgh PA 15213-3890
#
# any improvements or extensions that they make and grant Carnegie Mellon
# the rights to redistribute these changes.
# UB - Unified Backups
# methods/afs/dumpscan/afsdump_errs.et - AFS dump scanner errors
error_table AVds
ec DSERR_TAG, "Unknown tag in AFS volume dump"
ec DSERR_MAGIC, "Bad magic number in AFS volume dump"
ec DSERR_BOGUS, "Bogus value in AFS volume dump"
ec DSERR_FMT, "AFS volume dump format incorrect"
ec DSERR_KEEP, "[AFS dumpscan internal: keep string]"
ec DSERR_PANIC, "[AFS dumpscan internal: panic]"
ec DSERR_DONE, "[AFS dumpscan internal: done]"
ec DSERR_MEM, "[AFS dumpscan internal: out of memory]"
end

2640
src/tests/dumptool.c Normal file

File diff suppressed because it is too large Load Diff

407
src/tests/int64.c Normal file
View File

@ -0,0 +1,407 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* int64.c - Support for 64-bit integers */
#include <stdio.h>
#include <string.h>
#include "intNN.h"
char *hexify_int64(u_int64 *X, char *buf)
{
static char mybuf[17];
#ifdef NATIVE_INT64
char c, *p;
u_int64 x = *X;
if (!buf) buf = mybuf;
p = buf + 16;
*p-- = 0;
while (x && p >= buf) {
c = x & 0xf;
c += ((c < 10) ? '0' : 'a' - 10);
*p-- = c;
x >>= 4;
}
while (p >= buf) *p-- = '0';
#else
if (!buf) buf = mybuf;
sprintf(buf, "%08lx%08lx", X->hi, X->lo);
#endif
return buf;
}
#ifdef NATIVE_INT64
char *decimate_int64(u_int64 *X, char *buf)
{
static char mybuf[21];
char *p;
u_int64 x = *X;
if (!buf) buf = mybuf;
p = buf + 21;
*--p = 0;
while (x && p > buf) {
*--p = ((x % 10) + '0');
x /= 10;
}
if (!*p) *--p = '0';
return p;
}
#else
static char bitvals[64][21] = {
/* 1 */ "00000000000000000001",
/* 2 */ "00000000000000000002",
/* 4 */ "00000000000000000004",
/* 8 */ "00000000000000000008",
/* 10 */ "00000000000000000016",
/* 20 */ "00000000000000000032",
/* 40 */ "00000000000000000064",
/* 80 */ "00000000000000000128",
/* 100 */ "00000000000000000256",
/* 200 */ "00000000000000000512",
/* 400 */ "00000000000000001024",
/* 800 */ "00000000000000002048",
/* 1000 */ "00000000000000004096",
/* 2000 */ "00000000000000008192",
/* 4000 */ "00000000000000016384",
/* 8000 */ "00000000000000032768",
/* 10000 */ "00000000000000065536",
/* 20000 */ "00000000000000131072",
/* 40000 */ "00000000000000262144",
/* 80000 */ "00000000000000524288",
/* 100000 */ "00000000000001048576",
/* 200000 */ "00000000000002097152",
/* 400000 */ "00000000000004194304",
/* 800000 */ "00000000000008388608",
/* 1000000 */ "00000000000016777216",
/* 2000000 */ "00000000000033554432",
/* 4000000 */ "00000000000067108864",
/* 8000000 */ "00000000000134217728",
/* 10000000 */ "00000000000268435456",
/* 20000000 */ "00000000000536870912",
/* 40000000 */ "00000000001073741824",
/* 80000000 */ "00000000002147483648",
/* 100000000 */ "00000000004294967296",
/* 200000000 */ "00000000008589934592",
/* 400000000 */ "00000000017179869184",
/* 800000000 */ "00000000034359738368",
/* 1000000000 */ "00000000068719476736",
/* 2000000000 */ "00000000137438953472",
/* 4000000000 */ "00000000274877906944",
/* 8000000000 */ "00000000549755813888",
/* 10000000000 */ "00000001099511627776",
/* 20000000000 */ "00000002199023255552",
/* 40000000000 */ "00000004398046511104",
/* 80000000000 */ "00000008796093022208",
/* 100000000000 */ "00000017592186044416",
/* 200000000000 */ "00000035184372088832",
/* 400000000000 */ "00000070368744177664",
/* 800000000000 */ "00000140737488355328",
/* 1000000000000 */ "00000281474976710656",
/* 2000000000000 */ "00000562949953421312",
/* 4000000000000 */ "00001125899906842624",
/* 8000000000000 */ "00002251799813685248",
/* 10000000000000 */ "00004503599627370496",
/* 20000000000000 */ "00009007199254740992",
/* 40000000000000 */ "00018014398509481984",
/* 80000000000000 */ "00036028797018963968",
/* 100000000000000 */ "00072057594037927936",
/* 200000000000000 */ "00144115188075855872",
/* 400000000000000 */ "00288230376151711744",
/* 800000000000000 */ "00576460752303423488",
/* 1000000000000000 */ "01152921504606846976",
/* 2000000000000000 */ "02305843009213693952",
/* 4000000000000000 */ "04611686018427387904",
/* 8000000000000000 */ "09223372036854775808" };
static void prep_table(void)
{
int bit, digit;
if (bitvals[0][0] < '0') return;
for (bit = 0; bit < 64; bit++)
for (digit = 0; digit < 20; digit++)
bitvals[bit][digit] -= '0';
}
static void add_bit(int bit, char *answer)
{
int digit;
for (digit = 19; digit >= 0; digit--) {
answer[digit] += bitvals[bit][digit];
if (!digit) break;
while(answer[digit] > 9) {
answer[digit] -= 10;
answer[digit-1]++;
}
}
}
static void decimate(unsigned long hi, unsigned long lo, char *answer)
{
unsigned long mask;
int bit, digit;
memset(answer, 0, 21);
for (bit = 0, mask = 1; bit < 32; bit++, mask <<= 1)
if (lo&mask) add_bit(bit, answer);
for (bit = 0, mask = 1; bit < 32; bit++, mask <<= 1)
if (hi&mask) add_bit(bit + 32, answer);
for (digit = 0; digit < 20; digit++)
answer[digit] += '0';
}
char *decimate_int64(u_int64 *X, char *buf)
{
static char mybuf[21];
char *p;
prep_table();
if (!buf) buf = mybuf;
decimate(X->hi, X->lo, buf);
for (p = buf; *p == '0'; p++);
return (*p) ? p : p-1;
}
#endif /* NATIVE_INT64 */
void shift_int64(u_int64 *X, int bits)
{
#ifdef NATIVE_INT64
if (bits < 0) *X >>= (-bits);
else *X <<= bits;
#else
if (bits < 0) {
bits = -bits;
if (bits >= 32) {
X->lo = ((X->hi & 0xffffffffL) >> (bits - 32));
X->hi = 0;
} else {
X->lo = ((X->lo & 0xffffffffL) >> bits)
| ((X->hi & ((1 << (32 - bits)) - 1)) << (32 - bits));
X->hi = ((X->hi & 0xffffffffL) >> bits);
}
} else {
if (bits >= 32) {
X->hi = ((X->lo & 0xffffffffL) << (bits - 32));
X->lo = 0;
} else {
X->hi = ((X->hi & 0xffffffffL) << bits)
| ((X->lo & (((1 << bits) - 1) << (32 - bits))) >> (32 - bits));
X->lo = ((X->lo & 0xffffffffL) << bits);
}
}
#endif
}
#ifdef TEST_INT64
/** the rest of this is for testing the int64 suite **/
#ifdef NATIVE_INT64
#define xize(x) #x
#define stringize(x) xize(x)
#define INT64_NAME stringize(unsigned NATIVE_INT64)
#endif /* NATIVE_INT64 */
void verify_int64_size () {
#ifdef NATIVE_INT64
signed char testchar = -1;
unsigned int testint = (unsigned char)testchar;
printf("We think '%s' is a native 64-bit type\n", INT64_NAME);
if (testint != 0xff) {
printf("testint = 0x%x; should be 0xff\n", testint);
fprintf(stderr, "Hmm... char's are not 8 bits. That sucks!\n");
exit(-1);
}
printf("Looks like a char is 8 bits...\n");
if (sizeof(unsigned NATIVE_INT64) != 8) {
printf("sizeof(%s) = %d; should be 8\n", INT64_NAME, sizeof(unsigned NATIVE_INT64));
fprintf(stderr, "Hey! You said a %s was 64-bits wide!\n", INT64_NAME);
exit(-1);
}
printf("Yippee! We have a native 64-bit type (%s)\n\n", INT64_NAME);
#else /* !NATIVE_INT64 */
printf("Using fake 64-bit integers...\n\n");
#endif /* NATIVE_INT64 */
}
void test_int64_constructs(void)
{
u_int64 x, y;
afs_uint32 hi, lo;
int failures = 0, pass;
char buf[17];
printf("Constructor/accessor tests:\n");
printf("Setting x := %s\n", INT64_TEST_STR);
mk64(x, INT64_TEST_HI, INT64_TEST_LO);
#ifdef NATIVE_INT64
pass = (x == INT64_TEST_CONST);
hexify_int64(&x, buf);
printf("NATIVE mk64: x = 0x%16s %s\n",
buf, pass ? "PASSED" : "FAILED");
if (!pass) failures++;
#else
pass = (x.hi == INT64_TEST_HI && x.lo == INT64_TEST_LO);
printf("FAKE mk64: x.hi = 0x%08lx x.lo = 0x%08lx %s\n",
x.hi, x.lo, pass ? "PASSED" : "FAILED");
if (!pass) failures++;
#endif
pass = (hi64(x) == INT64_TEST_HI && lo64(x) == INT64_TEST_LO);
printf("hi64/lo64: hi64(x) = 0x%08lx lo64(x) = 0x%08lx %s\n",
hi64(x), lo64(x), pass ? "PASSED" : "FAILED");
if (!pass) failures++;
ex64(x, hi, lo);
pass = (hi == INT64_TEST_HI && lo == INT64_TEST_LO);
printf("ex64: hi = 0x%08lx lo = 0x%08lx %s\n",
hi, lo, pass ? "PASSED" : "FAILED");
if (!pass) failures++;
cp64(y, x);
pass = (hi64(y) == INT64_TEST_HI && lo64(y) == INT64_TEST_LO);
printf("cp64: hi64(y) = 0x%08lx lo64(y) = 0x%08lx %s\n",
hi64(y), lo64(y), pass ? "PASSED" : "FAILED");
if (!pass) failures++;
if (failures) printf("%d/4 tests FAILED\n\n", failures);
else printf("All 4 tests PASSED\n\n");
}
void test_int64_compares()
{
#define NCOMPARE 9
u_int64 control, test[NCOMPARE];
char cbuf[17], tbuf[17];
int i, r, result[NCOMPARE];
int pass, failures, FAILURES = 0;
printf("Comparison tests:\n");
mk64(control, 0x12345678, 0xabcdabcd);
mk64(test[0], 0x12340000, 0xabcd0000); result[0] = +1;
mk64(test[1], 0x12340000, 0xabcdabcd); result[1] = +1;
mk64(test[2], 0x12340000, 0xabcdffff); result[2] = +1;
mk64(test[3], 0x12345678, 0xabcd0000); result[3] = +1;
mk64(test[4], 0x12345678, 0xabcdabcd); result[4] = 0;
mk64(test[5], 0x12345678, 0xabcdffff); result[5] = -1;
mk64(test[6], 0x1234ffff, 0xabcd0000); result[6] = -1;
mk64(test[7], 0x1234ffff, 0xabcdabcd); result[7] = -1;
mk64(test[8], 0x1234ffff, 0xabcdffff); result[8] = -1;
for (i = 0; i < NCOMPARE; i++) {
failures = 0;
hexify_int64(&control, cbuf);
hexify_int64(&test[i], tbuf);
r = eq64(control, test[i]);
pass = (r == (result[i] == 0)); if (!pass) failures++;
printf("0x%s == 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
r = ne64(control, test[i]);
pass = (r == (result[i] != 0)); if (!pass) failures++;
printf("0x%s != 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
r = lt64(control, test[i]);
pass = (r == (result[i] < 0)); if (!pass) failures++;
printf("0x%s < 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
r = le64(control, test[i]);
pass = (r == (result[i] <= 0)); if (!pass) failures++;
printf("0x%s <= 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
r = gt64(control, test[i]);
pass = (r == (result[i] > 0)); if (!pass) failures++;
printf("0x%s > 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
r = ge64(control, test[i]);
pass = (r == (result[i] >= 0)); if (!pass) failures++;
printf("0x%s >= 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
r = zero64(test[i]);
pass = !r; if (!pass) failures++;
printf("0x%s is nonzero %s\n",
tbuf, pass ? "PASSED" : "FAILED");
if (failures) printf("%d/7 tests on this pair FAILED\n\n", failures);
else printf("All 7 tests on this pair PASSED\n\n");
}
mk64(control, 0, 0);
pass = zero64(control); if (!pass) FAILURES++;
printf("0x0000000000000000 is zero %s\n",
pass ? "PASSED" : "FAILED");
if (FAILURES)
printf("%d/%d comparison tests FAILED\n\n", FAILURES, 7 * NCOMPARE + 1);
else
printf("All %d comparison tests PASSED\n\n", 7 * NCOMPARE + 1);
}
void test_int64_arith()
{
printf("No arithmetic tests yet!!!\n");
}
void main() {
verify_int64_size();
test_int64_constructs();
test_int64_compares();
test_int64_arith();
exit(0);
}
#endif

155
src/tests/intNN.h Normal file
View File

@ -0,0 +1,155 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
#ifndef _INTNN_H_
#define _INTNN_H_
/* intNN.h - Sized integer types */
#include <afs/stds.h>
#if 0
typedef short afs_int16;
typedef unsigned short afs_uint16;
typedef long afs_int32;
typedef unsigned long afs_uint32;
#endif
/* Support for 64-bit integers.
* Presently, only unsigned 64-bit numbers are supported.
*/
#define INT64_TEST_STR "0x12345678fedcba98"
#define INT64_TEST_HI 0x12345678
#define INT64_TEST_LO 0xfedcba98
#ifdef NATIVE_INT64
typedef unsigned NATIVE_INT64 u_int64;
/* construct/extract/assign */
#define mk64(X,H,L) ((X) = ( ((u_int64)(H) << 32) \
| ((u_int64)(L) & 0xffffffff)))
#define hi64(Y) ((afs_uint32)(((Y) >> 32) & 0xffffffff))
#define lo64(Y) ((afs_uint32)((Y) & 0xffffffff))
#define ex64(Y,H,L) ((H) = hi64(Y), (L) = lo64(Y))
#define cp64(X,Y) ((X) = (Y))
#define get64(X) (X)
#define set64(X,V) ((X) = (V))
/* Comparison */
#define eq64(X,Y) ((X) == (Y))
#define ne64(X,Y) ((X) != (Y))
#define lt64(X,Y) ((X) < (Y))
#define le64(X,Y) ((X) <= (Y))
#define gt64(X,Y) ((X) > (Y))
#define ge64(X,Y) ((X) >= (Y))
#define zero64(X) (!(X))
/* Arithmetic */
#define add64_32(X,A,B) ((X) = (A) + (u_int64)(B))
#define add64_64(X,A,B) ((X) = (A) + (B))
#define sub64_32(X,A,B) ((X) = (A) - (u_int64)(B))
#define sub64_64(X,A,B) ((X) = (A) - (B))
/* Byte-order */
#ifdef WORDS_BIGENDIAN
#define hton64(X,Y) cp64(X,Y)
#define ntoh64(X,Y) cp64(X,Y)
#else
#define hton64(X,Y) mk64(X,htonl(lo64(Y)),htonl(hi64(Y)))
#define ntoh64(X,Y) mk64(X,ntohl(lo64(Y)),ntohl(hi64(Y)))
#endif
#else /* !NATIVE_INT64 */
/** We have to provide our own 64-bit integers **/
typedef struct { afs_uint32 hi, lo; } u_int64;
/* construct/extract/assign */
#define mk64(X,H,L) ((X).hi = (H), (X).lo = (L))
#define ex64(Y,H,L) ((H) = (Y).hi, (L) = (Y).lo)
#define hi64(Y) ((Y).hi)
#define lo64(Y) ((Y).lo)
#define cp64(X,Y) ((X).hi = (Y).hi, (X).lo = (Y).lo)
#define get64(X) ((X).lo)
#define set64(X,V) ((X).hi = 0, (X).lo = (V))
/* Comparison */
#define eq64(A,B) ((A).hi == (B).hi && (A).lo == (B).lo)
#define ne64(A,B) ((A).hi != (B).hi || (A).lo != (B).lo)
#define lt64(A,B) ((A).hi < (B).hi || ((A).hi == (B).hi && (A).lo < (B).lo))
#define le64(A,B) ((A).hi < (B).hi || ((A).hi == (B).hi && (A).lo <= (B).lo))
#define gt64(A,B) ((A).hi > (B).hi || ((A).hi == (B).hi && (A).lo > (B).lo))
#define ge64(A,B) ((A).hi > (B).hi || ((A).hi == (B).hi && (A).lo >= (B).lo))
#define zero64(X) ((X).hi == 0 && (X).lo == 0)
/* Arithmetic */
#define add64_32(X,A,B) ( \
(X).lo = (A).lo + (B), \
(X).hi = (A).hi + \
(((((A).lo & 0x80000000) ^ ((B) & 0x80000000)) && !((X).lo & 0x80000000)) \
|| (((A).lo & 0x80000000) && ((B) & 0x80000000))) \
)
#define add64_64(X,A,B) (add64_32(X,A,(B).lo), (X).hi += (B).hi)
#define sub64_32(X,A,B) ((X).lo = (A).lo - (B), \
(X).hi = (A).hi - ((A).lo < (B)))
#define sub64_64(X,A,B) (sub64_32(X,A,(B).lo), (X).hi -= (B).hi)
/* Byte-order */
#define hton64(X,Y) mk64(X,htonl(hi64(Y)),htonl(lo64(Y)))
#define ntoh64(X,Y) mk64(X,ntohl(hi64(Y)),ntohl(lo64(Y)))
#endif /* NATIVE_INT64 */
/* The following are too complex to be macros: */
/* char *hexify_int64(u_int64 a, char *buf)
* Produces an ASCII representation of a in hexadecimal, and returns
* a pointer to the resulting string. If buf is non-NULL, it is taken
* to be a pointer to the buffer to be used, which must be at least 17
* bytes long. This function is thread-safe iff buf is provided.
*/
extern char *hexify_int64(u_int64 *, char *);
/* char *decimate_int64(u_int64 a, char *buf)
* Produces an ASCII representation of a in decimal, and returns
* a pointer to the resulting string. If buf is non-NULL, it is taken
* to be a pointer to the buffer to be used, which must be at least 21
* bytes long. This function is thread-safe iff buf is provided.
*/
extern char *decimate_int64(u_int64 *, char *);
/* void shift_int64(u_int64 a, int bits)
* Shifts the 64-bit integer in a by the specified number of bits.
* If bits is positive, the shift is to the left; if negative, the
* shift is to the right.
*/
extern void shift_int64(u_int64 *, int);
#endif /* _INTNN_H_ */

55
src/tests/internal.h Normal file
View File

@ -0,0 +1,55 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* internal.h - Routines for internal use only */
#include "xfiles.h"
#include "dumpscan.h"
/* parsevol.c - Routines to parse volume headers */
extern afs_uint32 parse_volhdr(XFILE *, unsigned char *, tagged_field *, afs_uint32,
tag_parse_info *, void *, void *);
/* parsevnode.c - Routines to parse vnodes and their fields */
extern afs_uint32 parse_vnode(XFILE *, unsigned char *, tagged_field *, afs_uint32,
tag_parse_info *, void *, void *);
/* directory.c - Routines for parsing AFS directories */
extern afs_uint32 parse_directory(XFILE *, dump_parser *, afs_vnode *,
afs_uint32, int);
/* backuphdr.c - Generic support for backup system headers */
extern afs_uint32 try_backuphdr(XFILE *X, unsigned char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon);
/* util.c - Random utilities */
extern afs_uint32 handle_return(int, XFILE *, unsigned char, dump_parser *);
extern void prep_pi(dump_parser *, tag_parse_info *);
extern afs_uint32 match_next_vnode(XFILE *, dump_parser *, u_int64 *, afs_uint32);

150
src/tests/null-search.c Normal file
View File

@ -0,0 +1,150 @@
#include <sys/fcntl.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "dumpscan.h"
char *argv0;
static char *input_path = 0;
static int quiet = 0, showpaths = 0, searchcount = 1;
static int error_count = 0, bad_count = 0;
static path_hashinfo phi;
static dump_parser dp;
/* Print a usage message and exit */
static void usage(int status, char *msg)
{
if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
fprintf(stderr, " -h Print this help message\n");
fprintf(stderr, " -p Print paths of bad vnodes\n");
fprintf(stderr, " -q Quiet mode (don't print errors)\n");
exit(status);
}
/* Parse the command-line options */
static void parse_options(int argc, char **argv)
{
int c;
if (argv0 = strrchr(argv[0], '/')) argv0++;
else argv0 = argv[0];
/* Parse the options */
while ((c = getopt(argc, argv, "n:hpq")) != EOF) {
switch (c) {
case 'n': searchcount = atoi(optarg); continue;
case 'p': showpaths = 1; continue;
case 'q': quiet = 1; continue;
case 'h': usage(0, 0);
default: usage(1, "Invalid option!");
}
}
if (argc - optind > 1) usage(1, "Too many arguments!");
input_path = (argc == optind) ? "-" : argv[optind];
}
/* A callback to count and print errors */
static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
{
va_list alist;
error_count++;
if (!quiet) {
va_start(alist, msg);
com_err_va(argv0, code, msg, alist);
va_end(alist);
}
}
/* A callback to process file vnodes */
static afs_uint32 my_file_cb(afs_vnode *v, XFILE *X, void *refcon)
{
static char buf[1024];
afs_uint32 size, nulls, cnulls, maxcnulls, n, r;
char *name = 0;
int i;
nulls = cnulls = maxcnulls = 0;
size = v->size;
if ((r = xfseek(X, &v->d_offset))) return r;
while (size) {
n = (size > 1024) ? 1024 : size;
if (r = xfread(X, buf, n)) return r;
for (i = 0; i < n; i++) {
if (buf[i]) {
if (cnulls > maxcnulls) maxcnulls = cnulls;
cnulls = 0;
} else {
nulls++;
cnulls++;
}
}
size -= n;
}
if (maxcnulls >= searchcount) {
bad_count++;
if (showpaths) Path_Build(X, &phi, v->vnode, &name, 0);
if (name) {
printf("*** BAD %d (%s) - %d nulls, %d consecutive\n",
v->vnode, name, nulls, maxcnulls);
free(name);
} else {
printf("*** BAD %d - %d nulls, %d consecutive\n",
v->vnode, nulls, maxcnulls);
}
}
return r;
}
int main(int argc, char **argv)
{
XFILE input_file;
afs_uint32 r;
parse_options(argc, argv);
initialize_acfg_error_table();
initialize_AVds_error_table();
initialize_rxk_error_table();
initialize_u_error_table();
initialize_vl_error_table();
initialize_vols_error_table();
initialize_xFil_error_table();
r = xfopen(&input_file, O_RDONLY, input_path);
if (r) {
com_err(argv0, r, "opening %s", input_path);
exit(2);
}
memset(&dp, 0, sizeof(dp));
dp.cb_error = my_error_cb;
if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
if (showpaths) {
u_int64 where;
memset(&phi, 0, sizeof(phi));
phi.p = &dp;
if ((r = xftell(&input_file, &where))
|| (r = Path_PreScan(&input_file, &phi, 0))
|| (r = xfseek(&input_file, &where))) {
com_err(argv0, r, "- path initialization failed");
xfclose(&input_file);
exit(2);
}
}
dp.cb_vnode_file = my_file_cb;
r = ParseDumpFile(&input_file, &dp);
xfclose(&input_file);
if (error_count) printf("*** %d errors\n", error_count);
if (bad_count) printf("*** %d bad files\n", bad_count);
if (r && !quiet) printf("*** FAILED: %s\n", error_message(r));
}

258
src/tests/parsedump.c Normal file
View File

@ -0,0 +1,258 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* parsedump.c - Parse a volume dump file */
#include "dumpscan.h"
#include "dumpscan_errs.h"
#include "dumpfmt.h"
#include "internal.h"
#include "stagehdr.h"
static afs_uint32 parse_dumphdr (XFILE *, unsigned char *, tagged_field *,
afs_uint32, tag_parse_info *, void *, void *);
static afs_uint32 parse_dumpend (XFILE *, unsigned char *, tagged_field *,
afs_uint32, tag_parse_info *, void *, void *);
static afs_uint32 store_dumphdr (XFILE *, unsigned char *, tagged_field *,
afs_uint32, tag_parse_info *, void *, void *);
static afs_uint32 parse_dumptimes(XFILE *, unsigned char *, tagged_field *,
afs_uint32, tag_parse_info *, void *, void *);
/** Field list for top-level objects **/
static tagged_field top_fields[] = {
{ TAG_DUMPHEADER, DKIND_SPECIAL, "* DUMP HEADER", parse_dumphdr, 0, 0 },
{ TAG_VOLHEADER, DKIND_SPECIAL, "* VOLUME HEADER", parse_volhdr, 0, 0 },
{ TAG_VNODE, DKIND_SPECIAL, "* VNODE ", parse_vnode, 0, 0 },
{ TAG_DUMPEND, DKIND_INT32, "* DUMP END", parse_dumpend, 0, 0 },
{ STAGE_VERSMIN, DKIND_SPECIAL, "* STAGE HEADER", try_backuphdr, 0, 0 },
{ 0,0,0,0,0,0 }};
/** Field list for dump headers **/
static tagged_field dumphdr_fields[] = {
{ DHTAG_VOLNAME, DKIND_STRING, " Volume name: ", store_dumphdr, 0, 0 },
{ DHTAG_VOLID, DKIND_INT32, " Volume ID: ", store_dumphdr, 0, 0 },
{ DHTAG_DUMPTIMES, DKIND_SPECIAL, " Dump Range: ", parse_dumptimes, 0, 0 },
{ 0,0,0,0,0,0 }};
/* Parse a dump header, including its tagged attributes, and call the
* dump-header callback, if one is defined.
*/
static afs_uint32 parse_dumphdr(XFILE *X, unsigned char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
dump_parser *p = (dump_parser *)g_refcon;
afs_dump_header hdr;
u_int64 where;
afs_uint32 r;
memset(&hdr, 0, sizeof(hdr));
if (r = xftell(X, &where)) return r;
sub64_32(hdr.offset, where, 1);
if (r = ReadInt32(X, &hdr.magic)) return r;
if (r = ReadInt32(X, &hdr.version)) return r;
if (hdr.magic != DUMPBEGINMAGIC) {
if (p->cb_error)
(p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
"Invalid magic number (0x%08x) in dump header",
hdr.magic);
return DSERR_MAGIC;
}
if (hdr.version != DUMPVERSION) {
if (p->cb_error)
(p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
"Unknown dump format version (%d) in dump header",
hdr.version);
return DSERR_MAGIC;
}
if (p->print_flags & DSPRINT_DUMPHDR)
printf("%s [%s = 0x%s]\n", field->label,
decimate_int64(&hdr.offset, 0), hexify_int64(&hdr.offset, 0));
if (p->print_flags & DSPRINT_DUMPHDR) {
printf(" Magic number: 0x%08x\n", hdr.magic);
printf(" Version: %d\n", hdr.version);
}
r = ParseTaggedData(X, dumphdr_fields, tag, pi, g_refcon, (void *)&hdr);
if (!r && p->cb_dumphdr) {
r = xftell(X, &where);
if (!r) r = (p->cb_dumphdr)(&hdr, X, p->refcon);
if (p->flags & DSFLAG_SEEK) {
if (!r) r = xfseek(X, &where);
else xfseek(X, &where);
}
}
if (hdr.field_mask & F_DUMPHDR_VOLNAME)
free(hdr.volname);
return r;
}
/* Store tagged attributes into a dump header */
static afs_uint32 store_dumphdr(XFILE *X, unsigned char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
dump_parser *p = (dump_parser *)g_refcon;
afs_dump_header *hdr = (afs_dump_header *)l_refcon;
switch (field->tag) {
case DHTAG_VOLID:
hdr->field_mask |= F_DUMPHDR_VOLID;
hdr->volid = value;
if (p->print_flags & DSPRINT_DUMPHDR)
printf("%s%d\n", field->label, hdr->volid);
return 0;
case DHTAG_VOLNAME:
if (tag && tag[0]) {
hdr->field_mask |= F_DUMPHDR_VOLNAME;
hdr->volname = tag;
if (p->print_flags & DSPRINT_DUMPHDR)
printf("%s%s\n", field->label, hdr->volname);
return DSERR_KEEP;
} else return 0;
default:
if (p->print_flags & DSPRINT_DUMPHDR)
printf("%s<<< UNKNOWN FIELD >>>\n", field->label);
return 0;
}
}
/* Parse and store the dump time range from a dump header */
static afs_uint32 parse_dumptimes(XFILE *X, unsigned char *tag,
tagged_field *field, afs_uint32 value,
tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
dump_parser *p = (dump_parser *)g_refcon;
afs_dump_header *hdr = (afs_dump_header *)l_refcon;
afs_uint16 count;
afs_uint32 r;
if (r = ReadInt16(X, &count)) return r;
if (count != 2) {
if (p->cb_error)
(p->cb_error)(DSERR_FMT, 1, p->err_refcon,
"Incorrect array count (%d) in dump times", count);
return DSERR_FMT;
}
if (r = ReadInt32(X, &hdr->from_date)) return r;
if (r = ReadInt32(X, &hdr->to_date)) return r;
hdr->field_mask |= (F_DUMPHDR_FROM | F_DUMPHDR_TO);
if (p->print_flags & DSPRINT_DUMPHDR)
printf("%s%d => %d\n", field->label, hdr->from_date, hdr->to_date);
return ReadByte(X, tag);
}
/* Parse a dump_end record */
static afs_uint32 parse_dumpend(XFILE *X, unsigned char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
dump_parser *p = (dump_parser *)g_refcon;
afs_uint32 r;
if (value != DUMPENDMAGIC) {
if (p->cb_error)
(p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
"Invalid magic number (0x%08x) in dump trailer",
value);
return DSERR_MAGIC;
}
if (p->print_flags & (DSPRINT_DUMPHDR | DSPRINT_ITEM))
printf("%s\n", field->label);
return DSERR_DONE;
}
afs_uint32 ParseDumpFile(XFILE *X, dump_parser *p)
{
tag_parse_info pi;
unsigned char tag;
afs_uint32 r;
prep_pi(p, &pi);
r = ParseTaggedData(X, top_fields, &tag, &pi, (void *)p, 0);
return handle_return(r, X, tag, p);
}
afs_uint32 ParseDumpHeader(XFILE *X, dump_parser *p)
{
tag_parse_info pi;
unsigned char tag;
afs_uint32 r;
prep_pi(p, &pi);
if (r = ReadByte(X, &tag)) return handle_return(r, X, tag, p);
if (tag != TAG_DUMPHEADER) return handle_return(0, X, tag, p);
r = parse_dumphdr(X, &tag, &top_fields[0], 0, &pi, (void *)p, 0);
if (!r && tag >= 1 && tag <= 4) r = DSERR_DONE;
return handle_return(r, X, tag, p);
}
afs_uint32 ParseVolumeHeader(XFILE *X, dump_parser *p)
{
tag_parse_info pi;
unsigned char tag;
afs_uint32 r;
prep_pi(p, &pi);
if (r = ReadByte(X, &tag)) return handle_return(r, X, tag, p);
if (tag != TAG_VOLHEADER) return handle_return(0, X, tag, p);
r = parse_volhdr(X, &tag, &top_fields[1], 0, &pi, (void *)p, 0);
if (!r && tag >= 1 && tag <= 4) r = DSERR_DONE;
return handle_return(r, X, tag, p);
}
afs_uint32 ParseVNode(XFILE *X, dump_parser *p)
{
tag_parse_info pi;
unsigned char tag;
afs_uint32 r;
prep_pi(p, &pi);
if (r = ReadByte(X, &tag)) return handle_return(r, X, tag, p);
if (tag != TAG_VNODE) return handle_return(0, X, tag, p);
r = parse_vnode(X, &tag, &top_fields[2], 0, &pi, (void *)p, 0);
if (!r && tag >= 1 && tag <= 4) r = DSERR_DONE;
return handle_return(r, X, tag, p);
}

174
src/tests/parsetag.c Normal file
View File

@ -0,0 +1,174 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* parsetag.c - Parse a tagged data stream */
#include "dumpscan.h"
#include "dumpscan_errs.h"
/* If a parser function is defined, it will be called after the data value
* (if any) is read. The parser is called as follows:
*
* parser(input_file, &tag, &field_rec, value, g_refcon, l_refcon);
*
* - input_file is the FILE * for the input stream
* - field_rec is a pointer to the field record for the field just read
* - g_refcon and l_refcon are as passed in to ParseTaggedData
* - For integer types, value is the integer value
* - For DKIND_STRING, tag is a pointer to the string just read
* - For DKIND_SPEACH, tag is a pointer to the place to put the next tag.
*
* If the field type is DKIND_SPECIAL, the parser is expected to read its
* own data from the input stream, and return when ParseTaggedData is supposed
* to take over, with the next tag to process in *tag. At no other time
* should the parser read, write, or reposition the input stream.
*
* The parser routine should return 0 on success, non-0 on failure. If the
* data type is DKIND_STRING, the parser may return DSERR_KEEP to indicate
* that the memory allocated for the value should not be freed.
*/
/* Parse a file containing tagged data and attributes **/
afs_uint32 ParseTaggedData(XFILE *X, tagged_field *fields, unsigned char *tag,
tag_parse_info *pi, void *g_refcon, void *l_refcon)
{
int i = -1;
afs_uint32 r, val;
afs_uint16 val16;
unsigned char val8;
unsigned char *strval;
for (;;) {
if (i < 0 || (fields[i].kind & DKIND_MASK) != DKIND_SPECIAL) {
/* Need to read in a tag */
if (r = ReadByte(X, tag)) return r;
}
/* Simple error recovery - if we encounter a 0, it can never be
* a valid tag. If TPFLAG_SKIP is set, we can skip over any
* such null bytes, and process whatever tag we find beyond.
* In addition, if TPFLAG_RSKIP is set, then the next time
* we encounter a 0, try skipping backwards. That seems to
* work much of the time.
*/
if (!*tag && pi->shift_offset && (pi->flags & TPFLAG_RSKIP)) {
u_int64 where, tmp64a, tmp64b;
char buf1[21], buf2[21], buf3[21];
char *p1, *p2, *p3;
if (r = xftell(X, &tmp64a)) return r;
sub64_32(where, tmp64a, pi->shift_offset + 1);
if (r = xfseek(X, &where)) return r;
if (pi->cb_error){
(pi->cb_error)(DSERR_FMT, 0, pi->err_refcon,
"Inserted %d bytes before offset %d",
pi->shift_offset, decimate_int64(&where, 0));
add64_32(tmp64a, pi->shift_start, pi->shift_offset);
p1 = decimate_int64(&tmp64a, buf1);
sub64_64(tmp64b, where, tmp64a);
p2 = decimate_int64(&tmp64b, buf2);
p3 = decimate_int64(&pi->shift_start, buf3);
(pi->cb_error)(DSERR_FMT, 0, pi->err_refcon,
">>> SHIFT start=%s length=%s target=%s",
p1, p2, p3);
}
pi->shift_offset = 0;
if (r = ReadByte(X, tag)) return r;
}
if (!*tag && (pi->flags & TPFLAG_SKIP)) {
int count = 0;
u_int64 where, tmp64a;
if (r = xftell(X, &where)) return r;
while (!*tag) {
if (r = ReadByte(X, tag)) return r;
count++;
}
pi->shift_offset += count;
cp64(pi->shift_start, where);
if (pi->cb_error) {
sub64_32(tmp64a, where, 1);
(pi->cb_error)(DSERR_FMT, 0, pi->err_refcon,
"Skipped %d bytes at offset %s",
count, decimate_int64(&tmp64a, 0));
}
}
for (i = 0; fields[i].tag && fields[i].tag != *tag; i++);
if (!fields[i].tag) return 0;
switch (fields[i].kind & DKIND_MASK) {
case DKIND_NOOP:
if (fields[i].func) {
r = (fields[i].func)(X, 0, fields+i, 0, pi, g_refcon, l_refcon);
if (r) return r;
}
break;
case DKIND_BYTE:
if (r = ReadByte(X, &val8)) return r;
if (fields[i].func) {
r = (fields[i].func)(X, 0, fields+i, val8, pi, g_refcon, l_refcon);
if (r) return r;
}
break;
case DKIND_INT16:
if (r = ReadInt16(X, &val16)) return r;
if (fields[i].func) {
r = (fields[i].func)(X, 0, fields+i, val16, pi, g_refcon, l_refcon);
if (r) return r;
}
break;
case DKIND_INT32:
if (r = ReadInt32(X, &val)) return r;
if (fields[i].func) {
r = (fields[i].func)(X, 0, fields+i, val, pi, g_refcon, l_refcon);
if (r) return r;
}
break;
case DKIND_STRING:
if (r = ReadString(X, &strval)) return r;
if (fields[i].func) {
r = (fields[i].func)(X, strval, fields+i, 0, pi, g_refcon, l_refcon);
if (r != DSERR_KEEP) free(strval);
if (r && r != DSERR_KEEP) return r;
} else free(strval);
break;
case DKIND_SPECIAL:
if (fields[i].func) {
r = (fields[i].func)(X, tag, fields+i, 0, pi, g_refcon, l_refcon);
if (r) return r;
} else i = -1;
}
}
}

427
src/tests/parsevnode.c Normal file
View File

@ -0,0 +1,427 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* parsevnode.c - Parse a VNode */
#include <sys/types.h>
#include <netinet/in.h>
#include <errno.h>
#include "dumpscan.h"
#include "dumpscan_errs.h"
#include "dumpfmt.h"
#include "internal.h"
#include <afs/acl.h>
#include <afs/prs_fs.h>
static afs_uint32 LastGoodVNode = 0;
static afs_uint32 store_vnode(XFILE *, unsigned char *, tagged_field *, afs_uint32,
tag_parse_info *, void *, void *);
static afs_uint32 parse_acl (XFILE *, unsigned char *, tagged_field *, afs_uint32,
tag_parse_info *, void *, void *);
static afs_uint32 parse_vdata(XFILE *, unsigned char *, tagged_field *, afs_uint32,
tag_parse_info *, void *, void *);
/** Field list for vnodes **/
static tagged_field vnode_fields[] = {
{ VTAG_TYPE, DKIND_BYTE, " VNode type: ", store_vnode, 0, 0 },
{ VTAG_NLINKS, DKIND_INT16, " Link count: ", store_vnode, 0, 0 },
{ VTAG_DVERS, DKIND_INT32, " Version: ", store_vnode, 0, 0 },
{ VTAG_CLIENT_DATE, DKIND_TIME, " Server Date: ", store_vnode, 0, 0 },
{ VTAG_AUTHOR, DKIND_INT32, " Author: ", store_vnode, 0, 0 },
{ VTAG_OWNER, DKIND_INT32, " Owner: ", store_vnode, 0, 0 },
{ VTAG_GROUP, DKIND_INT32, " Group: ", store_vnode, 0, 0 },
{ VTAG_MODE, DKIND_INT16, " UNIX mode: ", store_vnode, 0, 0 },
{ VTAG_PARENT, DKIND_INT32, " Parent: ", store_vnode, 0, 0 },
{ VTAG_SERVER_DATE, DKIND_TIME, " Client Date: ", store_vnode, 0, 0 },
{ VTAG_ACL, DKIND_SPECIAL, " xxxxxxxx ACL: ", parse_acl, 0, 0 },
{ VTAG_DATA, DKIND_SPECIAL, " Contents: ", parse_vdata, 0, 0 },
{ 0,0,0,0,0,0 }};
static afs_uint32 resync_vnode(XFILE *X, dump_parser *p, afs_vnode *v,
int start, int limit)
{
u_int64 where, expected_where;
afs_uint32 r;
int i;
if (r = xftell(X, &expected_where)) return r;
cp64(where, expected_where);
r = match_next_vnode(X, p, &where, v->vnode);
if (r && r != DSERR_FMT) return r;
if (r) for (i = -start; i < limit; i++) {
add64_32(where, expected_where, i);
r = match_next_vnode(X, p, &where, v->vnode);
if (!r) break;
if (r != DSERR_FMT) return r;
}
if (r) {
if (p->cb_error)
(p->cb_error)(r, 1, p->err_refcon,
"Unable to resync after vnode %d [%s = 0x%s]",
v->vnode, decimate_int64(&expected_where, 0),
hexify_int64(&expected_where, 0));
return r;
}
if (ne64(where, expected_where) && p->cb_error) {
(p->cb_error)(DSERR_FMT, 0, p->err_refcon,
"Vnode after %d not in expected location",
v->vnode);
(p->cb_error)(DSERR_FMT, 0, p->err_refcon, "Expected location: %s = 0x%s",
decimate_int64(&expected_where, 0),
hexify_int64(&expected_where, 0));
(p->cb_error)(DSERR_FMT, 0, p->err_refcon, "Actual location: %s = 0x%s",
decimate_int64(&where, 0), hexify_int64(&where, 0));
}
return xfseek(X, &where);
}
/* Parse a VNode, including any tagged attributes and data, and call the
* appropriate callback, if one is defined.
*/
afs_uint32 parse_vnode(XFILE *X, unsigned char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
dump_parser *p = (dump_parser *)g_refcon;
afs_uint32 (*cb)(afs_vnode *, XFILE *, void *);
u_int64 where, offset2k;
afs_vnode v;
afs_uint32 r;
if (r = xftell(X, &where)) return r;
memset(&v, 0, sizeof(v));
sub64_32(v.offset, where, 1);
if (r = ReadInt32(X, &v.vnode)) return r;
if (r = ReadInt32(X, &v.vuniq)) return r;
mk64(offset2k, 0, 2048);
if (!LastGoodVNode
|| ((p->flags & DSFLAG_SEEK) && v.vnode == 1
&& lt64(v.offset, offset2k)))
LastGoodVNode = -1;
if (p->print_flags & DSPRINT_ITEM) {
printf("%s %d/%d [%s = 0x%s]\n", field->label, v.vnode, v.vuniq,
decimate_int64(&where, 0), hexify_int64(&where, 0));
}
r = ParseTaggedData(X, vnode_fields, tag, pi, g_refcon, (void *)&v);
/* Try to resync, if requested */
if (!r && (p->repair_flags & DSFIX_VFSYNC)) {
afs_uint32 drop;
u_int64 xwhere;
if (r = xftell(X, &where)) return r;
sub64_32(xwhere, where, 1);
/* Are we at the start of a valid vnode (or dump end)? */
r = match_next_vnode(X, p, &xwhere, v.vnode);
if (r && r != DSERR_FMT) return r;
if (r) { /* Nope. */
/* Was _this_ a valid vnode? If so, we can keep it and search for
* the next one. Otherwise, we throw it out, and start the search
* at the starting point of this vnode.
*/
drop = r = match_next_vnode(X, p, &v.offset, LastGoodVNode);
if (r && r != DSERR_FMT) return r;
if (!r) {
add64_32(where, v.offset, 1);
if (r = xfseek(X, &v.offset)) return r;
} else {
if (r = xfseek(X, &xwhere)) return r;
}
if (r = resync_vnode(X, p, &v, 0, 1024)) return r;
if (r = ReadByte(X, tag)) return r;
if (drop) {
if (p->cb_error)
(p->cb_error)(DSERR_FMT, 0, p->err_refcon,
"Dropping vnode %d", v.vnode);
return 0;
}
} else {
if (r = xfseek(X, &where)) return r;
}
}
LastGoodVNode = v.vnode;
if (!r) {
if (v.field_mask & F_VNODE_TYPE)
switch (v.type) {
case vFile: cb = p->cb_vnode_file; break;
case vDirectory: cb = p->cb_vnode_dir; break;
case vSymlink: cb = p->cb_vnode_link; break;
default: cb = p->cb_vnode_wierd; break;
}
else cb = p->cb_vnode_empty;
if (cb) {
u_int64 where;
if (r = xftell(X, &where)) return r;
r = (cb)(&v, X, p->refcon);
if (p->flags & DSFLAG_SEEK) {
if (!r) r = xfseek(X, &where);
else xfseek(X, &where);
}
}
}
return r;
}
/* Store data in a vnode */
static afs_uint32 store_vnode(XFILE *X, unsigned char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
dump_parser *p = (dump_parser *)g_refcon;
afs_vnode *v = (afs_vnode *)l_refcon;
time_t when;
afs_uint32 r = 0;
switch (field->tag) {
case VTAG_TYPE:
v->field_mask |= F_VNODE_TYPE;
v->type = value;
if (p->print_flags & DSPRINT_VNODE) {
switch (value) {
case vFile:
printf("%sFile (%d)\n", field->label, value);
break;
case vDirectory:
printf("%sDirectory (%d)\n", field->label, value);
break;
case vSymlink:
printf("%sSymbolic Link (%d)\n", field->label, value);
break;
default:
printf("%s??? (%d)\n", field->label, value);
}
return r;
}
break;
case VTAG_NLINKS:
v->field_mask |= F_VNODE_NLINKS;
v->nlinks = value;
break;
case VTAG_DVERS:
v->field_mask |= F_VNODE_DVERS;
v->datavers = value;
break;
case VTAG_CLIENT_DATE:
v->field_mask |= F_VNODE_CDATE;
v->client_date = value;
break;
case VTAG_SERVER_DATE:
v->field_mask |= F_VNODE_SDATE;
v->server_date = value;
break;
case VTAG_AUTHOR:
v->field_mask |= F_VNODE_AUTHOR;
v->author = value;
break;
case VTAG_OWNER:
v->field_mask |= F_VNODE_OWNER;
v->owner = value;
break;
case VTAG_GROUP:
v->field_mask |= F_VNODE_GROUP;
v->group = value;
break;
case VTAG_MODE:
v->field_mask |= F_VNODE_MODE;
v->mode = value;
break;
case VTAG_PARENT:
v->field_mask |= F_VNODE_PARENT;
v->parent = value;
break;
}
if (p->print_flags & DSPRINT_VNODE)
switch (field->kind) {
case DKIND_BYTE:
case DKIND_INT16:
case DKIND_INT32: printf("%s%d\n", field->label, value); break;
case DKIND_HEX8: printf("%s0x%02x\n", field->label, value); break;
case DKIND_HEX16: printf("%s0x%04x\n", field->label, value); break;
case DKIND_HEX32: printf("%s0x%08x\n", field->label, value); break;
case DKIND_CHAR: printf("%s%c\n", field->label, value); break;
case DKIND_STRING: printf("%s%s\n", field->label, tag); break;
case DKIND_FLAG:
printf("%s%s\n", field->label, value ? "true" : "false");
break;
case DKIND_TIME:
when = value;
printf("%s%s", field->label, ctime(&when));
break;
}
return r;
}
static char *rights2str(afs_uint32 rights)
{
static char str[16];
char *p = str;
if (rights & PRSFS_READ) *p++ = 'r';
if (rights & PRSFS_LOOKUP) *p++ = 'l';
if (rights & PRSFS_INSERT) *p++ = 'i';
if (rights & PRSFS_DELETE) *p++ = 'd';
if (rights & PRSFS_WRITE) *p++ = 'w';
if (rights & PRSFS_LOCK) *p++ = 'k';
if (rights & PRSFS_ADMINISTER) *p++ = 'a';
if (rights & PRSFS_USR0) *p++ = 'A';
if (rights & PRSFS_USR1) *p++ = 'B';
if (rights & PRSFS_USR2) *p++ = 'C';
if (rights & PRSFS_USR3) *p++ = 'D';
if (rights & PRSFS_USR4) *p++ = 'E';
if (rights & PRSFS_USR5) *p++ = 'F';
if (rights & PRSFS_USR6) *p++ = 'G';
if (rights & PRSFS_USR7) *p++ = 'H';
*p = 0;
if (!str[0]) strcpy(str, "none");
return str;
}
/* Parse and store the ACL data from a directory vnode */
static afs_uint32 parse_acl(XFILE *X, unsigned char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
struct acl_accessList *acl;
dump_parser *p = (dump_parser *)g_refcon;
afs_vnode *v = (afs_vnode *)l_refcon;
afs_uint32 r, i, n;
if (r = xfread(X, v->acl, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE))
return r;
v->field_mask |= F_VNODE_ACL;
if (p->print_flags & DSPRINT_ACL) {
acl = (struct acl_accessList *)(v->acl);
n = ntohl(acl->positive);
if (n) {
printf("Positive ACL: %d entries\n", n);
for (i = 0; i < n; i++)
printf(" %9d %s\n",
ntohl(acl->entries[i].id),
rights2str(acl->entries[i].rights));
}
n = ntohl(acl->negative);
if (n) {
printf("Positive ACL: %d entries\n", n);
for (i = ntohl(acl->positive); i < ntohl(acl->total); i++)
printf(" %9d %s\n",
ntohl(acl->entries[i].id),
rights2str(acl->entries[i].rights));
}
}
return ReadByte(X, tag);
}
/* Parse or skip over the vnode data */
static afs_uint32 parse_vdata(XFILE *X, unsigned char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
dump_parser *p = (dump_parser *)g_refcon;
afs_vnode *v = (afs_vnode *)l_refcon;
static char *symlink_buf = 0;
static int symlink_size = 0;
afs_uint32 r;
if (r = ReadInt32(X, &v->size)) return r;
v->field_mask |= F_VNODE_SIZE;
if (v->size) {
v->field_mask |= F_VNODE_DATA;
if (r = xftell(X, &v->d_offset)) return r;
if (p->print_flags & DSPRINT_VNODE)
printf("%s%d (0x%08x) bytes at %s (0x%s)\n", field->label,
v->size, v->size, decimate_int64(&v->d_offset, 0),
hexify_int64(&v->d_offset, 0));
switch (v->type) {
case vSymlink:
if (v->size > symlink_size) {
if (symlink_buf) symlink_buf = (char *)realloc(symlink_buf, v->size + 1);
else symlink_buf = (char *)malloc(v->size + 1);
symlink_size = symlink_buf ? v->size : 0;
}
if (symlink_buf) {
if (r = xfread(X, symlink_buf, v->size)) return r;
symlink_buf[v->size] = 0;
if (p->print_flags & DSPRINT_VNODE)
printf("Target: %s\n", symlink_buf);
} else {
/* Call the callback here, because it's non-fatal */
if (p->cb_error)
(p->cb_error)(ENOMEM, 0, p->err_refcon,
"Out of memory reading symlink");
if (r = xfskip(X, v->size)) return r;
}
break;
case vDirectory:
if (p->cb_dirent || (p->print_flags & DSPRINT_DIR)) {
if (r = parse_directory(X, p, v, v->size, 0)) return r;
break;
}
default:
if (r = xfskip(X, v->size)) return r;
}
} else if (p->print_flags & DSPRINT_VNODE) {
printf("%sEmpty\n", field->label);
}
if (p->repair_flags & DSFIX_VDSYNC) {
r = resync_vnode(X, p, v, 10, 15);
if (r) return r;
}
return ReadByte(X, tag);
}

302
src/tests/parsevol.c Normal file
View File

@ -0,0 +1,302 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* parsevol.c - Parse a volume header */
#include "dumpscan.h"
#include "dumpscan_errs.h"
#include "dumpfmt.h"
static afs_uint32 store_volhdr (XFILE *, unsigned char *, tagged_field *,
afs_uint32, tag_parse_info *, void *, void *);
static afs_uint32 parse_weekuse (XFILE *, unsigned char *, tagged_field *,
afs_uint32, tag_parse_info *, void *, void *);
/** Field list for volume headers **/
static tagged_field volhdr_fields[] = {
{ VHTAG_VOLID, DKIND_INT32, " Volume ID: ", store_volhdr, 0, 0 },
{ VHTAG_VERS, DKIND_INT32, " Version: ", store_volhdr, 0, 0 },
{ VHTAG_VOLNAME, DKIND_STRING, " Volume name: ", store_volhdr, 0, 0 },
{ VHTAG_INSERV, DKIND_FLAG, " In service? ", store_volhdr, 0, 0 },
{ VHTAG_BLESSED, DKIND_FLAG, " Blessed? ", store_volhdr, 0, 0 },
{ VHTAG_VUNIQ, DKIND_INT32, " Uniquifier: ", store_volhdr, 0, 0 },
{ VHTAG_TYPE, DKIND_BYTE, " Type: ", store_volhdr, 0, 0 },
{ VHTAG_PARENT, DKIND_INT32, " Parent ID: ", store_volhdr, 0, 0 },
{ VHTAG_CLONE, DKIND_INT32, " Clone ID: ", store_volhdr, 0, 0 },
{ VHTAG_MAXQUOTA, DKIND_INT32, " Max quota: ", store_volhdr, 0, 0 },
{ VHTAG_MINQUOTA, DKIND_INT32, " Min quota: ", store_volhdr, 0, 0 },
{ VHTAG_DISKUSED, DKIND_INT32, " Disk used: ", store_volhdr, 0, 0 },
{ VHTAG_FILECNT, DKIND_INT32, " File count: ", store_volhdr, 0, 0 },
{ VHTAG_ACCOUNT, DKIND_INT32, " Account: ", store_volhdr, 0, 0 },
{ VHTAG_OWNER, DKIND_INT32, " Owner: ", store_volhdr, 0, 0 },
{ VHTAG_CREAT, DKIND_TIME, " Created: ", store_volhdr, 0, 0 },
{ VHTAG_ACCESS, DKIND_TIME, " Accessed: ", store_volhdr, 0, 0 },
{ VHTAG_UPDATE, DKIND_TIME, " Updated: ", store_volhdr, 0, 0 },
{ VHTAG_EXPIRE, DKIND_TIME, " Expires: ", store_volhdr, 0, 0 },
{ VHTAG_BACKUP, DKIND_TIME, " Backed up: ", store_volhdr, 0, 0 },
{ VHTAG_OFFLINE, DKIND_STRING, " Offine Msg: ", store_volhdr, 0, 0 },
{ VHTAG_MOTD, DKIND_STRING, " MOTD: ", store_volhdr, 0, 0 },
{ VHTAG_WEEKUSE, DKIND_SPECIAL, " Weekuse: ", parse_weekuse, 0, 0 },
{ VHTAG_DUDATE, DKIND_TIME, " Dayuse Date: ", store_volhdr, 0, 0 },
{ VHTAG_DAYUSE, DKIND_INT32, " Daily usage: ", store_volhdr, 0, 0 },
{ 0,0,0,0,0,0 }};
/* Parse a volume header, including any tagged attributes, and call the
* volume-header callback, if one is defined.
*/
afs_uint32 parse_volhdr(XFILE *X, unsigned char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
dump_parser *p = (dump_parser *)g_refcon;
afs_vol_header hdr;
u_int64 where;
afs_uint32 r;
memset(&hdr, 0, sizeof(hdr));
if (r = xftell(X, &where)) return r;
sub64_32(hdr.offset, where, 1);
if (p->print_flags & DSPRINT_VOLHDR)
printf("%s [%s = 0x%s]\n", field->label,
decimate_int64(&hdr.offset, 0), hexify_int64(&hdr.offset, 0));
r = ParseTaggedData(X, volhdr_fields, tag, pi, g_refcon, (void *)&hdr);
if (!r && p->cb_volhdr) {
if (r = xftell(X, &where)) return r;
r = (p->cb_volhdr)(&hdr, X, p->refcon);
if (p->flags & DSFLAG_SEEK) {
if (!r) r = xfseek(X, &where);
else xfseek(X, &where);
}
}
if (hdr.field_mask & F_VOLHDR_VOLUNIQ)
p->vol_uniquifier = hdr.voluniq;
if (hdr.field_mask & F_VOLHDR_VOLNAME)
free(hdr.volname);
if (hdr.field_mask & F_VOLHDR_OFFLINE_MSG)
free(hdr.offline_msg);
if (hdr.field_mask & F_VOLHDR_MOTD)
free(hdr.motd_msg);
return r;
}
/* Store data in a volume header */
static afs_uint32 store_volhdr(XFILE *X, unsigned char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
dump_parser *p = (dump_parser *)g_refcon;
afs_vol_header *hdr = (afs_vol_header *)l_refcon;
time_t when;
afs_uint32 r = 0;
switch (field->tag) {
case VHTAG_VOLID:
hdr->field_mask |= F_VOLHDR_VOLID;
hdr->volid = value;
break;
case VHTAG_VERS:
hdr->field_mask |= F_VOLHDR_VOLVERS;
hdr->volvers = value;
break;
case VHTAG_VOLNAME:
if (tag && tag[0]) {
hdr->field_mask |= F_VOLHDR_VOLNAME;
hdr->volname = tag;
r = DSERR_KEEP;
}
break;
case VHTAG_INSERV:
hdr->field_mask |= F_VOLHDR_INSERV;
hdr->flag_inservice = value;
break;
case VHTAG_BLESSED:
hdr->field_mask |= F_VOLHDR_BLESSED;
hdr->flag_blessed = value;
break;
case VHTAG_VUNIQ:
hdr->field_mask |= F_VOLHDR_VOLUNIQ;
hdr->voluniq = value;
break;
case VHTAG_TYPE:
hdr->field_mask |= F_VOLHDR_VOLTYPE;
hdr->voltype = value;
break;
case VHTAG_PARENT:
hdr->field_mask |= F_VOLHDR_PARENT;
hdr->parent_volid = value;
break;
case VHTAG_CLONE:
hdr->field_mask |= F_VOLHDR_CLONE;
hdr->clone_volid = value;
break;
case VHTAG_MAXQUOTA:
hdr->field_mask |= F_VOLHDR_MAXQ;
hdr->maxquota = value;
break;
case VHTAG_MINQUOTA:
hdr->field_mask |= F_VOLHDR_MINQ;
hdr->minquota = value;
break;
case VHTAG_DISKUSED:
hdr->field_mask |= F_VOLHDR_DISKUSED;
hdr->diskused = value;
break;
case VHTAG_FILECNT:
hdr->field_mask |= F_VOLHDR_NFILES;
hdr->nfiles = value;
break;
case VHTAG_ACCOUNT:
hdr->field_mask |= F_VOLHDR_ACCOUNT;
hdr->account_no = value;
break;
case VHTAG_OWNER:
hdr->field_mask |= F_VOLHDR_OWNER;
hdr->owner = value;
break;
case VHTAG_CREAT:
hdr->field_mask |= F_VOLHDR_CREATE_DATE;
hdr->create_date = value;
break;
case VHTAG_ACCESS:
hdr->field_mask |= F_VOLHDR_ACCESS_DATE;
hdr->access_date = value;
break;
case VHTAG_UPDATE:
hdr->field_mask |= F_VOLHDR_UPDATE_DATE;
hdr->update_date = value;
break;
case VHTAG_EXPIRE:
hdr->field_mask |= F_VOLHDR_EXPIRE_DATE;
hdr->expire_date = value;
break;
case VHTAG_BACKUP:
hdr->field_mask |= F_VOLHDR_BACKUP_DATE;
hdr->backup_date = value;
break;
case VHTAG_OFFLINE:
if (tag && tag[0]) {
hdr->field_mask |= F_VOLHDR_OFFLINE_MSG;
hdr->offline_msg = tag;
r = DSERR_KEEP;
}
break;
case VHTAG_MOTD:
if (tag && tag[0]) {
hdr->field_mask |= F_VOLHDR_MOTD;
hdr->motd_msg = tag;
r = DSERR_KEEP;
}
break;
case VHTAG_DUDATE:
hdr->field_mask |= F_VOLHDR_DAYUSE_DATE;
hdr->dayuse_date = value;
break;
case VHTAG_DAYUSE:
hdr->field_mask |= F_VOLHDR_DAYUSE;
hdr->dayuse = value;
break;
}
if (p->print_flags & DSPRINT_VOLHDR)
switch (field->kind) {
case DKIND_BYTE:
case DKIND_INT16:
case DKIND_INT32: printf("%s%d\n", field->label, value); break;
case DKIND_HEX8: printf("%s0x%02x\n", field->label, value); break;
case DKIND_HEX16: printf("%s0x%04x\n", field->label, value); break;
case DKIND_HEX32: printf("%s0x%08x\n", field->label, value); break;
case DKIND_CHAR: printf("%s%c\n", field->label, value); break;
case DKIND_STRING: printf("%s%s\n", field->label, tag); break;
case DKIND_FLAG:
printf("%s%s\n", field->label, value ? "true" : "false");
break;
case DKIND_TIME:
when = value;
printf("%s%s", field->label, ctime(&when));
break;
}
return r;
}
/* Parse and store the week use data from a volume header */
static afs_uint32 parse_weekuse(XFILE *X, unsigned char *tag, tagged_field *field,
afs_uint32 value, tag_parse_info *pi,
void *g_refcon, void *l_refcon)
{
dump_parser *p = (dump_parser *)g_refcon;
afs_vol_header *hdr = (afs_vol_header *)l_refcon;
afs_uint16 count;
afs_uint32 r;
unsigned int i;
if (r = ReadInt16(X, &count)) return r;
if (count != 7) {
if (p->cb_error)
(p->cb_error)(DSERR_FMT, 1, p->err_refcon,
"Incorrect array count (%d) in weekuse data", count);
return DSERR_FMT;
}
for (i = 0; i < count; i++)
if (r = ReadInt32(X, hdr->weekuse + i)) return r;
hdr->field_mask |= F_VOLHDR_WEEKUSE;
if (p->print_flags & DSPRINT_VOLHDR) {
printf("%s%10d %10d %10d %10d\n", field->label,
hdr->weekuse[0], hdr->weekuse[1], hdr->weekuse[2], hdr->weekuse[3]);
printf("%s%10d %10d %10d\n", field->label,
hdr->weekuse[4], hdr->weekuse[5], hdr->weekuse[6]);
}
return ReadByte(X, tag);
}

376
src/tests/pathname.c Normal file
View File

@ -0,0 +1,376 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* pathname.c - Pathname lookup and traversal */
#include <errno.h>
#include <string.h>
#include "dumpscan.h"
#include "dumpscan_errs.h"
/* Hash function for a vnode */
#define BUCKET_SIZE 32
#define vnode_hash(phi,vnode) ((vnode) & ((1 << (phi)->hash_size) - 1))
static vhash_ent *get_vhash_ent(path_hashinfo *phi, afs_uint32 vnode, int make)
{
int key = vnode_hash(phi, vnode);
vhash_ent *vhe;
for (vhe = phi->hash_table[key];
vhe && vhe->vnode != vnode;
vhe = vhe->next);
if (make && !vhe) {
vhe = (vhash_ent *)malloc(sizeof(vhash_ent));
if (vhe) {
memset(vhe, 0, sizeof(vhash_ent));
vhe->vnode = vnode;
vhe->next = phi->hash_table[key];
phi->hash_table[key] = vhe;
}
}
return vhe;
}
static afs_uint32 volhdr_cb(afs_vol_header *hdr, XFILE *X, void *refcon)
{
path_hashinfo *phi = (path_hashinfo *)refcon;
int nfiles, hsize;
if (hdr->field_mask & F_VOLHDR_NFILES) {
nfiles = phi->n_vnodes = hdr->nfiles;
for (phi->hash_size = 1;
nfiles > BUCKET_SIZE;
phi->hash_size++, nfiles >>= 1);
hsize = (1 << phi->hash_size);
phi->hash_table = (vhash_ent **)malloc(hsize * sizeof(vhash_ent *));
if (!phi->hash_table) return ENOMEM;
memset(phi->hash_table, 0, hsize * sizeof(vhash_ent *));
return 0;
} else {
if (phi->p->cb_error)
(phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
"File count missing from volume header");
return DSERR_FMT;
}
}
static afs_uint32 vnode_keep(afs_vnode *v, XFILE *X, void *refcon)
{
path_hashinfo *phi = (path_hashinfo *)refcon;
vhash_ent *vhe;
if (!phi->hash_table) {
if (phi->p->cb_error)
(phi->p->cb_error)(DSERR_FMT, 1, phi->p->refcon,
"No volume header in dump???");
return DSERR_FMT;
}
vhe = get_vhash_ent(phi, v->vnode, 1);
if (!vhe) return ENOMEM;
cp64(vhe->v_offset, v->offset);
if (v->field_mask & F_VNODE_PARENT)
vhe->parent = v->parent;
if (v->field_mask & F_VNODE_DATA) {
cp64(vhe->d_offset, v->d_offset);
vhe->d_size = v->size;
}
if ((v->field_mask & F_VNODE_TYPE) && v->type == vDirectory)
phi->n_dirs++;
else
phi->n_files++;
return 0;
}
static afs_uint32 vnode_stop(afs_vnode *v, XFILE *X, void *refcon)
{
path_hashinfo *phi = (path_hashinfo *)refcon;
int r;
/* If the file is seekable, try to position so we can pick up later... */
if (phi->p->flags && DSFLAG_SEEK)
if (r = xfseek(X, &v->offset)) return r;
return DSERR_DONE;
}
static afs_uint32 dirent_cb(afs_vnode *v, afs_dir_entry *de,
XFILE *X, void *refcon)
{
path_hashinfo *phi = (path_hashinfo *)refcon;
vhash_ent *vhe;
if (!phi->hash_table) {
if (phi->p->cb_error)
(phi->p->cb_error)(DSERR_FMT, 1, phi->p->refcon,
"No volume header in dump???");
return DSERR_FMT;
}
if (!strcmp(de->name, ".") || !strcmp(de->name, "..")) return 0;
vhe = get_vhash_ent(phi, de->vnode, 1);
if (!vhe) return ENOMEM;
vhe->parent = v->vnode;
return 0;
}
/* Prescan the vnodes in a dump file, collecting information that will
* be useful in generating and following pathnames.
*/
afs_uint32 Path_PreScan(XFILE *X, path_hashinfo *phi, int full)
{
dump_parser my_p, *p = phi->p;
int r;
memset(phi, 0, sizeof(path_hashinfo));
phi->p = p;
memset(&my_p, 0, sizeof(my_p));
my_p.refcon = (void *)phi;
my_p.cb_volhdr = volhdr_cb;
my_p.cb_vnode_dir = vnode_keep;
if (full) {
my_p.cb_vnode_file = vnode_keep;
my_p.cb_vnode_link = vnode_keep;
my_p.cb_vnode_empty = vnode_keep;
my_p.cb_vnode_wierd = vnode_keep;
} else {
my_p.cb_vnode_file = vnode_stop;
my_p.cb_vnode_link = vnode_stop;
my_p.cb_vnode_empty = vnode_stop;
my_p.cb_vnode_wierd = vnode_stop;
}
my_p.err_refcon = p->err_refcon;
my_p.cb_error = p->cb_error;
my_p.cb_dirent = dirent_cb;
my_p.flags = p->flags;
my_p.print_flags = p->print_flags;
my_p.repair_flags = p->repair_flags;
return ParseDumpFile(X, &my_p);
}
/* Free the hash table in a path_hashinfo */
void Path_FreeHashTable(path_hashinfo *phi)
{
int i, size;
vhash_ent *vhe, *next_vhe;
if (phi->hash_table) {
size = (1 << phi->hash_size);
for (i = 0; i < size; i++)
for (vhe = phi->hash_table[i]; vhe; vhe = next_vhe) {
next_vhe = vhe->next;
free(vhe);
}
free(phi->hash_table);
}
}
/* Follow a pathname to the vnode it represents */
afs_uint32 Path_Follow(XFILE *X, path_hashinfo *phi,
char *path, vhash_ent *his_vhe)
{
vhash_ent *vhe;
char *name;
afs_uint32 r, vnum = 1;
if (*path == '/') path++;
name = strtok(path, "/");
for (name = strtok(path, "/"); name; name = strtok(0, "/")) {
if (!(vnum & 1)) {
if (phi->p->cb_error)
(phi->p->cb_error)(ENOTDIR, 1, phi->p->err_refcon,
"Not a directory vnode");
return ENOTDIR;
}
vhe = get_vhash_ent(phi, vnum, 0);
if (!vhe) {
if (phi->p->cb_error)
(phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
"Vnode %d not found in hash table", vnum);
return DSERR_FMT;
}
if (zero64(vhe->d_offset)) {
if (phi->p->cb_error)
(phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
"Directory vnode %d is incomplete", vnum);
return DSERR_FMT;
}
if (r = xfseek(X, &vhe->d_offset)) {
if (phi->p->cb_error)
(phi->p->cb_error)(r, 1, phi->p->err_refcon,
"Unable to seek to directory %d", vnum);
return r;
}
vnum = 0;
r = DirectoryLookup(X, phi->p, vhe->d_size, &name, &vnum, 0);
if (r) return r;
if (!vnum) {
if (phi->p->cb_error)
(phi->p->cb_error)(ENOENT, 1, phi->p->err_refcon,
"No such vnode");
return ENOENT;
}
}
vhe = get_vhash_ent(phi, vnum, 0);
if (!vhe) {
if (phi->p->cb_error)
(phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
"Vnode %d not found in hash table", vnum);
return DSERR_FMT;
}
if (his_vhe) *his_vhe = *vhe;
return 0;
}
afs_uint32 Path_Build(XFILE *X, path_hashinfo *phi, afs_uint32 vnode,
char **his_path, int fast)
{
vhash_ent *vhe;
char *name, *path = 0, fastbuf[12];
char *x, *y;
afs_uint32 parent, r;
int nl, pl = 0;
if (vnode == 1) {
*his_path = (char *)malloc(2);
if (!his_path) {
if (phi->p->cb_error)
(phi->p->cb_error)(ENOMEM, 1, phi->p->err_refcon,
"No memory for pathname of vnode 1");
return ENOMEM;
}
strcpy(*his_path, "/");
return 0;
}
*his_path = 0;
vhe = get_vhash_ent(phi, vnode, 0);
if (!vhe) {
if (phi->p->cb_error)
(phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
"Vnode %d not found in hash table", vnode);
return DSERR_FMT;
}
while (vnode != 1) {
/* Find the parent */
if (!vhe->parent) {
if (phi->p->cb_error)
(phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
"Vnode %d has no parent?", vnode);
if (path) free(path);
return DSERR_FMT;
}
parent = vhe->parent;
vhe = get_vhash_ent(phi, parent, 0);
if (phi->p->print_flags & DSPRINT_DEBUG)
fprintf(stderr, "Searching for vnode %d in parent %d\n", vnode, parent);
if (!vhe) {
if (phi->p->cb_error)
(phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
"Vnode %d not found in hash table", parent);
if (path) free(path);
return DSERR_FMT;
}
if (fast) {
/* Make up a path component from the vnode number */
sprintf(fastbuf, "%d", vnode);
name = fastbuf;
} else {
/* Do a reverse-lookup in the parent directory */
if (zero64(vhe->d_offset)) {
if (phi->p->cb_error)
(phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
"Directory vnode %d is incomplete", parent);
if (path) free(path);
return DSERR_FMT;
}
if (r = xfseek(X, &vhe->d_offset)) {
if (phi->p->cb_error)
(phi->p->cb_error)(errno, 1, phi->p->err_refcon,
"Unable to seek to directory %d", parent);
if (path) free(path);
return r;
}
name = 0;
r = DirectoryLookup(X, phi->p, vhe->d_size, &name, &vnode, 0);
if (r) return r;
if (!name) {
if (phi->p->cb_error)
(phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
"No entry for vnode %d in directory %d",
vnode, parent);
if (path) free(path);
return ENOENT;
}
}
nl = strlen(name);
if (path) {
path = (char *)realloc(path, nl + pl + 2);
if (!path) {
if (phi->p->cb_error)
(phi->p->cb_error)(ENOMEM, 1, phi->p->err_refcon,
"No memory for pathname of vnode 1");
return ENOMEM;
}
x = path + pl;
y = x + nl + 1;
while (x >= path) *y-- = *x--;
path[0] = '/';
for (x = name, y = path + 1; *x;) *y++ = *x++;
pl += nl + 1;
} else {
path = (char *)malloc(nl + 2);
if (!path) {
if (phi->p->cb_error)
(phi->p->cb_error)(ENOMEM, 1, phi->p->err_refcon,
"No memory for pathname of vnode 1");
return ENOMEM;
}
path[0] = '/';
strcpy(path + 1, name);
pl = nl + 1;
}
if (!fast) free(name);
vnode = parent;
}
*his_path = path;
return 0;
}

165
src/tests/primitive.c Normal file
View File

@ -0,0 +1,165 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* primitive.c - Routines for reading and writing low-level things */
#include <sys/types.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "dumpscan.h"
#define BUFSIZE 256
afs_uint32 ReadByte(XFILE *X, unsigned char *val)
{
return xfread(X, val, 1);
}
afs_uint32 ReadInt16(XFILE *X, afs_uint16 *val)
{
afs_uint32 r;
if (r = xfread(X, val, 2)) return r;
*val = ntohs(*val);
return 0;
}
afs_uint32 ReadInt32(XFILE *X, afs_uint32 *val)
{
afs_uint32 r;
if (r = xfread(X, val, 4)) return r;
*val = ntohl(*val);
return 0;
}
/* Read in a NUL-terminated string. This method is kind of messy, but
* has the advantage that it reads the data stream only once, doesn't
* read anything extra, and never has to seek on the data stream.
*/
afs_uint32 ReadString(XFILE *X, unsigned char **val)
{
static unsigned char buf[BUFSIZE];
unsigned char *result = 0;
afs_uint32 r;
int i, l = 0;
*val = 0;
for (;;) {
for (i = 0; i < BUFSIZE; i++) {
r = ReadByte(X, buf + i);
if (r) {
if (result) free(result);
return r;
}
if (!buf[i]) break;
}
/* iff we found a null, i < BUFSIZE and buf[i] holds the NUL */
if (result) result = (unsigned char *)realloc(result, l + i + 1);
else result = (unsigned char *)malloc(i + 1);
if (!result) return ENOMEM;
memcpy(result + l, buf, i);
result[l+i] = 0;
l += i;
if (i < BUFSIZE) break;
}
*val = result;
return 0;
}
afs_uint32 WriteByte(XFILE *X, unsigned char val)
{
return xfwrite(X, &val, 1);
}
afs_uint32 WriteInt16(XFILE *X, afs_uint16 val)
{
val = htons(val);
return xfwrite(X, &val, 2);
}
afs_uint32 WriteInt32(XFILE *X, afs_uint32 val)
{
val = htonl(val);
return xfwrite(X, &val, 4);
}
afs_uint32 WriteString(XFILE *X, unsigned char *str)
{
int len = strlen((char *)str) + 1;
return xfwrite(X, str, len);
}
afs_uint32 WriteTagByte(XFILE *X, unsigned char tag, unsigned char val)
{
char buffer[2];
buffer[0] = tag;
buffer[1] = val;
return xfwrite(X, buffer, 2);
}
afs_uint32 WriteTagInt16(XFILE *X, unsigned char tag, afs_uint16 val)
{
char buffer[3];
buffer[0] = tag;
buffer[1] = (val & 0xff00) >> 8;
buffer[2] = val & 0xff;
return xfwrite(X, buffer, 3);
}
afs_uint32 WriteTagInt32(XFILE *X, unsigned char tag, afs_uint32 val)
{
char buffer[5];
buffer[0] = tag;
buffer[1] = (val & 0xff000000) >> 24;
buffer[2] = (val & 0xff0000) >> 16;
buffer[3] = (val & 0xff00) >> 8;
buffer[4] = val & 0xff;
return xfwrite(X, buffer, 5);
}
afs_uint32 WriteTagInt32Pair(XFILE *X, unsigned char tag,
afs_uint32 val1, afs_uint32 val2)
{
char buffer[9];
buffer[0] = tag;
buffer[1] = (val1 & 0xff000000) >> 24;
buffer[2] = (val1 & 0xff0000) >> 16;
buffer[3] = (val1 & 0xff00) >> 8;
buffer[4] = val1 & 0xff;
buffer[5] = (val2 & 0xff000000) >> 24;
buffer[6] = (val2 & 0xff0000) >> 16;
buffer[7] = (val2 & 0xff00) >> 8;
buffer[8] = val2 & 0xff;
return xfwrite(X, buffer, 9);
}

366
src/tests/repair.c Normal file
View File

@ -0,0 +1,366 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* repair.c - Routines to generate a repaired dump */
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "dumpscan.h"
#include "dumpscan_errs.h"
#include "dumpfmt.h"
#include <afs/acl.h>
#include <afs/dir.h>
#include <afs/prs_fs.h>
XFILE repair_output;
int repair_verbose;
#define RV repair_verbose
/* Try to dump a dump header. Generate missing fields, if neccessary */
afs_uint32 repair_dumphdr_cb(afs_dump_header *hdr, XFILE *X, void *refcon)
{
afs_uint32 r, field_mask = hdr->field_mask;
char volname[22];
if (!(field_mask & F_DUMPHDR_VOLID)) {
if (RV) fprintf(stderr, ">>> DUMP HEADER missing volume ID\n");
return DSERR_FMT;
}
if (!(field_mask & F_DUMPHDR_VOLNAME)) {
if (RV) {
fprintf(stderr, ">>> DUMP HEADER missing volume name\n");
fprintf(stderr, ">>> Will use RESTORED.%d\n", hdr->volid);
}
sprintf(volname, "RESTORED.%d", hdr->volid);
hdr->volname = (unsigned char *)malloc(strlen(volname) + 1);
if (!hdr->volname) return ENOMEM;
strcpy(hdr->volname, volname);
hdr->field_mask |= F_DUMPHDR_VOLNAME;
}
if (!(field_mask & F_DUMPHDR_FROM)) {
if (RV) fprintf(stderr, ">>> DUMP HEADER missing from time (using 0)\n");
hdr->from_date = 0;
hdr->field_mask |= F_DUMPHDR_FROM;
}
if (!(field_mask & F_DUMPHDR_TO)) {
hdr->to_date = time(0);
if (RV) fprintf(stderr, ">>> DUMP HEADER missing from time (using %d)\n",
hdr->to_date);
hdr->field_mask |= F_DUMPHDR_TO;
}
return DumpDumpHeader(&repair_output, hdr);
}
/* Try to dump a volume header. Generate missing fields, if necessary */
afs_uint32 repair_volhdr_cb(afs_vol_header *hdr, XFILE *X, void *refcon)
{
afs_uint32 r, field_mask = hdr->field_mask;
char volname[22];
if (!(field_mask & F_VOLHDR_VOLID)) {
if (RV) fprintf(stderr, ">>> VOL HEADER missing volume ID\n");
return DSERR_FMT;
}
if (!(field_mask & F_VOLHDR_VOLVERS)) {
if (RV) fprintf(stderr, ">>> VOL HEADER missing version (using 1)\n");
hdr->volvers = 1;
hdr->field_mask |= F_VOLHDR_VOLVERS;
} else if (hdr->volvers != 1) {
if (RV) fprintf(stderr, ">>> VOL HEADER bogus version %d (using 1)\n",
hdr->volvers);
hdr->volvers = 1;
}
if (!(field_mask & F_VOLHDR_VOLNAME)) {
if (RV) {
fprintf(stderr, ">>> VOL HEADER missing volume name\n");
fprintf(stderr, ">>> Will use RESTORED.%d\n", hdr->volid);
}
sprintf(volname, "RESTORED.%d", hdr->volid);
hdr->volname = (unsigned char *)malloc(strlen(volname) + 1);
if (!hdr->volname) return ENOMEM;
strcpy(hdr->volname, volname);
hdr->field_mask |= F_VOLHDR_VOLNAME;
}
if (!(field_mask & F_VOLHDR_INSERV)) {
if (RV)
fprintf(stderr, ">>> VOL HEADER missing in-service flag (using 1)\n");
hdr->flag_inservice = 1;
hdr->field_mask |= F_VOLHDR_INSERV;
}
if (!(field_mask & F_VOLHDR_BLESSED)) {
if (RV) fprintf(stderr, ">>> VOL HEADER missing blessed flag (using 1)\n");
hdr->flag_blessed = 1;
hdr->field_mask |= F_VOLHDR_BLESSED;
}
if (!(field_mask & F_VOLHDR_VOLUNIQ)) {
if (RV) fprintf(stderr, ">>> VOL HEADER missing uniquifier (using 1)\n");
hdr->voluniq = 1;
hdr->field_mask |= F_VOLHDR_VOLUNIQ;
}
if (!(field_mask & F_VOLHDR_VOLTYPE)) {
if (RV) fprintf(stderr, ">>> VOL HEADER missing type (using 0: RW)\n");
hdr->voltype = 0;
hdr->field_mask |= F_VOLHDR_VOLTYPE;
} else if (hdr->voltype < 0 || hdr->voltype > 2) {
if (RV) fprintf(stderr, ">>> VOL HEADER bogus type %d (using 0: RW)\n",
hdr->voltype);
hdr->voltype = 0;
}
if (!(field_mask & F_VOLHDR_PARENT)) {
if (RV) fprintf(stderr, ">>> VOL HEADER parent (using %d)\n", hdr->volid);
hdr->parent_volid = hdr->volid;
hdr->field_mask |= F_VOLHDR_PARENT;
}
if (!(field_mask & F_VOLHDR_MAXQ)) {
if (field_mask & F_VOLHDR_DISKUSED) hdr->maxquota = hdr->diskused;
else hdr->maxquota = 1;
if (RV) fprintf(stderr, ">>> VOL HEADER missing max quota (using %d)\n",
hdr->maxquota);
hdr->field_mask |= F_VOLHDR_MAXQ;
}
if (!(field_mask & F_VOLHDR_DISKUSED)) {
if (RV) fprintf(stderr, ">>> VOL HEADER missing disk used (using 2048)\n");
hdr->diskused = 2048;
hdr->field_mask |= F_VOLHDR_DISKUSED;
}
if (!(field_mask & F_VOLHDR_NFILES)) {
if (RV) fprintf(stderr, ">>> VOL HEADER missing file count (using 1)\n");
hdr->nfiles = 1;
hdr->field_mask |= F_VOLHDR_NFILES;
}
if (!(field_mask & F_VOLHDR_CREATE_DATE)) {
hdr->create_date = 0;
if ((field_mask & F_VOLHDR_ACCESS_DATE)
&& (!hdr->create_date || hdr->access_date < hdr->create_date))
hdr->create_date = hdr->access_date;
if ((field_mask & F_VOLHDR_UPDATE_DATE)
&& (!hdr->create_date || hdr->update_date < hdr->create_date))
hdr->create_date = hdr->update_date;
if ((field_mask & F_VOLHDR_BACKUP_DATE)
&& (!hdr->create_date || hdr->backup_date < hdr->create_date))
hdr->create_date = hdr->backup_date;
if (RV) fprintf(stderr, ">>> VOL HEADER missing create date (using %d)\n",
hdr->create_date);
hdr->field_mask |= F_VOLHDR_CREATE_DATE;
}
if (!(field_mask & F_VOLHDR_ACCESS_DATE)) {
hdr->access_date = 0;
if ((field_mask & F_VOLHDR_CREATE_DATE)
&& (!hdr->access_date || hdr->create_date > hdr->access_date))
hdr->access_date = hdr->create_date;
if ((field_mask & F_VOLHDR_UPDATE_DATE)
&& (!hdr->access_date || hdr->update_date > hdr->access_date))
hdr->access_date = hdr->update_date;
if ((field_mask & F_VOLHDR_BACKUP_DATE)
&& (!hdr->access_date || hdr->backup_date > hdr->access_date))
hdr->access_date = hdr->backup_date;
if (RV) fprintf(stderr, ">>> VOL HEADER missing access date (using %d)\n",
hdr->access_date);
hdr->field_mask |= F_VOLHDR_ACCESS_DATE;
}
if (!(field_mask & F_VOLHDR_UPDATE_DATE)) {
hdr->update_date = 0;
if ((field_mask & F_VOLHDR_CREATE_DATE)
&& (!hdr->update_date || hdr->create_date > hdr->update_date))
hdr->update_date = hdr->create_date;
if ((field_mask & F_VOLHDR_ACCESS_DATE) && !hdr->update_date)
hdr->update_date = hdr->access_date;
if ((field_mask & F_VOLHDR_BACKUP_DATE) && !hdr->update_date)
hdr->update_date = hdr->backup_date;
if (RV) fprintf(stderr, ">>> VOL HEADER missing update date (using %d)\n",
hdr->update_date);
hdr->field_mask |= F_VOLHDR_UPDATE_DATE;
}
return DumpVolumeHeader(&repair_output, hdr);
}
/* Try to dump a vnode. Generate missing fields, if necessary */
afs_uint32 repair_vnode_cb(afs_vnode *v, XFILE *X, void *refcon)
{
afs_uint32 r, field_mask = v->field_mask;
if ((v->vnode & 1) && !field_mask) {
if (RV) fprintf(stderr, ">>> VNODE %d is directory but has no fields?\n");
v->type = vDirectory;
v->field_mask |= F_VNODE_TYPE;
field_mask = F_VNODE_TYPE; /* Messy! */
}
if (field_mask && !(field_mask & F_VNODE_TYPE)) {
v->type = (v->vnode & 1) ? vDirectory : vFile;
if (RV) fprintf(stderr, ">>> VNODE %d missing type (using %d)\n",
v->vnode, v->type);
v->field_mask |= F_VNODE_TYPE;
}
if (field_mask && !(field_mask & F_VNODE_NLINKS)) {
if (RV)
fprintf(stderr, ">>> VNODE %d missing link count (using 1)\n", v->vnode);
v->nlinks = 1;
v->field_mask |= F_VNODE_NLINKS;
}
if (field_mask && !(field_mask & F_VNODE_PARENT)) {
if (RV)
fprintf(stderr, ">>> VNODE %d missing parent (using 1)\n", v->vnode);
v->parent = 1;
v->field_mask |= F_VNODE_PARENT;
}
if (field_mask && !(field_mask & F_VNODE_DVERS)) {
if (RV) fprintf(stderr, ">>> VNODE %d missing data version (using 1)\n",
v->vnode);
v->datavers = 1;
v->field_mask |= F_VNODE_DVERS;
}
if (field_mask && !(field_mask & F_VNODE_AUTHOR)) {
if (field_mask & F_VNODE_OWNER) v->author = v->owner;
else v->author = 0;
if (RV) fprintf(stderr, ">>> VNODE %d missing author (using %d)\n",
v->vnode, v->author);
v->field_mask |= F_VNODE_AUTHOR;
}
if (field_mask && !(field_mask & F_VNODE_OWNER)) {
if (field_mask & F_VNODE_AUTHOR) v->owner = v->author;
else v->owner = 0;
if (RV) fprintf(stderr, ">>> VNODE %d missing owner (using %d)\n",
v->vnode, v->owner);
v->field_mask |= F_VNODE_OWNER;
}
if (field_mask && !(field_mask & F_VNODE_MODE)) {
v->mode = (v->vnode & 1) ? 0755 : 0644;
if (RV) fprintf(stderr, ">>> VNODE missing mode (using %d)\n", v->mode);
v->field_mask |= F_VNODE_MODE;
}
if (field_mask && !(field_mask & F_VNODE_CDATE)) {
if (field_mask & F_VNODE_SDATE) v->client_date = v->server_date;
else v->client_date = 0;
if (RV) fprintf(stderr, ">>> VNODE %d missing client date (using %d)\n",
v->vnode, v->client_date);
v->field_mask |= F_VNODE_CDATE;
}
if (field_mask && !(field_mask & F_VNODE_SDATE)) {
if (field_mask & F_VNODE_CDATE) v->server_date = v->client_date;
else v->server_date = 0;
if (RV) fprintf(stderr, ">>> VNODE %d missing server date (using %d)\n",
v->vnode, v->server_date);
v->field_mask |= F_VNODE_SDATE;
}
if (field_mask && !(field_mask & F_VNODE_SIZE)) {
if (RV) fprintf(stderr, ">>> VNODE %d has no data size (using 0)\n");
v->size = 0;
v->field_mask |= F_VNODE_SIZE;
}
if ((field_mask & F_VNODE_DATA) && !v->size) {
if (RV)
fprintf(stderr, ">>> VNODE %d has data, but size == 0 (ignoring)\n",
v->vnode);
v->field_mask &=~ F_VNODE_DATA;
}
if (field_mask && v->type == vDirectory && !(field_mask & F_VNODE_ACL)) {
struct acl_accessList *acl = (struct acl_accessList *)v->acl;
if (RV) {
fprintf(stderr, ">>> VNODE %d is directory but has no ACL\n");
fprintf(stderr, ">>> Will generate default ACL\n");
}
memset(v->acl, 0, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE);
acl->size = htonl(SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE);
acl->version = htonl(ACL_ACLVERSION);
acl->total = htonl(v->owner ? 0 : 1);
acl->positive = acl->total;
acl->negative = 0;
if (v->owner) {
acl->entries[0].id = htonl(v->owner);
acl->entries[0].rights = htonl((PRSFS_READ | PRSFS_WRITE
| PRSFS_INSERT | PRSFS_LOOKUP
| PRSFS_DELETE | PRSFS_LOCK
| PRSFS_ADMINISTER));
}
v->field_mask |= F_VNODE_ACL;
}
r = DumpVNode(&repair_output, v);
if (r) return r;
if (v->size) {
if (r = xfseek(X, &v->d_offset)) return r;
r = CopyVNodeData(&repair_output, X, v->size);
} else if (v->type == vDirectory) {
afs_dir_page page;
struct DirHeader *dhp = (struct DirHeader *)&page;
int i;
if (RV) {
fprintf(stderr, ">>> VNODE %d is directory but has no contents\n");
fprintf(stderr, ">>> Will generate deafult directory entries\n");
}
memset(&page, 0, sizeof(page));
/* Page and Directory Headers */
page.header.tag = htons(1234);
page.header.freecount = (EPP - DHE - 3);
page.header.freebitmap[0] = 0xff;
page.header.freebitmap[1] = 0x7f;
dhp->alloMap[0] = EPP - DHE - 3;
for (i = 1; i < MAXPAGES; i++) dhp->alloMap[i] = EPP;
/* Entry for . */
page.entry[DHE + 1].flag = FFIRST;
page.entry[DHE + 1].length = 1;
page.entry[DHE + 1].vnode = v->vnode;
page.entry[DHE + 1].vunique = v->vuniq;
strcpy(page.entry[DHE + 1].name, ".");
dhp->hashTable[0x2e] = DHE + 1;
/* Entry for .. */
page.entry[DHE + 2].flag = FFIRST;
page.entry[DHE + 2].length = 1;
page.entry[DHE + 2].vnode = v->parent;
page.entry[DHE + 2].vunique = 1; /* Can't have everything! */
strcpy(page.entry[DHE + 2].name, "..");
dhp->hashTable[0x44] = DHE + 2;
r = DumpVNodeData(&repair_output, (char *)&page, 2048);
} else if (field_mask) {
/* We wrote out attributes, so we should also write the 0-length data */
r = DumpVNodeData(&repair_output, "", 0);
}
return r;
}

150
src/tests/stagehdr.c Normal file
View File

@ -0,0 +1,150 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* stagehdr.c - Parse and dump stage backup headers */
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
#include "dumpscan.h"
#include "dumpscan_errs.h"
#include "xf_errs.h"
#include "stagehdr.h"
static afs_uint32 hdr_checksum(char *buf, int size)
{
afs_uint32 sum = 0, n = size / sizeof(afs_uint32), *words = (afs_uint32 *)buf;
while (--n)
sum += ntohl(*words++);
return sum;
}
/* Parse a stage backup header.
* If tag is non-NULL, *tag should contain the first byte (already read),
* and will be filled in with the first byte after the header, if one exists.
* On success, returns 0 and leaves us positioned after the header
* On failure, returns an error and position is undefined
* Iff there is no header, returns DSERR_MAGIC and leaves us
* positioned where we started.
*/
afs_uint32 ParseStageHdr(XFILE *X, unsigned char *tag, backup_system_header *hdr)
{
char buf[STAGE_HDRLEN];
struct stage_header *bckhdr = (struct stage_header *)buf;
u_int64 where;
afs_uint32 r;
if (r = xftell(X, &where)) return r;
if (hdr) memset(hdr, 0, sizeof(*hdr));
if (tag) {
if (*tag != STAGE_VERSMIN) return DSERR_MAGIC;
buf[0] = *tag;
r = xfread(X, buf + 1, STAGE_HDRLEN - 1);
} else {
r = xfread(X, buf, STAGE_HDRLEN);
}
if (r == ERROR_XFILE_EOF) {
r = xfseek(X, &where);
return r ? r : DSERR_MAGIC;
} else if (r) return r;
if (bckhdr->c_vers < STAGE_VERSMIN
|| ntohl(bckhdr->c_magic) != STAGE_MAGIC
|| hdr_checksum(buf, STAGE_HDRLEN) != STAGE_CHECKSUM) {
r = xfseek(X, &where);
return r ? r : DSERR_MAGIC;
}
if (hdr) {
hdr->version = bckhdr->c_vers;
hdr->from_date = ntohl(bckhdr->c_fdate);
hdr->to_date = ntohl(bckhdr->c_tdate);
hdr->dump_date = ntohl(bckhdr->c_time);
hdr->filenum = ntohl(bckhdr->c_filenum);
hdr->volid = ntohl(bckhdr->c_id);
hdr->dumplen = ntohl(bckhdr->c_length);
hdr->level = ntohl(bckhdr->c_level);
hdr->magic = ntohl(bckhdr->c_magic);
hdr->cksum = ntohl(bckhdr->c_checksum);
hdr->flags = ntohl(bckhdr->c_flags);
hdr->server = malloc(strlen(bckhdr->c_host) + 1);
hdr->part = malloc(strlen(bckhdr->c_disk) + 1);
hdr->volname = malloc(strlen(bckhdr->c_name) + 1);
if (!hdr->server || !hdr->part || !hdr->volname) {
if (hdr->server) free(hdr->server);
if (hdr->part) free(hdr->part);
if (hdr->volname) free(hdr->volname);
return ENOMEM;
}
strcpy(hdr->server, bckhdr->c_host);
strcpy(hdr->part, bckhdr->c_disk);
strcpy(hdr->volname, bckhdr->c_name);
}
if (tag) return ReadByte(X, tag);
else return 0;
}
/* Dump a stage backup header */
afs_uint32 DumpStageHdr(XFILE *OX, backup_system_header *hdr)
{
char buf[STAGE_HDRLEN];
struct stage_header *bckhdr = (struct stage_header *)buf;
afs_uint32 checksum;
afs_uint32 r;
memset(buf, 0, STAGE_HDRLEN);
bckhdr->c_vers = hdr->version;
bckhdr->c_fdate = htonl(hdr->from_date);
bckhdr->c_tdate = htonl(hdr->to_date);
bckhdr->c_filenum = htonl(hdr->filenum);
bckhdr->c_time = htonl(hdr->dump_date);
bckhdr->c_id = htonl(hdr->volid);
bckhdr->c_length = htonl(hdr->dumplen);
bckhdr->c_level = htonl(hdr->level);
bckhdr->c_magic = htonl(STAGE_MAGIC);
bckhdr->c_flags = htonl(hdr->flags);
strcpy(bckhdr->c_host, hdr->server);
strcpy(bckhdr->c_disk, hdr->part);
strcpy(bckhdr->c_name, hdr->volname);
/* Now, compute the checksum */
checksum = hdr_checksum(buf, STAGE_HDRLEN);
bckhdr->c_checksum = htonl(STAGE_CHECKSUM - checksum);
if (r = xfwrite(OX, buf, STAGE_HDRLEN)) return r;
return 0;
}

61
src/tests/stagehdr.h Normal file
View File

@ -0,0 +1,61 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* stagehdr.h - (old) Stage backup header format */
#ifndef _STAGEHDR_H_
#define _STAGEHDR_H_
#include "intNN.h"
/* Stage-related constants */
#define STAGE_MAGIC 0x00adf8bc /* magic number for stage header */
#define STAGE_CHECKSUM 84446 /* checksum (same as 4.2bsd dump) */
#define STAGE_VERSMIN 20 /* minimum version */
#define STAGE_NAMLEN 64 /* length of host/part/vol names */
#define STAGE_HDRLEN 1024 /* size of the header */
struct stage_header {
unsigned char c_vers; /* header version (starts at 20) */
unsigned char c_notused[3];
afs_uint32 c_fdate; /* dump "from" date */
afs_uint32 c_tdate; /* dump "to" date */
afs_uint32 c_filenum; /* tape file number */
afs_uint32 c_time; /* time dump was done */
char c_host[STAGE_NAMLEN]; /* hostname volume came from */
char c_disk[STAGE_NAMLEN]; /* partition volume came from */
char c_name[STAGE_NAMLEN]; /* volume name */
afs_uint32 c_id; /* volume ID */
afs_uint32 c_length; /* length of the dump */
afs_uint32 c_level; /* dump level */
afs_uint32 c_magic; /* magic number */
afs_uint32 c_checksum; /* checksum of backup header */
afs_uint32 c_flags; /* feature flags */
};
#endif /* _STAGEHDR_H_ */

164
src/tests/util.c Normal file
View File

@ -0,0 +1,164 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* util.c - Useful utilities */
#include <errno.h>
#include "xf_errs.h"
#include "dumpscan.h"
#include "dumpscan_errs.h"
#include "dumpfmt.h"
/* Take care of errno, ERROR_XFILE_EOF, and ENOMEM return codes.
* Call whatever callbacks are necessary, and return the code to
* actually use. If you don't want '0' to result in a DSERR_TAG,
* then you must translate it to DSERR_DONE before calling this.
*/
/*** THIS FUNCTION INTENDED FOR INTERNAL USE ONLY ***/
int handle_return(int r, XFILE *X, unsigned char tag, dump_parser *p)
{
u_int64 where, xwhere;
switch (r) {
case 0:
if (p->cb_error) {
xftell(X, &where);
sub64_32(xwhere, where, 1);
(p->cb_error)(DSERR_TAG, 1, p->err_refcon,
(tag > 0x20 && tag < 0x7f)
? "Unexpected tag '%c' at %s = 0x%s"
: "Unexpected tag 0x%02x at %s = 0x%s",
tag, decimate_int64(&xwhere, 0), hexify_int64(&xwhere, 0));
}
return DSERR_TAG;
case ERROR_XFILE_EOF:
if (p->cb_error) {
xftell(X, &where);
(p->cb_error)(ERROR_XFILE_EOF, 1, p->err_refcon,
"Unexpected EOF at %s = 0x%s",
decimate_int64(&where, 0), hexify_int64(&where, 0));
}
return ERROR_XFILE_EOF;
case ENOMEM:
if (p->cb_error) {
xftell(X, &where);
(p->cb_error)(ENOMEM, 1, p->err_refcon,
"Out of memory at %s = 0x%s",
decimate_int64(&where, 0), hexify_int64(&where, 0));
}
return ENOMEM;
case DSERR_DONE:
return 0;
default:
/* For other negative valuees, the callback was already done */
if (r > 0 && p->cb_error)
(p->cb_error)(r, 1, p->err_refcon,
"System error %d reading dump file", r);
return r;
}
}
/* Prepare a tag_parse_info for use by the dump parser. *
/*** THIS FUNCTION INTENDED FOR INTERNAL USE ONLY ***/
void prep_pi(dump_parser *p, tag_parse_info *pi)
{
memset(pi, 0, sizeof(tag_parse_info));
pi->err_refcon = p->err_refcon;
pi->cb_error = p->cb_error;
if (p->repair_flags & DSFIX_SKIP)
pi->flags |= TPFLAG_SKIP;
if ((p->flags & DSFLAG_SEEK) && (p->repair_flags & DSFIX_RSKIP))
pi->flags |= TPFLAG_RSKIP;
}
/* Does the designated location match a vnode?
* Returns 0 if yes, DSERR_FMT if no, something else on error
*/
/*** THIS FUNCTION INTENDED FOR INTERNAL USE ONLY ***/
int match_next_vnode(XFILE *X, dump_parser *p, u_int64 *where, afs_uint32 vnode)
{
afs_uint32 r, x, y, z;
unsigned char tag;
if (r = xfseek(X, where)) return r;
if (r = ReadByte(X, &tag)) return r;
switch (tag) {
case 3: /* A vnode? */
if (r = ReadInt32(X, &x)) return r;
if (r = ReadInt32(X, &y)) return r;
if (r = ReadByte(X, &tag)) return r;
if ( !((vnode & 1) && !(x & 1) && x < vnode)
&& !((vnode & 1) == (x & 1) && x > vnode))
return DSERR_FMT;
if (x > vnode && x - vnode > 10000) return DSERR_FMT;
if (y < 0 || y > p->vol_uniquifier) return DSERR_FMT;
/* Now, what follows the vnode/uniquifier? */
switch (tag) {
case 3: /* Another vnode? - Only if this is a non-directory */
if (x & 1) return DSERR_FMT;
if (r = ReadInt32(X, &z)) return r;
if ( !((x & 1) && !(z & 1) && z < x)
&& !((x & 1) == (z & 1) && z > x))
return DSERR_FMT;
return 0;
case 4: /* Dump end - Only if this is a non-directory */
if (x & 1) return DSERR_FMT;
if (r = ReadInt32(X, &z)) return r;
if (z != DUMPENDMAGIC) return DSERR_FMT;
return 0;
case 't': /* Vnode type byte */
if (r = ReadByte(X, &tag)) return r;
if ((tag == vFile || tag == vSymlink) && !(x & 1)) return 0;
if (tag == vDirectory && (x & 1)) return 0;
return DSERR_FMT;
default:
return DSERR_FMT;
}
case 4: /* A dump end? */
if (r = ReadInt32(X, &x)) return r;
if (x != DUMPENDMAGIC) return DSERR_FMT;
return 0;
default:
return DSERR_FMT;
}
}

37
src/tests/xf_errs.et Normal file
View File

@ -0,0 +1,37 @@
# CMUCS AFStools
# dumpscan - routines for scanning and manipulating AFS volume dumps
#
# Copyright (c) 1998 Carnegie Mellon University
# All Rights Reserved.
#
# Permission to use, copy, modify and distribute this software and its
# documentation is hereby granted, provided that both the copyright
# notice and this permission notice appear in all copies of the
# software, derivative works or modified versions, and any portions
# thereof, and that both notices appear in supporting documentation.
#
# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
# CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
#
# Carnegie Mellon requests users of this software to return to
#
# Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
# School of Computer Science
# Carnegie Mellon University
# Pittsburgh PA 15213-3890
#
# any improvements or extensions that they make and grant Carnegie Mellon
# the rights to redistribute these changes.
# xf_errs.et - Error table for xfiles
error_table xFil
ec ERROR_XFILE_EOF, "EOF while reading XFILE"
ec ERROR_XFILE_WRONLY, "XFILE may not be opened write-only"
ec ERROR_XFILE_RDONLY, "XFILE is read-only"
ec ERROR_XFILE_NOSEEK, "XFILE is not seekable"
ec ERROR_XFILE_ISPASS, "XFILE passthru already set"
ec ERROR_XFILE_NOPASS, "XFILE passthru not set"
ec ERROR_XFILE_TYPE, "unknown XFILE type"
end

200
src/tests/xf_files.c Normal file
View File

@ -0,0 +1,200 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* xf_files.c - XFILE routines for accessing UNIX files */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "xfiles.h"
#include "xf_errs.h"
#define O_MODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)
/* do_read for stdio xfiles */
static afs_uint32 xf_FILE_do_read(XFILE *X, void *buf, afs_uint32 count)
{
FILE *F = X->refcon;
/* XXX: handle short and interrupted reads */
if (fread(buf, count, 1, F) != 1)
return ferror(F) ? errno : ERROR_XFILE_EOF;
return 0;
}
/* do_write for stdio xfiles */
static afs_uint32 xf_FILE_do_write(XFILE *X, void *buf, afs_uint32 count)
{
FILE *F = X->refcon;
/* XXX: handle interrupted writes */
if (fwrite(buf, count, 1, F) != 1)
return errno;
return 0;
}
/* do_tell for stdio xfiles */
static afs_uint32 xf_FILE_do_tell(XFILE *X, u_int64 *offset)
{
FILE *F = X->refcon;
off_t where;
where = ftell(F);
if (where == -1) return errno;
set64(*offset, where);
return 0;
}
/* do_seek for stdio xfiles */
static afs_uint32 xf_FILE_do_seek(XFILE *X, u_int64 *offset)
{
FILE *F = X->refcon;
off_t where = get64(*offset);
if (fseek(F, where, SEEK_SET) == -1) return errno;
return 0;
}
/* do_skip for stdio xfiles */
static afs_uint32 xf_FILE_do_skip(XFILE *X, afs_uint32 count)
{
FILE *F = X->refcon;
if (fseek(F, count, SEEK_CUR) == -1) return errno;
return 0;
}
/* do_close for stdio xfiles */
static afs_uint32 xf_FILE_do_close(XFILE *X)
{
FILE *F = X->refcon;
X->refcon = 0;
if (fclose(F)) return errno;
return 0;
}
/* Prepare a stdio XFILE */
static void prepare(XFILE *X, FILE *F, int xflag)
{
struct stat st;
memset(X, 0, sizeof(*X));
X->do_read = xf_FILE_do_read;
X->do_write = xf_FILE_do_write;
X->do_tell = xf_FILE_do_tell;
X->do_close = xf_FILE_do_close;
X->refcon = F;
if (xflag == O_RDWR) X->is_writable = 1;
if (!fstat(fileno(F), &st)
&& ((st.st_mode & S_IFMT) == S_IFREG
|| (st.st_mode & S_IFMT) == S_IFBLK)) {
X->is_seekable = 1;
X->do_seek = xf_FILE_do_seek;
X->do_skip = xf_FILE_do_skip;
}
}
/* Open an XFILE by path */
afs_uint32 xfopen_path(XFILE *X, int flag, char *path, int mode)
{
FILE *F = 0;
int fd = -1, xflag;
afs_uint32 code;
xflag = flag & O_MODE_MASK;
if (xflag == O_WRONLY) return ERROR_XFILE_WRONLY;
if ((fd = open(path, flag, mode)) < 0) return errno;
if (!(F = fdopen(fd, (xflag == O_RDONLY) ? "r" : "r+"))) {
code = errno;
close(fd);
return code;
}
prepare(X, F, xflag);
return 0;
}
/* Open an XFILE by FILE * */
afs_uint32 xfopen_FILE(XFILE *X, int flag, FILE *F)
{
flag &= O_MODE_MASK;
if (flag == O_WRONLY) return ERROR_XFILE_WRONLY;
prepare(X, F, flag);
return 0;
}
/* Open an XFILE by file descriptor */
afs_uint32 xfopen_fd(XFILE *X, int flag, int fd)
{
FILE *F;
flag &= O_MODE_MASK;
if (flag == O_WRONLY) return ERROR_XFILE_WRONLY;
if (!(F = fdopen(fd, (flag == O_RDONLY) ? "r" : "r+"))) return errno;
prepare(X, F, flag);
return 0;
}
/* open-by-name support for filenames */
afs_uint32 xfon_path(XFILE *X, int flag, char *name)
{
return xfopen_path(X, flag, name, 0644);
}
/* open-by-name support for file descriptors */
afs_uint32 xfon_fd(XFILE *X, int flag, char *name)
{
int fd = atoi(name);
return xfopen_fd(X, flag, fd);
}
/* open-by-name support for standard I/O */
afs_uint32 xfon_stdio(XFILE *X, int flag)
{
flag &= O_MODE_MASK;
if (flag == O_WRONLY) flag = O_RDWR;
return xfopen_FILE(X, flag, (flag == O_RDONLY) ? stdin : stdout);
}

444
src/tests/xf_printf.c Normal file
View File

@ -0,0 +1,444 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <ctype.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include "xfiles.h"
#include "xf_errs.h"
#define SPBUFLEN 40
static char spbuf[SPBUFLEN + 1] = "";
#define MAXPREC 100
/* Generate an ASCII representation of an integer <val>, as follows:
* <base> indicates the base to be used (2-36)
* <uc> is nonzero if letter digits should be uppercase
* <prec> is the minimum number of digits
* The resulting number is stored in <buf>, which must be long enough
* to receive it. The minimum length is <prec> or ceil(log{base}(val)),
* whichever is larger, plus room for a trailing NUL.
*/
static void mkint(char *buf, unsigned long val, int base, int uc, int prec)
{
int len = 0, dig, i;
while (val) {
dig = val % base;
val = (val - dig) / base;
if (dig < 10) dig = dig + '0';
else if (uc) dig = dig + 'A' - 10;
else dig = dig + 'a' - 10;
buf[len++] = dig;
}
while (len < prec) buf[len++] = '0';
for (i = 0; i < (len + 1) / 2; i++) {
dig = buf[i];
buf[i] = buf[len - i - 1];
buf[len - i - 1] = dig;
}
buf[len] = 0;
}
/* Write spaces faster than one at a time */
static afs_uint32 wsp(XFILE *X, int count)
{
char *x;
afs_uint32 err;
int i;
if (!spbuf[0]) {
for (x = spbuf, i = SPBUFLEN; i; x++, i--) *x = ' ';
}
while (count > SPBUFLEN) {
err = xfwrite(X, spbuf, SPBUFLEN);
if (err) return err;
count -= SPBUFLEN;
}
if (count > 0) return xfwrite(X, spbuf, count);
return 0;
}
/* This function is a mostly-complete implementation of snprintf,
* with the following features:
*
* - Actually obeys the length limit, which (unfortunately) many
* implementations of snprintf do not.
*
* - Supports all the standard format specifiers for integers
* (d, i, o, u, x, X), floating-point values (f, e, E, g, G),
* and strings and characters (c, s, %), plus a few unusual
* but useful ones described below.
*
* - Supports all the standard flags (-, 0, +, space, #). These
* flags are ignored if used when they are not appropriate.
*
* - Supports the standard size modifiers for short (h), long (h),
* and double (L) arguments. These modifiers are ignored if used
* when they are not appropriate.
*
* - Supports minimum field width and precision, where appropriate,
* including the use of '*' to specify a value given as an argument
* instead of in the format string. There is a maximum precision
* of 100 digits.
*
* - At present, the 'p' specifier for printing pointers is not
* implemented, because it is inherently non-portable and thus
* can be implemented correctly only by the compiler's run-time
* library.
*
* - Floating-point specifier (%e, %f, %g) are implemented by
* calling the standard sprintf, and thus may be unsafe.
*
* - The '%...$' notation is used primarily when the format string
* is specified by the user, who knows but cannot change the order
* of the arguments. Such usage is inherently dangerous and
* insecure; thus, it is not supported.
*
* The custom format specifier '%I' is supported. This specifier
* takes as its argument an unsigned long integer containing an
* IPv4 address in network byte order. The address is rendered
* either as a hostname or as a dotted quad, as follows:
*
* - If precision is nonzero or unspecified, a hostname lookup
* is attempted; if it is successful, the hostname is printed.
* If the hostname lookup fails, the address is printed in
* dotted-quad notation.
*
* - If precision is explicitly specified as 0, then the hostname
* lookup is skipped, and dotted-quad notation is always used.
*
* - If a hostname is to be printed:
* + The precision controls the maximum number of characters
* printed, as with %s.
* + If the '#' flag is specified, any letters in the hostname
* will be forced to lower case before printing.
* + If the '+' flag is specified, any letters in the hostname
* will be forced to upper case before printing. If both
* '#' and '+' are given, the '+' flag will be ignored.
* + The '0' and ' ' flags have no effect.
*
* - If a dotted quad is to be printed:
* + The precision has no effect; dotted quads are always
* 7 to 12 characters in length, depending on the value
* to be printed and the format flags used.
* + If the '0' flag is given, each field (byte) of the address
* will be padded with '0' on the left to three digits.
* + If the ' ' flag is given, each field (byte) of the address
* will be padded with spaces on the left to three digits. If
* both '0' and ' ' are given, the ' ' flag will be ignored.
* + The '#' and '+' flags have no effect.
*/
afs_uint32 vxfprintf(XFILE *X, char *fmt, va_list ap)
{
unsigned int width, precision, haveprec, len;
int ljust, plsign, spsign, altform, zfill;
int hflag, lflag, count, *countp, j;
char *x, *y, *lit = 0, xbuf[MAXPREC + 21], fbuf[20];
struct hostent *he;
struct in_addr ia;
unsigned long UVAL;
long SVAL, *lcountp;
double FVAL;
short *hcountp;
afs_uint32 err;
count = 0;
while (*fmt) {
if (*fmt != '%') {
if (!lit) lit = fmt;
fmt++;
count++;
continue;
}
if (lit) {
if ((err = xfwrite(X, lit, fmt - lit))) return err;
lit = 0;
}
/** Found a format specifier **/
ljust = plsign = spsign = altform = zfill = 0;
width = precision = haveprec = 0;
hflag = lflag = 0;
fmt++;
/* parse format flags */
while (*fmt) {
switch (*fmt) {
case '-': ljust = 1; fmt++; continue; /* left justify */
case '+': plsign = 1; fmt++; continue; /* use + or - */
case ' ': spsign = 1; fmt++; continue; /* use space or - */
case '#': altform = 1; fmt++; continue; /* alternate form */
case '0': zfill = 1; fmt++; continue; /* pad with 0 */
default: break;
}
break;
}
/* parse minimum width */
if (*fmt == '*') {
width = va_arg(ap, int);
fmt++;
} else while (isdigit(*fmt)) {
width = (width * 10) + (*fmt - '0');
fmt++;
}
/* parse precision */
if (*fmt == '.') {
fmt++;
haveprec = 1;
if (*fmt == '*') {
precision = va_arg(ap, int);
fmt++;
} else while (isdigit(*fmt)) {
precision = (precision * 10) + (*fmt - '0');
fmt++;
}
}
/* parse size flags */
while (*fmt) {
switch (*fmt) {
case 'h': hflag = 1; fmt++; continue; /* short argument */
case 'l': lflag = 1; fmt++; continue; /* long argument */
default: break;
}
break;
}
/* parse format specifier */
if (!*fmt) break;
switch (*fmt++) {
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
FVAL = va_arg(ap, double);
sprintf(fbuf, "%%%s%s.*L%c", plsign ? "+" : (spsign ? " " : ""),
altform ? "#" : "", fmt[-1]);
if (!haveprec) precision = 6;
if (precision > MAXPREC) precision = MAXPREC;
sprintf(xbuf, fbuf, precision, FVAL);
x = xbuf;
len = strlen(x);
break;
case 'i':
case 'd': /* signed decimal integer */
if (lflag) SVAL = va_arg(ap, long);
else if (hflag) SVAL = va_arg(ap, int);
else SVAL = va_arg(ap, int);
UVAL = (SVAL < 0) ? -SVAL : SVAL;
if (SVAL < 0) xbuf[0] = '-';
else if (plsign) xbuf[0] = '+';
else if (spsign) xbuf[0] = ' ';
else xbuf[0] = 0;
if (!haveprec) {
if (zfill && !ljust) precision = width - !!xbuf[0];
else precision = 1;
if (precision < 1 + !!xbuf[0]) precision = 1 + !!xbuf[0];
}
if (precision > MAXPREC) precision = MAXPREC;
mkint(xbuf + 1, UVAL, 10, 0, precision);
x = xbuf + !xbuf[0];
len = strlen(x);
break;
case 'o': /* unsigned octal integer */
if (lflag) UVAL = va_arg(ap, unsigned long);
else if (hflag) UVAL = va_arg(ap, unsigned int);
else UVAL = va_arg(ap, unsigned int);
xbuf[0] = '0';
if (!haveprec) {
if (zfill && !ljust) precision = width;
else precision = 1;
}
if (precision > MAXPREC) precision = MAXPREC;
mkint(xbuf + 1, UVAL, 8, 0, precision);
x = xbuf + (xbuf[1] == '0' || !altform);
len = strlen(x);
break;
case 'u': /* unsigned decimal integer */
if (lflag) UVAL = va_arg(ap, unsigned long);
else if (hflag) UVAL = va_arg(ap, unsigned int);
else UVAL = va_arg(ap, unsigned int);
if (!haveprec) {
if (zfill && !ljust) precision = width;
else precision = 1;
}
if (precision > MAXPREC) precision = MAXPREC;
mkint(xbuf, UVAL, 10, 0, precision);
x = xbuf;
len = strlen(x);
break;
case 'x':
case 'X': /* unsigned hexadecimal integer */
if (lflag) UVAL = va_arg(ap, unsigned long);
else if (hflag) UVAL = va_arg(ap, unsigned int);
else UVAL = va_arg(ap, unsigned int);
xbuf[0] = '0';
xbuf[1] = 'x';
if (!haveprec) {
if (zfill && !ljust) precision = width;
else precision = 1;
}
if (precision > MAXPREC) precision = MAXPREC;
mkint(xbuf + 2, UVAL, 16, 0, precision);
x = xbuf + ((altform && UVAL) ? 0 : 2);
len = strlen(x);
break;
case '%': /* literal % */
xbuf[0] = '%';
xbuf[1] = 0;
x = xbuf;
len = 1;
break;
case 'c': /* character */
xbuf[0] = va_arg(ap, int);
xbuf[1] = 0;
x = xbuf;
len = 1;
break;
case 's': /* string */
x = va_arg(ap, char *);
if (!x) x = "<null>";
len = strlen(x);
if (haveprec && precision < len) len = precision;
break;
case 'I': /* IP address:
* value is provided as a network-order unsigned long integer
* precision specifies max hostname length, as for %s
* if precision is explicitly 0, no hostname lookup is done
* if 0fill specified, IPaddr fields are 0-filled to 3 digits
* if spsign specified, IPaddr fields are space-filled to 3 digits
*/
UVAL = va_arg(ap, unsigned long);
ia.s_addr = UVAL;
/* XXX: add support for an application-provided function
* for doing hostname lookups. We don't do it automatically
* because on some platforms that would prevent us from
* being fully statically linked.
*/
if (haveprec && !precision) he = 0;
else he = gethostbyaddr((char *)&ia, 4, AF_INET);
if (he) {
x = he->h_name;
len = strlen(x);
if (haveprec && precision < len) len = precision;
if (altform)
for (y = x; *y; y++) if (isupper(*y)) *y = tolower(*y);
else if (plsign)
for (y = x; *y; y++) if (islower(*y)) *y = toupper(*y);
} else {
UVAL = ntohl(UVAL);
if (zfill) x = "%03u.%03u.%03u.%03u";
else if (spsign) x = "%3u.%3u.%3u.%3u";
else x = "%u.%u.%u.%u";
sprintf(xbuf, x,
(UVAL & 0xff000000) >> 24, (UVAL & 0x00ff0000) >> 16,
(UVAL & 0x0000ff00) >> 8, (UVAL & 0x000000ff));
x = xbuf;
len = strlen(xbuf);
}
break;
case 'n': /* report count so far */
if (lflag) {
lcountp = va_arg(ap, long *);
*lcountp = count;
} else if (hflag) {
hcountp = va_arg(ap, short *);
*hcountp = count;
} else {
countp = va_arg(ap, int *);
*countp = count;
}
continue;
default: /* unknown specifier */
continue;
}
/* render the results */
if (!width) width = len;
j = width - len;
if (j > 0) count += j;
count += len;
if (!ljust && (err = wsp(X, j))) return err;
if ((err = xfwrite(X, x, len))) return err;
if (ljust && (err = wsp(X, j))) return err;
}
if (lit && (err = xfwrite(X, lit, fmt - lit))) return err;
return 0;
lose:
return err;
}
afs_uint32 xfprintf(XFILE *X, char *fmt, ...)
{
va_list ap;
afs_uint32 err;
va_start(ap, fmt);
err = vxfprintf(X, fmt, ap);
va_end(ap);
return err;
}

184
src/tests/xf_profile.c Normal file
View File

@ -0,0 +1,184 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* xf_profile.c - XFILE routines for read/write profiling */
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include "xfiles.h"
#include "xf_errs.h"
#define O_MODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)
typedef struct {
XFILE content;
XFILE profile;
} PFILE;
/* do_read for profiled xfiles */
static afs_uint32 xf_PROFILE_do_read(XFILE *X, void *buf, afs_uint32 count)
{
PFILE *PF = X->refcon;
afs_uint32 err;
err = xfread(&PF->content, buf, count);
xfprintf(&PF->profile, "R %ld =%ld\n", (long)count, (long)err);
return err;
}
/* do_write for profiled xfiles */
static afs_uint32 xf_PROFILE_do_write(XFILE *X, void *buf, afs_uint32 count)
{
PFILE *PF = X->refcon;
afs_uint32 err;
err = xfwrite(&PF->content, buf, count);
xfprintf(&PF->profile, "W %ld =%ld\n", (long)count, (long)err);
return err;
}
/* do_tell for profiled xfiles */
static afs_uint32 xf_PROFILE_do_tell(XFILE *X, u_int64 *offset)
{
PFILE *PF = X->refcon;
afs_uint32 err;
err = xftell(&PF->content, offset);
if (err) xfprintf(&PF->profile, "TELL ERR =%ld\n", (long)err);
else xfprintf(&PF->profile, "TELL %s =0\n", hexify_int64(offset, 0));
return err;
}
/* do_seek for profiled xfiles */
static afs_uint32 xf_PROFILE_do_seek(XFILE *X, u_int64 *offset)
{
PFILE *PF = X->refcon;
afs_uint32 err;
err = xfseek(&PF->content, offset);
xfprintf(&PF->profile, "SEEK %s =%ld\n", hexify_int64(offset, 0), (long)err);
return err;
}
/* do_skip for profiled xfiles */
static afs_uint32 xf_PROFILE_do_skip(XFILE *X, afs_uint32 count)
{
PFILE *PF = X->refcon;
afs_uint32 err;
err = xfskip(&PF->content, count);
xfprintf(&PF->profile, "SKIP %ld =%ld\n", (long)count, (long)err);
return err;
}
/* do_close for profiled xfiles */
static afs_uint32 xf_PROFILE_do_close(XFILE *X)
{
PFILE *PF = X->refcon;
afs_uint32 err, err2;
err = xfclose(&PF->content);
err2 = xfclose(&PF->profile);
free(PF);
return err ? err : err2;
}
/* Open a profiled XFILE */
afs_uint32 xfopen_profile(XFILE *X, int flag, char *xname, char *profile)
{
PFILE *PF;
afs_uint32 err;
PF = malloc(sizeof(*PF));
if (!PF) return ENOMEM;
memset(PF, 0, sizeof(*PF));
err = xfopen(&PF->profile, O_RDWR|O_CREAT|O_TRUNC, profile);
if (err) {
free(PF);
return err;
}
err = xfopen(&PF->content, flag, xname);
if (err) {
xfclose(&PF->profile);
free(PF);
return err;
}
memset(X, 0, sizeof(*X));
X->refcon = PF;
X->do_read = xf_PROFILE_do_read;
X->do_write = xf_PROFILE_do_write;
X->do_tell = xf_PROFILE_do_tell;
X->do_close = xf_PROFILE_do_close;
X->is_writable = PF->content.is_writable;
if (PF->content.is_seekable) {
X->is_seekable;
X->do_seek = xf_PROFILE_do_seek;
X->do_skip = xf_PROFILE_do_skip;
}
xfprintf(&PF->profile, "OPEN %s\n", xname);
return 0;
}
afs_uint32 xfon_profile(XFILE *X, int flag, char *name)
{
char *x, *profile, *xname;
afs_uint32 err;
if (!(name = strdup(name))) return ENOMEM;
profile = "-";
xname = name;
for (x = name; *x; x++) {
if (x[0] == ':' && x[1] == ':') {
*x = 0;
profile = name;
xname = x + 2;
break;
}
}
if (!*name) profile = "-";
err = xfopen_profile(X, flag, xname, profile);
free(name);
return err;
}

260
src/tests/xf_rxcall.c Normal file
View File

@ -0,0 +1,260 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* xf_rxcall.c - XFILE routines for Rx bulk data transfers */
#include <sys/types.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <netdb.h>
#include "xfiles.h"
#include "xf_errs.h"
#include <rx/xdr.h>
#include <rx/rx.h>
#include <rx/rx_null.h>
#include <rx/rxkad.h>
#include <afs/auth.h>
#include <afs/cellconfig.h>
#include <afs/vlserver.h>
#include <afs/volser.h>
#ifndef AFSCONF_CLIENTNAME
#include <afs/dirpath.h>
#define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH
#endif
#define O_MODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)
struct rxinfo {
struct rx_connection *conn; /* connection */
struct rx_call *call; /* call */
afs_int32 tid; /* volser transaction ID */
afs_uint32 code; /* result code */
};
static afs_uint32 xf_rxcall_do_read(XFILE *X, void *buf, afs_uint32 count)
{
struct rxinfo *i = X->refcon;
afs_uint32 xcount;
xcount = rx_Read(i->call, buf, count);
if (xcount == count) return 0;
i->code = rx_EndCall(i->call, 0);
i->call = 0;
return i->code ? i->code : ERROR_XFILE_RDONLY;
}
static afs_uint32 xf_rxcall_do_write(XFILE *X, void *buf, afs_uint32 count)
{
struct rxinfo *i = X->refcon;
afs_uint32 xcount;
xcount = rx_Write(i->call, buf, count);
if (xcount == count) return 0;
i->code = rx_EndCall(i->call, 0);
i->call = 0;
return i->code;
}
static afs_uint32 xf_rxcall_do_close(XFILE *X)
{
struct rxinfo *i = X->refcon;
afs_uint32 code;
if (i->call) {
code = rx_EndCall(i->call, i->code);
i->call = 0;
} else {
code = i->code;
}
free(i);
return code;
}
static afs_uint32 xf_voldump_do_close(XFILE *X)
{
struct rxinfo *i = X->refcon;
struct rx_connection *conn = i->conn;
afs_uint32 code, rcode, xcode;
afs_int32 tid = i->tid;
code = xf_rxcall_do_close(X);
xcode = AFSVolEndTrans(conn, tid, &rcode);
if (!code) code = xcode ? xcode : rcode;
return code;
}
afs_uint32 xfopen_rxcall(XFILE *X, int flag, struct rx_call *call)
{
struct rxinfo *i;
flag &= O_MODE_MASK;
if (flag == O_WRONLY) return ERROR_XFILE_WRONLY;
memset(X, 0, sizeof(*X));
if (!(i = (struct rxinfo *)malloc(sizeof(struct rxinfo)))) return ENOMEM;
i->call = call;
i->code = 0;
X->do_read = xf_rxcall_do_read;
X->do_write = xf_rxcall_do_write;
X->do_close = xf_rxcall_do_close;
X->is_writable = (flag == O_RDWR);
X->refcon = i;
return 0;
}
afs_uint32 xfopen_voldump(XFILE *X, struct rx_connection *conn,
afs_int32 part, afs_int32 volid, afs_int32 date)
{
struct rx_call *call;
struct rxinfo *i;
afs_uint32 code, rcode;
afs_int32 tid;
if (code = AFSVolTransCreate(conn, volid, part, ITBusy, &tid)) return code;
call = rx_NewCall(conn);
if ((code = StartAFSVolDump(call, tid, date))
|| (code = xfopen_rxcall(X, O_RDONLY, call))) {
rx_EndCall(call, 0);
AFSVolEndTrans(conn, tid, &rcode);
return code;
}
i = X->refcon;
i->conn = conn;
i->tid = tid;
X->do_close = xf_voldump_do_close;
return 0;
}
afs_uint32 xfon_voldump(XFILE *X, int flag, char *name)
{
struct hostent *he;
struct rx_securityClass *class;
struct rx_connection *conn;
struct ktc_principal sname;
struct ktc_token token;
struct afsconf_dir *confdir;
afs_uint32 code, server_addr;
afs_int32 volid, partid, date;
int isnum, index;
char *x, *y;
/* Parse out the optional date and server location */
if (code = rx_Init(0)) return code;
if (!(name = strdup(name))) return ENOMEM;
if (x = strrchr(name, ',')) {
*x++ = 0;
date = atoi(x);
} else {
date = 0;
}
if (x = strrchr(name, '@')) {
int a, b, c, d;
*x++ = 0;
if (!(y = strchr(x, '/'))) {
free(name);
return VL_BADPARTITION;
}
*y++ = 0;
if (sscanf(x, "%d.%d.%d.%d", &a, &b, &c, &d) == 4
&& a >= 0 && a <= 255 && b >= 0 && b <= 255
&& c >= 0 && c <= 255 && d >= 0 && d <= 255) {
server_addr = (a << 24) | (b << 16) | (c << 8) | d;
server_addr = htonl(server_addr);
} else {
he = gethostbyname(x);
if (!he) {
free(name);
return VL_BADSERVER;
}
memcpy(&server_addr, he->h_addr, sizeof(server_addr));
}
partid = volutil_GetPartitionID(y);
if (partid < 0) {
free(name);
return VL_BADPARTITION;
}
}
/* Get tokens and set up a security object */
confdir = afsconf_Open(AFSCONF_CLIENTNAME);
if (!confdir) {
free(name);
return AFSCONF_NODB;
}
if (code = afsconf_GetLocalCell(confdir, sname.cell, MAXKTCNAMELEN)) {
free(name);
return code;
}
afsconf_Close(confdir);
strcpy(sname.name, "afs");
sname.instance[0] = 0;
code = ktc_GetToken(&sname, &token, sizeof(token), 0);
if (code) {
class = rxnull_NewClientSecurityObject();
index = 0;
} else {
class = rxkad_NewClientSecurityObject(rxkad_clear, &token.sessionKey,
token.kvno, token.ticketLen, token.ticket);
index = 2;
}
/* Figure out the volume ID, looking it up in the VLDB if neccessary.
* Also look up the server and partition, if they were not specified.
*/
for (isnum = 1, y = name; *y; y++)
if (*y < '0' || *y > '9') isnum = 0;
if (isnum) {
volid = atoi(name);
if (!x) {
fprintf(stderr, "XXX: need to lookup volume by ID!\n");
exit(-1);
}
} else {
fprintf(stderr, "XXX: need to lookup volume by name!\n");
exit(-1);
}
free(name);
/* Establish a connection and start the call */
conn = rx_NewConnection(server_addr, htons(AFSCONF_VOLUMEPORT),
VOLSERVICE_ID, class, index);
return xfopen_voldump(X, conn, partid, volid, date);
}

219
src/tests/xfiles.c Normal file
View File

@ -0,0 +1,219 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* xfiles.c - General support routines for xfiles */
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include "xfiles.h"
#include "xf_errs.h"
#define SKIP_SIZE 65536
extern afs_uint32 xfon_path(XFILE *, int, char *);
extern afs_uint32 xfon_fd(XFILE *, int, char *);
extern afs_uint32 xfon_voldump(XFILE *, int, char *);
extern afs_uint32 xfon_profile(XFILE *, int, char *);
extern afs_uint32 xfon_stdio(XFILE *, int);
struct xftype {
struct xftype *next;
char *name;
afs_uint32 (*do_on)(XFILE *, int, char *);
};
static struct xftype *xftypes = 0;
static int did_register_defaults = 0;
afs_uint32 xfread(XFILE *X, void *buf, afs_uint32 count)
{
afs_uint32 code;
u_int64 tmp64;
code = (X->do_read)(X, buf, count);
if (code) return code;
add64_32(tmp64, X->filepos, count);
cp64(X->filepos, tmp64);
if (X->passthru) return xfwrite(X->passthru, buf, count);
return 0;
}
afs_uint32 xfwrite(XFILE *X, void *buf, afs_uint32 count)
{
afs_uint32 code;
u_int64 tmp64;
if (!X->is_writable) return ERROR_XFILE_RDONLY;
code = (X->do_write)(X, buf, count);
if (code) return code;
add64_32(tmp64, X->filepos, count);
cp64(X->filepos, tmp64);
return 0;
}
afs_uint32 xftell(XFILE *X, u_int64 *offset)
{
if (X->do_tell) return (X->do_tell)(X, offset);
cp64(*offset, X->filepos);
return 0;
}
afs_uint32 xfseek(XFILE *X, u_int64 *offset)
{
afs_uint32 code;
if (!X->do_seek) return ERROR_XFILE_NOSEEK;
code = (X->do_seek)(X, offset);
if (code) return code;
cp64(X->filepos, *offset);
return 0;
}
afs_uint32 xfskip(XFILE *X, afs_uint32 count)
{
afs_uint32 code;
u_int64 tmp64;
/* Use the skip method, if there is one */
if (X->do_skip && !X->passthru) {
code = (X->do_skip)(X, count);
if (code) return code;
add64_32(tmp64, X->filepos, count);
cp64(X->filepos, tmp64);
return 0;
}
/* Simulate using absolute seek, if available */
if (X->do_seek && !X->passthru) {
if (code = xftell(X, &tmp64)) return code;
add64_32(X->filepos, tmp64, count);
cp64(tmp64, X->filepos);
return xfseek(X, &tmp64);
}
/* Do it the hard/slow way - read all the data to be skipped.
* This is done if no other method is available, or if we are
* supposed to be copying all the data to another XFILE
*/
{
char buf[SKIP_SIZE];
afs_uint32 n;
while (count) {
n = (count > SKIP_SIZE) ? SKIP_SIZE : count;
if (code = xfread(X, buf, n)) return code;
count -= n;
}
return 0;
}
}
afs_uint32 xfpass(XFILE *X, XFILE *Y)
{
if (X->passthru) return ERROR_XFILE_ISPASS;
if (!Y->is_writable) return ERROR_XFILE_RDONLY;
X->passthru = Y;
return 0;
}
afs_uint32 xfunpass(XFILE *X)
{
if (!X->passthru) return ERROR_XFILE_NOPASS;
X->passthru = 0;
return 0;
}
afs_uint32 xfclose(XFILE *X)
{
int code = 0;
if (X->do_close) code = (X->do_close)(X);
memset(X, 0, sizeof(*X));
return 0;
}
afs_uint32 xfregister(char *name, afs_uint32 (*do_on)(XFILE *, int, char *))
{
struct xftype *x;
if (!(x = (struct xftype *)malloc(sizeof(struct xftype)))) return ENOMEM;
memset(x, 0, sizeof(*x));
x->next = xftypes;
x->name = name;
x->do_on = do_on;
xftypes = x;
}
static void register_default_types(void)
{
xfregister("FILE", xfon_path);
xfregister("FD", xfon_fd);
xfregister("AFSDUMP", xfon_voldump);
xfregister("PROFILE", xfon_profile);
did_register_defaults = 1;
}
afs_uint32 xfopen(XFILE *X, int flag, char *name)
{
struct xftype *x;
char *type, *sep;
if (!did_register_defaults) register_default_types();
if (!strcmp(name, "-")) return xfon_stdio(X, flag);
for (type = name; *name && *name != ':'; name++);
if (*name) {
sep = name;
*name++ = 0;
} else {
sep = 0;
name = type;
type = "FILE";
}
for (x = xftypes; x; x = x->next)
if (!strcmp(type, x->name)) break;
if (sep) *sep = ':';
if (x) return (x->do_on)(X, flag, name);
return ERROR_XFILE_TYPE;
}

88
src/tests/xfiles.h Normal file
View File

@ -0,0 +1,88 @@
/*
* CMUCS AFStools
* dumpscan - routines for scanning and manipulating AFS volume dumps
*
* Copyright (c) 1998 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/* xfiles.h - Type, constant, and function declarations for
* extensible file-like things */
#ifndef _XFILES_H_
#define _XFILES_H_
#include <stdio.h>
#include <stdarg.h>
#include "intNN.h"
struct rx_call;
struct rx_connection;
/* The XFILE structure */
typedef struct XFILE XFILE;
struct XFILE {
afs_uint32 (*do_read)(XFILE *, void *, afs_uint32); /* read data */
afs_uint32 (*do_write)(XFILE *, void *, afs_uint32); /* write data */
afs_uint32 (*do_tell)(XFILE *, u_int64 *); /* find position */
afs_uint32 (*do_seek)(XFILE *, u_int64 *); /* set position */
afs_uint32 (*do_skip)(XFILE *, afs_uint32); /* skip forward */
afs_uint32 (*do_close)(XFILE *); /* close */
u_int64 filepos; /* position (counted) */
int is_seekable; /* 1 if seek works */
int is_writable; /* 1 if write works */
XFILE *passthru; /* XFILE to pass thru to */
void *refcon; /* type-specific data */
};
/* Functions for opening XFILEs. For these, the first two arguments are
* always a pointer to an XFILE to fill in, and the mode in which to
* open the file. O_RDONLY and O_RDWR are permitted; O_WRONLY is not.
* Other open modes may or may not be used, depending on the object type.
* Remaining arguments are a function of the object type
*/
extern afs_uint32 xfopen (XFILE *, int, char *); /* open by TYPE:name */
extern afs_uint32 xfopen_path(XFILE *, int, char *, int); /* open by path */
extern afs_uint32 xfopen_FILE(XFILE *, int, FILE *); /* open by FILE * */
extern afs_uint32 xfopen_fd (XFILE *, int, int); /* open by fd */
extern afs_uint32 xfopen_rxcall (XFILE *, int, struct rx_call *);
extern afs_uint32 xfopen_voldump(XFILE *, struct rx_connection *,
afs_int32, afs_int32, afs_int32);
extern afs_uint32 xfopen_profile(XFILE *, int, char *, char *);
extern afs_uint32 xfregister(char *, afs_uint32 (*)(XFILE *, int, char *));
/* Standard operations on XFILEs */
extern afs_uint32 xfread(XFILE *, void *, afs_uint32); /* read data */
extern afs_uint32 xfwrite(XFILE *, void *, afs_uint32); /* write data */
extern afs_uint32 xfprintf(XFILE *, char *, ...); /* formatted */
extern afs_uint32 vxfprintf(XFILE *, char *, va_list); /* formatted VA */
extern afs_uint32 xftell(XFILE *, u_int64 *); /* get position */
extern afs_uint32 xfseek(XFILE *, u_int64 *); /* set position */
extern afs_uint32 xfskip(XFILE *, afs_uint32); /* skip forward */
extern afs_uint32 xfpass(XFILE *, XFILE *); /* set passthru */
extern afs_uint32 xfunpass(XFILE *); /* unset passthru */
extern afs_uint32 xfclose(XFILE *); /* close */
#endif /* _XFILES_H_ */