]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/find_one.c
Fix seg fault in ignoredir code
[bacula/bacula] / bacula / src / findlib / find_one.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 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 two of the GNU 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 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
30    This file was derived from GNU TAR source code. Except for a few key
31    ideas, it has been entirely rewritten for Bacula.
32
33       Kern Sibbald, MM
34
35    Thanks to the TAR programmers.
36
37      Version $Id$
38
39  */
40
41 #include "bacula.h"
42 #include "find.h"
43 #ifdef HAVE_DARWIN_OS
44 #include <sys/param.h>
45 #include <sys/mount.h>
46 #include <sys/attr.h>
47 #endif
48
49 extern int32_t name_max;              /* filename max length */
50 extern int32_t path_max;              /* path name max length */
51
52 /*
53  * Structure for keeping track of hard linked files, we
54  *   keep an entry for each hardlinked file that we save,
55  *   which is the first one found. For all the other files that
56  *   are linked to this one, we save only the directory
57  *   entry so we can link it.
58  */
59 struct f_link {
60     struct f_link *next;
61     dev_t dev;                        /* device */
62     ino_t ino;                        /* inode with device is unique */
63     uint32_t FileIndex;               /* Bacula FileIndex of this file */
64     char name[1];                     /* The name */
65 };
66
67 typedef struct f_link link_t;
68 #define LINK_HASHTABLE_BITS 16
69 #define LINK_HASHTABLE_SIZE (1<<LINK_HASHTABLE_BITS)
70 #define LINK_HASHTABLE_MASK (LINK_HASHTABLE_SIZE-1)
71
72 static inline int LINKHASH(const struct stat &info)
73 {
74     int hash = info.st_dev;
75     unsigned long long i = info.st_ino;
76     hash ^= i;
77     i >>= 16;
78     hash ^= i;
79     i >>= 16;
80     hash ^= i;
81     i >>= 16;
82     hash ^= i;
83     return hash & LINK_HASHTABLE_MASK;
84 }
85
86 /*
87  * Create a new directory Find File packet, but copy
88  *   some of the essential info from the current packet.
89  *   However, be careful to zero out the rest of the 
90  *   packet.
91  */
92 static FF_PKT *new_dir_ff_pkt(FF_PKT *ff_pkt)
93 {
94    FF_PKT *dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
95    memcpy(dir_ff_pkt, ff_pkt, sizeof(FF_PKT));
96    dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
97    dir_ff_pkt->link = bstrdup(ff_pkt->link);
98    dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME);
99    dir_ff_pkt->included_files_list = NULL;
100    dir_ff_pkt->excluded_files_list = NULL;
101    dir_ff_pkt->excluded_paths_list = NULL;
102    dir_ff_pkt->linkhash = NULL;
103    dir_ff_pkt->fname_save = NULL;
104    dir_ff_pkt->link_save = NULL;
105    return dir_ff_pkt;
106 }
107
108 /*
109  * Free the temp directory ff_pkt
110  */
111 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
112 {
113    free(dir_ff_pkt->fname);
114    free(dir_ff_pkt->link);
115    free_pool_memory(dir_ff_pkt->sys_fname);
116    if (dir_ff_pkt->fname_save) {
117       free_pool_memory(dir_ff_pkt->fname_save);
118    }
119    if (dir_ff_pkt->link_save) {
120       free_pool_memory(dir_ff_pkt->link_save);
121    }
122    free(dir_ff_pkt);
123 }
124
125 /*
126  * Check to see if we allow the file system type of a file or directory.
127  * If we do not have a list of file system types, we accept anything.
128  */
129 static int accept_fstype(FF_PKT *ff, void *dummy) {
130    int i;
131    char fs[1000];
132    bool accept = true;
133
134    if (ff->fstypes.size()) {
135       accept = false;
136       if (!fstype(ff->fname, fs, sizeof(fs))) {
137          Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
138       } else {
139          for (i = 0; i < ff->fstypes.size(); ++i) {
140             if (strcmp(fs, (char *)ff->fstypes.get(i)) == 0) {
141                Dmsg2(100, "Accepting fstype %s for \"%s\"\n", fs, ff->fname);
142                accept = true;
143                break;
144             }
145             Dmsg3(200, "fstype %s for \"%s\" does not match %s\n", fs,
146                   ff->fname, ff->fstypes.get(i));
147          }
148       }
149    }
150    return accept;
151 }
152
153 /*
154  * Check to see if we allow the drive type of a file or directory.
155  * If we do not have a list of drive types, we accept anything.
156  */
157 static int accept_drivetype(FF_PKT *ff, void *dummy) {
158    int i;
159    char dt[100];
160    bool accept = true;
161
162    if (ff->drivetypes.size()) {
163       accept = false;
164       if (!drivetype(ff->fname, dt, sizeof(dt))) {
165          Dmsg1(50, "Cannot determine drive type for \"%s\"\n", ff->fname);
166       } else {
167          for (i = 0; i < ff->drivetypes.size(); ++i) {
168             if (strcmp(dt, (char *)ff->drivetypes.get(i)) == 0) {
169                Dmsg2(100, "Accepting drive type %s for \"%s\"\n", dt, ff->fname);
170                accept = true;
171                break;
172             }
173             Dmsg3(200, "drive type %s for \"%s\" does not match %s\n", dt,
174                   ff->fname, ff->drivetypes.get(i));
175          }
176       }
177    }
178    return accept;
179 }
180
181 /*
182  * This function determines whether we can use getattrlist()
183  * It's odd, but we have to use the function to determine that...
184  * Also, the man pages talk about things as if they were implemented.
185  *
186  * On Mac OS X, this succesfully differentiates between HFS+ and UFS
187  * volumes, which makes me trust it is OK for others, too.
188  */
189 static bool volume_has_attrlist(const char *fname)
190 {
191 #ifdef HAVE_DARWIN_OS
192    struct statfs st;
193    struct volinfo_struct {
194       unsigned long length;               /* Mandatory field */
195       vol_capabilities_attr_t info;       /* Volume capabilities */
196    } vol;
197    struct attrlist attrList;
198
199    memset(&attrList, 0, sizeof(attrList));
200    attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
201    attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES;
202    if (statfs(fname, &st) == 0) {
203       /* We need to check on the mount point */
204       if (getattrlist(st.f_mntonname, &attrList, &vol, sizeof(vol), FSOPT_NOFOLLOW) == 0
205             && (vol.info.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)
206             && (vol.info.valid[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)) {
207          return true;
208       }
209    }
210 #endif
211    return false;
212 }
213
214 /*
215  * check for BSD nodump flag
216  */
217 static bool no_dump(JCR *jcr, FF_PKT *ff_pkt)
218 {
219 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
220    if ( (ff_pkt->flags & FO_HONOR_NODUMP) &&
221         (ff_pkt->statp.st_flags & UF_NODUMP) ) {
222       Jmsg(jcr, M_INFO, 1, _("     NODUMP flag set - will not process %s\n"),
223            ff_pkt->fname);
224       return true;                    /* do not backup this file */
225    }
226 #endif
227    return false;                      /* do backup */
228 }
229
230 /* check if a file have changed during backup and display an error */
231 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
232 {
233    struct stat statp;
234    Dmsg1(500, "has_file_changed fname=%s\n",ff_pkt->fname);
235
236    if (ff_pkt->type != FT_REG) { /* not a regular file */
237       return false;
238    }
239
240    if (lstat(ff_pkt->fname, &statp) != 0) {
241       berrno be;
242       Jmsg(jcr, M_WARNING, 0, 
243            _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.bstrerror());
244       return true;
245    }
246
247    if (statp.st_mtime != ff_pkt->statp.st_mtime) {
248       /* TODO: add time of changes */
249       Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname);
250       return true;
251    }
252
253    if (statp.st_ctime != ff_pkt->statp.st_ctime) {
254       /* TODO: add time of changes */
255       Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname);
256       return true;
257    }
258   
259    if (statp.st_size != ff_pkt->statp.st_size) {
260       /* TODO: add size change */
261       Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
262       return true;
263    }
264
265    if ((statp.st_blksize != ff_pkt->statp.st_blksize) ||
266        (statp.st_blocks  != ff_pkt->statp.st_blocks)) {
267       /* TODO: add size change */
268       Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
269       return true;
270    }
271
272    return false;
273 }
274
275 /*
276  * For incremental/diffential or accurate backups, we
277  *   determine if the current file has changed.
278  */
279 static bool check_changes(JCR *jcr, FF_PKT *ff_pkt)
280 {
281    /* in special mode (like accurate backup), the programmer can 
282     * choose his comparison function.
283     */
284    if (ff_pkt->check_fct) {
285       return ff_pkt->check_fct(jcr, ff_pkt);
286    }
287
288    /* For normal backups (incr/diff), we use this default
289     * behaviour
290     */
291    if (ff_pkt->incremental &&
292        (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
293         ((ff_pkt->flags & FO_MTIMEONLY) ||
294          ff_pkt->statp.st_ctime < ff_pkt->save_time))) 
295    {
296       return false;
297    } 
298
299    return true;
300 }
301
302 static bool have_ignoredir(FF_PKT *ff_pkt)
303 {
304    struct stat sb;
305    char tmp_name[MAXPATHLEN];
306    char *ignoredir;
307
308    /* Ensure that pointers are defined */
309    if (!ff_pkt->fileset || !ff_pkt->fileset->incexe) {
310       return false;
311    }
312    ignoredir = ff_pkt->fileset->incexe->ignoredir;
313    
314    if (ignoredir) {
315       if (strlen(ff_pkt->fname) + strlen(ignoredir) + 2 > MAXPATHLEN) {
316          return false;
317       }
318
319       strcpy(tmp_name, ff_pkt->fname);
320       strcat(tmp_name, "/");
321       strcat(tmp_name, ignoredir);
322       if (stat(tmp_name, &sb) == 0) {
323          Dmsg2(100, "Directory '%s' ignored (found %s)\n",
324                ff_pkt->fname, ignoredir);
325          return true;      /* Just ignore this directory */
326       } 
327    }
328    return false;
329 }
330
331 /*
332  * Find a single file.
333  * handle_file is the callback for handling the file.
334  * p is the filename
335  * parent_device is the device we are currently on
336  * top_level is 1 when not recursing or 0 when
337  *  descending into a directory.
338  */
339 int
340 find_one_file(JCR *jcr, FF_PKT *ff_pkt, 
341                int handle_file(JCR *jcr, FF_PKT *ff, bool top_level),
342                char *fname, dev_t parent_device, bool top_level)
343 {
344    struct utimbuf restore_times;
345    int rtn_stat;
346    int len;
347
348    ff_pkt->fname = ff_pkt->link = fname;
349
350    if (lstat(fname, &ff_pkt->statp) != 0) {
351        /* Cannot stat file */
352        ff_pkt->type = FT_NOSTAT;
353        ff_pkt->ff_errno = errno;
354        return handle_file(jcr, ff_pkt, top_level);
355    }
356
357    Dmsg1(300, "File ----: %s\n", fname);
358
359    /* Save current times of this directory in case we need to
360     * reset them because the user doesn't want them changed.
361     */
362    restore_times.actime = ff_pkt->statp.st_atime;
363    restore_times.modtime = ff_pkt->statp.st_mtime;
364
365    /*
366     * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
367     */
368    if (top_level) {
369       if (!accept_fstype(ff_pkt, NULL)) {
370          ff_pkt->type = FT_INVALIDFS;
371          if (ff_pkt->flags & FO_KEEPATIME) {
372             utime(fname, &restore_times);
373          }
374
375          char fs[100];
376
377          if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
378              bstrncpy(fs, "unknown", sizeof(fs));
379          }
380
381          Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has unlisted fstype \"%s\"\n"), fname, fs);
382          return 1;      /* Just ignore this error - or the whole backup is cancelled */
383       }
384       if (!accept_drivetype(ff_pkt, NULL)) {
385          ff_pkt->type = FT_INVALIDDT;
386          if (ff_pkt->flags & FO_KEEPATIME) {
387             utime(fname, &restore_times);
388          }
389
390          char dt[100];
391
392          if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
393              bstrncpy(dt, "unknown", sizeof(dt));
394          }
395
396          Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has an unlisted drive type \"%s\"\n"), fname, dt);
397          return 1;      /* Just ignore this error - or the whole backup is cancelled */
398       }
399       ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
400    }
401
402    /*
403     * Ignore this entry if no_dump() returns true
404     */
405    if (no_dump(jcr, ff_pkt)) {
406            Dmsg1(100, "'%s' ignored (NODUMP flag set)\n",
407                  ff_pkt->fname);
408            return 1;
409    }
410
411    /*
412     * If this is an Incremental backup, see if file was modified
413     * since our last "save_time", presumably the last Full save
414     * or Incremental.
415     */
416    if (   ff_pkt->incremental 
417        && !S_ISDIR(ff_pkt->statp.st_mode) 
418        && !check_changes(jcr, ff_pkt)) 
419    {
420       Dmsg1(500, "Non-directory incremental: %s\n", ff_pkt->fname);
421       ff_pkt->type = FT_NOCHG;
422       return handle_file(jcr, ff_pkt, top_level);
423    }
424
425 #ifdef HAVE_DARWIN_OS
426    if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->volhas_attrlist
427          && S_ISREG(ff_pkt->statp.st_mode)) {
428        /* TODO: initialise attrList once elsewhere? */
429        struct attrlist attrList;
430        memset(&attrList, 0, sizeof(attrList));
431        attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
432        attrList.commonattr = ATTR_CMN_FNDRINFO;
433        attrList.fileattr = ATTR_FILE_RSRCLENGTH;
434        if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
435                 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
436           ff_pkt->type = FT_NOSTAT;
437           ff_pkt->ff_errno = errno;
438           return handle_file(jcr, ff_pkt, top_level);
439        }
440    }
441 #endif
442
443    ff_pkt->LinkFI = 0;
444    /*
445     * Handle hard linked files
446     *
447     * Maintain a list of hard linked files already backed up. This
448     *  allows us to ensure that the data of each file gets backed
449     *  up only once.
450     */
451    if (!(ff_pkt->flags & FO_NO_HARDLINK)
452        && ff_pkt->statp.st_nlink > 1
453        && (S_ISREG(ff_pkt->statp.st_mode)
454            || S_ISCHR(ff_pkt->statp.st_mode)
455            || S_ISBLK(ff_pkt->statp.st_mode)
456            || S_ISFIFO(ff_pkt->statp.st_mode)
457            || S_ISSOCK(ff_pkt->statp.st_mode))) {
458
459        struct f_link *lp;
460        if (ff_pkt->linkhash == NULL) {
461            ff_pkt->linkhash = (link_t **)bmalloc(LINK_HASHTABLE_SIZE * sizeof(link_t *));
462            memset(ff_pkt->linkhash, 0, LINK_HASHTABLE_SIZE * sizeof(link_t *));
463        }
464        const int linkhash = LINKHASH(ff_pkt->statp);
465
466       /* Search link list of hard linked files */
467        for (lp = ff_pkt->linkhash[linkhash]; lp; lp = lp->next)
468          if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
469              lp->dev == (dev_t)ff_pkt->statp.st_dev) {
470              /* If we have already backed up the hard linked file don't do it again */
471              if (strcmp(lp->name, fname) == 0) {
472                 Dmsg2(400, "== Name identical skip FI=%d file=%s\n", lp->FileIndex, fname);
473                 return 1;             /* ignore */
474              }
475              ff_pkt->link = lp->name;
476              ff_pkt->type = FT_LNKSAVED;       /* Handle link, file already saved */
477              ff_pkt->LinkFI = lp->FileIndex;
478              ff_pkt->linked = 0;
479              rtn_stat = handle_file(jcr, ff_pkt, top_level);
480              Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n", 
481                 ff_pkt->FileIndex, lp->FileIndex, lp->name);
482              return rtn_stat;
483          }
484
485       /* File not previously dumped. Chain it into our list. */
486       len = strlen(fname) + 1;
487       lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
488       lp->ino = ff_pkt->statp.st_ino;
489       lp->dev = ff_pkt->statp.st_dev;
490       lp->FileIndex = 0;                  /* set later */
491       bstrncpy(lp->name, fname, len);
492       lp->next = ff_pkt->linkhash[linkhash];
493       ff_pkt->linkhash[linkhash] = lp;
494       ff_pkt->linked = lp;            /* mark saved link */
495       Dmsg2(400, "added to hash FI=%d file=%s\n", ff_pkt->FileIndex, lp->name);
496    } else {
497       ff_pkt->linked = NULL;
498    }
499
500    /* This is not a link to a previously dumped file, so dump it.  */
501    if (S_ISREG(ff_pkt->statp.st_mode)) {
502       boffset_t sizeleft;
503
504       sizeleft = ff_pkt->statp.st_size;
505
506       /* Don't bother opening empty, world readable files.  Also do not open
507          files when archive is meant for /dev/null.  */
508       if (ff_pkt->null_output_device || (sizeleft == 0
509               && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
510          ff_pkt->type = FT_REGE;
511       } else {
512          ff_pkt->type = FT_REG;
513       }
514       rtn_stat = handle_file(jcr, ff_pkt, top_level);
515       if (ff_pkt->linked) {
516          ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
517       }
518       Dmsg3(400, "FT_REG FI=%d linked=%d file=%s\n", ff_pkt->FileIndex, 
519          ff_pkt->linked ? 1 : 0, fname);
520       if (ff_pkt->flags & FO_KEEPATIME) {
521          utime(fname, &restore_times);
522       }       
523       return rtn_stat;
524
525
526    } else if (S_ISLNK(ff_pkt->statp.st_mode)) {  /* soft link */
527       int size;
528       char *buffer = (char *)alloca(path_max + name_max + 102);
529
530       size = readlink(fname, buffer, path_max + name_max + 101);
531       if (size < 0) {
532          /* Could not follow link */
533          ff_pkt->type = FT_NOFOLLOW;
534          ff_pkt->ff_errno = errno;
535          rtn_stat = handle_file(jcr, ff_pkt, top_level);
536          if (ff_pkt->linked) {
537             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
538          }
539          return rtn_stat;
540       }
541       buffer[size] = 0;
542       ff_pkt->link = buffer;          /* point to link */
543       ff_pkt->type = FT_LNK;          /* got a real link */
544       rtn_stat = handle_file(jcr, ff_pkt, top_level);
545       if (ff_pkt->linked) {
546          ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
547       }
548       return rtn_stat;
549
550    } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
551       DIR *directory;
552       struct dirent *entry, *result;
553       char *link;
554       int link_len;
555       int len;
556       int status;
557       dev_t our_device = ff_pkt->statp.st_dev;
558       bool recurse = true;
559       bool volhas_attrlist = ff_pkt->volhas_attrlist;    /* Remember this if we recurse */
560
561       /*
562        * If we are using Win32 (non-portable) backup API, don't check
563        *  access as everything is more complicated, and
564        *  in principle, we should be able to access everything.
565        */
566       if (!have_win32_api() || (ff_pkt->flags & FO_PORTABLE)) {
567          if (access(fname, R_OK) == -1 && geteuid() != 0) {
568             /* Could not access() directory */
569             ff_pkt->type = FT_NOACCESS;
570             ff_pkt->ff_errno = errno;
571             rtn_stat = handle_file(jcr, ff_pkt, top_level);
572             if (ff_pkt->linked) {
573                ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
574             }
575             return rtn_stat;
576          }
577       }
578
579       /*
580        * Ignore this directory and everything below if the file .nobackup
581        * (or what is defined for IgnoreDir in this fileset) exists
582        */
583       if (have_ignoredir(ff_pkt)) {
584          return 1; /* Just ignore this directory */
585       }
586
587       /* Build a canonical directory name with a trailing slash in link var */
588       len = strlen(fname);
589       link_len = len + 200;
590       link = (char *)bmalloc(link_len + 2);
591       bstrncpy(link, fname, link_len);
592       /* Strip all trailing slashes */
593       while (len >= 1 && IsPathSeparator(link[len - 1]))
594         len--;
595       link[len++] = '/';             /* add back one */
596       link[len] = 0;
597
598       ff_pkt->link = link;
599       if (ff_pkt->incremental && !check_changes(jcr, ff_pkt)) {
600          /* Incremental option, directory entry not changed */
601          ff_pkt->type = FT_DIRNOCHG;
602       } else {
603          ff_pkt->type = FT_DIRBEGIN;
604       }
605       /*
606        * We have set st_rdev to 1 if it is a reparse point, otherwise 0,
607        *  if st_rdev is 2, it is a mount point 
608        */
609 #if defined(HAVE_WIN32)
610       if (ff_pkt->statp.st_rdev == WIN32_REPARSE_POINT) {
611          ff_pkt->type = FT_REPARSE;
612       }
613 #endif 
614       /*
615        * Note, we return the directory to the calling program (handle_file)
616        * when we first see the directory (FT_DIRBEGIN.
617        * This allows the program to apply matches and make a
618        * choice whether or not to accept it.  If it is accepted, we
619        * do not immediately save it, but do so only after everything
620        * in the directory is seen (i.e. the FT_DIREND).
621        */
622       rtn_stat = handle_file(jcr, ff_pkt, top_level);
623       if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE) {   /* ignore or error status */
624          free(link);
625          return rtn_stat;
626       }
627       /* Done with DIRBEGIN, next call will be DIREND */
628       if (ff_pkt->type == FT_DIRBEGIN) {
629          ff_pkt->type = FT_DIREND;
630       }
631
632       /*
633        * Create a temporary ff packet for this directory
634        *   entry, and defer handling the directory until
635        *   we have recursed into it.  This saves the
636        *   directory after all files have been processed, and
637        *   during the restore, the directory permissions will
638        *   be reset after all the files have been restored.
639        */
640       Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
641       FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
642
643       /*
644        * Do not descend into subdirectories (recurse) if the
645        * user has turned it off for this directory.
646        *
647        * If we are crossing file systems, we are either not allowed
648        * to cross, or we may be restricted by a list of permitted
649        * file systems.
650        */
651       bool is_win32_mount_point = false;
652 #if defined(HAVE_WIN32)
653       is_win32_mount_point = ff_pkt->statp.st_rdev == WIN32_MOUNT_POINT;
654 #endif
655       if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
656          ff_pkt->type = FT_NORECURSE;
657          recurse = false;
658       } else if (!top_level && (parent_device != ff_pkt->statp.st_dev ||
659                  is_win32_mount_point)) {
660          if(!(ff_pkt->flags & FO_MULTIFS)) {
661             ff_pkt->type = FT_NOFSCHG;
662             recurse = false;
663          } else if (!accept_fstype(ff_pkt, NULL)) {
664             ff_pkt->type = FT_INVALIDFS;
665             recurse = false;
666          } else {
667             ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
668          }
669       }
670       /* If not recursing, just backup dir and return */
671       if (!recurse) {
672          rtn_stat = handle_file(jcr, ff_pkt, top_level);
673          if (ff_pkt->linked) {
674             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
675          }
676          free(link);
677          free_dir_ff_pkt(dir_ff_pkt);
678          ff_pkt->link = ff_pkt->fname;     /* reset "link" */
679          if (ff_pkt->flags & FO_KEEPATIME) {
680             utime(fname, &restore_times);
681          }
682          return rtn_stat;
683       }
684
685       ff_pkt->link = ff_pkt->fname;     /* reset "link" */
686
687       /*
688        * Descend into or "recurse" into the directory to read
689        *   all the files in it.
690        */
691       errno = 0;
692       if ((directory = opendir(fname)) == NULL) {
693          ff_pkt->type = FT_NOOPEN;
694          ff_pkt->ff_errno = errno;
695          rtn_stat = handle_file(jcr, ff_pkt, top_level);
696          if (ff_pkt->linked) {
697             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
698          }
699          free(link);
700          free_dir_ff_pkt(dir_ff_pkt);
701          return rtn_stat;
702       }
703
704       /*
705        * Process all files in this directory entry (recursing).
706        *    This would possibly run faster if we chdir to the directory
707        *    before traversing it.
708        */
709       rtn_stat = 1;
710       entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
711       for ( ; !job_canceled(jcr); ) {
712          char *p, *q;
713          int i;
714
715          status  = readdir_r(directory, entry, &result);
716          if (status != 0 || result == NULL) {
717 //          Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
718 //             status, (long)result);
719             break;
720          }
721          ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
722          p = entry->d_name;
723          /* Skip `.', `..', and excluded file names.  */
724          if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
725              (p[1] == '.' && p[2] == '\0')))) {
726             continue;
727          }
728
729          if ((int)NAMELEN(entry) + len >= link_len) {
730              link_len = len + NAMELEN(entry) + 1;
731              link = (char *)brealloc(link, link_len + 1);
732          }
733          q = link + len;
734          for (i=0; i < (int)NAMELEN(entry); i++) {
735             *q++ = *p++;
736          }
737          *q = 0;
738          if (!file_is_excluded(ff_pkt, link)) {
739             rtn_stat = find_one_file(jcr, ff_pkt, handle_file, link, our_device, false);
740             if (ff_pkt->linked) {
741                ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
742             }
743          }
744       }
745       closedir(directory);
746       free(link);
747       free(entry);
748
749       /*
750        * Now that we have recursed through all the files in the
751        *  directory, we "save" the directory so that after all
752        *  the files are restored, this entry will serve to reset
753        *  the directory modes and dates.  Temp directory values
754        *  were used without this record.
755        */
756       handle_file(jcr, dir_ff_pkt, top_level);       /* handle directory entry */
757       if (ff_pkt->linked) {
758          ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
759       }
760       free_dir_ff_pkt(dir_ff_pkt);
761
762       if (ff_pkt->flags & FO_KEEPATIME) {
763          utime(fname, &restore_times);
764       }
765       ff_pkt->volhas_attrlist = volhas_attrlist;      /* Restore value in case it changed. */
766       return rtn_stat;
767    } /* end check for directory */
768
769    /*
770     * If it is explicitly mentioned (i.e. top_level) and is
771     *  a block device, we do a raw backup of it or if it is
772     *  a fifo, we simply read it.
773     */
774 #ifdef HAVE_FREEBSD_OS
775    /*
776     * On FreeBSD, all block devices are character devices, so
777     *   to be able to read a raw disk, we need the check for
778     *   a character device.
779     * crw-r----- 1 root  operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
780     * crw-r----- 1 root  operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
781     */
782    if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
783 #else
784    if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
785 #endif
786       ff_pkt->type = FT_RAW;          /* raw partition */
787    } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
788               ff_pkt->flags & FO_READFIFO) {
789       ff_pkt->type = FT_FIFO;
790    } else {
791       /* The only remaining types are special (character, ...) files */
792       ff_pkt->type = FT_SPEC;
793    }
794    rtn_stat = handle_file(jcr, ff_pkt, top_level);
795    if (ff_pkt->linked) {
796       ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
797    }
798    return rtn_stat;
799 }
800
801 int term_find_one(FF_PKT *ff)
802 {
803    struct f_link *lp, *lc;
804    int count = 0;
805    int i;
806
807    
808    if (ff->linkhash == NULL) return 0;
809
810    for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
811    /* Free up list of hard linked files */
812        lp = ff->linkhash[i];
813        while (lp) {
814       lc = lp;
815       lp = lp->next;
816       if (lc) {
817          free(lc);
818          count++;
819       }
820    }
821        ff->linkhash[i] = NULL;
822    }
823    free(ff->linkhash);
824    ff->linkhash = NULL;
825    return count;
826 }