Logo Search packages:      
Sourcecode: samhain version File versions  Download package

sh_hash.c

/* SAMHAIN file system integrity testing                                   */
/* Copyright (C) 1999, 2000, 2001, 2002 Rainer Wichmann                    */
/*                                                                         */
/*  This program is free software; you can redistribute it                 */
/*  and/or modify                                                          */
/*  it under the terms of the GNU General Public License as                */
/*  published by                                                           */
/*  the Free Software Foundation; either version 2 of the License, or      */
/*  (at your option) any later version.                                    */
/*                                                                         */
/*  This program is distributed in the hope that it will be useful,        */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
/*  GNU General Public License for more details.                           */
/*                                                                         */
/*  You should have received a copy of the GNU General Public License      */
/*  along with this program; if not, write to the Free Software            */
/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */

#include "config_xor.h"

/* define this if you want version 1.3 style database file */
/* #define OLD_BUG */

/* make sure state changes of a file are always reported, even
 *  with reportonlyonce=true
 */
/* #define REPLACE_OLD *//* moved to samhain.h */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#else
#ifdef MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#endif
#endif

#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif

#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)

#include "sh_hash.h"
#include "sh_utils.h"
#include "sh_error.h"
#include "sh_tiger.h"
#include "sh_gpg.h"
#include "sh_unix.h"
#include "sh_files.h"
#include "sh_ignore.h"

#if defined(SH_WITH_CLIENT)
#include "sh_forward.h"
#endif

#undef  FIL__
#define FIL__  _("sh_hash.c")

static char * all_items (file_type * theFile, char * fileHash, int is_new);

#define QUOTE_CHAR '='

static char * unquote_string (char * str)
{
  int    i = 0, j, k = 0, len;
  char * tmp;

  SL_ENTER(_("unquote_string"));

  if (str == NULL)
    {
      SL_RETURN(NULL, _("unquote_string"));
    }

  len = sl_strlen(str);

  tmp = SH_ALLOC(len + 1);
  for (j = 0; j <= len; ++j)
    {
      if (str[j] == QUOTE_CHAR && j < (len-2))
      {
        if (sh_util_hexchar(str[j+1]) >= 0 && sh_util_hexchar(str[j+2]) >= 0)
          {
            i = 16 * sh_util_hexchar(str[j+1]) + sh_util_hexchar(str[j+2]);
            tmp[k] = i; j += 2;
          }
        else
          {
            tmp[k] = str[j];
          }
      }
      else
      tmp[k] = str[j];
      ++k;
    }
  SL_RETURN(tmp, _("unquote_string"));
}

static char i2h[2];

char * int2hex (unsigned char i)
{
  int j, k;

  j = i / 16;
  k = i - (j*16);
  if (j < 10) 
    i2h[0] = '0'+j;
  else
    i2h[0] = 'A'+(j-10);
  
  if (k < 10) 
    i2h[1] = '0'+k;
  else
    i2h[1] = 'A'+(k-10);

  return i2h;
}

static char * quote_string (char * str)
{
  int    i = 0, j, k = 0, len;
  char * tmp;
  char * tmp2;

  SL_ENTER(_("quote_string"));

  if (str == NULL)
    {
      SL_RETURN(NULL, _("quote_string"));
    }

  len = sl_strlen(str);

  for (j = 0; j < len; ++j)
    if (str[j] == '\n' || str[j] == QUOTE_CHAR) ++i;

  tmp = SH_ALLOC(len + 1 + 3*i);
  for (j = 0; j <= len; ++j)
    {
      if (str[j] == '\n')
      {
        tmp2 = int2hex((unsigned char) '\n'); /* was 'n', fixed in 1.5.4 */
        tmp[k] = QUOTE_CHAR; ++k;
        tmp[k] = tmp2[0];    ++k;
        tmp[k] = tmp2[1];
      }
      else if (str[j] == QUOTE_CHAR)
      {
        tmp2 = int2hex((unsigned char) QUOTE_CHAR);
        tmp[k] = QUOTE_CHAR; ++k;
        tmp[k] = tmp2[0];    ++k;
        tmp[k] = tmp2[1];
      }
      else
      {
        tmp[k] = str[j];
      }
      ++k;
    }
  SL_RETURN(tmp, _("quote_string"));
}

static UINT32 * swap_32 (UINT32 * iptr)
{
#ifdef WORDS_BIGENDIAN
  unsigned char swap;
  unsigned char * ii = (unsigned char *) iptr;
  swap = ii[0]; ii[0] = ii[3]; ii[3] = swap;
  swap = ii[1]; ii[1] = ii[2]; ii[2] = swap;
  return iptr;
#else
  return iptr;
#endif
}

static UINT64 *  swap_64 (UINT64 * iptr)
{
#ifdef WORDS_BIGENDIAN
#ifdef UINT64_IS_32
  swap_32 ((UINT32*) iptr);
#else
  unsigned char swap;
  unsigned char * ii = (unsigned char *) iptr;
  swap = ii[0]; ii[0] = ii[7]; ii[7] = swap;
  swap = ii[1]; ii[1] = ii[6]; ii[6] = swap;
  swap = ii[2]; ii[2] = ii[5]; ii[5] = swap;
  swap = ii[3]; ii[3] = ii[4]; ii[4] = swap;
#endif
  return iptr;
#else
  return iptr;
#endif
}

static unsigned short *  swap_short (unsigned short * iptr)
{
#ifdef WORDS_BIGENDIAN
  if (sizeof(short) == 4)
    swap_32 ((UINT32*) iptr);
  else
    {
      /* alignment problem */
      unsigned char swap;
      static unsigned short ooop;
      unsigned char * ii;
      ooop = *iptr;
      ii = (unsigned char *) &ooop;
      /* printf("SWAP0: %hd  %d\n", *iptr, sizeof(unsigned short)); */
      swap = ii[0]; ii[0] = ii[1]; ii[1] = swap;
      /* printf("SWAP1: %hd\n", (unsigned short) ooop); */
#ifndef OLD_BUG
      return &ooop;
#endif
    }
  return iptr;
#else
  return iptr;
#endif
}


/* MAX_PATH_STORE must be >= KEY_LEN
 */
#define MAX_PATH_STORE 12287

typedef struct store_info {
  /*
  char             fullpath[MAX_PATH_STORE+2];
  char             linkpath[MAX_PATH_STORE+2];
  */
  UINT32           mode;
  UINT32           linkmode;

  UINT64           dev;
  UINT64           rdev;
  UINT32           hardlinks;
  UINT32           ino;
  UINT64           size;
  UINT64           atime;
  UINT64           mtime;
  UINT64           ctime;
  UINT32           owner;
  UINT32           group;

#ifdef OLD_BUG
#if defined(__linux__)
  UINT32           attributes;
  char             c_attributes[16];
#endif
#else
  /* #if defined(__linux__) */
  UINT32           attributes;
  char             c_attributes[16];
  /* endif                  */
#endif
  unsigned short   mark;
  char             c_owner[USER_MAX+2];
  char             c_group[GROUP_MAX+2];
  char             c_mode[11];
  char             checksum[KEY_LEN+1];
} sh_filestore_t;
  
typedef struct file_info {
  sh_filestore_t   theFile;
  char           * fullpath;
  char           * linkpath;
  int              visited;
  int              reported;
  int              allignore;
  unsigned long    modi_mask;
  struct           file_info * next;
} sh_file_t;

  static char  *policy[] = {
    N_("[]"),
    N_("[ReadOnly]"),
    N_("[LogFiles]"),
    N_("[GrowingLogs]"),
    N_("[IgnoreNone]"),
    N_("[IgnoreAll]"),
    N_("[Attributes]"),
    N_("[User0]"),
    N_("[User1]"),
    N_("[Prelink]"),
    NULL
  };


/**********************************
 *
 * hash table functions
 *
 **********************************
 */

#include "sh_hash.h"

/* must fit an int              */
#define TABSIZE 2048  

/* must fit an unsigned short   */
/* changed for V0.8, as the     */
/* database format has changed  */

/* changed again for V0.9       */
/* #define REC_MAGIC 19         */
/* changed again for V1.3       */
#ifdef OLD_BUG
#define REC_MAGIC 20
#else
/* changed again for V1.4       */
#define REC_MAGIC 21
#endif


/**************************************************************
 *
 * create a file_type from a sh_file_t
 *
 **************************************************************/
static file_type * sh_hash_create_ft (sh_file_t * p, char * fileHash)
{
  file_type * theFile;
#if defined(__linux__)
  int i = 16;
#endif

  SL_ENTER(_("sh_hash_create_ft"));

  theFile = SH_ALLOC(sizeof(file_type));

  sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11);
  theFile->mode  =  p->theFile.mode;
#if defined(__linux__)
  sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, i /* 16 */);
  theFile->attributes =  p->theFile.attributes;
#endif

  sl_strlcpy(theFile->fullpath, p->fullpath, PATH_MAX);
  if (p->linkpath != NULL && theFile->c_mode[0] == 'l')
    {
      sl_strlcpy(theFile->linkpath, p->linkpath, PATH_MAX);
    }
  else
    {
      theFile->linkpath[0] = '-';
      theFile->linkpath[1] = '\0';
    }
  sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
  
  theFile->mtime =  p->theFile.mtime;
  theFile->ctime =  p->theFile.ctime;
  theFile->atime =  p->theFile.atime;
  
  theFile->size  =  p->theFile.size;
  
  sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2);
  theFile->group =  p->theFile.group;
  sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2);
  theFile->owner =  theFile->owner;
  
  theFile->ino   =  p->theFile.ino;
  theFile->rdev  =  p->theFile.rdev;
  theFile->dev   =  p->theFile.dev;
  theFile->hardlinks = p->theFile.hardlinks;

  SL_RETURN((theFile), _("sh_hash_create_ft"));
}

static sh_file_t * hashsearch (char * s);

static sh_file_t * tab[TABSIZE];

/**************************************************************
 *
 * compute hash function
 *
 **************************************************************/
static int hashfunc(char *s) 
{
  unsigned n = 0; 

  for ( ; *s; s++) 
    n = 31 * n + *s; 
  return n % TABSIZE; 
} 

int hashreport_missing( char *fullpath, int level)
{
  sh_file_t * p;
  char * tmp;
  char   fileHash[KEY_LEN + 1];
  file_type * theFile;
  char * str;

  /* --------  find the entry for the file ----------------       */

  if (sl_strlen(fullpath) <= MAX_PATH_STORE) 
    p = hashsearch(fullpath);
  else 
    p = hashsearch( sh_tiger_hash(fullpath, 
                          TIGER_DATA, 
                          sl_strlen(fullpath))
                );
  if (p == NULL)
    return -1;

  theFile = sh_hash_create_ft (p, fileHash);
  str = all_items(theFile, fileHash, 0);
  tmp = sh_util_safe_name(fullpath);
  sh_error_handle (level, FIL__, __LINE__, 0, 
               MSG_FI_MISS2, tmp, str);
  SH_FREE(tmp);
  SH_FREE(str);
  SH_FREE(theFile);
  return 0;
}


/**************************************************************
 *
 * search for files not visited, and check whether they exist
 *
 **************************************************************/
