]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/findlib/find_one.c
Restore win32 dir from Branch-5.2 and update it
[bacula/bacula] / bacula / src / findlib / find_one.c
index d6c25fbdee2ad89290ce2a770c7798a8b794abbc..8e4beb931275ea4b3bfc8b007a49b95b60705f01 100644 (file)
@@ -1,42 +1,31 @@
 /*
 /*
+   Bacula(R) - The Network Backup Solution
 
 
-   This file is based on GNU TAR source code. Except for a few key
+   Copyright (C) 2000-2018 Kern Sibbald
+
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
+
+   This notice must be preserved when any source code is
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
+*/
+/*
+
+   This file was derived from GNU TAR source code. Except for a few key
    ideas, it has been entirely rewritten for Bacula.
 
       Kern Sibbald, MM
 
    Thanks to the TAR programmers.
 
    ideas, it has been entirely rewritten for Bacula.
 
       Kern Sibbald, MM
 
    Thanks to the TAR programmers.
 
-     Version $Id$
-
  */
  */
-/*
-   Bacula® - The Network Backup Solution
-
-   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
-
-   The main author of Bacula is Kern Sibbald, with contributions from
-   many others, a complete list can be found in the file AUTHORS.
-   This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
-   License as published by the Free Software Foundation plus additions
-   that are listed in the file LICENSE.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-   Bacula® is a registered trademark of John Walker.
-   The licensor of Bacula is the Free Software Foundation Europe
-   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-   Switzerland, email:ftf@fsfeurope.org.
-*/
 
 #include "bacula.h"
 #include "find.h"
 
 #include "bacula.h"
 #include "find.h"
@@ -60,8 +49,10 @@ struct f_link {
     struct f_link *next;
     dev_t dev;                        /* device */
     ino_t ino;                        /* inode with device is unique */
     struct f_link *next;
     dev_t dev;                        /* device */
     ino_t ino;                        /* inode with device is unique */
-    short linkcount;
     uint32_t FileIndex;               /* Bacula FileIndex of this file */
     uint32_t FileIndex;               /* Bacula FileIndex of this file */
+    int32_t digest_stream;            /* Digest type if needed */
+    uint32_t digest_len;              /* Digest len if needed */
+    char *digest;                     /* Checksum of the file if needed */
     char name[1];                     /* The name */
 };
 
     char name[1];                     /* The name */
 };
 
@@ -84,11 +75,53 @@ static inline int LINKHASH(const struct stat &info)
     return hash & LINK_HASHTABLE_MASK;
 }
 
     return hash & LINK_HASHTABLE_MASK;
 }
 
+/*
+ * Create a new directory Find File packet, but copy
+ *   some of the essential info from the current packet.
+ *   However, be careful to zero out the rest of the
+ *   packet.
+ */
+static FF_PKT *new_dir_ff_pkt(FF_PKT *ff_pkt)
+{
+   FF_PKT *dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
+   memcpy(dir_ff_pkt, ff_pkt, sizeof(FF_PKT));
+   dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
+   dir_ff_pkt->link = bstrdup(ff_pkt->link);
+   dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME);
+
+   if (ff_pkt->strip_snap_path) {
+      dir_ff_pkt->fname_save = get_pool_memory(PM_FNAME);
+      dir_ff_pkt->link_save = get_pool_memory(PM_FNAME);
+      pm_strcpy(dir_ff_pkt->fname_save, ff_pkt->fname_save);
+      pm_strcpy(dir_ff_pkt->link_save, ff_pkt->link_save);
+
+   } else {
+      dir_ff_pkt->fname_save = NULL;
+      dir_ff_pkt->link_save = NULL;
+   }
+
+   dir_ff_pkt->included_files_list = NULL;
+   dir_ff_pkt->excluded_files_list = NULL;
+   dir_ff_pkt->excluded_paths_list = NULL;
+   dir_ff_pkt->linkhash = NULL;
+   dir_ff_pkt->ignoredir_fname = NULL;
+   return dir_ff_pkt;
+}
+
+/*
+ * Free the temp directory ff_pkt
+ */
 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
 {
    free(dir_ff_pkt->fname);
    free(dir_ff_pkt->link);
    free_pool_memory(dir_ff_pkt->sys_fname);
 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
 {
    free(dir_ff_pkt->fname);
    free(dir_ff_pkt->link);
    free_pool_memory(dir_ff_pkt->sys_fname);
+   if (dir_ff_pkt->fname_save) {
+      free_pool_memory(dir_ff_pkt->fname_save);
+   }
+   if (dir_ff_pkt->link_save) {
+      free_pool_memory(dir_ff_pkt->link_save);
+   }
    free(dir_ff_pkt);
 }
 
    free(dir_ff_pkt);
 }
 
