source: trunk/src/sh_hash.c @ 481

Last change on this file since 481 was 481, checked in by katerina, 6 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 78.0 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 1999, 2000, 2001, 2002 Rainer Wichmann                    */
3/*                                                                         */
4/*  This program is free software; you can redistribute it                 */
5/*  and/or modify                                                          */
6/*  it under the terms of the GNU General Public License as                */
7/*  published by                                                           */
8/*  the Free Software Foundation; either version 2 of the License, or      */
9/*  (at your option) any later version.                                    */
10/*                                                                         */
11/*  This program is distributed in the hope that it will be useful,        */
12/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
13/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
14/*  GNU General Public License for more details.                           */
15/*                                                                         */
16/*  You should have received a copy of the GNU General Public License      */
17/*  along with this program; if not, write to the Free Software            */
18/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
19
20#include "config_xor.h"
21
22#include <stdlib.h>
23#include <string.h>
24#include <stdio.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <unistd.h>
28#include <ctype.h>
29
30#ifdef MAJOR_IN_MKDEV
31#include <sys/mkdev.h>
32#else
33#ifdef MAJOR_IN_SYSMACROS
34#include <sys/sysmacros.h>
35#endif
36#endif
37
38#ifdef HAVE_MEMORY_H
39#include <memory.h>
40#endif
41
42
43#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
44
45#include "samhain.h"
46#include "sh_utils.h"
47#include "sh_unix.h"
48#include "sh_dbIO_int.h"
49#include "sh_dbIO.h"
50#include "sh_hash.h"
51#include "sh_error.h"
52#include "sh_tiger.h"
53#include "sh_gpg.h"
54#include "sh_unix.h"
55#include "sh_files.h"
56#include "sh_ignore.h"
57#include "sh_pthread.h"
58
59#if defined(SH_WITH_CLIENT)
60#include "sh_xfer.h"
61#endif
62
63
64#define SH_KEY_NULL _("000000000000000000000000000000000000000000000000")
65
66
67#undef  FIL__
68#define FIL__  _("sh_hash.c")
69
70SH_MUTEX_INIT(mutex_hash,PTHREAD_MUTEX_INITIALIZER);
71
72static char * all_items (file_type * theFile, char * fileHash, int is_new);
73
74static const char  *policy[] = {
75  N_("[]"),
76  N_("[ReadOnly]"),
77  N_("[LogFiles]"),
78  N_("[GrowingLogs]"),
79  N_("[IgnoreNone]"),
80  N_("[IgnoreAll]"),
81  N_("[Attributes]"),
82  N_("[User0]"),
83  N_("[User1]"),
84  N_("[User2]"),
85  N_("[User3]"),
86  N_("[User4]"),
87  N_("[Prelink]"),
88  NULL
89};
90
91static int report_checkflags = S_FALSE;
92int set_report_checkflags(const char * c)
93{
94  return sh_util_flagval(c, &report_checkflags);
95}
96int get_report_checkflags()
97{
98  return report_checkflags;
99}
100
101
102
103const char * sh_hash_getpolicy(int class)
104{
105  if (class > 0 && class < SH_ERR_T_DIR)
106    return _(policy[class]);
107  return _("[indef]");
108}
109
110/**********************************
111 *
112 * hash table functions
113 *
114 **********************************
115 */
116
117#include "sh_hash.h"
118
119
120/**************************************************************
121 *
122 * create a file_type from a sh_file_t
123 *
124 **************************************************************/
125file_type * sh_hash_create_ft (const sh_file_t * p, char * fileHash)
126{
127  file_type * theFile;
128
129  SL_ENTER(_("sh_hash_create_ft"));
130
131  theFile = SH_ALLOC(sizeof(file_type));
132
133  sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11);
134  theFile->mode  =  p->theFile.mode;
135#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
136  sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, ATTRBUF_SIZE);
137  theFile->attributes =  p->theFile.attributes;
138#endif
139
140  sl_strlcpy(theFile->fullpath, p->fullpath, PATH_MAX);
141  if (p->linkpath != NULL /* && theFile->c_mode[0] == 'l' */)
142    {
143      theFile->link_path = sh_util_strdup(p->linkpath);
144    }
145  else
146    {
147      theFile->link_path = NULL;
148    }
149  sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
150 
151  theFile->mtime =  p->theFile.mtime;
152  theFile->ctime =  p->theFile.ctime;
153  theFile->atime =  p->theFile.atime;
154 
155  theFile->size  =  p->theFile.size;
156 
157  sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2);
158  theFile->group =  p->theFile.group;
159  sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2);
160  theFile->owner =  p->theFile.owner;
161 
162  theFile->ino   =  p->theFile.ino;
163  theFile->rdev  =  p->theFile.rdev;
164  theFile->dev   =  p->theFile.dev;
165  theFile->hardlinks = p->theFile.hardlinks;
166  theFile->check_flags = p->theFile.checkflags;
167
168  if (p->attr_string)
169    theFile->attr_string = sh_util_strdup(p->attr_string);
170  else
171    theFile->attr_string = NULL;
172
173  SL_RETURN((theFile), _("sh_hash_create_ft"));
174}
175
176struct two_sh_file_t {
177  sh_file_t * prev;
178  sh_file_t * this;
179};
180
181static sh_file_t * hashsearch (const char * s);
182static int hashsearch_prev (const char * s, struct two_sh_file_t * a, int * index); 
183
184
185/**************************************************************
186 *
187 * >>>> The internal database <<<
188 *
189 **************************************************************/
190
191static sh_file_t * tab[TABSIZE];
192
193sh_file_t ** get_default_data_table()
194{
195  return tab;
196}
197
198/**************************************************************
199 *
200 * compute hash function
201 *
202 **************************************************************/
203
204static int hashfunc(const char *s) 
205{
206  unsigned int n = 0; 
207
208  for ( ; *s; s++) 
209    n = 31 * n + *s; 
210
211  return n & (TABSIZE - 1); /* % TABSIZE */; 
212} 
213
214
215int hashreport_missing( char *fullpath, int level)
216{
217  sh_file_t * p;
218  char * tmp;
219  char   fileHash[KEY_LEN + 1];
220  file_type * theFile;
221  char * str;
222  char hashbuf[KEYBUF_SIZE];
223  volatile int  retval;
224
225  /* --------  find the entry for the file ----------------       */
226
227  SH_MUTEX_LOCK(mutex_hash);
228
229  retval = 0;
230
231  if (sl_strlen(fullpath) <= MAX_PATH_STORE) 
232    p = hashsearch(fullpath);
233  else 
234    p = hashsearch( sh_tiger_hash(fullpath, 
235                                  TIGER_DATA, 
236                                  sl_strlen(fullpath),
237                                  hashbuf, sizeof(hashbuf))
238                    );
239  if (p == NULL)
240    {
241      retval = -1;
242      goto unlock_and_return;
243    }
244
245  theFile = sh_hash_create_ft (p, fileHash);
246  str = all_items(theFile, fileHash, 0);
247  tmp = sh_util_safe_name(fullpath);
248
249  SH_MUTEX_LOCK(mutex_thread_nolog);
250  sh_error_handle (level, FIL__, __LINE__, 0, 
251                   MSG_FI_MISS2, tmp, str);
252  SH_MUTEX_UNLOCK(mutex_thread_nolog);
253  ++sh.statistics.files_report;
254
255  SH_FREE(tmp);
256  SH_FREE(str);
257  if (theFile->attr_string) SH_FREE(theFile->attr_string);
258  if (theFile->link_path)   SH_FREE(theFile->link_path);
259  SH_FREE(theFile);
260
261 unlock_and_return:
262  ; /* 'label at end of compound statement */
263  SH_MUTEX_UNLOCK(mutex_hash);
264
265  /* remove here to avoid second message from hash_unvisited */
266  if (retval == 0)
267    sh_hash_remove (fullpath);
268
269  return retval;
270}
271
272
273/**************************************************************
274 *
275 * search for files not visited, and check whether they exist
276 *
277 **************************************************************/
278static sh_file_t * delete_db_entry(sh_file_t *p)
279{
280  if (p->fullpath)
281    {
282      SH_FREE(p->fullpath);
283      p->fullpath = NULL;
284    }
285  if (p->linkpath)
286    {
287      SH_FREE(p->linkpath);
288      p->linkpath = NULL;
289    }
290  if (p->attr_string)
291    {
292      SH_FREE(p->attr_string);
293      p->attr_string = NULL;
294    }
295  SH_FREE(p);
296  return NULL;
297}
298
299static void hash_unvisited (int j, 
300                            sh_file_t *prev, sh_file_t *p, ShErrLevel level)
301{
302  struct stat buf;
303  int i;
304  char * tmp;
305  char * ptr;
306  char   fileHash[KEY_LEN + 1];
307  file_type * theFile;
308  char * str;
309
310  SL_ENTER(_("hash_unvisited"));
311
312  if (p->next != NULL)
313    hash_unvisited (j, p, p->next, level);
314
315  if (p->fullpath == NULL)
316    {
317      SL_RET0(_("hash_unvisited"));
318    }
319
320  /* Not a fully qualified path, i.e. some info stored by some module
321   */
322  if (p->fullpath[0] != '/')
323    {
324      SL_RET0(_("hash_unvisited"));
325    }
326
327  /* visited   flag not set: not seen;
328   * checked   flag     set: not seen (i.e. missing), and already checked
329   * reported  flag not set: not reported yet
330   * allignore flag not set: not under IgnoreAll
331   *
332   * Files/directories under IgnoreAll are noticed as missing already
333   * during the file check.
334   */
335  if (((!SH_FFLAG_VISITED_SET(p->fflags)) || SH_FFLAG_CHECKED_SET(p->fflags)) 
336      && (!SH_FFLAG_REPORTED_SET(p->fflags))
337      /* && (!SH_FFLAG_ALLIGNORE_SET(p->fflags)) */)
338    {
339      i = retry_lstat(FIL__, __LINE__, p->fullpath, &buf);
340
341     /* if file does not exist
342       */
343      if (0 != i)
344        {
345          ptr = sh_util_dirname (p->fullpath);
346          if (ptr)
347            {
348              /* If any of the parent directories is under IgnoreAll
349               */
350              if ((0 != sh_files_is_allignore(ptr)) || SH_FFLAG_ALLIGNORE_SET(p->fflags))
351                level = ShDFLevel[SH_LEVEL_ALLIGNORE];
352              SH_FREE(ptr);
353            }
354
355          /* Only report if !SH_FFLAG_CHECKED_SET
356           */
357          if (!SH_FFLAG_CHECKED_SET(p->fflags))
358            {
359              if (S_FALSE == sh_ignore_chk_del(p->fullpath))
360                {
361                  tmp = sh_util_safe_name(p->fullpath);
362
363                  theFile = sh_hash_create_ft (p, fileHash);
364                  str = all_items(theFile, fileHash, 0);
365                  sh_error_handle (level, FIL__, __LINE__, 0, 
366                                   MSG_FI_MISS2, tmp, str);
367                  ++sh.statistics.files_report;
368                  SH_FREE(str);
369                  if (theFile->attr_string) SH_FREE(theFile->attr_string);
370                  if (theFile->link_path)   SH_FREE(theFile->link_path);
371                  SH_FREE(theFile);
372
373                  SH_FREE(tmp);
374                }
375            }
376
377          /* We rewrite the db on update, thus we need to keep this
378           * if the user does not want to purge it from the db.
379           */
380
381          if ((sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) || 
382              (S_TRUE == sh.flag.update && S_TRUE == sh_util_ask_update(p->fullpath)))
383            {
384              /* Remove the old entry
385               */
386              if (prev == p)
387                tab[j] = p->next;
388              else
389                prev->next = p->next;
390
391              delete_db_entry(p);
392
393              SL_RET0(_("hash_unvisited"));
394            }
395        }
396    }
397
398  else if (SH_FFLAG_VISITED_SET(p->fflags) && SH_FFLAG_REPORTED_SET(p->fflags) 
399           && (!SH_FFLAG_ALLIGNORE_SET(p->fflags)))
400    {
401      if (S_FALSE == sh_ignore_chk_new(p->fullpath))
402        {
403          tmp = sh_util_safe_name(p->fullpath);
404
405          theFile = sh_hash_create_ft (p, fileHash);
406          str = all_items(theFile, fileHash, 0);
407          sh_error_handle (level, FIL__, __LINE__, 0, 
408                           MSG_FI_MISS2, tmp, str);
409          ++sh.statistics.files_report;
410          SH_FREE(str);
411          if (theFile->attr_string)
412            SH_FREE(theFile->attr_string);
413          SH_FREE(theFile);
414
415          SH_FREE(tmp);
416        }
417
418      CLEAR_SH_FFLAG_REPORTED(p->fflags);
419    }
420
421  if (sh.flag.reportonce == S_FALSE)
422    CLEAR_SH_FFLAG_REPORTED(p->fflags);
423
424  CLEAR_SH_FFLAG_VISITED(p->fflags);
425  CLEAR_SH_FFLAG_CHECKED(p->fflags);
426  SET_SH_FFLAG_ENOENT(p->fflags);
427
428  SL_RET0(_("hash_unvisited"));
429}
430
431
432
433/*********************************************************************
434 *
435 * Search for files in the database that have been deleted from disk.
436 *
437 *********************************************************************/
438void sh_hash_unvisited (ShErrLevel level)
439{
440  int i;
441
442  SL_ENTER(_("sh_hash_unvisited"));
443
444  SH_MUTEX_LOCK(mutex_hash);
445  for (i = 0; i < TABSIZE; ++i)
446    {
447      if (tab[i] != NULL) 
448        hash_unvisited (i, tab[i], tab[i], level);
449    }
450  SH_MUTEX_UNLOCK(mutex_hash);
451
452  SL_RET0(_("hash_unvisited"));
453}
454
455/*********************************************************************
456 *
457 * Remove a single file from the database.
458 *
459 *********************************************************************/
460void sh_hash_remove_unconditional (const char * path)
461{
462  struct two_sh_file_t entries;
463  int index;
464
465  SL_ENTER(_("sh_hash_remove_unconditional"));
466
467  SH_MUTEX_LOCK(mutex_hash);
468  if (0 == hashsearch_prev (path, &entries, &index))
469    {
470      sh_file_t * p = entries.this;
471     
472      /* Remove the old entry
473       */
474      if (entries.prev == p)
475        tab[index] = p->next;
476      else
477        entries.prev->next = p->next;
478     
479      delete_db_entry(p);
480    }
481  SH_MUTEX_UNLOCK(mutex_hash);
482
483  SL_RET0(_("sh_hash_remove_unconditional"));
484}
485
486void sh_hash_remove (const char * path)
487{
488  SL_ENTER(_("sh_hash_remove"));
489
490  if ((sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) || 
491      (S_TRUE == sh.flag.update && S_TRUE == sh_util_ask_update(path)))
492    {
493      sh_hash_remove_unconditional (path);
494    }
495  SL_RET0(_("sh_hash_remove"));
496}
497
498
499/*********************************************************************
500 *
501 * Search for unvisited entries in the database, custom error handler.
502 *
503 *********************************************************************/
504void sh_hash_unvisited_custom (char prefix, void(*handler)(const char * key))
505{
506  int i;
507  sh_file_t *p    = NULL;
508  sh_file_t *prev = NULL;
509  sh_file_t *next = NULL;
510
511  SL_ENTER(_("sh_hash_unvisited_custom"));
512
513  SH_MUTEX_LOCK(mutex_hash);
514  for (i = 0; i < TABSIZE; ++i)
515    {
516      if (tab[i] != NULL)
517        {
518          p = tab[i]; prev = p;
519
520          do 
521            {
522              next = p->next;
523
524              if (p->fullpath && 
525                  prefix == p->fullpath[0])
526                {
527                  if ((!SH_FFLAG_VISITED_SET(p->fflags)) 
528                      && (!SH_FFLAG_REPORTED_SET(p->fflags)))
529                    {
530                      handler(p->fullpath);
531
532                      if (!SH_FFLAG_CHECKED_SET(p->fflags))
533                        {
534                          /* delete */
535                          if (tab[i] == p)
536                            {
537                              tab[i] = p->next;
538                              prev   = tab[i];
539                              next   = prev;
540                            }
541                          else
542                            {
543                              prev->next = p->next;
544                              next       = prev->next;
545                            }
546
547                          p = delete_db_entry(p);
548                        }
549                    }
550                  if (p)
551                    {
552                      CLEAR_SH_FFLAG_VISITED(p->fflags);
553                      CLEAR_SH_FFLAG_CHECKED(p->fflags);
554                    }
555                }
556              if (p)
557                prev = p;
558              p    = next;
559            } 
560          while (p);
561        }
562    }
563  SH_MUTEX_UNLOCK(mutex_hash);
564
565  SL_RET0(_("hash_unvisited_custom"));
566}
567
568
569/**********************************************************************
570 *
571 * delete hash array
572 *
573 **********************************************************************/
574static void hash_kill (sh_file_t *p)
575{
576  SL_ENTER(_("hash_kill"));
577
578  if (p == NULL)
579    SL_RET0(_("hash_kill"));
580
581  if (p->next != NULL)
582    hash_kill (p->next);
583
584  if (p->fullpath)
585    {
586      SH_FREE(p->fullpath);
587      p->fullpath = NULL;
588    }
589  if (p->linkpath)
590    {
591      SH_FREE(p->linkpath);
592      p->linkpath = NULL;
593    }
594  if (p->attr_string)
595    {
596      SH_FREE(p->attr_string);
597      p->attr_string = NULL;
598    }
599  SH_FREE(p);
600  p = NULL;
601  SL_RET0(_("hash_kill"));
602}
603
604
605/***********************************************************************
606 *
607 * get info out of hash array
608 *
609 ***********************************************************************/
610static sh_file_t * hashsearch (const char * s) 
611{
612  sh_file_t * p;
613
614  SL_ENTER(_("hashsearch"));
615
616  if (s)
617    {
618      for (p = tab[hashfunc(s)]; p; p = p->next)
619        if ((p->fullpath != NULL) && (0 == strcmp(s, p->fullpath))) 
620          SL_RETURN( p, _("hashsearch"));
621    } 
622  SL_RETURN( NULL, _("hashsearch"));
623} 
624
625static int hashsearch_prev (const char * s, struct two_sh_file_t * a, int * index) 
626{
627  sh_file_t * this;
628  sh_file_t * prev = NULL;
629
630  SL_ENTER(_("hashsearch_prev"));
631
632  if (s)
633    {
634      *index = hashfunc(s);
635      this   = tab[*index];
636      prev   = this;
637
638      if (this)
639        {
640          do {
641            if ((this->fullpath != NULL) && (0 == strcmp(s, this->fullpath)))
642              {
643                a->prev = prev;
644                a->this = this; 
645                SL_RETURN( 0, _("hashsearch_prev"));
646              }
647            prev = this;
648            this = this->next;
649          } while(this);
650        } 
651    }
652  SL_RETURN( -1, _("hashsearch"));
653} 
654
655
656/***********************************************************************
657 *
658 * insert into hash array
659 *
660 ***********************************************************************/
661void hashinsert (sh_file_t * mtab[TABSIZE], sh_file_t * s) 
662{
663  sh_file_t * p;
664  sh_file_t * q;
665  int key;
666
667  SL_ENTER(_("hashinsert"));
668
669  key = hashfunc(s->fullpath);
670
671  if (mtab[key] == NULL) 
672    {
673      mtab[key] = s;
674      mtab[key]->next = NULL;
675      SL_RET0(_("hashinsert"));
676    } 
677  else 
678    {
679      p = mtab[key];
680      while (1) 
681        {
682          if (p && p->fullpath && 0 == strcmp(s->fullpath, p->fullpath))
683            {
684              q = p->next;
685              SH_FREE(p->fullpath);
686              if(p->linkpath)    SH_FREE(p->linkpath);
687              if(p->attr_string) SH_FREE(p->attr_string);
688              memcpy(p, s, sizeof(sh_file_t));
689              p->next = q;
690              SH_FREE(s); s = NULL;
691              SL_RET0(_("hashinsert"));
692            }
693          else if (p && p->next == NULL) 
694            {
695              p->next = s;
696              p->next->next = NULL;
697              SL_RET0(_("hashinsert"));
698            }
699          if (p)
700            p = p->next;
701          else /* cannot really happen, but llvm/clang does not know */
702            break;
703        }
704    }
705  /* notreached */
706}
707
708
709
710/******************************************************************
711 *
712 * ------- Check functions -------
713 *
714 ******************************************************************/
715
716static int IsInit = 0;
717
718void sh_hash_set_initialized()
719{
720  IsInit = 1;
721  return;
722}
723
724int sh_hash_get_initialized()
725{
726  return IsInit;
727}
728
729
730/******************************************************************
731 *
732 * Initialize
733 *
734 ******************************************************************/
735void sh_hash_init ()
736{
737  volatile int  retval  = 0;
738  volatile int  exitval = EXIT_SUCCESS;
739
740  SL_ENTER(_("sh_hash_init"));
741
742  if ( sh.flag.checkSum == SH_CHECK_INIT )
743    {
744      dlog(1, FIL__, __LINE__, 
745           _("Attempt to load the baseline database during initialisation. This is an internal error, please report it to the developer.\n"));
746      SH_ABORT;
747      aud_exit (FIL__, __LINE__, EXIT_FAILURE);
748    }
749
750  SH_MUTEX_LOCK(mutex_hash);
751
752  if (IsInit == 1)
753    { 
754      goto unlock_and_return;
755    }
756
757  /* Initialization completed.
758   */
759  retval = sh_dbIO_load_db(tab);
760
761  if (0 == retval)
762    IsInit = 1;
763  else
764    exitval = EXIT_FAILURE;
765
766 unlock_and_return:
767  ; /* 'label at end of compound statement */
768  SH_MUTEX_UNLOCK(mutex_hash);
769  if (retval == 0)
770    {
771      SL_RET0(_("sh_hash_init"));
772    }
773  sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1, sh.prg_name);
774  aud_exit (FIL__, __LINE__, exitval);
775}
776
777void sh_hash_init_and_checksum()
778{
779  TPT((0, FIL__, __LINE__, _("msg=<Get checksum of the database.>\n")))
780  if (sh.flag.checkSum == SH_CHECK_CHECK) 
781    {
782      if (0 != sl_strcmp(file_path('D', 'R'), _("REQ_FROM_SERVER")))
783        {
784          char hashbuf[KEYBUF_SIZE];
785          (void) sl_strlcpy(sh.data.hash,
786                            sh_tiger_hash (file_path('D', 'R'), 
787                                           TIGER_FILE, TIGER_NOLIM, 
788                                           hashbuf, sizeof(hashbuf)), 
789                            KEY_LEN+1);
790        }
791
792      /* this eventually fetches the file from server to get checksum
793       */
794      sh_hash_init ();
795    }
796  return;
797}
798 
799/*****************************************************************
800 *
801 * delete hash array
802 *
803 *****************************************************************/
804void sh_hash_hashdelete ()
805{
806  int i;
807
808  SL_ENTER(_("sh_hash_hashdelete"));
809
810  /* need deadlock detection here if called from exit handler
811   */
812  SH_MUTEX_TRYLOCK(mutex_hash);
813
814  if (IsInit == 0) 
815    goto unlock_and_exit;
816
817  for (i = 0; i < TABSIZE; ++i) 
818    if (tab[i] != NULL)
819      { 
820        hash_kill (tab[i]);
821        tab[i] = NULL;
822      }
823  IsInit = 0;
824
825 unlock_and_exit:
826  ; /* 'label at end of compound statement */
827  SH_MUTEX_TRYLOCK_UNLOCK(mutex_hash);
828
829  SL_RET0(_("sh_hash_hashdelete"));
830}
831
832static int sh_loosedircheck = S_FALSE;
833
834int sh_hash_loosedircheck(const char * str)
835{
836  return sh_util_flagval(str, &sh_loosedircheck);
837}
838
839
840
841
842/*********************************************************************
843 *
844 * Check whether a file is present in the database.
845 *
846 *********************************************************************/
847static sh_file_t *  sh_hash_have_it_int (const char * newname)
848{
849  sh_file_t * p;
850  char hashbuf[KEYBUF_SIZE];
851
852  SL_ENTER(_("sh_hash_have_it_int"));
853
854  if (newname == NULL)
855    SL_RETURN( (NULL), _("sh_hash_have_it_int"));
856
857  if (sl_strlen(newname) <= MAX_PATH_STORE) 
858    p = hashsearch(newname);
859  else 
860    p = hashsearch ( sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname),
861                                   hashbuf, sizeof(hashbuf)) );
862  if (p == NULL) 
863     SL_RETURN( (NULL), _("sh_hash_have_it_int"));
864
865  SL_RETURN( (p), _("sh_hash_have_it_int"));
866}
867
868int sh_hash_have_it (const char * newname)
869{
870  sh_file_t * p;
871  int retval;
872
873  if (IsInit != 1) 
874    sh_hash_init();
875
876  SH_MUTEX_LOCK(mutex_hash);
877
878  retval = 0;
879
880  p = sh_hash_have_it_int (newname);
881
882  if (!p) 
883    retval = (-1);
884  else if ((!SH_FFLAG_ALLIGNORE_SET(p->fflags)) && 
885           (p->modi_mask & MODI_CHK) != 0 &&
886           (p->modi_mask & MODI_MOD) != 0)
887    retval = 1;
888  SH_MUTEX_UNLOCK(mutex_hash);
889
890  return retval;
891}
892
893int sh_hash_get_it (const char * newname, file_type * tmpFile, char * fileHash)
894{
895  sh_file_t * p;
896  int retval;
897
898  if (IsInit != 1) 
899    sh_hash_init();
900
901  tmpFile->link_path   = NULL;
902  tmpFile->attr_string = NULL;
903
904  SH_MUTEX_LOCK(mutex_hash);
905
906  retval = (-1);
907
908  p = sh_hash_have_it_int (newname);
909  if (p)
910    {
911      sl_strlcpy(tmpFile->fullpath,  p->fullpath, PATH_MAX);
912      if (p->linkpath)
913        tmpFile->link_path = sh_util_strdup (p->linkpath);
914      tmpFile->size  = p->theFile.size;
915      tmpFile->mtime = p->theFile.mtime;
916      tmpFile->ctime = p->theFile.ctime;
917      tmpFile->atime = p->theFile.atime;
918
919      if (NULL != fileHash)
920        sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
921
922      tmpFile->attr_string = NULL;
923      retval = 0;
924    }
925  SH_MUTEX_UNLOCK(mutex_hash);
926
927  return retval;
928}
929
930int sh_hash_getflags (char * filename)
931{
932  sh_file_t * p;
933  int retval = 0;
934
935  if ( sh.flag.checkSum != SH_CHECK_INIT )
936    {
937      if (IsInit != 1) 
938        sh_hash_init();
939     
940      SH_MUTEX_LOCK(mutex_hash);
941      p = sh_hash_have_it_int (filename);
942      if (p)
943        retval = p->fflags;
944      else
945        retval = -1;
946      SH_MUTEX_UNLOCK(mutex_hash);
947    }
948  return retval;
949}
950
951int sh_hash_setflags (char * filename, int flags)
952{
953  sh_file_t * p;
954  int retval = 0;
955
956  if ( sh.flag.checkSum != SH_CHECK_INIT )
957    {
958      if (IsInit != 1) 
959        sh_hash_init();
960     
961      SH_MUTEX_LOCK(mutex_hash);
962      p = sh_hash_have_it_int (filename);
963      if (p)
964        {
965          p->fflags = flags;
966          retval = 0;
967        }
968      else
969        retval = -1;
970      SH_MUTEX_UNLOCK(mutex_hash);
971    }
972  return retval;
973}
974
975/* needs lock to be threadsafe
976 */
977void sh_hash_set_flag (char * filename, int flag_to_set)
978{
979  sh_file_t * p;
980
981  if ( sh.flag.checkSum != SH_CHECK_INIT )
982    {
983      if (IsInit != 1) 
984        sh_hash_init();
985     
986      SH_MUTEX_LOCK(mutex_hash);
987      p = sh_hash_have_it_int (filename);
988      if (p)
989        {
990          p->fflags |= flag_to_set;
991        }
992      SH_MUTEX_UNLOCK(mutex_hash);
993    }
994  return;
995}
996
997/* needs lock to be threadsafe
998 */
999void sh_hash_clear_flag (char * filename, int flag_to_clear)
1000{
1001  sh_file_t * p;
1002
1003  if ( sh.flag.checkSum != SH_CHECK_INIT )
1004    {
1005      if (IsInit != 1) 
1006        sh_hash_init();
1007     
1008      SH_MUTEX_LOCK(mutex_hash);
1009      p = sh_hash_have_it_int (filename);
1010      if (p)
1011        {
1012          p->fflags &= ~flag_to_clear;
1013        }
1014      SH_MUTEX_UNLOCK(mutex_hash);
1015    }
1016  return;
1017}
1018
1019
1020/*****************************************************************
1021 *
1022 * Set a file's status to 'visited'. This is required for
1023 * files that should be ignored, and may be present in the
1024 * database, but not on disk.
1025 *
1026 *****************************************************************/
1027static int sh_hash_set_visited_int (char * newname, int flag)
1028{
1029  sh_file_t * p;
1030  char hashbuf[KEYBUF_SIZE];
1031  int  retval;
1032
1033  SL_ENTER(_("sh_hash_set_visited_int"));
1034
1035  if (newname == NULL)
1036    SL_RETURN((-1), _("sh_hash_set_visited_int"));
1037
1038  if (IsInit != 1) 
1039    sh_hash_init();
1040
1041  SH_MUTEX_LOCK(mutex_hash);
1042
1043  if (sl_strlen(newname) <= MAX_PATH_STORE) 
1044    p = hashsearch(newname);
1045  else 
1046    p = hashsearch (sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname),
1047                                  hashbuf, sizeof(hashbuf)));
1048 
1049  if (p)
1050    {
1051      if (flag == SH_FFLAG_CHECKED)
1052        {
1053          CLEAR_SH_FFLAG_REPORTED(p->fflags);
1054          CLEAR_SH_FFLAG_VISITED(p->fflags);
1055          SET_SH_FFLAG_CHECKED(p->fflags);
1056        }
1057      else
1058        {
1059          SET_SH_FFLAG_VISITED(p->fflags);
1060          CLEAR_SH_FFLAG_CHECKED(p->fflags);
1061          if (flag == SH_FFLAG_REPORTED)
1062            SET_SH_FFLAG_REPORTED(p->fflags);
1063          else
1064            CLEAR_SH_FFLAG_REPORTED(p->fflags);
1065        }
1066      retval = 0;
1067    }
1068  else
1069    retval = -1;
1070
1071  SH_MUTEX_UNLOCK(mutex_hash);
1072  SL_RETURN((retval), _("sh_hash_set_visited_int"));
1073}
1074
1075
1076/* cause the record to be deleted without a 'missing' message
1077 */
1078int sh_hash_set_missing (char * newname)
1079{
1080  int i;
1081  SL_ENTER(_("sh_hash_set_missing"));
1082
1083  i = sh_hash_set_visited_int(newname, SH_FFLAG_CHECKED);
1084
1085  if (sh.flag.checkSum != SH_CHECK_INIT) {
1086    sh_hash_remove(newname);
1087  }
1088
1089  SL_RETURN(i, _("sh_hash_set_missing"));
1090}
1091
1092/* mark the file as visited and reported
1093 */
1094int sh_hash_set_visited (char * newname)
1095{
1096  int i;
1097  SL_ENTER(_("sh_hash_set_visited"));
1098  i = sh_hash_set_visited_int(newname, SH_FFLAG_REPORTED);
1099  SL_RETURN(i, _("sh_hash_set_visited"));
1100}
1101
1102/* mark the file as visited and NOT reported
1103 * used to avoid deletion of file from internal database
1104 */
1105int sh_hash_set_visited_true (char * newname)
1106{
1107  int i;
1108  SL_ENTER(_("sh_hash_set_visited_true"));
1109  i = sh_hash_set_visited_int(newname, 0);
1110  SL_RETURN(i, _("sh_hash_set_visited_true"));
1111}
1112
1113
1114/******************************************************************
1115 *
1116 * Data entry for arbitrary data into database
1117 *
1118 ******************************************************************/
1119
1120void sh_hash_push2db (const char * key, struct store2db * save)
1121{
1122  int         i = 0;
1123  char      * p;
1124  char        i2h[2];
1125  file_type * tmpFile = SH_ALLOC(sizeof(file_type));
1126
1127  int size            = save->size;
1128  unsigned char * str = save->str;
1129
1130
1131  tmpFile->attr_string = NULL;
1132  tmpFile->link_path   = NULL;
1133
1134  sl_strlcpy(tmpFile->fullpath, key, PATH_MAX);
1135  tmpFile->size  = save->val0;
1136  tmpFile->mtime = save->val1;
1137  tmpFile->ctime = save->val2;
1138  tmpFile->atime = save->val3;
1139
1140  tmpFile->mode  = 0;
1141  tmpFile->owner = 0;
1142  tmpFile->group = 0;
1143  sl_strlcpy(tmpFile->c_owner, _("root"), 5);
1144  sl_strlcpy(tmpFile->c_group, _("root"), 5);
1145
1146  tmpFile->check_flags = 0;
1147
1148  if ((str != NULL) && (size < (PATH_MAX/2)-1))
1149    {
1150      tmpFile->c_mode[0] = 'l'; 
1151      tmpFile->c_mode[1] = 'r'; tmpFile->c_mode[2]  = 'w';
1152      tmpFile->c_mode[3] = 'x'; tmpFile->c_mode[4]  = 'r'; 
1153      tmpFile->c_mode[5] = 'w'; tmpFile->c_mode[6]  = 'x'; 
1154      tmpFile->c_mode[7] = 'r'; tmpFile->c_mode[8]  = 'w'; 
1155      tmpFile->c_mode[9] = 'x'; tmpFile->c_mode[10] = '\0';
1156      tmpFile->link_path = SH_ALLOC((size * 2) + 2);
1157      for (i = 0; i < size; ++i)
1158        {
1159          p = sh_util_charhex (str[i],i2h);
1160          tmpFile->link_path[2*i]   = p[0];
1161          tmpFile->link_path[2*i+1] = p[1];
1162          tmpFile->link_path[2*i+2] = '\0';
1163        }
1164    }
1165  else
1166    {
1167      for (i = 0; i < 10; ++i) 
1168        tmpFile->c_mode[i] = '-';
1169      tmpFile->c_mode[10] = '\0';
1170      tmpFile->link_path = sh_util_strdup("-");
1171    }
1172
1173  if (sh.flag.checkSum == SH_CHECK_INIT)
1174    sh_dbIO_data_write (tmpFile, 
1175                        (save->checksum[0] == '\0') ? SH_KEY_NULL : save->checksum);
1176  else
1177    sh_hash_pushdata_memory (tmpFile, 
1178                             (save->checksum[0] == '\0') ? SH_KEY_NULL : save->checksum);
1179
1180  if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
1181  SH_FREE(tmpFile);
1182  return;
1183}
1184
1185extern int sh_util_hextobinary (char * binary, char * hex, int bytes);
1186
1187char * sh_hash_db2pop (const char * key, struct store2db * save)
1188{
1189  size_t      len;
1190  char      * p;
1191  int         i;
1192  char      * retval = NULL;
1193  char        fileHash[KEY_LEN+1];
1194  file_type * tmpFile = SH_ALLOC(sizeof(file_type));
1195 
1196  save->size = 0;
1197
1198  if (0 == sh_hash_get_it (key, tmpFile, fileHash))
1199    {
1200      save->val0 = tmpFile->size;
1201      save->val1 = tmpFile->mtime;
1202      save->val2 = tmpFile->ctime;
1203      save->val3 = tmpFile->atime;
1204
1205      sl_strlcpy(save->checksum, fileHash, KEY_LEN+1);
1206
1207      if (tmpFile->link_path && tmpFile->link_path[0] != '-')
1208        {
1209          len = strlen(tmpFile->link_path);
1210
1211          p = SH_ALLOC((len/2)+1);
1212          i = sh_util_hextobinary (p, tmpFile->link_path, len);
1213
1214          if (i == 0)
1215            {
1216              save->size = (len/2);
1217              p[save->size] = '\0';
1218              retval = p;
1219            }
1220          else
1221            {
1222              SH_FREE(p);
1223              save->size = 0;
1224            }
1225        }
1226      else
1227        {
1228          save->size = 0;
1229        }
1230    }
1231  else
1232    {
1233      save->size = -1;
1234      save->val0 = 0;
1235      save->val1 = 0;
1236      save->val2 = 0;
1237      save->val3 = 0;
1238    }
1239  if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
1240  SH_FREE(tmpFile);
1241  return retval;
1242}
1243
1244
1245
1246
1247/******************************************************************
1248 *
1249 * Data entry in hash table
1250 *
1251 ******************************************************************/
1252sh_file_t * sh_hash_push_int (file_type * buf, char * fileHash)
1253{
1254  sh_file_t    * fp;
1255  sh_filestore_t p;
1256
1257  size_t len;
1258  char * fullpath;
1259  char * linkpath;
1260  char * attr_string = NULL;
1261  char hashbuf[KEYBUF_SIZE];
1262
1263  SL_ENTER(_("sh_hash_push_int"));
1264
1265  fp = SH_ALLOC(sizeof(sh_file_t));
1266
1267  p.mark = REC_MAGIC;
1268  if (buf->attr_string)
1269    p.mark |= REC_FLAGS_ATTR;
1270  sl_strlcpy(p.c_mode,   buf->c_mode,   11);
1271  sl_strlcpy(p.c_group,  buf->c_group,  GROUP_MAX+1);
1272  sl_strlcpy(p.c_owner,  buf->c_owner,  USER_MAX+1);
1273  sl_strlcpy(p.checksum, fileHash,      KEY_LEN+1);
1274#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1275  sl_strlcpy(p.c_attributes, buf->c_attributes, 13);
1276#endif
1277
1278#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1279  p.attributes  = (UINT32) buf->attributes;
1280#endif
1281  p.linkmode    = (UINT32) buf->linkmode;
1282  p.hardlinks   = (UINT32) buf->hardlinks;
1283  p.dev   = (UINT64) buf->dev;
1284  p.rdev  = (UINT64) buf->rdev;
1285  p.mode  = (UINT32) buf->mode;
1286  p.ino   = (UINT32) buf->ino;
1287  p.size  = (UINT64) buf->size;
1288  p.mtime = (UINT64) buf->mtime;
1289  p.atime = (UINT64) buf->atime;
1290  p.ctime = (UINT64) buf->ctime;
1291  p.owner = (UINT32) buf->owner;
1292  p.group = (UINT32) buf->group;
1293
1294  p.checkflags = (UINT32) buf->check_flags;
1295
1296  memcpy( &(*fp).theFile, &p, sizeof(sh_filestore_t) );
1297  fp->fflags    = 0;  /* init fflags */
1298  fp->modi_mask = 0L;
1299
1300  if (buf->attr_string)
1301    attr_string = sh_util_strdup(buf->attr_string);
1302  fp->attr_string = attr_string;
1303
1304  len = sl_strlen(buf->fullpath);
1305  if (len <= MAX_PATH_STORE) 
1306    {
1307      fullpath = SH_ALLOC(len+1);
1308      sl_strlcpy(fullpath, buf->fullpath, len+1);
1309    } 
1310  else 
1311    {
1312      fullpath = SH_ALLOC(KEY_LEN + 1);
1313      sl_strlcpy(fullpath, 
1314                 sh_tiger_hash (buf->fullpath, TIGER_DATA, len,
1315                                hashbuf, sizeof(hashbuf)), 
1316                 KEY_LEN+1);
1317    }
1318  fp->fullpath  = fullpath;
1319
1320  if (buf->link_path)
1321    { 
1322      len = sl_strlen(buf->link_path);
1323      if (len <= MAX_PATH_STORE) 
1324        {
1325          linkpath = SH_ALLOC(len+1);
1326          sl_strlcpy(linkpath, buf->link_path, len+1);
1327        } 
1328      else 
1329        {
1330          linkpath = SH_ALLOC(KEY_LEN + 1);
1331          sl_strlcpy(linkpath, 
1332                     sh_tiger_hash (buf->link_path, TIGER_DATA, len,
1333                                    hashbuf, sizeof(hashbuf)), 
1334                     KEY_LEN+1);
1335        }
1336      fp->linkpath  = linkpath;
1337    }
1338  else
1339    fp->linkpath  = NULL;
1340
1341  SL_RETURN( fp, _("sh_hash_push_int"));
1342}
1343
1344#ifdef HAVE_INTTYPES_H
1345#include <inttypes.h>
1346#else
1347#ifdef HAVE_STDINT_H
1348#include <stdint.h>
1349#endif
1350#endif
1351
1352#ifndef PRIu64
1353#ifdef  HAVE_LONG_32
1354#define PRIu64 "llu"
1355#else
1356#define PRIu64 "lu"
1357#endif
1358#endif
1359
1360char * sh_hash_size_format()
1361{
1362  static char form_rval[81];
1363
1364  SL_ENTER(_("sh_hash_size_format"));
1365
1366
1367#ifdef SH_USE_XML
1368  sl_snprintf(form_rval, 80, _("%s%s%s%s%s"), 
1369              _("size_old=\"%"), PRIu64, _("\" size_new=\"%"), PRIu64, "\" ");
1370#else
1371  sl_snprintf(form_rval, 80, _("%s%s%s%s%s"), 
1372              _("size_old=<%"), PRIu64, _(">, size_new=<%"), PRIu64, ">, ");
1373#endif
1374
1375  SL_RETURN( form_rval, _("sh_hash_size_format"));
1376}
1377
1378
1379#ifdef SH_USE_XML
1380static char * all_items (file_type * theFile, char * fileHash, int is_new)
1381{
1382  char timstr1c[32];
1383  char timstr1a[32];
1384  char timstr1m[32];
1385
1386  char * tmp_lnk;
1387  char * format;
1388
1389  char * tmp = SH_ALLOC(SH_MSG_BUF);
1390  char * msg = SH_ALLOC(SH_MSG_BUF);
1391
1392  tmp[0] = '\0';
1393  msg[0] = '\0';
1394
1395  if (report_checkflags != S_FALSE)
1396    {
1397      if (is_new)
1398        format = _("checkflags_new=\"0%lo\" ");
1399      else
1400        format = _("checkflags_old=\"0%lo\" ");
1401      sl_snprintf(tmp, SH_MSG_BUF, format,
1402                  (unsigned long) theFile->check_flags);
1403      sl_strlcat(msg, tmp, SH_MSG_BUF); 
1404    }
1405
1406#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1407  if (is_new)
1408    format = _("mode_new=\"%s\" attr_new=\"%s\" imode_new=\"%ld\" iattr_new=\"%ld\" ");
1409  else 
1410    format = _("mode_old=\"%s\" attr_old=\"%s\" imode_old=\"%ld\" iattr_old=\"%ld\" ");
1411  sl_snprintf(tmp, SH_MSG_BUF, format,
1412              theFile->c_mode,
1413              theFile->c_attributes,
1414              (long) theFile->mode,
1415              (long) theFile->attributes
1416              );
1417#else
1418  if (is_new)
1419    format = _("mode_new=\"%s\" imode_new=\"%ld\" ");
1420  else
1421    format = _("mode_old=\"%s\" imode_old=\"%ld\" ");
1422
1423  sl_snprintf(tmp, SH_MSG_BUF, format,
1424              theFile->c_mode,
1425              (long) theFile->mode
1426              );
1427#endif
1428  sl_strlcat(msg, tmp, SH_MSG_BUF);
1429
1430  if (is_new)
1431    format = _("hardlinks_new=\"%lu\" ");
1432  else
1433    format = _("hardlinks_old=\"%lu\" ");
1434  sl_snprintf(tmp, SH_MSG_BUF, format,
1435              (unsigned long) theFile->hardlinks);
1436  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1437
1438
1439  if (is_new)
1440    format = _("idevice_new=\"%lu\" ");
1441  else
1442    format = _("idevice_old=\"%lu\" ");
1443  sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->rdev);
1444  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1445
1446
1447  if (is_new)
1448    format = _("inode_new=\"%lu\" ");
1449  else
1450    format = _("inode_old=\"%lu\" ");
1451  sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->ino);
1452  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1453
1454  /*
1455   * also report device for prelude
1456   */
1457#if defined(HAVE_LIBPRELUDE)
1458  if (is_new)
1459    format = _("dev_new=\"%lu,%lu\" ");
1460  else
1461    format = _("dev_old=\"%lu,%lu\" ");
1462  sl_snprintf(tmp, SH_MSG_BUF, format,               
1463              (unsigned long) major(theFile->dev),
1464              (unsigned long) minor(theFile->dev));
1465  sl_strlcat(msg, tmp, SH_MSG_BUF);
1466#endif
1467
1468
1469  if (is_new)
1470    format = _("owner_new=\"%s\" iowner_new=\"%ld\" ");
1471  else
1472    format = _("owner_old=\"%s\" iowner_old=\"%ld\" ");
1473  sl_snprintf(tmp, SH_MSG_BUF, format,
1474              theFile->c_owner, (long) theFile->owner);
1475  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1476
1477
1478  if (is_new)
1479    format = _("group_new=\"%s\" igroup_new=\"%ld\" ");
1480  else
1481    format = _("group_old=\"%s\" igroup_old=\"%ld\" ");
1482  sl_snprintf(tmp, SH_MSG_BUF, format,
1483              theFile->c_group, (long) theFile->group);
1484  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1485
1486
1487  if (is_new)
1488    sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
1489                (UINT64) 0, (UINT64) theFile->size);
1490  else
1491    sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
1492                (UINT64) theFile->size, (UINT64) 0);
1493  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1494
1495
1496  (void) sh_unix_gmttime (theFile->ctime, timstr1c,  sizeof(timstr1c));
1497  if (is_new)
1498    sl_snprintf(tmp, SH_MSG_BUF, _("ctime_new=\"%s\" "), timstr1c);
1499  else
1500    sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=\"%s\" "), timstr1c);
1501  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1502
1503  (void) sh_unix_gmttime (theFile->atime, timstr1a,  sizeof(timstr1a));
1504  if (is_new)
1505    sl_snprintf(tmp, SH_MSG_BUF, _("atime_new=\"%s\" "), timstr1a);
1506  else
1507    sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=\"%s\" "), timstr1a);
1508  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1509
1510  (void) sh_unix_gmttime (theFile->mtime, timstr1m,  sizeof(timstr1m));
1511  if (is_new)
1512    sl_snprintf(tmp, SH_MSG_BUF, _("mtime_new=\"%s\" "), timstr1m);
1513  else
1514    sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=\"%s\" "), timstr1m);
1515  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1516
1517  if (is_new)
1518    sl_snprintf(tmp, SH_MSG_BUF, _("chksum_new=\"%s\" "), fileHash);
1519  else
1520    sl_snprintf(tmp, SH_MSG_BUF, _("chksum_old=\"%s\" "), fileHash);
1521  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1522
1523  if (theFile->c_mode[0] == 'l' || 
1524      (theFile->link_path != NULL && theFile->link_path[0] != '-'))
1525    {
1526      tmp_lnk     = sh_util_safe_name(theFile->link_path);
1527      if (tmp_lnk)
1528        {
1529          if (is_new)
1530            sl_snprintf(tmp, SH_MSG_BUF, _("link_new=\"%s\" "), tmp_lnk);
1531          else
1532            sl_snprintf(tmp, SH_MSG_BUF, _("link_old=\"%s\" "), tmp_lnk);
1533          SH_FREE(tmp_lnk);
1534          sl_strlcat(msg, tmp, SH_MSG_BUF);
1535        } 
1536    }
1537
1538  if (theFile->attr_string)
1539    {
1540      tmp_lnk     = sh_util_safe_name(theFile->attr_string);
1541      if (tmp_lnk)
1542        {
1543          if (is_new)
1544            sl_snprintf(tmp, SH_MSG_BUF, _("acl_new=\"%s\" "), tmp_lnk);
1545          else
1546            sl_snprintf(tmp, SH_MSG_BUF, _("acl_old=\"%s\" "), tmp_lnk);
1547          SH_FREE(tmp_lnk);
1548          sl_strlcat(msg, tmp, SH_MSG_BUF);
1549        } 
1550    }
1551
1552 
1553  SH_FREE(tmp);
1554  return (msg);
1555}
1556#else
1557static char * all_items (file_type * theFile, char * fileHash, int is_new)
1558{
1559  char timstr1c[32];
1560  char timstr1a[32];
1561  char timstr1m[32];
1562
1563  char * tmp_lnk;
1564  char * format;
1565
1566  char * tmp = SH_ALLOC(SH_MSG_BUF);
1567  char * msg = SH_ALLOC(SH_MSG_BUF);
1568
1569  tmp[0] = '\0';
1570  msg[0] = '\0';
1571
1572  if (report_checkflags == S_TRUE)
1573    {
1574      if (is_new)
1575        format = _("checkflags_new=<0%lo> ");
1576      else
1577        format = _("checkflags_old=<0%lo> ");
1578      sl_snprintf(tmp, SH_MSG_BUF, format,
1579                  (unsigned long) theFile->check_flags);
1580      sl_strlcat(msg, tmp, SH_MSG_BUF); 
1581    }
1582
1583
1584#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1585  if (is_new)
1586    format = _("mode_new=<%s>, attr_new=<%s>, imode_new=<%ld>, iattr_new=<%ld>, ");
1587  else 
1588    format = _("mode_old=<%s>, attr_old=<%s>, imode_old=<%ld>, iattr_old=<%ld>, ");
1589  sl_snprintf(tmp, SH_MSG_BUF, format,
1590              theFile->c_mode,
1591              theFile->c_attributes,
1592              (long) theFile->mode,
1593              (long) theFile->attributes
1594              );
1595#else
1596  if (is_new)
1597    format = _("mode_new=<%s>, imode_new=<%ld>, ");
1598  else
1599    format = _("mode_old=<%s>, imode_old=<%ld>, ");
1600
1601  sl_snprintf(tmp, SH_MSG_BUF, format,
1602              theFile->c_mode,
1603              (long) theFile->mode
1604              );
1605#endif
1606  sl_strlcat(msg, tmp, SH_MSG_BUF);
1607
1608  if (is_new)
1609    format = _("hardlinks_new=<%lu>, ");
1610  else
1611    format = _("hardlinks_old=<%lu>, ");
1612  sl_snprintf(tmp, SH_MSG_BUF, format,
1613              (unsigned long) theFile->hardlinks);
1614  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1615
1616
1617  if (is_new)
1618    format = _("idevice_new=<%lu>, ");
1619  else
1620    format = _("idevice_old=<%lu>, ");
1621  sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->rdev);
1622  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1623
1624
1625  if (is_new)
1626    format = _("inode_new=<%lu>, ");
1627  else
1628    format = _("inode_old=<%lu>, ");
1629  sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->ino);
1630  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1631
1632
1633  /*
1634   * also report device for prelude
1635   */
1636#if defined(HAVE_LIBPRELUDE)
1637  if (is_new)
1638    format = _("dev_new=<%lu,%lu>, ");
1639  else
1640    format = _("dev_old=<%lu,%lu>, ");
1641  sl_snprintf(tmp, SH_MSG_BUF, format,               
1642              (unsigned long) major(theFile->dev),
1643              (unsigned long) minor(theFile->dev));
1644  sl_strlcat(msg, tmp, SH_MSG_BUF);
1645#endif
1646
1647  if (is_new)
1648    format = _("owner_new=<%s>, iowner_new=<%ld>, ");
1649  else
1650    format = _("owner_old=<%s>, iowner_old=<%ld>, ");
1651  sl_snprintf(tmp, SH_MSG_BUF, format,
1652              theFile->c_owner, (long) theFile->owner);
1653  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1654
1655
1656  if (is_new)
1657    format = _("group_new=<%s>, igroup_new=<%ld>, ");
1658  else
1659    format = _("group_old=<%s>, igroup_old=<%ld>, ");
1660  sl_snprintf(tmp, SH_MSG_BUF, format,
1661              theFile->c_group, (long) theFile->group);
1662  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1663
1664
1665  if (is_new)
1666    sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
1667                (UINT64) 0, (UINT64) theFile->size);
1668  else
1669    sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
1670                (UINT64) theFile->size, (UINT64) 0);
1671  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1672
1673
1674  (void) sh_unix_gmttime (theFile->ctime, timstr1c,  sizeof(timstr1c));
1675  if (is_new)
1676    sl_snprintf(tmp, SH_MSG_BUF, _("ctime_new=<%s>, "), timstr1c);
1677  else
1678    sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=<%s>, "), timstr1c);
1679  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1680
1681  (void) sh_unix_gmttime (theFile->atime, timstr1a,  sizeof(timstr1a));
1682  if (is_new)
1683    sl_snprintf(tmp, SH_MSG_BUF, _("atime_new=<%s>, "), timstr1a);
1684  else
1685    sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=<%s>, "), timstr1a);
1686  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1687
1688  (void) sh_unix_gmttime (theFile->mtime, timstr1m,  sizeof(timstr1m));
1689  if (is_new)
1690    sl_snprintf(tmp, SH_MSG_BUF, _("mtime_new=<%s>, "), timstr1m);
1691  else
1692    sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=<%s>, "), timstr1m);
1693  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1694
1695  if (is_new)
1696    sl_snprintf(tmp, SH_MSG_BUF, _("chksum_new=<%s>"), fileHash);
1697  else
1698    sl_snprintf(tmp, SH_MSG_BUF, _("chksum_old=<%s>"), fileHash);
1699  sl_strlcat(msg, tmp, SH_MSG_BUF); 
1700
1701  if (theFile->c_mode[0] == 'l' || 
1702      (theFile->link_path != NULL && theFile->link_path[0] != '-'))
1703    {
1704      tmp_lnk     = sh_util_safe_name(theFile->link_path);
1705      if (tmp_lnk)
1706        {
1707          if (is_new)
1708            sl_snprintf(tmp, SH_MSG_BUF, _(", link_new=<%s> "), tmp_lnk);
1709          else
1710            sl_snprintf(tmp, SH_MSG_BUF, _(", link_old=<%s> "), tmp_lnk);
1711          SH_FREE(tmp_lnk);
1712          sl_strlcat(msg, tmp, SH_MSG_BUF);
1713        } 
1714    }
1715 
1716  if (theFile->attr_string)
1717    {
1718      tmp_lnk     = sh_util_safe_name(theFile->attr_string);
1719      if (tmp_lnk)
1720        {
1721          if (is_new)
1722            sl_snprintf(tmp, SH_MSG_BUF, _(", acl_new=<%s> "), tmp_lnk);
1723          else
1724            sl_snprintf(tmp, SH_MSG_BUF, _(", acl_old=<%s> "), tmp_lnk);
1725          SH_FREE(tmp_lnk);
1726          sl_strlcat(msg, tmp, SH_MSG_BUF);
1727        } 
1728    }
1729
1730  SH_FREE(tmp);
1731  return (msg);
1732}
1733#endif
1734
1735void sh_hash_pushdata_memory (file_type * theFile, char * fileHash)
1736{
1737  sh_file_t * p;
1738
1739  SL_ENTER(_("sh_hash_pushdata_memory"));
1740
1741  p = sh_hash_push_int(theFile, fileHash);
1742  if (p) 
1743    {
1744      SH_MUTEX_LOCK(mutex_hash);
1745      hashinsert (tab, p);
1746      p->modi_mask = theFile->check_flags;
1747      SH_MUTEX_UNLOCK(mutex_hash);
1748    }
1749
1750  SL_RET0(_("sh_hash_pushdata_memory"));
1751}
1752
1753int sh_hash_is_null_file(file_type * theFile)
1754{
1755  if (theFile->hardlinks == SH_DEADFILE && theFile->mode  == 0 &&
1756      theFile->ino == 0                 && theFile->ctime == 0)
1757    {
1758      return S_TRUE;
1759    }
1760  return S_FALSE;
1761}
1762
1763int sh_hash_is_null_record(sh_filestore_t * theFile)
1764{
1765  if (theFile->hardlinks == SH_DEADFILE && theFile->mode  == 0 &&
1766      theFile->ino == 0                 && theFile->ctime == 0)
1767    {
1768      return S_TRUE;
1769    }
1770  return S_FALSE;
1771}
1772
1773void sh_hash_insert_null(char * str)
1774{
1775  file_type theFile = { 0, 0, {'\0'}, 0, 0, 0, 0, 0, 
1776#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1777                        0, {'\0'},
1778#endif
1779                        {'\0'}, 0, {'\0'}, 0, {'\0'}, 
1780                        0, 0, 0, 0, 0, 0, 0, NULL,  0, {'\0'}, 0, NULL
1781  }; /* clang compiler bails out on standard conforming init with just {0} */
1782  char      fileHash[KEY_LEN+1];
1783  char      hashbuf[KEYBUF_SIZE];
1784
1785  sl_strlcpy(fileHash, SH_KEY_NULL, sizeof(fileHash));
1786  theFile.hardlinks = SH_DEADFILE;
1787
1788  if (sl_strlen(str) < PATH_MAX)
1789    sl_strlcpy(theFile.fullpath, str, PATH_MAX);
1790  else 
1791     sl_strlcpy(theFile.fullpath, 
1792                sh_tiger_hash(str, TIGER_DATA, sl_strlen(str),
1793                              hashbuf, sizeof(hashbuf)),
1794                PATH_MAX);
1795
1796  sh_hash_pushdata_memory(&theFile, fileHash);
1797  return;
1798}
1799
1800static int handle_notfound(int  log_severity, int class,
1801                           file_type * theFile, char * fileHash)
1802{
1803  sh_file_t * p;
1804  int         retval = 0;
1805
1806  if (S_FALSE == sh_ignore_chk_new(theFile->fullpath))
1807    {
1808      char * tmp = sh_util_safe_name(theFile->fullpath);
1809      char * str;
1810
1811      sh_files_fixup_mask(class, &(theFile->check_flags));
1812      str = all_items (theFile, fileHash, 1);
1813     
1814      sh_error_handle (log_severity, FIL__, __LINE__, 0, 
1815                       MSG_FI_ADD2, 
1816                       tmp, str);
1817      ++sh.statistics.files_report;
1818      SH_FREE(str);
1819      SH_FREE(tmp);
1820    }
1821 
1822  if (sh.flag.reportonce == S_TRUE)
1823    SET_SH_FFLAG_REPORTED(theFile->file_reported);
1824 
1825  if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
1826    {
1827      p = sh_hash_push_int(theFile, fileHash);
1828      if (p)
1829        {
1830          hashinsert (tab, p);
1831          p->modi_mask = theFile->check_flags;
1832          p->theFile.checkflags = p->modi_mask;
1833        }
1834    }
1835 
1836  else if (S_TRUE == sh.flag.update)
1837    {
1838      if (S_TRUE == sh_util_ask_update (theFile->fullpath))
1839        {
1840          p = sh_hash_push_int(theFile, fileHash);
1841          if (p)
1842            {
1843              hashinsert (tab, p);
1844              p->modi_mask = theFile->check_flags;
1845              p->theFile.checkflags = p->modi_mask;
1846            }
1847        }
1848      else
1849        retval = 1;
1850    }
1851  return retval;
1852}
1853
1854/*****************************************************************
1855 *
1856 * Compare a file with the database status.
1857 *
1858 *****************************************************************/
1859int sh_hash_compdata (int class, file_type * theFile, char * fileHash,
1860                      char * policy_override, int severity_override)
1861{
1862  char * msg;
1863  sh_file_t * p;
1864  char * tmp;
1865  char * tmp_path;
1866  char * tmp_lnk;
1867  char * tmp_lnk_old;
1868
1869  char timstr1c[32];
1870  char timstr2c[32];
1871  char timstr1a[32];
1872  char timstr2a[32];
1873  char timstr1m[32];
1874  char timstr2m[32];
1875  char linkHash[KEY_LEN+1];
1876  char * linkComp;
1877  int  maxcomp;
1878
1879  char change_code[16];
1880  int  i;
1881
1882  unsigned long modi_mask;
1883
1884  char log_policy[32];
1885  volatile int  log_severity;
1886  char hashbuf[KEYBUF_SIZE];
1887  struct {
1888    unsigned long oldflags;
1889    unsigned long newflags;
1890  } cf_report;
1891
1892  int  retval;
1893
1894  SL_ENTER(_("sh_hash_compdata"));
1895
1896  if (IsInit != 1) sh_hash_init();
1897
1898  if (severity_override < 0)
1899    log_severity = ShDFLevel[class];
1900  else
1901    log_severity = severity_override;
1902
1903  if (policy_override != NULL)
1904    sl_strlcpy (log_policy, policy_override, 32);
1905
1906  /* --------  find the entry for the file ----------------       */
1907
1908  SH_MUTEX_LOCK(mutex_hash);
1909
1910  modi_mask = 0;
1911  retval    = 0;
1912
1913  if (sl_strlen(theFile->fullpath) <= MAX_PATH_STORE) 
1914    p = hashsearch(theFile->fullpath);
1915  else 
1916    p = hashsearch( sh_tiger_hash(theFile->fullpath, 
1917                                  TIGER_DATA, 
1918                                  sl_strlen(theFile->fullpath),
1919                                  hashbuf, sizeof(hashbuf))
1920                    );
1921
1922
1923  /* --------- Not found in database. ------------
1924   */
1925
1926  if (p == NULL) 
1927    {
1928      retval = handle_notfound(log_severity, class, theFile, fileHash);
1929      goto unlock_and_return;
1930    }
1931
1932  /* ---------  Skip if we don't want to report changes. ------------
1933   */
1934 
1935  if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath))
1936    {
1937      MODI_SET(theFile->check_flags, MODI_NOCHECK);
1938      p->modi_mask = theFile->check_flags;
1939      p->theFile.checkflags = p->modi_mask;
1940      goto unlock_and_return;
1941    }
1942
1943  cf_report.oldflags = p->theFile.checkflags;
1944  cf_report.newflags = theFile->check_flags;
1945
1946  p->modi_mask = theFile->check_flags;
1947  p->theFile.checkflags = p->modi_mask;
1948
1949  /* initialize change_code */
1950  for (i = 0; i < 15; ++i)
1951    change_code[i] = '-';
1952  change_code[15] = '\0';
1953
1954  TPT ((0, FIL__, __LINE__, _("file=<%s>, cs_old=<%s>, cs_new=<%s>\n"),
1955        theFile->fullpath, fileHash, p->theFile.checksum));
1956
1957  if ( (fileHash != NULL) &&
1958       (strncmp (fileHash, p->theFile.checksum, KEY_LEN) != 0) && 
1959       (theFile->check_flags & MODI_CHK) != 0)
1960    {
1961      if ((theFile->check_flags & MODI_SGROW) == 0)
1962        {
1963          modi_mask |= MODI_CHK;
1964          change_code[0] = 'C';
1965          TPT ((0, FIL__, __LINE__, _("mod=<checksum>")));
1966        }
1967      else
1968        {
1969          if (0 != strncmp (&fileHash[KEY_LEN + 1], p->theFile.checksum, KEY_LEN))
1970            {
1971              if (S_FALSE == sh_check_rotated_log (theFile->fullpath, (UINT64) p->theFile.size, 
1972                                                   (UINT64) p->theFile.ino, p->theFile.checksum,
1973                                                   p->theFile.checkflags))
1974                {
1975                  modi_mask |= MODI_CHK;
1976                  change_code[0] = 'C';
1977                  TPT ((0, FIL__, __LINE__, _("mod=<checksum>")));
1978                }
1979              else
1980                {
1981                  /* logfile has been rotated */
1982                  p->theFile.size  = theFile->size;
1983                  p->theFile.ino   = theFile->ino;
1984                  sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
1985                }
1986            }
1987          else
1988            {
1989              p->theFile.size  = theFile->size;
1990              sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
1991            }
1992        }
1993    } 
1994
1995  if (p->theFile.c_mode[0] == 'l') 
1996    {
1997      if (!(theFile->link_path) &&
1998          (theFile->check_flags & MODI_LNK) != 0)
1999        {
2000          linkComp = NULL;
2001          modi_mask |= MODI_LNK;
2002          change_code[1] = 'L';
2003          TPT ((0, FIL__, __LINE__, _("mod=<link>")));
2004        }
2005      else
2006        {
2007          if (sl_strlen(theFile->link_path) >= MAX_PATH_STORE) 
2008            {
2009              sl_strlcpy(linkHash, 
2010                         sh_tiger_hash(theFile->link_path, 
2011                                       TIGER_DATA,
2012                                       sl_strlen(theFile->link_path),
2013                                       hashbuf, sizeof(hashbuf)), 
2014                         MAX_PATH_STORE+1);
2015              linkComp = linkHash;
2016              maxcomp  = KEY_LEN;
2017            } 
2018          else 
2019            {
2020              linkComp = theFile->link_path;
2021              maxcomp  = MAX_PATH_STORE;
2022            }
2023         
2024          if ( sl_strncmp (linkComp, p->linkpath, maxcomp) != 0 &&
2025               (theFile->check_flags & MODI_LNK) != 0)
2026            {
2027              modi_mask |= MODI_LNK;
2028              change_code[1] = 'L';
2029              TPT ((0, FIL__, __LINE__, _("mod=<link>")));
2030            } 
2031        }
2032    }
2033
2034  if (p->theFile.c_mode[0] == 'c' || p->theFile.c_mode[0] == 'b') 
2035    {
2036      if ( ( major(theFile->rdev) != major((dev_t)p->theFile.rdev) || 
2037             minor(theFile->rdev) != minor((dev_t)p->theFile.rdev) ) &&
2038           (theFile->check_flags & MODI_RDEV) != 0)
2039        {
2040          modi_mask |= MODI_RDEV;
2041          change_code[2] = 'D';
2042          TPT ((0, FIL__, __LINE__, _("mod=<rdev>")));
2043        } 
2044    }
2045     
2046  /* cast to UINT32 in case ino_t is not 32bit
2047   */
2048  if ( (UINT32) theFile->ino != (UINT32) p->theFile.ino  &&
2049       (theFile->check_flags & MODI_INO) != 0)
2050    {
2051      modi_mask |= MODI_INO;
2052      change_code[3] = 'I';
2053      TPT ((0, FIL__, __LINE__, _("mod=<inode>")));
2054    } 
2055   
2056  if ( theFile->hardlinks != (nlink_t) p->theFile.hardlinks &&
2057       (theFile->check_flags & MODI_HLN) != 0)
2058    {
2059      modi_mask |= MODI_HLN;
2060      change_code[4] = 'H';
2061      TPT ((0, FIL__, __LINE__, _("mod=<hardlink>")));
2062    } 
2063
2064
2065  if ( (  (theFile->mode != p->theFile.mode)
2066#if defined(USE_ACL) || defined(USE_XATTR)
2067          || ( (sh_unix_check_selinux|sh_unix_check_acl) &&
2068               ( 
2069                (theFile->attr_string == NULL && p->attr_string != NULL) ||
2070                (theFile->attr_string != NULL && p->attr_string == NULL) ||
2071                (theFile->attr_string != NULL && 0 != strcmp(theFile->attr_string, p->attr_string))
2072                )
2073               )
2074#endif
2075#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2076          || (theFile->attributes != p->theFile.attributes)
2077#endif
2078          )
2079       && (theFile->check_flags & MODI_MOD) != 0)
2080    {
2081      modi_mask |= MODI_MOD;
2082      change_code[5] = 'M';
2083      TPT ((0, FIL__, __LINE__, _("mod=<mode>")));
2084      /*
2085       * report link path if switch link/no link
2086       */
2087      if ((theFile->check_flags & MODI_LNK) != 0 &&
2088          (theFile->c_mode[0] != p->theFile.c_mode[0]) &&
2089          (theFile->c_mode[0] == 'l' || p->theFile.c_mode[0] == 'l'))
2090        {
2091          modi_mask |= MODI_LNK;
2092          change_code[1] = 'L';
2093          TPT ((0, FIL__, __LINE__, _("mod=<link>")));
2094        }
2095    } 
2096
2097  if ( theFile->owner != (uid_t) p->theFile.owner &&
2098       (theFile->check_flags & MODI_USR) != 0)
2099    {
2100      modi_mask |= MODI_USR;
2101      change_code[6] = 'U';
2102      TPT ((0, FIL__, __LINE__, _("mod=<user>")));
2103    } 
2104
2105  if ( theFile->group != (gid_t) p->theFile.group &&
2106       (theFile->check_flags & MODI_GRP) != 0)
2107    {
2108      modi_mask |= MODI_GRP;
2109      change_code[7] = 'G';
2110      TPT ((0, FIL__, __LINE__, _("mod=<group>")));
2111    } 
2112
2113 
2114  if ( theFile->mtime != (time_t) p->theFile.mtime &&
2115       (theFile->check_flags & MODI_MTM) != 0)
2116    {
2117      modi_mask |= MODI_MTM;
2118      change_code[8] = 'T';
2119      TPT ((0, FIL__, __LINE__, _("mod=<mtime>")));
2120    } 
2121 
2122  if ( (theFile->check_flags & MODI_ATM) != 0 &&
2123       theFile->atime != (time_t) p->theFile.atime)
2124    {
2125      modi_mask |= MODI_ATM;
2126      change_code[8] = 'T';
2127      TPT ((0, FIL__, __LINE__, _("mod=<atime>")));
2128    } 
2129
2130 
2131  /* Resetting the access time will set a new ctime. Thus, either we ignore
2132   * the access time or the ctime for NOIGNORE
2133   */
2134  if ( theFile->ctime != (time_t) p->theFile.ctime &&
2135       (theFile->check_flags & MODI_CTM) != 0)
2136    {
2137      modi_mask |= MODI_CTM;
2138      change_code[8] = 'T';
2139      TPT ((0, FIL__, __LINE__, _("mod=<ctime>")));
2140    } 
2141
2142  if ( theFile->size != (off_t) p->theFile.size &&
2143       (theFile->check_flags & MODI_SIZ) != 0)
2144    {
2145      if ((theFile->check_flags & MODI_SGROW) == 0 || 
2146          theFile->size < (off_t) p->theFile.size)
2147        {
2148          modi_mask |= MODI_SIZ;
2149          change_code[9] = 'S';
2150          TPT ((0, FIL__, __LINE__, _("mod=<size>")));
2151        }
2152    }
2153  change_code[10] = '\0';
2154
2155  /* --- Directories special case ---
2156   */
2157  if (p->theFile.c_mode[0] == 'd'                               &&
2158      0 == (modi_mask & ~(MODI_SIZ|MODI_ATM|MODI_CTM|MODI_MTM)) && 
2159      sh_loosedircheck == S_TRUE)
2160    {
2161      modi_mask = 0;
2162    }
2163
2164  /* --- Report full details. ---
2165   */
2166  if (modi_mask != 0 && sh.flag.fulldetail == S_TRUE)
2167    {
2168      if ((theFile->check_flags & MODI_ATM) == 0)
2169        modi_mask = MASK_READONLY_;
2170      else
2171        modi_mask = MASK_NOIGNORE_;
2172    }
2173
2174  /* --- Report on modified files. ---
2175   */
2176  if (modi_mask != 0 && (!SH_FFLAG_REPORTED_SET(p->fflags)))
2177    { 
2178      tmp = SH_ALLOC(SH_MSG_BUF);
2179      msg = SH_ALLOC(SH_MSG_BUF);
2180      msg[0] = '\0';
2181
2182      sh_files_fixup_mask(class, &(cf_report.newflags));
2183
2184      if ( (report_checkflags != S_FALSE) && (cf_report.oldflags != cf_report.newflags))
2185        {
2186          sl_snprintf(tmp, SH_MSG_BUF,
2187#ifdef SH_USE_XML
2188                      _("checkflags_old=\"0%lo\" checkflags_new=\"0%lo\" "),
2189#else
2190                      _("checkflags_old=<0%lo>, checkflags_new=<0%lo>, "),
2191#endif
2192                      cf_report.oldflags,  cf_report.newflags);
2193          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2194        }
2195
2196      if (   ((modi_mask & MODI_MOD) != 0)
2197#if defined(HAVE_LIBPRELUDE)
2198             || ((modi_mask & MODI_USR) != 0)
2199             || ((modi_mask & MODI_GRP) != 0)
2200#endif
2201             )
2202        {
2203#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2204          sl_snprintf(tmp, SH_MSG_BUF, 
2205#ifdef SH_USE_XML
2206                      _("mode_old=\"%s\" mode_new=\"%s\" attr_old=\"%s\" attr_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" iattr_old=\"%ld\" iattr_new=\"%ld\" "),
2207#else
2208                      _("mode_old=<%s>, mode_new=<%s>, attr_old=<%s>, attr_new=<%s>, "),
2209#endif
2210                      p->theFile.c_mode, theFile->c_mode,
2211                      p->theFile.c_attributes, theFile->c_attributes
2212#ifdef SH_USE_XML
2213                      , (long) p->theFile.mode, (long) theFile->mode,
2214                      (long) p->theFile.attributes, 
2215                      (long) theFile->attributes
2216#endif
2217                      );
2218#else
2219#ifdef SH_USE_XML
2220          sl_snprintf(tmp, SH_MSG_BUF, 
2221                      _("mode_old=\"%s\" mode_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" "),
2222                      p->theFile.c_mode, theFile->c_mode,
2223                      (long) p->theFile.mode, (long) theFile->mode);
2224#else
2225          sl_snprintf(tmp, SH_MSG_BUF, _("mode_old=<%s>, mode_new=<%s>, "),
2226                      p->theFile.c_mode, theFile->c_mode);
2227#endif
2228#endif
2229          sl_strlcat(msg, tmp, SH_MSG_BUF);
2230
2231#if defined(USE_ACL) || defined(USE_XATTR)
2232          if (theFile->attr_string != NULL || p->attr_string != NULL)
2233            {
2234              sl_snprintf(tmp, SH_MSG_BUF, 
2235#ifdef SH_USE_XML
2236                          _("acl_old=\"%s\" acl_new=\"%s\" "),
2237#else
2238                          _("acl_old=<%s>, acl_new=<%s>, "),
2239#endif
2240                          (p->attr_string)       ? p->attr_string       : _("none"), 
2241                          (theFile->attr_string) ? theFile->attr_string : _("none"));
2242             
2243              sl_strlcat(msg, tmp, SH_MSG_BUF);
2244            }
2245#endif
2246
2247          if ((modi_mask & MODI_MOD) != 0)
2248            {
2249              /*
2250               * We postpone update if sh.flag.update == S_TRUE because
2251               * in interactive mode the user may not accept the change.
2252               */
2253              if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2254                {
2255                  sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
2256                  p->theFile.mode = theFile->mode;
2257#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2258                  sl_strlcpy(p->theFile.c_attributes,theFile->c_attributes,16);
2259                  p->theFile.attributes = theFile->attributes;
2260#endif
2261#if defined(USE_ACL) || defined(USE_XATTR)
2262                  if      (p->attr_string == NULL && theFile->attr_string != NULL)
2263                    { p->attr_string = sh_util_strdup (theFile->attr_string); }
2264                  else if (p->attr_string != NULL && theFile->attr_string == NULL)
2265                    { SH_FREE(p->attr_string); p->attr_string = NULL; }
2266                  else if (theFile->attr_string != NULL && p->attr_string != NULL)
2267                    { 
2268                      if (0 != strcmp(theFile->attr_string, p->attr_string))
2269                        {
2270                          SH_FREE(p->attr_string);
2271                          p->attr_string = sh_util_strdup (theFile->attr_string);
2272                        }
2273                    }
2274#endif
2275                }
2276            }
2277
2278        }
2279
2280      if ((modi_mask & MODI_HLN) != 0)
2281        {
2282          sl_snprintf(tmp, SH_MSG_BUF, 
2283#ifdef SH_USE_XML
2284                      _("hardlinks_old=\"%lu\" hardlinks_new=\"%lu\" "),
2285#else
2286                      _("hardlinks_old=<%lu>, hardlinks_new=<%lu>, "),
2287#endif
2288                      (unsigned long) p->theFile.hardlinks, 
2289                      (unsigned long) theFile->hardlinks);
2290          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2291
2292          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2293            p->theFile.hardlinks = theFile->hardlinks;
2294        }
2295
2296      if ((modi_mask & MODI_RDEV) != 0)
2297        {
2298          sl_snprintf(tmp, SH_MSG_BUF,
2299#ifdef SH_USE_XML
2300                      _("device_old=\"%lu,%lu\" device_new=\"%lu,%lu\" idevice_old=\"%lu\" idevice_new=\"%lu\" "),
2301#else
2302                      _("device_old=<%lu,%lu>, device_new=<%lu,%lu>, "),
2303#endif
2304                      (unsigned long) major(p->theFile.rdev), 
2305                      (unsigned long) minor(p->theFile.rdev), 
2306                      (unsigned long) major(theFile->rdev),
2307                      (unsigned long) minor(theFile->rdev)
2308#ifdef SH_USE_XML
2309                      , (unsigned long) p->theFile.rdev, 
2310                      (unsigned long) theFile->rdev
2311#endif
2312                      );
2313          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2314
2315          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2316            p->theFile.rdev = theFile->rdev;
2317        }
2318
2319      if ((modi_mask & MODI_INO) != 0)
2320        {
2321          sl_snprintf(tmp, SH_MSG_BUF,
2322#ifdef SH_USE_XML
2323                      _("inode_old=\"%lu\" inode_new=\"%lu\" "),
2324#else
2325                      _("inode_old=<%lu>, inode_new=<%lu>, "),
2326#endif
2327                      (unsigned long) p->theFile.ino, 
2328                      (unsigned long) theFile->ino);
2329          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2330
2331          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2332            {
2333              p->theFile.ino = theFile->ino;
2334              p->theFile.dev = theFile->dev;
2335            }
2336        }
2337
2338
2339      /*
2340       * also report device for prelude
2341       */
2342#if defined(HAVE_LIBPRELUDE)
2343      if ((modi_mask & MODI_INO) != 0)
2344        {
2345          sl_snprintf(tmp, SH_MSG_BUF,
2346#ifdef SH_USE_XML
2347                      _("dev_old=\"%lu,%lu\" dev_new=\"%lu,%lu\" "),
2348#else
2349                      _("dev_old=<%lu,%lu>, dev_new=<%lu,%lu>, "),
2350#endif
2351                      (unsigned long) major(p->theFile.dev),
2352                      (unsigned long) minor(p->theFile.dev),
2353                      (unsigned long) major(theFile->dev),
2354                      (unsigned long) minor(theFile->dev)
2355                      );
2356          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2357
2358          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2359            p->theFile.dev = theFile->dev;
2360        }
2361#endif
2362
2363      if (   ((modi_mask & MODI_USR) != 0)
2364#if defined(HAVE_LIBPRELUDE)
2365          || ((modi_mask & MODI_MOD) != 0)
2366#endif
2367          )
2368        {
2369#ifdef SH_USE_XML
2370          sl_snprintf(tmp, SH_MSG_BUF, 
2371                      _("owner_old=\"%s\" owner_new=\"%s\" iowner_old=\"%ld\" iowner_new=\"%ld\" "),
2372#else
2373          sl_snprintf(tmp, SH_MSG_BUF, 
2374                      _("owner_old=<%s>, owner_new=<%s>, iowner_old=<%ld>, iowner_new=<%ld>, "),
2375#endif
2376                      p->theFile.c_owner, theFile->c_owner, 
2377                      (long) p->theFile.owner, (long) theFile->owner
2378                      );
2379          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2380
2381          if ((modi_mask & MODI_USR) != 0) {
2382            if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2383              {
2384                sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
2385                p->theFile.owner = theFile->owner;
2386              }
2387          }
2388        }
2389
2390      if (   ((modi_mask & MODI_GRP) != 0)
2391#if defined(HAVE_LIBPRELUDE)
2392          || ((modi_mask & MODI_MOD) != 0)
2393#endif
2394          )
2395        {
2396#ifdef SH_USE_XML
2397          sl_snprintf(tmp, SH_MSG_BUF, 
2398                      _("group_old=\"%s\" group_new=\"%s\" igroup_old=\"%ld\" igroup_new=\"%ld\" "),
2399                      p->theFile.c_group, theFile->c_group,
2400                      (long) p->theFile.group, (long) theFile->group);
2401#else
2402          sl_snprintf(tmp, SH_MSG_BUF, 
2403                      _("group_old=<%s>, group_new=<%s>, igroup_old=<%ld>, igroup_new=<%ld>, "),
2404                      p->theFile.c_group, theFile->c_group,
2405                      (long) p->theFile.group, (long) theFile->group);
2406#endif
2407
2408          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2409
2410          if ((modi_mask & MODI_GRP) != 0) {
2411            if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2412              {
2413                sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
2414                p->theFile.group = theFile->group;
2415              }
2416          }
2417        }
2418
2419      if ((modi_mask & MODI_SIZ) != 0)
2420        {
2421          sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
2422                      (UINT64) p->theFile.size, 
2423                      (UINT64) theFile->size);
2424          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2425
2426          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2427            p->theFile.size = theFile->size;
2428        }
2429
2430      if ((modi_mask & MODI_CTM) != 0)
2431        {
2432          (void) sh_unix_gmttime (p->theFile.ctime, timstr1c, sizeof(timstr1c));
2433          (void) sh_unix_gmttime (theFile->ctime,   timstr2c, sizeof(timstr2c));
2434#ifdef SH_USE_XML
2435          sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=\"%s\" ctime_new=\"%s\" "),
2436                      timstr1c, timstr2c);
2437#else
2438          sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=<%s>, ctime_new=<%s>, "),
2439                      timstr1c, timstr2c);
2440#endif
2441          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2442
2443          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2444            p->theFile.ctime = theFile->ctime;
2445        }
2446
2447      if ((modi_mask & MODI_ATM) != 0)
2448        {
2449          (void) sh_unix_gmttime (p->theFile.atime, timstr1a, sizeof(timstr1a));
2450          (void) sh_unix_gmttime (theFile->atime,   timstr2a, sizeof(timstr2a));
2451#ifdef SH_USE_XML
2452          sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=\"%s\" atime_new=\"%s\" "),
2453                      timstr1a, timstr2a);
2454#else
2455          sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=<%s>, atime_new=<%s>, "),
2456                      timstr1a, timstr2a);
2457#endif
2458          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2459
2460          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2461            p->theFile.atime = theFile->atime;
2462        }
2463
2464      if ((modi_mask & MODI_MTM) != 0)
2465        {
2466          (void) sh_unix_gmttime (p->theFile.mtime, timstr1m, sizeof(timstr1m));
2467          (void) sh_unix_gmttime (theFile->mtime,   timstr2m, sizeof(timstr2m));
2468#ifdef SH_USE_XML
2469          sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=\"%s\" mtime_new=\"%s\" "),
2470                      timstr1m, timstr2m);
2471#else
2472          sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=<%s>, mtime_new=<%s>, "),
2473                      timstr1m, timstr2m);
2474#endif
2475          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2476
2477          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2478            p->theFile.mtime = theFile->mtime;
2479        }
2480
2481
2482      if ((modi_mask & MODI_CHK) != 0)
2483        {
2484          sl_snprintf(tmp, SH_MSG_BUF, 
2485#ifdef SH_USE_XML
2486                      _("chksum_old=\"%s\" chksum_new=\"%s\" "),
2487#else
2488                      _("chksum_old=<%s>, chksum_new=<%s>, "),
2489#endif
2490                      p->theFile.checksum, fileHash);
2491          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2492
2493          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2494            {
2495              sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
2496              if ((theFile->check_flags & MODI_SGROW) != 0)           
2497                p->theFile.size  = theFile->size;
2498            }
2499
2500
2501          if (theFile->c_mode[0] != 'l' && theFile->link_path &&
2502              strlen(theFile->link_path) > 2)
2503            modi_mask |= MODI_LNK;
2504        }
2505
2506
2507      if ((modi_mask & MODI_LNK) != 0 /* && theFile->c_mode[0] == 'l' */)
2508        {
2509          if (theFile->link_path)
2510            tmp_lnk     = sh_util_safe_name(theFile->link_path);
2511          else
2512            tmp_lnk     = sh_util_strdup("-");
2513          if (p->linkpath)
2514            tmp_lnk_old = sh_util_safe_name(p->linkpath);
2515          else
2516            tmp_lnk_old = sh_util_strdup("-");
2517#ifdef SH_USE_XML
2518          sl_snprintf(tmp, SH_MSG_BUF, _("link_old=\"%s\" link_new=\"%s\" "),
2519                      tmp_lnk_old, tmp_lnk);
2520#else
2521          sl_snprintf(tmp, SH_MSG_BUF, _("link_old=<%s>, link_new=<%s>, "),
2522                      tmp_lnk_old, tmp_lnk);
2523#endif
2524          SH_FREE(tmp_lnk);
2525          SH_FREE(tmp_lnk_old);
2526          sl_strlcat(msg, tmp, SH_MSG_BUF); 
2527
2528          if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2529            {
2530              if (p->linkpath != NULL)
2531                SH_FREE(p->linkpath);
2532              if (!(theFile->link_path))
2533                p->linkpath = sh_util_strdup("-");
2534              else
2535                p->linkpath = sh_util_strdup(theFile->link_path);
2536            }
2537        }
2538
2539      if (MODI_AUDIT_ENABLED(theFile->check_flags))
2540        {
2541          char result[256];
2542
2543          if (NULL != sh_audit_fetch (theFile->fullpath, theFile->mtime, result, sizeof(result)))
2544            {
2545#ifdef SH_USE_XML
2546              sl_strlcat(msg, _("obj=\""), SH_MSG_BUF);
2547#else
2548              sl_strlcat(msg, _("obj=<"), SH_MSG_BUF);
2549#endif
2550
2551              sl_strlcat(msg, result, SH_MSG_BUF);
2552
2553#ifdef SH_USE_XML
2554              sl_strlcat(msg, _("\" "), SH_MSG_BUF);
2555#else
2556              sl_strlcat(msg, _(">"), SH_MSG_BUF);
2557#endif
2558            } 
2559        }
2560
2561      /****************************************************
2562       *
2563       * REPORT on file change
2564       *
2565       ****************************************************/
2566      tmp_path = sh_util_safe_name(theFile->fullpath);
2567      sh_error_handle(log_severity, FIL__, __LINE__, 
2568                      (long) modi_mask, MSG_FI_CHAN,
2569                      (policy_override == NULL) ? _(policy[class]):log_policy,
2570                      change_code, tmp_path, msg);
2571      ++sh.statistics.files_report;
2572
2573      SH_FREE(tmp_path);
2574      SH_FREE(tmp);
2575      SH_FREE(msg);
2576
2577      if (S_TRUE  == sh.flag.update)
2578        {
2579          if (S_FALSE == sh_util_ask_update(theFile->fullpath))
2580            {
2581              /* user does not want to update, thus we replace
2582               * with data from the baseline database
2583               */
2584              sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11);
2585              theFile->mode  =  p->theFile.mode;
2586#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2587              sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, 16);
2588              theFile->attributes =  p->theFile.attributes;
2589#endif
2590#if defined(USE_ACL) || defined(USE_XATTR)
2591              if      (theFile->attr_string == NULL && p->attr_string != NULL)
2592                { theFile->attr_string = sh_util_strdup (p->attr_string); }
2593              else if (theFile->attr_string != NULL && p->attr_string == NULL)
2594                { SH_FREE(theFile->attr_string); theFile->attr_string = NULL; }
2595              else if (theFile->attr_string != NULL && p->attr_string != NULL)
2596                { 
2597                  if (0 != strcmp(theFile->attr_string, p->attr_string))
2598                    {
2599                      SH_FREE(theFile->attr_string);
2600                      theFile->attr_string = sh_util_strdup (p->attr_string);
2601                    }
2602                }
2603#endif
2604             
2605              if (theFile->c_mode[0] == 'l') /* c_mode is already copied */
2606                {
2607                  if (theFile->link_path)
2608                    SH_FREE(theFile->link_path);
2609                  if (p->linkpath)
2610                    theFile->link_path = sh_util_strdup(p->linkpath);
2611                  else
2612                    theFile->link_path = sh_util_strdup("-");
2613                }
2614              else
2615                {
2616                  if (theFile->link_path)
2617                    SH_FREE(theFile->link_path);
2618                  if (p->linkpath)
2619                    theFile->link_path = sh_util_strdup(p->linkpath);
2620                  else
2621                    theFile->link_path = NULL;
2622                }
2623             
2624              sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
2625             
2626              theFile->mtime =  p->theFile.mtime;
2627              theFile->ctime =  p->theFile.ctime;
2628              theFile->atime =  p->theFile.atime;
2629             
2630              theFile->size  =  p->theFile.size;
2631             
2632              sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2);
2633              theFile->group =  p->theFile.group;
2634              sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2);
2635              theFile->owner =  p->theFile.owner;
2636             
2637              theFile->ino   =  p->theFile.ino;
2638              theFile->rdev  =  p->theFile.rdev;
2639              theFile->dev   =  p->theFile.dev;
2640              theFile->hardlinks = p->theFile.hardlinks;
2641             
2642              SET_SH_FFLAG_VISITED(p->fflags);
2643              CLEAR_SH_FFLAG_CHECKED(p->fflags);
2644              retval = 1;
2645              goto unlock_and_return;
2646            }
2647          else /* if (sh.flag.reportonce == S_TRUE) */
2648            {
2649              /* we replace the data in the in-memory copy of the
2650               * baseline database, because otherwise we would get
2651               * another warning if the suidcheck runs
2652               */
2653              sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
2654              p->theFile.mode  =  theFile->mode;
2655#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2656              sl_strlcpy(p->theFile.c_attributes, theFile->c_attributes, 16);
2657              p->theFile.attributes = theFile->attributes;
2658#endif
2659#if defined(USE_ACL) || defined(USE_XATTR)
2660              if      (p->attr_string == NULL && theFile->attr_string != NULL)
2661                { p->attr_string = sh_util_strdup (theFile->attr_string); }
2662              else if (p->attr_string != NULL && theFile->attr_string == NULL)
2663                { SH_FREE(p->attr_string); p->attr_string = NULL; }
2664              else if (theFile->attr_string != NULL && p->attr_string != NULL)
2665                { 
2666                  if (0 != strcmp(theFile->attr_string, p->attr_string))
2667                    {
2668                      SH_FREE(p->attr_string);
2669                      p->attr_string = sh_util_strdup (theFile->attr_string);
2670                    }
2671                }
2672#endif
2673             
2674              if (theFile->c_mode[0] == 'l' || theFile->link_path)
2675                {
2676                  if (p->linkpath != NULL)
2677                    SH_FREE(p->linkpath);
2678                  p->linkpath = sh_util_strdup(theFile->link_path);
2679                }
2680              else
2681                {
2682                  if (p->linkpath != NULL)
2683                    SH_FREE(p->linkpath);
2684                  p->linkpath = sh_util_strdup("-");
2685                }
2686             
2687              sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
2688             
2689              p->theFile.mtime = theFile->mtime;
2690              p->theFile.ctime = theFile->ctime;
2691              p->theFile.atime = theFile->atime;
2692             
2693              p->theFile.size  = theFile->size;
2694             
2695              sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
2696              p->theFile.group =  theFile->group;
2697              sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
2698              p->theFile.owner =  theFile->owner;
2699             
2700              p->theFile.ino  = theFile->ino;
2701              p->theFile.rdev = theFile->rdev;
2702              p->theFile.dev  = theFile->dev;
2703              p->theFile.hardlinks = theFile->hardlinks;
2704            }
2705        }
2706    }
2707
2708  SET_SH_FFLAG_VISITED(p->fflags);
2709  CLEAR_SH_FFLAG_CHECKED(p->fflags);
2710
2711 unlock_and_return:
2712  ; /* 'label at end of compound statement */
2713  SH_MUTEX_UNLOCK(mutex_hash);
2714  SL_RETURN(retval, _("sh_hash_compdata"));
2715}
2716
2717int hash_full_tree () 
2718{
2719  sh_file_t * p;
2720  int         i;
2721
2722  SL_ENTER(_("hash_full_tree"));
2723
2724  if (IsInit != 1) 
2725    SL_RETURN(0, _("hash_full_tree"));
2726
2727  SH_MUTEX_LOCK_UNSAFE(mutex_hash);
2728  for (i = 0; i < TABSIZE; ++i)
2729    {
2730      for (p = tab[i]; p; p = p->next)
2731        CLEAR_SH_FFLAG_ALLIGNORE(p->fflags);
2732    }
2733  SH_MUTEX_UNLOCK_UNSAFE(mutex_hash);
2734  SL_RETURN (0, _("hash_full_tree"));
2735} 
2736
2737#if !defined(SH_CUTEST)
2738static 
2739#endif
2740int hash_remove_tree_test(char * s, char * fullpath, size_t len_s)
2741{
2742  size_t       len_p;
2743  char      *  test;
2744
2745  len_p = strlen(fullpath);
2746 
2747  if (len_p >= len_s)
2748    {
2749      if (0 == strncmp(s, fullpath, len_s)) 
2750        { 
2751          if (len_p > len_s)
2752            {
2753              /* continue if not inside directory;
2754               * len_s > 1 because everything is inside '/'
2755               */
2756              if ((len_s > 1) && (fullpath[len_s] != '/'))
2757                return S_FALSE;
2758
2759              test = sh_files_find_mostspecific_dir(fullpath);
2760             
2761              if (test && 0 != strcmp(test, s)) {
2762                /* There is a more specific directory, continue */
2763                return S_FALSE;
2764              }
2765             
2766              if (NULL == sh_files_findfile(fullpath)) {
2767                /* SET_SH_FFLAG_ALLIGNORE(p->fflags); */
2768                return S_TRUE;
2769              }
2770            }
2771          else /* len_p == len */
2772            {
2773              /* it is 's' itself, mark and continue
2774               * unless there is a policy for the inode itself
2775               */
2776              if (NULL == sh_files_findfile(fullpath)) {
2777                /* SET_SH_FFLAG_ALLIGNORE(p->fflags); */
2778                return S_TRUE;
2779              }
2780              else {
2781                return S_FALSE;
2782              }
2783            }
2784
2785        } /* if path is in tree */
2786    } /* if path is possibly in tree */
2787  return S_FALSE;
2788}
2789
2790
2791int hash_remove_tree (char * s) 
2792{
2793  sh_file_t *  p;
2794  size_t       len_s;
2795  unsigned int i;
2796
2797  SL_ENTER(_("hash_remove_tree"));
2798
2799  if (!s || *s == '\0')
2800    SL_RETURN ((-1), _("hash_remove_tree"));
2801
2802  len_s = sl_strlen(s);
2803
2804  if (IsInit != 1) 
2805    sh_hash_init();
2806
2807  SH_MUTEX_LOCK_UNSAFE(mutex_hash);
2808  for (i = 0; i < TABSIZE; ++i)
2809    {
2810      for (p = tab[i]; p; p = p->next)
2811        {
2812          if (p->fullpath)
2813            {
2814              /* if (0 == strncmp(s, p->fullpath, len_s)) *//* old */
2815              if (S_TRUE == hash_remove_tree_test(s, p->fullpath, len_s)) {
2816                SET_SH_FFLAG_ALLIGNORE(p->fflags);
2817                MODI_SET(p->theFile.checkflags, MODI_ALLIGNORE);
2818              }
2819            } /* if path is not null */
2820
2821        }
2822    }
2823  SH_MUTEX_UNLOCK_UNSAFE(mutex_hash);
2824  SL_RETURN ((0), _("hash_remove_tree"));
2825} 
2826
2827#if TIME_WITH_SYS_TIME
2828#include <sys/time.h>
2829#include <time.h>
2830#else
2831#if HAVE_SYS_TIME_H
2832#include <sys/time.h>
2833#else
2834#include <time.h>
2835#endif
2836#endif
2837
2838static int ListFullDetail    = S_FALSE;
2839static int ListWithDelimiter = S_FALSE;
2840static char * ListFile       = NULL;
2841
2842int set_list_file (const char * c)
2843{
2844  ListFile = sh_util_strdup(c);
2845  return 0;
2846}
2847char * get_list_file()
2848{
2849  return ListFile;
2850}
2851
2852int set_full_detail (const char * c)
2853{
2854  (void) c;
2855  ListFullDetail = S_TRUE;
2856  return 0;
2857}
2858 
2859int set_list_delimited (const char * c)
2860{
2861  (void) c;
2862  ListFullDetail = S_TRUE;
2863  ListWithDelimiter = S_TRUE;
2864  return 0;
2865}
2866
2867/* Always quote the string, except if it is empty. Quote quotes by
2868 * doubling them.
2869 */
2870char * csv_escape(const char * str)
2871{
2872  const  char * p = str;
2873  const  char * q;
2874
2875  size_t size       = 0;
2876  size_t flag_quote = 0;
2877
2878  char * new;
2879  char * pnew;
2880
2881  if (p)
2882    {
2883
2884      while (*p) 
2885        {
2886          if (*p == '"')
2887            ++flag_quote;
2888         
2889          ++size; ++p;
2890        }
2891
2892      if (sl_ok_adds(size, flag_quote))
2893        size += flag_quote;      /* double each quote */
2894      else
2895        return NULL;
2896
2897      if (sl_ok_adds(size, 3))
2898        size += 3; /* two quotes and terminating null */
2899      else
2900        return NULL;
2901     
2902      new = SH_ALLOC(size);
2903     
2904      if (flag_quote != 0)
2905        {
2906          new[0] = '"';
2907          pnew = &new[1];
2908          q    = str;
2909          while (*q)
2910            {
2911              *pnew = *q;
2912              if (*pnew == '"')
2913                {
2914                  ++pnew; *pnew = '"';
2915                }
2916              ++pnew; ++q;
2917            }
2918          *pnew = '"'; ++pnew;
2919          *pnew = '\0';
2920        }
2921      else
2922        {
2923          if (size > 3) 
2924            {
2925              new[0] = '"';
2926              sl_strlcpy (&new[1], str, size-1);
2927              new[size-2] = '"';
2928              new[size-1] = '\0';
2929            }
2930          else
2931            {
2932              new[0] = '\0';
2933            }
2934        }
2935
2936      return new;
2937    }
2938  return NULL;
2939}
2940
2941int isHexKey(char * s)
2942{
2943  int i;
2944 
2945  for (i = 0; i < KEY_LEN; ++i)
2946    {
2947      if (*s)
2948        {
2949          if ((*s >= '0' && *s <= '9') ||
2950              (*s >= 'A' && *s <= 'F') ||
2951              (*s >= 'a' && *s <= 'f'))
2952            {
2953              ++s;
2954              continue;
2955            }
2956        }
2957      return S_FALSE;
2958    }
2959  return S_TRUE;
2960}
2961 
2962#include "sh_checksum.h"
2963
2964static char * KEYBUFtolower (char * s, char * result)
2965{
2966  char * r = result;
2967  if (s)
2968    {
2969      for (; *s; ++s)
2970        { 
2971          *r = tolower((unsigned char) *s); ++r;
2972        }
2973      *r = '\0';
2974    }
2975  return result;
2976}
2977
2978void sh_hash_list_db_entry_full_detail (sh_file_t * p)
2979{
2980  char * tmp;
2981  char * esc;
2982  char   str[81];
2983  char   hexdigest[SHA256_DIGEST_STRING_LENGTH];
2984  char   keybuffer[KEYBUF_SIZE];
2985
2986  if (ListWithDelimiter == S_TRUE)
2987    {
2988      printf(_("%7ld, %7ld, %10s, %5d, %12s, %5d, %3d, %-8s, %5d, %-8s, %5d, "),
2989             (unsigned long) p->theFile.ino, (unsigned long) p->theFile.dev,
2990             p->theFile.c_mode, (int) p->theFile.mode,
2991             p->theFile.c_attributes, (int) p->theFile.attributes,
2992             (int) p->theFile.hardlinks,
2993             p->theFile.c_owner, (int) p->theFile.owner, 
2994             p->theFile.c_group, (int) p->theFile.group);
2995    }
2996  else
2997    {
2998      printf(_("%7ld %7ld %10s %5d %12s %5d %3d %-8s %5d %-8s %5d "),
2999             (unsigned long) p->theFile.ino, (unsigned long) p->theFile.dev,
3000             p->theFile.c_mode, (int) p->theFile.mode,
3001             p->theFile.c_attributes, (int) p->theFile.attributes,
3002             (int) p->theFile.hardlinks,
3003             p->theFile.c_owner, (int) p->theFile.owner, 
3004             p->theFile.c_group, (int) p->theFile.group);
3005    }
3006
3007  if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
3008    sl_snprintf(str, sizeof(str), "%"PRIu64, p->theFile.rdev);
3009  else
3010    sl_snprintf(str, sizeof(str), "%"PRIu64, p->theFile.size);
3011
3012  printf( _(" %8s"), str);
3013  if (ListWithDelimiter == S_TRUE)
3014    putchar(',');
3015
3016  printf( _(" %s"), sh_unix_gmttime (p->theFile.ctime, str, sizeof(str)));
3017  if (ListWithDelimiter == S_TRUE)
3018    putchar(',');
3019  printf( _(" %s"), sh_unix_gmttime (p->theFile.mtime, str, sizeof(str)));
3020  if (ListWithDelimiter == S_TRUE)
3021    putchar(',');
3022  printf( _(" %s"), sh_unix_gmttime (p->theFile.atime, str, sizeof(str)));
3023  if (ListWithDelimiter == S_TRUE)
3024    putchar(',');
3025
3026  if (isHexKey(p->theFile.checksum))
3027    printf( _(" %s"), KEYBUFtolower(p->theFile.checksum, keybuffer));
3028  else
3029    printf( _(" %s"), SHA256_Base2Hex(p->theFile.checksum, hexdigest));
3030  if (ListWithDelimiter == S_TRUE)
3031    putchar(',');
3032
3033  tmp = sh_util_safe_name(p->fullpath);
3034  if (ListWithDelimiter != S_TRUE)
3035    {
3036      printf( _(" %s"), tmp);
3037    }
3038  else
3039    {
3040      esc = csv_escape(tmp);
3041      printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
3042      if (esc)
3043        SH_FREE(esc);
3044    }
3045  SH_FREE(tmp);
3046
3047  if ('l' == p->theFile.c_mode[0])
3048    {
3049      tmp = sh_util_safe_name(p->linkpath);
3050      if (ListWithDelimiter != S_TRUE)
3051        {
3052          printf(_(" -> %s"), tmp);
3053        }
3054      else
3055        {
3056          esc = csv_escape(tmp);
3057          printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
3058          if (esc)
3059            SH_FREE(esc);
3060        }
3061      SH_FREE(tmp);
3062    }
3063
3064  if (p->attr_string)
3065    {
3066      tmp = sh_util_safe_name(p->attr_string);
3067      if (ListWithDelimiter != S_TRUE) 
3068        {
3069          printf(_(" %s"), tmp);
3070        }
3071      else
3072        {
3073          esc = csv_escape(tmp);
3074          printf( _(" %s"), (esc != NULL) ? esc : _("(null)"));
3075          if (esc)
3076            SH_FREE(esc);
3077        }
3078      SH_FREE(tmp);
3079    }
3080  else
3081    {
3082      if (ListWithDelimiter == S_TRUE)
3083        printf("%s",_(" no_attr"));
3084    }
3085  putchar('\n');
3086
3087  return;
3088}
3089
3090void sh_hash_list_db_entry (sh_file_t * p)
3091{
3092  char nowtime[128];
3093  char thetime[128];
3094  char * tmp;
3095  time_t now  = time(NULL);
3096  time_t then = (time_t) p->theFile.mtime;
3097  struct tm   * time_ptr;
3098
3099#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
3100  struct tm     time_tm;
3101#endif
3102
3103  if (ListFullDetail != S_FALSE)
3104    {
3105      sh_hash_list_db_entry_full_detail (p);
3106      return;
3107    }
3108
3109#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
3110  time_ptr = gmtime_r(&then, &time_tm);
3111  if (!time_ptr)
3112    return;
3113  strftime(thetime, 127, _("%b %d  %Y"), time_ptr);
3114  time_ptr = gmtime_r(&now,  &time_tm);
3115  if (!time_ptr)
3116    return;
3117  strftime(nowtime, 127, _("%b %d  %Y"), time_ptr);
3118  if (0 == strncmp(&nowtime[7], &thetime[7], 4))
3119    {
3120      time_ptr = gmtime_r(&then, &time_tm);
3121      if (!time_ptr)
3122        return;
3123      strftime(thetime, 127, _("%b %d %H:%M"), time_ptr);
3124    }
3125#else
3126  time_ptr = gmtime(&then);
3127  if (!time_ptr)
3128    return;
3129  strftime(thetime, 127, _("%b %d  %Y"), time_ptr);
3130  time_ptr = gmtime(&now);
3131  if (!time_ptr)
3132    return;
3133  strftime(nowtime, 127, _("%b %d  %Y"), time_ptr);
3134  if (0 == strncmp(&nowtime[7], &thetime[7], 4))
3135    {
3136      time_ptr = gmtime(&then);
3137      if (!time_ptr)
3138        return;
3139      strftime(thetime, 127, _("%b %d %H:%M"), time_ptr);
3140    }
3141#endif
3142
3143  tmp = sh_util_safe_name(p->fullpath);
3144  if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
3145    printf(_("%10s %3d %-8s %-8s %3d,%4d %s %s"),
3146           p->theFile.c_mode, (int) p->theFile.hardlinks,
3147           p->theFile.c_owner, p->theFile.c_group, 
3148           (int) major((dev_t)p->theFile.rdev), 
3149           (int) minor((dev_t)p->theFile.rdev),
3150           thetime, 
3151           tmp);
3152  else
3153    printf(_("%10s %3d %-8s %-8s %8ld %s %s"),
3154           p->theFile.c_mode, (int) p->theFile.hardlinks,
3155           p->theFile.c_owner, p->theFile.c_group, (long) p->theFile.size,
3156           thetime, 
3157           tmp);
3158  SH_FREE(tmp);
3159
3160  if ('l' == p->theFile.c_mode[0])
3161    {
3162      tmp = sh_util_safe_name(p->linkpath);
3163      printf(_(" -> %s\n"), tmp);
3164      SH_FREE(tmp);
3165    }
3166  else
3167    printf("\n");
3168         
3169  return;
3170}
3171
3172#ifdef HAVE_LIBZ
3173#include <zlib.h>
3174#endif   
3175
3176int sh_hash_printcontent(char * linkpath)
3177{
3178#ifdef HAVE_LIBZ
3179  unsigned char * decoded;
3180  unsigned char * decompressed = NULL;
3181  size_t dlen;
3182  unsigned long clen;
3183  unsigned long clen_o;
3184  int    res;
3185
3186  if (linkpath && *linkpath != '-')
3187    {
3188      dlen = sh_util_base64_dec_alloc (&decoded, 
3189                                       (unsigned char *)linkpath, 
3190                                       strlen(linkpath));
3191
3192      clen = dlen * 2 + 1;
3193
3194      do {
3195        if (decompressed)
3196          SH_FREE(decompressed);
3197        clen += dlen; clen_o = clen;
3198        decompressed = SH_ALLOC(clen);
3199        res = uncompress(decompressed, &clen, decoded, dlen);
3200        if (res == Z_MEM_ERROR)
3201          { fprintf(stderr, "%s",_("Error: Not enough memory\n")); return -1; }
3202        if (res == Z_DATA_ERROR)
3203          { fprintf(stderr, "%s",_("Error: Data corrupt or incomplete\n")); return -1; }
3204      } while (res == Z_BUF_ERROR || clen == clen_o);
3205
3206      decompressed[clen] = '\0';
3207      fputs( (char*) decompressed, stdout);
3208      SH_FREE(decompressed);
3209      return 0;
3210    }
3211#else
3212  (void) linkpath;
3213#endif
3214  fprintf(stderr, "%s",_("Error: No data available\n")); 
3215  return -1;
3216}
3217
3218/* if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
3219#endif
Note: See TracBrowser for help on using the repository browser.