[OpenAFS-devel] (patch) Adding utility to do a volume dump table of contents...

Marc Mengel mengel@fnal.gov
Thu, 09 May 2002 14:32:34 -0500


--=-BI/zzuLtHCWVIp64i9RP
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

There is a utility (restorevol) in OpenAFS to unpack a vos dump image
into a file tree, but I wanted something to just give me a listing of
what files/directories were in the volume, so I hacked up the attached,
which adds "tocvol" to the OpenAFS tree to do a table of contents of a
vos dump image.

Why did I want this? I'm working on integrating AFS backups into 
Amanda, and I wanted a table of contents of the volume dump so
I can have file level backup indexing...

Anyway, it's mostly restorevol with most of its guts replaced with
a (wimpy, horribly inefficient, but simple) vnode graph.



--=-BI/zzuLtHCWVIp64i9RP
Content-Disposition: inline; filename=openafs-tocvol-patch
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-patch; name=openafs-tocvol-patch; charset=ISO-8859-1

*** src/volser/Makefile.in.orig	Thu May  9 11:43:41 2002
--- src/volser/Makefile.in	Thu May  9 11:42:21 2002
***************
*** 8,14 ****
  srcdir=3D@srcdir@
  include @TOP_OBJDIR@/src/config/Makefile.config
 =20
-=20
  CFLAGS=3D-I. -I${srcdir} ${DBG} ${OPTMZ} -I${TOP_OBJDIR}/src/config -I${T=
OP_INCDIR} ${XCFLAGS}
  LDFLAGS=3D${DBG} ${OPTMZ} ${XLDFLAGS}
 =20
--- 8,13 ----
***************
*** 48,54 ****
  SOBJS=3Dvolmain.o volprocs.o physio.o common.o voltrans.o volerr.o \
   volint.cs.o dumpstuff.o volint.ss.o volint.xdr.o
 =20
! all: volserver vos restorevol \
  	${TOP_INCDIR}/afs/volser.h \
  	${TOP_INCDIR}/afs/volint.h \
  	${TOP_LIBDIR}/libvolser.a
--- 47,53 ----
  SOBJS=3Dvolmain.o volprocs.o physio.o common.o voltrans.o volerr.o \
   volint.cs.o dumpstuff.o volint.ss.o volint.xdr.o
 =20
! all: volserver vos restorevol tocvol \
  	${TOP_INCDIR}/afs/volser.h \
  	${TOP_INCDIR}/afs/volint.h \
  	${TOP_LIBDIR}/libvolser.a
***************
*** 57,62 ****
--- 56,65 ----
  	${CC} ${CFLAGS} -o restorevol ${srcdir}/restorevol.c \
  		${TOP_LIBDIR}/libcmd.a ${TOP_LIBDIR}/util.a
 =20
+ tocvol: tocvol.c
+ 	${CC} ${CFLAGS} -o tocvol ${srcdir}/tocvol.c \
+ 		${TOP_LIBDIR}/libcmd.a ${TOP_LIBDIR}/util.a
+=20
  vos: vos.o ${VSOBJS} libvolser.a ${LIBS}
  	${CC} ${LDFLAGS} -o vos vos.o $(VSOBJS) libvolser.a ${LIBS} ${XLIBS}
 =20
***************
*** 111,116 ****
--- 114,120 ----
  #
  install: \
  	${DESTDIR}${sbindir}/restorevol \
+ 	${DESTDIR}${sbindir}/tocvol \
  	${DESTDIR}${includedir}/afs/volser.h \
  	${DESTDIR}${includedir}/afs/volint.h \
  	${DESTDIR}${sbindir}/vos \
***************
*** 126,131 ****
--- 130,138 ----
  	${INSTALL} $? $@
 =20
  ${DEST}/etc/restorevol: restorevol
+ 	${INSTALL} $? $@
+=20
+ ${DEST}/etc/tocvol: tocvol
  	${INSTALL} $? $@
 =20
  ${DEST}/etc/vos ${DEST}/root.server/usr/afs/bin/vos: vos