static void hash_unvisited (int j, 
                      sh_file_t *prev, sh_file_t *p, ShErrLevel level)
{
  struct stat buf;
  int i;
  char * tmp;
  char * ptr;
  char   fileHash[KEY_LEN + 1];
  file_type * theFile;

  char * str;


  SL_ENTER(_("hash_unvisited"));

  if (p->next != NULL)
    hash_unvisited (j, p, p->next, level);

  if (p->fullpath == NULL)
    {
      SL_RET0(_("hash_unvisited"));
    }

  /* Kernel info
   */
  if (p->fullpath[0] == 'K')
    {
      SL_RET0(_("hash_unvisited"));
    }

  /* visited   = FALSE: not seen; 
   * visited   = 99:    not seen, and already checked 
   * reported  = FALSE: not reported yet
   * allignore = FALSE: not under IgnoreAll
   *
   * Files/directories under IgnoreAll are noticed as missing already
   * during the file check.
   */
  if ((p->visited == S_FALSE || p->visited == 99) && p->reported == S_FALSE 
      && p->allignore == S_FALSE)
    {
      i = retry_lstat(FIL__, __LINE__, p->fullpath, &buf);

      /* if file does not exist
       */
      if (0 != i)
      {
        ptr = sh_util_basename (p->fullpath);
        if (ptr)
          {
            /* If any of the parent directories is under IgnoreAll
             */
            if (0 != sh_files_is_allignore(ptr))
            level = ShDFLevel[SH_LEVEL_ALLIGNORE];
            SH_FREE(ptr);
          }
        if (p->visited != 99)
          {
            if (S_FALSE == sh_ignore_chk_del(p->fullpath))
            {
              tmp = sh_util_safe_name(p->fullpath);

              theFile = sh_hash_create_ft (p, fileHash);
              str = all_items(theFile, fileHash, 0);
              sh_error_handle (level, FIL__, __LINE__, 0, 
                           MSG_FI_MISS2, tmp, str);
              SH_FREE(str);
              SH_FREE(theFile);

              SH_FREE(tmp);
            }
          }

        /* We rewrite the db on update, thus we need to push this out
         * if the user does not want to purge it from the db.
         */
        if (sh.flag.update == S_TRUE &&
            S_FALSE == sh_util_ask_update(p->fullpath))
          {
            theFile = sh_hash_create_ft (p, fileHash);
            sh_hash_pushdata (theFile, fileHash);
            SH_FREE(theFile);
          }

        if (sh.flag.reportonce == S_TRUE)
          {
#ifdef REPLACE_OLD
            /* Remove the old entry
             */
            if (prev == p)
            tab[j] = p->next;
            else
            prev->next = p->next;
            if (p->fullpath)
            {
              SH_FREE(p->fullpath);
              p->fullpath = NULL;
            }
            if (p->linkpath)
            {
              SH_FREE(p->linkpath);
              p->linkpath = NULL;
            }
            SH_FREE(p);
            p = NULL;
            SL_RET0(_("hash_unvisited"));
#else
            p->reported = S_TRUE; 
#endif
          }
      }
    }

  else if (p->visited == S_TRUE && p->reported == S_TRUE 
         && p->allignore == S_FALSE)
    {
      if (S_FALSE == sh_ignore_chk_new(p->fullpath))
      {
        tmp = sh_util_safe_name(p->fullpath);

        theFile = sh_hash_create_ft (p, fileHash);
        str = all_items(theFile, fileHash, 0);
        sh_error_handle (level, FIL__, __LINE__, 0, 
                     MSG_FI_MISS2, tmp, str);
        SH_FREE(str);
        SH_FREE(theFile);

        SH_FREE(tmp);
      }

      p->reported = S_FALSE;
    }

  if (sh.flag.reportonce == S_FALSE)
    p->reported = S_FALSE;

  p->visited = S_FALSE;
  SL_RET0(_("hash_unvisited"));
}


/*********************************************************************
 *
 * Search for files in the database that have been deleted from disk.
 *
 *********************************************************************/
void sh_hash_unvisited (ShErrLevel level)
{
  int i;

  SL_ENTER(_("sh_hash_unvisited"));
  for (i = 0; i < TABSIZE; ++i)
    {
      if (tab[i] != NULL) 
      hash_unvisited (i, tab[i], tab[i], level);
    }
  SL_RET0(_("hash_unvisited"));
}


/**********************************************************************
 *
 * delete hash array
 *
 **********************************************************************/
static void hash_kill (sh_file_t *p)
{
  SL_ENTER(_("hash_kill"));

  if (p == NULL)
    SL_RET0(_("hash_kill"));

  if (p->next != NULL)
    hash_kill (p->next);

  if (p->fullpath)
    {
      SH_FREE(p->fullpath);
      p->fullpath = NULL;
    }
  if (p->linkpath)
    {
      SH_FREE(p->linkpath);
      p->linkpath = NULL;
    }
  SH_FREE(p);
  p = NULL;
  SL_RET0(_("hash_kill"));
}


/***********************************************************************
 *
 * get info out of hash array
 *
 ***********************************************************************/
static sh_file_t * hashsearch (char * s) 
{
  sh_file_t * p;

  SL_ENTER(_("hashsearch"));

  if (!s)
    SL_RETURN( NULL, _("hashsearch"));

  for (p = tab[hashfunc(s)]; p; p = p->next) 
    if ((p->fullpath != NULL) && (0 == strcmp(s, p->fullpath))) 
      SL_RETURN( p, _("hashsearch")); 
  SL_RETURN( NULL, _("hashsearch"));
} 


/***********************************************************************
 *
 * insert into hash array
 *
 ***********************************************************************/
static void hashinsert (sh_file_t * s) 
{
  sh_file_t * p;
  int key;

  SL_ENTER(_("hashinsert"));

  key = hashfunc(s->fullpath);

  if (tab[key] == NULL) 
    {
      tab[key] = s;
      tab[key]->next = NULL;
      SL_RET0(_("hashinsert"));
    } 
  else 
    {
      p = tab[key];
      while (1) 
      {
        if (p && p->fullpath && 
            0 == strcmp(s->fullpath, p->fullpath) &&
            strlen(s->fullpath) == strlen(p->fullpath))
          {
            SH_FREE(s->fullpath);
            if(s->linkpath)
            SH_FREE(s->linkpath);
            SH_FREE(s);
            s = NULL;
            SL_RET0(_("hashinsert"));
          }
        else 
          if (p->next == NULL) 
            {
            p->next = s;
            p->next->next = NULL;
            SL_RET0(_("hashinsert"));
            }
        p = p->next;
      }
    }
  /* notreached */
}


/******************************************************************
 *
 * Get a single line
 *
 ******************************************************************/
static FILE * sh_fin_fd = NULL;

static int sh_hash_getline (FILE * fd, char * line, int sizeofline)
{
  register int  n = 0;
  char        * res;

  if (sizeofline < 2) {
    line[0] = '\0';
    return 0;
  }
  res = fgets(line, sizeofline, fd);
  if (res == NULL)
    {
      line[0] = '\0';
      return -1;
    }
  n = strlen(line);
  if (n > 1) {
    --n;
    line[n] = '\0';
  }
  return n;
}

static void sh_hash_getline_end ()
{
  fclose (sh_fin_fd);
  sh_fin_fd = NULL;
  return;
}

/******************************************************************
 *
 * ------- Check functions -------
 *
 ******************************************************************/

static int IsInit = 0;


/******************************************************************
 *
 * Fast forward to start of data
 *
 ******************************************************************/
int sh_hash_setdataent (SL_TICKET fd, char * line, int size, char * file)
{
  long i;
  extern int get_the_fd (SL_TICKET ticket);

  SL_ENTER(_("sh_hash_setdataent"));

  sl_rewind (fd);

  if (sh_fin_fd != NULL)
    {
      fclose (sh_fin_fd);
      sh_fin_fd = NULL;
    }

  sh_fin_fd = fdopen(get_the_fd(fd), "rb");
  if (!sh_fin_fd)
    {
      dlog(1, FIL__, __LINE__, 
         _("The file signature database: %s is not readable.\n"),
         (NULL == file) ? _("(null)") : file);
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
                   ( (NULL == file) ? _("(null)") : file)
                   );
      aud_exit (FIL__, __LINE__, EXIT_FAILURE);
    }

  while (1) 
    {
      i =  sh_hash_getline (sh_fin_fd, line, size-1);
      if (i < 0 ) 
      {
        SH_FREE(line);
        dlog(1, FIL__, __LINE__, 
             _("The file signature database: %s does not\ncontain any data, or the start-of-file marker is missing (unlikely,\nunless modified by hand).\n"),
             (NULL == file) ? _("(null)") : file);
             
        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
                     ( (NULL == file) ? _("(null)") : file)
                     );
        aud_exit (FIL__, __LINE__, EXIT_FAILURE);
      }

#if defined(SH_STEALTH)
      if (0 == sl_strncmp (line, N_("[SOF]"), 5)) 
#else
      if (0 == sl_strncmp (line, _("[SOF]"),  5)) 
#endif
      break;
    }
  SL_RETURN( 1, _("sh_hash_setdataent"));
}

static int sh_hash_setdataent_old (SL_TICKET fd, char * line, int size, 
                           char * file)
{
  long i;

  SL_ENTER(_("sh_hash_setdataent_old"));

  sl_rewind (fd);

  while (1) 
    {
      i =  sh_unix_getline (fd, line, size-1);
      if (i < 0 ) 
      {
        SH_FREE(line);
        dlog(1, FIL__, __LINE__, 
             _("The file signature database: %s does not\ncontain any data, or the start-of-file marker is missing (unlikely,\nunless modified by hand).\n"),
             (NULL == file) ? _("(null)") : file);
             
        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
                     ( (NULL == file) ? _("(null)") : file)
                     );
        aud_exit (FIL__, __LINE__, EXIT_FAILURE);
      }

#if defined(SH_STEALTH)
      if (0 == sl_strncmp (line, N_("[SOF]"), 5)) 
#else
      if (0 == sl_strncmp (line, _("[SOF]"),  5)) 
#endif
      break;
    }
  SL_RETURN( 1, _("sh_hash_setdataent_old"));
}

/******************************************************************
 *
 * Read next record
 *
 ******************************************************************/
sh_file_t *  sh_hash_getdataent (SL_TICKET fd, char * line, int size)
{
  sh_file_t * p;
  sh_filestore_t ft;
  long i;
  char * fullpath;
  char * linkpath;
  char * tmp;

  SL_ENTER(_("sh_hash_getdataent"));

  (void) fd;

  /* Read next record -- Part One 
   */
  p = SH_ALLOC(sizeof(sh_file_t));

  i = fread (&ft, sizeof(sh_filestore_t), 1, sh_fin_fd);
  /* i = sl_read(fd, &ft, sizeof(sh_filestore_t)); */
  /* if ( SL_ISERROR(i) || i == 0) */
  if (i < 1)
    {
      SH_FREE(p);
      SL_RETURN( NULL, _("sh_hash_getdataent"));
    }

  swap_32(&(ft.mode));
  swap_32(&(ft.linkmode));
  swap_64(&(ft.dev));
  swap_64(&(ft.rdev));
  swap_32(&(ft.hardlinks));
  swap_32(&(ft.ino));
  swap_64(&(ft.size));
  swap_64(&(ft.atime));
  swap_64(&(ft.mtime));
  swap_64(&(ft.ctime));
  swap_32(&(ft.owner));
  swap_32(&(ft.group));
#if defined(__linux__)
  swap_32(&(ft.attributes));
#endif
#ifdef OLD_BUG
  swap_short(&(ft.mark));
#else
  ft.mark = *(swap_short(&(ft.mark)));
#endif

  if (ft.mark != REC_MAGIC)
    {
      SH_FREE(p);
      SL_RETURN( NULL, _("sh_hash_getdataent"));
    }

  /* Read next record -- Part Two -- Fullpath
   */
  i =  sh_hash_getline (sh_fin_fd, line, size-1);
  if (i < 0 ) 
    {
      SH_FREE(line);
      SH_FREE(p);
      dlog(1, FIL__, __LINE__, 
         _("There is a corrupt record in the file signature database: %s\nThe file path is missing.\n"),
         (NULL == file_path('D', 'R'))? _("(null)"):file_path('D', 'R'));
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
                     ( (NULL == file_path('D', 'R')) ? _("(null)") :
                       file_path('D', 'R'))
                      );
      aud_exit (FIL__, __LINE__,EXIT_FAILURE);
    }

  tmp = unquote_string (line);
  i = sl_strlen(tmp)+1;
  fullpath = SH_ALLOC(i);
  sl_strlcpy (fullpath, tmp, i);
  if (tmp)
    SH_FREE(tmp);
  if (fullpath[i-2] == '\n')
    fullpath[i-2] = '\0';

  /* Read next record -- Part Three -- Linkpath
   */
  i =  sh_hash_getline (sh_fin_fd, line, size-1);
  if (i < 0 ) 
    {
      SH_FREE(line);
      SH_FREE(fullpath);
      SH_FREE(p);
      dlog(1, FIL__, __LINE__, 
         _("There is a corrupt record in the file signature database: %s\nThe link path (or its placeholder) is missing.\n"),
         (NULL == file_path('D', 'R'))? _("(null)"):file_path('D', 'R'));
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
                   ( (NULL == file_path('D', 'R')) ? _("(null)") :
                   file_path('D', 'R'))
                   );
      aud_exit (FIL__, __LINE__,EXIT_FAILURE);
    }

  tmp = unquote_string (line);
  i = sl_strlen(tmp)+1;
  linkpath = SH_ALLOC(i);
  sl_strlcpy (linkpath, tmp, i);
  if (tmp)
    SH_FREE(tmp);
  if (linkpath[i-2] == '\n')
    linkpath[i-2] = '\0';

  /* Read next record -- Part Four -- Decode
   */
