LCOV - code coverage report
Current view: top level - src/client - find.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 199 225 88.4 %
Date: 2022-12-03 01:09:05 Functions: 20 21 95.2 %

          Line data    Source code
       1             : /*
       2             :    Bacula® - The Network Backup Solution
       3             : 
       4             :    Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
       5             : 
       6             :    The main author of Bacula is Kern Sibbald, with contributions from
       7             :    many others, a complete list can be found in the file AUTHORS.
       8             :    This program is Free Software; you can redistribute it and/or
       9             :    modify it under the terms of version three of the GNU Affero General Public
      10             :    License as published by the Free Software Foundation and included
      11             :    in the file LICENSE.
      12             : 
      13             :    This program is distributed in the hope that it will be useful, but
      14             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :    General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU Affero General Public License
      19             :    along with this program; if not, write to the Free Software
      20             :    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
      21             :    02110-1301, USA.
      22             : 
      23             :    Bacula® is a registered trademark of Kern Sibbald.
      24             :    The licensor of Bacula is the Free Software Foundation Europe
      25             :    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
      26             :    Switzerland, email:ftf@fsfeurope.org.
      27             : */
      28             : /*
      29             :    This file was derived from GNU TAR source code. Except for a few key
      30             :    ideas, it has been entirely rewritten for Bacula.
      31             : 
      32             :       Kern Sibbald, MM
      33             : 
      34             :    Thanks to the TAR programmers.
      35             : */
      36             : /*
      37             :    This file was derived from the findlib code from bacula-5.0.3, and
      38             :    heavily modified. Therefore, I have retained the bacula copyright notice.
      39             :    The specific bacula files were:
      40             :    src/findlib/find.c
      41             :    src/findlib/find_one.c.
      42             :    The comment by Kern above, about TAR, was from find_one.c.
      43             : 
      44             :       Graham Keeling, 2014.
      45             : */
      46             : 
      47             : #include "../burp.h"
      48             : #include "../alloc.h"
      49             : #include "../conf.h"
      50             : #include "../fsops.h"
      51             : #include "../linkhash.h"
      52             : #include "../log.h"
      53             : #include "../pathcmp.h"
      54             : #include "../prepend.h"
      55             : #include "../regexp.h"
      56             : #include "../strlist.h"
      57             : #include "cvss.h"
      58             : #include "find.h"
      59             : #include "find_logic.h"
      60             : 
      61             : #ifdef HAVE_LINUX_OS
      62             : #include <sys/statfs.h>
      63             : #endif
      64             : #ifdef HAVE_SUN_OS
      65             : #include <sys/statvfs.h>
      66             : #endif
      67             : 
      68             : static int (*my_send_file)(struct asfd *, struct FF_PKT *, struct conf **);
      69             : 
      70             : // Initialize the find files "global" variables
      71          15 : struct FF_PKT *find_files_init(
      72             :         int callback(struct asfd *asfd, struct FF_PKT *ff, struct conf **confs))
      73             : {
      74             :         struct FF_PKT *ff;
      75             : 
      76          15 :         if(!(ff=(struct FF_PKT *)calloc_w(1, sizeof(struct FF_PKT), __func__))
      77          15 :           || linkhash_init())
      78             :                 return NULL;
      79          15 :         my_send_file=callback;
      80             : 
      81          15 :         return ff;
      82             : }
      83             : 
      84          15 : void find_files_free(struct FF_PKT **ff)
      85             : {
      86          15 :         linkhash_free();
      87          15 :         free_v((void **)ff);
      88          15 : }
      89             : 
      90             : // Return 1 to include the file, 0 to exclude it.
      91          67 : static int in_include_ext(struct strlist *incext, const char *fname)
      92             : {
      93          67 :         int i=0;
      94             :         struct strlist *l;
      95          67 :         const char *cp=NULL;
      96             :         // If not doing include_ext, let the file get backed up.
      97          67 :         if(!incext) return 1;
      98             : 
      99             :         // The flag of the first item contains the maximum number of characters
     100             :         // that need to be checked.
     101             :         // FIX THIS: The next two functions do things very similar to this.
     102          32 :         for(cp=fname+strlen(fname)-1; i<incext->flag && cp>=fname; cp--, i++)
     103             :         {
     104          14 :                 if(*cp!='.') continue;
     105           3 :                 for(l=incext; l; l=l->next)
     106           7 :                         if(!strcasecmp(l->path, cp+1))
     107             :                                 return 1;
     108             :                 // If file has no extension, it cannot be included.
     109             :                 return 0;
     110             :         }
     111             :         return 0;
     112             : }
     113             : 
     114         160 : static int in_exclude_ext(struct strlist *excext, const char *fname)
     115             : {
     116         160 :         int i=0;
     117             :         struct strlist *l;
     118         160 :         const char *cp=NULL;
     119             :         // If not doing exclude_ext, let the file get backed up.
     120         160 :         if(!excext) return 0;
     121             : 
     122             :         // The flag of the first item contains the maximum number of characters
     123             :         // that need to be checked.
     124          50 :         for(cp=fname+strlen(fname)-1; i<excext->flag && cp>=fname; cp--, i++)
     125             :         {
     126          20 :                 if(*cp!='.') continue;
     127           5 :                 for(l=excext; l; l=l->next)
     128           8 :                         if(!strcasecmp(l->path, cp+1))
     129             :                                 return 1;
     130             :                 // If file has no extension, it is included.
     131             :                 return 0;
     132             :         }
     133             :         return 0;
     134             : }
     135             : 
     136             : // Returns the level of compression.
     137           8 : int in_exclude_comp(struct strlist *excom, const char *fname, int compression)
     138             : {
     139           8 :         int i=0;
     140             :         struct strlist *l;
     141           8 :         const char *cp=NULL;
     142             :         // If not doing compression, or there are no excludes, return
     143             :         // straight away.
     144           8 :         if(!compression || !excom) return compression;
     145             : 
     146             :         // The flag of the first item contains the maximum number of characters
     147             :         // that need to be checked.
     148           0 :         for(cp=fname+strlen(fname)-1; i<excom->flag && cp>=fname; cp--, i++)
     149             :         {
     150           0 :                 if(*cp!='.') continue;
     151           0 :                 for(l=excom; l; l=l->next)
     152           0 :                         if(!strcasecmp(l->path, cp+1))
     153             :                                 return 0;
     154             :                 return compression;
     155             :         }
     156             :         return compression;
     157             : }
     158             : 
     159             : /* Return 1 to include the file, 0 to exclude it. */
     160         154 : int in_include_regex(struct strlist *increg, const char *fname)
     161             : {
     162             :         // If not doing include_regex, let the file get backed up.
     163         154 :         if(!increg) return 1;
     164           8 :         for(; increg; increg=increg->next)
     165          14 :                 if(regex_check(increg->re, fname))
     166             :                         return 1;
     167             :         return 0;
     168             : }
     169             : 
     170             : static int in_exclude_regex(struct strlist *excreg, const char *fname)
     171             : {
     172             :         // If not doing exclude_regex, let the file get backed up.
     173          20 :         for(; excreg; excreg=excreg->next)
     174          23 :                 if(regex_check(excreg->re, fname))
     175             :                         return 1;
     176             :         return 0;
     177             : }
     178             : 
     179             : // When recursing into directories, do not want to check the include_ext list.
     180             : #ifndef UTEST
     181             : static
     182             : #endif
     183         160 : int file_is_included_no_incext(struct conf **confs, const char *fname)
     184             : {
     185         160 :         int ret=0;
     186         160 :         int longest=0;
     187         160 :         int matching=0;
     188         160 :         struct strlist *l=NULL;
     189         160 :         struct strlist *best=NULL;
     190             : 
     191         160 :         if(in_exclude_ext(get_strlist(confs[OPT_EXCEXT]), fname)
     192         314 :           || in_exclude_regex(get_strlist(confs[OPT_EXCREG]), fname)
     193         154 :                 || !in_include_regex(get_strlist(confs[OPT_INCREG]), fname))
     194             :                 return 0;
     195             : 
     196             :         // Check include/exclude directories.
     197         384 :         for(l=get_strlist(confs[OPT_INCEXCDIR]); l; l=l->next)
     198             :         {
     199         233 :                 matching=is_subdir(l->path, fname);
     200         233 :                 if(matching>=longest)
     201             :                 {
     202         181 :                         longest=matching;
     203         181 :                         best=l;
     204             :                 }
     205             :         }
     206         151 :         if(!best) ret=0;
     207         151 :         else ret=best->flag;
     208             : 
     209             :         return ret;
     210             : }
     211             : 
     212          83 : static int file_is_included(struct conf **confs,
     213             :         const char *fname, bool top_level)
     214             : {
     215             :         // Always save the top level directory.
     216             :         // This will help in the simulation of browsing backups because it
     217             :         // will mean that there is always a directory before any files:
     218             :         // d /home/graham
     219             :         // f /home/graham/somefile.txt
     220             :         // This means that we can use the stats of the directory (/home/graham
     221             :         // in this example) as the stats of the parent directories (/home,
     222             :         // for example). Trust me on this.
     223          83 :         if(!top_level
     224          67 :           && !in_include_ext(get_strlist(confs[OPT_INCEXT]), fname)) return 0;
     225             : 
     226          80 :         return file_is_included_no_incext(confs, fname);
     227             : }
     228             : 
     229           0 : static int fs_change_is_allowed(struct conf **confs, const char *fname)
     230             : {
     231             :         struct strlist *l;
     232           0 :         if(get_int(confs[OPT_CROSS_ALL_FILESYSTEMS])) return 1;
     233           0 :         for(l=get_strlist(confs[OPT_FSCHGDIR]); l; l=l->next)
     234           0 :                 if(!strcmp(l->path, fname)) return 1;
     235             :         return 0;
     236             : }
     237             : 
     238           6 : static int need_to_read_fifo(struct conf **confs, const char *fname)
     239             : {
     240             :         struct strlist *l;
     241           6 :         if(get_int(confs[OPT_READ_ALL_FIFOS])) return 1;
     242           7 :         for(l=get_strlist(confs[OPT_FIFOS]); l; l=l->next)
     243           5 :                 if(!strcmp(l->path, fname)) return 1;
     244             :         return 0;
     245             : }
     246             : 
     247           2 : static int need_to_read_blockdev(struct conf **confs, const char *fname)
     248             : {
     249             :         struct strlist *l;
     250           2 :         if(get_int(confs[OPT_READ_ALL_BLOCKDEVS])) return 1;
     251           3 :         for(l=get_strlist(confs[OPT_BLOCKDEVS]); l; l=l->next)
     252           3 :                 if(!strcmp(l->path, fname)) return 1;
     253             :         return 0;
     254             : }
     255             : 
     256          27 : static int nobackup_directory(struct strlist *nobackup, const char *path)
     257             : {
     258             :         struct stat statp;
     259          64 :         for(; nobackup; nobackup=nobackup->next)
     260             :         {
     261           7 :                 char *fullpath=NULL;
     262           7 :                 if(!(fullpath=prepend_s(path, nobackup->path)))
     263           2 :                         return -1;
     264          14 :                 if(!lstat(fullpath, &statp))
     265             :                 {
     266           2 :                         free_w(&fullpath);
     267           2 :                         return 1;
     268             :                 }
     269           5 :                 free_w(&fullpath);
     270             :         }
     271             :         return 0;
     272             : }
     273             : 
     274          37 : static int file_size_match(struct FF_PKT *ff_pkt, struct conf **confs)
     275             : {
     276             :         uint64_t sizeleft;
     277          37 :         uint64_t min_file_size=get_uint64_t(confs[OPT_MIN_FILE_SIZE]);
     278          37 :         uint64_t max_file_size=get_uint64_t(confs[OPT_MAX_FILE_SIZE]);
     279          37 :         sizeleft=(uint64_t)ff_pkt->statp.st_size;
     280             : 
     281          37 :         if(min_file_size && sizeleft<min_file_size)
     282             :                 return 0;
     283          36 :         if(max_file_size && sizeleft>max_file_size)
     284             :                 return 0;
     285             :         return 1;
     286             : }
     287             : 
     288             : // Last checks before actually processing the file system entry.
     289          83 : static int my_send_file_w(struct asfd *asfd, struct FF_PKT *ff, bool top_level, struct conf **confs)
     290             : {
     291          83 :         if(!file_is_included(confs, ff->fname, top_level)
     292          79 :                 || is_logic_excluded(confs, ff)) return 0;
     293             : 
     294             :         // Doing the file size match here also catches hard links.
     295          74 :         if(S_ISREG(ff->statp.st_mode)
     296          37 :           && !file_size_match(ff, confs))
     297             :                 return 0;
     298             : 
     299             :         /*
     300             :          * Handle hard linked files
     301             :          * Maintain a list of hard linked files already backed up. This
     302             :          *  allows us to ensure that the data of each file gets backed
     303             :          *  up only once.
     304             :          */
     305          72 :         if(ff->statp.st_nlink > 1
     306          62 :           && (S_ISREG(ff->statp.st_mode)
     307          31 :                 || S_ISCHR(ff->statp.st_mode)
     308          27 :                 || S_ISBLK(ff->statp.st_mode)
     309          27 :                 || S_ISFIFO(ff->statp.st_mode)
     310          27 :                 || S_ISSOCK(ff->statp.st_mode)))
     311             :         {
     312             :                 struct f_link *lp;
     313           4 :                 struct f_link **bucket=NULL;
     314             : 
     315           4 :                 if((lp=linkhash_search(&ff->statp, &bucket)))
     316             :                 {
     317           2 :                         if(!strcmp(lp->name, ff->fname)) return 0;
     318           2 :                         ff->link=lp->name;
     319             :                         /* Handle link, file already saved */
     320           2 :                         ff->type=FT_LNK_H;
     321             :                 }
     322             :                 else
     323             :                 {
     324           2 :                         if(linkhash_add(ff->fname,
     325             :                                 &ff->statp, bucket)) return -1;
     326             :                 }
     327             :         }
     328             : 
     329          72 :         return my_send_file(asfd, ff, confs);
     330             : }
     331             : 
     332             : static int found_regular_file(struct asfd *asfd,
     333             :         struct FF_PKT *ff_pkt, struct conf **confs,
     334             :         bool top_level)
     335             : {
     336          44 :         ff_pkt->type=FT_REG;
     337          44 :         return my_send_file_w(asfd, ff_pkt, top_level, confs);
     338             : }
     339             : 
     340           1 : static int found_soft_link(struct asfd *asfd, struct FF_PKT *ff_pkt, struct conf **confs,
     341             :         char *fname, bool top_level)
     342             : {
     343             :         ssize_t size;
     344           1 :         char *buffer=(char *)alloca(fs_full_path_max+102);
     345             : 
     346           1 :         if((size=readlink(fname, buffer, fs_full_path_max+101))<0)
     347             :         {
     348             :                 /* Could not follow link */
     349           0 :                 ff_pkt->type=FT_NOFOLLOW;
     350             :         }
     351             :         else
     352             :         {
     353           1 :                 buffer[size]=0;
     354           1 :                 ff_pkt->link=buffer; /* point to link */
     355           1 :                 ff_pkt->type=FT_LNK_S;       /* got a soft link */
     356             :         }
     357           1 :         return my_send_file_w(asfd, ff_pkt, top_level, confs);
     358             : }
     359             : 
     360          15 : static int fstype_matches(struct asfd *asfd,
     361             :         struct conf **confs, const char *fname, int inex)
     362             : {
     363             : #if defined(HAVE_LINUX_OS) \
     364             :  || defined(HAVE_SUN_OS)
     365             :         struct strlist *l;
     366             : #if defined(HAVE_LINUX_OS)
     367             :         struct statfs buf;
     368          15 :         if(statfs(fname, &buf))
     369             : #elif defined(HAVE_SUN_OS)
     370             :         struct statvfs buf;
     371             :         if(statvfs(fname, &buf))
     372             : #endif
     373             :         {
     374           0 :                 logw(asfd, get_cntr(confs), "Could not statfs %s: %s\n",
     375           0 :                         fname, strerror(errno));
     376           0 :                 return -1;
     377             :         }
     378          15 :         for(l=get_strlist(confs[inex]); l; l=l->next)
     379             : #if defined(HAVE_LINUX_OS)
     380           0 :                 if(l->flag==buf.f_type)
     381             : #elif defined(HAVE_SUN_OS)
     382             :                 if(strcmp(l->path,buf.f_basetype)==0)
     383             : #endif
     384             :                         return -1;
     385             : #elif defined(HAVE_WIN32)
     386             :         char filesystem_name[MAX_PATH_UTF8 + 1];
     387             :         if (win32_getfsname(fname, filesystem_name, sizeof(filesystem_name)))
     388             :                 return -1;
     389             :         for(strlist *l=get_strlist(confs[inex]); l; l=l->next)
     390             :                 if(strcmp(l->path,filesystem_name)==0)
     391             :                         return -1;
     392             : #endif
     393             :         return 0;
     394             : }
     395             : 
     396             : #if defined(HAVE_WIN32)
     397             : static void windows_reparse_point_fiddling(struct FF_PKT *ff_pkt)
     398             : {
     399             :         /*
     400             :         * We have set st_rdev to 1 if it is a reparse point, otherwise 0,
     401             :         *  if st_rdev is 2, it is a mount point.
     402             :         */
     403             :         /*
     404             :          * A reparse point (WIN32_REPARSE_POINT)
     405             :          *  is something special like one of the following:
     406             :          *  IO_REPARSE_TAG_DFS              0x8000000A
     407             :          *  IO_REPARSE_TAG_DFSR             0x80000012
     408             :          *  IO_REPARSE_TAG_HSM              0xC0000004
     409             :          *  IO_REPARSE_TAG_HSM2             0x80000006
     410             :          *  IO_REPARSE_TAG_SIS              0x80000007
     411             :          *  IO_REPARSE_TAG_SYMLINK          0xA000000C
     412             :          *
     413             :          * A junction point is a:
     414             :          *  IO_REPARSE_TAG_MOUNT_POINT      0xA0000003
     415             :          * which can be either a link to a Volume (WIN32_MOUNT_POINT)
     416             :          * or a link to a directory (WIN32_JUNCTION_POINT)
     417             :          */
     418             :         if (ff_pkt->statp.st_rdev == WIN32_REPARSE_POINT) {
     419             :                 ff_pkt->type = FT_REPARSE;
     420             :         } else if (ff_pkt->statp.st_rdev == WIN32_JUNCTION_POINT) {
     421             :                 ff_pkt->type = FT_JUNCTION;
     422             :         }
     423             : }
     424             : #endif
     425             : 
     426             : // Prototype because process_entries_in_directory() recurses using find_files().
     427             : static int find_files(struct asfd *asfd,
     428             :         struct FF_PKT *ff_pkt, struct conf **confs,
     429             :         char *fname, dev_t parent_device, bool top_level);
     430             : 
     431          19 : static int process_entries_in_directory(struct asfd *asfd, char **nl,
     432             :         int count, char **link, size_t len, size_t *link_len,
     433             :         struct conf **confs, struct FF_PKT *ff_pkt, dev_t our_device)
     434             : {
     435          19 :         int m=0;
     436          19 :         int ret=0;
     437          93 :         for(m=0; m<count; m++)
     438             :         {
     439             :                 size_t i;
     440          74 :                 char *p=NULL;
     441          74 :                 char *q=NULL;
     442             :                 size_t plen;
     443             : 
     444          74 :                 p=nl[m];
     445             : 
     446          74 :                 if(strlen(p)+len>=*link_len)
     447             :                 {
     448           0 :                         *link_len=len+strlen(p)+1;
     449           0 :                         if(!(*link=(char *)
     450           0 :                           realloc_w(*link, (*link_len)+1, __func__)))
     451             :                                 return -1;
     452             :                 }
     453          74 :                 q=(*link)+len;
     454          74 :                 plen=strlen(p);
     455         221 :                 for(i=0; i<plen; i++)
     456         147 :                         *q++=*p++;
     457          74 :                 *q=0;
     458          74 :                 ff_pkt->flen=i;
     459             : 
     460          74 :                 if(file_is_included_no_incext(confs, *link))
     461             :                 {
     462          63 :                         ret=find_files(asfd, ff_pkt,
     463             :                                 confs, *link, our_device, false /*top_level*/);
     464             :                 }
     465             :                 else
     466             :                 {
     467             :                         struct strlist *x;
     468             :                         // Excluded, but there might be a subdirectory that is
     469             :                         // included.
     470          30 :                         for(x=get_strlist(confs[OPT_INCEXCDIR]); x; x=x->next)
     471             :                         {
     472          19 :                                 if(x->flag
     473          16 :                                   && is_subdir(*link, x->path))
     474             :                                 {
     475             :                                         struct strlist *y;
     476           4 :                                         if((ret=find_files(asfd, ff_pkt,
     477             :                                                 confs, x->path,
     478             :                                                 our_device, false)))
     479             :                                                         break;
     480             :                                         // Now need to skip subdirectories of
     481             :                                         // the thing that we just stuck in
     482             :                                         // find_one_file(), or we might get
     483             :                                         // some things backed up twice.
     484           6 :                                         for(y=x->next; y; y=y->next)
     485           2 :                                                 if(y->next
     486           1 :                                                  && is_subdir(x->path, y->path))
     487           1 :                                                         y=y->next;
     488             :                                 }
     489             :                         }
     490             :                 }
     491          74 :                 free_w(&(nl[m]));
     492          74 :                 if(ret) break;
     493             :         }
     494             :         return ret;
     495             : }
     496             : 
     497          27 : static int found_directory(struct asfd *asfd,
     498             :         struct FF_PKT *ff_pkt, struct conf **confs,
     499             :         char *fname, dev_t parent_device, bool top_level)
     500             : {
     501          27 :         int ret=-1;
     502          27 :         char *link=NULL;
     503             :         size_t link_len;
     504             :         size_t len;
     505          27 :         int nbret=0;
     506          27 :         int count=0;
     507             :         dev_t our_device;
     508          27 :         char **nl=NULL;
     509             : 
     510          27 :         our_device=ff_pkt->statp.st_dev;
     511             : 
     512             :         /* Build a canonical directory name with a trailing slash in link var */
     513          27 :         len=strlen(fname);
     514          27 :         link_len=len+200;
     515          27 :         if(!(link=(char *)malloc_w(link_len+2, __func__)))
     516             :                 goto end;
     517          27 :         snprintf(link, link_len, "%s", fname);
     518             : 
     519             :         /* Strip all trailing slashes */
     520          27 :         while(len >= 1 && IsPathSeparator(link[len - 1])) len--;
     521             :         /* add back one */
     522          27 :         link[len++]='/';
     523          27 :         link[len]=0;
     524             : 
     525          27 :         ff_pkt->link=link;
     526          27 :         ff_pkt->type=FT_DIR;
     527             : 
     528             : #if defined(HAVE_WIN32)
     529             :         windows_reparse_point_fiddling(ff_pkt);
     530             : #endif
     531             : 
     532          27 :         if(my_send_file_w(asfd, ff_pkt, top_level, confs))
     533             :                 goto end;
     534             : 
     535             :         // After my_send_file_w, so that we backup the directory itself.
     536          27 :         if((nbret=nobackup_directory(get_strlist(confs[OPT_NOBACKUP]),
     537          27 :                 ff_pkt->fname)))
     538             :         {
     539           2 :                 if(nbret<0) goto end; // Error.
     540           2 :                 ret=0; // Do not back it up.
     541           2 :                 goto end;
     542             :         }
     543             : 
     544          25 :         if(ff_pkt->type==FT_REPARSE || ff_pkt->type==FT_JUNCTION)
     545             :         {
     546             :                 // Ignore.
     547             :                 ret=0;
     548             :                 goto end;
     549             :         }
     550             : 
     551          25 :         if(top_level
     552          10 :           || (parent_device!=ff_pkt->statp.st_dev
     553             : #if defined(HAVE_WIN32)
     554             :                 || ff_pkt->statp.st_rdev==WIN32_MOUNT_POINT
     555             : #endif
     556             :                 ))
     557             :         {
     558          15 :                 if(fstype_matches(asfd, confs, ff_pkt->fname, OPT_EXCFS)
     559          15 :                   || (get_strlist(confs[OPT_INCFS])
     560           0 :                      && !fstype_matches(asfd, confs, ff_pkt->fname, OPT_INCFS)))
     561             :                 {
     562           0 :                         if(top_level)
     563           0 :                                 logw(asfd, get_cntr(confs),
     564             :                                         "Skipping '%s' because of file system include or exclude.\n", fname);
     565           0 :                         ret=my_send_file_w(asfd, ff_pkt, top_level, confs);
     566           0 :                         goto end;
     567             :                 }
     568          15 :                 if(!top_level && !fs_change_is_allowed(confs, ff_pkt->fname))
     569             :                 {
     570           0 :                         ff_pkt->type=FT_NOFSCHG;
     571             :                         // Just backup the directory and return.
     572           0 :                         ret=my_send_file_w(asfd, ff_pkt, top_level, confs);
     573           0 :                         goto end;
     574             :                 }
     575             :         }
     576             : 
     577          25 :         ff_pkt->link=ff_pkt->fname;
     578             : 
     579          25 :         errno=0;
     580          25 :         switch(entries_in_directory_alphasort(fname,
     581             :                 &nl, &count, get_int(confs[OPT_ATIME]),
     582             :                 /* follow_symlinks */ 0))
     583             :         {
     584             :                 case 0: break;
     585             :                 case 1:
     586           0 :                         ff_pkt->type=FT_NOOPEN;
     587           0 :                         ret=my_send_file_w(asfd, ff_pkt, top_level, confs);
     588             :                 default:
     589             :                         goto end;
     590             :         }
     591             : 
     592          25 :         if(nl)
     593             :         {
     594          19 :                 if(process_entries_in_directory(asfd, nl, count,
     595             :                         &link, len, &link_len, confs, ff_pkt, our_device))
     596             :                                 goto end;
     597             :         }
     598             :         ret=0;
     599             : end:
     600          27 :         free_w(&link);
     601          27 :         free_v((void **)&nl);
     602          27 :         return ret;
     603             : }
     604             : 
     605           9 : static int found_other(struct asfd *asfd, struct FF_PKT *ff_pkt,
     606             :         struct conf **confs, bool top_level)
     607             : {
     608             : #ifdef HAVE_FREEBSD_OS
     609             :         /*
     610             :          * On FreeBSD, all block devices are character devices, so
     611             :          *   to be able to read a raw disk, we need the check for
     612             :          *   a character device.
     613             :          * crw-r----- 1 root  operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
     614             :          * crw-r----- 1 root  operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
     615             :          */
     616             :         if((S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))
     617             :                 && need_to_read_blockdev(confs, ff_pkt->fname))
     618             :         {
     619             : #else
     620           9 :         if(S_ISBLK(ff_pkt->statp.st_mode)
     621           2 :                 && need_to_read_blockdev(confs, ff_pkt->fname))
     622             :         {
     623             : #endif
     624             :                 /* raw partition */
     625           2 :                 ff_pkt->type=FT_RAW;
     626             :         }
     627           7 :         else if(S_ISFIFO(ff_pkt->statp.st_mode)
     628           6 :                 && need_to_read_fifo(confs, ff_pkt->fname))
     629             :         {
     630           4 :                 ff_pkt->type=FT_FIFO;
     631             :         }
     632             :         else
     633             :         {
     634             :                 /* The only remaining are special (character, ...) files */
     635           3 :                 ff_pkt->type=FT_SPEC;
     636             :         }
     637           9 :         return my_send_file_w(asfd, ff_pkt, top_level, confs);
     638             : }
     639             : 
     640          83 : static int find_files(
     641             :         struct asfd *asfd,
     642             :         struct FF_PKT *ff_pkt,
     643             :         struct conf **confs,
     644             :         char *fname,
     645             :         dev_t parent_device,
     646             :         bool top_level
     647             : ) {
     648          83 :         ff_pkt->fname=fname;
     649          83 :         ff_pkt->link=fname;
     650             : 
     651             : #ifdef HAVE_WIN32
     652             :         ff_pkt->use_winapi=get_use_winapi(
     653             :                 get_string(confs[OPT_REMOTE_DRIVES]),
     654             :                 ff_pkt->fname[0]
     655             :         );
     656             :         if(win32_lstat(fname, &ff_pkt->statp, &ff_pkt->winattr))
     657             : #else
     658         166 :         if(lstat(fname, &ff_pkt->statp))
     659             : #endif
     660             :         {
     661           2 :                 ff_pkt->type=FT_NOSTAT;
     662           2 :                 return my_send_file_w(asfd, ff_pkt, top_level, confs);
     663             :         }
     664             : 
     665          81 :         if(S_ISREG(ff_pkt->statp.st_mode))
     666          88 :                 return found_regular_file(asfd, ff_pkt, confs, top_level);
     667          37 :         else if(S_ISLNK(ff_pkt->statp.st_mode))
     668             :         {
     669             : #ifdef S_IFLNK
     670             :                 /* A symlink.
     671             :                    If they have specified the symlink in a read_blockdev
     672             :                    argument, treat it as a block device.
     673             :                 */
     674             :                 struct strlist *l;
     675           4 :                 for(l=get_strlist(confs[OPT_BLOCKDEVS]); l; l=l->next)
     676             :                 {
     677           3 :                         if(!strcmp(l->path, fname))
     678             :                         {
     679           2 :                                 ff_pkt->statp.st_mode ^= S_IFLNK;
     680           2 :                                 ff_pkt->statp.st_mode |= S_IFBLK;
     681           2 :                                 return found_other(asfd, ff_pkt, confs,
     682             :                                         top_level);
     683             :                         }
     684             :                 }
     685             : #endif
     686           1 :                 return found_soft_link(asfd, ff_pkt, confs, fname, top_level);
     687             :         }
     688          34 :         else if(S_ISDIR(ff_pkt->statp.st_mode))
     689          27 :                 return found_directory(asfd, ff_pkt, confs, fname,
     690             :                         parent_device, top_level);
     691             :         else
     692           7 :                 return found_other(asfd, ff_pkt, confs, top_level);
     693             : }
     694             : 
     695          16 : int find_files_begin(struct asfd *asfd,
     696             :         struct FF_PKT *ff_pkt, struct conf **confs, char *fname)
     697             : {
     698          16 :         return find_files(asfd, ff_pkt,
     699             :                 confs, fname, (dev_t)-1, 1 /* top_level */);
     700             : }

Generated by: LCOV version 1.13