]> git.sur5r.net Git - bacula/bacula/commitdiff
Detect mount/junction points and ignore junctions in Windows
authorEric Bollengier <eric@eb.homelinux.org>
Fri, 28 Jan 2011 09:50:31 +0000 (10:50 +0100)
committerKern Sibbald <kern@sibbald.com>
Sat, 20 Apr 2013 12:39:55 +0000 (14:39 +0200)
bacula/src/filed/backup.c
bacula/src/filed/estimate.c
bacula/src/filed/verify.c
bacula/src/findlib/create_file.c
bacula/src/findlib/find.c
bacula/src/findlib/find_one.c
bacula/src/win32/compat/compat.cpp
bacula/src/win32/compat/compat.h
bacula/src/win32/compat/winconfig.h

index 72bef802be0cd410c27e2dadf1c9b23dccdf3f98..78ec13f01e9da3eb742c22e105a3b7bd2844d8d9 100644 (file)
@@ -353,13 +353,8 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
    case FT_NOFSCHG:
       /* Suppress message for /dev filesystems */
       if (!is_in_fileset(ff_pkt)) {
-#ifdef HAVE_WIN32
-         Jmsg(jcr, M_INFO, 1, _("     %s is a junction point or a different filesystem. Will not descend from %s into it.\n"),
-              ff_pkt->fname, ff_pkt->top_fname);
-#else
          Jmsg(jcr, M_INFO, 1, _("     %s is a different filesystem. Will not descend from %s into it.\n"),
               ff_pkt->fname, ff_pkt->top_fname);
-#endif
       }
       ff_pkt->type = FT_DIREND;       /* Backup only the directory entry */
       break;
@@ -373,6 +368,7 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
            ff_pkt->fname);
       break;
    case FT_REPARSE:
+   case FT_JUNCTION:
    case FT_DIREND:
       Dmsg1(130, "FT_DIREND: %s\n", ff_pkt->link);
       break;
@@ -538,7 +534,7 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
       do_read = ff_pkt->statp.st_size > 0;  
 #endif
    } else if (ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO ||
-              ff_pkt->type == FT_REPARSE ||
+              ff_pkt->type == FT_REPARSE || ff_pkt->type == FT_JUNCTION ||
          (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
       do_read = true;
    }
@@ -557,7 +553,8 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
          tid = NULL;
       }
       int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
-      ff_pkt->bfd.reparse_point = ff_pkt->type == FT_REPARSE;
+      ff_pkt->bfd.reparse_point = (ff_pkt->type == FT_REPARSE || 
+                                   ff_pkt->type == FT_JUNCTION);
       if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0) < 0) {
          ff_pkt->ff_errno = errno;
          berrno be;
@@ -1197,6 +1194,7 @@ bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream)
       break;
    case FT_DIREND:
    case FT_REPARSE:
+   case FT_JUNCTION:
       /* Here link is the canonical filename (i.e. with trailing slash) */
       stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
                        ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0, 
@@ -1385,6 +1383,7 @@ static void close_vss_backup_session(JCR *jcr)
          ff_pkt->object_name = (char *)"job_metadata.xml";
          ff_pkt->object = (char *)metadata;
          ff_pkt->object_len = (wcslen(metadata) + 1) * sizeof(WCHAR);
+         ff_pkt->object_index = (int)time(NULL);
          save_file(jcr, ff_pkt, true);
      }
    }
index 3f6f7dc6271b1d0117d110e1c5647ceefeaa6405..7888bc9ffe00c4feb292a518c6c89108841dbf4c 100644 (file)
@@ -82,6 +82,7 @@ static int tally_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
    case FT_INVALIDFS:
    case FT_INVALIDDT:
    case FT_REPARSE:
+   case FT_JUNCTION:
    case FT_DIREND:
    case FT_SPEC:
    case FT_RAW:
index 5f3841d4c5cdad5f6bbd3e5495e79adb3735bf7e..287f0a4ad3217400c24b738986928a25e93c964c 100644 (file)
@@ -108,6 +108,7 @@ static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
       jcr->num_files_examined--;      /* correct file count */
       return 1;                       /* ignored */
    case FT_REPARSE: 
+   case FT_JUNCTION:
    case FT_DIREND:
       Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
       break;
@@ -196,7 +197,8 @@ static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
       stat = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
                         STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
                         0, attribs, 0, ff_pkt->link, 0);
