/*
 * CMUCS AFStools
 * dumpscan - routines for scanning and manipulating AFS volume dumps
 *
 * Copyright (c) 1998, 2001, 2003 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 <rx/rx_queue.h>
#include <lock.h>
#include <afs/afsint.h>
#include <afs/nfs.h>
#include <afs/ihandle.h>
#include <afs/vnode.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 *);
typedef struct dir_state dir_state;

/* 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;
  dt_uint64 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 {
  dt_uint64 offset;              /* Where in the input stream 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 {
  dt_uint64 offset;              /* Where in the input stream 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_ACL           0x00000400
#define F_VNODE_SIZE          0x00000800 /* Set if size is present */
#define F_VNODE_DATA          0x00001000 /* Set if size nonzero and data present */
#define F_VNODE_PARTIAL       0x00002000 /* Partial vnode continuation (no header) */
#define F_VNODE_LINK_TARGET   0x00004000 /* Symlink target present */
typedef struct {
  dt_uint64 offset;              /* Where in the input stream 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 */
  dt_uint64 d_offset;            /* Where in the input stream is the data? */
  char *link_target;           /* Target of symbolic link */
  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_OCT16     0x28  /* 2 bytes - octal */
#define DKIND_INT32     0x30  /* 4 bytes - decimal */
#define DKIND_HEX32     0x31  /* 4 bytes - hex */
#define DKIND_TIME      0x32  /* 4 bytes - time */
#define DKIND_OCT32     0x38  /* 4 bytes - octal */
#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;
  dt_uint64 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 Header   */
  afs_uint32 (*cb_dumphdr)(afs_dump_header *, XFILE *, void *);     /* Dump Header     */
  afs_uint32 (*cb_volhdr)(afs_vol_header *, XFILE *, void *);       /* Volume Header   */
  afs_uint32 (*cb_vnode_dir)(afs_vnode *, XFILE *, void *);         /* Directory Vnode */
  afs_uint32 (*cb_vnode_file)(afs_vnode *, XFILE *, void *);        /* File Vnode      */
  afs_uint32 (*cb_vnode_link)(afs_vnode *, XFILE *, void *);        /* Symlink Vnode   */
  afs_uint32 (*cb_vnode_empty)(afs_vnode *, XFILE *, void *);       /* vnode+uniq only */
  afs_uint32 (*cb_vnode_wierd)(afs_vnode *, XFILE *, void *);       /* Unknown type    */
  afs_uint32 (*cb_file_data)(afs_vnode *, XFILE *, void *);         /* File Data       */
  afs_uint32 (*cb_dir_data)(afs_vnode *, XFILE *, void *);          /* Directory Data  */
  afs_uint32 (*cb_link_data)(afs_vnode *, XFILE *, void *);         /* Symlink Data    */

  /* 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 */
  dt_uint64 v_offset;          /* Offset to start of vnode */
  dt_uint64 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);
extern afs_uint32 WriteTagString(XFILE *, unsigned char, unsigned char *);

/* 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 ParseStageV20Hdr(XFILE *, unsigned char *, backup_system_header *);
extern afs_uint32 DumpStageV20Hdr(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, lookup, and generation */
extern afs_uint32 ParseDirectory(XFILE *, dump_parser *, afs_uint32, int);
extern afs_uint32 DirectoryLookup(XFILE *, dump_parser *, afs_uint32,
                           char **, afs_uint32 *, afs_uint32 *);
extern afs_uint32 Dir_Init(dir_state **);
extern afs_uint32 Dir_AddEntry(dir_state *, char *, afs_uint32, afs_uint32);
extern afs_uint32 Dir_Finalize(dir_state *);
extern afs_uint32 Dir_EmitData(dir_state *, XFILE *, int);
extern afs_uint32 Dir_Free(dir_state *ds);


/* 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);
extern afs_uint32 DumpVNodeData(XFILE *OX, char *buf, afs_uint32 size);
extern afs_uint32 DumpDumpEnd(XFILE *OX);

/* 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