@@ -103,7 +136,7 @@ static int accept_fstype(FF_PKT *ff, void *dummy) {
 
    if (ff->fstypes.size()) {
       accept = false;
 
    if (ff->fstypes.size()) {
       accept = false;
-      if (!fstype(ff->fname, fs, sizeof(fs))) {
+      if (!fstype(ff, fs, sizeof(fs))) {
          Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
       } else {
          for (i = 0; i < ff->fstypes.size(); ++i) {
          Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
       } else {
          for (i = 0; i < ff->fstypes.size(); ++i) {
@@ -181,6 +214,22 @@ static bool volume_has_attrlist(const char *fname)
    return false;
 }
 
    return false;
 }
 
+/*
+ * check for BSD nodump flag
+ */
+static bool no_dump(JCR *jcr, FF_PKT *ff_pkt)
+{
+#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
+   if ( (ff_pkt->flags & FO_HONOR_NODUMP) &&
+        (ff_pkt->statp.st_flags & UF_NODUMP) ) {
+      Jmsg(jcr, M_INFO, 1, _("     NODUMP flag set - will not process %s\n"),
+           ff_pkt->fname);
+      return true;                    /* do not backup this file */
+   }
+#endif
+   return false;                      /* do backup */
+}
+
 /* check if a file have changed during backup and display an error */
 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
 {
 /* check if a file have changed during backup and display an error */
 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
 {
@@ -193,39 +242,104 @@ bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
 
    if (lstat(ff_pkt->fname, &statp) != 0) {
       berrno be;
 
    if (lstat(ff_pkt->fname, &statp) != 0) {
       berrno be;
-      Jmsg(jcr, M_WARNING, 0, 
-          _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.strerror());
+      Jmsg(jcr, M_WARNING, 0,
+           _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.bstrerror());
       return true;
    }
 
    if (statp.st_mtime != ff_pkt->statp.st_mtime) {
       return true;
    }
 
    if (statp.st_mtime != ff_pkt->statp.st_mtime) {
-      /* TODO: add time of changes */
       Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname);
       Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname);
+      Dmsg3(50, "%s mtime (%lld) changed during backup (%lld).\n", ff_pkt->fname,
+            (int64_t)ff_pkt->statp.st_mtime, (int64_t)statp.st_mtime);
       return true;
    }
 
    if (statp.st_ctime != ff_pkt->statp.st_ctime) {
       return true;
    }
 
    if (statp.st_ctime != ff_pkt->statp.st_ctime) {
-      /* TODO: add time of changes */
       Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname);
       Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname);
+      Dmsg3(50, "%s ctime (%lld) changed during backup (%lld).\n", ff_pkt->fname,
+            (int64_t)ff_pkt->statp.st_ctime, (int64_t)statp.st_ctime);
       return true;
    }
       return true;
    }
-  
-   if (statp.st_size != ff_pkt->statp.st_size) {
-      /* TODO: add size change */
-      Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
+
+   if ((int64_t)statp.st_size != (int64_t)ff_pkt->statp.st_size) {
+      Jmsg(jcr, M_ERROR, 0, _("%s size of %lld changed during backup to %lld.n"),ff_pkt->fname,
+         (int64_t)ff_pkt->statp.st_size, (int64_t)statp.st_size);
+      Dmsg3(50, "%s size (%lld) changed during backup (%lld).\n", ff_pkt->fname,
+            (int64_t)ff_pkt->statp.st_size, (int64_t)statp.st_size);
       return true;
    }
 
       return true;
    }
 
-   if ((statp.st_blksize != ff_pkt->statp.st_blksize) ||
-       (statp.st_blocks  != ff_pkt->statp.st_blocks)) {
-      /* TODO: add size change */
-      Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
-      return true;
+   return false;
+}
+
+/*
+ * For incremental/diffential or accurate backups, we
+ *   determine if the current file has changed.
+ */
+bool check_changes(JCR *jcr, FF_PKT *ff_pkt)
+{
+   /* in special mode (like accurate backup), the programmer can
+    * choose his comparison function.
+    */
+   if (ff_pkt->check_fct) {
+      return ff_pkt->check_fct(jcr, ff_pkt);
+   }
+
+   /* For normal backups (incr/diff), we use this default
+    * behaviour
+    */
+   if (ff_pkt->incremental &&
+       (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
+        ((ff_pkt->flags & FO_MTIMEONLY) ||
+         ff_pkt->statp.st_ctime < ff_pkt->save_time)))
+   {
+      return false;
    }
 
    }
 
+   return true;
+}
+
+static bool have_ignoredir(FF_PKT *ff_pkt)
+{
+   struct stat sb;
+   char *ignoredir;
+
+   /* Ensure that pointers are defined */
+   if (!ff_pkt->fileset || !ff_pkt->fileset->incexe) {
+      return false;
+   }
+   ignoredir = ff_pkt->fileset->incexe->ignoredir;
+
+   if (ignoredir) {
+      if (!ff_pkt->ignoredir_fname) {
+         ff_pkt->ignoredir_fname = get_pool_memory(PM_FNAME);
+      }
+      Mmsg(ff_pkt->ignoredir_fname, "%s/%s", ff_pkt->fname, ignoredir);
+      if (stat(ff_pkt->ignoredir_fname, &sb) == 0) {
+         Dmsg2(100, "Directory '%s' ignored (found %s)\n",
+               ff_pkt->fname, ignoredir);
+         return true;      /* Just ignore this directory */
+      }
+   }
    return false;
 }
 
    return false;
 }
 
+/*
+ * When the current file is a hardlink, the backup code can compute
+ * the checksum and store it into the link_t structure.
+ */
+void
+ff_pkt_set_link_digest(FF_PKT *ff_pkt,
+                       int32_t digest_stream, const char *digest, uint32_t len)
+{
+   if (ff_pkt->linked && !ff_pkt->linked->digest) {     /* is a hardlink */
+      ff_pkt->linked->digest = (char *) bmalloc(len);
+      memcpy(ff_pkt->linked->digest, digest, len);
+      ff_pkt->linked->digest_len = len;
+      ff_pkt->linked->digest_stream = digest_stream;
+   }
+}
+
 /*
  * Find a single file.
  * handle_file is the callback for handling the file.
 /*
  * Find a single file.
  * handle_file is the callback for handling the file.
@@ -235,9 +349,9 @@ bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
  *  descending into a directory.
  */
 int
  *  descending into a directory.
  */
 int
-find_one_file(JCR *jcr, FF_PKT *ff_pkt, 
-               int handle_file(FF_PKT *ff, void *hpkt, bool top_level),
-               void *pkt, char *fname, dev_t parent_device, bool top_level)
+find_one_file(JCR *jcr, FF_PKT *ff_pkt,
+               int handle_file(JCR *jcr, FF_PKT *ff, bool top_level),
+               char *fname, dev_t parent_device, bool top_level)
 {
    struct utimbuf restore_times;
    int rtn_stat;
 {
    struct utimbuf restore_times;
    int rtn_stat;
@@ -249,7 +363,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
        /* Cannot stat file */
        ff_pkt->type = FT_NOSTAT;
        ff_pkt->ff_errno = errno;
        /* Cannot stat file */
        ff_pkt->type = FT_NOSTAT;
        ff_pkt->ff_errno = errno;
-       return handle_file(ff_pkt, pkt, top_level);
+       return handle_file(jcr, ff_pkt, top_level);
    }
 
    Dmsg1(300, "File ----: %s\n", fname);
    }
 
    Dmsg1(300, "File ----: %s\n", fname);
@@ -272,7 +386,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
 
          char fs[100];
 
 
          char fs[100];
 
-         if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
+         if (!fstype(ff_pkt, fs, sizeof(fs))) {
              bstrncpy(fs, "unknown", sizeof(fs));
          }
 
              bstrncpy(fs, "unknown", sizeof(fs));
          }
 