-   } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE) {
+   } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE ||
+              ff_pkt->type == FT_JUNCTION) {
       /* Here link is the canonical filename (i.e. with trailing slash) */
       stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
                         STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
index 6a4fddd5683d9a21f286a5b2d97cc37321ad1146..ab8afd2ff55cf6570ae60683b76add4e18c9cd2f 100644 (file)
@@ -362,6 +362,7 @@ int create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
       } /* End inner switch */
 
    case FT_REPARSE:
+   case FT_JUNCTION:
       bfd->reparse_point = true;
       /* Fall through wanted */
    case FT_DIRBEGIN:
index 3c60f95219e9b06cecb8cba670ddb02f3581019e..77ac196dabf57b33a94e31ff276227f6cf98666c 100644 (file)
@@ -445,7 +445,6 @@ static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level)
    case FT_INVALIDFS:
    case FT_INVALIDDT:
    case FT_NOOPEN:
-   case FT_REPARSE:
 //    return ff->file_save(jcr, ff, top_level);
 
    /* These items can be filtered */
@@ -459,6 +458,8 @@ static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level)
    case FT_FIFO:
    case FT_SPEC:
    case FT_DIRNOCHG:
+   case FT_REPARSE:
+   case FT_JUNCTION:
       if (accept_file(ff)) {
          return ff->file_save(jcr, ff, top_level);
       } else {
index 6cad34151800357b7707b5726298c4c083907871..64a5ec0dd872c5faedae1e015f290a9c9787c6e2 100644 (file)
@@ -586,8 +586,27 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
        *  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 
       /*
@@ -599,7 +618,8 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
        * in the directory is seen (i.e. the FT_DIREND).
        */
       rtn_stat = handle_file(jcr, ff_pkt, top_level);
-      if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE) {   /* ignore or error status */
+      if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE ||
+          ff_pkt->type == FT_JUNCTION) {   /* ignore or error status */
          free(link);
          return rtn_stat;
       }
index d662f0279f7ede19bdeaa16962baff7dc7ea424d..cb83a9b36de720b5d64b04a2fca723a5cbbb174b 100644 (file)
 #include "jcr.h"
 #include "findlib/find.h"
 
+/* Note, if you want to see what Windows variables and structures
+ * are defined, bacula.h includes <windows.h>, which is found in:
+ *
+ *   cross-tools/mingw32/mingw32/include
+ * or
+ *   cross-tools/mingw-w64/x86_64-pc-mingw32/include
+ * 
+ * depending on whether we are building the 32 bit version or
+ * the 64 bit version. 
+ */
+
 static const int dbglvl = 500;
 
 #define b_errno_win32 (1<<29)
@@ -404,6 +415,30 @@ make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
    return (POOLMEM *)pwszBuf;
 }
 
+/*
+ * Convert from WCHAR (UCS) to UTF-8
+ */
+int
+wchar_2_UTF8(POOLMEM **pszUTF, const wchar_t *pszUCS)
+{
+   /**
+    * The return value is the number of bytes written to the buffer.
+    * The number includes the byte for the null terminator.
+    */
+
+   if (p_WideCharToMultiByte) {
+      int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,NULL,0,NULL,NULL);
+      *pszUTF = check_pool_memory_size(*pszUTF, nRet);
+      return p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,*pszUTF,nRet,NULL,NULL);
+
+   } else {
+      return 0;
+   }
+}
+
+/*
+ * Convert from WCHAR (UCS) to UTF-8
+ */
 int
 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
 {
@@ -638,6 +673,11 @@ static const char *errorString(void)
 }
 
 
