]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
win32: Move the MTab code to compat.cpp and use it with Plugins
authorNorbert Bizet <norbert.bizet@baculasystems.com>
Mon, 12 Oct 2020 10:00:27 +0000 (12:00 +0200)
committerEric Bollengier <eric@baculasystems.com>
Thu, 24 Mar 2022 08:02:57 +0000 (09:02 +0100)
bacula/src/filed/job.c
bacula/src/lib/rblist.h
bacula/src/win32/compat/mtab.cpp [new file with mode: 0644]
bacula/src/win32/compat/mtab.h [new file with mode: 0644]
bacula/src/win32/filed/Makefile
bacula/src/win32/filed/vss.cpp
bacula/src/win32/filed/vss.h
bacula/src/win32/lib/Makefile

index 1dedbe34beb11542221644bfbfc4d0c750338a69..5b7aaf428149510246390780316c830082da548d 100644 (file)
@@ -2190,18 +2190,21 @@ static void list_drives(findFILESET *fileset, dlist *name_list, MTab *mtab)
  *
  */
 static int
-get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
+get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives, void* mtab_def)
 {
    int nCount = 0;
-
 #ifdef HAVE_WIN32
    findFILESET *fileset = ff->fileset;
    findINCEXE *alldrives = NULL, *inc = NULL;
    uint64_t    flags = 0;
    char drive[4];
 
-   MTab mtab;
-   mtab.get();                  /* read the disk structure */
+   /* give it our best shot */
+   MTab *mtab = (MTab*) mtab_def;
+   if (!mtab_def) {
+      mtab = New(MTab());
+      mtab->get();
+   }
 
    /* We check if we need to complete the fileset with File=/ */
    if (fileset) {
@@ -2216,7 +2219,7 @@ get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
              * sub volumes are added in the second part if needed
              */
             alldrives = incexe; /* Keep it if MULTIFS is set */
-            list_drives(fileset, &incexe->name_list, &mtab);
+            list_drives(fileset, &incexe->name_list, mtab);
          }
       }
    }