@@ -297,21 +411,26 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
       ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
    }
 
       ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
    }
 
+   /*
+    * Ignore this entry if no_dump() returns true
+    */
+   if (no_dump(jcr, ff_pkt)) {
+           Dmsg1(100, "'%s' ignored (NODUMP flag set)\n",
+                 ff_pkt->fname);
+           return 1;
+   }
+
    /*
     * If this is an Incremental backup, see if file was modified
     * since our last "save_time", presumably the last Full save
     * or Incremental.
     */
    /*
     * If this is an Incremental backup, see if file was modified
     * since our last "save_time", presumably the last Full save
     * or Incremental.
     */
-   if (ff_pkt->incremental && !S_ISDIR(ff_pkt->statp.st_mode)) {
-      Dmsg1(300, "Non-directory incremental: %s\n", ff_pkt->fname);
-      /* Not a directory */
-      if (ff_pkt->statp.st_mtime < ff_pkt->save_time
-          && ((ff_pkt->flags & FO_MTIMEONLY) ||
-              ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
-         /* Incremental option, file not changed */
-         ff_pkt->type = FT_NOCHG;
-         return handle_file(ff_pkt, pkt, top_level);
-      }
+   if (   !S_ISDIR(ff_pkt->statp.st_mode)
+       && !check_changes(jcr, ff_pkt))
+   {
+      Dmsg1(500, "Non-directory incremental: %s\n", ff_pkt->fname);
+      ff_pkt->type = FT_NOCHG;
+      return handle_file(jcr, ff_pkt, top_level);
    }
 
 #ifdef HAVE_DARWIN_OS
    }
 
 #ifdef HAVE_DARWIN_OS
@@ -327,19 +446,12 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
                 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
           ff_pkt->type = FT_NOSTAT;
           ff_pkt->ff_errno = errno;
                 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
           ff_pkt->type = FT_NOSTAT;
           ff_pkt->ff_errno = errno;
-          return handle_file(ff_pkt, pkt, top_level);
+          return handle_file(jcr, ff_pkt, top_level);
        }
        }