+/*
+ * This is only called for directories, and is used to get the directory
+ *  attributes and find out if we have a junction point or a mount point
+ *  or other kind of "funny" directory.
+ */
 static int
 statDir(const char *file, struct stat *sb)
 {
@@ -652,6 +692,7 @@ statDir(const char *file, struct stat *sb)
    FILETIME *pftLastAccessTime;
    FILETIME *pftLastWriteTime;
    FILETIME *pftCreationTime;
+   HANDLE h = INVALID_HANDLE_VALUE;
 
    /* 
     * Oh, cool, another exception: Microsoft doesn't let us do 
@@ -669,7 +710,6 @@ statDir(const char *file, struct stat *sb)
       return 0;
     }
 
-   HANDLE h = INVALID_HANDLE_VALUE;
 
    // use unicode
    if (p_FindFirstFileW) {
@@ -737,10 +777,62 @@ statDir(const char *file, struct stat *sb)
     *  filesystem).
     */
    if (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-      if (*pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) {
-         sb->st_rdev = WIN32_MOUNT_POINT;           /* mount point */
+      sb->st_rdev = WIN32_MOUNT_POINT;
+   } else {
+      sb->st_rdev = 0;
+   }
+   if ((*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
+        (*pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT)) {
+      sb->st_rdev = WIN32_MOUNT_POINT;           /* mount point */
+      /* 
+       * Now to find out if the directory is a mount point or
+       * a reparse point, we must do a song and a dance.
+       * Explicitly open the file to read the reparse point, then
+       * call DeviceIoControl to find out if it points to a Volume
+       * or to a directory.
+       */
+      h = INVALID_HANDLE_VALUE;
+      if (p_GetFileAttributesW) {
+         POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
+         make_win32_path_UTF8_2_wchar(&pwszBuf, file);
+         if (p_CreateFileW) {
+            h = CreateFileW((LPCWSTR)pwszBuf, GENERIC_READ,
+                   FILE_SHARE_READ, NULL, OPEN_EXISTING, 
+                   FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+                   NULL);
+         }
+         free_pool_memory(pwszBuf);
+      } else if (p_GetFileAttributesA) {
+         h = CreateFileA(file, GENERIC_READ,
+                FILE_SHARE_READ, NULL, OPEN_EXISTING, 
+                FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+                NULL);         
+      }
+      if (h != INVALID_HANDLE_VALUE) {
+         char dummy[1000];
+         REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)dummy;
+         rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+         DWORD bytes;
+         bool ok;
+         ok = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, 
+                 NULL, 0,                           /* in buffer, bytes */
+                 (LPVOID)rdb, (DWORD)sizeof(dummy), /* out buffer, btyes */
+                 (LPDWORD)&bytes, (LPOVERLAPPED)0);
+         if (ok) {
+            POOLMEM *utf8 = get_pool_memory(PM_NAME);
+            wchar_2_UTF8(&utf8, (wchar_t *)rdb->SymbolicLinkReparseBuffer.PathBuffer);
+            Dmsg2(dbglvl, "Junction %s points to: %s\n", file, utf8);
+            if (strncasecmp(utf8, "\\??\\volume{", 11) == 0) {
+               sb->st_rdev = WIN32_MOUNT_POINT;
+            } else { 
+               /* It points to a directory so we ignore it. */
+               sb->st_rdev = WIN32_JUNCTION_POINT;
+            }
+            free_pool_memory(utf8);
+         }
+         CloseHandle(h);
       } else {
-         sb->st_rdev = WIN32_REPARSE_POINT;         /* reparse point */
+         Dmsg1(dbglvl, "Invalid handle from CreateFile(%s)\n", file);
       }
    }  
    Dmsg2(dbglvl, "st_rdev=%d file=%s\n", sb->st_rdev, file);
@@ -1297,9 +1389,10 @@ readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
 
       // copy unicode
       if (dp->valid_w) {
-         char szBuf[MAX_PATH_UTF8+1];
-         wchar_2_UTF8(szBuf,dp->data_w.cFileName);
+         POOLMEM *szBuf = get_pool_memory(PM_NAME);
+         wchar_2_UTF8(&szBuf, dp->data_w.cFileName);
          dp->offset += copyin(*entry, szBuf);
+         free_pool_memory(szBuf);
       } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
          dp->offset += copyin(*entry, dp->data_a.cFileName);
       }
@@ -1543,7 +1636,7 @@ win32_getcwd(char *buf, int maxlen)
    } else if (p_GetCurrentDirectoryA)
       n = p_GetCurrentDirectoryA(maxlen, buf);
 