#if defined(SH_STEALTH)
  sh_do_decode(fullpath,    sl_strlen(fullpath));
  
#if defined(__linux__)
  sh_do_decode(ft.c_attributes,   sl_strlen(ft.c_attributes));
#endif
  
  sh_do_decode(ft.c_mode,   sl_strlen(ft.c_mode));
  sh_do_decode(ft.c_owner,  sl_strlen(ft.c_owner));
  sh_do_decode(ft.c_group,  sl_strlen(ft.c_group));
  sh_do_decode(ft.checksum, sl_strlen(ft.checksum));
  
  
  if (ft.c_mode[0] == 'l') 
    {  
      sh_do_decode(linkpath, sl_strlen(linkpath));
    }
#endif

  memcpy( &(*p).theFile, &ft, sizeof(sh_filestore_t) );
  p->visited   = S_FALSE;
  p->reported  = S_FALSE;
  p->allignore = S_FALSE;
  p->modi_mask = 0L;
  p->fullpath  = fullpath;
  p->linkpath  = linkpath;

  /* set to an invalid value 
   */
  ft.mark = (REC_MAGIC + 5);

  SL_RETURN( p, _("sh_hash_getdataent"));
}

/******************************************************************
 *
 * Initialize
 *
 ******************************************************************/
void sh_hash_init ()
{
  sh_file_t * p;
  SL_TICKET fd    = (-1);
  long i;
  int count = 0;
  char * line = NULL;

#if defined(WITH_GPG) || defined(WITH_PGP)
  extern int get_the_fd (SL_TICKET ticket);
  FILE *   fin_cp;

  char * buf  = NULL;
  int    bufc;
  int    flag_pgp = S_FALSE;
  int    flag_nohead = S_FALSE;
  SL_TICKET fdTmp = (-1);
  SL_TICKET open_tmp (void);
#endif

  SL_ENTER(_("sh_hash_init"));

  if (IsInit == 1) 
    SL_RET0(_("sh_hash_init"));

  for (i = 0; i < TABSIZE; ++i) 
    tab[i] = NULL;

#if defined(SH_WITH_CLIENT)

  /* Data file from Server
   */

  if (fd == (-1) && 0 == sl_strcmp(file_path('D', 'R'), _("REQ_FROM_SERVER")))
    {
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_D_DSTART);
      fd = sh_forward_req_file(_("DATA"));
      if (SL_ISERROR(fd))
      {
        dlog(1, FIL__, __LINE__, 
             _("Could not retrieve the file signature database from the server.\nPossible reasons include:\n - the server is not running,\n - session key negotiation failed (see the manual for proper setup), or\n - the server cannot access the file.\n")); 
        sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_EXIT_ABORT1, 
                     sh.prg_name);
        aud_exit (FIL__, __LINE__, EXIT_FAILURE);
      }
      sl_rewind (fd);

      tiger_fd = fd;
      sl_strlcpy (sh.data.hash, 
              sh_tiger_hash (file_path('C', 'R'), /*irrelevant, TIGER_FD*/ 
                         TIGER_FD, 0),
              KEY_LEN+1);
      sl_rewind (fd);
    }
  else 
#endif
    /* Local data file
     */

    if (fd == (-1))
      {
      if ( SL_ISERROR(fd = sl_open_read(file_path('D', 'R'), SL_YESPRIV))) 
        {
          TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s>\n"), 
              file_path('D', 'R')));
          dlog(1, FIL__, __LINE__, 
             _("Could not open the local file signature database for reading because\nof the following error: %s\nIf this is a permission problem, you need to change file permissions\nto make the file readable for the effective UID: %d\n"), 
             sl_get_errmsg(), (int) sl_ret_euid());
          sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_EXIT_ABORT1, 
                       sh.prg_name);
          aud_exit (FIL__, __LINE__, EXIT_FAILURE);
        }
      
      TPT(( 0, FIL__, __LINE__, _("msg=<Opened database: %s>\n"), 
            file_path('D', 'R')));

      tiger_fd = fd;
      if (0 != sl_strncmp(sh.data.hash, 
                      sh_tiger_hash (file_path('D', 'R'), TIGER_FD, 0),
                      KEY_LEN)
          && sh.flag.checkSum != SH_CHECK_INIT) 
        {
          dlog(1, FIL__, __LINE__, 
             _("The checksum of the file signature database has changed since startup.\n"));
          sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_AUTH,
                       ( (NULL == file_path('D', 'R')) ? _("(null)") :
                         file_path('D', 'R') )
                       );
          aud_exit (FIL__, __LINE__, EXIT_FAILURE);
        }
      sl_rewind (fd);

      } /* new 1.4.8 */

  if (sig_termfast == 1)  /* SIGTERM */
    {
      TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
      --sig_raised; --sig_urgent;
      aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
    }

#if defined(WITH_GPG) || defined(WITH_PGP)
  /* new 1.4.8: also checked for server data */

  /* extract the data and copy to temporary file
   */
  fdTmp = open_tmp();

  fin_cp = fdopen(get_the_fd(fd), "rb");
  buf = (char *) SH_ALLOC(8192);


  /* while ( (bufc = sh_unix_getline (fd, buf, 8191)) > 0) */
  while (NULL != fgets(buf, 8192, fin_cp))
    {
      bufc = 0; 
      while (bufc < 8192) { 
      if (buf[bufc] == '\n') { ++bufc; break; }
      ++bufc;
      }

      if (sig_termfast == 1)  /* SIGTERM */
      {
        TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
        --sig_raised; --sig_urgent;
        aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
      }

      if (flag_pgp == S_FALSE &&
        (0 == sl_strcmp(buf, _("-----BEGIN PGP SIGNED MESSAGE-----\n"))||
         0 == sl_strcmp(buf, _("-----BEGIN PGP MESSAGE-----\n")))
        )
      {
        flag_pgp = S_TRUE;
        sl_write(fdTmp, buf, bufc);
        continue;
      }
      
      if (flag_pgp == S_TRUE && flag_nohead == S_FALSE)
      {
        if (buf[0] == '\n')
          {
            flag_nohead = S_TRUE;
            sl_write(fdTmp, buf, 1);
            continue;
          }
        else if (0 == sl_strncmp(buf, _("Hash:"), 5) ||
               0 == sl_strncmp(buf, _("NotDashEscaped:"), 15))
          {
            sl_write(fdTmp, buf, bufc);
            continue;
          }
        else
          continue;
      }
    
      if (flag_pgp == S_TRUE && buf[0] == '\n')
      {
        sl_write(fdTmp, buf, 1);
      }
      else if (flag_pgp == S_TRUE)
      {
        /* sl_write_line(fdTmp, buf, bufc); */
        sl_write(fdTmp, buf, bufc);
      }
      
      if (flag_pgp == S_TRUE && 
        0 == sl_strcmp(buf, _("-----END PGP SIGNATURE-----\n")))
      break;
    }
  SH_FREE(buf);
  sl_close(fd);
  fclose(fin_cp);

  fd = fdTmp;
  sl_rewind (fd);

  /* Validate signature of open file.
   */
  if (0 != sh_gpg_check_sign (0, fd, 2))
    {
      aud_exit (FIL__, __LINE__, EXIT_FAILURE);
    }
  sl_rewind (fd);
#endif
  /* } new 1.4.8 check sig also for files downloaded from server */

  line = SH_ALLOC(MAX_PATH_STORE+1);

  /* fast forward to start of data
   */
  sh_hash_setdataent(fd, line, MAX_PATH_STORE, file_path('D', 'R'));

  while (1) 
    {
      if (sig_termfast == 1)  /* SIGTERM */
      {
        TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
        --sig_raised; --sig_urgent;
        aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
      }

      p = sh_hash_getdataent (fd, line, MAX_PATH_STORE);
      if (p != NULL)
      {
        hashinsert (p); 
        ++count;
      }
      else
      break;
    }

  if (line != NULL)
    SH_FREE(line);

  /* Always keep db in memory, so we have no open file
   */
  sl_close (fd);
  sh_hash_getline_end();
  fd = -1;

  /* --- Initialization done successfully. ---
   */
  IsInit = 1;
  SL_RET0(_("sh_hash_init"));
}
  
/*****************************************************************
 *
 * delete hash array
 *
 *****************************************************************/
void sh_hash_hashdelete ()
{
  int i;

  SL_ENTER(_("sh_hash_hashdelete"));

  if (IsInit == 0) 
    SL_RET0(_("sh_hash_hashdelete"));
  for (i = 0; i < TABSIZE; ++i) 
    if (tab[i] != NULL)
      { 
      hash_kill (tab[i]);
      tab[i] = NULL;
      }
  IsInit = 0;
  SL_RET0(_("sh_hash_hashdelete"));
}

/******************************************************************
 *
 * Insert a file into the database.
 *
 ******************************************************************/ 
static int       pushdata_isfirst =  1;
static SL_TICKET pushdata_fd      = -1;

static int       pushdata_stdout  =  S_FALSE;

static char * sh_db_version_string = NULL;

int sh_hash_pushdata_stdout (char * str)
{
  if (!str)
    { pushdata_stdout  =  S_TRUE; return 0; }
  return -1;
}

int sh_hash_version_string(char * str)
{
  int i;
  if (str)
    {
      i = sl_strlen(str);
      if (sh_db_version_string != NULL) {
      SH_FREE(sh_db_version_string);
      }
      if (0 == sl_strncmp(str, _("NULL"), 4))
      {
        sh_db_version_string = NULL;
        return 0;
      }
      sh_db_version_string = SH_ALLOC(i+1);
      sl_strlcpy(sh_db_version_string, str, i+1);
      return 0;
    }
  return -1;
}

#if 0
void sh_hash_pushdata_reset ()
{
  if (!SL_ISERROR(pushdata_fd))
    {
      sl_close(pushdata_fd);
      pushdata_fd = -1;
    }
  pushdata_isfirst =  1;
}
#endif