+       return -1; /* ignore */
    }
 #endif
 
    }
 #endif
 
-/* ***FIXME*** implement this */
-#if xxxxxxx
-   /* See if we are trying to dump the archive.  */
-   if (ar_dev && ff_pkt->statp.st_dev == ar_dev && ff_pkt->statp.st_ino == ar_ino) {
-       ff_pkt->type = FT_ISARCH;
-       return handle_file(ff_pkt, pkt, top_level);
-   }
-#endif
    ff_pkt->LinkFI = 0;
    /*
     * Handle hard linked files
    ff_pkt->LinkFI = 0;
    /*
     * Handle hard linked files
@@ -369,23 +481,36 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
              lp->dev == (dev_t)ff_pkt->statp.st_dev) {
              /* If we have already backed up the hard linked file don't do it again */
              if (strcmp(lp->name, fname) == 0) {
              lp->dev == (dev_t)ff_pkt->statp.st_dev) {
              /* If we have already backed up the hard linked file don't do it again */
              if (strcmp(lp->name, fname) == 0) {
+                Dmsg2(400, "== Name identical skip FI=%d file=%s\n", lp->FileIndex, fname);
                 return 1;             /* ignore */
              }
              ff_pkt->link = lp->name;
              ff_pkt->type = FT_LNKSAVED;       /* Handle link, file already saved */
              ff_pkt->LinkFI = lp->FileIndex;
                 return 1;             /* ignore */
              }
              ff_pkt->link = lp->name;
              ff_pkt->type = FT_LNKSAVED;       /* Handle link, file already saved */
              ff_pkt->LinkFI = lp->FileIndex;
-             return handle_file(ff_pkt, pkt, top_level);
+             ff_pkt->linked = 0;
+             ff_pkt->digest = lp->digest;
+             ff_pkt->digest_stream = lp->digest_stream;
+             ff_pkt->digest_len = lp->digest_len;
+             rtn_stat = handle_file(jcr, ff_pkt, top_level);
+             Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n",
+                ff_pkt->FileIndex, lp->FileIndex, lp->name);
+             return rtn_stat;
          }
 
       /* File not previously dumped. Chain it into our list. */
       len = strlen(fname) + 1;
       lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
          }
 
       /* File not previously dumped. Chain it into our list. */
       len = strlen(fname) + 1;
       lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
+      lp->digest = NULL;                /* set later */
+      lp->digest_stream = 0;            /* set later */
+      lp->digest_len = 0;               /* set later */
       lp->ino = ff_pkt->statp.st_ino;
       lp->dev = ff_pkt->statp.st_dev;
       lp->ino = ff_pkt->statp.st_ino;
       lp->dev = ff_pkt->statp.st_dev;
+      lp->FileIndex = 0;                  /* set later */
       bstrncpy(lp->name, fname, len);
       bstrncpy(lp->name, fname, len);
