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

Generated by: LCOV version 1.10