void sh_hash_pushdata (file_type * buf, char * fileHash)
{
  static long p_count = 0;

  char      * tmp;
  size_t      tmp_len = 0;
  size_t      old_len = 0;

  sh_filestore_t p;

  struct stat sbuf;

  char *  fullpath = NULL;
  char *  linkpath = NULL;

  char * line = NULL;

  char   timestring[81];
  char * timep;

#if !defined(__linux__)
  int    i;
#endif

  SL_ENTER(_("sh_hash_pushdata"));

  fullpath = SH_ALLOC(MAX_PATH_STORE+1);
  linkpath = SH_ALLOC(MAX_PATH_STORE+1);

  linkpath[0] =  '-'; 
  linkpath[1] = '\0'; 
  fullpath[0] =  '-'; 
  fullpath[1] = '\0';

  if (!buf) {
    memset(&p, '\0', sizeof(sh_filestore_t));
  }

  if ((pushdata_stdout == S_TRUE) && (sh.flag.update == S_TRUE))
    {
      dlog(1, FIL__, __LINE__, 
         _("You cannot write the database to stdout when you use update rather than init.\n"));
      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
                  _("Writing database to stdout with update"), 
                  sh.prg_name, 
                  _("sh_hash_pushdata"));
      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
    }

  if ((pushdata_stdout == S_TRUE) && (sl_is_suid()))
    {
      dlog(1, FIL__, __LINE__, 
         _("You cannot write the database to stdout when running with suid privileges.\n"));
      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
                  _("Writing database to stdout when suid"), 
                  sh.prg_name, 
                  _("sh_hash_pushdata"));
      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
    }


  if ((pushdata_stdout == S_FALSE) && 
      ( (NULL == file_path('D', 'W')) || 
      (0 == sl_strcmp(file_path('D', 'W'), _("REQ_FROM_SERVER"))) ))
    {
      dlog(1, FIL__, __LINE__, 
         _("You need to configure a local path for initializing the database\nlike ./configure --with-data-file=REQ_FROM_SERVER/some/local/path\n"));
      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
                  _("No local path for database specified"), 
                  sh.prg_name, 
                  _("sh_hash_pushdata"));
      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
    }


  if ((pushdata_stdout == S_FALSE) && (pushdata_isfirst == 1))  
    {
      /* Warn that file already exists; file_path != NULL here because
       * checked above
       */
      if (0 == retry_lstat(FIL__, __LINE__, file_path('D', 'W'), &sbuf))
      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_FI_DBEX,
                  file_path('D', 'W'));
    }


  if (sh.flag.update == S_FALSE)
    {
      if (pushdata_stdout == S_FALSE)
      {
        pushdata_fd = -1;
        if ( SL_ISERROR(pushdata_fd = sl_open_write(file_path('D', 'W'), SL_YESPRIV))) {
          SH_FREE(fullpath);
          SH_FREE(linkpath);
          SL_RET0(_("sh_hash_pushdata"));
        }
        if ( SL_ISERROR(sl_forward(pushdata_fd))) {
          SH_FREE(fullpath);
          SH_FREE(linkpath);
          SL_RET0(_("sh_hash_pushdata"));
        }
      }
    }
  else /* update == TRUE */
    {
      if (pushdata_isfirst == 1)
      {
        TPT((0, FIL__, __LINE__, _("msg=<Update.>\n")))
        if ( SL_ISERROR(pushdata_fd = sl_open_rdwr(file_path('D', 'W'), SL_YESPRIV))){
          SH_FREE(fullpath);
          SH_FREE(linkpath);
          SL_RET0(_("sh_hash_pushdata"));
        }
        line = SH_ALLOC(MAX_PATH_STORE+1);
        if (SL_ISERROR(sh_hash_setdataent_old (pushdata_fd, line, 
                                     MAX_PATH_STORE, 
                                     file_path('D', 'W'))))
          {
            SH_FREE(fullpath);
            SH_FREE(linkpath);
            SH_FREE(line);
            SL_RET0(_("sh_hash_pushdata"));
          }
        SH_FREE(line);
      }
    }
       
  if (buf != NULL && buf->fullpath != NULL) {

    old_len = sl_strlen(buf->fullpath);
#if defined(SH_STEALTH)
    sh_do_encode(buf->fullpath, old_len);
#endif
    tmp = quote_string(buf->fullpath);
    tmp_len = sl_strlen(tmp);
#if defined(SH_STEALTH)
    sh_do_decode(buf->fullpath, old_len);
#endif

    if (tmp_len <= MAX_PATH_STORE) 
      {
      sl_strlcpy(fullpath, buf->fullpath, MAX_PATH_STORE+1);
      /*
      if (sl_strlen(buf->fullpath) < (MAX_PATH_STORE-3))
        {
          fullpath[MAX_PATH_STORE-2] = '\0';
          fullpath[MAX_PATH_STORE-1] = '\n';
        }
      */
      } 
    else 
      {
      sl_strlcpy(fullpath, 
               sh_tiger_hash (buf->fullpath,
                          TIGER_DATA, old_len), 
               KEY_LEN+1);
      }
    SH_FREE(tmp);
  }

#if defined(SH_STEALTH)
  sh_do_encode(fullpath, sl_strlen(fullpath));
#endif

  tmp = quote_string(fullpath);
  sl_strlcpy(fullpath, tmp, MAX_PATH_STORE+1);
  SH_FREE(tmp);

  if (buf != NULL && buf->c_mode[0] == 'l' && buf->linkpath != NULL) 
    {  

      old_len = sl_strlen(buf->linkpath);
#if defined(SH_STEALTH)
      sh_do_encode(buf->linkpath, old_len);
#endif
      tmp = quote_string(buf->linkpath);
      tmp_len = sl_strlen(tmp);
#if defined(SH_STEALTH)
      sh_do_decode(buf->linkpath, old_len);
#endif

      if (tmp_len <= MAX_PATH_STORE) 
      {
        sl_strlcpy(linkpath, buf->linkpath, MAX_PATH_STORE+1);  
      } 
      else 
      {
        sl_strlcpy(linkpath, 
                 sh_tiger_hash (buf->linkpath,
                            TIGER_DATA, old_len),
                 KEY_LEN+1);
      }
      SH_FREE(tmp);

#if defined(SH_STEALTH)
      sh_do_encode(linkpath, sl_strlen(linkpath));
#endif
      tmp = quote_string(linkpath);
      sl_strlcpy(linkpath, tmp, MAX_PATH_STORE+1);
      SH_FREE(tmp);
    }

  if (buf != NULL) {
    p.mark = REC_MAGIC;
    sl_strlcpy(p.c_mode,   buf->c_mode,   11);
    sl_strlcpy(p.c_group,  buf->c_group,  GROUP_MAX+1);
    sl_strlcpy(p.c_owner,  buf->c_owner,  USER_MAX+1);
    if (fileHash) {
      sl_strlcpy(p.checksum, fileHash,      KEY_LEN+1);
    }
#if defined(__linux__)
    sl_strlcpy(p.c_attributes, buf->c_attributes, 13);
#else
    for (i = 0; i < 12; ++i) p.c_attributes[i] = '-';
    p.c_attributes[12] = '\0';
#endif
    
#if defined(SH_STEALTH)
    sh_do_encode(p.c_mode,   sl_strlen(p.c_mode));
    sh_do_encode(p.c_owner,  sl_strlen(p.c_owner));
    sh_do_encode(p.c_group,  sl_strlen(p.c_group));
    sh_do_encode(p.checksum, sl_strlen(p.checksum));

    sh_do_encode(p.c_attributes,   sl_strlen(p.c_attributes));
#endif
    
#if defined(__linux__)
    p.attributes  = (UINT32) buf->attributes;
#else
    p.attributes  = 0;
#endif
    p.linkmode    = (UINT32) buf->linkmode;
    p.hardlinks   = (UINT32) buf->hardlinks;
    p.dev   = (UINT64) buf->dev;
    p.rdev  = (UINT64) buf->rdev;
    p.mode  = (UINT32) buf->mode;
    p.ino   = (UINT32) buf->ino;
    p.size  = (UINT64) buf->size;
    p.mtime = (UINT64) buf->mtime;
    p.atime = (UINT64) buf->atime;
    p.ctime = (UINT64) buf->ctime;
    p.owner = (UINT32) buf->owner;
    p.group = (UINT32) buf->group;
    
    swap_32(&(p.mode));
    swap_32(&(p.linkmode));
    swap_64(&(p.dev));
    swap_64(&(p.rdev));
    swap_32(&(p.hardlinks));
    swap_32(&(p.ino));
    swap_64(&(p.size));
    swap_64(&(p.atime));
    swap_64(&(p.mtime));
    swap_64(&(p.ctime));
    swap_32(&(p.owner));
    swap_32(&(p.group));
    swap_32(&(p.attributes));

#ifdef OLD_BUG
    swap_short(&(p.mark));
#else
    p.mark = *(swap_short(&(p.mark)));
#endif
  }

  /* write the start marker 
   */
  if (pushdata_isfirst == 1) 
    {
      if (sh.flag.update == S_FALSE)
      {
        if (sh_db_version_string != NULL)
          {
            if (pushdata_stdout == S_FALSE)
            {
              sl_write (pushdata_fd, _("\n#Host "), 7);
              sl_write (pushdata_fd, sh.host.name, 
                      sl_strlen(sh.host.name));
              sl_write (pushdata_fd, _(" Version "), 9);
              sl_write (pushdata_fd, sh_db_version_string, 
                      sl_strlen(sh_db_version_string));
              sl_write (pushdata_fd, _(" Date "), 6);
              timep = sh_unix_time(0);
              sl_strlcpy(timestring, timep, sizeof(timestring));
              sl_write (pushdata_fd, timestring, sl_strlen(timestring));
              sl_write (pushdata_fd,        "\n", 1);
            } else {
              printf (_("\n#Host "));
              printf ("%s", sh.host.name);
              printf (_(" Version "));
              printf ("%s", sh_db_version_string);
              printf (_(" Date "));
              timep = sh_unix_time(0);
              sl_strlcpy(timestring, timep, sizeof(timestring));
              printf ("%s\n", timestring);
            }
          }

        if (pushdata_stdout == S_FALSE)
          {
#if defined(SH_STEALTH)
            sl_write      (pushdata_fd,        "\n", 1);
            sl_write_line (pushdata_fd, N_("[SOF]"), 5);
#else
            sl_write_line (pushdata_fd, _("\n[SOF]"),  6);
#endif
          }
        else 
          {
#if defined(SH_STEALTH)
            printf ("\n%s\n", N_("[SOF]"));
#else
            printf ("%s\n", _("\n[SOF]"));
#endif
          }
      }
      pushdata_isfirst = 0;
    }
      
  if (pushdata_stdout == S_FALSE)
    {
      sl_write      (pushdata_fd,       &p, sizeof(sh_filestore_t));
      sl_write_line (pushdata_fd, fullpath,    sl_strlen(fullpath));
      sl_write_line (pushdata_fd, linkpath,    sl_strlen(linkpath));
    } else {
      fwrite (&p, sizeof(sh_filestore_t), 1, stdout);
      printf ("%s\n", fullpath);
      printf ("%s\n", linkpath);
    }

  ++p_count;

  if ((sh.flag.update != S_TRUE) && (pushdata_stdout == S_FALSE))
    {
      sl_close (pushdata_fd);
      pushdata_fd = -1;
    }

  SH_FREE(fullpath);
  SH_FREE(linkpath);

  SL_RET0(_("sh_hash_pushdata"));
}

/*********************************************************************
 *
 * Check whether a file is present in the database.
 *
 *********************************************************************/
static sh_file_t *  sh_hash_have_it_int (char * newname)
{
  sh_file_t * p;

  SL_ENTER(_("sh_hash_have_it"));

  if (newname == NULL)
    SL_RETURN( (NULL), _("sh_hash_have_it"));

  if (IsInit != 1) 
    sh_hash_init();
  if (sl_strlen(newname) <= MAX_PATH_STORE) 
    p = hashsearch(newname);
  else 
    p = hashsearch ( sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname)) );
  if (p == NULL) 
     SL_RETURN( (NULL), _("sh_hash_have_it"));
  /*
  if (p->allignore == S_FALSE && 
      (p->modi_mask & MODI_CHK) != 0 &&
      (p->modi_mask & MODI_MOD) != 0)
    SL_RETURN( (1), _("sh_hash_have_it"));
  */
  SL_RETURN( (p), _("sh_hash_have_it"));
}

int sh_hash_have_it (char * newname)
{
  sh_file_t * p = sh_hash_have_it_int (newname);

  if (!p) return (-1);
  if (p->allignore == S_FALSE && 
      (p->modi_mask & MODI_CHK) != 0 &&
      (p->modi_mask & MODI_MOD) != 0)
    return 1;
  return 0;
}

int sh_hash_get_it (char * newname, file_type * tmpFile)
{
  sh_file_t * p = sh_hash_have_it_int (newname);
  if (!p)
    return (-1);
  sl_strlcpy(tmpFile->fullpath, p->fullpath, PATH_MAX);
  sl_strlcpy(tmpFile->linkpath, p->linkpath, PATH_MAX);
  tmpFile->size  = p->theFile.size;
  tmpFile->mtime = p->theFile.mtime;
  tmpFile->ctime = p->theFile.ctime;
  return 0;
}
 

/*****************************************************************
 *
 * Set a file's status to 'visited'. This is required for
 * files that should be ignored, and may be present in the
 * database, but not on disk.
 *
 *****************************************************************/
static int sh_hash_set_visited_int (char * newname, int flag)
{
  sh_file_t * p;

  SL_ENTER(_("sh_hash_set_visited_int"));

  if (newname == NULL)
    SL_RETURN((-1), _("sh_hash_set_visited_int"));
  if (IsInit != 1) 
    sh_hash_init();

  if (sl_strlen(newname) <= MAX_PATH_STORE) 
    p = hashsearch(newname);
  else 
    p = hashsearch (sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname)));
  
  if (p == NULL) 
    SL_RETURN((-1), _("sh_hash_set_visited_int"));
  if (flag == 99)
    {
      p->visited  = 99;
      p->reported = S_FALSE;
    }
  else
    {
      p->visited  = S_TRUE;
      p->reported = flag;
    }
  SL_RETURN((0), _("sh_hash_set_visited_int"));
}