-       lp->next = ff_pkt->linkhash[linkhash];
-       ff_pkt->linkhash[linkhash] = lp;
+      lp->next = ff_pkt->linkhash[linkhash];
+      ff_pkt->linkhash[linkhash] = lp;
       ff_pkt->linked = lp;            /* mark saved link */
       ff_pkt->linked = lp;            /* mark saved link */
+      Dmsg2(400, "added to hash FI=%d file=%s\n", ff_pkt->FileIndex, lp->name);
    } else {
       ff_pkt->linked = NULL;
    }
    } else {
       ff_pkt->linked = NULL;
    }
@@ -404,13 +529,15 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
       } else {
          ff_pkt->type = FT_REG;
       }
       } else {
          ff_pkt->type = FT_REG;
       }
-      rtn_stat = handle_file(ff_pkt, pkt, top_level);
+      rtn_stat = handle_file(jcr, ff_pkt, top_level);
       if (ff_pkt->linked) {
          ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
       }
       if (ff_pkt->linked) {
          ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
       }
+      Dmsg3(400, "FT_REG FI=%d linked=%d file=%s\n", ff_pkt->FileIndex,
+         ff_pkt->linked ? 1 : 0, fname);
       if (ff_pkt->flags & FO_KEEPATIME) {
          utime(fname, &restore_times);
       if (ff_pkt->flags & FO_KEEPATIME) {
          utime(fname, &restore_times);
-      }       
+      }
       return rtn_stat;
 
 
       return rtn_stat;
 
 
@@ -423,7 +550,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
          /* Could not follow link */
          ff_pkt->type = FT_NOFOLLOW;
          ff_pkt->ff_errno = errno;
          /* Could not follow link */
          ff_pkt->type = FT_NOFOLLOW;
          ff_pkt->ff_errno = errno;
-         rtn_stat = handle_file(ff_pkt, pkt, top_level);
+         rtn_stat = handle_file(jcr, ff_pkt, top_level);
          if (ff_pkt->linked) {
             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
          }
          if (ff_pkt->linked) {
             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
          }
@@ -432,7 +559,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
       buffer[size] = 0;
       ff_pkt->link = buffer;          /* point to link */
       ff_pkt->type = FT_LNK;          /* got a real link */
       buffer[size] = 0;
       ff_pkt->link = buffer;          /* point to link */
       ff_pkt->type = FT_LNK;          /* got a real link */
-      rtn_stat = handle_file(ff_pkt, pkt, top_level);
+      rtn_stat = handle_file(jcr, ff_pkt, top_level);
       if (ff_pkt->linked) {
          ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
       }
       if (ff_pkt->linked) {
          ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
       }
@@ -450,21 +577,11 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
       bool volhas_attrlist = ff_pkt->volhas_attrlist;    /* Remember this if we recurse */
 
       /*
       bool volhas_attrlist = ff_pkt->volhas_attrlist;    /* Remember this if we recurse */
 
       /*
-       * If we are using Win32 (non-portable) backup API, don't check
-       *  access as everything is more complicated, and
-       *  in principle, we should be able to access everything.
+       * Ignore this directory and everything below if the file .nobackup
+       * (or what is defined for IgnoreDir in this fileset) exists
        */
        */
-      if (!have_win32_api() || (ff_pkt->flags & FO_PORTABLE)) {
-         if (access(fname, R_OK) == -1 && geteuid() != 0) {
-            /* Could not access() directory */
-            ff_pkt->type = FT_NOACCESS;
-            ff_pkt->ff_errno = errno;
-            rtn_stat = handle_file(ff_pkt, pkt, top_level);
-            if (ff_pkt->linked) {
-               ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
-            }
-            return rtn_stat;
-         }
+      if (have_ignoredir(ff_pkt)) {
+         return 1; /* Just ignore this directory */
       }
 
       /* Build a canonical directory name with a trailing slash in link var */
       }
 
       /* Build a canonical directory name with a trailing slash in link var */
@@ -479,15 +596,40 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
       link[len] = 0;
 
       ff_pkt->link = link;
       link[len] = 0;
 
       ff_pkt->link = link;
