*
*/
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) {
* 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);
}
}
}
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;
}
}
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++) {
/* 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;
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 */
}
/* 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 ? */
*(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();
}
/* 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 {
}
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++;
}
}
+ if (!mtab_def) {
+ delete mtab;
+ }
#endif /* HAVE_WIN32 */
return nCount;
}
}
/* 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),
/* 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());
} 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");
*
*/
+#ifndef RBLIST_H
+#define RBLIST_H
+
#define M_ABORT 1
/*
{
return ((rblink *)(((char *)item)+loffset))->red;
}
+#endif /* RBLIST_H */
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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 */
$(OBJDIR)/heartbeat.o \
$(OBJDIR)/hello.o \
$(OBJDIR)/job.o \
+ $(OBJDIR)/mtab.o \
$(OBJDIR)/restore.o \
$(OBJDIR)/status.o \
$(OBJDIR)/verify.o \
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);
#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:
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;
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 \