/* cause the record to be deleted without a 'missing' message
 */
int sh_hash_set_missing (char * newname)
{
  int i;
  SL_ENTER(_("sh_hash_set_visited"));
  i = sh_hash_set_visited_int(newname, 99);
  SL_RETURN(i, _("sh_hash_set_visited"));
}

int sh_hash_set_visited (char * newname)
{
  int i;
  SL_ENTER(_("sh_hash_set_visited"));
  i = sh_hash_set_visited_int(newname, S_TRUE);
  SL_RETURN(i, _("sh_hash_set_visited"));
}

int sh_hash_set_visited_true (char * newname)
{
  int i;
  SL_ENTER(_("sh_hash_set_visited_true"));
  i = sh_hash_set_visited_int(newname, S_FALSE);
  SL_RETURN(i, _("sh_hash_set_visited_true"));
}


/******************************************************************
 *
 * Data entry for arbitrary data into database
 *
 ******************************************************************/

static char * sh_hash_charhex( unsigned char i )
{
  static char i2h[2];
  int j, k;

  j = i / 16;
  k = i - (j*16);

  if (j < 10) i2h[0] = '0'+j;
  else        i2h[0] = 'A'+(j-10);
  
  if (k < 10) i2h[1] = '0'+k;
  else        i2h[1] = 'A'+(k-10);

  return i2h;
}

void sh_hash_push2db (char * key, unsigned long val1, 
                  unsigned long val2, unsigned long val3,
                  unsigned char * str, int size)
{
  file_type   tmpFile;
  int         i = 0;
  char      * p;

  sl_strlcpy(tmpFile.fullpath, key, PATH_MAX);
  tmpFile.size  = val1;
  tmpFile.mtime = val2;
  tmpFile.ctime = val3;

  tmpFile.atime = 0;
  tmpFile.mode  = 0;
  tmpFile.owner = 0;
  tmpFile.group = 0;
  sl_strlcpy(tmpFile.c_owner, _("root"), 5);
  sl_strlcpy(tmpFile.c_group, _("root"), 5);

  if ((str != NULL) && (size < (PATH_MAX/2)-1))
    {
      tmpFile.c_mode[0] = 'l';  
      tmpFile.c_mode[1] = 'r'; tmpFile.c_mode[2]  = 'w';
      tmpFile.c_mode[3] = 'x'; tmpFile.c_mode[4]  = 'r'; 
      tmpFile.c_mode[5] = 'w'; tmpFile.c_mode[6]  = 'x'; 
      tmpFile.c_mode[7] = 'r'; tmpFile.c_mode[8]  = 'w'; 
      tmpFile.c_mode[9] = 'x'; tmpFile.c_mode[10] = '\0'; 
      for (i = 0; i < size; ++i)
      {
        p = sh_hash_charhex (str[i]);
        tmpFile.linkpath[2*i]   = p[0];
        tmpFile.linkpath[2*i+1] = p[1];
        tmpFile.linkpath[2*i+2] = '\0';
      }
    }
  else
    {
      tmpFile.c_mode[0] = '-';  
      tmpFile.c_mode[1] = '-'; tmpFile.c_mode[2]  = '-';
      tmpFile.c_mode[3] = '-'; tmpFile.c_mode[4]  = '-'; 
      tmpFile.c_mode[5] = '-'; tmpFile.c_mode[6]  = '-'; 
      tmpFile.c_mode[7] = '-'; tmpFile.c_mode[8]  = '-'; 
      tmpFile.c_mode[9] = '-'; tmpFile.c_mode[10] = '\0'; 
      tmpFile.linkpath[0] = '-'; tmpFile.linkpath[1] = '\0';
    }

  sh_hash_pushdata (&tmpFile, 
                _("000000000000000000000000000000000000000000000000"));
  return;
}

extern int sh_util_hextobinary (char * binary, char * hex, int bytes);

char * sh_hash_db2pop (char * key, unsigned long * val1, 
                   unsigned long * val2, unsigned long * val3,
                   int * size)
{
  file_type   tmpFile;
  size_t      len;
  char      * p;
  int         i;

  *size = 0;

  if (0 == sh_hash_get_it (key, &tmpFile))
    {
      *val1  = tmpFile.size;
      *val2 = tmpFile.mtime;
      *val3 = tmpFile.ctime;

      if (tmpFile.linkpath[0] != '-')
      {
        len = strlen(tmpFile.linkpath);

        p = SH_ALLOC((len/2)+1);
        i = sh_util_hextobinary (p, tmpFile.linkpath, len);

        if (i == 0)
          {
            *size = (len/2);
            p[*size] = '\0';
            return p;
          }
        else
          {
            SH_FREE(p);
            *size = 0;
            return NULL;
          }
      }
      else
      {
        *size = 0;
        return NULL;
      }
    }
  else
    {
      *size = -1;
      *val1 =  0;
      *val2 =  0;
      *val3 =  0;
      return NULL;
    }
}




/******************************************************************
 *
 * Data entry in hash table
 *
 ******************************************************************/
sh_file_t * sh_hash_push_int (file_type * buf, char * fileHash)
{
  sh_file_t    * fp;
  sh_filestore_t p;
  long i;
  char * fullpath;
  char * linkpath;

  SL_ENTER(_("sh_hash_push_int"));

  fp = SH_ALLOC(sizeof(sh_file_t));

  p.mark = REC_MAGIC;
  sl_strlcpy(p.c_mode,   buf->c_mode,   11);
  sl_strlcpy(p.c_group,  buf->c_group,  GROUP_MAX+1);
  sl_strlcpy(p.c_owner,  buf->c_owner,  USER_MAX+1);
  sl_strlcpy(p.checksum, fileHash,      KEY_LEN+1);
#if defined(__linux__)
  sl_strlcpy(p.c_attributes, buf->c_attributes, 13);
#endif

#if defined(__linux__)
  p.attributes  = (UINT32) buf->attributes;
#endif
  p.linkmode    = (UINT32) buf->linkmode;
  p.hardlinks   = (UINT32) buf->hardlinks;
  p.mode  = (UINT32) buf->mode;
  p.ino   = (UINT32) buf->ino;
  p.size  = (UINT64) buf->size;
  p.mtime = (UINT64) buf->mtime;
  p.atime = (UINT64) buf->atime;
  p.ctime = (UINT64) buf->ctime;
  p.owner = (UINT32) buf->owner;
  p.group = (UINT32) buf->group;

  memcpy( &(*fp).theFile, &p, sizeof(sh_filestore_t) );
  fp->visited   = S_FALSE;
  fp->reported  = S_FALSE;
  fp->allignore = S_FALSE;
  fp->modi_mask = 0L;

  i = sl_strlen(buf->fullpath);
  if (i <= MAX_PATH_STORE) 
    {
      fullpath = SH_ALLOC(i+ 1);
      sl_strlcpy(fullpath, buf->fullpath, i+1);
    } 
  else 
    {
      fullpath = SH_ALLOC(KEY_LEN + 1);
      sl_strlcpy(fullpath, 
             sh_tiger_hash (buf->fullpath, TIGER_DATA, i), 
             KEY_LEN+1);
    }
  fp->fullpath  = fullpath;

  if (buf->c_mode[0] == 'l')
    {  
      i = sl_strlen(buf->linkpath);
      if (i <= MAX_PATH_STORE) 
      {
        linkpath = SH_ALLOC(i+ 1);
        sl_strlcpy(linkpath, buf->linkpath, i+1);
      } 
      else 
      {
        linkpath = SH_ALLOC(KEY_LEN + 1);
        sl_strlcpy(linkpath, 
                 sh_tiger_hash (buf->linkpath, TIGER_DATA, i), 
                 KEY_LEN+1);
      }
      fp->linkpath  = linkpath;
    }
  else
    fp->linkpath  = NULL;

  SL_RETURN( fp, _("sh_hash_push_int"));
}

#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#else
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#endif

#ifndef PRIi64
#define PRIi64 "lld"
#endif

char * sh_hash_size_format()
{
  static char form_rval[81];

  SL_ENTER(_("sh_hash_size_format"));


#ifdef SH_USE_XML
  sl_snprintf(form_rval, 80, _("%s%s%s%s%s"), 
            _("size_old=\"%"), PRIi64, _("\" size_new=\"%"), PRIi64, "\" ");
#else
  sl_snprintf(form_rval, 80, _("%s%s%s%s%s"), 
            _("size_old=<%"), PRIi64, _(">, size_new=<%"), PRIi64, ">, ");
#endif

  SL_RETURN( form_rval, _("sh_hash_size_format"));
}