-      if (ff_pkt->incremental &&
-          (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
-             ((ff_pkt->flags & FO_MTIMEONLY) ||
-               ff_pkt->statp.st_ctime < ff_pkt->save_time))) {
-         /* Incremental option, directory entry not changed */
+      if (!check_changes(jcr, ff_pkt)) {
+         /* Incremental/Full+Base option, directory entry not changed */
          ff_pkt->type = FT_DIRNOCHG;
       } else {
          ff_pkt->type = FT_DIRBEGIN;
       }
          ff_pkt->type = FT_DIRNOCHG;
       } else {
          ff_pkt->type = FT_DIRBEGIN;
       }
+      /*
+       * We have set st_rdev to 1 if it is a reparse point, otherwise 0,
+       *  if st_rdev is 2, it is a mount point
+       */
+#if defined(HAVE_WIN32)
+      /*
+       * A reparse point (WIN32_REPARSE_POINT)
+       *  is something special like one of the following:
+       *  IO_REPARSE_TAG_DFS              0x8000000A
+       *  IO_REPARSE_TAG_DFSR             0x80000012
+       *  IO_REPARSE_TAG_HSM              0xC0000004
+       *  IO_REPARSE_TAG_HSM2             0x80000006
+       *  IO_REPARSE_TAG_SIS              0x80000007
+       *  IO_REPARSE_TAG_SYMLINK          0xA000000C
+       *
+       * A junction point is a:
+       *  IO_REPARSE_TAG_MOUNT_POINT      0xA0000003
+       * which can be either a link to a Volume (WIN32_MOUNT_POINT)
+       * or a link to a directory (WIN32_JUNCTION_POINT)
+       *
+       * Ignore WIN32_REPARSE_POINT and WIN32_JUNCTION_POINT
+       */
+      if (ff_pkt->statp.st_rdev == WIN32_REPARSE_POINT) {
+         ff_pkt->type = FT_REPARSE;
+      } else if (ff_pkt->statp.st_rdev == WIN32_JUNCTION_POINT) {
+         ff_pkt->type = FT_JUNCTION;
+      }
+#endif
       /*
        * Note, we return the directory to the calling program (handle_file)
        * when we first see the directory (FT_DIRBEGIN.
       /*
        * Note, we return the directory to the calling program (handle_file)
        * when we first see the directory (FT_DIRBEGIN.
@@ -496,8 +638,9 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
        * do not immediately save it, but do so only after everything
        * in the directory is seen (i.e. the FT_DIREND).
        */
        * do not immediately save it, but do so only after everything
        * in the directory is seen (i.e. the FT_DIREND).
        */
-      rtn_stat = handle_file(ff_pkt, pkt, top_level);
-      if (rtn_stat < 1) {             /* ignore or error status */
+      rtn_stat = handle_file(jcr, ff_pkt, top_level);
+      if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE ||
+          ff_pkt->type == FT_JUNCTION) {   /* ignore or error status */
          free(link);
          return rtn_stat;
       }
          free(link);
          return rtn_stat;
       }
@@ -515,15 +658,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
        *   be reset after all the files have been restored.
        */
       Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
        *   be reset after all the files have been restored.
        */
       Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
-      FF_PKT *dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
-      memcpy(dir_ff_pkt, ff_pkt, sizeof(FF_PKT));
-      dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
-      dir_ff_pkt->link = bstrdup(ff_pkt->link);
-      dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME);
-      dir_ff_pkt->included_files_list = NULL;
-      dir_ff_pkt->excluded_files_list = NULL;
-      dir_ff_pkt->excluded_paths_list = NULL;
-      dir_ff_pkt->linkhash = NULL;
+      FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
 
       /*
        * Do not descend into subdirectories (recurse) if the
 
       /*
        * Do not descend into subdirectories (recurse) if the
@@ -533,10 +668,15 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
        * to cross, or we may be restricted by a list of permitted
        * file systems.
        */
        * to cross, or we may be restricted by a list of permitted
        * file systems.
        */
+      bool is_win32_mount_point = false;
+#if defined(HAVE_WIN32)
+      is_win32_mount_point = ff_pkt->statp.st_rdev == WIN32_MOUNT_POINT;
+#endif
       if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
          ff_pkt->type = FT_NORECURSE;
          recurse = false;
       if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
          ff_pkt->type = FT_NORECURSE;
          recurse = false;