@@ -2226,7 +2229,7 @@ get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
       strcpy(drive, "c:\\");
       for (int i=0; szDrives[i] ; i++) {
          drive[0] = szDrives[i];
-         if (mtab.addInSnapshotSet(drive)) { /* When all volumes are selected, we can stop */
+         if (mtab->addInSnapshotSet(drive)) { /* When all volumes are selected, we can stop */
             Dmsg0(DT_VOLUME|50, "All Volumes are marked, stopping the loop here\n");
             goto all_included;
          }
@@ -2234,6 +2237,11 @@ get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
    }
 
    if (fileset) {
+
+      /* Writer dictates the snapshot included components
+       * but we still give the chanche to include extra files to
+       * the snapshot set via fileset include_list
+       */
       dlistString *node;
 
       for (int i=0; i<fileset->include_list.size(); i++) {
@@ -2242,7 +2250,7 @@ get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
          /* look through all files */
          foreach_dlist(node, &incexe->name_list) {
             char *fname = node->c_str();
-            if (mtab.addInSnapshotSet(fname)) {
+            if (mtab->addInSnapshotSet(fname)) {
                /* When all volumes are selected, we can stop */
                Dmsg0(DT_VOLUME|50, "All Volumes are marked, stopping the loop here\n");
                goto all_included;
@@ -2261,7 +2269,7 @@ get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
 
          Dmsg0(DT_VOLUME|50, "OneFS is set, looking for remaining volumes\n");
 
-         foreach_rblist(elt, mtab.entries) {
+         foreach_rblist(elt, mtab->entries) {
             if (elt->in_SnapshotSet) {
                continue;         /* Already in */
             }
@@ -2281,15 +2289,17 @@ get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
                /* First thing is to look in the exclude list to see if this directory
                 * is explicitly excluded
                 */
-               if (is_excluded(fileset, fn)) {
+               if (!is_excluded(fileset, fn)) {
+                  elt->setInSnapshotSet();
+               } else {
                   Dmsg1(DT_VOLUME|50, "Looks to be excluded %s\n", fn);
                   continue;
                }
 
                /* c:/vol/vol2/vol3
-                * will look c:/, then c:/vol/, then c:/vol2/ and if one of them
-                * is selected, the sub volume will be directly marked.
-                */
+               * will look c:/, then c:/vol/, then c:/vol2/ and if one of them
+               * is selected, the sub volume will be directly marked.
+               */
                for (char *p1 = fn ; *p1 && !elt->in_SnapshotSet ; p1++) {
                   if (IsPathSeparator(*p1)) {
                      bool to_add=false; /* Add this volume to the FileSet ? */
@@ -2297,10 +2307,10 @@ get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
                      *(p1 + 1) = 0;
 
                      /* We look for the previous directory, and if marked, we mark
-                      * the current one as well
-                      */
+                     * the current one as well
+                     */
                      Dmsg1(DT_VOLUME|50, "Looking for %s\n", fn);
-                     elt2 = mtab.search(fn);
+                     elt2 = mtab->search(fn);
                      if (elt2 && elt2->in_SnapshotSet) {
                         Dmsg0(DT_VOLUME|50, "Put volume in SnapshotSet\n");
                         elt->setInSnapshotSet();
@@ -2308,8 +2318,8 @@ get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
                      }
 
                      /* Find where to add the new volume, normally near the
-                      * root volume, or if we are using /
-                      */
+                     * root volume, or if we are using /
+                     */
                      if (alldrives) {
                         inc = alldrives;
                      } else {
@@ -2337,10 +2347,10 @@ get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
          }
          free_pool_memory(fn);
       }
-   all_included:
+all_included:
       /* Now, we look the volume list to know which one to include */
       MTabEntry *elt;
-      foreach_rblist(elt, mtab.entries) {
+      foreach_rblist(elt, mtab->entries) {
          if (elt->in_SnapshotSet) {
             Dmsg1(DT_VOLUME|50,"Adding volume in mount_points list %ls\n",elt->volumeName);
             nCount++;
@@ -2349,6 +2359,9 @@ get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
       }
    }
 
+   if (!mtab_def) {
+      delete mtab;
+   }
 #endif  /* HAVE_WIN32 */
    return nCount;
 }
@@ -2366,7 +2379,7 @@ static int estimate_cmd(JCR *jcr)
    }
 
    /* On windows, the fileset can be completed by this function (File=/ => File=C:/ + File=E:/) */
-   get_win32_driveletters(jcr, jcr->ff, NULL);
+   get_win32_driveletters(jcr, jcr->ff, NULL, NULL);
 
    make_estimate(jcr);
    dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
@@ -2888,12 +2901,13 @@ static int backup_cmd(JCR *jcr)
    /* START VSS ON WIN32 */
       jcr->pVSSClient = VSSInit();
       if (jcr->pVSSClient->InitializeForBackup(jcr)) {
-         generate_plugin_event(jcr, bEventVssBackupAddComponents);
+         MTab *tab = jcr->pVSSClient->GetVolumeList();
+         generate_plugin_event(jcr, bEventVssBackupAddComponents, tab);
          /* tell vss which drives to snapshot */
          char szWinDriveLetters[27];
          *szWinDriveLetters=0;
          generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
-         if (get_win32_driveletters(jcr, jcr->ff, szWinDriveLetters)) {
+         if (get_win32_driveletters(jcr, jcr->ff, szWinDriveLetters, tab)) {
             Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\"\n"),
                  jcr->pVSSClient->GetDriverName());
 
@@ -2927,7 +2941,7 @@ static int backup_cmd(JCR *jcr)
 
    } else {                     /* No snapshot */
       /* On windows, the FileSet might be adjusted with the options that are used (File=/ => File=C:/, File=E:/) */
-      get_win32_driveletters(jcr, jcr->ff, NULL);
+      get_win32_driveletters(jcr, jcr->ff, NULL, NULL);
    }
    /* Call RunScript just after the Snapshot creation, usually, we restart services */
    run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
index 6e19cd7097b72c3b69dce7af859729c725d3f2b7..becd7377d7d04f0f89f1f1bb6b9a23f9f7e0b536 100644 (file)
@@ -24,6 +24,9 @@
  *
  */
 
+#ifndef RBLIST_H
+#define RBLIST_H
+
 #define M_ABORT 1
 
 /*
@@ -154,3 +157,4 @@ inline bool rblist::red(const void *item) const
 {
    return ((rblink *)(((char *)item)+loffset))->red;
 }
+#endif /* RBLIST_H */
diff --git a/bacula/src/win32/compat/mtab.cpp b/bacula/src/win32/compat/mtab.cpp
new file mode 100644 (file)
index 0000000..69e1820
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2020 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.
+*/
+
+#include "bacula.h"
+#include "compat.h"
+#include "mtab.h"
+#include "ms_atl.h"
+#include <objbase.h>
+#undef setlocale
+#include <string>
+using namespace std;
+
+#define dbglvl_snap DT_VOLUME|50
+
+/* empty namespace to avoid collisions */
+namespace {
+    // Append a backslash to the current string
+    wstring AppendBackslash(wstring str)
+    {
+        if (str.length() == 0) {
+            return wstring(L"\\");
+        }
+        if (str[str.length() - 1] == L'\\') {
+            return str;
+        }
+        return str.append(L"\\");
+    }
+
+    // Get the unique volume name for the given path
+    wstring GetUniqueVolumeNameForPath(wstring path, wstring &rootPath)
+    {
+        if (path.length() <= 0) {
+        //Dmsg0(50, "Failed path.len <= 0\n");
+        return L"";
+        }
+
+        // Add the backslash termination, if needed
+        path = AppendBackslash(path);
+        //Dmsg1(50, "Path=%ls\n", path.c_str());
+
+        // Get the root path of the volume
+        wchar_t volumeRootPath[MAX_PATH];
+        wchar_t volumeName[MAX_PATH];
+        wchar_t volumeUniqueName[MAX_PATH];
+
+        volumeRootPath[0] = 0;
+        volumeName[0] = 0;
+        volumeUniqueName[0] = 0;
+
+        if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH)) {
+        Dmsg1(50, "Failed GetVolumePathNameW path=%ls\n", path.c_str());
+        return L"";
+        }
+        rootPath.assign(volumeRootPath);
+        Dmsg1(dbglvl_snap, "VolumeRootPath=%ls\n", volumeRootPath);
+
+        // Get the volume name alias (might be different from the unique volume name in rare cases)
+        if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH)) {
+        Dmsg1(50, "Failed GetVolumeNameForVolumeMountPointW path=%ls\n", volumeRootPath);
+        return L"";
+        }
+        Dmsg1(dbglvl_snap, "VolumeName=%ls\n", volumeName);
+
+        // Get the unique volume name
+        if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH)) {
+        Dmsg1(50, "Failed GetVolumeNameForVolumeMountPointW path=%ls\n", volumeName);
+        return L"";
+        }
+        Dmsg1(dbglvl_snap, "VolumeUniqueName=%ls\n", volumeUniqueName);
+        return volumeUniqueName;
+    }
+
+    int volume_search(void *i1, void *i2)
+    {
+        wstring   *volname = (wstring *) i1;
+        MTabEntry *vol = (MTabEntry *) i2;
+
+        return volname->compare(vol->volumeName);
+    }
+
+    int volume_cmp(void *e1, void *e2)
+    {
+        MTabEntry *v1 = (MTabEntry *) e1;
+        MTabEntry *v2 = (MTabEntry *) e2;
+        return wcscmp(v1->volumeName, v2->volumeName);
+    }
+}
+
+MTab::MTab() {
+    MTabEntry *elt = NULL;
+    lasterror = ERROR_SUCCESS;
+    lasterror_str = "";
+    nb_in_SnapshotSet = 0;
+    entries = New(rblist(elt, &elt->link));
+}
+
+MTab::~MTab() {
+   if (entries) {
+      MTabEntry *elt;
+      foreach_rblist(elt, entries) {
+         elt->destroy();
+      }
+      delete entries;
+   }
+}
+
+UINT MTabEntry::getDriveType()
+{
+   WCHAR *root = first();
+
+   // Make sure to discard CD-ROM and network drives
+   if (!root) {
+      return 0;
+   }
+
+   driveType = GetDriveTypeW(root);
+   return driveType;
+}
+
+/* Return true if the current volume can be snapshoted (ie not CDROM or fat32) */
+bool MTabEntry::isSuitableForSnapshot()
+{
+   DWORD componentlength, fsflags;
+   WCHAR fstype[50];
+   WCHAR *root = first();
+   UINT oldmode;
+   BOOL result;
+
+   // Make sure to discard CD-ROM and network drives
+   if (!root) {
+      Dmsg1(dbglvl_snap, "No mount point for %ls\n", volumeName);
+      goto bail_out;
+   }
+
+   if (getDriveType() != DRIVE_FIXED) {
+      Dmsg2(dbglvl_snap, "Invalid disk type %d for %ls\n", driveType, root);
+      goto bail_out;
+   }
+
+   /* From fstype.c, except that we have WCHAR instead of char */
+   /* We don't want any popups if there isn't any media in the drive */
+   oldmode = SetErrorMode(SEM_FAILCRITICALERRORS);
+   result = GetVolumeInformationW(root, NULL, 0, NULL,
+                                  &componentlength, &fsflags, fstype, ARRAYSIZE(fstype));
+   SetErrorMode(oldmode);
+
+   if (result) {
+      /* Windows returns NTFS, FAT, etc.  Make it lowercase to be consistent with other OSes */
+      Dmsg1(dbglvl_snap, "fstype=%ls\n", fstype);
+      if (!_wcsicmp(fstype, L"ntfs")) {
+         can_Snapshot = true;
+      }
+      if (!_wcsicmp(fstype, L"refs")) {
+         can_Snapshot = true;
+      }
+      if (!_wcsicmp(fstype, L"csvfs")) {
+         can_Snapshot = true;
+      }
+   }
+bail_out:
+   Dmsg2(dbglvl_snap, "%ls is %s suitable for VSS snapshot\n", root, can_Snapshot?"":"not");
+   return can_Snapshot;
+}
+
+/* Find a volume for a specific path */
+MTabEntry *MTab::search(char *p)
+{
+   wstring volume;
+   wstring path;
+   wstring rootPath;
+
+   POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
+   wutf8_path_2_wchar(&pwszBuf, p);
+   path.assign((wchar_t *)pwszBuf);
+   volume = GetUniqueVolumeNameForPath(path, rootPath);
+
+   MTabEntry *elt = (MTabEntry *)entries->search(&volume, volume_search);
+   free_pool_memory(pwszBuf);
+
+   if (!elt) {
+      Dmsg1(000, "Unable to find %ls in volume list\n", volume.c_str());
+   }
+
+   return elt;
+}
+
+bool MTab::addInSnapshotSet(char *p)
+{
+   MTabEntry *elt = search(p);
+   if (elt) {
+      if (!elt->in_SnapshotSet && elt->isSuitableForSnapshot()) {
+         nb_in_SnapshotSet++;
+         elt->setInSnapshotSet();
+      }
+   }
+   return nb_in_SnapshotSet == entries->size();
+}
+
+/* Initialize the "entries" list will all existing volumes */
+bool MTab::get()
+{
+   DWORD  count                = 0;
+   WCHAR  DeviceName[MAX_PATH] = L"";
+   HANDLE FindHandle           = INVALID_HANDLE_VALUE;
+   size_t Index                = 0;
+   bool   Success              = FALSE;
+   WCHAR  VolumeName[MAX_PATH] = L"";
+
+   Dmsg0(dbglvl_snap, "Filling MTAB\n");
+
+
+   //  Enumerate all volumes in the system.
+   FindHandle = FindFirstVolumeW(VolumeName, ARRAYSIZE(VolumeName));
+
+   if (FindHandle == INVALID_HANDLE_VALUE) {
+      lasterror = GetLastError();
+      return false;
+   }
+
+   for (;;) {
+      //  Skip the \\?\ prefix and remove the trailing backslash.
+      Index = wcslen(VolumeName) - 1;
+
+      if (VolumeName[0]     != L'\\' ||
+          VolumeName[1]     != L'\\' ||
+          VolumeName[2]     != L'?'  ||
+          VolumeName[3]     != L'\\' ||
+          VolumeName[Index] != L'\\')
+      {
+         lasterror = ERROR_BAD_PATHNAME;
+         lasterror_str = "FindFirstVolumeW/FindNextVolumeW returned a bad path";
+         Dmsg1(000, "FindFirstVolumeW/FindNextVolumeW returned a bad path %ls\n", VolumeName);
+         break;
+      }
+
+      //
+      //  QueryDosDeviceW does not allow a trailing backslash,
+      //  so temporarily remove it.
+      VolumeName[Index] = L'\0';
+
+      count = QueryDosDeviceW(&VolumeName[4], DeviceName,
+                              ARRAYSIZE(DeviceName));
+
+      VolumeName[Index] = L'\\';
+
+      if (count == 0) {
+         lasterror = GetLastError();
+         Dmsg1(000, "QueryDosDeviceW failed with error code %d\n", lasterror);
+         break;
+      }
+
+      // VolumeName='\\\\?\\Volume{086fc09e-7781-4076-9b2e-a4ff5c6b52c7}\\'
+      // DeviceName='\\Device\\HarddiskVolume2'
+      MTabEntry *entry = New(MTabEntry(DeviceName, VolumeName));
+      entries->insert(entry, volume_cmp);
+
+      //
+      //  Move on to the next volume.
+      Success = FindNextVolumeW(FindHandle, VolumeName, ARRAYSIZE(VolumeName));
+
+      if (!Success) {
+         lasterror = GetLastError();
+         if (lasterror != ERROR_NO_MORE_FILES) {
+            Dmsg1(000, "FindNextVolumeW failed with error code %d\n", lasterror);
+            break;
+         }
+
+         //  Finished iterating
+         //  through all the volumes.
+         lasterror = ERROR_SUCCESS;
+         break;
+      }
+   }
+
+   FindVolumeClose(FindHandle);
+   FindHandle = INVALID_HANDLE_VALUE;
+
+   return true;
+}
diff --git a/bacula/src/win32/compat/mtab.h b/bacula/src/win32/compat/mtab.h
new file mode 100644 (file)
index 0000000..8fe1dd8
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2020 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.
+*/
+
+#ifndef BEE_MTAB_ENTRY_H
+#define BEE_MTAB_ENTRY_H
+
+#include "winapi.h"
+
+#define bwcsdup(str) wcscpy((WCHAR *)bmalloc((wcslen(str)+1)*sizeof(WCHAR)),(str))
+#define safe_bfree(buf) if (buf) { bfree(buf); buf = NULL; }
+
+/* The MTabEntry class is representing a mounted volume,
+ * it associates a volume name with mount paths and a device name
+ */
+class MTabEntry: public SMARTALLOC {
+public:
+   WCHAR *volumeName;         // Name of the current volume
+   WCHAR *mountPaths;         // List of mount paths
+   WCHAR *deviceName;
+   WCHAR *shadowCopyName;
+   bool   in_SnapshotSet;
+   bool   can_Snapshot;
+   UINT   driveType;
+   rblink link;
+
+   MTabEntry() {
+      mountPaths = NULL;
+      volumeName = NULL;
+      deviceName = NULL;
+      in_SnapshotSet = false;
+      shadowCopyName = NULL;
+      can_Snapshot = false;
+      driveType = 0;
+   };
+
+   MTabEntry(WCHAR *DeviceName, WCHAR *VolumeName) {
+      int last = wcslen(VolumeName);
+      if (VolumeName[last - 1] == L'\\') {
+         volumeName = bwcsdup(VolumeName);
+      } else {                         /* \\ + \0 */
+         volumeName = (WCHAR *)bmalloc((last+1)*sizeof(WCHAR));
+         wcscpy(volumeName, VolumeName);
+         volumeName[last] = L'\\';
+         volumeName[last+1] = L'\0';
+      }
+      mountPaths = NULL;
+      in_SnapshotSet = false;
+      deviceName = bwcsdup(DeviceName);
+      shadowCopyName = NULL;
+      driveType = 0;
+      can_Snapshot = false;
+      get_paths();
+   };
+
+   ~MTabEntry() {
+      destroy();
+   };
+
+   void destroy() {
+      safe_bfree(mountPaths);
+      safe_bfree(volumeName);
+      safe_bfree(deviceName);
+      safe_bfree(shadowCopyName);
+   };
+
+   /* Return  the drive type (cdrom, fixed, network, ...) */
+   UINT getDriveType();
+
+   /* Return true if the current volume can be snapshoted (ie not CDROM or fat32) */
+   bool isSuitableForSnapshot();
+
+   void setInSnapshotSet() {
+      Dmsg1(050, "Marking %ls for the SnapshotSet\n", mountPaths);
+      in_SnapshotSet = true;
+   }
+
+   void debug_paths() {
+      WCHAR *p;
+      /*  Display the paths in the list. */
+      if (mountPaths != NULL) {
+         Dmsg2(DT_VOLUME|10, "Device: [%ls], Volume: [%ls]\n", deviceName, volumeName);
+         for ( p = mountPaths;  p[0] != L'\0'; p += wcslen(p) + 1) {
+            Dmsg1(DT_VOLUME|10, "  %ls\n", p);
+         }
+      }
+   };
+
+   /* Compute the path list assiciated with the current volume */
+   bool get_paths() {
+      DWORD  count = MAX_PATH + 1;
+      bool   ret = false;
+
+      for (;;) {
+         //  Allocate a buffer to hold the paths.
+         mountPaths = (WCHAR*) malloc(count * sizeof(WCHAR));
+
+         //  Obtain all of the paths
+         //  for this volume.
+         ret = GetVolumePathNamesForVolumeNameW(volumeName, mountPaths, 
+                                                count, &count);
+         if (ret) {
+            break;
+         }
+
+         if (GetLastError() != ERROR_MORE_DATA) {
+            break;
+         }
+
+         //  Try again with the
+         //  new suggested size.
+         free(mountPaths);
+         mountPaths = NULL;
+      }
+      debug_paths();
+      return ret;
+   };
+
+   /* Return the first mount point */
+   WCHAR *first() {
+      return mountPaths;
+   };
+
+   /* Return the next mount point */
+   WCHAR *next(WCHAR *prev) {
+      if (prev == NULL || prev[0] == L'\0') {
+         return NULL;
+      }
+
+      prev += wcslen(prev) + 1;
+
+      return (prev[0] == L'\0') ? NULL : prev;
+   };
+};
+
+/* Class to handle all volumes of the system, it contains
+ * a list of all current volumes (MTabEntry)
+ */
+class MTab: public SMARTALLOC {
+public:
+   DWORD       lasterror;
+   const char *lasterror_str;
+   rblist     *entries;         /* MTabEntry */
+   int         nb_in_SnapshotSet;
+
+   MTab();
+   ~MTab(); 
+
+   /* Get a Volume by name */
+   MTabEntry *search(char *file);
+
+   /* Try to add a volume to the current snapshotset */
+   bool addInSnapshotSet(char *file);
+
+   /* Fill the "entries" list will all detected volumes of the system*/
+   bool get();
+};
+
+#endif /* BEE_MTAB_ENTRY_H */
index 8f6c2a0ca61256eec19658b628885277fcb65054..20d02e1ab90c6ba04389d12ccd17d7aeeeed2134 100644 (file)
@@ -58,6 +58,7 @@ FILED_OBJS = \
        $(OBJDIR)/heartbeat.o \
        $(OBJDIR)/hello.o \
        $(OBJDIR)/job.o \
+       $(OBJDIR)/mtab.o \
        $(OBJDIR)/restore.o \
        $(OBJDIR)/status.o \
        $(OBJDIR)/verify.o \
index 155f069e1366dda34b313806d84bdeb5a52141d3..0d7f179135afb5cde6936cf343b7bd45720bf102 100644 (file)
@@ -48,184 +48,6 @@ static int volume_search(void *i1, void *i2)
    return volname->compare(vol->volumeName);
 }
 
-static int volume_cmp(void *e1, void *e2)
-{
-   MTabEntry *v1 = (MTabEntry *) e1;
-   MTabEntry *v2 = (MTabEntry *) e2;
-   return wcscmp(v1->volumeName, v2->volumeName);
-}
-
-UINT MTabEntry::getDriveType()
-{
-   WCHAR *root = first();
-
-   // Make sure to discard CD-ROM and network drives
-   if (!root) {
-      return 0;
-   }
-
-   driveType = GetDriveTypeW(root);
-   return driveType;
-}
-
-/* Return true if the current volume can be snapshoted (ie not CDROM or fat32) */
-bool MTabEntry::isSuitableForSnapshot()
-{
-   DWORD componentlength, fsflags;
-   WCHAR fstype[50];
-   WCHAR *root = first();
-   UINT oldmode;
-   BOOL result;
-
-   // Make sure to discard CD-ROM and network drives
-   if (!root) {
-      Dmsg1(dbglvl_snap, "No mount point for %ls\n", volumeName);
-      goto bail_out;
-   }
-
-   if (getDriveType() != DRIVE_FIXED) {
-      Dmsg2(dbglvl_snap, "Invalid disk type %d for %ls\n", driveType, root);
-      goto bail_out;
-   }
-
-   /* From fstype.c, except that we have WCHAR instead of char */
-   /* We don't want any popups if there isn't any media in the drive */
-   oldmode = SetErrorMode(SEM_FAILCRITICALERRORS);
-   result = GetVolumeInformationW(root, NULL, 0, NULL,
-                                  &componentlength, &fsflags, fstype, ARRAYSIZE(fstype));
-   SetErrorMode(oldmode);
-
-   if (result) {
-      /* Windows returns NTFS, FAT, etc.  Make it lowercase to be consistent with other OSes */
-      Dmsg1(dbglvl_snap, "fstype=%ls\n", fstype);
-      if (!_wcsicmp(fstype, L"ntfs")) {
-         can_Snapshot = true;
-      }
-      if (!_wcsicmp(fstype, L"refs")) {
-         can_Snapshot = true;
-      }
-   }
-bail_out:
-   Dmsg2(dbglvl_snap, "%ls is %s suitable for VSS snapshot\n", root, can_Snapshot?"":"not");
-   return can_Snapshot;
-}
-
-/* Find a volume for a specific path */
-MTabEntry *MTab::search(char *p)
-{
-   wstring volume;
-   wstring path;
-   wstring rootPath;
-
-   POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
-   wutf8_path_2_wchar(&pwszBuf, p);
-   path.assign((wchar_t *)pwszBuf);
-   volume = GetUniqueVolumeNameForPath(path, rootPath);
-
-   MTabEntry *elt = (MTabEntry *)entries->search(&volume, volume_search);
-   free_pool_memory(pwszBuf);
-
-   if (!elt) {
-      Dmsg1(000, "Unable to find %ls in volume list\n", volume.c_str());
-   }
-
-   return elt;
-}
-
-bool MTab::addInSnapshotSet(char *p)
-{
-   MTabEntry *elt = search(p);
-   if (elt) {
-      if (!elt->in_SnapshotSet && elt->isSuitableForSnapshot()) {
-         nb_in_SnapshotSet++;
-         elt->setInSnapshotSet();
-      }
-   }
-   return nb_in_SnapshotSet == entries->size();
-}
-
-/* Initialize the "entries" list will all existing volumes */
-bool MTab::get()
-{
-   DWORD  count                = 0;
-   WCHAR  DeviceName[MAX_PATH] = L"";
-   HANDLE FindHandle           = INVALID_HANDLE_VALUE;
-   size_t Index                = 0;
-   bool   Success              = FALSE;
-   WCHAR  VolumeName[MAX_PATH] = L"";
-
-   Dmsg0(dbglvl_snap, "Filling MTAB\n");
-
-
-   //  Enumerate all volumes in the system.
-   FindHandle = FindFirstVolumeW(VolumeName, ARRAYSIZE(VolumeName));
-
-   if (FindHandle == INVALID_HANDLE_VALUE) {
-      lasterror = GetLastError();
-      return false;
-   }
-
-   for (;;) {
-      //  Skip the \\?\ prefix and remove the trailing backslash.
-      Index = wcslen(VolumeName) - 1;
-
-      if (VolumeName[0]     != L'\\' ||
-          VolumeName[1]     != L'\\' ||
-          VolumeName[2]     != L'?'  ||
-          VolumeName[3]     != L'\\' ||
-          VolumeName[Index] != L'\\')
-      {
-         lasterror = ERROR_BAD_PATHNAME;
-         lasterror_str = "FindFirstVolumeW/FindNextVolumeW returned a bad path";
-         Dmsg1(000, "FindFirstVolumeW/FindNextVolumeW returned a bad path %ls\n", VolumeName);
-         break;
-      }
-
-      //
-      //  QueryDosDeviceW does not allow a trailing backslash,
-      //  so temporarily remove it.
-      VolumeName[Index] = L'\0';
-
-      count = QueryDosDeviceW(&VolumeName[4], DeviceName,
-                              ARRAYSIZE(DeviceName));
-
-      VolumeName[Index] = L'\\';
-
-      if (count == 0) {
-         lasterror = GetLastError();
-         Dmsg1(000, "QueryDosDeviceW failed with error code %d\n", lasterror);
-         break;
-      }
-
-      // VolumeName='\\\\?\\Volume{086fc09e-7781-4076-9b2e-a4ff5c6b52c7}\\'
-      // DeviceName='\\Device\\HarddiskVolume2'
-      MTabEntry *entry = New(MTabEntry(DeviceName, VolumeName));
-      entries->insert(entry, volume_cmp);
-
-      //
-      //  Move on to the next volume.
-      Success = FindNextVolumeW(FindHandle, VolumeName, ARRAYSIZE(VolumeName));
-
-      if (!Success) {
-         lasterror = GetLastError();
-         if (lasterror != ERROR_NO_MORE_FILES) {
-            Dmsg1(000, "FindNextVolumeW failed with error code %d\n", lasterror);
-            break;
-         }
-
-         //  Finished iterating
-         //  through all the volumes.
-         lasterror = ERROR_SUCCESS;
-         break;
-      }
-   }
-
-   FindVolumeClose(FindHandle);
-   FindHandle = INVALID_HANDLE_VALUE;
-
-   return true;
-}
-
 BOOL VSSPathConverter();
 BOOL VSSPathConvert(const char *szFilePath, char *szShadowPath, int nBuflen);
 BOOL VSSPathConvertW(const wchar_t *szFilePath, wchar_t *szShadowPath, int nBuflen);
index 90be3185061e24af6f1e8be6778ba121f13321f4..4ec40e8fe9edbe3788524155ce9aa24a2a166738 100644 (file)
  
 #ifdef WIN32_VSS
 
-#define VSS_INIT_RESTORE_AFTER_INIT   1
-#define VSS_INIT_RESTORE_AFTER_GATHER 2
+#include "mtab.h"
 
 // some forward declarations
 struct IVssAsync;
 
-#define bwcsdup(str) wcscpy((WCHAR *)bmalloc((wcslen(str)+1)*sizeof(WCHAR)),(str))
-#define safe_bfree(buf) if (buf) { bfree(buf); buf = NULL; }
-
-/* The MTabEntry class is representing a mounted volume,
- * it associates a volume name with mount paths and a device name
- */
-class MTabEntry: public SMARTALLOC {
-public:
-   WCHAR *volumeName;         // Name of the current volume
-   WCHAR *mountPaths;         // List of mount paths
-   WCHAR *deviceName;
-   WCHAR *shadowCopyName;
-   bool   in_SnapshotSet;
-   bool   can_Snapshot;
-   UINT   driveType;
-   rblink link;
-
-   MTabEntry() {
-      mountPaths = NULL;
-      volumeName = NULL;
-      deviceName = NULL;
-      in_SnapshotSet = false;
-      shadowCopyName = NULL;
-      can_Snapshot = false;
-      driveType = 0;
-   };
-
-   MTabEntry(WCHAR *DeviceName, WCHAR *VolumeName) {
-      int last = wcslen(VolumeName);
-      if (VolumeName[last - 1] == L'\\') {
-         volumeName = bwcsdup(VolumeName);
-      } else {                         /* \\ + \0 */
-         volumeName = (WCHAR *)bmalloc((last+1)*sizeof(WCHAR));
-         wcscpy(volumeName, VolumeName);
-         volumeName[last] = L'\\';
-         volumeName[last+1] = L'\0';
-      }
-      mountPaths = NULL;
-      in_SnapshotSet = false;
-      deviceName = bwcsdup(DeviceName);
-      shadowCopyName = NULL;
-      driveType = 0;
-      can_Snapshot = false;
-      get_paths();
-   };
-
-   ~MTabEntry() {
-      destroy();
-   };
-
-   void destroy() {
-      safe_bfree(mountPaths);
-      safe_bfree(volumeName);
-      safe_bfree(deviceName);
-      safe_bfree(shadowCopyName);
-   };
-
-   /* Return  the drive type (cdrom, fixed, network, ...) */
-   UINT getDriveType();
-
-   /* Return true if the current volume can be snapshoted (ie not CDROM or fat32) */
-   bool isSuitableForSnapshot();
-
-   void setInSnapshotSet() {
-      Dmsg1(050, "Marking %ls for the SnapshotSet\n", mountPaths);
-      in_SnapshotSet = true;
-   }
-
-   void debug_paths() {
-      WCHAR *p;
-      /*  Display the paths in the list. */
-      if (mountPaths != NULL) {
-         Dmsg2(DT_VOLUME|10, "Device: [%ls], Volume: [%ls]\n", deviceName, volumeName);
-         for ( p = mountPaths;  p[0] != L'\0'; p += wcslen(p) + 1) {
-            Dmsg1(DT_VOLUME|10, "  %ls\n", p);
-         }
-      }
-   };
-
-   /* Compute the path list assiciated with the current volume */
-   bool get_paths() {
-      DWORD  count = MAX_PATH + 1;
-      bool   ret = false;
-
-      for (;;) {
-         //  Allocate a buffer to hold the paths.
-         mountPaths = (WCHAR*) malloc(count * sizeof(WCHAR));
-
-         //  Obtain all of the paths
-         //  for this volume.
-         ret = GetVolumePathNamesForVolumeNameW(volumeName, mountPaths, 
-                                                count, &count);
-         if (ret) {
-            break;
-         }
-
-         if (GetLastError() != ERROR_MORE_DATA) {
-            break;
-         }
-
-         //  Try again with the
-         //  new suggested size.
-         free(mountPaths);
-         mountPaths = NULL;
-      }
-      debug_paths();
-      return ret;
-   };
-
-   /* Return the first mount point */
-   WCHAR *first() {
-      return mountPaths;
-   };
-
-   /* Return the next mount point */
-   WCHAR *next(WCHAR *prev) {
-      if (prev == NULL || prev[0] == L'\0') {
-         return NULL;
-      }
-
-      prev += wcslen(prev) + 1;
-
-      return (prev[0] == L'\0') ? NULL : prev;
-   };
-};
-
-/* Class to handle all volumes of the system, it contains
- * a list of all current volumes (MTabEntry)
- */
-class MTab: public SMARTALLOC {
-public:
-   DWORD       lasterror;
-   const char *lasterror_str;
-   rblist     *entries;         /* MTabEntry */
-   int         nb_in_SnapshotSet;
-
-   MTab() {
-      MTabEntry *elt = NULL;
-      lasterror = ERROR_SUCCESS;
-      lasterror_str = "";
-      nb_in_SnapshotSet = 0;
-      entries = New(rblist(elt, &elt->link));
-   };
-
-   ~MTab() {
-      if (entries) {
-         MTabEntry *elt;
-         foreach_rblist(elt, entries) {
-            elt->destroy();
-         }
-         delete entries;
-      }
-   };
-   /* Get a Volume by name */
-   MTabEntry *search(char *file);
-
-   /* Try to add a volume to the current snapshotset */
-   bool addInSnapshotSet(char *file);
-
-   /* Fill the "entries" list will all detected volumes of the system*/
-   bool get();
-};
-
 class VSSClient
 {
 public:
@@ -230,6 +66,7 @@ public:
     void AppendWriterInfo(int nState, const char* pszInfo);
     const bool  IsInitialized() { return m_bBackupIsInitialized; };
     IUnknown *GetVssObject() { return m_pVssObject; };
+    MTab* GetVolumeList() { return m_VolumeList; };
 
 private:
     virtual bool Initialize(DWORD dwContext, bool bDuringRestore = FALSE) = 0;
index a1e6295ddb52a88d2d482f112622aabd09f07daf..283a257ab7e167d837c9dbbaf57443c4854ba75a 100644 (file)
@@ -33,9 +33,8 @@ EXTRA_LIB_OBJS = $(addprefix $(OBJDIR)/, $(EXTRA_LIB_OBJS_ORG))
 COMPAT_OBJS = \
        $(OBJDIR)/compat.o \
        $(OBJDIR)/print.o \
-       $(OBJDIR)/winapi.o
-
-#      $(OBJDIR)/getopt.o \
+       $(OBJDIR)/winapi.o \
+       $(OBJDIR)/mtab.o
 
 FIND_OBJS = \
        $(OBJDIR)/attribs.o \