#ifdef SH_USE_XML
static char * all_items (file_type * theFile, char * fileHash, int is_new)
{
  char timstr1c[32];
  char timstr1a[32];
  char timstr1m[32];

  char * tmp_lnk;
  char * format;

  char * tmp = SH_ALLOC(SH_BUFSIZE);
  char * msg = SH_ALLOC(SH_BUFSIZE);

  tmp[0] = '\0';
  msg[0] = '\0';


#if defined(__linux__)
  if (is_new)
    format = _("mode_new=\"%s\" attr_new=\"%s\" imode_new=\"%ld\" iattr_new=\"%ld\" ");
  else 
    format = _("mode_old=\"%s\" attr_old=\"%s\" imode_old=\"%ld\" iattr_old=\"%ld\" ");
  sl_snprintf(tmp, SH_BUFSIZE, format,
            theFile->c_mode,
            theFile->c_attributes,
            (long) theFile->mode,
            (long) theFile->attributes
            );
#else
  if (is_new)
    format = _("mode_new=\"%s\" imode_new=\"%ld\" ");
  else
    format = _("mode_old=\"%s\" imode_old=\"%ld\" ");

  sl_snprintf(tmp, SH_BUFSIZE, format,
            theFile->c_mode,
            (long) theFile->mode
            );
#endif
  sl_strlcat(msg, tmp, SH_BUFSIZE);

  if (is_new)
    format = _("hardlinks_new=\"%ld\" ");
  else
    format = _("hardlinks_old=\"%ld\" ");
  sl_snprintf(tmp, SH_BUFSIZE, format,
            (unsigned long) theFile->hardlinks);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  if (is_new)
    format = _("idevice_new=\"%ld\" ");
  else
    format = _("idevice_old=\"%ld\" ");
  sl_snprintf(tmp, SH_BUFSIZE, format, (unsigned long) theFile->rdev);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  if (is_new)
    format = _("inode_new=\"%ld\" ");
  else
    format = _("inode_old=\"%ld\" ");
  sl_snprintf(tmp, SH_BUFSIZE, format, (unsigned long) theFile->ino);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  if (is_new)
    format = _("owner_new=\"%s\" iowner_new=\"%ld\" ");
  else
    format = _("owner_old=\"%s\" iowner_old=\"%ld\" ");
  sl_snprintf(tmp, SH_BUFSIZE, format,
            theFile->c_owner, (long) theFile->owner);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  if (is_new)
    format = _("group_new=\"%s\" igroup_new=\"%ld\" ");
  else
    format = _("group_old=\"%s\" igroup_old=\"%ld\" ");
  sl_snprintf(tmp, SH_BUFSIZE, format,
            theFile->c_group, (long) theFile->group);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  if (is_new)
    sl_snprintf(tmp, SH_BUFSIZE, sh_hash_size_format(),
            (UINT64) 0, (UINT64) theFile->size);
  else
    sl_snprintf(tmp, SH_BUFSIZE, sh_hash_size_format(),
            (UINT64) theFile->size, (UINT64) 0);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  sl_strlcpy (timstr1c, sh_unix_gmttime (theFile->ctime),   32);
  if (is_new)
    sl_snprintf(tmp, SH_BUFSIZE, _("ctime_new=\"%s\" "), timstr1c);
  else
    sl_snprintf(tmp, SH_BUFSIZE, _("ctime_old=\"%s\" "), timstr1c);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 

  sl_strlcpy (timstr1a, sh_unix_gmttime (theFile->atime),   32);
  if (is_new)
    sl_snprintf(tmp, SH_BUFSIZE, _("atime_new=\"%s\" "), timstr1a);
  else
    sl_snprintf(tmp, SH_BUFSIZE, _("atime_old=\"%s\" "), timstr1a);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 

  sl_strlcpy (timstr1m, sh_unix_gmttime (theFile->mtime),   32);
  if (is_new)
    sl_snprintf(tmp, SH_BUFSIZE, _("mtime_new=\"%s\" "), timstr1m);
  else
    sl_snprintf(tmp, SH_BUFSIZE, _("mtime_old=\"%s\" "), timstr1m);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 

  if (is_new)
    sl_snprintf(tmp, SH_BUFSIZE, _("chksum_new=\"%s\" "), fileHash);
  else
    sl_snprintf(tmp, SH_BUFSIZE, _("chksum_old=\"%s\" "), fileHash);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 

  if (theFile->c_mode[0] == 'l')
    {
      tmp_lnk     = sh_util_safe_name(theFile->linkpath);
      if (tmp_lnk)
      {
        if (is_new)
          sl_snprintf(tmp, SH_BUFSIZE, _("link_new=\"%s\" "), tmp_lnk);
        else
          sl_snprintf(tmp, SH_BUFSIZE, _("link_old=\"%s\" "), tmp_lnk);
        SH_FREE(tmp_lnk);
        sl_strlcat(msg, tmp, SH_BUFSIZE);
      } 
    }
  
  SH_FREE(tmp);
  return (msg);
}
#else
static char * all_items (file_type * theFile, char * fileHash, int is_new)
{
  char timstr1c[32];
  char timstr1a[32];
  char timstr1m[32];

  char * tmp_lnk;
  char * format;

  char * tmp = SH_ALLOC(SH_BUFSIZE);
  char * msg = SH_ALLOC(SH_BUFSIZE);

  tmp[0] = '\0';
  msg[0] = '\0';


#if defined(__linux__)
  if (is_new)
    format = _("mode_new=<%s>, attr_new=<%s>, imode_new=<%ld>, iattr_new=<%ld>, ");
  else 
    format = _("mode_old=<%s>, attr_old=<%s>, imode_old=<%ld>, iattr_old=<%ld>, ");
  sl_snprintf(tmp, SH_BUFSIZE, format,
            theFile->c_mode,
            theFile->c_attributes,
            (long) theFile->mode,
            (long) theFile->attributes
            );
#else
  if (is_new)
    format = _("mode_new=<%s>, imode_new=<%ld>, ");
  else
    format = _("mode_old=<%s>, imode_old=<%ld>, ");

  sl_snprintf(tmp, SH_BUFSIZE, format,
            theFile->c_mode,
            (long) theFile->mode
            );
#endif
  sl_strlcat(msg, tmp, SH_BUFSIZE);

  if (is_new)
    format = _("hardlinks_new=<%ld>, ");
  else
    format = _("hardlinks_old=<%ld>, ");
  sl_snprintf(tmp, SH_BUFSIZE, format,
            (unsigned long) theFile->hardlinks);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  if (is_new)
    format = _("idevice_new=<%ld>, ");
  else
    format = _("idevice_old=<%ld>, ");
  sl_snprintf(tmp, SH_BUFSIZE, format, (unsigned long) theFile->rdev);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  if (is_new)
    format = _("inode_new=<%ld>, ");
  else
    format = _("inode_old=<%ld>, ");
  sl_snprintf(tmp, SH_BUFSIZE, format, (unsigned long) theFile->ino);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  if (is_new)
    format = _("owner_new=<%s>, iowner_new=<%ld>, ");
  else
    format = _("owner_old=<%s>, iowner_old=<%ld>, ");
  sl_snprintf(tmp, SH_BUFSIZE, format,
            theFile->c_owner, (long) theFile->owner);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  if (is_new)
    format = _("group_new=<%s>, igroup_new=<%ld>, ");
  else
    format = _("group_old=<%s>, igroup_old=<%ld>, ");
  sl_snprintf(tmp, SH_BUFSIZE, format,
            theFile->c_group, (long) theFile->group);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  if (is_new)
    sl_snprintf(tmp, SH_BUFSIZE, sh_hash_size_format(),
            (UINT64) 0, (UINT64) theFile->size);
  else
    sl_snprintf(tmp, SH_BUFSIZE, sh_hash_size_format(),
            (UINT64) theFile->size, (UINT64) 0);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 


  sl_strlcpy (timstr1c, sh_unix_gmttime (theFile->ctime),   32);
  if (is_new)
    sl_snprintf(tmp, SH_BUFSIZE, _("ctime_new=<%s>, "), timstr1c);
  else
    sl_snprintf(tmp, SH_BUFSIZE, _("ctime_old=<%s>, "), timstr1c);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 

  sl_strlcpy (timstr1a, sh_unix_gmttime (theFile->atime),   32);
  if (is_new)
    sl_snprintf(tmp, SH_BUFSIZE, _("atime_new=<%s>, "), timstr1a);
  else
    sl_snprintf(tmp, SH_BUFSIZE, _("atime_old=<%s>, "), timstr1a);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 

  sl_strlcpy (timstr1m, sh_unix_gmttime (theFile->mtime),   32);
  if (is_new)
    sl_snprintf(tmp, SH_BUFSIZE, _("mtime_new=<%s>, "), timstr1m);
  else
    sl_snprintf(tmp, SH_BUFSIZE, _("mtime_old=<%s>, "), timstr1m);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 

  if (is_new)
    sl_snprintf(tmp, SH_BUFSIZE, _("chksum_new=<%s>"), fileHash);
  else
    sl_snprintf(tmp, SH_BUFSIZE, _("chksum_old=<%s>"), fileHash);
  sl_strlcat(msg, tmp, SH_BUFSIZE); 

  if (theFile->c_mode[0] == 'l')
    {
      tmp_lnk     = sh_util_safe_name(theFile->linkpath);
      if (tmp_lnk)
      {
        if (is_new)
          sl_snprintf(tmp, SH_BUFSIZE, _(", link_new=<%s> "), tmp_lnk);
        else
          sl_snprintf(tmp, SH_BUFSIZE, _(", link_old=<%s> "), tmp_lnk);
        SH_FREE(tmp_lnk);
        sl_strlcat(msg, tmp, SH_BUFSIZE);
      } 
    }
  
  SH_FREE(tmp);
  return (msg);
}
#endif

/*****************************************************************
 *
 * Compare a file with the database status.
 *
 *****************************************************************/
