source: trunk/src/sh_dbIO.c @ 483

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

Fix for ticket #381 (BSD suid check compile failure).

File size: 41.1 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 2015 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 <stdio.h>
23#include <string.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27
28#include "samhain.h"
29#include "sh_utils.h"
30#include "sh_dbIO_int.h"
31#include "sh_hash.h"
32#include "sh_dbIO.h"
33#include "sh_gpg.h"
34#include "sh_tiger.h"
35#include "sh_xfer.h"
36#include "sh_pthread.h"
37#include "sh_socket.h"
38#include "sh_files.h"
39
40#undef  FIL__
41#define FIL__  _("sh_dbIO.c")
42
43#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
44
45/* external prototypes                                                     */
46
47extern int get_the_fd (SL_TICKET ticket);
48
49SH_MUTEX_EXTERN(mutex_hash);
50
51/******************************************************************
52 *
53 * Get a single line
54 *
55 ******************************************************************/
56static FILE * sh_fin_fd = NULL;
57
58int sh_dbIO_getline (FILE * fd, char * line, const size_t sizeofline)
59{
60  size_t  n = 0;
61
62  SL_REQUIRE(sizeofline >= SH_MINIBUF, _("sizeofline >= SH_MINIBUF"));
63
64  if (NULL != fgets(line, sizeofline, fd))
65    {
66      n = strlen(line);
67      if (n > 0 && line[n-1] == '\n') {
68        n--; line[n] = '\0';
69      }
70    } 
71  else {
72    line[0] = '\0';
73    return -1;
74  }
75
76  return n;
77}
78
79/******************************************************************
80 *
81 * Fast forward to start of data
82 *
83 ******************************************************************/
84
85static void reopen_fin_fd(SL_TICKET fd)
86{
87  if (sh_fin_fd != NULL)
88    {
89      sl_fclose (FIL__, __LINE__, sh_fin_fd);
90      sh_fin_fd = NULL;
91    }
92
93  sh_fin_fd = fdopen(dup(get_the_fd(fd)), "rb");
94  return;
95}
96
97
98static int seek_sof(FILE * fd, char * line, int size, const char * file)
99{
100  long i;
101
102  while (1) 
103    {
104      i =  sh_dbIO_getline (fd, line, size);
105      if (i < 0 ) 
106        {
107          SH_FREE(line);
108          dlog(1, FIL__, __LINE__, 
109               _("The file signature database: %s does not\ncontain any data, or the start-of-file marker is missing (unlikely,\nunless modified by hand).\n"),
110               (NULL == file) ? _("(null)") : file);
111               
112          sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
113                           ( (NULL == file) ? _("(null)") : file)
114                           );
115          return -1;
116        }
117
118#if defined(SH_STEALTH)
119      if (0 == sl_strncmp (line, N_("[SOF]"), 5)) 
120#else
121      if (0 == sl_strncmp (line, _("[SOF]"),  5)) 
122#endif
123        break;
124    }
125  fflush(fd);
126  return 0;
127}
128
129static int sh_dbIO_setdataent (SL_TICKET fd, char * line, int size, 
130                               const char * file)
131{
132  int retval;
133
134  SL_ENTER(_("sh_dbIO_setdataent"));
135
136  sl_rewind (fd);
137  reopen_fin_fd(fd);
138
139  if (!sh_fin_fd)
140    {
141      dlog(1, FIL__, __LINE__, 
142           _("The file signature database: %s is not readable.\n"),
143           (NULL == file) ? _("(null)") : file);
144      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
145                       ( (NULL == file) ? _("(null)") : file)
146                       );
147      SL_RETURN( -1, _("sh_dbIO_setdataent"));
148    }
149
150  retval = seek_sof(sh_fin_fd, line, size, file);
151  SL_RETURN( retval, _("sh_dbIO_setdataent"));
152}
153
154static int sh_dbIO_setdataent_old (SL_TICKET fd, char * line, int size, 
155                                   const char * file)
156{
157  FILE * fdp;
158
159  SL_ENTER(_("sh_dbIO_setdataent_old"));
160
161  sl_rewind (fd);
162  fdp = sl_stream(fd, "r+");
163  if (0 != seek_sof(fdp, line, size, file))
164    SL_RETURN( SL_EREAD, _("sh_dbIO_setdataent_old"));
165  if (0 != ftruncate(fileno(fdp), ftello(fdp)))
166    {
167      char ebuf[SH_ERRBUF_SIZE];
168      int errnum = errno;
169      sh_error_message(errnum, ebuf, sizeof(ebuf));
170      sh_error_handle ((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN,
171                       ebuf, _("sh_dbIO_setdataent_old") );
172      SL_RETURN( SL_EWRITE, _("sh_dbIO_setdataent_old"));
173    }
174  SL_RETURN( 0, _("sh_dbIO_setdataent_old"));
175}
176
177/******************************************************************
178 *
179 * IO helper functions
180 *
181 ******************************************************************/
182
183
184static UINT32 * swap_32 (UINT32 * iptr)
185{
186#ifdef WORDS_BIGENDIAN
187  unsigned char swap;
188  unsigned char * ii = (unsigned char *) iptr;
189  swap = ii[0]; ii[0] = ii[3]; ii[3] = swap;
190  swap = ii[1]; ii[1] = ii[2]; ii[2] = swap;
191  return iptr;
192#else
193  return iptr;
194#endif
195}
196
197static UINT64 *  swap_64 (UINT64 * iptr)
198{
199#ifdef WORDS_BIGENDIAN
200#ifdef UINT64_IS_32
201  swap_32 ((UINT32*) iptr);
202#else
203  unsigned char swap;
204  unsigned char * ii = (unsigned char *) iptr;
205  swap = ii[0]; ii[0] = ii[7]; ii[7] = swap;
206  swap = ii[1]; ii[1] = ii[6]; ii[6] = swap;
207  swap = ii[2]; ii[2] = ii[5]; ii[5] = swap;
208  swap = ii[3]; ii[3] = ii[4]; ii[4] = swap;
209#endif
210  return iptr;
211#else
212  return iptr;
213#endif
214}
215
216static unsigned short *  swap_short (unsigned short * iptr)
217{
218#ifdef WORDS_BIGENDIAN
219  if (sizeof(short) == 4)
220    swap_32 ((UINT32*) iptr);
221  else
222    {
223      /* alignment problem */
224      unsigned char swap;
225      static unsigned short ooop;
226      unsigned char * ii;
227      ooop = *iptr;
228      ii = (unsigned char *) &ooop;
229      swap = ii[0]; ii[0] = ii[1]; ii[1] = swap;
230      return &ooop;
231    }
232  return iptr;
233#else
234  return iptr;
235#endif
236}
237
238static void swap_data(sh_filestore_t * ft)
239{
240  swap_32(&(ft->mode));
241  swap_32(&(ft->linkmode));
242  swap_64(&(ft->dev));
243  swap_64(&(ft->rdev));
244  swap_32(&(ft->hardlinks));
245  swap_32(&(ft->ino));
246  swap_64(&(ft->size));
247  swap_64(&(ft->atime));
248  swap_64(&(ft->mtime));
249  swap_64(&(ft->ctime));
250  swap_32(&(ft->owner));
251  swap_32(&(ft->group));
252  swap_32(&(ft->checkflags));
253#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
254  swap_32(&(ft->attributes));
255#endif
256  ft->mark = *(swap_short(&(ft->mark)));
257  return;
258}
259
260#define QUOTE_CHAR '='
261
262char * unquote_string (const char * str, size_t len)
263{
264  int    i = 0, t1, t2;
265  char * tmp = NULL;
266  size_t l2, j, k = 0;
267
268  SL_ENTER(_("unquote_string"));
269
270  if (str != NULL)
271    {
272      l2  = len - 2;
273      tmp = SH_ALLOC(len + 1);
274
275      for (j = 0; j <= len; ++j)
276        {
277          if (str[j] != QUOTE_CHAR)
278            {
279              tmp[k] = str[j];
280            }
281          else if (str[j] == QUOTE_CHAR && j < l2)
282            {
283              t1 = sh_util_hexchar(str[j+1]);
284              t2 = sh_util_hexchar(str[j+2]);
285              if ((t1|t2) >= 0)
286                {
287                  i = 16 * t1 + t2;
288                  tmp[k] = i; 
289                  j += 2;
290                }
291              else
292                {
293                  tmp[k] = str[j];
294                }
295            }
296          else
297            tmp[k] = str[j];
298          ++k;
299        }
300    }
301  SL_RETURN(tmp, _("unquote_string"));
302}
303
304static char * int2hex (unsigned char i, char * i2h)
305{
306  static char hexchars[] = "0123456789ABCDEF";
307
308  i2h[0] = hexchars[(((i) & 0xF0) >> 4)]; /* high */
309  i2h[1] = hexchars[((i) & 0x0F)];        /* low  */
310
311  return i2h;
312}
313
314char * quote_string (const char * str, size_t len)
315{
316  char * tmp;
317  char * tmp2;
318  size_t l2, j, i = 0, k = 0;
319  char   i2h[2];
320
321  SL_ENTER(_("quote_string"));
322
323  if (str == NULL)
324    {
325      SL_RETURN(NULL, _("quote_string"));
326    }
327
328  for (j = 0; j < len; ++j)
329    if (str[j] == '\n' || str[j] == QUOTE_CHAR) ++i;
330
331  l2 = len + 1;
332  if (sl_ok_muls(3, i) && sl_ok_adds(l2, (3*i)))
333    {
334      tmp = SH_ALLOC(len + 1 + 3*i);
335    }
336  else
337    {
338      sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
339                      _("integer overflow"), 
340                      _("quote_string"));
341      SL_RETURN(NULL, _("quote_string"));
342    }
343
344  for (j = 0; j <= len; ++j)
345    {
346      if (str[j] == '\n')
347        {
348          tmp2 = int2hex((unsigned char) '\n', i2h);
349          tmp[k] = QUOTE_CHAR; ++k;
350          tmp[k] = tmp2[0];    ++k;
351          tmp[k] = tmp2[1];
352        }
353      else if (str[j] == QUOTE_CHAR)
354        {
355          tmp2 = int2hex((unsigned char) QUOTE_CHAR, i2h);
356          tmp[k] = QUOTE_CHAR; ++k;
357          tmp[k] = tmp2[0];    ++k;
358          tmp[k] = tmp2[1];
359        }
360      else
361        {
362          tmp[k] = str[j];
363        }
364      ++k;
365    }
366  SL_RETURN(tmp, _("quote_string"));
367}
368
369static char * unquote_path(char * line, long i)
370{
371  char * tmp  = unquote_string (line, i);
372  size_t len  = sl_strlen(tmp)+1;
373  char * path = SH_ALLOC(len);
374
375  (void) sl_strlcpy (path, tmp, len);
376  if (tmp)
377    SH_FREE(tmp);
378  if (len > 1) {
379    if (path[len-2] == '\n')
380      path[len-2] = '\0';
381  }
382  return path;
383}
384
385/******************************************************************
386 *
387 * Read next record and return it
388 *
389 ******************************************************************/
390
391static void corrupt_record(char * file, int line, const char * filepath)
392{
393  dlog(1, file, line, 
394       _("There is a corrupt record in the file signature database: %s\n"),
395       (NULL == filepath)? _("(null)") : filepath);
396  sh_error_handle ((-1), file, line, 0, MSG_E_SUBGPATH,
397                   _("Corrupt record in file signature database"), 
398                   _("sh_dbIO_getdataent"),
399                   ( (NULL == filepath) ? _("(null)") : filepath) );
400  return;
401}
402
403static void wrong_version(char * file, int line, const char * filepath)
404{
405  dlog(1, file, line, 
406       _("There is a record with a bad version number in the file signature database: %s\n"),
407       (NULL == filepath) ? _("(null)") : filepath);
408  sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH,
409                  _("Record with bad version number in file signature database"), 
410                  _("sh_dbIO_getdataent"),
411                  (NULL == filepath) ? _("(null)") : filepath);
412  return;
413}
414
415static void hexdump(unsigned char * data, size_t size)
416{
417  unsigned int count =0;
418  char ith[3];
419
420  do {
421    int2hex(data[count], ith); ith[2] = '\0';
422    printf("%2s", ith);
423    ++count;
424    if (count % 40 == 0) putc('\n', stdout);
425  } while (count < size);
426}
427
428static size_t dbIO_fread_struct (sh_filestore_t * ptr, FILE *stream, 
429                                 const char * path, int * errflag)
430{
431  sh_filestore_old_t old_struct;
432  fpos_t position;
433  static int oldflag = -1;
434
435 start:
436  if (oldflag != -1) /* 'initialized' case first */
437    {
438      if (oldflag == 0)
439        return fread (ptr, sizeof(sh_filestore_t), 1, stream);
440
441      else
442        {
443          unsigned short mark;
444          if (1 != fread (&old_struct, sizeof(old_struct), 1, stream))
445            return 0;
446
447          /* set mark to current version */
448          mark = old_struct.mark;
449          mark = *(swap_short(&(mark)));
450          if ((mark & ~REC_FLAGS_MASK) != OLD_REC_MAGIC)
451            {
452              sh_filestore_old_t try_struct;
453              char try[5];
454
455              if (1 == 0)
456                hexdump((unsigned char *)&old_struct, sizeof(old_struct));
457              memset(&try_struct, '\0', sizeof(try_struct));
458              if (!memcmp(&old_struct, &try_struct, sizeof(try_struct)))
459                return 0; /* NULL read */
460              if (1 != fread (try, sizeof(try), 1, stream))
461                return 0;
462              if (feof(stream))
463                return 0;
464
465              wrong_version(FIL__, __LINE__, path);
466              *errflag = -1;
467              return 0;
468            }
469          if ((mark & REC_FLAGS_ATTR) != 0)
470            mark = REC_MAGIC|REC_FLAGS_ATTR;
471          else
472            mark = REC_MAGIC;
473          mark = *(swap_short(&(mark)));
474          old_struct.mark = mark;
475
476          /* copy into current struct version */
477          memcpy(ptr, &old_struct, sizeof(old_struct));
478          ptr->checkflags = 0;
479          return 1;
480        }
481    }
482  else /* not initialized yet, test DB version */
483    {
484      if (0 == fgetpos(stream, &position))
485        {
486          unsigned short mark;
487
488          if (1 != fread (&old_struct, sizeof(old_struct), 1, stream))
489            return 0;
490
491          mark = old_struct.mark;
492          mark = *(swap_short(&(mark)));
493          if ((mark & ~REC_FLAGS_MASK) == REC_MAGIC)
494            oldflag = 0;
495          else if ((mark & ~REC_FLAGS_MASK) == OLD_REC_MAGIC)
496            oldflag = 1;
497          else
498            {
499              wrong_version(FIL__, __LINE__, path);
500              *errflag = -1;
501              return 0;
502            }
503
504          /* return to previous position and read data */
505          if (0 != fsetpos(stream, &position))
506            return 0;
507          goto start;
508        }
509      return 0;
510    }
511}
512
513int sig_end_detected (void * ft)
514{
515  char * str = (char *) ft;
516  char cmp[SH_MINIBUF];
517
518  sl_strlcpy(cmp, _("-----BEGIN PGP SIGNATURE-----"), sizeof(cmp));
519
520  if ( 0 == memcmp(str, cmp, strlen(cmp)) ) 
521    return S_TRUE;
522  return S_FALSE;
523}
524
525static sh_file_t *  sh_dbIO_getdataent (char * line, int size, 
526                                        const char * filepath, int * errflag)
527{
528  sh_file_t * p;
529  sh_filestore_t ft;
530  long i;
531  char * fullpath;
532  char * linkpath;
533  char * attr_string = NULL;
534
535  SL_ENTER(_("sh_dbIO_getdataent"));
536
537  *errflag = 0;
538
539  p = SH_ALLOC(sizeof(sh_file_t));
540
541  /* Read next record -- Part One
542   */
543  if (1 != dbIO_fread_struct (&ft, sh_fin_fd, filepath, errflag))
544    {
545      SH_FREE(p);
546      SL_RETURN( NULL, _("sh_dbIO_getdataent"));
547    }
548
549  ft.mark = *(swap_short(&(ft.mark)));
550
551  if ((ft.mark & ~REC_FLAGS_MASK) != REC_MAGIC)
552    {
553      if (sig_end_detected(&ft))
554        {
555          SH_FREE(p);
556          SL_RETURN( NULL, _("sh_dbIO_getdataent"));
557        }
558      SH_FREE(p);
559      wrong_version(FIL__, __LINE__, filepath);
560      *errflag = -1;
561      SL_RETURN( NULL, _("sh_dbIO_getdataent"));
562    }
563
564  ft.mark = *(swap_short(&(ft.mark)));
565  swap_data(&ft);
566
567  /* Read next record -- Part Two -- Fullpath
568   */
569  i = sh_dbIO_getline (sh_fin_fd, line, size);
570
571  if (i <= 0 ) 
572    {
573      SH_FREE(p);
574      corrupt_record(FIL__, __LINE__, filepath);
575      *errflag = -1;
576      SL_RETURN( NULL, _("sh_dbIO_getdataent"));
577    }
578
579  fullpath = unquote_path(line, i);
580
581  /* Read next record -- Part Three -- Linkpath
582   */
583  i =  sh_dbIO_getline (sh_fin_fd, line, size);
584
585  if (i <= 0 ) 
586    {
587      SH_FREE(fullpath); SH_FREE(p);
588      corrupt_record(FIL__, __LINE__, filepath);
589      *errflag = -1;
590      SL_RETURN( NULL, _("sh_dbIO_getdataent"));
591    }
592
593  linkpath = unquote_path(line, i);
594
595  /* Read next record -- Part Four -- attr_string
596   */
597  if ((ft.mark & REC_FLAGS_ATTR) != 0)
598    {
599      i =  sh_dbIO_getline (sh_fin_fd, line, size);
600      if (i <= 0 ) 
601        {
602          SH_FREE(fullpath); SH_FREE(linkpath); SH_FREE(p);
603          corrupt_record(FIL__, __LINE__, filepath);
604          *errflag = -1;
605          SL_RETURN( NULL, _("sh_dbIO_getdataent"));
606        }
607
608      attr_string = unquote_path(line, i);
609    }
610
611  /* Read next record -- Part Four -- Decode
612   */
613#if defined(SH_STEALTH)
614  sh_do_decode(fullpath,    sl_strlen(fullpath));
615#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
616  sh_do_decode(ft.c_attributes,   sl_strlen(ft.c_attributes));
617#endif
618  sh_do_decode(ft.c_mode,   sl_strlen(ft.c_mode));
619  sh_do_decode(ft.c_owner,  sl_strlen(ft.c_owner));
620  sh_do_decode(ft.c_group,  sl_strlen(ft.c_group));
621  sh_do_decode(ft.checksum, sl_strlen(ft.checksum)); 
622  /*
623   * TXT entries are c_mode[0] != 'l' and do not get decoded
624   */
625  if (ft.c_mode[0] == 'l' && linkpath[0] != '-')
626    { 
627      sh_do_decode(linkpath, sl_strlen(linkpath));
628    }
629  if ((ft.mark & REC_FLAGS_ATTR) != 0)
630    { 
631      sh_do_decode(attr_string, sl_strlen(attr_string));
632    }
633#endif
634
635  memcpy( &(*p).theFile, &ft, sizeof(sh_filestore_t) );
636
637  /* init fflags, such that suid files in
638   * database are recognized as such
639   */
640  {
641    mode_t mode = (mode_t) ft.mode;
642
643    if (S_ISREG(mode) &&
644        (0 !=(S_ISUID & mode) ||
645#if defined(HOST_IS_LINUX)
646         (0 !=(S_ISGID & mode) && 
647          0 !=(S_IXGRP & mode)) 
648#else 
649         0 !=(S_ISGID & mode)
650#endif
651         )
652        )
653      p->fflags = SH_FFLAG_SUIDCHK;
654
655    else
656      p->fflags = 0;
657  }
658
659  p->modi_mask   = ft.checkflags;
660  if (MODI_ISSET(ft.checkflags, MODI_ALLIGNORE))
661    SET_SH_FFLAG_ALLIGNORE(p->fflags);
662  p->fullpath    = fullpath;
663  p->linkpath    = linkpath;
664  p->attr_string = attr_string;
665
666  /* set to an invalid value
667   */
668  ft.mark = (REC_MAGIC + 5);
669
670  SL_REQUIRE((*errflag == 0), _("errflag not set correctly"));
671  SL_RETURN( p, _("sh_dbIO_getdataent"));
672}
673
674/******************************************************************
675 *
676 * Data loading routines
677 *
678 ******************************************************************/
679static SL_TICKET load_data_from_server(const char * uuid)
680{
681  SL_TICKET fd = -1;
682
683#if defined(SH_WITH_CLIENT)
684  char hashbuf[KEYBUF_SIZE];
685
686  /* Data file from Server
687   */
688  if (0 != sl_strcmp(file_path('D', 'R'), _("REQ_FROM_SERVER")))
689    return -1;
690
691  sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_D_DSTART);
692  fd = sh_xfer_request_file((!uuid) ? _("DATA") : uuid);
693
694  if (SL_ISERROR(fd))
695    {
696      if (!uuid)
697        {
698          sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_FBAD);
699          dlog(1, FIL__, __LINE__, 
700               _("Could not retrieve the file signature database from the server(errnum = %ld).\nPossible reasons include:\n - the server is not running,\n - session key negotiation failed (see the manual for proper setup), or\n - the server cannot access the file.\n"), fd); 
701        }
702      else
703        sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_TCP_FBAD);
704      return fd;
705    }
706  sl_rewind (fd);
707
708  if (!uuid)
709    {
710      sl_strlcpy (sh.data.hash, 
711                  sh_tiger_hash (file_path('D', 'R'), 
712                                 fd, TIGER_NOLIM, hashbuf, sizeof(hashbuf)),
713                  KEY_LEN+1);
714      sl_rewind (fd);
715    }
716#else
717  (void) uuid;
718#endif
719  return fd;
720}
721
722static SL_TICKET load_data_from_disk(const char * filepath)
723{
724  char hashbuf[KEYBUF_SIZE];
725  SL_TICKET fd = -1;
726
727  /* Local data file
728   */
729  if ( SL_ISERROR(fd = sl_open_read(FIL__, __LINE__, filepath, SL_YESPRIV)) )
730    {
731      TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s>\n"), filepath));
732      dlog(1, FIL__, __LINE__, 
733    _("Could not open the local file signature database for reading because\nof the following error: %s (errnum = %ld)\nIf this is a permission problem, you need to change file permissions\nto make the file readable for the effective UID: %d\n"), 
734           sl_get_errmsg(), fd, (int) sl_ret_euid());
735      sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_EXIT_ABORT1, 
736                       sh.prg_name);
737      return -1;
738    }
739 
740  TPT(( 0, FIL__, __LINE__, _("msg=<Opened database: %s>\n"), 
741        filepath));
742
743  if (sh.data.hash[0] == '\0')
744    {
745      char hashbuf[KEYBUF_SIZE];
746      sl_strlcpy(sh.data.hash, 
747                 sh_tiger_hash (filepath, TIGER_FILE, TIGER_NOLIM, hashbuf, sizeof(hashbuf)), 
748                 KEY_LEN+1);
749    }
750  else
751    {
752      if (0 != sl_strncmp(sh.data.hash, 
753                          sh_tiger_hash (filepath, fd, TIGER_NOLIM, 
754                                         hashbuf, sizeof(hashbuf)),
755                          KEY_LEN)
756          && sh.flag.checkSum != SH_CHECK_INIT) 
757        {
758          dlog(1, FIL__, __LINE__, 
759               _("The checksum of the file signature database has changed since startup: %s -> %s\n"),
760               sh.data.hash, sh_tiger_hash (filepath, fd, TIGER_NOLIM, 
761                                            hashbuf, sizeof(hashbuf)));
762          sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_AUTH,
763                           ( (NULL == filepath) ? _("(null)") :
764                             filepath )
765                           );
766        }
767    }
768  sl_rewind (fd);
769  return fd;
770}
771
772static SL_TICKET verify_data (SL_TICKET fd)
773{
774#if defined(WITH_GPG) || defined(WITH_PGP)
775  SL_TICKET fdTmp;
776
777  /* extract the data and copy to temporary file
778   */
779  fdTmp = sh_gpg_extract_signed(fd);
780
781  if (sig_termfast == 1)  /* SIGTERM */
782    {
783      TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
784      --sig_raised; --sig_urgent;
785      return -1;
786    }
787
788  sl_close(fd);
789  fd = fdTmp;
790
791  /* Validate signature of open file.
792   */
793  if (0 != sh_gpg_check_sign (fd, SIG_DATA))
794    {
795      sl_close(fd);
796      return -1;
797    }
798  sl_rewind (fd);
799#endif
800
801  return fd;
802}
803
804static int read_data(SL_TICKET fd, sh_file_t * tab[TABSIZE], 
805                     const char * filepath)
806{
807  sh_file_t * p;
808  int count = 0;
809  int errflag = 0;
810  char * line = SH_ALLOC(MAX_PATH_STORE+2);
811
812  /* fast forward to start of data
813   */
814  if (0 != sh_dbIO_setdataent(fd, line, MAX_PATH_STORE+1, filepath))
815    return -1;
816
817  while (1) 
818    {
819      if (sig_termfast == 1)  /* SIGTERM */
820        {
821          TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
822          --sig_raised; --sig_urgent;
823          SH_FREE(line);
824          return -1;
825        }
826
827      p = sh_dbIO_getdataent (line, MAX_PATH_STORE+1, filepath, &errflag);
828      if (p != NULL)
829        {
830          if (!sh_hash_is_null_record(&(p->theFile)))
831            hashinsert (tab, p);
832          else
833            sh_hash_remove_unconditional (p->fullpath);
834          ++count;
835        }
836      else
837        break;
838    }
839
840  if (line != NULL)
841    SH_FREE(line);
842
843  /* Always keep db in memory, so we have no open file
844   */
845  sl_close (fd);
846
847  sl_fclose (FIL__, __LINE__, sh_fin_fd);
848  sh_fin_fd = NULL;
849
850  return errflag;
851}
852
853
854static int sh_dbIO_load_db_int(sh_file_t * tab[TABSIZE], 
855                               const char * filepath, const char * uuid)
856{
857#define FGETS_BUF 16384
858
859  SL_TICKET fd = -1;
860
861  if (uuid)
862    {
863      fd = load_data_from_server(uuid);
864      if (SL_ISERROR(fd))
865        return -1;
866    }
867  else if (!filepath)
868    {
869      char * dbpath = file_path('D', 'R');
870
871      fd = load_data_from_server(NULL);
872
873      if (SL_ISERROR(fd))
874        {
875          if (*dbpath == '/')
876            fd = load_data_from_disk(dbpath);
877        }
878    }
879  else
880    {
881      fd = load_data_from_disk(filepath);
882    }
883
884  if (SL_ISERROR(fd))
885    return -1;
886
887  if (sig_termfast == 1)  /* SIGTERM */
888    {
889      TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
890      --sig_raised; --sig_urgent;
891      aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
892    }
893
894  fd = verify_data(fd);
895  if (SL_ISERROR(fd))
896    return -1;
897
898  if (!uuid) { int i; for (i = 0; i < TABSIZE; ++i) tab[i] = NULL; }
899
900  return read_data (fd, tab, filepath);
901}
902
903
904int sh_dbIO_load_db(sh_file_t * tab[TABSIZE])
905{
906  return sh_dbIO_load_db_int(tab, NULL, NULL);
907}
908int sh_dbIO_load_db_file(sh_file_t * tab[TABSIZE], const char * filepath)
909{
910  return sh_dbIO_load_db_int(tab, filepath, NULL);
911}
912
913int sh_dbIO_load_delta()
914{
915  int    status = 0;
916#if defined(SH_WITH_CLIENT)
917  sh_file_t ** mtab = get_default_data_table();
918  int errflag = 0;
919  unsigned int count;
920  time_t last;
921
922  if ( sh.flag.checkSum != SH_CHECK_INIT )
923    {
924      if (sh_hash_get_initialized() != 0)
925        {
926          char * uuid = sh_socket_get_uuid(&errflag, &count, &last);
927
928          if (!uuid) 
929            return errflag;
930
931          if (count > 0)
932            sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, count, MSG_E_SUBGEN,
933                          _("Retrying download of delta DB"), 
934                          _("sh_dbIO_load_delta"));
935
936          status = sh_dbIO_load_db_int(mtab, NULL, uuid);
937          if (status < 0)
938            {
939              /* Return status < 0 indicates that max_try is exceeded
940               */
941              if (sh_socket_return_uuid(uuid, count, last) < 0)
942                sh_error_handle((-1), FIL__, __LINE__, -1, MSG_D_DELTAFAIL, uuid);
943            }
944          else
945            {
946              sh_error_handle((-1), FIL__, __LINE__, -1, MSG_D_DELTAOK, uuid);
947            }
948          SH_FREE(uuid);
949        }
950      else
951        {
952          /* not initialized yet */
953          sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, -1, MSG_E_SUBGEN,
954                          _("Download of delta DB skipped, not initialized yet"), 
955                          _("sh_dbIO_load_delta"));
956          return -1;
957        }
958    }
959#endif
960  return status;
961}
962
963/******************************************************************
964 *
965 * Writing out a file to the database.
966 *
967 ******************************************************************/ 
968static int       pushdata_isfirst =  1;
969static SL_TICKET pushdata_fd      = -1;
970
971static int       pushdata_stdout  =  S_FALSE;
972
973static char * sh_db_version_string = NULL;
974
975int sh_dbIO_writeout_stdout (const char * str)
976{
977  if (!str)
978    { pushdata_stdout  =  S_TRUE; return 0; }
979  return -1;
980}
981
982int sh_dbIO_version_string(const char * str)
983{
984  if (str)
985    {
986      if (sh_db_version_string != NULL) {
987        SH_FREE(sh_db_version_string);
988      }
989      if (0 == sl_strncmp(str, _("NULL"), 4))
990        {
991          sh_db_version_string = NULL;
992          return 0;
993        }
994      sh_db_version_string = sh_util_strdup(str);
995      return 0;
996    }
997  return -1;
998}
999
1000void do_writeout_checks(const char * outpath)
1001{
1002  if ((pushdata_stdout == S_TRUE) && (sh.flag.update == S_TRUE))
1003    {
1004      dlog(1, FIL__, __LINE__, 
1005           _("You cannot write the database to stdout when you use update rather than init.\n"));
1006      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
1007                      _("Writing database to stdout with update"), 
1008                      sh.prg_name, 
1009                      _("sh_dbIO_data_write_int"));
1010      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1011    }
1012
1013  if ((pushdata_stdout == S_TRUE) && (sl_is_suid()))
1014    {
1015      dlog(1, FIL__, __LINE__, 
1016           _("You cannot write the database to stdout when running with suid privileges.\n"));
1017      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
1018                      _("Writing database to stdout when suid"), 
1019                      sh.prg_name, 
1020                      _("sh_dbIO_data_write_int"));
1021      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1022    }
1023
1024
1025  if ( (pushdata_isfirst == 1) && (pushdata_stdout == S_FALSE) && 
1026       ( (NULL == outpath) || (0 == sl_strcmp(outpath, _("REQ_FROM_SERVER"))) ) )
1027    {
1028      dlog(1, FIL__, __LINE__, 
1029           _("You need to configure a local path for initializing the database\nlike ./configure --with-data-file=REQ_FROM_SERVER/some/local/path\n"));
1030      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
1031                      _("No local path for database specified"), 
1032                      sh.prg_name, 
1033                      _("sh_dbIO_data_write_int"));
1034      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1035    }
1036
1037  if ((pushdata_isfirst == 1) && (pushdata_stdout == S_FALSE)) 
1038    {
1039      /* Warn that file already exists; file_path != NULL here because
1040       * checked above
1041       */
1042      struct stat sbuf;
1043
1044      if (0 == retry_lstat(FIL__, __LINE__, outpath, &sbuf))
1045        {
1046          if (sh.flag.update == S_FALSE)
1047            {
1048              sh_error_handle((-1), FIL__, __LINE__, 0, MSG_FI_DBEX,
1049                              file_path('D', 'W'));
1050            }
1051        }
1052    }
1053
1054  return;
1055}
1056
1057static SL_TICKET open_writeout_data_truncate(const char * path)
1058{
1059  int status;
1060  SL_TICKET fd;
1061
1062  if ( SL_ISERROR(fd = sl_open_rdwr_trunc(FIL__, __LINE__, path, SL_YESPRIV))) 
1063    {
1064      sh_error_handle((-1), FIL__, __LINE__, fd, MSG_E_ACCESS,
1065                      geteuid(), path);
1066      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1067    }
1068
1069  if (SL_ISERROR(status = sl_lock (fd)))
1070    {
1071      sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1072                      _("Failed to lock baseline database"), _("sh_dbIO_data_write_int"),
1073                      path);
1074      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1075    }
1076  return fd;
1077}
1078
1079static SL_TICKET open_writeout_data(const char * path)
1080{
1081  int status;
1082  SL_TICKET fd;
1083
1084  if ( SL_ISERROR(fd = sl_open_rdwr(FIL__, __LINE__, path, SL_YESPRIV))) 
1085    {
1086      sh_error_handle((-1), FIL__, __LINE__, fd, MSG_E_ACCESS,
1087                      geteuid(), path);
1088      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1089    }
1090
1091  if (SL_ISERROR(status = sl_lock (fd)))
1092    {
1093      sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1094                      _("Failed to lock baseline database"), _("sh_dbIO_data_write_int"),
1095                      path);
1096      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1097    }
1098  return fd;
1099}
1100
1101static void seek_writeout_data(SL_TICKET fd, const char * path)
1102{
1103  int status;
1104
1105  if ( SL_ISERROR(status = sl_forward(fd))) 
1106    {
1107      sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1108                      _("Failed to seek to end of baseline database"),
1109                      _("seek_writeout_data"),
1110                      path);
1111      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1112    }
1113  return;
1114}
1115
1116static int seek_writeout_data_old(SL_TICKET fd, const char * path)
1117{
1118  char * line = SH_ALLOC(MAX_PATH_STORE+1);
1119
1120  if (SL_ISERROR(sh_dbIO_setdataent_old (fd, line, MAX_PATH_STORE, path)))
1121    {
1122      SH_FREE(line);
1123      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH,
1124                      _("Failed to seek to end of baseline database"),
1125                      _("seek_writeout_data_old"),
1126                      path);
1127      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1128    }
1129  SH_FREE(line);
1130  return 0;
1131}
1132
1133char * prep_path(char * path, int flag)
1134{
1135  size_t old_len = sl_strlen(path);
1136  char * tmp;
1137  size_t tmp_len;
1138  size_t path_len;
1139  char * outpath = NULL;
1140#if !defined(SH_STEALTH)
1141  (void) flag;
1142#endif
1143
1144#if defined(SH_STEALTH)
1145  if (flag == S_TRUE)
1146    sh_do_encode(path, old_len);
1147#endif
1148  tmp = quote_string(path, old_len);
1149  tmp_len = sl_strlen(tmp);
1150#if defined(SH_STEALTH)
1151  if (flag == S_TRUE)
1152    sh_do_decode(path, old_len);
1153#endif
1154
1155  if (tmp && tmp_len <= MAX_PATH_STORE) 
1156    {
1157      outpath = sh_util_strdup(path);
1158    } 
1159  else 
1160    {
1161      char hashbuf[KEYBUF_SIZE];
1162     
1163      outpath = sh_util_strdup(sh_tiger_hash (path,
1164                                              TIGER_DATA, old_len, 
1165                                              hashbuf, sizeof(hashbuf)));
1166    }
1167  if (tmp) 
1168    SH_FREE(tmp);
1169
1170  path_len = sl_strlen(outpath);
1171#if defined(SH_STEALTH)
1172  if (flag == S_TRUE)
1173    sh_do_encode(outpath, path_len);
1174#endif
1175 
1176  tmp = quote_string(outpath, path_len);
1177  if (tmp) {
1178    SH_FREE(outpath);
1179    outpath = tmp;
1180  }
1181  return outpath;
1182}
1183
1184static char * prep_attr(char * attr_str)
1185{
1186  char * tmp;
1187  char * outstr = NULL;
1188  size_t old_len = sl_strlen(attr_str);
1189
1190#if defined(SH_STEALTH)
1191  sh_do_encode(attr_str, old_len);
1192#endif
1193
1194  tmp = quote_string(attr_str, old_len);
1195  if (tmp)
1196    {
1197      outstr = tmp;
1198    }
1199
1200#if defined(SH_STEALTH)
1201  sh_do_decode(attr_str, old_len);
1202#endif
1203  return outstr;
1204}
1205
1206static void prep_encode(sh_filestore_t * p)
1207{
1208#if defined(SH_STEALTH)
1209  sh_do_encode(p->c_mode,   sl_strlen(p->c_mode));
1210  sh_do_encode(p->c_owner,  sl_strlen(p->c_owner));
1211  sh_do_encode(p->c_group,  sl_strlen(p->c_group));
1212  sh_do_encode(p->checksum, sl_strlen(p->checksum));
1213  sh_do_encode(p->c_attributes,   sl_strlen(p->c_attributes));
1214#else
1215  (void) p;
1216#endif
1217  return;
1218}
1219
1220static void prep_struct(sh_filestore_t * p, file_type * buf, char * fileHash)
1221{
1222#if !defined(__linux__) && !defined(HAVE_STAT_FLAGS)
1223  int    i;
1224#endif
1225  p->mark = REC_MAGIC;
1226  sl_strlcpy(p->c_mode,   buf->c_mode,   CMODE_SIZE);
1227  sl_strlcpy(p->c_group,  buf->c_group,  GROUP_MAX+1);
1228  sl_strlcpy(p->c_owner,  buf->c_owner,  USER_MAX+1);
1229  if (fileHash) {
1230    sl_strlcpy(p->checksum, fileHash,      KEY_LEN+1);
1231  }
1232#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1233  sl_strlcpy(p->c_attributes, buf->c_attributes, ATTRBUF_SIZE);
1234#else
1235  for (i = 0; i < ATTRBUF_USED; ++i) p->c_attributes[i] = '-';
1236  p->c_attributes[ATTRBUF_USED] = '\0';
1237#endif
1238 
1239  prep_encode(p);
1240 
1241#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1242  p->attributes  = (UINT32) buf->attributes;
1243#else
1244  p->attributes  = 0;
1245#endif
1246  p->linkmode    = (UINT32) buf->linkmode;
1247  p->hardlinks   = (UINT32) buf->hardlinks;
1248  p->dev   = (UINT64) buf->dev;
1249  p->rdev  = (UINT64) buf->rdev;
1250  p->mode  = (UINT32) buf->mode;
1251  p->ino   = (UINT32) buf->ino;
1252  p->size  = (UINT64) buf->size;
1253  p->mtime = (UINT64) buf->mtime;
1254  p->atime = (UINT64) buf->atime;
1255  p->ctime = (UINT64) buf->ctime;
1256  p->owner = (UINT32) buf->owner;
1257  p->group = (UINT32) buf->group;
1258
1259  p->checkflags = (UINT32) buf->check_flags; 
1260 
1261  return;
1262}
1263
1264
1265static void write_start_header(SL_TICKET fd)
1266{
1267  char   timestring[81];
1268
1269  if (pushdata_stdout == S_FALSE)
1270    {
1271      sl_write (fd, _("\n#Host "), 7);
1272      sl_write (fd, sh.host.name, 
1273                sl_strlen(sh.host.name));
1274      sl_write (fd, _(" Version "), 9);
1275      sl_write (fd, sh_db_version_string, 
1276                sl_strlen(sh_db_version_string));
1277      sl_write (fd, _(" Date "), 6);
1278      (void) sh_unix_time(0, timestring, sizeof(timestring));
1279      sl_write (fd, timestring, strlen(timestring));
1280      sl_write (fd,        "\n", 1);
1281    } 
1282  else 
1283    {
1284      printf ("%s",_("\n#Host "));
1285      printf ("%s", sh.host.name);
1286      printf ("%s",_(" Version "));
1287      printf ("%s", sh_db_version_string);
1288      printf ("%s",_(" Date "));
1289      (void) sh_unix_time(0, timestring, sizeof(timestring));
1290      printf ("%s\n", timestring);
1291    }
1292}
1293
1294static void write_start_marker(SL_TICKET fd)
1295{
1296  if (sh_db_version_string != NULL)
1297    {
1298      write_start_header(fd);
1299    }
1300 
1301  if (pushdata_stdout == S_FALSE)
1302    {
1303#if defined(SH_STEALTH)
1304      sl_write      (fd,        "\n", 1);
1305      sl_write_line (fd, N_("[SOF]"), 5);
1306#else
1307      sl_write_line (fd, _("\n[SOF]"),  6);
1308#endif
1309    }
1310  else 
1311    {
1312#if defined(SH_STEALTH)
1313      puts (N_("[SOF]"));
1314#else
1315      puts (_("\n[SOF]"));
1316#endif
1317    }
1318}
1319
1320static void   write_record(SL_TICKET fd, sh_filestore_t * p, 
1321                           char * fullpath, char * linkpath, char * attr_string)
1322{
1323  static char ll[2] = { '-', '\0' };
1324  char * lpath;
1325
1326  if (!linkpath || 0 == sl_strlen(linkpath))
1327    lpath = ll;
1328  else
1329    lpath = linkpath;
1330
1331  if (pushdata_stdout == S_FALSE)
1332    {
1333      sl_write           (fd,        p, sizeof(sh_filestore_t));
1334      sl_write_line_fast (fd, fullpath, sl_strlen(fullpath));
1335      sl_write_line_fast (fd,    lpath, sl_strlen(lpath));
1336      if (attr_string)
1337        sl_write_line_fast (fd, attr_string, sl_strlen(attr_string));
1338    } 
1339  else 
1340    {
1341      if (fwrite (p, sizeof(sh_filestore_t), 1, stdout))
1342        {
1343          puts (fullpath);
1344          puts (lpath);
1345          if (attr_string)
1346            puts (attr_string);
1347        }
1348      else
1349        {
1350          perror(_("Error writing database"));
1351          aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1352        }
1353    }
1354
1355  SH_FREE(fullpath);
1356  if (linkpath)
1357    SH_FREE(linkpath);
1358  if (attr_string)
1359    SH_FREE(attr_string);
1360
1361  return;
1362}
1363
1364static void sh_dbIO_data_write_int (file_type * buf, char * fileHash, 
1365                                    const char * outpath, int truncate)
1366{
1367  static long p_count = 0;
1368  sh_filestore_t p;
1369  char *  fullpath = NULL;
1370  char *  linkpath = NULL;
1371  char *  attr_string = NULL;
1372
1373  SL_ENTER(_("sh_dbIO_data_write_int"));
1374
1375  do_writeout_checks(outpath);
1376
1377  if (sh.flag.update == S_FALSE)
1378    {
1379      if (pushdata_stdout == S_FALSE && pushdata_fd == -1)
1380        {
1381          if (truncate == S_TRUE)
1382            pushdata_fd = open_writeout_data_truncate(outpath);
1383          else
1384            {
1385              pushdata_fd = open_writeout_data(outpath);
1386              seek_writeout_data(pushdata_fd, outpath);
1387            }
1388        }
1389    }
1390  else /* update == TRUE */
1391    {
1392      if (pushdata_isfirst == 1)
1393        {
1394          TPT((0, FIL__, __LINE__, _("msg=<Update.>\n")));
1395          pushdata_fd = open_writeout_data(outpath);
1396          seek_writeout_data_old(pushdata_fd, outpath);
1397        }
1398    }
1399         
1400  if (!buf) {
1401    memset(&p, '\0', sizeof(sh_filestore_t));
1402  }
1403
1404  if (buf != NULL) 
1405    {
1406      fullpath = prep_path(buf->fullpath, S_TRUE);
1407    }
1408
1409  /* NOTE: TXT entries are c_mode[0] != 'l' and do not get decoded
1410   */
1411  if (buf != NULL /* && buf->c_mode[0] == 'l' */ && buf->link_path != NULL) 
1412    { 
1413      if (buf->c_mode[0] == 'l')
1414        linkpath = prep_path(buf->link_path, S_TRUE);
1415      else
1416        linkpath = prep_path(buf->link_path, S_FALSE);
1417    }
1418
1419  if (buf != NULL && buf->attr_string != NULL) 
1420    {
1421      attr_string = prep_attr(buf->attr_string);
1422    }
1423
1424  if (buf != NULL) 
1425    {
1426      prep_struct(&p, buf, fileHash);
1427      if (attr_string)
1428        p.mark |= REC_FLAGS_ATTR;
1429      swap_data(&p);
1430    }
1431
1432  /* write the start marker
1433   */
1434  if (pushdata_isfirst == 1) 
1435    {
1436      if (sh.flag.update == S_FALSE)
1437        write_start_marker(pushdata_fd);
1438      pushdata_isfirst = 0;
1439    }
1440
1441  if (buf && fullpath)
1442    {
1443      write_record(pushdata_fd, &p, fullpath, linkpath, attr_string);
1444      ++p_count;
1445    }
1446
1447  if ((sh.flag.update != S_TRUE) && (pushdata_stdout == S_FALSE))
1448    {
1449      if (sh.flag.checkSum != SH_CHECK_INIT || (buf == NULL && fileHash == NULL))
1450        {
1451          sl_close (pushdata_fd);
1452          pushdata_fd = -1;
1453        }
1454    }
1455
1456  SL_RET0(_("sh_dbIO_data_write_int"));
1457}
1458
1459SH_MUTEX_STATIC(mutex_writeout,PTHREAD_MUTEX_INITIALIZER);
1460
1461void sh_dbIO_data_write (file_type * buf, char * fileHash)
1462{
1463  SH_MUTEX_LOCK(mutex_writeout); 
1464  sh_dbIO_data_write_int (buf, fileHash, file_path('D', 'W'), S_FALSE);
1465  SH_MUTEX_UNLOCK(mutex_writeout); 
1466  return;
1467}
1468
1469
1470static int dbIO_writeout(sh_file_t * mtab[TABSIZE], const char * outpath, int truncate)
1471{
1472  sh_file_t * p;
1473  int         i;
1474  file_type * f;
1475  char   fileHash[KEY_LEN + 1];
1476
1477  SL_ENTER(_("dbIO_writeout"));
1478
1479  SH_MUTEX_LOCK(mutex_writeout); 
1480  if (!SL_ISERROR(pushdata_fd))
1481    {
1482      sl_close(pushdata_fd);
1483      pushdata_fd = -1;
1484    }
1485  pushdata_isfirst =  1;
1486
1487
1488  SH_MUTEX_LOCK(mutex_hash);
1489  for (i = 0; i < TABSIZE; ++i)
1490    {
1491      for (p = mtab[i]; p; p = p->next)
1492        {
1493          f = sh_hash_create_ft (p, fileHash);
1494          sh_dbIO_data_write_int (f, fileHash, outpath, (i == 0) ? truncate : S_FALSE);
1495          if (f->attr_string) SH_FREE(f->attr_string);
1496          if (f->link_path)   SH_FREE(f->link_path);
1497          SH_FREE(f);
1498        }
1499    }
1500  SH_MUTEX_UNLOCK(mutex_hash);
1501
1502  if (!SL_ISERROR(pushdata_fd))
1503    {
1504      sl_close(pushdata_fd);
1505      pushdata_fd = -1;
1506    }
1507  pushdata_isfirst =  1;
1508  SH_MUTEX_UNLOCK(mutex_writeout); 
1509
1510  SL_RETURN (0, _("dbIO_writeout"));
1511}
1512
1513int sh_dbIO_writeout_update()
1514{
1515  sh_file_t ** mtab = get_default_data_table();
1516
1517  if (S_TRUE == file_is_remote())
1518    {
1519      sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGEN, 
1520                      _("Baseline database is remote"), _("sh_dbIO_writeout"));
1521      SL_RETURN (1, _("sh_dbIO_writeout_update"));
1522    }
1523
1524  return dbIO_writeout(mtab, file_path('D', 'W'), S_FALSE);
1525}
1526
1527int sh_dbIO_writeout_to_path(const char * path)
1528{
1529  sh_file_t ** mtab = get_default_data_table();
1530  return dbIO_writeout(mtab, path, S_TRUE);
1531}
1532
1533static void dbIO_write_record(sh_file_t * record, SL_TICKET fd)
1534{
1535  sh_filestore_t * p = &(record->theFile);
1536  char * fullpath    = NULL;
1537  char * linkpath    = NULL;
1538  char * attr_string = NULL;
1539
1540  fullpath = prep_path(record->fullpath, S_TRUE);
1541
1542  /* NOTE: TXT entries are c_mode[0] != 'l' and do not get decoded
1543   */
1544  if (record->linkpath != NULL && 0 != strcmp("-", record->linkpath)) 
1545    { 
1546      if (p->c_mode[0] == 'l')
1547        linkpath = prep_path(record->linkpath, S_TRUE);
1548      else
1549        linkpath = prep_path(record->linkpath, S_FALSE);
1550    }
1551
1552  if (record->attr_string != NULL) 
1553    attr_string = prep_attr(record->attr_string);
1554
1555  prep_encode(p);
1556  swap_data(p);
1557
1558  write_record(fd, p, fullpath, linkpath, attr_string);
1559  return;
1560}
1561
1562static void dbIO_write_entry(sh_file_t * p)
1563{
1564  static int is_first = 1;
1565
1566  if (is_first)
1567    {
1568      pushdata_isfirst =  1;
1569      if (!sh.outpath || sh.outpath[0] == '\0') 
1570        pushdata_stdout  =  S_TRUE;
1571      else
1572        pushdata_fd = open_writeout_data_truncate(sh.outpath);
1573      write_start_marker(pushdata_fd);
1574      pushdata_isfirst = 0;
1575      is_first = 0;
1576    }
1577
1578  dbIO_write_record(p, pushdata_fd);
1579
1580}
1581
1582
1583/******************************************************************
1584 *
1585 * Listing the database.
1586 *
1587 ******************************************************************/ 
1588
1589static int ListBinary = S_FALSE;
1590static char * ListFilter = NULL;
1591
1592int sh_dbIO_list_binary (const char * c)
1593{
1594  (void) c;
1595  ListBinary = S_TRUE;
1596  return 0;
1597}
1598int sh_dbIO_list_filter (const char * c)
1599{
1600  ListFilter = sh_util_strdup(c);
1601  return 0;
1602}
1603
1604#include "zAVLTree.h"
1605
1606static zAVLTree * filter_list = NULL;
1607extern char * rtrim (char * str);
1608
1609#include <ctype.h>
1610static void read_filter()
1611{
1612  int    i, n = 0;
1613  size_t len;
1614  char * key;
1615  char * str;
1616  char * line = SH_ALLOC(SH_MAXBUF);
1617  FILE * fd   = fopen(ListFilter, "r");
1618 
1619  if (!fd)
1620    {
1621      perror(_("read_filter: fopen:"));
1622      _exit(EXIT_FAILURE);
1623    }
1624  do {
1625    i = sh_dbIO_getline (fd, line, SH_MAXBUF);
1626    str = rtrim(line);
1627    while (isspace((int)*str)) ++str;
1628
1629    key = sh_files_parse_input(str, &len);
1630
1631    if (key && *key == '/')
1632      {
1633        zAVL_string_set(&filter_list, key);
1634        ++n;
1635      }
1636  } while (i >= 0);
1637
1638  fclose(fd);
1639  SH_FREE(line);
1640
1641  if (n == 0)
1642    {
1643      fprintf(stderr, _("read_filter: empty file <%s>\n"), ListFilter);
1644      _exit (EXIT_FAILURE);
1645    }
1646  return;
1647}
1648
1649static int check_filter(char * path)
1650{
1651  if (NULL == zAVL_string_get(filter_list, path))
1652    return S_FALSE;
1653  return S_TRUE;
1654}
1655
1656int sh_dbIO_list_db (const char * db_file)
1657{
1658  sh_file_t * p;
1659  SL_TICKET fd;
1660  char * line;
1661  int  errflag = 0;
1662  int  flag = 0;
1663  char * ListFile = get_list_file();
1664
1665  if (!db_file)
1666    {
1667      fputs(_("ERROR: no database file given\n"), stderr);
1668      _exit(EXIT_FAILURE);
1669      return -1; 
1670    }
1671  if (sl_is_suid())
1672    {
1673      fputs(_("ERROR: insufficient privilege\n"), stderr);
1674      _exit (EXIT_FAILURE);
1675      return -1; /* for Mac OSX compiler */
1676    }
1677  if (0 == strcmp(db_file, _("default")))
1678    db_file = file_path('D', 'W');
1679  if (!db_file)
1680    {
1681      fputs(_("ERROR: no filename\n"), stderr);
1682      _exit(EXIT_FAILURE);
1683      return -1; 
1684    }
1685
1686  if (ListFilter) 
1687    read_filter();
1688
1689  line = SH_ALLOC(MAX_PATH_STORE+2);
1690
1691  if ( SL_ISERROR(fd = sl_open_read(FIL__, __LINE__, db_file, SL_YESPRIV))) 
1692    {
1693      fprintf(stderr, _("ERROR: can't open %s for read (errnum = %ld)\n"), 
1694              db_file, fd);
1695      _exit(EXIT_FAILURE);
1696      return -1; 
1697    }
1698
1699  /* fast forward to start of data
1700   */
1701  if (0 != sh_dbIO_setdataent(fd, line, MAX_PATH_STORE+1, db_file))
1702    {
1703      fprintf(stderr, _("ERROR: can't find start marker in %s\n"), 
1704              db_file);
1705      _exit(EXIT_FAILURE);
1706      return -1; 
1707    }
1708
1709  while (1) 
1710    {
1711      p = sh_dbIO_getdataent (line, MAX_PATH_STORE+1, db_file, &errflag);
1712      if ((p != NULL) && (p->fullpath[0] == '/'))
1713        {
1714          if (!ListFile)
1715            {
1716              flag = 1;
1717              if (ListFilter && S_FALSE == check_filter(p->fullpath))
1718                continue;
1719              if (ListBinary)
1720                dbIO_write_entry (p);
1721              else
1722                sh_hash_list_db_entry (p); 
1723            }
1724          else
1725            {
1726              if (0 != sl_strcmp(ListFile, p->fullpath))
1727                {
1728                  continue;
1729                }
1730              flag = 1;
1731              if ('l' != p->theFile.c_mode[0])
1732                {
1733                  if (sh_hash_printcontent(p->linkpath) < 0)
1734                    {
1735                      fputs(_("Error listing file content\n"), stderr);
1736                      _exit(EXIT_FAILURE);
1737                      return -1;
1738                    }
1739                }
1740              else
1741                {
1742                  fputs(_("File is a link\n"), stderr);
1743                  _exit(EXIT_FAILURE);
1744                  return -1;
1745                }
1746              break;
1747            }
1748        }
1749      else if (p == NULL)
1750        {
1751          break;
1752        }
1753    }
1754
1755  if (line != NULL)
1756    SH_FREE(line);
1757  sl_close (fd);
1758
1759  fflush(NULL);
1760
1761  if (flag == 0)
1762    {
1763      fputs(_("File not found.\n"), stderr);
1764      _exit(EXIT_FAILURE);
1765    }
1766  else if (errflag < 0)
1767    {
1768      fputs(_("Error while reading file.\n"), stderr);
1769      _exit(EXIT_FAILURE);
1770    }
1771     
1772  _exit(EXIT_SUCCESS);
1773  return 0; 
1774}
1775
1776/* if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
1777#endif
Note: See TracBrowser for help on using the repository browser.