source: trunk/src/sh_files.c

Last change on this file was 565, checked in by katerina, 5 months ago

Fix for ticket #454 (memory leak introduced in version 4.4.4).

File size: 83.3 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 1999 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#if defined(HAVE_PTHREAD_MUTEX_RECURSIVE) && defined(HAVE_DIRENT_H) && defined(HAVE_SCANDIR)
23
24/* Linux */
25#if defined(__linux__)
26#define _XOPEN_SOURCE 700
27#define SH_USE_SCANDIR 1
28
29/* FreeBSD */
30#elif defined(__FreeBSD__)
31
32#if __FreeBSD__ >= 8
33#define __XSI_VISIBLE 700
34#define SH_USE_SCANDIR 1
35#endif
36
37/* OpenBSD */
38#elif defined(__OpenBSD__)
39#define __POSIX_VISIBLE 200809
40#define SH_USE_SCANDIR 1
41
42#elif defined(__NetBSD__)
43#define _NETBSD_SOURCE
44#define SH_USE_SCANDIR 1
45
46/* other os */
47#else
48#define _XOPEN_SOURCE 500
49
50#endif
51
52#elif defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
53#define _XOPEN_SOURCE 500
54#endif
55
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <ctype.h>
60#include <limits.h>
61
62#include <errno.h>
63
64/* Must be before <utime.h> on FreeBSD
65 */
66#include <sys/types.h>
67#include <unistd.h>
68#include <sys/stat.h>
69#include <fcntl.h>
70
71#if !defined(O_NOATIME)
72#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
73#define O_NOATIME 01000000
74#endif
75#endif
76
77#include <utime.h>
78
79#ifdef HAVE_DIRENT_H
80#include <dirent.h>
81#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
82#else
83#define dirent direct
84#define NAMLEN(dirent) (dirent)->d_namlen
85#ifdef HAVE_SYS_NDIR_H
86#include <sys/ndir.h>
87#endif
88#ifdef HAVE_SYS_DIR_H
89#include <sys/dir.h>
90#endif
91#ifdef HAVE_NDIR_H
92#include <ndir.h>
93#endif
94#endif
95#define NEED_ADD_DIRENT
96
97#ifdef HAVE_GLOB_H
98#include <glob.h>
99#endif
100#ifdef HAVE_FNMATCH_H
101#include <fnmatch.h>
102#endif
103
104
105#include "samhain.h"
106
107#if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
108
109#include "sh_pthread.h"
110#include "sh_error.h"
111#include "sh_utils.h"
112#include "sh_unix.h"
113#include "sh_files.h"
114#include "sh_tiger.h"
115#include "sh_hash.h"
116#include "sh_ignore.h"
117#include "sh_inotify.h"
118#include "zAVLTree.h"
119#include "sh_dbIO.h"
120
121#undef  FIL__
122#define FIL__  _("sh_files.c")
123
124extern sh_watches sh_file_watches;
125
126static char * sh_files_C_dequote (char * s, size_t * length)
127{
128  size_t i, len = *length;
129  int    flag = 0;
130  char  *p, *q, *po, *pend;
131 
132  /* search for backslash
133   */
134  for (i = 0; i < len; ++i)
135    {
136      if (s[i] == '\\')
137        {
138          flag = 1;
139          break;
140        }
141    }
142
143  if (flag == 0 || *s == '\0')
144    return s;
145
146  po = SH_ALLOC(len+1); *po = '\0'; p = po; pend = &po[len];
147
148  q = s;
149
150  do
151    {
152      if (*q == '\\')
153        {
154          ++q;
155
156          if (*q == '\0')
157            { *p = *q; flag = 0; break; }
158          else if (*q == 'a')
159            { *p = '\a'; ++p; ++q; }
160          else if (*q == 'b')
161            { *p = '\b'; ++p; ++q; }
162          else if (*q == 'f')
163            { *p = '\f'; ++p; ++q; }
164          else if (*q == 'n')
165            { *p = '\n'; ++p; ++q; }
166          else if (*q == 'r')
167            { *p = '\r'; ++p; ++q; }
168          else if (*q == 't')
169            { *p = '\t'; ++p; ++q; }
170          else if (*q == 'v')
171            { *p = '\v'; ++p; ++q; }
172          else if (*q == '\\')
173            { *p = '\\'; ++p; ++q; }
174          else if (*q == '\'')
175            { *p = '\''; ++p; ++q; }
176          else if (*q == '"')
177            { *p = '"';  ++p; ++q; }
178          else if (*q == 'x')
179            {
180              if (isxdigit((int) q[1]) && isxdigit((int) q[2]))
181                {
182                  /* hexadecimal value following */
183                  unsigned char cc = (16 * sh_util_hexchar(q[1])) 
184                    + sh_util_hexchar(q[2]);
185                  *p = (char) cc;
186                  ++p; q += 3;
187                }
188              else
189                {
190                  *p = '\0'; flag = 0; break;
191                }
192            }
193          else if (isdigit((int)*q))
194            {
195              if (isdigit((int) q[1]) && q[1] < '8' && 
196                  isdigit((int) q[2]) && q[2] < '8')
197                {
198                  /* octal value following */
199                  char tmp[4];  unsigned char cc;
200                  tmp[0] = *q; ++q; tmp[1] = *q; ++q; tmp[2] = *q; ++q; 
201                  tmp[3] = '\0';
202                  cc = strtol(tmp, NULL, 8);
203                  *p = (char) cc; ++p;
204                }
205              else
206                {
207                  *p = '\0'; flag = 0; break;
208                }
209            }
210          else
211            {
212              /* invalid escape sequence */
213              *p = '\0'; flag = 0; break;
214            }
215        }
216      else
217        {
218          *p = *q; 
219          ++p; ++q;
220        }
221    } while (*q && p <= pend);
222
223  SL_REQUIRE (p <= pend, _("p <= pend"));
224
225  if (flag)
226    {
227      *p = '\0';
228      *length = strlen(po);
229    }
230  else
231    {
232      SH_FREE(po);
233      po = NULL;
234      *length = 0;
235    }
236
237  SL_REQUIRE (*length <= len, _("*length <= len"));
238
239  SH_FREE(s);
240  return po;
241}
242
243char * sh_files_parse_input(const char * str_s, size_t * len)
244{
245  char  * p;
246 
247  if (!str_s || *str_s == '\0')
248    return NULL;
249
250  *len = sl_strlen(str_s);
251  if (sh.flag.checkSum == SH_CHECK_INIT)
252    {
253      size_t addspace = sh_dbIO_get_rootfs_len();
254      if (addspace != 0 && S_TRUE == sl_ok_adds (*len, addspace))
255        *len += addspace;
256    }
257 
258  if ( (str_s[0] == '"'  && str_s[*len-1] == '"' ) ||
259       (str_s[0] == '\'' && str_s[*len-1] == '\'') )
260    {
261      if (*len < 3)
262        return NULL;
263      --(*len);
264      p = sh_util_strdup_l(&str_s[1], *len);
265      p[*len-1] = '\0';
266      --(*len);
267    }
268  else
269    {
270      p = sh_util_strdup_l(str_s, *len);
271    }
272
273  p = sh_files_C_dequote(p, len);
274
275  return p;
276}
277
278
279extern int flag_err_debug;
280extern int flag_err_info;
281
282int sh_files_reportonce(const char * c)
283{
284  int i;
285  SL_ENTER(_("sh_files_reportonce"));
286  i = sh_util_flagval(c, &(sh.flag.reportonce));
287
288  SL_RETURN(i, _("sh_files_reportonce"));
289}
290   
291int sh_files_fulldetail(const char * c)
292{
293  int i;
294  SL_ENTER(_("sh_files_fulldetail"));
295  i = sh_util_flagval(c, &(sh.flag.fulldetail));
296
297  SL_RETURN((i), _("sh_files_fulldetail"));
298}
299   
300
301typedef struct dir_struct {
302  long    NumRegular;
303  long    NumDirs;
304  long    NumSymlinks;
305  long    NumFifos;
306  long    NumSockets;
307  long    NumCDev;
308  long    NumBDev;
309  long    NumDoor;
310  long    NumPort;
311  long    NumAll;
312  long    TotalBytes;
313  char    DirPath[PATH_MAX];
314} dir_type;
315
316typedef struct dirstack_entry {
317  char                  * name;
318  int                     class;
319  unsigned long           check_flags;
320  int                     rdepth;
321  short                   checked;
322  short                   childs_checked;
323  short                   is_reported;
324  /* struct dirstack_entry * next; */
325} dirstack_t;
326
327
328/* the destructor
329 */
330void free_dirstack (void * inptr)
331{
332  dirstack_t * here;
333
334  SL_ENTER(_("free_dirstack"));
335  if (inptr == NULL)
336    SL_RET0(_("free_dirstack"));
337  else
338    here = (dirstack_t *) inptr;
339
340  if (here->name != NULL)
341    SH_FREE(here->name);
342  SH_FREE(here);
343  SL_RET0(_("free_dirstack"));
344}
345
346/* Function to return the key for indexing
347 * the argument
348 */
349zAVLKey zdirstack_key (void const * arg)
350{
351  const dirstack_t * sa = (const dirstack_t *) arg;
352  return (zAVLKey) sa->name;
353}
354
355#define SH_LIST_FILE 0
356#define SH_LIST_DIR1 1
357#define SH_LIST_DIR2 2
358
359
360static int which_dirList = SH_LIST_DIR1;
361
362static zAVLTree * zdirListOne   = NULL;
363static zAVLTree * zdirListTwo   = NULL;
364static zAVLTree * zfileList     = NULL;
365
366SH_MUTEX_STATIC(mutex_zfiles,      PTHREAD_MUTEX_INITIALIZER);
367SH_MUTEX_STATIC(mutex_zglob,       PTHREAD_MUTEX_INITIALIZER);
368SH_MUTEX_RECURSIVE(mutex_zdirs);
369
370static int        sh_files_fullpath  (const char * testdir, 
371                                      const char * d_name, 
372                                      char * statpath);
373static int        sh_files_pushdir   (int class, const char * str_s);
374static int        sh_files_pushfile  (int class, const char * str_s);
375
376static long MaxRecursionLevel = 0;
377
378/* set default recursion level
379 */
380int sh_files_setrecursion (const char * flag_s)
381{
382  long flag = 0;
383  static int reject = 0;
384
385  SL_ENTER( _("sh_files_setrecursion"));
386
387  if (reject == 1)
388    SL_RETURN((-1), _("sh_files_setrecursion"));
389
390  if (sh.flag.opts == S_TRUE) 
391    reject = 1;
392
393  if (flag_s != NULL) 
394    flag = (int)(atof(flag_s));
395
396  if (flag >= 0 && flag <= 99)
397    MaxRecursionLevel = flag;
398  else
399    SL_RETURN((-1), _("sh_files_setrecursion"));
400
401  SL_RETURN((0), _("sh_files_setrecursion"));
402}
403
404static int handle_filecheck_ret(dirstack_t * ptr, char * tmp_in, int status)
405{
406  int fcount = 0;
407  char * tmp;
408
409  if (!tmp_in)
410    tmp = sh_util_safe_name (ptr->name);
411  else
412    tmp = tmp_in;
413
414  if (status == SH_FILE_UNKNOWN && (!SH_FFLAG_REPORTED_SET(ptr->is_reported)))
415    {
416      TPT(( 0, FIL__, __LINE__, _("msg=<file: %s> status=<%d>\n"), 
417            tmp, status));
418     
419      if ( sh.flag.checkSum == SH_CHECK_INIT  || 
420           sh_hash_have_it (ptr->name) >= 0)
421        {
422          if (S_FALSE == sh_ignore_chk_del(ptr->name))
423            {
424              if (0 != hashreport_missing(ptr->name, 
425                                          (ptr->class == SH_LEVEL_ALLIGNORE) ? 
426                                          ShDFLevel[ptr->class] : 
427                                          ShDFLevel[SH_ERR_T_FILE])) {
428                if (tmp == NULL) 
429                  tmp = sh_util_safe_name (ptr->name);
430                if (!sh_global_check_silent)
431                  sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ? 
432                                   ShDFLevel[ptr->class] : 
433                                   ShDFLevel[SH_ERR_T_FILE],
434                                   FIL__, __LINE__, 0, MSG_FI_MISS,
435                                   tmp);
436                ++sh.statistics.files_report;
437              }
438            }
439        }
440      else /* not there at init, and still missing */
441        {
442          if (tmp == NULL) 
443            tmp = sh_util_safe_name (ptr->name);
444          sh_error_handle (SH_ERR_NOTICE,
445                           FIL__, __LINE__, 0,
446                           MSG_FI_FAIL,
447                           tmp);
448        }
449
450      if (sh.flag.checkSum != SH_CHECK_INIT) 
451        sh_hash_set_missing(ptr->name);
452
453      if (sh.flag.reportonce == S_TRUE)
454        SET_SH_FFLAG_REPORTED(ptr->is_reported);
455    }
456  else 
457    {
458      /* exists (status >= 0), but was missing (reported == TRUE)
459       */
460      if (status != SH_FILE_UNKNOWN && SH_FFLAG_REPORTED_SET(ptr->is_reported))
461        {
462          CLEAR_SH_FFLAG_REPORTED(ptr->is_reported);
463          sh_hash_clear_flag(ptr->name, SH_FFLAG_ENOENT);
464        }
465     
466      /* Catchall
467       */
468      else if (status == SH_FILE_UNKNOWN)
469        {
470          /* Thu Mar  7 15:09:40 CET 2002 Make sure missing file
471           * is reported if ptr->reported == S_TRUE because the
472           * file has been added.
473           */
474          if (sh_hash_have_it (ptr->name) >= 0 && 
475              !SH_FFLAG_REPORTED_SET(ptr->is_reported))
476            {
477              if (S_FALSE == sh_ignore_chk_del(ptr->name))
478                {
479                  if (0 != hashreport_missing(ptr->name, 
480                                              (ptr->class == SH_LEVEL_ALLIGNORE) ? 
481                                              ShDFLevel[ptr->class] : 
482                                              ShDFLevel[SH_ERR_T_FILE])) {
483                    if (tmp == NULL) 
484                      tmp = sh_util_safe_name (ptr->name);
485                    if (!sh_global_check_silent)
486                      sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE)? 
487                                       ShDFLevel[ptr->class] : 
488                                       ShDFLevel[SH_ERR_T_FILE],
489                                       FIL__, __LINE__, 0, MSG_FI_MISS,
490                                       tmp);
491                    ++sh.statistics.files_report;
492                  }
493                }
494
495              /* delete from database
496               */
497              if (sh.flag.checkSum != SH_CHECK_INIT) 
498                sh_hash_set_missing(ptr->name);
499            }
500          else
501            {
502              if (tmp == NULL) 
503                tmp = sh_util_safe_name (ptr->name);
504              sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0,
505                               MSG_FI_FAIL,
506                               tmp);
507              if (sh.flag.checkSum != SH_CHECK_INIT)
508                sh_hash_set_visited_true(ptr->name);
509            }
510        }
511     
512      ++fcount;
513    }
514  if (!tmp_in)
515    SH_FREE(tmp);
516
517  return fcount;
518}
519
520
521unsigned long sh_files_chk ()
522{
523  zAVLCursor    cursor;
524  ShFileType    status;
525  unsigned long fcount = 0;
526
527  char       * tmp = NULL;
528
529  dirstack_t * ptr;
530  char       * dir;
531  char       * file;
532  int          tmp_reported;
533 
534  SL_ENTER(_("sh_files_chk"));
535
536  for (ptr = (dirstack_t *) zAVLFirst(&cursor, zfileList); ptr;
537       ptr = (dirstack_t *) zAVLNext(&cursor))
538    {
539
540      if (sig_urgent > 0) {
541        SL_RETURN(fcount, _("sh_files_chk"));
542      }
543
544      if (ptr->checked == S_FALSE)
545        {
546          dir  = sh_util_dirname (ptr->name);
547          file = sh_util_basename (ptr->name);
548#if defined(WITH_TPT)
549          tmp = sh_util_safe_name (ptr->name);
550#endif
551
552         
553          if (flag_err_info == S_TRUE)
554            {
555              char pstr[32];
556#if !defined(WITH_TPT)
557              tmp = sh_util_safe_name (ptr->name);
558#endif
559              sl_strlcpy(pstr, sh_hash_getpolicy(ptr->class), sizeof(pstr));
560              sh_error_handle ((-1),  FIL__, __LINE__, 0, 
561                               MSG_FI_CHK, pstr, tmp);
562            }
563
564          if ((sh.flag.inotify & SH_INOTIFY_INSCAN) != 0)
565            {
566              sh_inotify_add_watch_later(ptr->name, &sh_file_watches, NULL,
567                                         ptr->class, ptr->check_flags, 
568                                         SH_INOTIFY_FILE, 0);
569            }
570
571          BREAKEXIT(sh_files_filecheck);
572          tmp_reported = ptr->is_reported; /* fix aliasing warning */ 
573          status = sh_files_filecheck (ptr->class, ptr->check_flags, dir, file, 
574                                       &tmp_reported, 0);
575          ptr->is_reported = tmp_reported;
576         
577          TPT(( 0, FIL__, __LINE__, 
578                _("msg=<filecheck complete: %s> status=<%d> reported=<%d>\n"), 
579                tmp, status, ptr->is_reported));
580
581          fcount += handle_filecheck_ret(ptr, tmp, status);
582         
583          if (tmp != NULL)
584            {
585              SH_FREE(tmp);
586              tmp = NULL;
587            }
588          if (file)
589            SH_FREE(file);
590          if (dir)
591            SH_FREE(dir);
592
593          ptr->checked = S_TRUE;
594        }
595    }
596
597  SL_RETURN(fcount, _("sh_files_chk"));
598}
599
600static zAVLTree * fileTree = NULL;
601static zAVLTree * dirTree  = NULL;
602
603static void clear_lists()
604{
605  if (fileTree) {
606    zAVL_string_reset(fileTree);
607    fileTree  = NULL;
608  }
609  if (dirTree) {
610    zAVL_string_reset(dirTree);
611    dirTree  = NULL;
612  }
613  return;
614}
615
616static void add_to_filelist(zAVLTree * tree)
617{
618  dirstack_t * ptr;
619  zAVLCursor   avlcursor;
620
621  SL_ENTER(_("add_to_filelist"));
622
623  SH_MUTEX_LOCK(mutex_zfiles);
624  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
625       ptr = (dirstack_t *) zAVLNext(&avlcursor))
626    zAVL_string_set (&fileTree, ptr->name);
627  SH_MUTEX_UNLOCK(mutex_zfiles);
628  SL_RET0(_("add_to_filelist"));
629}
630static void add_to_dirlist(zAVLTree * tree)
631{
632  dirstack_t * ptr;
633  zAVLCursor   avlcursor;
634
635  SL_ENTER(_("add_to_dirlist"));
636
637  SH_MUTEX_LOCK(mutex_zfiles);
638  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
639       ptr = (dirstack_t *) zAVLNext(&avlcursor))
640    zAVL_string_set (&dirTree, ptr->name);
641  SH_MUTEX_UNLOCK(mutex_zfiles);
642  SL_RET0(_("add_to_dirlist"));
643}
644char * sh_files_findfile(const char * path)
645{
646  return zAVL_string_get (fileTree, path);
647}
648
649void * sh_dummy_621_candidate;
650
651static char * intern_find_morespecific_dir(zAVLTree * tree, 
652                                           const char * path, size_t * len)
653{
654  dirstack_t * ptr;
655  zAVLCursor   avlcursor;
656  size_t       l_path = strlen(path);
657  size_t       l_name;
658  char *       candidate = NULL;
659  volatile size_t       l_candidate = 0;
660 
661  if (NULL == tree)
662    return NULL;
663
664  sh_dummy_621_candidate = (void *) &candidate;
665
666  SH_MUTEX_LOCK(mutex_zfiles);
667  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
668       ptr = (dirstack_t *) zAVLNext(&avlcursor))
669    {
670      l_name = strlen(ptr->name);
671      if (l_name <= l_path)
672        {
673          if (0 == strncmp(ptr->name, path, l_name))
674            {
675              if ((l_name == l_path) || (path[l_name] == '/'))
676                {
677                  if (!candidate || (l_candidate < l_name))
678                    {
679                      candidate = ptr->name;
680                      l_candidate = l_name;
681                      *len = l_candidate;
682                    }
683                }
684            }
685        }
686    }
687  SH_MUTEX_UNLOCK(mutex_zfiles);
688  return candidate;
689}
690char * sh_files_find_mostspecific_dir(const char * path)
691{
692  size_t l_one = 0;
693  size_t l_two = 0;
694  char * one;
695  char * two;
696
697  one = intern_find_morespecific_dir(zdirListOne, path, &l_one);
698  two = intern_find_morespecific_dir(zdirListTwo, path, &l_two);
699
700  if      (l_one > l_two) return one;
701  else                    return two;
702}
703
704int sh_files_delfilestack ()
705{
706  SL_ENTER(_("sh_files_delfilestack"));
707
708  SH_MUTEX_LOCK(mutex_zfiles);
709  zAVLFreeTree (zfileList, free_dirstack);
710  zfileList = NULL;
711  SH_MUTEX_UNLOCK(mutex_zfiles);
712
713  SL_RETURN(0, _("sh_files_delfilestack"));
714}
715 
716int sh_files_setrec_int (zAVLTree * tree)
717{
718  dirstack_t * ptr;
719  zAVLCursor   avlcursor;
720
721  SL_ENTER(_("sh_files_setrec"));
722  if (tree != NULL) {
723    for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
724         ptr = (dirstack_t *) zAVLNext(&avlcursor))
725      {
726        if (ptr->rdepth < (-1) || ptr->rdepth > 99)
727          {
728            ptr->rdepth = MaxRecursionLevel;
729          }
730
731        if ( (ptr->rdepth      == (-1)) && 
732             (ptr->class       == SH_LEVEL_ALLIGNORE) && 
733             (sh.flag.checkSum != SH_CHECK_INIT))
734          hash_remove_tree (ptr->name);
735      }
736  }
737  SL_RETURN(0, _("sh_files_setrec"));
738}
739
740int sh_files_setrec ()
741{
742  volatile int ret;
743  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
744  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
745  clear_lists();
746  add_to_dirlist(zdirListOne);
747  add_to_dirlist(zdirListTwo);
748  add_to_filelist(zfileList);
749  sh_files_setrec_int(zdirListOne);
750  ret = sh_files_setrec_int(zdirListTwo);
751  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
752
753  return ret;
754}
755
756zAVLTree * sh_files_deldirstack_int (zAVLTree * ptr)
757{
758  SL_ENTER(_("sh_files_deldirstack"));
759
760  zAVLFreeTree (ptr, free_dirstack);
761
762  SL_RETURN(NULL, _("sh_files_deldirstack"));
763}
764
765int sh_files_deldirstack ()
766{
767  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
768  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
769  zdirListOne = sh_files_deldirstack_int(zdirListOne);
770  zdirListTwo = sh_files_deldirstack_int(zdirListTwo);
771  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
772  return 0;
773}
774
775void sh_files_reset()
776{
777  dirstack_t * ptr;
778  zAVLCursor   avlcursor;
779
780  SL_ENTER(_("sh_files_reset"));
781
782  SH_MUTEX_LOCK(mutex_zfiles);
783  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, zfileList); ptr;
784       ptr = (dirstack_t *) zAVLNext(&avlcursor))
785    ptr->checked = 0;
786  SH_MUTEX_UNLOCK(mutex_zfiles);
787  SL_RET0(_("sh_files_reset"));
788}
789
790void sh_dirs_reset()
791{
792  dirstack_t * ptr;
793  zAVLCursor   avlcursor1;
794  zAVLCursor   avlcursor2;
795
796  SL_ENTER(_("sh_dirs_reset"));
797
798  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
799  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
800  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor1, zdirListOne); ptr;
801       ptr = (dirstack_t *) zAVLNext(&avlcursor1))
802    ptr->checked = 0;
803
804  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor2, zdirListTwo); ptr;
805       ptr = (dirstack_t *) zAVLNext(&avlcursor2))
806    ptr->checked = 0;
807  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
808
809  SL_RET0(_("sh_dirs_reset"));
810}
811
812
813int sh_files_pushfile_prelink (const char * str_s)
814{
815  return (sh_files_pushfile (SH_LEVEL_PRELINK, str_s));
816}
817
818int sh_files_pushfile_user0 (const char * str_s)
819{
820  return (sh_files_pushfile (SH_LEVEL_USER0, str_s));
821}
822
823int sh_files_pushfile_user1 (const char * str_s)
824{
825  return (sh_files_pushfile (SH_LEVEL_USER1, str_s));
826}
827
828int sh_files_pushfile_user2 (const char * str_s)
829{
830  return (sh_files_pushfile (SH_LEVEL_USER2, str_s));
831}
832
833int sh_files_pushfile_user3 (const char * str_s)
834{
835  return (sh_files_pushfile (SH_LEVEL_USER3, str_s));
836}
837
838int sh_files_pushfile_user4 (const char * str_s)
839{
840  return (sh_files_pushfile (SH_LEVEL_USER4, str_s));
841}
842
843
844int sh_files_pushfile_ro (const char * str_s)
845{
846  return (sh_files_pushfile (SH_LEVEL_READONLY, str_s));
847}
848
849int sh_files_pushfile_attr (const char * str_s)
850{
851  return (sh_files_pushfile (SH_LEVEL_ATTRIBUTES, str_s));
852}
853
854int sh_files_pushfile_log (const char * str_s)
855{
856  return (sh_files_pushfile (SH_LEVEL_LOGFILES, str_s));
857}
858
859int sh_files_pushfile_glog (const char * str_s)
860{
861  return (sh_files_pushfile (SH_LEVEL_LOGGROW, str_s));
862}
863
864int sh_files_pushfile_noig (const char * str_s)
865{
866  return (sh_files_pushfile (SH_LEVEL_NOIGNORE, str_s));
867}
868
869int sh_files_pushfile_allig (const char * str_s)
870{
871  return (sh_files_pushfile (SH_LEVEL_ALLIGNORE, str_s));
872}
873
874
875static void sh_files_set_mask (unsigned long * mask, 
876                               unsigned long val, int act)
877{
878  SL_ENTER(_("sh_files_set_mask"));
879
880  if       (act == 0)
881    (*mask)  = val;
882  else if  (act > 0)
883    (*mask) |= val;
884  else 
885    (*mask) &= ~val;
886
887  SL_RET0(_("sh_files_set_mask"));
888}
889
890/* set mask(class)
891 */
892static int sh_files_parse_mask (unsigned long * mask, const char * str)
893{
894  int l, i = 0, act = 0, k = 0;
895  char  myword[64];
896 
897  SL_ENTER(_("sh_files_parse_mask"));
898
899  myword[0] = '\0';
900
901  if (str == NULL)
902    {
903      SL_RETURN ( (-1), _("sh_files_parse_mask"));
904    }
905  else
906    l = sl_strlen(str);
907
908  while (i < l) {
909
910    if (str[i] == '\0')
911      break;
912
913    if (str[i] == ' ' || str[i] == '\t' || str[i] == ',')
914      {
915        ++i;
916        continue;
917      }
918
919    if (str[i] == '+')
920      {
921        act = +1; ++i;
922        myword[0] = '\0';
923        goto getword;
924      }
925    else if (str[i] == '-')
926      {
927        act = -1; ++i;
928        myword[0] = '\0';
929        goto getword;
930      }
931    else /* a word */
932      {
933      getword:
934        k = 0;
935        while (k < 63 && str[i] != ' ' && str[i] != '\t' && str[i] != ','
936               && str[i] != '+' && str[i] != '-' && str[i] != '\0') {
937          myword[k] = str[i]; 
938          ++i; ++k;
939        }
940        myword[k] = '\0';
941
942        if (sl_strlen(myword) == 0)
943          {
944            SL_RETURN ( (-1), _("sh_files_parse_mask"));
945          }
946
947/* checksum     */
948        if      (0 == strcmp(myword, _("CHK")))
949          sh_files_set_mask (mask, MODI_CHK, act);
950/* link         */
951        else if (0 == strcmp(myword, _("LNK")))
952          sh_files_set_mask (mask, MODI_LNK, act);
953/* inode        */
954        else if (0 == strcmp(myword, _("RDEV")))
955          sh_files_set_mask (mask, MODI_RDEV, act);
956/* inode        */
957        else if (0 == strcmp(myword, _("INO")))
958          sh_files_set_mask (mask, MODI_INO, act);
959/* user         */
960        else if (0 == strcmp(myword, _("USR")))
961          sh_files_set_mask (mask, MODI_USR, act);
962/* group        */
963        else if (0 == strcmp(myword, _("GRP")))
964          sh_files_set_mask (mask, MODI_GRP, act);
965/* mtime        */
966        else if (0 == strcmp(myword, _("MTM")))
967          sh_files_set_mask (mask, MODI_MTM, act);
968/* ctime        */
969        else if (0 == strcmp(myword, _("CTM")))
970          sh_files_set_mask (mask, MODI_CTM, act);
971/* atime        */
972        else if (0 == strcmp(myword, _("ATM")))
973          sh_files_set_mask (mask, MODI_ATM, act);
974/* size         */
975        else if (0 == strcmp(myword, _("SIZ")))
976          sh_files_set_mask (mask, MODI_SIZ, act);
977/* file mode    */
978        else if (0 == strcmp(myword, _("MOD")))
979          sh_files_set_mask (mask, MODI_MOD, act);
980/* hardlinks    */
981        else if (0 == strcmp(myword, _("HLN")))
982          sh_files_set_mask (mask, MODI_HLN, act);
983/* size may grow */
984        else if (0 == strcmp(myword, _("SGROW")))
985          sh_files_set_mask (mask, MODI_SGROW, act);
986/* use prelink */
987        else if (0 == strcmp(myword, _("PRE")))
988          sh_files_set_mask (mask, MODI_PREL, act);
989/* get content */
990        else if (0 == strcmp(myword, _("TXT")))
991          sh_files_set_mask (mask, MODI_TXT, act);
992/* get audit report */
993        else if (0 == strcmp(myword, _("AUDIT")))
994          sh_files_set_mask (mask, MODI_AUDIT, act);
995        else
996          {
997            SL_RETURN ( (-1), _("sh_files_parse_mask"));
998          }
999        act       = 0;
1000        myword[0] = '\0';
1001      }
1002  }
1003  SL_RETURN ( (0), _("sh_files_parse_mask"));
1004}
1005
1006int sh_files_redef_prelink(const char * str)
1007{
1008  return (sh_files_parse_mask(&mask_PRELINK, str));
1009} 
1010int sh_files_redef_user0(const char * str)
1011{
1012  return (sh_files_parse_mask(&mask_USER0, str));
1013} 
1014int sh_files_redef_user1(const char * str)
1015{
1016  return (sh_files_parse_mask(&mask_USER1, str));
1017} 
1018int sh_files_redef_user2(const char * str)
1019{
1020  return (sh_files_parse_mask(&mask_USER2, str));
1021} 
1022int sh_files_redef_user3(const char * str)
1023{
1024  return (sh_files_parse_mask(&mask_USER3, str));
1025} 
1026int sh_files_redef_user4(const char * str)
1027{
1028  return (sh_files_parse_mask(&mask_USER4, str));
1029} 
1030int sh_files_redef_readonly(const char * str)
1031{
1032  return (sh_files_parse_mask(&mask_READONLY, str));
1033} 
1034int sh_files_redef_loggrow(const char * str)
1035{
1036  return (sh_files_parse_mask(&mask_LOGGROW, str));
1037} 
1038int sh_files_redef_logfiles(const char * str)
1039{
1040  return (sh_files_parse_mask(&mask_LOGFILES, str));
1041} 
1042int sh_files_redef_attributes(const char * str)
1043{
1044  return (sh_files_parse_mask(&mask_ATTRIBUTES, str));
1045} 
1046int sh_files_redef_noignore(const char * str)
1047{
1048  return (sh_files_parse_mask(&mask_NOIGNORE, str));
1049} 
1050int sh_files_redef_allignore(const char * str)
1051{
1052  return (sh_files_parse_mask(&mask_ALLIGNORE, str));
1053} 
1054
1055unsigned long sh_files_maskof (int class)
1056{
1057  switch (class)
1058    {
1059    case SH_LEVEL_READONLY:
1060      return (unsigned long) (mask_READONLY | MODI_INIT);
1061    case SH_LEVEL_ATTRIBUTES:
1062      return (unsigned long) (mask_ATTRIBUTES | MODI_INIT);
1063    case SH_LEVEL_LOGFILES:
1064      return (unsigned long) (mask_LOGFILES | MODI_INIT);
1065    case SH_LEVEL_LOGGROW:
1066      return (unsigned long) (mask_LOGGROW | MODI_INIT);
1067    case SH_LEVEL_ALLIGNORE:
1068      return (unsigned long) (mask_ALLIGNORE | MODI_INIT);
1069    case SH_LEVEL_NOIGNORE:
1070      return (unsigned long) (mask_NOIGNORE | MODI_INIT);
1071    case SH_LEVEL_USER0:
1072      return (unsigned long) (mask_USER0 | MODI_INIT);
1073    case SH_LEVEL_USER1:
1074      return (unsigned long) (mask_USER1 | MODI_INIT);
1075    case SH_LEVEL_USER2:
1076      return (unsigned long) (mask_USER2 | MODI_INIT);
1077    case SH_LEVEL_USER3:
1078      return (unsigned long) (mask_USER3 | MODI_INIT);
1079    case SH_LEVEL_USER4:
1080      return (unsigned long) (mask_USER4 | MODI_INIT);
1081    case SH_LEVEL_PRELINK:
1082      return (unsigned long) (mask_PRELINK | MODI_INIT);
1083    default:
1084      return (unsigned long) 0;
1085    }
1086}
1087
1088#ifdef HAVE_GLOB_H
1089int sh_files_has_metachar (const char * str)
1090{
1091  SL_ENTER(_("sh_files_has_metachar"));
1092  if      (NULL != strchr(str, '*'))
1093    SL_RETURN(1, _("sh_files_has_metachar"));
1094  else if (NULL != strchr(str, '?'))
1095    SL_RETURN(1, _("sh_files_has_metachar"));
1096  else if (NULL != (strchr(str, '[')))
1097    SL_RETURN(1, _("sh_files_has_metachar"));
1098  else
1099    SL_RETURN(0, _("sh_files_has_metachar"));
1100}
1101
1102
1103int sh_files_globerr (const char * epath, int errnum)
1104{
1105  char * p;
1106  char errbuf[SH_ERRBUF_SIZE];
1107
1108  SL_ENTER(_("sh_files_globerr"));
1109
1110  if (errnum == ENOTDIR || errnum == ENOENT)
1111    {
1112      SL_RETURN(0, _("sh_files_globerr"));
1113    }
1114
1115  p = sh_util_safe_name (epath);
1116  sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_FI_GLOB,
1117                   sh_error_message (errnum, errbuf, sizeof(errbuf)), p);
1118  SH_FREE(p);
1119
1120  SL_RETURN(0, _("sh_files_globerr"));
1121}
1122
1123/* #ifdef HAVE_GLOB_H
1124 */
1125#endif
1126
1127int sh_files_push_file_int (int class, const char * str_s, size_t len, 
1128                            unsigned long check_flags)
1129{
1130  dirstack_t * new_item_ptr;
1131  char  * fileName;
1132  int     ret;
1133  volatile int     count = 0;
1134
1135  SL_ENTER(_("sh_files_push_file_int"));
1136
1137  fileName = SH_ALLOC(len+1);
1138  sl_strlcpy(fileName, str_s, len+1);
1139
1140  new_item_ptr = (dirstack_t *) SH_ALLOC (sizeof(dirstack_t));
1141
1142  new_item_ptr->name           = fileName;
1143  new_item_ptr->class          = class;
1144  new_item_ptr->check_flags     = check_flags;
1145  new_item_ptr->rdepth         = 0;
1146  new_item_ptr->checked        = S_FALSE;
1147  new_item_ptr->is_reported    = 0;
1148  new_item_ptr->childs_checked = S_FALSE;
1149
1150  SH_MUTEX_LOCK(mutex_zfiles);
1151  if (zfileList == NULL)
1152    {
1153      zfileList = zAVLAllocTree (zdirstack_key, zAVL_KEY_STRING);
1154      if (zfileList == NULL) 
1155        {
1156          (void) safe_logger (0, 0, NULL);
1157          aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1158        }
1159    }
1160
1161  ret = zAVLInsert (zfileList, new_item_ptr);
1162  SH_MUTEX_UNLOCK(mutex_zfiles);
1163
1164  if (-1 == ret)
1165    {
1166      (void) safe_logger (0, 0, NULL);
1167      aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1168    }
1169  else if (3 == ret)
1170    { 
1171      if (sh.flag.started != S_TRUE)
1172        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
1173                         fileName);
1174      SH_FREE(fileName);
1175      SH_FREE(new_item_ptr);
1176      new_item_ptr = NULL;
1177    }
1178  else
1179    {
1180      int           reported;
1181      unsigned long check_flags = sh_files_maskof(class);
1182
1183      if ((sh.flag.inotify & SH_INOTIFY_INSCAN) != 0)
1184        {
1185          sh_files_filecheck (class, check_flags, str_s, NULL,
1186                              &reported, 0);
1187          if (SH_FFLAG_REPORTED_SET(reported))
1188            sh_files_set_file_reported(str_s);
1189          sh_inotify_add_watch_later(str_s, &sh_file_watches, NULL,
1190                                     class, check_flags, 
1191                                     SH_INOTIFY_FILE, 0);
1192        }
1193
1194      if (MODI_AUDIT_ENABLED(check_flags))
1195        {
1196          sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGPATH,
1197                          _("Setting audit watch"),
1198                          _("sh_files_push_file_int"), str_s);
1199          sh_audit_mark(str_s);
1200        }
1201      ++count;
1202    }
1203  SL_RETURN(count, _("sh_files_push_file_int"));
1204}
1205
1206int sh_files_push_dir_int (int class, char * tail, size_t len, int rdepth, unsigned long check_flags);
1207
1208#ifdef HAVE_GLOB_H
1209
1210typedef struct globstack_entry {
1211  char                  * name;
1212  char                  * type_name;
1213  int                     class;
1214  unsigned long           check_flags;
1215  int                     rdepth;
1216  short                   type;
1217  /* struct dirstack_entry * next; */
1218} sh_globstack_t;
1219
1220static zAVLTree * zglobList   = NULL;
1221
1222zAVLKey zglobstack_key (void const * arg)
1223{
1224  const sh_globstack_t * sa = (const sh_globstack_t *) arg;
1225  return (zAVLKey) sa->type_name;
1226}
1227
1228
1229static int sh_files_pushglob (int class, int type, const char * p, int rdepth,
1230                               unsigned long check_flags_in, int flag)
1231{
1232  int     globstatus = -1;
1233  unsigned int     gloop;
1234  glob_t  pglob;
1235
1236  volatile int     count = 0;
1237  volatile unsigned long check_flags = (flag == 0) ? sh_files_maskof(class) : check_flags_in;
1238 
1239  SL_ENTER(_("sh_files_pushglob"));
1240
1241  pglob.gl_offs = 0;
1242  globstatus    = glob (p, 0, sh_files_globerr, &pglob);
1243 
1244  if (sh.flag.checkSum != SH_CHECK_INIT)
1245    {
1246      sh_globstack_t * new_item_ptr;
1247      char  * fileName;
1248      char  * typeName;
1249      int     ret;
1250     
1251      SH_MUTEX_TRYLOCK(mutex_zfiles);
1252      fileName = sh_util_strdup (p);
1253      typeName = sh_util_strconcat ((type == SH_LIST_FILE) ? "F" : "D", p, NULL);
1254     
1255      new_item_ptr = (sh_globstack_t *) SH_ALLOC (sizeof(sh_globstack_t));
1256     
1257      new_item_ptr->name           = fileName;
1258      new_item_ptr->type_name      = typeName;
1259      new_item_ptr->class          = class;
1260      new_item_ptr->check_flags    = check_flags;
1261      new_item_ptr->rdepth         = rdepth;
1262      new_item_ptr->type           = type;
1263     
1264      if (zglobList == NULL)
1265        {
1266          zglobList = zAVLAllocTree (zglobstack_key, zAVL_KEY_STRING);
1267          if (zglobList == NULL) 
1268            {
1269              (void) safe_logger (0, 0, NULL);
1270              aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1271            }
1272        }
1273     
1274      ret = zAVLInsert (zglobList, new_item_ptr);
1275     
1276      if (ret != 0) /* already in list */
1277        {
1278          SH_FREE(fileName);
1279          SH_FREE(typeName);
1280          SH_FREE(new_item_ptr);
1281        }
1282      SH_MUTEX_TRYLOCK_UNLOCK(mutex_zfiles);
1283    }
1284
1285
1286  if (globstatus == 0 && pglob.gl_pathc > 0)
1287    {
1288      for (gloop = 0; gloop < (unsigned int) pglob.gl_pathc; ++gloop)
1289        {
1290          if (type == SH_LIST_FILE)
1291            {
1292              count += sh_files_push_file_int (class, pglob.gl_pathv[gloop], 
1293                                               sl_strlen(pglob.gl_pathv[gloop]), check_flags);
1294            }
1295          else
1296            {
1297              which_dirList = type;
1298
1299              count += sh_files_push_dir_int  (class, pglob.gl_pathv[gloop], 
1300                                               sl_strlen(pglob.gl_pathv[gloop]), rdepth, check_flags);
1301            }
1302        }
1303    }
1304  else
1305    {
1306      char * tmp = sh_util_safe_name (p);
1307     
1308      if (pglob.gl_pathc == 0
1309#ifdef GLOB_NOMATCH
1310          || globstatus == GLOB_NOMATCH
1311#endif
1312          )
1313        sh_error_handle ((sh.flag.started != S_TRUE) ? SH_ERR_ERR : SH_ERR_NOTICE, 
1314                         FIL__, __LINE__, 
1315                         globstatus, MSG_FI_GLOB,
1316                         _("No matches found"), tmp);
1317#ifdef GLOB_NOSPACE
1318      else if (globstatus == GLOB_NOSPACE)
1319        sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1320                         globstatus, MSG_FI_GLOB,
1321                         _("Out of memory"), tmp);
1322#endif
1323#ifdef GLOB_ABORTED
1324      else if (globstatus == GLOB_ABORTED)
1325        sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1326                         globstatus, MSG_FI_GLOB,
1327                         _("Read error"), tmp);
1328#endif
1329      else 
1330        sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1331                         globstatus, MSG_FI_GLOB,
1332                         _("Unknown error"), tmp);
1333     
1334      SH_FREE(tmp);
1335     
1336    }
1337 
1338  globfree(&pglob);
1339  SL_RETURN(count, _("sh_files_pushglob"));
1340  return count;
1341}
1342
1343void sh_files_check_globFilePatterns()
1344{
1345  sh_globstack_t * testPattern;
1346  zAVLCursor   cursor;
1347
1348  SL_ENTER(_("sh_files_check_globPatterns"));
1349
1350  SH_MUTEX_LOCK(mutex_zglob);
1351  for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); 
1352       testPattern;
1353       testPattern = (sh_globstack_t *) zAVLNext  (&cursor))
1354    {
1355      if (testPattern->type == SH_LIST_FILE)
1356        {
1357          sh_files_pushglob(testPattern->class, testPattern->type, 
1358                            testPattern->name, testPattern->rdepth,
1359                            testPattern->check_flags, 1);
1360        }
1361    }
1362  SH_MUTEX_UNLOCK(mutex_zglob);
1363  SL_RET0(_("sh_files_check_globPatterns"));
1364}
1365
1366void sh_files_check_globPatterns()
1367{
1368  sh_globstack_t * testPattern;
1369  zAVLCursor   cursor;
1370
1371  SL_ENTER(_("sh_files_check_globPatterns"));
1372
1373  SH_MUTEX_LOCK(mutex_zglob);
1374  for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); 
1375       testPattern;
1376       testPattern = (sh_globstack_t *) zAVLNext  (&cursor))
1377    {
1378      sh_files_pushglob(testPattern->class, testPattern->type, 
1379                        testPattern->name, testPattern->rdepth,
1380                        testPattern->check_flags, 1);
1381    }
1382  SH_MUTEX_UNLOCK(mutex_zglob);
1383  SL_RET0(_("sh_files_check_globPatterns"));
1384}
1385
1386/* the destructor
1387 */
1388void free_globstack (void * inptr)
1389{
1390  sh_globstack_t * here;
1391
1392  SL_ENTER(_("free_globstack"));
1393  if (inptr == NULL)
1394    SL_RET0(_("free_globstack"));
1395  else
1396    here = (sh_globstack_t *) inptr;
1397
1398  if (here->name != NULL)
1399    SH_FREE(here->name);
1400  if (here->type_name != NULL)
1401    SH_FREE(here->type_name);
1402  SH_FREE(here);
1403  SL_RET0(_("free_globstack"));
1404}
1405
1406int sh_files_delglobstack ()
1407{
1408  SL_ENTER(_("sh_files_delglobstack"));
1409
1410  SH_MUTEX_LOCK(mutex_zglob);
1411  zAVLFreeTree (zglobList, free_globstack);
1412  zglobList = NULL;
1413  SH_MUTEX_UNLOCK(mutex_zglob);
1414
1415  SL_RETURN(0, _("sh_files_delglobstack"));
1416}
1417 
1418
1419#else
1420void sh_files_check_globPatterns()
1421{
1422  return;
1423}
1424int sh_files_delglobstack ()
1425{
1426  return 0;
1427}
1428#endif
1429
1430static int sh_files_pushfile (int class, const char * str_s)
1431{
1432  size_t  len;
1433  char  * tmp;
1434  char  * p;
1435
1436  static int reject = 0;
1437
1438  SL_ENTER(_("sh_files_pushfile"));
1439
1440  if (reject == 1)
1441    SL_RETURN((-1),_("sh_files_pushfile"));
1442
1443  /* if we push a filename from the command line, make sure it
1444   * is the only one -- and will stay the only one
1445   */
1446  if (sh.flag.opts == S_TRUE) 
1447    {
1448      sh_files_delfilestack ();
1449      sh_files_deldirstack ();
1450      sh_files_delglobstack ();
1451      reject = 1;
1452    }
1453
1454  p = sh_files_parse_input(str_s, &len);
1455  if (!p || len == 0)
1456    SL_RETURN((-1), _("sh_files_pushfile"));
1457
1458  if (sh.flag.checkSum == SH_CHECK_INIT)
1459    p = sh_dbIO_rootfs_prepend(p);
1460     
1461  if (len >= PATH_MAX) 
1462    {
1463      /* Name too long
1464       */
1465      tmp = sh_util_safe_name (p);
1466      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_2LONG,
1467                       tmp);
1468      SH_FREE(tmp);
1469      SL_RETURN((-1),_("sh_files_pushfile"));
1470    } 
1471  else if (p[0] != '/') 
1472    {
1473      /* Not an absolute path
1474       */
1475      tmp = sh_util_safe_name (p);
1476      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NOPATH,
1477                       tmp);
1478      SH_FREE(tmp);
1479      SL_RETURN((-1),_("sh_files_pushfile"));
1480    } 
1481  else 
1482    {
1483      /* remove a terminating '/', take care of the
1484       * special case of the root directory.
1485       */
1486      if (p[len-1] == '/' && len > 1)
1487        {
1488          p[len-1] = '\0';
1489          --len;
1490        }
1491    } 
1492
1493#ifdef HAVE_GLOB_H
1494  if (0 == sh_files_has_metachar(p))
1495    {
1496      sh_files_push_file_int (class, p, len, sh_files_maskof(class));
1497    }
1498  else
1499    {
1500      sh_files_pushglob (class, SH_LIST_FILE, p, 0, 0, 0);
1501    }
1502
1503#else
1504  sh_files_push_file_int (class, p, len, sh_files_maskof(class));
1505#endif
1506
1507  SH_FREE(p);
1508  SL_RETURN((0),_("sh_files_pushfile"));
1509}
1510
1511
1512/* ------ directories ----- */
1513
1514int sh_files_is_allignore_int (char * str, zAVLTree * tree)
1515{
1516  dirstack_t * ptr;
1517
1518  SL_ENTER(_("sh_files_is_allignore"));
1519
1520  if (tree)
1521    {
1522      ptr = zAVLSearch(tree, str);
1523      if (ptr)
1524        {
1525          if (ptr->class == SH_LEVEL_ALLIGNORE)
1526            SL_RETURN( 1, _("sh_files_is_allignore"));
1527          else
1528            SL_RETURN( 0, _("sh_files_is_allignore"));
1529        }
1530    }
1531  SL_RETURN( 0, _("sh_files_is_allignore"));
1532}
1533
1534int sh_files_is_allignore (char * str)
1535{
1536  int retval = 0;
1537
1538  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
1539  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
1540  retval = sh_files_is_allignore_int(str, zdirListOne);
1541
1542  if (NULL != zdirListTwo && retval == 0)
1543    {
1544      retval = sh_files_is_allignore_int(str, zdirListTwo);
1545    }
1546  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
1547  return retval;
1548}
1549
1550void * sh_dummy_1493_ptr;
1551
1552unsigned long sh_dirs_chk (int which)
1553{
1554  zAVLTree   * tree;
1555  zAVLCursor   cursor;
1556  dirstack_t * ptr;
1557  dirstack_t * dst_ptr;
1558  int          status;
1559  int          tmp_reported;
1560  volatile int          filetype = SH_FILE_UNKNOWN;
1561  volatile unsigned long dcount = 0;
1562  char       * tmp;
1563 
1564  SL_ENTER(_("sh_dirs_chk"));
1565
1566  sh_dummy_1493_ptr = (void *) &ptr;
1567 
1568  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
1569  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
1570  if (which == 1)
1571    tree = zdirListOne;
1572  else
1573    tree = zdirListTwo;
1574
1575  for (ptr = (dirstack_t *) zAVLFirst(&cursor, tree); ptr;
1576       ptr = (dirstack_t *) zAVLNext(&cursor))
1577    {
1578      if (sig_urgent > 0) {
1579        goto out;
1580      }
1581
1582      if (ptr->checked == S_FALSE)
1583        {
1584          SH_MUTEX_LOCK(mutex_zfiles);
1585          /* 28 Aug 2001 check the top level directory
1586           */
1587          status        = S_FALSE;
1588          dst_ptr       = zAVLSearch(zfileList, ptr->name);
1589          if (dst_ptr) 
1590            {
1591              if (dst_ptr->checked == S_FALSE)
1592                {
1593                  BREAKEXIT(sh_files_filecheck);
1594                  tmp_reported = dst_ptr->is_reported;
1595                  filetype = sh_files_filecheck (dst_ptr->class, dst_ptr->check_flags, 
1596                                                 ptr->name, 
1597                                                 NULL,  &tmp_reported, 0);
1598                  dst_ptr->is_reported = tmp_reported;
1599                  (void) handle_filecheck_ret(dst_ptr, NULL, filetype);
1600
1601                  dst_ptr->checked = S_TRUE;
1602                  status           = S_TRUE;
1603                }
1604              else
1605                {
1606                  status           = S_TRUE;
1607                }
1608            }
1609          SH_MUTEX_UNLOCK(mutex_zfiles);
1610
1611          if (status == S_FALSE)
1612            {
1613              tmp_reported = ptr->is_reported;
1614              filetype = sh_files_filecheck (ptr->class,  ptr->check_flags, 
1615                                             ptr->name,  NULL,  &tmp_reported, 0);
1616              ptr->is_reported = tmp_reported;
1617              (void) handle_filecheck_ret(ptr, NULL, filetype);
1618            }
1619
1620          BREAKEXIT(sh_files_checkdir);
1621          status = sh_files_checkdir (ptr->class, ptr->check_flags, 
1622                                      ptr->rdepth, ptr->name, 
1623                                      ptr->name);
1624
1625          if (status < 0 && (!SH_FFLAG_REPORTED_SET(ptr->is_reported))) 
1626            {
1627              /* directory is missing
1628               */
1629              if (S_FALSE == sh_ignore_chk_del(ptr->name))
1630                {
1631                  if (0 != hashreport_missing(ptr->name, 
1632                                              (ptr->class == SH_LEVEL_ALLIGNORE) ? 
1633                                              ShDFLevel[ptr->class] : 
1634                                              ShDFLevel[SH_ERR_T_DIR])) {
1635                    tmp = sh_util_safe_name (ptr->name);
1636                    if (!sh_global_check_silent)
1637                      sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ? 
1638                                       ShDFLevel[ptr->class] : 
1639                                       ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__,
1640                                       0, MSG_FI_MISS, tmp);
1641                    ++sh.statistics.files_report;
1642                    SH_FREE(tmp);
1643                  }
1644                }
1645              if (sh.flag.reportonce == S_TRUE)
1646                SET_SH_FFLAG_REPORTED(ptr->is_reported);
1647            } 
1648          else 
1649            {
1650              /* exists (status >= 0), but was missing (reported == TRUE)
1651               */
1652              if (status >= 0 && SH_FFLAG_REPORTED_SET(ptr->is_reported))
1653                {
1654                  CLEAR_SH_FFLAG_REPORTED(ptr->is_reported);
1655                  sh_hash_clear_flag(ptr->name, SH_FFLAG_ENOENT);
1656#if 0
1657                  /* obsoleted (really?) by the mandatory sh_files_filecheck()
1658                   * above, which will catch missing directories anyway
1659                   */
1660                  tmp = sh_util_safe_name (ptr->name);
1661                  if (!sh_global_check_silent)
1662                    sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ?
1663                                     ShDFLevel[ptr->class] :
1664                                     ShDFLevel[SH_ERR_T_DIR],
1665                                     FIL__, __LINE__, 0, MSG_FI_ADD,
1666                                     tmp);
1667                  ++sh.statistics.files_report;
1668                  SH_FREE(tmp);
1669#endif
1670                }
1671              else if (status == SH_FILE_UNKNOWN)
1672                {
1673                  /* catchall
1674                   */
1675                  tmp = sh_util_safe_name (ptr->name);
1676                  sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0,
1677                                   MSG_FI_FAIL,
1678                                   tmp);
1679                  SH_FREE(tmp);
1680                  if (sh.flag.checkSum != SH_CHECK_INIT)
1681                    sh_hash_set_visited_true(ptr->name);
1682                }
1683
1684              ++dcount;
1685            }
1686          ptr->checked        = S_TRUE;
1687          ptr->childs_checked = S_TRUE;
1688        }
1689
1690      if (sig_urgent > 0) {
1691        goto out;
1692      }
1693
1694    }
1695 out:
1696  ; /* 'label at end of compound statement' */
1697  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
1698
1699  SL_RETURN(dcount, _("sh_dirs_chk"));
1700}
1701
1702int sh_files_pushdir_prelink (const char * str_s)
1703{
1704  return (sh_files_pushdir (SH_LEVEL_PRELINK, str_s));
1705}
1706
1707int sh_files_pushdir_user0 (const char * str_s)
1708{
1709  return (sh_files_pushdir (SH_LEVEL_USER0, str_s));
1710}
1711
1712int sh_files_pushdir_user1 (const char * str_s)
1713{
1714  return (sh_files_pushdir (SH_LEVEL_USER1, str_s));
1715}
1716
1717int sh_files_pushdir_user2 (const char * str_s)
1718{
1719  return (sh_files_pushdir (SH_LEVEL_USER2, str_s));
1720}
1721
1722int sh_files_pushdir_user3 (const char * str_s)
1723{
1724  return (sh_files_pushdir (SH_LEVEL_USER3, str_s));
1725}
1726
1727int sh_files_pushdir_user4 (const char * str_s)
1728{
1729  return (sh_files_pushdir (SH_LEVEL_USER4, str_s));
1730}
1731
1732int sh_files_pushdir_attr (const char * str_s)
1733{
1734  return (sh_files_pushdir (SH_LEVEL_ATTRIBUTES, str_s));
1735}
1736
1737int sh_files_pushdir_ro (const char * str_s)
1738{
1739  return (sh_files_pushdir (SH_LEVEL_READONLY, str_s));
1740}
1741
1742int sh_files_pushdir_log (const char * str_s)
1743{
1744  return (sh_files_pushdir (SH_LEVEL_LOGFILES, str_s));
1745}
1746
1747int sh_files_pushdir_glog (const char * str_s)
1748{
1749  return (sh_files_pushdir (SH_LEVEL_LOGGROW, str_s));
1750}
1751
1752int sh_files_pushdir_noig (const char * str_s)
1753{
1754  return (sh_files_pushdir (SH_LEVEL_NOIGNORE, str_s));
1755}
1756
1757int sh_files_pushdir_allig (const char * str_s)
1758{
1759  return (sh_files_pushdir (SH_LEVEL_ALLIGNORE, str_s));
1760}
1761
1762int set_dirList (int which)
1763{
1764  if (which == 2)
1765    which_dirList = SH_LIST_DIR2;
1766  else
1767    which_dirList = SH_LIST_DIR1;
1768  return 0;
1769}
1770
1771int sh_files_push_dir_int (int class, char * tail, size_t len, int rdepth, unsigned long check_flags)
1772{
1773  zAVLTree   * tree;
1774  dirstack_t * new_item_ptr;
1775  char       * dirName;
1776  int          ret;
1777
1778  SL_ENTER(_("sh_files_push_dir_int"));
1779
1780  dirName = SH_ALLOC(len+1);
1781  sl_strlcpy(dirName, tail, len+1);
1782
1783  new_item_ptr = (dirstack_t * ) SH_ALLOC (sizeof(dirstack_t));
1784
1785  new_item_ptr->name           = dirName;
1786  new_item_ptr->class          = class;
1787  new_item_ptr->check_flags     = check_flags;
1788  new_item_ptr->rdepth         = rdepth;
1789  new_item_ptr->checked        = S_FALSE;
1790  new_item_ptr->is_reported    = 0;
1791  new_item_ptr->childs_checked = S_FALSE;
1792
1793  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
1794  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
1795  if (which_dirList == SH_LIST_DIR1)
1796    {
1797      tree = zdirListOne;
1798    }
1799  else
1800    {
1801      tree = zdirListTwo;
1802    }
1803
1804  if (tree == NULL)
1805    {
1806      tree = zAVLAllocTree (zdirstack_key, zAVL_KEY_STRING);
1807      if (tree == NULL) 
1808        {
1809          (void) safe_logger (0, 0, NULL);
1810          aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1811        }
1812      if (which_dirList == SH_LIST_DIR1)
1813        zdirListOne = tree;
1814      else
1815        zdirListTwo = tree;
1816    }
1817
1818  ret = zAVLInsert (tree, new_item_ptr);
1819  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
1820
1821  if (-1 == ret)
1822    {
1823      (void) safe_logger (0, 0, NULL);
1824      aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1825    }
1826  if (3 == ret)
1827    { 
1828      if (sh.flag.started != S_TRUE)
1829        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
1830                         dirName);
1831      SH_FREE(dirName);
1832      SH_FREE(new_item_ptr);
1833      new_item_ptr = NULL;
1834    }
1835  else
1836    {
1837      if (MODI_AUDIT_ENABLED(check_flags))
1838        {
1839          sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGPATH,
1840                          _("Setting audit watch"),
1841                          _("sh_files_push_file_int"), tail);
1842          sh_audit_mark(tail);
1843        }
1844    }
1845  SL_RETURN(0, _("sh_files_push_dir_int"));
1846}
1847
1848static int sh_files_pushdir (int class, const char * str_s)
1849{
1850  char  * tmp;
1851  size_t  len;
1852  int     rdepth = 0;
1853  char  * tail = NULL;
1854  char  * p;
1855
1856  SL_ENTER(_("sh_files_pushdir"));
1857
1858  if (sh.flag.opts == S_TRUE) {
1859    sh_files_delfilestack ();
1860    sh_files_deldirstack ();
1861    sh_files_delglobstack ();
1862  }
1863
1864  p = sh_files_parse_input(str_s, &len);
1865  if (!p || len == 0)
1866    SL_RETURN((-1),_("sh_files_pushdir"));
1867
1868  if (p[0] != '/')
1869    {
1870      rdepth = strtol(p, &tail, 10);
1871      if (tail == p)
1872        {
1873          SH_FREE(p);
1874          SL_RETURN((-1), _("sh_files_pushdir"));
1875        }
1876    }
1877  else
1878    tail   = p;
1879 
1880
1881  if (tail == p)
1882    {
1883      /* Setting to an invalid number will force MaxRecursionLevel,
1884       * see sh_files_setrec_int()
1885       */
1886      rdepth = (-2);
1887    }
1888  else if ( (rdepth < (-1) || rdepth > 99) || 
1889            ((rdepth == (-1)) && (class != SH_LEVEL_ALLIGNORE)) )
1890    {
1891      SH_FREE(p);
1892      SL_RETURN((-1), _("sh_files_pushdir"));
1893    }
1894
1895  if (sh.flag.checkSum == SH_CHECK_INIT)
1896    tail = sh_dbIO_rootfs_prepend(tail);
1897
1898  len = sl_strlen(tail);
1899
1900  if (len >= PATH_MAX) 
1901    {
1902      tmp = sh_util_safe_name (tail);
1903      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_2LONG,
1904                       tmp);
1905      SH_FREE(tmp);
1906      SH_FREE(p);
1907      SL_RETURN((-1), _("sh_files_pushdir"));
1908    } 
1909  else if (len < 1) 
1910    {
1911      SH_FREE(p);
1912      SL_RETURN((-1), _("sh_files_pushdir"));
1913    } 
1914  else if (tail[0] != '/') 
1915    {
1916      tmp = sh_util_safe_name (tail);
1917      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NOPATH,
1918                       tmp);
1919      SH_FREE(tmp);
1920      SH_FREE(p);
1921      SL_RETURN((-1), _("sh_files_pushdir"));
1922    } 
1923  else 
1924    {
1925      if (tail[len-1] == '/' && len > 1)
1926        {
1927          tail[len-1] = '\0';
1928          --len;
1929        }
1930    } 
1931
1932#ifdef HAVE_GLOB_H
1933  if (0 == sh_files_has_metachar(tail))
1934    {
1935      sh_files_push_dir_int (class, tail, len, rdepth, sh_files_maskof(class));
1936    }
1937  else
1938    {
1939      sh_files_pushglob (class, which_dirList, tail, rdepth, 0, 0);
1940    }
1941#else 
1942  sh_files_push_dir_int (class, tail, len, rdepth, sh_files_maskof(class));
1943#endif
1944
1945  SH_FREE(p);
1946  SL_RETURN((0), _("sh_files_pushdir"));
1947}
1948
1949/**
1950struct sh_dirent {
1951  char             * sh_d_name;
1952  struct sh_dirent * next;
1953};
1954**/
1955
1956void kill_sh_dirlist (struct sh_dirent * dirlist)
1957{
1958  struct sh_dirent * this;
1959
1960  while (dirlist)
1961    {
1962      this    = dirlist->next;
1963      SH_FREE(dirlist->sh_d_name);
1964      SH_FREE(dirlist);
1965      dirlist = this;
1966    }
1967  return;
1968}
1969 
1970/* -- add an entry to a directory listing
1971 */
1972struct sh_dirent * addto_sh_dirlist (struct dirent * thisEntry, 
1973                                     struct sh_dirent * dirlist)
1974{
1975  struct sh_dirent * this;
1976  size_t len;
1977
1978  if (thisEntry == NULL)
1979    return dirlist;
1980 
1981  len = sl_strlen(thisEntry->d_name);
1982  if (len == 0)
1983    return dirlist;
1984  ++len;
1985 
1986  this = SH_ALLOC(sizeof(struct sh_dirent));
1987  if (!this)
1988    return dirlist;
1989
1990  this->sh_d_name = SH_ALLOC(len);
1991  sl_strlcpy(this->sh_d_name, thisEntry->d_name, len);
1992
1993  this->next = dirlist;
1994  return this;
1995}
1996
1997static int sh_check_hardlinks = S_TRUE;
1998
1999/* Simply sets our boolean as to whether this check is active
2000 */
2001int sh_files_check_hardlinks (const char * opt)
2002{
2003  int i;
2004  SL_ENTER(_("sh_files_check_hardlinks"));
2005  i = sh_util_flagval(opt, &sh_check_hardlinks);
2006  SL_RETURN(i, _("sh_files_check_hardlinks"));
2007}
2008
2009struct sh_hle_struct {
2010  long   offset;
2011  char * path;
2012  struct sh_hle_struct * next;
2013};
2014
2015static struct sh_hle_struct * sh_hl_exc = NULL;
2016
2017int sh_files_hle_reg (const char * str)
2018{
2019  long   offset;
2020  size_t len;
2021  char * path;
2022 
2023  struct sh_hle_struct * tmp = sh_hl_exc;
2024
2025  SL_ENTER(_("sh_files_hle_reg"));
2026
2027  /* Free the linked list if called with NULL argument
2028   */
2029  if (str == NULL)
2030    {
2031      while (tmp)
2032        {
2033          sh_hl_exc = tmp->next;
2034          SH_FREE(tmp->path);
2035          SH_FREE(tmp);
2036          tmp = sh_hl_exc;
2037        }
2038      sh_hl_exc = NULL;
2039      SL_RETURN(0, _("sh_files_hle_reg"));
2040    }
2041
2042  /* We expect 'offset:/path'
2043   */
2044  offset = strtol(str, &path, 0);
2045  if ((path == NULL) || (*path == '\0') || (*path != ':') || (path[1] != '/'))
2046    {
2047      SL_RETURN(-1, _("sh_files_hle_reg"));
2048    }
2049  ++path;
2050  len = 1 + sl_strlen(path);
2051
2052  tmp         = SH_ALLOC(sizeof(struct sh_hle_struct));
2053  tmp->path   = SH_ALLOC(len);
2054  sl_strlcpy (tmp->path, path, len);
2055  tmp->offset = offset;
2056  tmp->next   = sh_hl_exc;
2057  sh_hl_exc   = tmp;
2058
2059  SL_RETURN(0, _("sh_files_hle_reg"));
2060}
2061
2062#if !defined(HOST_IS_DARWIN)
2063static int sh_files_hle_test (int offset, char * path)
2064{
2065  struct sh_hle_struct * tmp = sh_hl_exc;
2066
2067  SL_ENTER(_("sh_files_hle_reg"));
2068
2069  while(tmp)
2070    {
2071      if ((offset == tmp->offset) && (0 == strcmp(path, tmp->path)))
2072        {
2073          SL_RETURN(0, _("sh_files_hle_test"));
2074        }
2075      tmp = tmp->next;
2076    }
2077#ifdef HAVE_FNMATCH_H
2078  if ( (offset == 1) && (0 == fnmatch(_("/run/user/*"), path, FNM_PATHNAME)) )
2079    {
2080      /* gvfs directory in /run/user/username/ */
2081      SL_RETURN(0, _("sh_files_hle_test"));
2082    }
2083#endif
2084
2085  SL_RETURN(-1, _("sh_files_hle_test"));
2086}
2087#endif
2088
2089/* This is the LCG from Numerical Recipies. Deterministic.
2090 */
2091static unsigned int simple_rand(unsigned int * state)
2092{
2093  *state = 1664525 * (*state) + 1013904223;
2094  return *state;
2095}
2096
2097void * sh_dummy_dirlist;
2098void * sh_dummy_tmpcat;
2099
2100/* -- Check a single directory and its content. Does not
2101 *    check the directory inode itself.
2102 */
2103int sh_files_checkdir (int iclass, unsigned long check_flags, 
2104                       int idepth, char * iname, 
2105                       char * relativeName)
2106{
2107  struct sh_dirent * dirlist;
2108  struct sh_dirent * dirlist_orig;
2109
2110  DIR *           thisDir = NULL;
2111  struct dirent * thisEntry;
2112#if defined(SH_USE_SCANDIR)
2113  struct dirent **entryList;
2114  int             entry;
2115#endif
2116  int             status;
2117  int             dummy = S_FALSE;
2118  dir_type      * theDir;
2119  ShFileType      checkit;
2120  static unsigned int state = 1;
2121
2122  file_type     * theFile;
2123  char          * tmpname;
2124  char          * tmpcat;
2125  char errbuf[SH_ERRBUF_SIZE];
2126
2127  int             rdepth = 0;
2128  int             class  = 0;
2129  volatile int    rdepth_next;
2130  volatile int    class_next;
2131  volatile int    file_class_next;
2132  volatile unsigned long   check_flags_next;
2133  volatile unsigned long   file_check_flags_next;
2134
2135  volatile int    checked_flag  = S_FALSE;
2136  volatile int    cchecked_flag = S_FALSE;
2137
2138  dirstack_t *    dst_ptr;
2139  dirstack_t *    tmp_ptr;
2140
2141  int             hardlink_num = 0;
2142#if !defined(HOST_IS_DARWIN)
2143  size_t          len;
2144#endif
2145
2146  SL_ENTER(_("sh_files_checkdir"));
2147
2148  if (sig_urgent > 0) {
2149    SL_RETURN((0), _("sh_files_checkdir"));
2150  }
2151
2152  if (iname == NULL || idepth < (-1))
2153    SL_RETURN((-1), _("sh_files_checkdir"));
2154 
2155  if (idepth < 0)
2156    {
2157      /* hash_remove_tree (iname); */
2158      SL_RETURN((0), _("sh_files_checkdir"));
2159    }
2160 
2161  rdepth = idepth;
2162  class  = iclass;
2163 
2164  tmpname = sh_util_safe_name (iname);
2165
2166  /* ---- check for obscure name ----
2167   */
2168  if (iclass != SH_LEVEL_ALLIGNORE)
2169    {
2170      sh_util_obscurename (ShDFLevel[SH_ERR_T_NAME], iname, S_TRUE);
2171    }
2172
2173  if (flag_err_info == S_TRUE)
2174    {
2175      char pstr[32];
2176
2177      sl_strlcpy(pstr, sh_hash_getpolicy(iclass), sizeof(pstr));
2178      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_CHK, pstr, tmpname);
2179    }
2180
2181  /* ---- check input ----
2182   */
2183  if ( sl_strlen(iname) >= PATH_MAX) 
2184    {
2185      sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
2186                       MSG_FI_2LONG,
2187                       tmpname);
2188      SH_FREE(tmpname);
2189      SL_RETURN((-1), _("sh_files_checkdir"));
2190    }
2191 
2192  /* ---- check for absolute path ---- */
2193  if ( iname[0] != '/') 
2194    {
2195      sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
2196                       MSG_FI_NOPATH,
2197                       tmpname);
2198      SH_FREE(tmpname);
2199      SL_RETURN((-1), _("sh_files_checkdir"));
2200    }
2201
2202  /* ---- stat the directory ----
2203   */
2204  theFile = SH_ALLOC(sizeof(file_type));
2205  sl_strlcpy (theFile->fullpath, iname, PATH_MAX);
2206  theFile->attr_string = NULL;
2207  theFile->link_path   = NULL;
2208  theFile->check_flags  = check_flags;
2209
2210  (void) relativeName;
2211  status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_DIR], 
2212                            iname,
2213                            theFile, NULL, iclass);
2214
2215  if ((sig_termfast == 1) || (sig_terminate == 1)) 
2216    {
2217      if (theFile->attr_string) SH_FREE(theFile->attr_string);
2218      if (theFile->link_path)   SH_FREE(theFile->link_path);
2219      SH_FREE(theFile);
2220      SH_FREE(tmpname);
2221      SL_RETURN((0), _("sh_files_checkdir"));
2222    }
2223
2224  if (status == -1)
2225    {
2226      if (theFile->attr_string) SH_FREE(theFile->attr_string);
2227      if (theFile->link_path)   SH_FREE(theFile->link_path);
2228      SH_FREE(theFile);
2229      SH_FREE(tmpname);
2230      SL_RETURN((-1), _("sh_files_checkdir"));
2231    }
2232
2233  if (theFile->c_mode[0] != 'd') 
2234    { 
2235      if (!sh_global_check_silent)
2236        sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
2237                         MSG_FI_NODIR,
2238                         tmpname);
2239      ++sh.statistics.files_nodir;
2240      if (theFile->attr_string) SH_FREE(theFile->attr_string);
2241      if (theFile->link_path)   SH_FREE(theFile->link_path);
2242      SH_FREE(theFile);
2243      SH_FREE(tmpname);
2244      SL_RETURN((-1), _("sh_files_checkdir"));
2245    }
2246
2247  if ((sh.flag.inotify & SH_INOTIFY_INSCAN) != 0)
2248    {
2249      sh_inotify_add_watch_later(iname, &sh_file_watches, &status,
2250                                 iclass, check_flags, SH_INOTIFY_DIR, idepth);
2251    }
2252   
2253  hardlink_num = theFile->hardlinks;
2254
2255  if (theFile->attr_string) SH_FREE(theFile->attr_string);
2256  if (theFile->link_path)   SH_FREE(theFile->link_path);
2257  SH_FREE(theFile);
2258
2259  /* ---- open directory for reading ----
2260   *
2261   * opendir() will fail with ENOTDIR if the path has been changed
2262   * to a non-directory in between lstat() and opendir().
2263   */
2264  thisDir = opendir (iname);
2265
2266  if (thisDir == NULL) 
2267    {
2268      status = errno;
2269      sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
2270                       MSG_E_OPENDIR,
2271                       sh_error_message (status, errbuf, sizeof(errbuf)), tmpname);
2272      SH_FREE(tmpname); 
2273      SL_RETURN((-1), _("sh_files_checkdir"));
2274    }
2275
2276  theDir = SH_ALLOC(sizeof(dir_type));
2277
2278  theDir->NumRegular  = 0;
2279  theDir->NumDirs     = 0;
2280  theDir->NumSymlinks = 0;
2281  theDir->NumFifos    = 0;
2282  theDir->NumSockets  = 0;
2283  theDir->NumCDev     = 0;
2284  theDir->NumBDev     = 0;
2285  theDir->NumDoor     = 0;
2286  theDir->NumPort     = 0;
2287  theDir->NumAll      = 0;
2288  theDir->TotalBytes  = 0;
2289  sl_strlcpy (theDir->DirPath, iname, PATH_MAX); 
2290
2291
2292  sh_dummy_dirlist = (void *) &dirlist;
2293  sh_dummy_tmpcat  = (void *) &tmpcat;
2294
2295  /* ---- read ----
2296   */
2297  SH_MUTEX_LOCK(mutex_readdir);
2298
2299  dirlist = NULL;
2300  dirlist_orig = NULL;
2301
2302#if defined(SH_USE_SCANDIR)
2303  entry = scandir(iname, &entryList, 0, alphasort);
2304  while(entry > 0) { /* scandir() may return -1 on error! */
2305      entry--;
2306      thisEntry = entryList[entry];
2307#else
2308  do {
2309      thisEntry = readdir (thisDir);
2310#endif
2311      if (thisEntry != NULL) 
2312        {
2313          ++theDir->NumAll;
2314          if (sl_strcmp (thisEntry->d_name, ".") == 0)
2315            { 
2316              ++theDir->NumDirs;
2317              continue;
2318            }
2319          if (sl_strcmp (thisEntry->d_name, "..") == 0)
2320            {
2321              ++theDir->NumDirs;
2322              continue;
2323            }
2324          dirlist = addto_sh_dirlist (thisEntry, dirlist);
2325#if defined(SH_USE_SCANDIR)
2326          free(entryList[entry]); /* scandir() mallocs entries */
2327#endif
2328        }
2329  }
2330#if defined(SH_USE_SCANDIR)
2331  free(entryList);
2332#else
2333  while (thisEntry != NULL);
2334#endif
2335 
2336  SH_MUTEX_UNLOCK(mutex_readdir);
2337
2338  closedir (thisDir);
2339
2340  ++sh.statistics.dirs_checked;
2341
2342  dirlist_orig = dirlist;
2343
2344  do {
2345
2346    /* If the directory is empty, dirlist = NULL
2347     */
2348    if (!dirlist)
2349      break;
2350
2351    if (sig_termfast == 1) 
2352      {
2353        SH_FREE(theDir);
2354        SH_FREE(tmpname);
2355        SL_RETURN((0), _("sh_files_checkdir"));
2356      }
2357
2358    BREAKEXIT(sh_derr);
2359
2360    if (0 == (simple_rand(&state) % 5)) (void) sh_derr();
2361   
2362    /* ---- Check the file. ----
2363     */
2364    tmpcat = SH_ALLOC(PATH_MAX);
2365    sl_strlcpy(tmpcat, iname,                   PATH_MAX);
2366    if (sl_strlen(tmpcat) > 1 || tmpcat[0] != '/')
2367      sl_strlcat(tmpcat, "/",                   PATH_MAX);
2368    sl_strlcat(tmpcat, dirlist->sh_d_name,      PATH_MAX);
2369   
2370    rdepth_next     = rdepth - 1;
2371    class_next      = class;
2372    check_flags_next = check_flags;
2373    file_class_next = class;
2374    file_check_flags_next = check_flags;
2375    checked_flag    = -1;
2376    cchecked_flag   = -1;
2377
2378    /* Wed Aug 24 2005 compare against dirListOne, dirListTwo
2379     * this fixes the problem that the directory special file
2380     * is checked with the policy of the parent directory
2381     */
2382    SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
2383    SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
2384    dst_ptr         = (dirstack_t *) zAVLSearch(zdirListOne, tmpcat);
2385
2386    if (dst_ptr) 
2387      {
2388        /* Tue Aug  6 22:13:27 CEST 2002 introduce file_class_next
2389         * this fixes the problem that a policy for the directory
2390         * inode erroneously becomes a policy for the directory itself.
2391         */
2392        file_class_next    = dst_ptr->class;
2393        file_check_flags_next = dst_ptr->check_flags;
2394        checked_flag       = dst_ptr->checked;
2395        cchecked_flag      = dst_ptr->childs_checked;
2396      }
2397
2398    if (checked_flag == -1)
2399      {
2400        dst_ptr         = (dirstack_t *) zAVLSearch(zdirListTwo, tmpcat);
2401
2402        if (dst_ptr) 
2403          {
2404            /* Tue Aug  6 22:13:27 CEST 2002 introduce file_class_next
2405             * this fixes the problem that a policy for the directory
2406             * inode erroneously becomes a policy for the directory itself.
2407             */
2408            file_class_next    = dst_ptr->class;
2409            file_check_flags_next = dst_ptr->check_flags;
2410            checked_flag       = dst_ptr->checked;
2411            cchecked_flag      = dst_ptr->childs_checked;
2412          }
2413      }
2414    SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
2415
2416    SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
2417    dst_ptr         = (dirstack_t *) zAVLSearch(zfileList, tmpcat);
2418
2419    if (dst_ptr) 
2420      {
2421        /* Tue Aug  6 22:13:27 CEST 2002 introduce file_class_next
2422         * this fixes the problem that a policy for the directory
2423         * inode erroneously becomes a policy for the directory itself.
2424         */
2425        file_class_next    = dst_ptr->class;
2426        file_check_flags_next = dst_ptr->check_flags;
2427        checked_flag       = dst_ptr->checked;
2428        /* not set, hence always FALSE                   */
2429        /* cchecked_flag      = dst_ptr->childs_checked; */
2430
2431        if (checked_flag != S_TRUE)
2432          {
2433            /* -- need to check the file itself --
2434             */
2435            if (sh.flag.reportonce == S_TRUE)
2436              dummy = dst_ptr->is_reported;
2437          }
2438      }
2439    SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
2440   
2441    /* ---- Has been checked already. ----
2442     */
2443    if (checked_flag == S_TRUE && cchecked_flag == S_TRUE)
2444      {
2445        /* Mar 11 2004 get ftype for complete directory count
2446         */
2447        checkit = sh_unix_get_ftype(tmpcat);
2448        if (checkit == SH_FILE_DIRECTORY) 
2449          {
2450            ++theDir->NumDirs;
2451          }
2452        SH_FREE(tmpcat);
2453        dirlist = dirlist->next;
2454        continue;
2455      }
2456   
2457    /* --- May be true, false, or not found. ---
2458     */
2459    if (checked_flag == S_TRUE)
2460      {
2461        /* -- need only the file type --
2462         */
2463        checkit = sh_unix_get_ftype(tmpcat);
2464      }
2465    else
2466      {
2467        /* -- need to check the file itself --
2468         */
2469        /* -- moved up --
2470         * if (dst_ptr && sh.flag.reportonce == S_TRUE)
2471         *   dummy = dst_ptr->is_reported;
2472         */
2473
2474        checkit = sh_files_filecheck (file_class_next, file_check_flags_next, 
2475                                      iname, 
2476                                      dirlist->sh_d_name,
2477                                      &dummy, 0);
2478
2479       
2480        SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
2481        dst_ptr         = (dirstack_t *) zAVLSearch(zfileList, tmpcat);
2482
2483        if (dst_ptr && checked_flag == S_FALSE)
2484          dst_ptr->checked = S_TRUE;
2485
2486        /* Thu Mar  7 15:09:40 CET 2002 Propagate the 'reported' flag
2487         */
2488        if (dst_ptr && sh.flag.reportonce == S_TRUE)
2489          dst_ptr->is_reported = dummy;
2490
2491        if (dst_ptr)
2492          dst_ptr->childs_checked = S_TRUE;
2493        SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
2494      }
2495   
2496    if      (checkit == SH_FILE_REGULAR)   
2497      ++theDir->NumRegular;
2498   
2499    else if (checkit == SH_FILE_DIRECTORY) 
2500      {
2501        ++theDir->NumDirs;
2502
2503        if (rdepth_next >= 0 && cchecked_flag != S_TRUE) 
2504          {
2505            rdepth_next = rdepth - 1;
2506           
2507            /* check whether the new directory is in the
2508             * list with a recursion depth already defined
2509             */
2510            checked_flag  = -1;
2511            cchecked_flag = -1;
2512           
2513            SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
2514            SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
2515            tmp_ptr     = (dirstack_t *) zAVLSearch(zdirListOne, tmpcat);
2516
2517            if (tmp_ptr) 
2518              {
2519                TPT((0, FIL__, __LINE__, 
2520                     _("msg=<%s -> recursion depth %d\n>"),
2521                     tmp_ptr->name, tmp_ptr->rdepth));
2522                rdepth_next   = tmp_ptr->rdepth;
2523                class_next    = tmp_ptr->class;
2524                check_flags_next = tmp_ptr->check_flags;
2525                /* 28. Aug 2001 reversed
2526                 */
2527                cchecked_flag = tmp_ptr->childs_checked;
2528                checked_flag  = tmp_ptr->checked;
2529              }
2530           
2531            if (checked_flag == -1)
2532              {
2533                tmp_ptr     = (dirstack_t *) zAVLSearch(zdirListTwo, tmpcat);
2534
2535                if (tmp_ptr) 
2536                  {
2537                    TPT((0, FIL__, __LINE__, 
2538                         _("msg=<%s -> recursion depth %d\n>"),
2539                         tmp_ptr->name, tmp_ptr->rdepth));
2540                    rdepth_next   = tmp_ptr->rdepth;
2541                    class_next    = tmp_ptr->class;
2542                    check_flags_next = tmp_ptr->check_flags;
2543                    /* 28. Aug 2001 reversed
2544                     */
2545                    cchecked_flag = tmp_ptr->childs_checked;
2546                    checked_flag  = tmp_ptr->checked;
2547                  }
2548              }
2549
2550            if (tmp_ptr && cchecked_flag == S_FALSE)
2551              {
2552                tmp_ptr->childs_checked = S_TRUE;
2553                /*
2554                 * 04. Feb 2006 avoid double checking
2555                 */
2556                tmp_ptr->checked        = S_TRUE;
2557              }
2558            SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
2559
2560            if (cchecked_flag == S_FALSE)
2561              {
2562                sh_files_checkdir (class_next, check_flags_next, rdepth_next, 
2563                                   tmpcat, dirlist->sh_d_name);
2564                /*
2565                  tmp_ptr->childs_checked = S_TRUE;
2566                  tmp_ptr->checked        = S_TRUE;
2567                */
2568              }
2569            else if (checked_flag == -1)
2570              sh_files_checkdir (class_next, check_flags_next, rdepth_next, 
2571                                 tmpcat, dirlist->sh_d_name);
2572           
2573          }
2574      }
2575   
2576    else if (checkit == SH_FILE_SYMLINK)   ++theDir->NumSymlinks;
2577    else if (checkit == SH_FILE_FIFO)      ++theDir->NumFifos;
2578    else if (checkit == SH_FILE_SOCKET)    ++theDir->NumSockets;
2579    else if (checkit == SH_FILE_CDEV)      ++theDir->NumCDev;
2580    else if (checkit == SH_FILE_BDEV)      ++theDir->NumBDev;
2581    else if (checkit == SH_FILE_DOOR)      ++theDir->NumDoor;
2582    else if (checkit == SH_FILE_PORT)      ++theDir->NumPort;
2583   
2584    SH_FREE(tmpcat);
2585   
2586    if ((sig_termfast == 1) || (sig_terminate == 1)) 
2587      {
2588        SH_FREE(theDir);
2589        sh_dummy_dirlist = NULL;
2590        SH_FREE(tmpname);
2591        SL_RETURN((0), _("sh_files_checkdir"));
2592      }
2593   
2594    dirlist = dirlist->next;
2595
2596    /* -- moved up, only affects zfileList anyway
2597     * if (dst_ptr)
2598     *   dst_ptr->childs_checked = S_TRUE;
2599     */
2600
2601  } while (dirlist != NULL);
2602
2603  if (flag_err_info == S_TRUE)
2604    {
2605      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DSUM,
2606                       theDir->NumDirs,
2607                       theDir->NumRegular,
2608                       theDir->NumSymlinks,
2609                       theDir->NumFifos,
2610                       theDir->NumSockets,
2611                       theDir->NumCDev,
2612                       theDir->NumBDev);
2613    }
2614
2615  kill_sh_dirlist (dirlist_orig);
2616
2617#if !defined(HOST_IS_DARWIN)
2618  /*
2619   * Hardlink check; not done on MacOS X because of resource forks
2620   */
2621  if ((sh_check_hardlinks == S_TRUE) && (hardlink_num != theDir->NumDirs)) 
2622    {
2623      if (0 != sh_files_hle_test(hardlink_num-theDir->NumDirs, iname))
2624        {
2625          len = strlen(tmpname);
2626          if (sl_ok_adds(len, 256)) 
2627            len += 256;
2628          tmpcat = SH_ALLOC(len);
2629          sl_snprintf(tmpcat, len, 
2630                      _("%s: subdirectory count (%d) != hardlinks (%d)"),
2631                      tmpname, theDir->NumDirs, hardlink_num);
2632          sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
2633                           MSG_E_SUBGEN, tmpcat, _("sh_files_checkdir"));
2634          SH_FREE(tmpcat);
2635        }
2636    }
2637#endif
2638
2639  SH_FREE(tmpname);
2640  SH_FREE(theDir);
2641
2642  sh_dummy_dirlist = NULL;
2643
2644  SL_RETURN((0), _("sh_files_checkdir"));
2645}
2646
2647void sh_files_fixup_mask (int class, unsigned long * check_flags)
2648{
2649  if (class == SH_LEVEL_ALLIGNORE)
2650    MODI_SET((*check_flags), MODI_ALLIGNORE);
2651  sh_tiger_get_mask_hashtype(check_flags);
2652  return;
2653}
2654
2655int get_the_fd (SL_TICKET ticket);
2656
2657static int sh_use_rsrc = S_FALSE;
2658
2659int sh_files_use_rsrc(const char * str)
2660{
2661  return sh_util_flagval(str, &sh_use_rsrc);
2662}
2663
2664static void * sh_dummy_fileName;
2665static void * sh_dummy_tmpname;
2666static void * sh_dummy_tmpdir;
2667
2668ShFileType sh_files_filecheck (int class, unsigned long check_flags,
2669                               const char * dirName, 
2670                               const char * infileName,
2671                               int * reported, 
2672                               int rsrcflag)
2673{
2674  /* 28 Aug 2001 allow NULL fileName
2675   */
2676  char          * fullpath;
2677  char            fileHash[2*(KEY_LEN + 1)];
2678  int             status;
2679  file_type     * theFile;
2680  char          * tmpdir;
2681  char          * tmpname;
2682  const char    * fileName;
2683#if !defined(O_NOATIME)
2684  struct utimbuf  utime_buf;
2685#endif
2686  static unsigned int state = 1;
2687  char            sc;
2688
2689  SL_ENTER(_("sh_files_filecheck"));
2690
2691  fullpath = SH_ALLOC(PATH_MAX);
2692  theFile  = SH_ALLOC(sizeof(file_type));
2693
2694  /* Take the address to keep gcc from putting it into a register.
2695   * Avoids the 'clobbered by longjmp' warning.
2696   */
2697  sh_dummy_fileName = (void *) &fileName;
2698  sh_dummy_tmpname  = (void *) &tmpname;
2699  sh_dummy_tmpdir   = (void *) &tmpdir;
2700
2701  BREAKEXIT(sh_derr);
2702
2703  if (0 == (simple_rand(&state) % 2)) (void) sh_derr();
2704
2705  if (dirName && infileName && (dirName[0] == '/') && (dirName[1] == '\0')
2706      && (infileName[0] == '/') && (infileName[1] == '\0'))
2707    {
2708      fileName = NULL;
2709    }
2710  else
2711    {
2712      fileName = infileName;
2713    }
2714
2715  /* fileName may be NULL if this is a directory
2716   */
2717  if (dirName == NULL /* || fileName == NULL */)
2718    {
2719      SH_MUTEX_LOCK(mutex_thread_nolog);
2720      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NULL);
2721      SH_MUTEX_UNLOCK(mutex_thread_nolog);
2722      SH_FREE(fullpath);
2723      SH_FREE(theFile);
2724      SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
2725    }
2726
2727  if ((fileName != NULL) && (class != SH_LEVEL_ALLIGNORE) && 
2728      (0 != sh_util_obscurename (ShDFLevel[SH_ERR_T_NAME], 
2729                                 fileName, S_FALSE))) 
2730    {
2731      if ((dirName != NULL) && (dirName[0] == '/') && (dirName[1] == '\0')) 
2732        {
2733          tmpname = sh_util_safe_name (fileName);
2734          SH_MUTEX_LOCK(mutex_thread_nolog);
2735          sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, 0,
2736                           MSG_FI_OBSC2,
2737                           "", tmpname);
2738          SH_MUTEX_UNLOCK(mutex_thread_nolog);
2739          SH_FREE(tmpname);
2740        }
2741      else
2742        {
2743          tmpdir  = sh_util_safe_name (dirName);
2744          tmpname = sh_util_safe_name (fileName);
2745          SH_MUTEX_LOCK(mutex_thread_nolog);
2746          sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, 0,
2747                           MSG_FI_OBSC2,
2748                           tmpdir, tmpname);
2749          SH_MUTEX_UNLOCK(mutex_thread_nolog);
2750          SH_FREE(tmpname);
2751          SH_FREE(tmpdir);
2752        }
2753    }   
2754
2755  /* sh_files_fullpath accepts NULL fileName
2756   */
2757  if (0 != sh_files_fullpath (dirName, fileName, fullpath)) 
2758    { 
2759      tmpdir  = sh_util_safe_name (dirName);
2760      tmpname = sh_util_safe_name (fileName);
2761      SH_MUTEX_LOCK(mutex_thread_nolog);
2762      sh_error_handle (ShDFLevel[SH_ERR_T_FILE],  FIL__, __LINE__, 0,
2763                       MSG_FI_2LONG2,
2764                       tmpdir, tmpname);
2765      SH_MUTEX_UNLOCK(mutex_thread_nolog);
2766      SH_FREE(tmpname);
2767      SH_FREE(tmpdir);
2768      SH_FREE(fullpath);
2769      SH_FREE(theFile);
2770      SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
2771    } 
2772
2773  /* stat the file and determine checksum (if a regular file)
2774   */
2775  sl_strlcpy (theFile->fullpath, fullpath, PATH_MAX);
2776  theFile->check_flags    = check_flags /* sh_files_maskof(class) */;
2777  theFile->file_reported = (*reported);
2778  theFile->attr_string   = NULL;
2779  theFile->link_path     = NULL;
2780
2781  TPT(( 0, FIL__, __LINE__, _("msg=<checking file: %s>\n"),  fullpath));
2782
2783  status = sh_unix_getinfo ( (class == SH_LEVEL_ALLIGNORE) ? 
2784                             ShDFLevel[class] : ShDFLevel[SH_ERR_T_FILE], 
2785                             fileName,
2786                             theFile, fileHash, class);
2787
2788  if (status != 0)
2789    {
2790      TPT(( 0, FIL__, __LINE__, _("msg=<file: %s> status=<%d>\n"), 
2791            fullpath, status));
2792      if (class == SH_LEVEL_ALLIGNORE && sh.flag.checkSum != SH_CHECK_INIT)
2793        sh_hash_set_visited_true (fullpath);
2794      if (theFile->attr_string) SH_FREE(theFile->attr_string);
2795      if (theFile->link_path)   SH_FREE(theFile->link_path);
2796      SH_FREE(fullpath);
2797      SH_FREE(theFile);
2798      SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
2799    }
2800 
2801  if (sig_termfast == 1) {
2802    goto ret_point;
2803  }
2804
2805  /* report
2806   */
2807  if ((flag_err_debug == S_TRUE) && (theFile->c_mode[0] == '-'))
2808    {
2809      tmpname = sh_util_safe_name (fullpath); /* fixed in 1.5.4 */
2810      SH_MUTEX_LOCK(mutex_thread_nolog);
2811      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_CSUM,
2812                       fileHash, tmpname);
2813      SH_MUTEX_UNLOCK(mutex_thread_nolog);
2814      SH_FREE(tmpname);
2815    } 
2816  ++sh.statistics.files_checked;
2817     
2818  if ( sh.flag.checkSum == SH_CHECK_INIT) 
2819    {
2820      if (class == SH_LEVEL_ALLIGNORE)
2821        MODI_SET(theFile->check_flags, MODI_ALLIGNORE);
2822      if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath))
2823        MODI_SET(theFile->check_flags, MODI_NOCHECK);
2824      sh_tiger_get_mask_hashtype(&(theFile->check_flags));
2825
2826      sh_dbIO_rootfs_strip(theFile->fullpath);
2827      if (theFile->link_path)
2828        sh_dbIO_rootfs_strip_link(theFile->link_path);
2829      sh_dbIO_data_write (theFile, fileHash);
2830    }
2831  else if (sh.flag.checkSum == SH_CHECK_CHECK
2832           /* && theFile.c_mode[0] == '-' */
2833           /* && class != SH_LEVEL_ALLIGNORE */
2834           ) 
2835    {
2836      if (sh.flag.update == S_TRUE)
2837        {
2838          if (class == SH_LEVEL_ALLIGNORE)
2839            MODI_SET(theFile->check_flags, MODI_ALLIGNORE);
2840          if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath))
2841            MODI_SET(theFile->check_flags, MODI_NOCHECK);
2842          sh_tiger_get_mask_hashtype(&(theFile->check_flags));
2843        }
2844      sh_hash_compdata (class, theFile, fileHash, NULL, -1);
2845    }
2846 
2847  (*reported) = theFile->file_reported;
2848
2849  /* reset the access time
2850   */
2851#if !defined(O_NOATIME)
2852  if (class == SH_LEVEL_NOIGNORE && (theFile->check_flags & MODI_ATM) != 0)
2853    {
2854      utime_buf.actime   = (time_t) theFile->atime;
2855      utime_buf.modtime  = (time_t) theFile->mtime;
2856
2857      retry_aud_utime (FIL__, __LINE__, fullpath, &utime_buf);
2858    }
2859#endif
2860 
2861#if defined(HOST_IS_DARWIN)
2862  /*
2863   * Check for resource fork
2864   */
2865  if ( (sh_use_rsrc == S_TRUE) && (theFile->c_mode[0] != 'd') && (rsrcflag == 0) )
2866    {
2867      int  dummy;
2868      static int rsrc_init = 0;
2869      static char rsrc[17];
2870      char * testpath = SH_ALLOC(PATH_MAX);
2871
2872      if (rsrc_init == 0) {
2873        sl_strlcpy(rsrc, _("..namedfork/rsrc"), 17);
2874        rsrc_init = 1;
2875      }
2876      sl_strlcpy (testpath, fullpath, PATH_MAX);
2877      sl_strlcat (testpath,      "/", PATH_MAX);
2878      sl_strlcat (testpath,     rsrc, PATH_MAX);
2879
2880      if (sl_strlen(testpath) == (17 + sl_strlen(fullpath)))
2881        {
2882          if (S_TRUE == sh_unix_file_exists (testpath))
2883            {
2884              sh_files_filecheck (class, check_flags, fullpath, rsrc, &dummy, 1);
2885            }
2886        }
2887      SH_FREE(testpath);
2888    }
2889#else
2890  (void) rsrcflag; /* avoid compiler warning */
2891#endif
2892
2893 ret_point:
2894
2895  sc = theFile->c_mode[0];
2896
2897  if (theFile->attr_string) SH_FREE(theFile->attr_string);
2898  if (theFile->link_path)   SH_FREE(theFile->link_path);
2899  SH_FREE(fullpath);
2900  SH_FREE(theFile);
2901
2902  switch (sc) 
2903    {
2904    case '-': SL_RETURN(SH_FILE_REGULAR, _("sh_files_filecheck"));   
2905    case 'l': SL_RETURN(SH_FILE_SYMLINK, _("sh_files_filecheck"));   
2906    case 'd': SL_RETURN(SH_FILE_DIRECTORY, _("sh_files_filecheck")); 
2907    case 'c': SL_RETURN(SH_FILE_CDEV, _("sh_files_filecheck"));     
2908    case 'b': SL_RETURN(SH_FILE_BDEV, _("sh_files_filecheck"));     
2909    case '|': SL_RETURN(SH_FILE_FIFO, _("sh_files_filecheck"));     
2910    case 'D': SL_RETURN(SH_FILE_DOOR, _("sh_files_filecheck"));   
2911    case 'P': SL_RETURN(SH_FILE_PORT, _("sh_files_filecheck"));   
2912    case 's': SL_RETURN(SH_FILE_SOCKET, _("sh_files_filecheck"));   
2913    default:  SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));   
2914    }
2915 
2916  /* notreached */
2917}
2918
2919/* concatenate statpath = testdir"/"d_name
2920 */
2921static int sh_files_fullpath (const char * testdir, const char * d_name, 
2922                              char * statpath)
2923{
2924  int llen = 0;
2925
2926  SL_ENTER(_("sh_files_fullpath"));
2927
2928  if (testdir != NULL) 
2929    {
2930      if ( (llen = sl_strlen(testdir)) > (PATH_MAX-2) ) 
2931        SL_RETURN((-1),_("sh_files_fullpath"));
2932      sl_strlcpy(statpath, testdir,    PATH_MAX - 1);
2933    }
2934  if (d_name != NULL) 
2935    {
2936      if (llen > 1 || statpath[0] != '/')
2937        sl_strlcat(statpath, "/",   PATH_MAX);
2938      if ((sl_strlen(d_name) + sl_strlen(statpath)) >= PATH_MAX)
2939        SL_RETURN((-1),_("sh_files_fullpath"));
2940      sl_strlcat(statpath, d_name,   PATH_MAX);
2941    }
2942  if (statpath == NULL) 
2943    SL_RETURN((-1),_("sh_files_fullpath"));
2944  SL_RETURN((0),_("sh_files_fullpath"));
2945}
2946
2947/* -----------------------------------
2948 * Routines required for inotify
2949 * -----------------------------------
2950 */
2951int sh_files_search_dir(char * name, int * class, 
2952                        unsigned long *check_flags, int *reported,
2953                        int * rdepth)
2954{
2955  volatile int retval = 0;
2956#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
2957  sh_globstack_t * testPattern;
2958  zAVLCursor   cursor;
2959#endif
2960  dirstack_t * item;
2961
2962  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
2963  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
2964
2965  item = zAVLSearch(zdirListOne, name);
2966
2967  if (item)
2968    {
2969      *check_flags = item->check_flags;
2970      *class      = item->class;
2971      *reported   = item->is_reported;
2972      *rdepth     = item->rdepth;
2973      item->checked        = S_FALSE;
2974      item->childs_checked = S_FALSE;
2975      item->is_reported    = S_FALSE;
2976      retval = 1;
2977      goto out;
2978    }
2979
2980  item = zAVLSearch(zdirListTwo, name);
2981
2982  if (item)
2983    {
2984      *check_flags = item->check_flags;
2985      *class      = item->class;
2986      *reported   = item->is_reported;
2987      *rdepth     = item->rdepth;
2988      item->checked        = S_FALSE;
2989      item->childs_checked = S_FALSE;
2990      item->is_reported    = S_FALSE;
2991      retval = 1;
2992      goto out;
2993    }
2994
2995#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
2996  SH_MUTEX_LOCK(mutex_zglob);
2997  for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); 
2998       testPattern;
2999       testPattern = (sh_globstack_t *) zAVLNext  (&cursor))
3000    {
3001      if (testPattern->type == SH_LIST_DIR1 || 
3002          testPattern->type == SH_LIST_DIR2)
3003        {
3004          if (0 == fnmatch(testPattern->name, name, FNM_PATHNAME|FNM_PERIOD))
3005            {
3006              *check_flags = testPattern->check_flags;
3007              *class      = testPattern->class;
3008              *rdepth     = testPattern->rdepth;
3009              retval = 1;
3010              break;
3011            }
3012       
3013        }
3014    }
3015  SH_MUTEX_UNLOCK(mutex_zglob);
3016#endif
3017 out:
3018  ; /* 'label at end of compound statement' */
3019  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
3020  return retval;
3021}
3022
3023int sh_files_search_file(char * name, int * class, 
3024                         unsigned long *check_flags, int *reported)
3025{
3026  volatile int retval = 0;
3027#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
3028  sh_globstack_t * testPattern;
3029  zAVLCursor   cursor;
3030#endif
3031  dirstack_t * item;
3032
3033  SH_MUTEX_LOCK(mutex_zfiles);
3034  item = zAVLSearch(zfileList, name);
3035
3036  if (item)
3037    {
3038      *check_flags = item->check_flags;
3039      *class      = item->class;
3040      *reported   = item->is_reported;
3041      retval = 1;
3042    }
3043  SH_MUTEX_UNLOCK(mutex_zfiles);
3044
3045#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
3046  if (retval == 0)
3047    {
3048      SH_MUTEX_LOCK(mutex_zglob);
3049      for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); 
3050           testPattern;
3051           testPattern = (sh_globstack_t *) zAVLNext  (&cursor))
3052        {
3053          if (testPattern->type == SH_LIST_FILE)
3054            {
3055              if (0 == fnmatch(testPattern->name, name, 
3056                               FNM_PATHNAME|FNM_PERIOD))
3057                {
3058                  *check_flags = testPattern->check_flags;
3059                  *class      = testPattern->class;
3060                  retval = 1;
3061                  break;
3062                }
3063             
3064            }
3065        }
3066      SH_MUTEX_UNLOCK(mutex_zglob);
3067    }
3068#endif
3069
3070  return retval;
3071}
3072
3073void sh_files_set_file_reported(const char * name)
3074{
3075  dirstack_t * item;
3076
3077  SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
3078  item = zAVLSearch(zfileList, name);
3079
3080  if (item)
3081    {
3082      if (sh.flag.reportonce == S_TRUE)
3083        SET_SH_FFLAG_REPORTED(item->is_reported);
3084    }
3085  SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
3086  return;
3087}
3088
3089void sh_files_clear_file_reported(const char * name)
3090{
3091  dirstack_t * item;
3092
3093  SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
3094  item = zAVLSearch(zfileList, name);
3095
3096  if (item)
3097    {
3098      CLEAR_SH_FFLAG_REPORTED(item->is_reported);
3099    }
3100  SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
3101  return;
3102}
3103
3104/* -----------------------------------
3105 *
3106 *  The following two routines serve to
3107 *  verify that the user has selected
3108 *  a proper setup for file policies.
3109 *
3110 * -----------------------------------
3111 */
3112static int check_file(char * name)
3113{
3114  dirstack_t * pfilL;
3115  zAVLCursor   cursor;
3116  volatile int retval = -1;
3117
3118  SL_ENTER(_("check_file"));
3119
3120  if (SH_FILE_DIRECTORY == sh_unix_get_ftype(name))
3121    SL_RETURN(0, _("check_file"));
3122
3123  for (pfilL = (dirstack_t *) zAVLFirst (&cursor, zfileList); pfilL;
3124       pfilL = (dirstack_t *) zAVLNext  (&cursor))
3125    {
3126      if (0 == strcmp(name, pfilL->name) &&
3127          (pfilL->check_flags & MODI_ATM) == 0 &&
3128          (pfilL->check_flags & MODI_CTM) == 0 &&
3129          (pfilL->check_flags & MODI_MTM) == 0)
3130        {
3131          retval = 0;
3132          break;
3133        }
3134    }
3135
3136  SL_RETURN(retval, _("check_file"));
3137}
3138
3139static void * sh_dummy_pdirL;
3140
3141int sh_files_test_setup_int (zAVLTree * tree)
3142{
3143  int dlen, flen;
3144  zAVLCursor   cursor1;
3145  zAVLCursor   cursor2;
3146
3147  dirstack_t * pdirL; 
3148  dirstack_t * pfilL;
3149
3150  SL_ENTER(_("sh_files_test_setup"));
3151
3152  sh_dummy_pdirL = (void *) &pdirL;
3153
3154  for (pdirL = (dirstack_t *) zAVLFirst (&cursor1, tree); pdirL;
3155       pdirL = (dirstack_t *) zAVLNext  (&cursor1))
3156    {
3157      dlen = strlen(pdirL->name);
3158
3159      SH_MUTEX_LOCK(mutex_zfiles);
3160      for (pfilL = (dirstack_t *) zAVLFirst (&cursor2, zfileList); pfilL;
3161           pfilL = (dirstack_t *) zAVLNext  (&cursor2))
3162        {
3163          flen = strlen(pfilL->name);
3164
3165          /* check whether file is in tree of dir
3166           */
3167          if ((pfilL->class == SH_LEVEL_READONLY) ||
3168              (pfilL->class == SH_LEVEL_NOIGNORE))
3169            {
3170              ;  /* do nothing */
3171            }
3172          else
3173            {
3174              if ((flen > (dlen+1)) && 
3175                  (pfilL->name[dlen] == '/') &&
3176                  (NULL == strchr(&(pfilL->name[dlen+1]), '/')) && /*30-5-01*/
3177                  (0 == strncmp(pfilL->name, pdirL->name, dlen)))
3178                {
3179                  if ((pdirL->check_flags & MODI_ATM) != 0  ||
3180                      (pdirL->check_flags & MODI_MTM) != 0  ||
3181                      (pdirL->check_flags & MODI_CTM) != 0)
3182                    {
3183                      if (check_file (pdirL->name) != 0)
3184                        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_COLL,
3185                                         pdirL->name, pfilL->name);
3186                    }
3187                }
3188            }
3189        }
3190      SH_MUTEX_UNLOCK(mutex_zfiles);
3191    }
3192
3193  SL_RETURN((0), _("sh_files_test_setup"));
3194}
3195     
3196int sh_files_test_double (zAVLTree * firstList, zAVLTree * secondList)
3197{
3198  int          retval = 0;
3199  zAVLCursor   cursor;
3200  dirstack_t * first;
3201
3202  for (first = (dirstack_t *) zAVLFirst (&cursor, firstList); first;
3203       first = (dirstack_t *) zAVLNext  (&cursor))
3204    {
3205
3206      if (NULL != zAVLSearch(secondList, first->name))
3207        {
3208          sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
3209                           first->name);
3210          retval = 1;
3211        }
3212    }
3213  return retval;
3214}
3215
3216extern void     aud_exit   (const char * file, int line, int fd);
3217     
3218int sh_files_test_setup ()
3219{
3220  int retval;
3221
3222  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
3223  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
3224  /* Test for modifications allowed in ReadOnly directory
3225   */ 
3226  sh_files_test_setup_int (zdirListOne);
3227  sh_files_test_setup_int (zdirListTwo);
3228
3229  /* Test for files/dirz defined twice
3230   */ 
3231  retval = sh_files_test_double (zdirListOne, zdirListTwo);
3232  if (retval != 0)
3233    aud_exit(FIL__, __LINE__, EXIT_FAILURE);
3234
3235  retval = sh_files_test_double (zdirListTwo, zdirListOne);
3236  if (retval != 0)
3237    aud_exit(FIL__, __LINE__, EXIT_FAILURE);
3238  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
3239
3240  return 0;
3241}
3242
3243#endif
3244
3245#ifdef SH_CUTEST
3246#include "CuTest.h"
3247
3248void Test_file_lists (CuTest *tc)
3249{
3250#if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
3251
3252  extern int hash_remove_tree_test(char * s, char * fullpath, size_t len_s);
3253
3254  char * test;
3255  int ret;
3256
3257  sh_files_pushfile_ro("/usr/test");
3258  sh_files_pushfile_ro("/usr/bin/test");
3259  sh_files_pushfile_ro("/usr/bin/foo/test");
3260
3261  sh_files_pushdir_ro("/usr");
3262  sh_files_pushdir_attr("/usr/bin");
3263  sh_files_pushdir_ro("/usr/bin/foo");
3264
3265  add_to_dirlist(zdirListOne);
3266  add_to_dirlist(zdirListTwo);
3267  add_to_filelist(zfileList);
3268
3269  test = sh_files_findfile("/usr/tes");
3270  CuAssertTrue(tc, test == NULL);
3271  test = sh_files_findfile("/usr/test");
3272  CuAssertPtrNotNull(tc, test);
3273  test = sh_files_findfile("/usr/testi");
3274  CuAssertTrue(tc, test == NULL);
3275  test = sh_files_findfile("/test");
3276  CuAssertTrue(tc, test == NULL);
3277
3278  test = sh_files_find_mostspecific_dir("/usr/bin/foo/test");
3279  CuAssertStrEquals(tc, "/usr/bin/foo", test);
3280  test = sh_files_find_mostspecific_dir("/usr/bin/test");
3281  CuAssertStrEquals(tc, "/usr/bin", test);
3282  test = sh_files_find_mostspecific_dir("/usr/test");
3283  CuAssertStrEquals(tc, "/usr", test);
3284  test = sh_files_find_mostspecific_dir("/test");
3285  CuAssertTrue(tc, test == NULL);
3286  test = sh_files_find_mostspecific_dir("/usr/foo/test");
3287  CuAssertStrEquals(tc, "/usr", test);
3288
3289  test = sh_files_find_mostspecific_dir("/usr/bin");
3290  CuAssertStrEquals(tc, "/usr/bin", test);
3291
3292  ret = hash_remove_tree_test("/usr", "/usr/test", strlen("/usr"));
3293  CuAssertIntEquals(tc, S_FALSE, ret);
3294  ret = hash_remove_tree_test("/usr", "/usr/testi", strlen("/usr"));
3295  CuAssertIntEquals(tc, S_TRUE, ret);
3296  ret = hash_remove_tree_test("/usr", "/usr/tes", strlen("/usr"));
3297  CuAssertIntEquals(tc, S_TRUE, ret);
3298
3299  ret = hash_remove_tree_test("/usr/bin", "/usr/test", strlen("/usr/bin"));
3300  CuAssertIntEquals(tc, S_FALSE, ret);
3301  ret = hash_remove_tree_test("/usr/bin", "/usr/testi", strlen("/usr/bin"));
3302  CuAssertIntEquals(tc, S_FALSE, ret);
3303  ret = hash_remove_tree_test("/usr/bin", "/usr/tes", strlen("/usr/bin"));
3304  CuAssertIntEquals(tc, S_FALSE, ret);
3305
3306  ret = hash_remove_tree_test("/usr/bin", "/usr/bin/test", strlen("/usr/bin"));
3307  CuAssertIntEquals(tc, S_FALSE, ret);
3308  ret = hash_remove_tree_test("/usr/bin", "/usr/bin/testi", strlen("/usr/bin"));
3309  CuAssertIntEquals(tc, S_TRUE, ret);
3310  ret = hash_remove_tree_test("/usr/bin", "/usr/bin/tes", strlen("/usr/bin"));
3311  CuAssertIntEquals(tc, S_TRUE, ret);
3312
3313  ret = hash_remove_tree_test("/usr/bin", "/usr/bin", strlen("/usr/bin"));
3314  CuAssertIntEquals(tc, S_TRUE, ret);
3315  ret = hash_remove_tree_test("/usr", "/usr", strlen("/usr"));
3316  CuAssertIntEquals(tc, S_TRUE, ret);
3317  ret = hash_remove_tree_test("/usr", "/usrbin", strlen("/usr"));
3318  CuAssertIntEquals(tc, S_FALSE, ret);
3319  ret = hash_remove_tree_test("/", "/usrbin", strlen("/"));
3320  CuAssertIntEquals(tc, S_TRUE, ret);
3321  ret = hash_remove_tree_test("/", "/usr", strlen("/"));
3322  CuAssertIntEquals(tc, S_FALSE, ret);
3323
3324#else
3325  (void) tc; /* fix compiler warning */
3326  return;
3327#endif
3328}
3329
3330void Test_file_dequote (CuTest *tc)
3331{
3332#if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
3333
3334  char str1[]  = "1234567890";
3335  char str1a[] = "123456\\\"789\\r";
3336  char str1b[] = "12345678\\r9";
3337  char str1c[] = "12345678\\x0a_9";
3338  char str1d[] = "12345678\\007_9";
3339  char str1e[] = "123456789\\\\";
3340
3341  char str2[] = "1234567890\\xw";
3342  char str3[] = "1234567890\\xw99";
3343  char str4[] = "1234567890\\0ww";
3344  char str5[] = "12345\\g67890";
3345  char str6[] = "1234567890\\009a";
3346
3347  char *s, *p, *q;
3348  size_t lo, lr;
3349
3350  s = SH_ALLOC(64); sl_strlcpy(s, str1, 64); p = s; lo = strlen(s); lr = lo;
3351  q = sh_files_C_dequote(s, &lr);
3352  CuAssertPtrNotNull(tc, q);
3353  CuAssertTrue(tc, p  == q);
3354  CuAssertTrue(tc, lr == lo);
3355
3356  s = SH_ALLOC(64); sl_strlcpy(s, str1a, 64); p = s; lo = strlen(s); lr = lo;
3357  q = sh_files_C_dequote(s, &lr);
3358  CuAssertPtrNotNull(tc, q);
3359  CuAssertTrue(tc, p  != q);
3360  CuAssertTrue(tc, 0 == strcmp(q, "123456\"789\r"));
3361  CuAssertTrue(tc, lr == (lo-2));
3362
3363  s = SH_ALLOC(64); sl_strlcpy(s, str1b, 64); p = s; lo = strlen(s); lr = lo;
3364  q = sh_files_C_dequote(s, &lr);
3365  CuAssertPtrNotNull(tc, q);
3366  CuAssertTrue(tc, p  != q);
3367  CuAssertTrue(tc, 0 == strcmp(q, "12345678\r9"));
3368  CuAssertTrue(tc, lr == (lo-1));
3369
3370  s = SH_ALLOC(64); sl_strlcpy(s, str1c, 64); p = s; lo = strlen(s); lr = lo;
3371  q = sh_files_C_dequote(s, &lr);
3372  CuAssertPtrNotNull(tc, q);
3373  CuAssertTrue(tc, p  != q);
3374  CuAssertTrue(tc, 0 == strcmp(q, "12345678\x0a_9"));
3375  CuAssertTrue(tc, lr == (lo-3));
3376
3377  s = SH_ALLOC(64); sl_strlcpy(s, str1d, 64); p = s; lo = strlen(s); lr = lo;
3378  q = sh_files_C_dequote(s, &lr);
3379  CuAssertPtrNotNull(tc, q);
3380  CuAssertTrue(tc, p  != q);
3381  CuAssertTrue(tc, 0 == strcmp(q, "12345678\007_9"));
3382  CuAssertTrue(tc, lr == (lo-3));
3383
3384  s = SH_ALLOC(64); sl_strlcpy(s, str1e, 64); p = s; lo = strlen(s); lr = lo;
3385  q = sh_files_C_dequote(s, &lr);
3386  CuAssertPtrNotNull(tc, q);
3387  CuAssertTrue(tc, p  != q);
3388  CuAssertTrue(tc, 0 == strcmp(q, "123456789\\"));
3389  CuAssertTrue(tc, lr == (lo-1));
3390
3391  s = SH_ALLOC(64); sl_strlcpy(s, str2, 64); p = s; lo = strlen(s); lr = lo;
3392  q = sh_files_C_dequote(s, &lr);
3393  CuAssertTrue(tc, q == NULL);
3394  CuAssertTrue(tc, lr == 0);
3395
3396  s = SH_ALLOC(64); sl_strlcpy(s, str3, 64); p = s; lo = strlen(s); lr = lo;
3397  q = sh_files_C_dequote(s, &lr);
3398  CuAssertTrue(tc, q == NULL);
3399  CuAssertTrue(tc, lr == 0);
3400
3401  s = SH_ALLOC(64); sl_strlcpy(s, str4, 64); p = s; lo = strlen(s); lr = lo;
3402  q = sh_files_C_dequote(s, &lr);
3403  CuAssertTrue(tc, q == NULL);
3404  CuAssertTrue(tc, lr == 0);
3405
3406  s = SH_ALLOC(64); sl_strlcpy(s, str5, 64); p = s; lo = strlen(s); lr = lo;
3407  q = sh_files_C_dequote(s, &lr);
3408  CuAssertTrue(tc, q == NULL);
3409  CuAssertTrue(tc, lr == 0);
3410
3411  s = SH_ALLOC(64); sl_strlcpy(s, str6, 64); p = s; lo = strlen(s); lr = lo;
3412  q = sh_files_C_dequote(s, &lr);
3413  CuAssertTrue(tc, q == NULL);
3414  CuAssertTrue(tc, lr == 0);
3415
3416  return;
3417#else
3418  (void) tc; /* fix compiler warning */
3419  return;
3420#endif
3421}
3422#endif
3423
Note: See TracBrowser for help on using the repository browser.