-      } else if (!top_level && parent_device != ff_pkt->statp.st_dev) {
+      } else if (!top_level && (parent_device != ff_pkt->statp.st_dev ||
+                 is_win32_mount_point)) {
          if(!(ff_pkt->flags & FO_MULTIFS)) {
             ff_pkt->type = FT_NOFSCHG;
             recurse = false;
          if(!(ff_pkt->flags & FO_MULTIFS)) {
             ff_pkt->type = FT_NOFSCHG;
             recurse = false;
@@ -549,7 +689,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
       }
       /* If not recursing, just backup dir and return */
       if (!recurse) {
       }
       /* If not recursing, just backup dir and return */
       if (!recurse) {
-         rtn_stat = handle_file(ff_pkt, pkt, top_level);
+         rtn_stat = handle_file(jcr, ff_pkt, top_level);
          if (ff_pkt->linked) {
             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
          }
          if (ff_pkt->linked) {
             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
          }
@@ -572,7 +712,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
       if ((directory = opendir(fname)) == NULL) {
          ff_pkt->type = FT_NOOPEN;
          ff_pkt->ff_errno = errno;
       if ((directory = opendir(fname)) == NULL) {
          ff_pkt->type = FT_NOOPEN;
          ff_pkt->ff_errno = errno;
-         rtn_stat = handle_file(ff_pkt, pkt, top_level);
+         rtn_stat = handle_file(jcr, ff_pkt, top_level);
          if (ff_pkt->linked) {
             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
          }
          if (ff_pkt->linked) {
             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
          }
@@ -616,7 +756,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
          }
          *q = 0;
          if (!file_is_excluded(ff_pkt, link)) {
          }
          *q = 0;
          if (!file_is_excluded(ff_pkt, link)) {
-            rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, false);
+            rtn_stat = find_one_file(jcr, ff_pkt, handle_file, link, our_device, false);
             if (ff_pkt->linked) {
                ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
             }
             if (ff_pkt->linked) {
                ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
             }
@@ -633,7 +773,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
        *  the directory modes and dates.  Temp directory values
        *  were used without this record.
        */
        *  the directory modes and dates.  Temp directory values
        *  were used without this record.
        */
-      handle_file(dir_ff_pkt, pkt, top_level);       /* handle directory entry */
+      handle_file(jcr, dir_ff_pkt, top_level);       /* handle directory entry */
       if (ff_pkt->linked) {
          ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
       }
       if (ff_pkt->linked) {
          ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
       }
@@ -656,8 +796,8 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
     * On FreeBSD, all block devices are character devices, so
     *   to be able to read a raw disk, we need the check for
     *   a character device.
     * On FreeBSD, all block devices are character devices, so
     *   to be able to read a raw disk, we need the check for
     *   a character device.
-    * crw-r-----  1 root  operator  - 116, 0x00040002 Jun  9 19:32 /dev/ad0s3
-    * crw-r-----  1 root  operator  - 116, 0x00040002 Jun  9 19:32 /dev/rad0s3
+    * crw-r----- 1 root  operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
+    * crw-r----- 1 root  operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
     */
    if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
 #else
     */
    if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
 #else
@@ -671,7 +811,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
       /* The only remaining types are special (character, ...) files */
       ff_pkt->type = FT_SPEC;
    }
       /* The only remaining types are special (character, ...) files */
       ff_pkt->type = FT_SPEC;
    }
-   rtn_stat = handle_file(ff_pkt, pkt, top_level);
+   rtn_stat = handle_file(jcr, ff_pkt, top_level);
    if (ff_pkt->linked) {
       ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
    }
    if (ff_pkt->linked) {
       ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
    }
@@ -684,21 +824,24 @@ int term_find_one(FF_PKT *ff)
    int count = 0;
    int i;
 
    int count = 0;
    int i;
 
-   
+
    if (ff->linkhash == NULL) return 0;
 
    for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
    /* Free up list of hard linked files */
    if (ff->linkhash == NULL) return 0;
 
    for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
    /* Free up list of hard linked files */
-       lp = ff->linkhash[i];
-       while (lp) {
-      lc = lp;
-      lp = lp->next;
-      if (lc) {
-         free(lc);
-         count++;
+      lp = ff->linkhash[i];
+      while (lp) {
+         lc = lp;
+         lp = lp->next;
+         if (lc) {
+            if (lc->digest) {
+               free(lc->digest);
+            }
+            free(lc);
+            count++;
+         }
       }
       }
-   }
-       ff->linkhash[i] = NULL;
+      ff->linkhash[i] = NULL;
    }
    free(ff->linkhash);
    ff->linkhash = NULL;
    }
    free(ff->linkhash);
    ff->linkhash = NULL;