int sh_hash_compdata (int class, file_type * theFile, char * fileHash,
                  char * policy_override, int severity_override)
{
  char * msg;
  sh_file_t * p;
  char * tmp;
  char * tmp_path;
  char * tmp_lnk;
  char * tmp_lnk_old;

  char * str;

  char timstr1c[32];
  char timstr2c[32];
  char timstr1a[32];
  char timstr2a[32];
  char timstr1m[32];
  char timstr2m[32];
  char linkHash[KEY_LEN+1];
  int  maxcomp;

  char change_code[16];
  int  i;

  unsigned long modi_mask = 0;

  char log_policy[32];
  int  log_severity;

  SL_ENTER(_("sh_hash_compdata"));

  if (IsInit != 1) sh_hash_init();

  if (severity_override < 0)
    log_severity = ShDFLevel[class];
  else
    log_severity = severity_override;

  if (policy_override != NULL)
    sl_strlcpy (log_policy, policy_override, 32);

  /* --------  find the entry for the file ----------------       */

  if (sl_strlen(theFile->fullpath) <= MAX_PATH_STORE) 
    p = hashsearch(theFile->fullpath);
  else 
    p = hashsearch( sh_tiger_hash(theFile->fullpath, 
                          TIGER_DATA, 
                          sl_strlen(theFile->fullpath))
                );


  /* --------- Not found in database. ------------
   */

  if (p == NULL) 
    {
      if (sh.flag.reportonce == S_TRUE)
      {
        p = sh_hash_push_int(theFile, fileHash);
        hashinsert (p);
        if (p)
          p->modi_mask = theFile->check_mask;

      }

      if (S_FALSE == sh_ignore_chk_new(theFile->fullpath))
      {
        tmp = sh_util_safe_name(theFile->fullpath);

        str = all_items (theFile, fileHash, 1);
        sh_error_handle (log_severity, FIL__, __LINE__, 0, 
                     MSG_FI_ADD2, 
                     tmp, str);
        SH_FREE(str);

        SH_FREE(tmp);
      }

      if (p)
      p->visited   = S_TRUE;
      if (sh.flag.reportonce == S_TRUE)
      theFile->reported = S_TRUE;
      
      if (sh.flag.checkSum == SH_CHECK_INIT && sh.flag.update == S_TRUE )
      {
        if (S_FALSE == sh_util_ask_update (theFile->fullpath))
          {
            SL_RETURN(1, _("sh_hash_compdata"));
          } 
      }
      SL_RETURN(0, _("sh_hash_compdata"));
    }
  else
    {
      p->modi_mask = theFile->check_mask;
    }

  /* initialize change_code */
  for (i = 0; i < 15; ++i)
    change_code[i] = '-';
  change_code[15] = '\0';

  TPT ((0, FIL__, __LINE__, _("file=<%s>, cs_old=<%s>, cs_new=<%s>\n"),
      theFile->fullpath, fileHash, p->theFile.checksum));

  if ( (fileHash != NULL) && (p->theFile.checksum != NULL)   && 
       (strncmp (fileHash, p->theFile.checksum, 50) != 0) && 
       (theFile->check_mask & MODI_CHK) != 0)
    {
      modi_mask |= MODI_CHK;
      change_code[0] = 'C';
      TPT ((0, FIL__, __LINE__, _("mod=<checksum>")));
    } 

  if (p->theFile.c_mode[0] == 'l') 
    {
      if (sl_strlen(theFile->linkpath) >= MAX_PATH_STORE) 
      {
        sl_strlcpy(linkHash, 
                 sh_tiger_hash(theFile->linkpath, 
                           TIGER_DATA,
                           sl_strlen(theFile->linkpath)), 
                 MAX_PATH_STORE+1);
        maxcomp = MAX_PATH_STORE;
      } 
      else 
      {
        sl_strlcpy(linkHash, theFile->linkpath, KEY_LEN + 1);
        maxcomp = KEY_LEN;
      }

    if ( sl_strncmp (linkHash, p->linkpath, maxcomp) != 0 &&
       (theFile->check_mask & MODI_LNK) != 0)
      {
      modi_mask |= MODI_LNK;
      change_code[1] = 'L';
      TPT ((0, FIL__, __LINE__, _("mod=<link>")));
      } 
    }

  if (p->theFile.c_mode[0] == 'c' || p->theFile.c_mode[0] == 'b') 
    {
      if ( ( major(theFile->rdev) != major((dev_t)p->theFile.rdev) || 
           minor(theFile->rdev) != minor((dev_t)p->theFile.rdev) ) &&
         (theFile->check_mask & MODI_RDEV) != 0)
      {
        modi_mask |= MODI_RDEV;
        change_code[2] = 'D';
        TPT ((0, FIL__, __LINE__, _("mod=<rdev>")));
      } 
    }
      
  /* cast to UINT32 in case ino_t is not 32bit
   */
  if ( (UINT32) theFile->ino != (UINT32) p->theFile.ino  &&
       (theFile->check_mask & MODI_INO) != 0)
    {
      modi_mask |= MODI_INO;
      change_code[3] = 'I';
      TPT ((0, FIL__, __LINE__, _("mod=<inode>")));
    } 
    
  if ( theFile->hardlinks != (nlink_t) p->theFile.hardlinks &&
       (theFile->check_mask & MODI_HLN) != 0)
    {
      modi_mask |= MODI_HLN;
      change_code[4] = 'H';
      TPT ((0, FIL__, __LINE__, _("mod=<hardlink>")));
    } 


  if ( (  (theFile->mode != p->theFile.mode)
#if defined(__linux__)
          || (theFile->attributes != p->theFile.attributes)
#endif
        )
       && (theFile->check_mask & MODI_MOD) != 0)
    {
      modi_mask |= MODI_MOD;
      change_code[5] = 'M';
      TPT ((0, FIL__, __LINE__, _("mod=<mode>")));
    } 

  if ( theFile->owner != (uid_t) p->theFile.owner &&
       (theFile->check_mask & MODI_USR) != 0)
    {
      modi_mask |= MODI_USR;
      change_code[6] = 'U';
      TPT ((0, FIL__, __LINE__, _("mod=<user>")));
    } 

  if ( theFile->group != (gid_t) p->theFile.group &&
       (theFile->check_mask & MODI_GRP) != 0)
    {
      modi_mask |= MODI_GRP;
      change_code[7] = 'G';
      TPT ((0, FIL__, __LINE__, _("mod=<group>")));
    } 

  
  if ( theFile->mtime != (time_t) p->theFile.mtime &&
       (theFile->check_mask & MODI_MTM) != 0)
    {
      modi_mask |= MODI_MTM;
      change_code[8] = 'T';
      TPT ((0, FIL__, __LINE__, _("mod=<mtime>")));
    } 
  
  if ( theFile->atime != (time_t) p->theFile.atime &&
       (theFile->check_mask & MODI_ATM) != 0)
    {
      modi_mask |= MODI_ATM;
      change_code[8] = 'T';
      TPT ((0, FIL__, __LINE__, _("mod=<atime>")));
    } 

  
  /* Resetting the access time will set a new ctime. Thus, either we ignore
   * the access time or the ctime for NOIGNORE
   */
  if ( theFile->ctime != (time_t) p->theFile.ctime &&
       (theFile->check_mask & MODI_CTM) != 0)
    {
      modi_mask |= MODI_CTM;
      change_code[8] = 'T';
      TPT ((0, FIL__, __LINE__, _("mod=<ctime>")));
    } 

  if ( theFile->size != (off_t) p->theFile.size &&
       (theFile->check_mask & MODI_SIZ) != 0)
    {
      if (class == SH_LEVEL_LOGGROW && theFile->size < (off_t) p->theFile.size)
      {
        modi_mask |= MODI_SIZ;
        change_code[9] = 'S';
        TPT ((0, FIL__, __LINE__, _("mod=<size>")));
      } 
      else if (class != SH_LEVEL_LOGGROW)
      { 
        modi_mask |= MODI_SIZ;
        change_code[9] = 'S';
        TPT ((0, FIL__, __LINE__, _("mod=<size>")));
      } 
    }
  change_code[10] = '\0';

  /* --- Report full details. ---
   */
  if (modi_mask != 0 && sh.flag.fulldetail == S_TRUE)
    {
      if ((theFile->check_mask & MODI_ATM) == 0)
      modi_mask = MASK_READONLY_;
      else
      modi_mask = MASK_NOIGNORE_;
    }

  /* --- Report on modified files. ---
   */
  if (modi_mask != 0 && p->reported == S_FALSE)
    { 
      tmp = SH_ALLOC(SH_BUFSIZE);
      msg = SH_ALLOC(SH_BUFSIZE);
      msg[0] = '\0';

      if (   ((modi_mask & MODI_MOD) != 0)
#if defined(HAVE_LIBPRELUDE) && defined(HAVE_LIBPRELUDE_9)
        || ((modi_mask & MODI_USR) != 0)
        || ((modi_mask & MODI_GRP) != 0)
#endif
           )
      {
#if defined(__linux__)
        sl_snprintf(tmp, SH_BUFSIZE, 
#ifdef SH_USE_XML
                  _("mode_old=\"%s\" mode_new=\"%s\" attr_old=\"%s\" attr_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" iattr_old=\"%ld\" iattr_new=\"%ld\" "),
#else
                  _("mode_old=<%s>, mode_new=<%s>, attr_old=<%s>, attr_new=<%s>, "),
#endif
                  p->theFile.c_mode, theFile->c_mode,
                  p->theFile.c_attributes, theFile->c_attributes
#ifdef SH_USE_XML
                  , (long) p->theFile.mode, (long) theFile->mode,
                  (long) p->theFile.attributes, 
                  (long) theFile->attributes
#endif
                  );
#else
#ifdef SH_USE_XML
        sl_snprintf(tmp, SH_BUFSIZE, 
                  _("mode_old=\"%s\" mode_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" "),
#else
                  sl_snprintf(tmp, SH_BUFSIZE, _("mode_old=<%s>, mode_new=<%s>, "),
#endif
                  p->theFile.c_mode, theFile->c_mode
#ifdef SH_USE_XML
                  , (long) p->theFile.mode, (long) theFile->mode
#endif
                  );
#endif
        sl_strlcat(msg, tmp, SH_BUFSIZE);
#ifdef REPLACE_OLD
        if ((modi_mask & MODI_MOD) != 0)
          {
            if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
            {
              sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
              p->theFile.mode = theFile->mode;
#if defined(__linux__)
              sl_strlcpy(p->theFile.c_attributes,theFile->c_attributes,16);
              p->theFile.attributes = theFile->attributes;
#endif
            }
          }
#endif
      }

      if ((modi_mask & MODI_HLN) != 0)
      {
        sl_snprintf(tmp, SH_BUFSIZE, 
#ifdef SH_USE_XML
                  _("hardlinks_old=\"%ld\" hardlinks_new=\"%ld\" "),
#else
                  _("hardlinks_old=<%ld>, hardlinks_new=<%ld>, "),
#endif
                  (unsigned long) p->theFile.hardlinks, 
                  (unsigned long) theFile->hardlinks);
        sl_strlcat(msg, tmp, SH_BUFSIZE); 
#ifdef REPLACE_OLD
        if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
          p->theFile.hardlinks = theFile->hardlinks;
#endif
      }

      if ((modi_mask & MODI_RDEV) != 0)
      {
        sl_snprintf(tmp, SH_BUFSIZE,
#ifdef SH_USE_XML 
                  _("device_old=\"%ld,%ld\" device_new=\"%ld,%ld\" idevice_old=\"%ld\" idevice_new=\"%ld\" "),
#else
                  _("device_old=<%ld,%ld>, device_new=<%ld,%ld>, "),
#endif
                  (unsigned long) major(p->theFile.rdev), 
                  (unsigned long) minor(p->theFile.rdev), 
                  (unsigned long) major(theFile->rdev),
                  (unsigned long) minor(theFile->rdev)
#ifdef SH_USE_XML 
                  , (unsigned long) p->theFile.rdev, 
                  (unsigned long) theFile->rdev
#endif
                  );
        sl_strlcat(msg, tmp, SH_BUFSIZE); 
#ifdef REPLACE_OLD
        if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
          p->theFile.rdev = theFile->rdev;
#endif
      }

      if ((modi_mask & MODI_INO) != 0)
      {
        sl_snprintf(tmp, SH_BUFSIZE,
#ifdef SH_USE_XML 
                  _("inode_old=\"%ld\" inode_new=\"%ld\" "),
#else
                  _("inode_old=<%ld>, inode_new=<%ld>, "),
#endif
                  (unsigned long) p->theFile.ino, 
                  (unsigned long) theFile->ino);
        sl_strlcat(msg, tmp, SH_BUFSIZE); 
#ifdef REPLACE_OLD
        if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
          p->theFile.ino = theFile->ino;
#endif
      }

      if (   ((modi_mask & MODI_USR) != 0)
#if defined(HAVE_LIBPRELUDE) && defined(HAVE_LIBPRELUDE_9)
        || ((modi_mask & MODI_MOD) != 0)
#endif
        )
      {
#ifdef SH_USE_XML
        sl_snprintf(tmp, SH_BUFSIZE, _("owner_old=\"%s\" owner_new=\"%s\" iowner_old=\"%ld\" iowner_new=\"%ld\" "),
#else
        sl_snprintf(tmp, SH_BUFSIZE, _("owner_old=<%s>, owner_new=<%s>, "),
#endif
                  p->theFile.c_owner, theFile->c_owner
#ifdef SH_USE_XML
                  , (long) p->theFile.owner, (long) theFile->owner
#endif
                  );
        sl_strlcat(msg, tmp, SH_BUFSIZE); 
#ifdef REPLACE_OLD
        if ((modi_mask & MODI_USR) != 0) {
          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
            {
            sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
            p->theFile.owner = theFile->owner;
            }
        }
#endif
      }

      if (   ((modi_mask & MODI_GRP) != 0)
#if defined(HAVE_LIBPRELUDE) && defined(HAVE_LIBPRELUDE_9)
        || ((modi_mask & MODI_MOD) != 0)
#endif
        )
      {
#ifdef SH_USE_XML
        sl_snprintf(tmp, SH_BUFSIZE, _("group_old=\"%s\" group_new=\"%s\" igroup_old=\"%ld\" igroup_new=\"%ld\" "),
                  p->theFile.c_group, theFile->c_group,
                  (long) p->theFile.group, (long) theFile->group);
#else
        sl_snprintf(tmp, SH_BUFSIZE, _("group_old=<%s>, group_new=<%s>, "),
                  p->theFile.c_group, theFile->c_group);
#endif

        sl_strlcat(msg, tmp, SH_BUFSIZE); 
#ifdef REPLACE_OLD
          if ((modi_mask & MODI_GRP) != 0) {
          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
            {
            sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
            p->theFile.group = theFile->group;
            }
        }
#endif
      }

      if ((modi_mask & MODI_SIZ) != 0)
      {
        sl_snprintf(tmp, SH_BUFSIZE, sh_hash_size_format(),
                  (UINT64) p->theFile.size, 
                  (UINT64) theFile->size);
        sl_strlcat(msg, tmp, SH_BUFSIZE); 
#ifdef REPLACE_OLD
        if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
          p->theFile.size = theFile->size;
#endif
      }

      if ((modi_mask & MODI_CTM) != 0)
      {
        sl_strlcpy (timstr1c, sh_unix_gmttime (p->theFile.ctime), 32);
        sl_strlcpy (timstr2c, sh_unix_gmttime (theFile->ctime),   32);
#ifdef SH_USE_XML
        sl_snprintf(tmp, SH_BUFSIZE, _("ctime_old=\"%s\" ctime_new=\"%s\" "),
                  timstr1c, timstr2c);
#else
        sl_snprintf(tmp, SH_BUFSIZE, _("ctime_old=<%s>, ctime_new=<%s>, "),
                  timstr1c, timstr2c);
#endif
        sl_strlcat(msg, tmp, SH_BUFSIZE); 
#ifdef REPLACE_OLD
        if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
          p->theFile.ctime = theFile->ctime;
#endif
      }

      if ((modi_mask & MODI_ATM) != 0)
      {
        sl_strlcpy (timstr1a, sh_unix_gmttime (p->theFile.atime), 32);
        sl_strlcpy (timstr2a, sh_unix_gmttime (theFile->atime),   32);
#ifdef SH_USE_XML
        sl_snprintf(tmp, SH_BUFSIZE, _("atime_old=\"%s\" atime_new=\"%s\" "),
                  timstr1a, timstr2a);
#else
        sl_snprintf(tmp, SH_BUFSIZE, _("atime_old=<%s>, atime_new=<%s>, "),
                  timstr1a, timstr2a);
#endif
        sl_strlcat(msg, tmp, SH_BUFSIZE); 
#ifdef REPLACE_OLD
        if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
          p->theFile.atime = theFile->atime;
#endif
      }

      if ((modi_mask & MODI_MTM) != 0)
      {
        sl_strlcpy (timstr1m, sh_unix_gmttime (p->theFile.mtime), 32);
        sl_strlcpy (timstr2m, sh_unix_gmttime (theFile->mtime),   32);
#ifdef SH_USE_XML
        sl_snprintf(tmp, SH_BUFSIZE, _("mtime_old=\"%s\" mtime_new=\"%s\" "),
                  timstr1m, timstr2m);
#else
        sl_snprintf(tmp, SH_BUFSIZE, _("mtime_old=<%s>, mtime_new=<%s>, "),
                  timstr1m, timstr2m);
#endif
        sl_strlcat(msg, tmp, SH_BUFSIZE); 
#ifdef REPLACE_OLD
        if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
          p->theFile.mtime = theFile->mtime;
#endif
      }


      if ((modi_mask & MODI_CHK) != 0)
      {
        sl_snprintf(tmp, SH_BUFSIZE, 
#ifdef SH_USE_XML
                  _("chksum_old=\"%s\" chksum_new=\"%s\" "),
#else
                  _("chksum_old=<%s>, chksum_new=<%s>, "),
#endif
                  p->theFile.checksum, fileHash);
        sl_strlcat(msg, tmp, SH_BUFSIZE); 
#ifdef REPLACE_OLD
        if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
          sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
#endif
      }


      if ((modi_mask & MODI_LNK) != 0 && theFile->c_mode[0] == 'l')
      {
        tmp_lnk     = sh_util_safe_name(theFile->linkpath);
        tmp_lnk_old = sh_util_safe_name(p->linkpath);
#ifdef SH_USE_XML
        sl_snprintf(tmp, SH_BUFSIZE, _("link_old=\"%s\" link_new=\"%s\" "),
                  tmp_lnk_old, tmp_lnk);
#else
        sl_snprintf(tmp, SH_BUFSIZE, _("link_old=<%s>, link_new=<%s>"),
                  tmp_lnk_old, tmp_lnk);
#endif
        SH_FREE(tmp_lnk);
        SH_FREE(tmp_lnk_old);
        sl_strlcat(msg, tmp, SH_BUFSIZE); 
#ifdef REPLACE_OLD
        if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
          {
            if (p->linkpath != NULL)
            SH_FREE(p->linkpath);
            p->linkpath = (char*)SH_ALLOC (sl_strlen(theFile->linkpath) + 1);
            sl_strlcpy(p->linkpath, theFile->linkpath, 
                   sl_strlen(theFile->linkpath) + 1);
          }
#endif
      }


      tmp_path = sh_util_safe_name(theFile->fullpath);
      sh_error_handle(log_severity, FIL__, __LINE__, 
                  (long) modi_mask, MSG_FI_CHAN,
                  (policy_override == NULL) ? _(policy[class]):log_policy,
                  change_code, tmp_path, msg);

      SH_FREE(tmp_path);
      SH_FREE(tmp);
      SH_FREE(msg);

#ifndef REPLACE_OLD
      p->reported = S_TRUE;
#endif

      if (S_TRUE  == sh.flag.update)
      {
        if (S_FALSE == sh_util_ask_update(theFile->fullpath))
          {
            /* user does not want to update, thus we replace
             * with data from the baseline database
             */
            sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11);
            theFile->mode  =  p->theFile.mode;
#if defined(__linux__)
            sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, 16);
            theFile->attributes =  p->theFile.attributes;
#endif
            
            if (theFile->c_mode[0] == 'l') /* c_mode is already copied */
            {
              sl_strlcpy(theFile->linkpath, p->linkpath, PATH_MAX);
            }
            else
            {
              theFile->linkpath[0] = '-';
              theFile->linkpath[1] = '\0';
            }
            
            sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
            
            theFile->mtime =  p->theFile.mtime;
            theFile->ctime =  p->theFile.ctime;
            theFile->atime =  p->theFile.atime;
            
            theFile->size  =  p->theFile.size;
            
            sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2);
            theFile->group =  p->theFile.group;
            sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2);
            theFile->owner =  p->theFile.owner;
            
            theFile->ino   =  p->theFile.ino;
            theFile->rdev  =  p->theFile.rdev;
            theFile->dev   =  p->theFile.dev;
            theFile->hardlinks = p->theFile.hardlinks;
            
            p->visited = S_TRUE;
            SL_RETURN(1, _("sh_hash_compdata"));
          }
        else if (sh.flag.reportonce == S_TRUE)
          {
            /* we replace the data in the in-memory copy of the
             * baseline database, because otherwise we would get
             * another warning if the suidcheck runs
             */
            sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
            p->theFile.mode  =  p->theFile.mode;
#if defined(__linux__)
            sl_strlcpy(p->theFile.c_attributes, theFile->c_attributes, 16);
            p->theFile.attributes = theFile->attributes;
#endif
            
            if (theFile->c_mode[0] == 'l')
            {
                  if (p->linkpath != NULL)
                SH_FREE(p->linkpath);
              p->linkpath = SH_ALLOC(1 + strlen(theFile->linkpath));
              sl_strlcpy(p->linkpath, theFile->linkpath, 
                       1 + strlen(theFile->linkpath));
            }
            else
            {
                if (p->linkpath != NULL) {
                p->linkpath[0] = '-';
                p->linkpath[1] = '\0';
                  } else {
                p->linkpath = SH_ALLOC(2);
                p->linkpath[0] = '-';
                    p->linkpath[1] = '\0';
                  }
            }
            
            sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
            
            p->theFile.mtime = theFile->mtime;
            p->theFile.ctime = theFile->ctime;
            p->theFile.atime = theFile->atime;
            
            p->theFile.size  = theFile->size;
            
            sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
            p->theFile.group =  theFile->group;
            sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
            p->theFile.owner =  theFile->owner;
            
            p->theFile.ino  = theFile->ino;
            p->theFile.rdev = theFile->rdev;
            p->theFile.dev  = theFile->dev;
            p->theFile.hardlinks = theFile->hardlinks;
          }
      }

    }

  p->visited = S_TRUE;

  SL_RETURN(0, _("sh_hash_compdata"));
}