*** src/volser/tocvol.c.orig	Thu May  9 13:54:52 2002
--- src/volser/tocvol.c	Thu May  9 13:58:11 2002
***************
*** 0 ****
--- 1,715 ----
+ /*
+  * Copyright 2000, International Business Machines Corporation and others=
.
+  * All Rights Reserved.
+  *=20
+  * This software has been released under the terms of the IBM Public
+  * License.  For details, see the LICENSE file in the top-level source
+  * directory or online at http://www.openafs.org/dl/license10.html
+  */
+=20
+ /*
+  * Read a vos dump and print a table of contents
+  *
+  * tocvol [-file <dump file>]
+  *            [-dir <restore dir>]
+  *            [-extension <name extension>]
+  *            [-mountpoint <mount point root>]
+  *            [-umask <mode mask>]
+  * Based on restorevol, but with an internal index instead of symlinks.
+  *
+  */
+=20
+ #include <afsconfig.h>
+ #include <afs/param.h>
+=20
+ RCSID("$Header: /cvs/openafs/src/volser/restorevol.c,v 1.6 2001/08/08 00:=
04:26 shadow Exp $");
+=20
+ #include <afs/afsint.h>
+ #include <afs/nfs.h>
+ #include <lock.h>
+ #include <afs/ihandle.h>
+ #include <afs/vnode.h>
+ #include <afs/volume.h>
+ #include "volint.h"
+ #include "dump.h"
+ #include <afs/cmd.h>
+=20
+ #include <sys/param.h>
+ #include <sys/types.h>
+ #include <sys/uio.h>
+ #include <stdio.h>
+ #include <errno.h>
+ #include <netinet/in.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <dirent.h>
+=20
+ struct vmapnode {
+ 	char *name;
+ 	int parent;
+ 	char printed;
+ 	char isset;
+ } *vnodemap =3D 0;
+ int  vnodemaplen =3D 0;
+ int  vnodemapmax =3D 0;
+=20
+ growvnodemap(int n) {
+     int i;
+     if (n > vnodemapmax) {
+ 	vnodemapmax =3D 2 * n;
+ 	/* fprintf(stderr,"growing map to %d\n", vnodemapmax); */
+         /* fflush(stderr); */
+ 	vnodemap =3D realloc(vnodemap, sizeof(struct vmapnode) * vnodemapmax );
+ 	for ( i =3D vnodemaplen+1; i < vnodemapmax; i++ )
+              vnodemap[i].isset =3D 0;
+     }
+     if (n > vnodemaplen)
+ 	vnodemaplen =3D n;
+ }
+=20
+ void
+ setvnode(int n, char *name, int parent) {
+     /* fprintf(stderr, "setting map for %d to %s parent %d\n", n, name, p=
arent); */
+     /* fflush(stderr); */
+     growvnodemap(n);
+     vnodemap[n].name =3D (char *)strdup(name);
+     vnodemap[n].parent =3D parent;
+     vnodemap[n].isset =3D 1;
+ }
+=20
+ int
+ getvnodename(int n, char *p, int max) {
+     int len, nlen;
+     /* printf("getvnodename(%d)\n", n); */
+     if( vnodemap[n].isset ) {
+ 	nlen =3D strlen(vnodemap[n].name);
+ 	if (n !=3D 1 && vnodemap[n].parent !=3D n ) {
+ 	    len =3D getvnodename(vnodemap[n].parent, p, max);
+ 	} else {=20
+ 	    /* root vnode */
+ 	    p[0] =3D '.';
+ 	    p[1] =3D 0;
+ 	    return 1;
+         }
+ 	if (len !=3D 0 && len + nlen + 1 < max) {
+ 	    strcat(p+len, "/");
+ 	    strcat(p+len, vnodemap[n].name);
+ 	    return len + nlen + 1;
+ 	}
+     } else {=20
+ 	/* printf("notset\n") */;
+     }
+     return 0;
+ }
+=20
+ int printvnode(int n) {
+     char buf[1024];
+     int len;
+     /* printf ("printvnode %d\n", n); */
+     if (!vnodemap[n].printed && vnodemap[n].isset) {
+ 	len =3D getvnodename(n, buf, 1024);
+ 	if( len !=3D 0 ) {
+ 	    printf("%s\n", buf);
+ 	    vnodemap[n].printed =3D 1;
+ 	}  =20
+     }
+ }
+=20
+ int  inc_dump =3D 0;
+=20
+ FILE *dumpfile;
+=20
+ afs_int32 readvalue(size)
+ {
+   afs_int32 value, s;
+   int   code;
+   char  *ptr;
+=20
+   value =3D 0;
+   ptr =3D (char *) &value;
+=20
+   s =3D sizeof(value) - size;
+   if (size < 0) {
+       fprintf (stderr, "Too much data in afs_int32\n");
+       return 0;
+   }
+  =20
+   code =3D fread (&ptr[s], 1, size, dumpfile);
+   if (code !=3D size) fprintf (stderr, "Code =3D %d; Errno =3D %d\n", cod=
e, errno);
+=20
+   return (value);
+ }
+=20
+ char readchar()
+ {
+   char  value;
+   int   code;
+   char  *ptr;
+=20
+   value =3D '\0';
+   code =3D fread (&value, 1, 1, dumpfile);
+   if (code !=3D 1) fprintf (stderr, "Code =3D %d; Errno =3D %d\n", code, =
errno);
+=20
+   return (value);
+ }
+=20
+ #define BUFSIZE 16384
+ char buf[BUFSIZE];
+=20
+ char readdata(buffer, size)
+   char  *buffer;
+   afs_int32 size;
+ {
+   int   code;
+   afs_int32 s;
+=20
+   if (!buffer) {
+       while (size > 0) {
+ 	  s =3D ((size > BUFSIZE) ? BUFSIZE : size);
+ 	  code =3D fread(buf, 1, s, dumpfile);
+ 	  if (code !=3D s) fprintf (stderr, "Code =3D %d; Errno =3D %d\n", code,=
 errno);
+ 	  size -=3D s;
+       }
+   }
+   else {
+       code =3D fread (buffer, 1, size, dumpfile);
+       if (code !=3D size) {
+ 	 if (code < 0)
+ 	    fprintf (stderr, "Code =3D %d; Errno =3D %d\n", code, errno);
+ 	 else=20
+ 	    fprintf (stderr, "Read %d bytes out of %d\n", code, size);
+       }
+       if ((code >=3D 0) && (code < BUFSIZE))
+ 	 buffer[size] =3D 0;      /* Add null char at end */
+   }
+ }
+=20
+ afs_int32 ReadDumpHeader(dh)
+   struct DumpHeader *dh;                  /* Defined in dump.h */
+ {
+   int               code, i, done;
+   char              tag, c;
+   afs_int32             magic;
+=20
+ /*  memset(&dh, 0, sizeof(dh)); */
+=20
+   magic   =3D ntohl(readvalue(4));
+   dh->version =3D ntohl(readvalue(4));
+=20
+   done =3D 0;
+   while (!done) {
+       tag =3D readchar();
+       switch (tag) {
+           case 'v':
+ 	      dh->volumeId =3D ntohl(readvalue(4));
+ 	      break;
+=20
+ 	  case 'n':
+ 	      for (i=3D0, c=3D'a'; c!=3D'\0'; i++) {
+ 		  dh->volumeName[i] =3D c =3D readchar();
+ 	      }
+ 	      dh->volumeName[i] =3D c;
+ 	      break;
+=20
+ 	  case 't':
+ 	      dh->nDumpTimes =3D ntohl(readvalue(2)) >> 1;
+ 	      for (i=3D0; i<dh->nDumpTimes; i++) {
+ 		  dh->dumpTimes[i].from =3D ntohl(readvalue(4));
+ 		  dh->dumpTimes[i].to   =3D ntohl(readvalue(4));
+ 	      }
+ 	      break;
+=20
+ 	  default:
+ 	      done =3D 1;
+ 	      break;
+       }
+   }
+=20
+   return((afs_int32)tag);
+ }
+=20
+ struct volumeHeader
+ {
+   afs_int32         volumeId;
+   char          volumeName[100];
+   afs_int32         volType;
+   afs_int32         uniquifier;
+   afs_int32         parentVol;
+   afs_int32         cloneId;
+   afs_int32         maxQuota;
+   afs_int32         minQuota;
+   afs_int32         diskUsed;
+   afs_int32         fileCount;
+   afs_int32         accountNumber;
+   afs_int32         owner;
+   afs_int32         creationDate;
+   afs_int32         accessDate;
+   afs_int32         updateDate;
+   afs_int32         expirationDate;
+   afs_int32         backupDate;
+   afs_int32         dayUseDate;
+   afs_int32         dayUse;
+   afs_int32         weekCount;
+   afs_int32         weekUse[100];    /* weekCount of these */
+   char          motd[1024];
+   int           inService;
+   int           blessed;
+   char          message[1024];
+ };
+=20
+ afs_int32 ReadVolumeHeader(count)
+   afs_int32 count;
+ {
+   struct volumeHeader vh;
+   int               code, i, done, entries;
+   char              tag, c;
+=20
+ /*  memset(&vh, 0, sizeof(vh)); */
+=20
+   done =3D 0;
+   while (!done) {
+       tag =3D readchar();
+       switch (tag) {
+           case 'i':
+ 	      vh.volumeId =3D ntohl(readvalue(4));
+ 	      break;
+=20
+ 	  case 'v':
+ 	      ntohl(readvalue(4));   /* version stamp - ignore */
+               break;
+=20
+ 	  case 'n':
+ 	      for (i=3D0, c=3D'a'; c!=3D'\0'; i++) {
+ 		  vh.volumeName[i] =3D c =3D readchar();
+ 	      }
+ 	      vh.volumeName[i] =3D c;
+ 	      break;
+=20
+ 	  case 's':
+ 	      vh.inService =3D ntohl(readvalue(1));
+ 	      break;
+=20
+ 	  case 'b':
+ 	      vh.blessed =3D ntohl(readvalue(1));
+ 	      break;
+=20
+ 	  case 'u':
+ 	      vh.uniquifier =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 't':
+ 	      vh.volType =3D ntohl(readvalue(1));
+               break;
+=20
+ 	  case 'p':
+ 	      vh.parentVol =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'c':
+ 	      vh.cloneId =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'q':
+ 	      vh.maxQuota =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'm':
+ 	      vh.minQuota =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'd':
+ 	      vh.diskUsed =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'f':
+ 	      vh.fileCount =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'a':
+ 	      vh.accountNumber =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'o':
+ 	      vh.owner =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'C':
+ 	      vh.creationDate =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'A':
+ 	      vh.accessDate =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'U':
+ 	      vh.updateDate =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'E':
+ 	      vh.expirationDate =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'B':
+ 	      vh.backupDate =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'O':
+ 	      for (i=3D0, c=3D'a'; c!=3D'\0'; i++) {
+ 		  vh.message[i] =3D c =3D readchar();
+ 	      }
+ 	      vh.volumeName[i] =3D c;
+ 	      break;
+=20
+ 	  case 'W':
+ 	      vh.weekCount =3D ntohl(readvalue(2));
+ 	      for (i=3D0; i<vh.weekCount; i++) {
+ 		  vh.weekUse[i] =3D ntohl(readvalue(4));
+ 	      }
+ 	      break;
+=20
+ 	  case 'M':
+ 	      for (i=3D0, c=3D'a'; c!=3D'\0'; i++) {
+ 		  vh.motd[i] =3D c =3D readchar();
+ 	      }
+ 	      break;
+=20
+ 	  case 'D':
+ 	      vh.dayUseDate =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  case 'Z':
+ 	      vh.dayUse =3D ntohl(readvalue(4));
+               break;
+=20
+ 	  default:
+ 	      done =3D 1;
+ 	      break;
+       }
+   }
+=20
+   return((afs_int32)tag);
+ }
+=20
+ struct vNode
+ {
+   afs_int32 vnode;
+   afs_int32 uniquifier;
+   afs_int32 type;
+   afs_int32 linkCount;
+   afs_int32 dataVersion;
+   afs_int32 unixModTime;
+   afs_int32 servModTime;
+   afs_int32 author;
+   afs_int32 owner;
+   afs_int32 group;
+   afs_int32 modebits;
+   afs_int32 parent;
+   char acl[192];
+ #ifdef notdef
+   struct acl_accessList=20
+   {
+     int size;           /*size of this access list in bytes, including My=
Size itself*/   =20
+     int version;        /*to deal with upward compatibility ; <=3D ACL_AC=
LVERSION*/
+     int total;
+     int positive;       /* number of positive entries */
+     int negative;       /* number of minus entries */
+     struct acl_accessEntry=20
+     {
+       int id;         /*internally-used ID of user or group*/
+       int rights;     /*mask*/
+     } entries[100];
+   } acl;
+ #endif
+   afs_int32 dataSize;
+ };
+=20
+ #define MAXNAMELEN 256
+=20
+ afs_int32 ReadVNode(count, tocflag)
+   afs_int32 count;
+   int tocflag;
+ {
+   struct vNode      vn;
+   int               code, i, done, entries;
+   char              tag, c;
+   char              dirname[MAXNAMELEN], linkname[MAXNAMELEN], lname[MAXN=
AMELEN];
+   char              parentdir[MAXNAMELEN], vflink[MAXNAMELEN];
+   char              filename[MAXNAMELEN], fname[MAXNAMELEN];
+   int               len;
+   afs_int32             vnode;
+   afs_int32             mode=3D0;
+=20
+ /*  memset(&vn, 0, sizeof(vn)); */
+   vn.dataSize =3D 0;
+   vn.vnode =3D 0;
+   vn.parent =3D 0;
+   vn.type =3D 0;
+=20
+   vn.vnode =3D ntohl(readvalue(4));
+   vn.uniquifier =3D ntohl(readvalue(4));
+  =20
+   done =3D 0;
+   while (!done) {
+       tag =3D readchar();
+       switch (tag) {
+           case 't':
+ 	      vn.type =3D ntohl(readvalue(1));
+ 	      break;
+=20
+           case 'l':
+ 	      vn.linkCount =3D ntohl(readvalue(2));
+ 	      break;
+=20
+           case 'v':
+ 	      vn.dataVersion =3D ntohl(readvalue(4));
+ 	      break;
+=20
+           case 'm':
+ 	      vn.unixModTime =3D ntohl(readvalue(4));
+ 	      break;
+=20
+           case 's':
+ 	      vn.servModTime =3D ntohl(readvalue(4));
+ 	      break;
+=20
+           case 'a':
+ 	      vn.author =3D ntohl(readvalue(4));
+ 	      break;
+=20
+           case 'o':
+ 	      vn.owner =3D ntohl(readvalue(4));
+ 	      break;
+=20
+           case 'g':
+ 	      vn.group =3D ntohl(readvalue(4));
+ 	      break;
+=20
+           case 'b':
+ 	      vn.modebits =3D ntohl(readvalue(2));
+ 	      break;
+=20
+           case 'p':
+ 	      vn.parent =3D ntohl(readvalue(4));
+ 	      break;
+=20
+           case 'A':
+ 	      readdata(vn.acl, 192);             /* Skip ACL data */
+ 	      break;
+=20
+           case 'f':
+ 	      vn.dataSize =3D ntohl(readvalue(4));
+=20
+ 	      /* parentdir is the name of this dir's vnode-file-link
+ 	       * or this file's parent vnode-file-link.
+ 	       * "./AFSDir-<#>". It's a symbolic link to its real dir.
+ 	       * The parent dir and symbolic link to it must exist.
+ 	       */
+ 	      vnode =3D ((vn.type =3D=3D 2) ? vn.vnode : vn.parent);
+=20
+ 	      if (vn.type =3D=3D 2) {
+ 		  /*ITSADIR*/
+ 		  /* We read the directory entries. If the entry is a
+ 		   * directory, the subdir is created and the root dir
+ 		   * will contain a link to it. If its a file, we only
+ 		   * create a symlink in the dir to the file name.
+ 		   */
+ 		  char           *buffer;
+ 		  unsigned short j;
+ 		  afs_int32          this_vn;
+ 		  char           *this_name;
+=20
+ 		  struct DirEntry
+ 		  {
+ 		      char flag;
+ 		      char length;
+ 		      unsigned short next;
+ 		      struct MKFid
+ 		      {
+ 			  afs_int32 vnode;
+ 			  afs_int32 vunique;
+ 		      } fid;
+ 		      char name[20];
+ 		  };
+=20
+ 		  struct Pageheader
+ 		  {
+ 		      unsigned short pgcount;
+ 		      unsigned short tag;
+ 		      char           freecount;
+ 		      char           freebitmap[8];
+ 		      char           padding[19];
+ 		  };
+=20
+ 		  struct DirHeader
+ 		  {
+ 		      struct Pageheader  header;
+ 		      char               alloMap[128];
+ 		      unsigned short     hashTable[128];
+ 		  };
+=20
+ 		  struct Page0
+ 		  {
+ 		      struct DirHeader header;
+ 		      struct DirEntry  entry[1];
+ 		  } *page0;
+ 		 =20
+=20
+ 		  buffer =3D (char *)0;
+ 		  buffer =3D (char *)malloc(vn.dataSize);
+=20
+ 		  readdata(buffer, vn.dataSize);
+ 		  page0 =3D (struct Page0 *)buffer;
+=20
+ 		  /* Step through each bucket in the hash table, i,
+ 		   * and follow each element in the hash chain, j.
+ 		   * This gives us each entry of the dir.
+ 		   */
+ 		  for (i=3D0; i<128; i++) {
+ 		     for (j=3Dntohs(page0->header.hashTable[i]); j;
+ 			  j=3Dntohs(page0->entry[j].next)) {
+ 		        j -=3D 13;
+ 			this_vn   =3D ntohl(page0->entry[j].fid.vnode);
+ 			this_name =3D page0->entry[j].name;
+=20
+ 			if ((strcmp(this_name,"." ) =3D=3D 0) ||
+ 			    (strcmp(this_name,"..") =3D=3D 0))
+ 			   continue;                      /* Skip these */
+=20
+ 		       setvnode(this_vn,this_name, vnode);
+ 		       printvnode(this_vn);
+ 		     }
+ 		  }
+ 		  free(buffer);
+ 	      } /*ITSADIR*/
+=20
+ 	      else if (vn.type =3D=3D 1) {
+ 		  /*ITSAFILE*/
+ 		  /* A file vnode. So create it into the desired directory. A
+ 		   * link should exist in the directory naming the file.
+ 		   */
+ 		  int fid;
+ 		  int lfile;
+ 		  afs_int32 size, s;
+=20
+ 		  size =3D vn.dataSize;
+ 		  while (size > 0) {
+ 		     s =3D ((size > BUFSIZE) ? BUFSIZE : size);
+ 		     code =3D fread(buf, 1, s, dumpfile);
+ 		     if (code > 0) {
+ 			size -=3D code;
+ 		     }
+ 		     if (code !=3D s) {
+ 		        if (code < 0)
+ 			   fprintf (stderr, "Code =3D %d; Errno =3D %d\n", code, errno);
+ 			else=20
+ 			   fprintf (stderr, "Read %d bytes out of %d\n",=20
+ 				    (vn.dataSize - size), vn.dataSize);
+ 			break;
+ 		     }
+ 		  }
+ 		  if (size !=3D 0) {
+ 		     fprintf(stderr, "   File %s (%s) is incomplete\n", filename, fname=
);
+ 		  }
+=20
+ 	      } /*ITSAFILE*/
+=20
+ 	      else if (vn.type =3D=3D 3) {
+ 		  /*ITSASYMLINK*/
+ 		  /* A symlink vnode. So read it into the desired directory. This could
+ 		   * also be a mount point. If the volume is being restored to AFS, thi=
s
+ 		   * will become a mountpoint. If not, it becomes a symlink to no-where=
.
+ 		   */
+ 		  int fid;
+ 		  afs_int32 size, s;
+=20
+ 		  /* Check if its vnode-file-link exists and create pathname
+ 		   * of the symbolic link. If it doesn't exist,
+ 		   * then the link will be an orphaned link.
+ 		   */
+ 		  /* Read the link in */
+ 		  readdata(buf, vn.dataSize);
+ 	      }	/*ITSASYMLINK*/
+ 	      else {
+ 		 fprintf (stderr, "Unknown Vnode block\n");
+ 	      }
+ 	      break;
+=20
+ 	  default:
+ 	      done =3D 1;
+ 	      break;
+       }
+   }
+   if (vn.type =3D=3D 0)
+      inc_dump =3D 1;
+=20
+   return((afs_int32)tag);
+ }
+=20
+ WorkerBee(as, arock)
+   struct cmd_syndesc *as;
+   char *arock;
+ {
+   int    code=3D0, c, len;
+   afs_int32  type, count, vcount;
+   DIR           *dirP, *dirQ;
+   struct dirent *dirE, *dirF;
+   char   fname[MAXNAMELEN], name[MAXNAMELEN], lname[MAXNAMELEN], mname[MA=
XNAMELEN];
+   char   thisdir[MAXPATHLEN], *t;
+   struct DumpHeader dh;                  /* Defined in dump.h */
+ #if 0/*ndef HAVE_GETCWD*/ /* XXX enable when autoconf happens */
+   extern char *getwd();
+ #define getcwd(x,y) getwd(x)
+ #endif
+  =20
+   if (as->parms[0].items) {                         /* -file <dumpfile> *=
/
+      dumpfile =3D fopen(as->parms[0].items->data, "r");
+      if (!dumpfile) {
+         fprintf(stderr, "Cannot open '%s'. Code =3D %d\n",
+ 		as->parms[0].items->data, errno);
+ 	goto cleanup;
+      }
+   } else {
+      dumpfile =3D (FILE *)stdin;                     /* use stdin */
+   }
+=20
+   /* Read the dump header. From it we get the volume name */
+   type =3D ntohl(readvalue(1));
+   if (type !=3D 1) {
+       fprintf(stderr, "Expected DumpHeader\n");
+       code =3D -1;
+       goto cleanup;
+   }
+   type =3D ReadDumpHeader(&dh);
+=20
+   fprintf(stderr, "Table of Contents of volume dump of '%s':\n",
+ 	  dh.volumeName);
+=20
+   for (count=3D1; type=3D=3D2; count++) {
+       type =3D ReadVolumeHeader(count);
+       for (vcount=3D1; type=3D=3D3; vcount++)
+ 	  type =3D ReadVNode(vcount, as->parms[5].items);
+   }
+   for (count=3D1; count < vnodemaplen ; count++ ) {
+       printvnode(count);
+   }
+=20
+ cleanup:
+   return(code);
+ }
+=20
+ main(argc, argv)
+   int  argc;
+   char **argv;
+ {
+   struct cmd_syndesc *ts;
+   struct cmd_item    *ti;
+=20
+   setlinebuf(stdout);
+   setvnode(1,"/",1);
+   printvnode(1);
+=20
+   ts=3Dcmd_CreateSyntax((char *)0, WorkerBee, (char *) 0, "vldb check");
+   cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "dump file");
+=20
+   return cmd_Dispatch(argc, argv);
+ }

--=-BI/zzuLtHCWVIp64i9RP--