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