int hash_full_tree () 
{
  sh_file_t * p;
  int         i;

  SL_ENTER(_("sh_hash_compdata"));

  if (IsInit != 1) 
    SL_RETURN(0, _("sh_hash_compdata"));

  for (i = 0; i < TABSIZE; ++i)
    {
      for (p = tab[i]; p; p = p->next)
      p->allignore  = S_FALSE;
    }
  SL_RETURN (0, _("sh_hash_compdata"));
} 


int hash_remove_tree (char * s) 
{
  sh_file_t * p;
  int         len;
  int         i;

  SL_ENTER(_("hash_remove_tree"));

  if (!s)
    SL_RETURN ((-1), _("hash_remove_tree"));
  else
    len = sl_strlen(s);

  if (IsInit != 1) 
    sh_hash_init();

  for (i = 0; i < TABSIZE; ++i)
    {
      for (p = tab[i]; p; p = p->next)
      {
        if (sl_strncmp(s, p->fullpath, len) == 0)
          { 
            p->allignore  = S_TRUE;
          }
      }
    }
  SL_RETURN ((0), _("hash_remove_tree"));
} 

#if TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
#endif

static int ListFullDetail = S_FALSE;
static int ListWithDelimiter = S_FALSE;

int set_full_detail (char * c)
{
  ListFullDetail = S_TRUE;
  /* warning: unused parameter `c' */
  if (c)
    return 0;
  else
    return 0;
}
 
int set_list_delimited (char * c)
{
  ListFullDetail = S_TRUE;
  ListWithDelimiter = S_TRUE;
  /* warning: unused parameter `c' */
  if (c)
    return 0;
  else
    return 0;
}
 
void sh_hash_list_db_entry_full_detail (sh_file_t * p)
{
  char * tmp;
  char   str[81];

  if (ListWithDelimiter == S_TRUE)
    {
      printf(_("%7ld, %10s, %5d, %12s, %5d, %3d, %-8s, %5d, %-8s, %5d, "),
           (unsigned long) p->theFile.ino,
           p->theFile.c_mode, (int) p->theFile.mode,
           p->theFile.c_attributes, (int) p->theFile.attributes,
           (int) p->theFile.hardlinks,
           p->theFile.c_owner, (int) p->theFile.owner, 
           p->theFile.c_group, (int) p->theFile.group);
    }
  else
    {
      printf(_("%7ld %10s %5d %12s %5d %3d %-8s %5d %-8s %5d "),
           (unsigned long) p->theFile.ino,
           p->theFile.c_mode, (int) p->theFile.mode,
           p->theFile.c_attributes, (int) p->theFile.attributes,
           (int) p->theFile.hardlinks,
           p->theFile.c_owner, (int) p->theFile.owner, 
           p->theFile.c_group, (int) p->theFile.group);
    }

  if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
    sl_snprintf(str, 80, "%"PRIi64, p->theFile.rdev);
  else
    sl_snprintf(str, 80, "%"PRIi64, p->theFile.size);

  printf( _(" %8s"), str);
  if (ListWithDelimiter == S_TRUE)
    putchar(',');

  printf( _(" %s"), sh_unix_gmttime (p->theFile.ctime));
  if (ListWithDelimiter == S_TRUE)
    putchar(',');
  printf( _(" %s"), sh_unix_gmttime (p->theFile.mtime));
  if (ListWithDelimiter == S_TRUE)
    putchar(',');
  printf( _(" %s"), sh_unix_gmttime (p->theFile.atime));
  if (ListWithDelimiter == S_TRUE)
    putchar(',');
  printf( _(" %s"), p->theFile.checksum);
  if (ListWithDelimiter == S_TRUE)
    putchar(',');

  tmp = sh_util_safe_name(p->fullpath);
  printf( _(" %s"), tmp);
  SH_FREE(tmp);
  if (ListWithDelimiter == S_TRUE)
    putchar(',');

  if ('l' == p->theFile.c_mode[0])
    {
      tmp = sh_util_safe_name(p->linkpath);
      if (ListWithDelimiter == S_TRUE)
      printf(_(" %s\n"), tmp);
      else
      printf(_(" -> %s\n"), tmp);
      SH_FREE(tmp);
    }
  else
    printf("\n");

  return;
}

void sh_hash_list_db_entry (sh_file_t * p)
{
  char nowtime[128];
  char thetime[128];
  char * tmp;
  time_t now  = time(NULL);
  time_t then = (time_t) p->theFile.mtime;

  strftime(thetime, 127, _("%b %d  %Y"), gmtime(&then));
  strftime(nowtime, 127, _("%b %d  %Y"), gmtime(&now));
  if (0 == strncmp(&nowtime[7], &thetime[7], 4))
    strftime(thetime, 127, _("%b %d %H:%M"), gmtime(&then));

  tmp = sh_util_safe_name(p->fullpath);
  if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
    printf(_("%10s %3d %-8s %-8s %3d,%4d %s %s"),
         p->theFile.c_mode, (int) p->theFile.hardlinks,
         p->theFile.c_owner, p->theFile.c_group, 
         (int) major((dev_t)p->theFile.rdev), 
         (int) minor((dev_t)p->theFile.rdev),
         thetime, 
         tmp);
  else
    printf(_("%10s %3d %-8s %-8s %8ld %s %s"),
         p->theFile.c_mode, (int) p->theFile.hardlinks,
         p->theFile.c_owner, p->theFile.c_group, (long) p->theFile.size,
         thetime, 
         tmp);
  SH_FREE(tmp);

  if ('l' == p->theFile.c_mode[0])
    {
      tmp = sh_util_safe_name(p->linkpath);
      printf(_(" -> %s\n"), tmp);
      SH_FREE(tmp);
    }
  else
    printf("\n");
        
  return;
}

int sh_hash_list_db (char * db_file)
{
  sh_file_t * p;
  SL_TICKET fd;
  char * line;

  if (!db_file)
    {
      _exit(EXIT_FAILURE);
      return -1; 
    }
  if (sl_is_suid())
    {
      fprintf(stderr, _("ERROR: insufficient privilege\n"));
      _exit (EXIT_FAILURE);
      return -1; /* for Mac OSX compiler */
    }
  if (0 == strcmp(db_file, _("default")))
    db_file = file_path('D', 'W');
  if (!db_file)
    {
      _exit(EXIT_FAILURE);
      return -1; 
    }

  line = SH_ALLOC(MAX_PATH_STORE+1);

  if ( SL_ISERROR(fd = sl_open_read(db_file, SL_YESPRIV))) 
    {
      fprintf(stderr, _("ERROR: can't open %s for read\n"), db_file);
      _exit(EXIT_FAILURE);
      return -1; 
    }

  /* fast forward to start of data
   */
  sh_hash_setdataent(fd, line, MAX_PATH_STORE, db_file);

  while (1) 
    {
      p = sh_hash_getdataent (fd, line, MAX_PATH_STORE);
      if ((p != NULL) && (p->fullpath[0] != 'K'))
      {
        if (ListFullDetail == S_FALSE)
          sh_hash_list_db_entry (p); 
        else
          sh_hash_list_db_entry_full_detail (p); 
      }
      else if (p == NULL)
      {
        break;
      }
    }

  if (line != NULL)
    SH_FREE(line);
  sl_close (fd);

  fflush(NULL);

  _exit(EXIT_SUCCESS);
  return 0; 
}

/* if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
#endif

Generated by  Doxygen 1.6.0   Back to index