diff --git a/src/filed/dir_cmd.c b/src/filed/dir_cmd.c index 869ab1181be..9158d0f35cd 100644 --- a/src/filed/dir_cmd.c +++ b/src/filed/dir_cmd.c @@ -1634,9 +1634,9 @@ static bool backup_cmd(JCR *jcr) */ if (jcr->VSS) { if (g_pVSSClient->InitializeForBackup(jcr)) { - int drive_count, vmp_count; + int drive_count; char szWinDriveLetters[27]; - dlist *szWinVolumeMountpoints = NULL; + bool onefs_disabled; generate_plugin_event(jcr, bEventVssBackupAddComponents); @@ -1651,15 +1651,22 @@ static bool backup_cmd(JCR *jcr) generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters); drive_count = get_win32_driveletters(jcr->ff->fileset, szWinDriveLetters); - vmp_count = get_win32_virtualmountpoints(jcr->ff->fileset, &szWinVolumeMountpoints); - if (drive_count > 0 || vmp_count > 0) { - Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\" VMP(s)=%d\n"), - g_pVSSClient->GetDriverName(), (drive_count) ? szWinDriveLetters : "None", vmp_count); - if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters, szWinVolumeMountpoints)) { + onefs_disabled = win32_onefs_is_disabled(jcr->ff->fileset); + + if (drive_count > 0) { + Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), + g_pVSSClient->GetDriverName(), (drive_count) ? szWinDriveLetters : "None"); + + if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters, onefs_disabled)) { berrno be; Jmsg(jcr, M_FATAL, 0, _("CreateSGenerate VSS snapshots failed. ERR=%s\n"), be.bstrerror()); } else { + /* + * Inform about VMPs if we have them + */ + g_pVSSClient->ShowVolumeMountPointStats(jcr); + /* * Tell user if snapshot creation of a specific drive failed */ @@ -1679,12 +1686,8 @@ static bool backup_cmd(JCR *jcr) } } - if (szWinVolumeMountpoints) { - szWinVolumeMountpoints->destroy(); - free(szWinVolumeMountpoints); - } } else { - Jmsg(jcr, M_FATAL, 0, _("No drive letters or Volume Mount Points found for generating VSS snapshots.\n")); + Jmsg(jcr, M_FATAL, 0, _("No drive letters found for generating VSS snapshots.\n")); } } else { berrno be; diff --git a/src/findlib/find_one.c b/src/findlib/find_one.c index b1408a3fa7d..1e4c92a944e 100644 --- a/src/findlib/find_one.c +++ b/src/findlib/find_one.c @@ -589,10 +589,18 @@ static inline int process_directory(JCR *jcr, FF_PKT *ff_pkt, ff_pkt->type = FT_DIRBEGIN; } + bool is_win32_mount_point = false; #if defined(HAVE_WIN32) + is_win32_mount_point = ff_pkt->statp.st_rdev & FILE_ATTRIBUTE_VOLUME_MOUNT_POINT; + if (ff_pkt->statp.st_rdev & FILE_ATTRIBUTE_REPARSE_POINT) { ff_pkt->type = FT_REPARSE; } + + /* treat win32 mount points (Volume Mount Points) as directories */ + if (is_win32_mount_point) { + ff_pkt->type = FT_DIRBEGIN; + } #endif /* @@ -637,10 +645,6 @@ static inline int process_directory(JCR *jcr, FF_PKT *ff_pkt, * 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 & FILE_ATTRIBUTE_VOLUME_MOUNT_POINT; -#endif if (!top_level && bit_is_set(FO_NO_RECURSION, ff_pkt->flags)) { ff_pkt->type = FT_NORECURSE; recurse = false; diff --git a/src/findlib/protos.h b/src/findlib/protos.h index 3d37ef7e0bf..b7226397db5 100644 --- a/src/findlib/protos.h +++ b/src/findlib/protos.h @@ -107,6 +107,7 @@ void check_include_list_shadowing(JCR *jcr, findFILESET *fileset); #if defined(HAVE_WIN32) /* win32.c */ +bool win32_onefs_is_disabled(findFILESET *fileset); int get_win32_driveletters(findFILESET *fileset, char *szDrives); int get_win32_virtualmountpoints(findFILESET *fileset, dlist **szVmps); bool expand_win32_fileset(findFILESET *fileset); diff --git a/src/win32/filed/vss_generic.c b/src/win32/filed/vss_generic.c index 3c7e70bd95d..c79709a0ccd 100644 --- a/src/win32/filed/vss_generic.c +++ b/src/win32/filed/vss_generic.c @@ -105,6 +105,9 @@ class IXMLDOMDocument; #include "Win2003/vsbackup.h" #endif +#define VSS_ERROR_OBJECT_ALREADY_EXISTS 0x8004230D + + /* In VSSAPI.DLL */ typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **); typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*); @@ -306,6 +309,68 @@ static inline wstring GetUniqueVolumeNameForPath(wstring path) return volumeUniqueName; } +static inline POOLMEM *GetMountedVolumeForMountPointPath(POOLMEM *volumepath, POOLMEM *mountpoint) +{ + POOLMEM *fullPath, *buf, *vol; + int len; + + /* + * GetUniqueVolumeNameForPath() should be used here + */ + len = strlen(volumepath) + 1; + fullPath = get_pool_memory(PM_FNAME); + pm_strcpy(fullPath, volumepath); + pm_strcat(fullPath, mountpoint); + + buf = get_pool_memory(PM_FNAME); + GetVolumeNameForVolumeMountPoint(fullPath, buf, len); + + Dmsg3(200, "%s%s mounts volume %s\n", volumepath, mountpoint, buf); + + vol = get_pool_memory(PM_FNAME); + UTF8_2_wchar(&vol, buf); + + free_pool_memory(fullPath); + free_pool_memory(buf); + + return vol; +} + +static inline bool HandleVolumeMountPoint(VSSClientGeneric *pVssClient, + IVssBackupComponents *pVssObj, + POOLMEM *volumepath, + POOLMEM *mountpoint) +{ + bool retval = false; + HRESULT hr; + POOLMEM *vol = NULL; + POOLMEM *pvol; + VSS_ID pid; + + vol = GetMountedVolumeForMountPointPath(volumepath, mountpoint); + hr = pVssObj->AddToSnapshotSet((LPWSTR)vol, GUID_NULL, &pid); + + pvol = get_pool_memory(PM_FNAME); + wchar_2_UTF8(&pvol, (wchar_t *)vol); + + if (SUCCEEDED(hr)) { + pVssClient->AddVolumeMountPointSnapshots(pVssObj, (wchar_t *)vol); + Dmsg1(200, "%s added to snapshotset \n", pvol); + retval = true; + } else if((unsigned)hr == VSS_ERROR_OBJECT_ALREADY_EXISTS) { + Dmsg1(200, "%s already in snapshotset, skipping.\n" ,pvol); + } else { + Dmsg3(200, "%s with vmp %s could not be added to snapshotset, COM ERROR: 0x%X\n", vol, mountpoint, hr); + } + + free_pool_memory(pvol); + if (vol) { + free_pool_memory(vol); + } + + return retval; +} + /* * Helper macro for quick treatment of case statements for error codes */ @@ -375,10 +440,12 @@ VSSClientGeneric::~VSSClientGeneric() */ bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore) { + VMPs = 0; + VMP_snapshots = 0; HRESULT hr; CComPtr pAsync1; VSS_BACKUP_TYPE backup_type; - IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject; + IVssBackupComponents *pVssObj = (IVssBackupComponents *)m_pVssObject; if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) { Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents=0x%08X, p_VssFreeSnapshotProperties=0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties); @@ -447,7 +514,7 @@ bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore) /* * Define shorthand VssObject with time */ - pVssObj = (IVssBackupComponents*)m_pVssObject; + pVssObj = (IVssBackupComponents *)m_pVssObject; if (!bDuringRestore) { @@ -580,7 +647,7 @@ bool VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync) /* * Add all drive letters that need to be snapshotted. */ -void VSSClientGeneric::AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters) +void VSSClientGeneric::AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters, bool onefs_disabled) { wstring volume; wchar_t szDrive[3]; @@ -600,43 +667,89 @@ void VSSClientGeneric::AddDriveSnapshots(IVssBackupComponents *pVssObj, char *sz /* * Store uniquevolumname. */ + if (SUCCEEDED(pVssObj->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) { if (debug_level >= 200) { + POOLMEM *szBuf = get_pool_memory(PM_FNAME); wchar_2_UTF8(&szBuf, volume.c_str()); - Dmsg1(200, "VSSClientGeneric::AddDriveSnapshots added snapshot for drive with volumename %s\n", szBuf); - + Dmsg2(200, "%s added to snapshotset (Drive %s:\\)\n", szBuf, szDrive); free_pool_memory(szBuf); } wcsncpy(m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR)volume.c_str(), MAX_PATH); } else { szDriveLetters[i] = tolower(szDriveLetters[i]); } + if (onefs_disabled) { + AddVolumeMountPointSnapshots(pVssObj, (LPWSTR)volume.c_str()); + } else { + Jmsg(m_jcr, M_INFO, 0, "VolumeMountpoints are not processed as onefs = yes.\n"); + } } } /* * Add all volume mountpoints that need to be snapshotted. + * Volumes can be mounted multiple times, but can only be added to the snapshotset once. + * So we skip adding a volume if it is already in snapshotset. + * We count the total number of vmps and the number of volumes we added to the snapshotset. */ -void VSSClientGeneric::AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, dlist *szVmps) +void VSSClientGeneric::AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, LPWSTR volume) { - dlistString *vmp; - POOLMEM *volume; - VSS_ID pid; + BOOL b; + int len; + HANDLE hMount; + POOLMEM *mp, *path; - if (szVmps) { - volume = get_pool_memory(PM_FNAME); - foreach_dlist(vmp, szVmps) { - Dmsg1(200, "VSSClientGeneric::AddVolumeMountPointSnapshots added snapshot for volume mountpoint with volumename %s\n", vmp->c_str()); - UTF8_2_wchar(&volume, vmp->c_str()); - pVssObj->AddToSnapshotSet((LPWSTR)volume, GUID_NULL, &pid); + mp = get_pool_memory(PM_FNAME); + path = get_pool_memory(PM_FNAME); + + wchar_2_UTF8(&path, volume); + + len = wcslen(volume) + 1; + + hMount = FindFirstVolumeMountPoint(path, mp, len); + if (hMount != INVALID_HANDLE_VALUE) { + /* + * Count number of vmps. + */ + VMPs += 1; + if (HandleVolumeMountPoint(this, pVssObj, path, mp)) { + /* + * Count vmps that were snapshotted + */ + VMP_snapshots += 1; + } + + while ((b = FindNextVolumeMountPoint(hMount, mp, len))) { + /* + * Count number of vmps. + */ + VMPs += 1; + if (HandleVolumeMountPoint(this, pVssObj, path, mp)) { + /* + * Count vmps that were snapshotted + */ + VMP_snapshots += 1; + } } - free_pool_memory(volume); } + + FindVolumeMountPointClose(hMount); + + free_pool_memory(path); + free_pool_memory(mp); } -bool VSSClientGeneric::CreateSnapshots(char *szDriveLetters, dlist *szVmps) +void VSSClientGeneric::ShowVolumeMountPointStats(JCR *jcr) +{ + if (VMPs) { + Jmsg(jcr, M_INFO, 0, _("Volume Mount Points found: %d, added to snapshotset: %d\n"), VMPs, VMP_snapshots); + } +} + +bool VSSClientGeneric::CreateSnapshots(char *szDriveLetters, bool onefs_disabled) { IVssBackupComponents *pVssObj; CComPtr pAsync1; @@ -670,10 +783,7 @@ bool VSSClientGeneric::CreateSnapshots(char *szDriveLetters, dlist *szVmps) * AddToSnapshotSet */ if (szDriveLetters) { - AddDriveSnapshots(pVssObj, szDriveLetters); - } - if (szVmps) { - AddVolumeMountPointSnapshots(pVssObj, szVmps); + AddDriveSnapshots(pVssObj, szDriveLetters, onefs_disabled); } /* @@ -860,10 +970,10 @@ void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID) * Get list all shadow copies. */ CComPtr pIEnumSnapshots; - HRESULT hr = pVssObj->Query( GUID_NULL, - VSS_OBJECT_NONE, - VSS_OBJECT_SNAPSHOT, - (IVssEnumObject**)(&pIEnumSnapshots) ); + HRESULT hr = pVssObj->Query(GUID_NULL, + VSS_OBJECT_NONE, + VSS_OBJECT_SNAPSHOT, + (IVssEnumObject**)(&pIEnumSnapshots)); /* * If there are no shadow copies, just return @@ -885,7 +995,7 @@ void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID) * Get the next element */ ULONG ulFetched; - hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched ); + hr = (pIEnumSnapshots.p)->Next(1, &Prop, &ulFetched); /* * We reached the end of list diff --git a/src/win32/findlib/win32.c b/src/win32/findlib/win32.c index 13e61bdefc2..a4f5f929240 100644 --- a/src/win32/findlib/win32.c +++ b/src/win32/findlib/win32.c @@ -29,6 +29,30 @@ #include "find.h" #include "lib/cbuf.h" +/* + * We need to analyze if a fileset contains onefs=no as option, because only then + * we need to snapshot submounted vmps + */ +bool win32_onefs_is_disabled(findFILESET *fileset) +{ + findINCEXE *incexe; + + for (int i = 0; i < fileset->include_list.size(); i++) { + incexe = (findINCEXE *)fileset->include_list.get(i); + /* + * Look through all files and check + */ + for (int j = 0; j < incexe->opts_list.size(); j++) { + findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j); + if (bit_is_set(FO_MULTIFS, fo->flags)) { + return true; + } + } + } + + return false; +} + /* * For VSS we need to know which windows drives are used, because we create a snapshot * of all used drives. This function returns the number of used drives and fills diff --git a/src/win32/include/vss.h b/src/win32/include/vss.h index 2f463b2614b..191bfe4aa7d 100644 --- a/src/win32/include/vss.h +++ b/src/win32/include/vss.h @@ -55,9 +55,11 @@ class VSSClient // Backup Process bool InitializeForBackup(JCR *jcr); bool InitializeForRestore(JCR *jcr); - virtual void AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters) = 0; - virtual void AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, dlist *szVmps) = 0; - virtual bool CreateSnapshots(char *szDriveLetters, dlist *szVmps) = 0; + virtual void AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters, bool onefs_disabled) = 0; + virtual void AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, LPWSTR volume) = 0; + virtual void ShowVolumeMountPointStats(JCR *jcr) = 0; + + virtual bool CreateSnapshots(char *szDriveLetters, bool onefs_disabled) = 0; virtual bool CloseBackup() = 0; virtual bool CloseRestore() = 0; virtual WCHAR *GetMetadata() = 0; @@ -88,9 +90,12 @@ class VSSClient IUnknown *m_pVssObject; GUID m_uidCurrentSnapshotSet; - // drive A will be stored on position 0,Z on pos. 25 - wchar_t m_wszUniqueVolumeName[26][MAX_PATH]; // approx. 7 KB - wchar_t m_szShadowCopyName[26][MAX_PATH]; // approx. 7 KB + /* + ! drive A will be stored on position 0, Z on pos. 25 + */ + wchar_t m_wszUniqueVolumeName[26][MAX_PATH]; + wchar_t m_szShadowCopyName[26][MAX_PATH]; + wchar_t *m_metadata; alist *m_pAlistWriterState; alist *m_pAlistWriterInfoText; @@ -101,17 +106,19 @@ class VSSClient bool m_bBackupIsInitialized; bool m_bWriterStatusCurrent; - WCHAR *m_metadata; + int VMPs; /* volume mount points */ + int VMP_snapshots; /* volume mount points that are snapshotted */ }; -class VSSClientXP:public VSSClient +class VSSClientXP: public VSSClient { public: VSSClientXP(); virtual ~VSSClientXP(); - virtual void AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters); - virtual void AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, dlist *szVmps); - virtual bool CreateSnapshots(char *szDriveLetters, dlist *szVmps); + virtual void AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters, bool onefs_disabled); + virtual void AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, LPWSTR volume); + virtual void ShowVolumeMountPointStats(JCR *jcr); + virtual bool CreateSnapshots(char *szDriveLetters, bool onefs_disabled); virtual bool CloseBackup(); virtual bool CloseRestore(); virtual WCHAR *GetMetadata(); @@ -120,6 +127,7 @@ class VSSClientXP:public VSSClient #else virtual const char *GetDriverName() { return "Win32 VSS"; }; #endif + private: virtual bool Initialize(DWORD dwContext, bool bDuringRestore); virtual bool WaitAndCheckForAsyncOperation(IVssAsync *pAsync); @@ -127,14 +135,15 @@ class VSSClientXP:public VSSClient bool CheckWriterStatus(); }; -class VSSClient2003:public VSSClient +class VSSClient2003: public VSSClient { public: VSSClient2003(); virtual ~VSSClient2003(); - virtual void AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters); - virtual void AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, dlist *szVmps); - virtual bool CreateSnapshots(char *szDriveLetters, dlist *szVmps); + virtual void AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters, bool onefs_disabled); + virtual void AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, LPWSTR volume); + virtual void ShowVolumeMountPointStats(JCR *jcr); + virtual bool CreateSnapshots(char *szDriveLetters, bool onefs_disabled); virtual bool CloseBackup(); virtual bool CloseRestore(); virtual WCHAR *GetMetadata(); @@ -143,6 +152,7 @@ class VSSClient2003:public VSSClient #else virtual const char *GetDriverName() { return "Win32 VSS"; }; #endif + private: virtual bool Initialize(DWORD dwContext, bool bDuringRestore); virtual bool WaitAndCheckForAsyncOperation(IVssAsync *pAsync); @@ -150,14 +160,15 @@ class VSSClient2003:public VSSClient bool CheckWriterStatus(); }; -class VSSClientVista:public VSSClient +class VSSClientVista: public VSSClient { public: VSSClientVista(); virtual ~VSSClientVista(); - virtual void AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters); - virtual void AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, dlist *szVmps); - virtual bool CreateSnapshots(char *szDriveLetters, dlist *szVmps); + virtual void AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters, bool onefs_disabled); + virtual void AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, LPWSTR volume); + virtual void ShowVolumeMountPointStats(JCR *jcr); + virtual bool CreateSnapshots(char *szDriveLetters, bool onefs_disabled); virtual bool CloseBackup(); virtual bool CloseRestore(); virtual WCHAR *GetMetadata(); @@ -166,6 +177,7 @@ class VSSClientVista:public VSSClient #else virtual const char *GetDriverName() { return "Win32 VSS"; }; #endif + private: virtual bool Initialize(DWORD dwContext, bool bDuringRestore); virtual bool WaitAndCheckForAsyncOperation(IVssAsync *pAsync); @@ -173,7 +185,6 @@ class VSSClientVista:public VSSClient bool CheckWriterStatus(); }; - extern VSSClient *g_pVSSClient; bool VSSPathConvert(const char *szFilePath, char *szShadowPath, int nBuflen);