2 // vss.cpp -- Interface to Volume Shadow Copies (VSS)
4 // Copyright transferred from MATRIX-Computer GmbH to
5 // Kern Sibbald by express permission.
7 // Copyright (C) 2004-2005 Kern Sibbald
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License as
11 // published by the Free Software Foundation; either version 2 of
12 // the License, or (at your option) any later version.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // General Public License for more details.
19 // You should have received a copy of the GNU General Public
20 // License along with this program; if not, write to the Free
21 // Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 // MA 02111-1307, USA.
24 // Author : Thorsten Engel
25 // Created On : Fri May 06 21:44:00 2006
31 #include <sys/types.h>
62 #include <atlcomcli.h>
66 // Used for safe string manipulation
69 #include "vss/inc/WinXP/vss.h"
70 #include "vss/inc/WinXP/vswriter.h"
71 #include "vss/inc/WinXP/vsbackup.h"
75 #pragma comment(lib,"C:/Development/bacula/bacula/src/win32/compat/vss/lib/WinXP/obj/i386/vssapi.lib")
76 #pragma comment(lib,"C:/Development/bacula/bacula/src/win32/compat/vss/lib/WinXP/obj/i386/vss_uuid.lib")
77 #pragma comment(lib,"atlsd.lib")
81 // define global VssClient
82 VSSClient g_VSSClient;
86 * some helper functions
91 // Append a backslash to the current string
92 inline wstring AppendBackslash(wstring str)
94 if (str.length() == 0)
95 return wstring(L"\\");
96 if (str[str.length() - 1] == L'\\')
98 return str.append(L"\\");
101 // Get the unique volume name for the given path
102 inline wstring GetUniqueVolumeNameForPath(wstring path)
104 _ASSERTE(path.length() > 0);
106 // Add the backslash termination, if needed
107 path = AppendBackslash(path);
109 // Get the root path of the volume
110 WCHAR volumeRootPath[MAX_PATH];
111 WCHAR volumeName[MAX_PATH];
112 WCHAR volumeUniqueName[MAX_PATH];
114 if (!GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
117 // Get the volume name alias (might be different from the unique volume name in rare cases)
118 if (!GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
121 // Get the unique volume name
122 if (!GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
125 return volumeUniqueName;
129 // we need something like a map
132 VSSClient::VSSClient()
134 m_bCoInitializeCalled = false;
135 m_dwContext = VSS_CTX_BACKUP;
136 m_bDuringRestore = false;
137 m_bBackupIsInitialized = false;
139 memset (m_wszUniqueVolumeName,0,sizeof (m_wszUniqueVolumeName));
140 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
144 VSSClient::~VSSClient()
146 // Release the IVssBackupComponents interface
147 // WARNING: this must be done BEFORE calling CoUninitialize()
149 m_pVssObject->Release();
153 // Call CoUninitialize if the CoInitialize was performed sucesfully
154 if (m_bCoInitializeCalled)
158 BOOL VSSClient::InitializeForBackup()
160 return Initialize (VSS_CTX_BACKUP);
163 // Initialize the COM infrastructure and the internal pointers
164 BOOL VSSClient::Initialize(DWORD dwContext, bool bDuringRestore)
168 if (!m_bCoInitializeCalled) {
169 if (FAILED(CoInitialize(NULL)))
172 m_bCoInitializeCalled = true;
174 // Initialize COM security
176 CoInitializeSecurity(
177 NULL, // Allow *all* VSS writers to communicate back!
178 -1, // Default COM authentication service
179 NULL, // Default COM authorization service
180 NULL, // reserved parameter
181 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level
182 RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities
183 NULL, // Default COM authentication settings
184 EOAC_NONE, // No special options
185 NULL // Reserved parameter
192 // Release the IVssBackupComponents interface
194 m_pVssObject->Release();
198 // Create the internal backup components object
199 hr = CreateVssBackupComponents(&m_pVssObject);
203 // We are during restore now?
204 m_bDuringRestore = bDuringRestore;
206 // Call either Initialize for backup or for restore
207 if (m_bDuringRestore) {
208 hr = m_pVssObject->InitializeForRestore(CComBSTR(L""));
214 // Initialize for backup
215 hr = m_pVssObject->InitializeForBackup();
222 // Set various properties per backup components instance
223 hr = m_pVssObject->SetBackupState(true, true, VSS_BT_FULL, false);
228 m_dwContext = dwContext;
234 void VSSClient::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
236 // Wait until the async operation finishes
237 HRESULT hr = pAsync->Wait();
239 // Check the result of the asynchronous operation
240 HRESULT hrReturned = S_OK;
241 hr = pAsync->QueryStatus(&hrReturned, NULL);
243 // Check if the async operation succeeded...
244 if(FAILED(hrReturned))
250 BOOL VSSClient::CreateSnapshots(char* szDriveLetters)
252 /* szDriveLetters contains all drive letters in uppercase */
253 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
254 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
256 if (!m_pVssObject || m_bBackupIsInitialized)
259 m_bBackupIsInitialized = true;
261 // 1. InitializeForBackup
262 HRESULT hr = m_pVssObject->InitializeForBackup();
267 hr = m_pVssObject->SetBackupState(true, true, VSS_BT_FULL, false);
271 CComPtr<IVssAsync> pAsync;
272 VSS_ID latestSnapshotSetID;
275 // 3. startSnapshotSet
277 m_pVssObject->StartSnapshotSet(&latestSnapshotSetID);
279 // 4. AddToSnapshotSet
287 for (size_t i=0; i < strlen (szDriveLetters); i++) {
288 szDrive[0] = szDriveLetters[i];
289 volume = GetUniqueVolumeNameForPath(szDrive);
290 // store uniquevolumname
291 if (SUCCEEDED(m_pVssObject->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid)))
292 wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
294 szDriveLetters[i] = tolower (szDriveLetters[i]);
297 // 5. PrepareForBackup
299 m_pVssObject->PrepareForBackup(&pAsync);
301 // Waits for the async operation to finish and checks the result
302 WaitAndCheckForAsyncOperation(pAsync);
308 m_pVssObject->DoSnapshotSet(&pAsync);
310 // Waits for the async operation to finish and checks the result
311 WaitAndCheckForAsyncOperation(pAsync);
313 /* query snapshot info */
314 QuerySnapshotSet(latestSnapshotSetID);
319 BOOL VSSClient::CloseBackup()
321 if (!m_pVssObject || !m_bBackupIsInitialized)
324 m_bBackupIsInitialized = false;
326 CComPtr<IVssAsync> pAsync;
328 if (SUCCEEDED(m_pVssObject->BackupComplete(&pAsync))) {
329 // Waits for the async operation to finish and checks the result
330 WaitAndCheckForAsyncOperation(pAsync);
337 // Query all the shadow copies in the given set
338 void VSSClient::QuerySnapshotSet(GUID snapshotSetID)
340 memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
342 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL)
345 // Get list all shadow copies.
346 CComPtr<IVssEnumObject> pIEnumSnapshots;
347 HRESULT hr = m_pVssObject->Query( GUID_NULL,
352 // If there are no shadow copies, just return
357 // Enumerate all shadow copies.
358 VSS_OBJECT_PROP Prop;
359 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
363 // Get the next element
365 hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
367 // We reached the end of list
371 // Print the shadow copy (if not filtered out)
372 if (Snap.m_SnapshotSetId == snapshotSetID) {
373 for (char ch='A'-'A';ch<='Z'-'A';ch++) {
374 if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {
375 WideCharToMultiByte(CP_UTF8,0,Snap.m_pwszSnapshotDeviceObject,-1,m_szShadowCopyName[ch],MAX_PATH*2,NULL,NULL);
380 ::VssFreeSnapshotProperties(&Snap);
384 BOOL VSSClient::GetShadowPath (const char* szFilePath, char* szShadowPath, int nBuflen)
386 /* check for valid pathname */
389 bIsValidName = strlen (szFilePath) > 3;
391 bIsValidName &= isalpha (szFilePath[0]) &&
392 szFilePath[1]==':' &&
396 int nDriveIndex = toupper(szFilePath[0])-'A';
397 if (m_szShadowCopyName[nDriveIndex][0] != 0) {
398 strncpy (szShadowPath, m_szShadowCopyName[nDriveIndex], nBuflen);
399 nBuflen -= (int) strlen (m_szShadowCopyName[nDriveIndex]);
400 strncat (szShadowPath, szFilePath+2,nBuflen);
406 strncpy (szShadowPath, szFilePath, nBuflen);