-   if (n == 0 || n > maxlen) return NULL;
+   if (n <= 0 || n > maxlen) return NULL;
 
    if (n+1 > maxlen) return NULL;
    if (n != 3) {
@@ -2151,10 +2244,11 @@ typedef struct s_bpipe {
 */
 
 static void
-CloseIfValid(HANDLE handle)
+CloseHandleIfValid(HANDLE handle)
 {
-    if (handle != INVALID_HANDLE_VALUE)
+    if (handle != INVALID_HANDLE_VALUE) {
         CloseHandle(handle);
+    }
 }
 
 BPIPE *
@@ -2272,12 +2366,12 @@ open_bpipe(char *prog, int wait, const char *mode)
 
 cleanup:
 
-    CloseIfValid(hChildStdoutRd);
-    CloseIfValid(hChildStdoutRdDup);
-    CloseIfValid(hChildStdinWr);
-    CloseIfValid(hChildStdinWrDup);
+    CloseHandleIfValid(hChildStdoutRd);
+    CloseHandleIfValid(hChildStdoutRdDup);
+    CloseHandleIfValid(hChildStdinWr);
+    CloseHandleIfValid(hChildStdinWrDup);
 
-    free((void *) bpipe);
+    free((void *)bpipe);
     errno = b_errno_win32;            /* do GetLastError() for error code */
     return NULL;
 }
index 13e01ba876ab8e695b5654040e431390a3454fbd..c11c3b06e5c2c7ff8c0f7bb8c3efffc03bf08eee 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2004-2009 Free Software Foundation Europe e.V.
+   Copyright (C) 2004-2010 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.
 /*
  * Author          : Christopher S. Hull
  * Created On      : Fri Jan 30 13:00:51 2004
- * Last Modified By: Thorsten Engel
- * Last Modified On: Fri Apr 22 19:30:00 2004
- * Update Count    : 218
- * $Id$
  */
 
 
 #ifdef MINGW64
 #include <direct.h>
 #define _declspec __declspec
+
+/* Missing in 64 bit mingw */
+typedef struct _REPARSE_DATA_BUFFER {
+        DWORD  ReparseTag;
+        WORD   ReparseDataLength;
+        WORD   Reserved;
+        union {
+                struct {
+                        WORD   SubstituteNameOffset;
+                        WORD   SubstituteNameLength;
+                        WORD   PrintNameOffset;
+                        WORD   PrintNameLength;
+                        WCHAR PathBuffer[1];
+                } SymbolicLinkReparseBuffer;
+                struct {
+                        WORD   SubstituteNameOffset;
+                        WORD   SubstituteNameLength;
+                        WORD   PrintNameOffset;
+                        WORD   PrintNameLength;
+                        WCHAR PathBuffer[1];
+                } MountPointReparseBuffer;
+                struct {
+                        BYTE   DataBuffer[1];
+                } GenericReparseBuffer;
+        } DUMMYUNIONNAME;
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
 #endif
 
+#include <winioctl.h>
+
 #ifdef _WIN64
 # define GWL_USERDATA  GWLP_USERDATA
 #endif
@@ -381,8 +406,6 @@ void closelog();
 void openlog(const char *ident, int option, int facility);
 #endif //HAVE_MINGW
 
-void LogErrorMsg(const char *message);
-
 /* Don't let OS go to sleep (usually a Laptop) while we are backing up */
 void prevent_os_suspensions();
 void allow_os_suspensions();
@@ -390,7 +413,11 @@ void allow_os_suspensions();
 typedef DWORD EXECUTION_STATE;
 #ifndef ES_CONTINUOUS
 #define ES_CONTINUOUS            0x80000000
+#endif
+#ifndef ES_SYSTEM_REQUIRED
 #define ES_SYSTEM_REQUIRED       0x00000001
+#endif
+#ifndef ES_DISPLAY_REQUIRED
 #define ES_DISPLAY_REQUIRED      0x00000002
 #endif
 #ifndef ES_USER_PRESENT
@@ -400,6 +427,8 @@ typedef DWORD EXECUTION_STATE;
 WINBASEAPI EXECUTION_STATE WINAPI SetThreadExecutionState(EXECUTION_STATE esFlags);
 
 
+extern void LogErrorMsg(const char *message);
+
 #if !defined(INVALID_FILE_ATTRIBUTES)
 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
 #endif
index be02604bf1c35c7045680e6e995521cba3ee4332..567faa28268269ee1e3feadda7c04e4e22fdfb75 100644 (file)
 /* Use long unsigned int for ioctl request */
 #define HAVE_IOCTL_ULINT_REQUEST
 
+/* Little Endian */
+#define HAVE_LITTLE_ENDIAN 1
+
 #endif /* __WINCONFIG_H */