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