/*-
 * Copyright (c) 2001, 2003 Allan Saddi <allan@saddi.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY ALLAN SADDI AND HIS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL ALLAN SADDI OR HIS CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: view.c 927 2003-12-14 10:35:27Z asaddi $
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include "yafic-db.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "common.h"

#include "yafic.h"
#include "statpack.h"
#include "sha1.h"

#ifndef lint
static const char rcsid[] =
	"$Id: view.c 927 2003-12-14 10:35:27Z asaddi $";
#endif /* !lint */

#define LTYPE_DIR	1
#define LTYPE_FILE	2
#define LTYPE_SYMLINK	4
#define LTYPE_SPECIAL	8

#define LTYPE_ALL	(LTYPE_DIR | LTYPE_FILE | LTYPE_SYMLINK | LTYPE_SPECIAL)

static DB *db;

static void
cleanUp (void)
{
  if (db)
    db->close (db);
}

void
ViewDB (const char *root, const char *dbName, const char *type)
{
  DBT key, data;
  int flags;
  int res;
  char *entry;
  struct stat oldsb;
  uint8_t *bufp;

  int ltype = LTYPE_ALL, currtype;

  memset (&key, 0, sizeof (key));
  memset (&data, 0, sizeof (key));

  atexit (cleanUp);

  if (type) {
    ltype = 0;
    while (*type) {
      switch (*type) {
      case 'd':
	ltype |= LTYPE_DIR;
	break;
      case 'f':
	ltype |= LTYPE_FILE;
	break;
      case 'l':
	ltype |= LTYPE_SYMLINK;
	break;
      case 's':
	ltype |= LTYPE_SPECIAL;
	break;
      default:
	fprintf (stderr, "%s: ignoring unknown type -- %c\n", prog, *type);
	break;
      }
      type++;
    }
  }

  if (!(db = dbopen (dbName, O_RDONLY, 0, DB_HASH, NULL)))
    yaficError (dbName);

  flags = R_FIRST;
  while (!(res = db->seq (db, &key, &data, flags))) {
    if (data.size != DB_RECORD_SIZE) {
      fprintf (stderr, "%s: %s: %s\n", prog, dbName, "bad database format");
      exit (1);
    }

    entry = mymalloc (key.size + 1);
    strncpy (entry, key.data, key.size);
    entry[key.size] = '\0';

    if (Verbosity || ltype != LTYPE_ALL) {
      /* Unpack the record. */
      UnpackStat (data.data, &oldsb);
      bufp = &((uint8_t *) data.data)[DB_RECORD_SIZE - SHA1_HASH_SIZE];

      if (ltype != LTYPE_ALL) {
	currtype = 0;
	if (S_ISDIR (oldsb.st_mode))
	  currtype |= LTYPE_DIR;
	else if (S_ISREG (oldsb.st_mode))
	  currtype |= LTYPE_FILE;
	else if (S_ISLNK (oldsb.st_mode))
	  currtype |= LTYPE_SYMLINK;
	else
	  currtype |= LTYPE_SPECIAL;

	if (!(currtype & ltype)) {
	  free (entry);
	  flags = R_NEXT;
	  continue;
	}
      }

      if (Verbosity) {
	printf ("%s%s"
		" p(" ST_MODE_FMT ")"
		" i(" ST_INO_FMT ")"
		" n(" ST_NLINK_FMT ")"
		" u(" ST_UID_FMT ")"
		" g(" ST_GID_FMT ")"
		" s(" ST_SIZE_FMT ")"
		" a(" ST_ATIME_FMT ")"
		" m(" ST_MTIME_FMT ")"
		" c(" ST_CTIME_FMT ")"
		" h(%s)\n",
		root, entry,
		ST_MODE_CAST oldsb.st_mode,
		ST_INO_CAST oldsb.st_ino,
		ST_NLINK_CAST oldsb.st_nlink,
		ST_UID_CAST oldsb.st_uid,
		ST_GID_CAST oldsb.st_gid,
		ST_SIZE_CAST oldsb.st_size,
		ST_ATIME_CAST oldsb.st_atime,
		ST_MTIME_CAST oldsb.st_mtime,
		ST_CTIME_CAST oldsb.st_ctime,
		ToHexStr (bufp, SHA1_HASH_SIZE));
      }
    }

    if (!Verbosity)
      printf ("%s%s\n", root, entry);

    free (entry);
    flags = R_NEXT;
  }
  if (res == -1)
    yaficError (dbName);

  db->close (db);
  db = NULL;
}
