1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2005-2010 Free Software Foundation Europe e.V.
5 
6    This program is Free Software; you can redistribute it and/or
7    modify it under the terms of version three of the GNU Affero General Public
8    License as published by the Free Software Foundation and included
9    in the file LICENSE.
10 
11    This program is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14    Affero General Public License for more details.
15 
16    You should have received a copy of the GNU Affero General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19    02110-1301, USA.
20 */
21 
22 /*
23  * vss.c -- Interface to Volume Shadow Copies (VSS)
24  *
25  * Copyright transferred from MATRIX-Computer GmbH to
26  *   Kern Sibbald by express permission.
27  *
28  * Author          : Thorsten Engel
29  * Created On      : Fri May 06 21:44:00 2005
30  */
31 
32 #ifdef WIN32_VSS
33 
34 #include "include/bareos.h"
35 #include "include/jcr.h"
36 #include "lib/berrno.h"
37 #include "findlib/find.h"
38 #define FILE_DAEMON 1
39 #include "filed/fd_plugins.h"
40 
41 #undef setlocale
42 
43 // STL includes
44 #include <vector>
45 #include <algorithm>
46 #include <string>
47 #include <sstream>
48 #include <fstream>
49 using namespace std;
50 
51 #include "ms_atl.h"
52 #include <objbase.h>
53 
54 /*
55  * Kludges to get Vista code to compile.
56  */
57 #define __in IN
58 #define __out OUT
59 #define __RPC_unique_pointer
60 #define __RPC_string
61 #ifndef __RPC__out_ecount_part
62 #define __RPC__out_ecount_part(x, y)
63 #endif
64 #define __RPC__deref_inout_opt
65 #define __RPC__out
66 
67 #if !defined(ENABLE_NLS)
68 #define setlocale(p, d)
69 #endif
70 
71 #ifdef HAVE_STRSAFE_H
72 /*
73  * Used for safe string manipulation
74  */
75 #include <strsafe.h>
76 #endif
77 
78 #ifdef HAVE_MINGW
79 class IXMLDOMDocument;
80 #endif
81 
82 /*
83  * Reduce compiler warnings from Windows vss code
84  */
85 #undef uuid
86 #define uuid(x)
87 
88 #ifdef B_VSS_XP
89 #define VSSClientGeneric VSSClientXP
90 #include "WinXP/vss.h"
91 #include "WinXP/vswriter.h"
92 #include "WinXP/vsbackup.h"
93 #endif
94 
95 #ifdef B_VSS_W2K3
96 #define VSSClientGeneric VSSClient2003
97 #include "Win2003/vss.h"
98 #include "Win2003/vswriter.h"
99 #include "Win2003/vsbackup.h"
100 #endif
101 
102 #ifdef B_VSS_VISTA
103 #define VSSClientGeneric VSSClientVista
104 #include "Win2003/vss.h"
105 #include "Win2003/vswriter.h"
106 #include "Win2003/vsbackup.h"
107 #endif
108 
109 #define VSS_ERROR_OBJECT_ALREADY_EXISTS 0x8004230D
110 
111 #pragma GCC diagnostic push
112 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
113 #include "vss.h"
114 #pragma GCC diagnostic pop
115 
116 using namespace filedaemon;
117 
JmsgVssApiStatus(JobControlRecord * jcr,int msg_status,HRESULT hr,const char * apiName)118 static void JmsgVssApiStatus(JobControlRecord* jcr,
119                              int msg_status,
120                              HRESULT hr,
121                              const char* apiName)
122 {
123   const char* errmsg;
124 
125   if (hr == S_OK || hr == VSS_S_ASYNC_FINISHED) { return; }
126 
127   switch (hr) {
128     case E_INVALIDARG:
129       errmsg = "One of the parameter values is not valid.";
130       break;
131     case E_OUTOFMEMORY:
132       errmsg = "The caller is out of memory or other system resources.";
133       break;
134     case E_ACCESSDENIED:
135       errmsg =
136           "The caller does not have sufficient backup privileges or is not an "
137           "administrator.";
138       break;
139     case VSS_E_INVALID_XML_DOCUMENT:
140       errmsg = "The XML document is not valid.";
141       break;
142     case VSS_E_OBJECT_NOT_FOUND:
143       errmsg = "The specified file does not exist.";
144       break;
145     case VSS_E_BAD_STATE:
146       errmsg =
147           "Object is not initialized; called during restore or not called in "
148           "correct sequence.";
149       break;
150     case VSS_E_WRITER_INFRASTRUCTURE:
151       errmsg =
152           "The writer infrastructure is not operating properly. Check that the "
153           "Event Service and VSS have been started, and check for errors "
154           "associated with those services in the error log.";
155       break;
156     case VSS_S_ASYNC_CANCELLED:
157       errmsg =
158           "The asynchronous operation was canceled by a previous call to "
159           "IVssAsync::Cancel.";
160       break;
161     case VSS_S_ASYNC_PENDING:
162       errmsg = "The asynchronous operation is still running.";
163       break;
164     case RPC_E_CHANGED_MODE:
165       errmsg =
166           "Previous call to CoInitializeEx specified the multithread apartment "
167           "(MTA). This call indicates single-threaded apartment has occurred.";
168       break;
169     case S_FALSE:
170       errmsg = "No writer found for the current component.";
171       break;
172     default:
173       errmsg =
174           "Unexpected error. The error code is logged in the error log file.";
175       break;
176   }
177   Jmsg(jcr, msg_status, 0, "VSS API failure calling \"%s\". ERR=%s\n", apiName,
178        errmsg);
179 }
180 
181 #ifndef VSS_WS_FAILED_AT_BACKUPSHUTDOWN
182 #define VSS_WS_FAILED_AT_BACKUPSHUTDOWN (VSS_WRITER_STATE)15
183 #endif
184 
JmsgVssWriterStatus(JobControlRecord * jcr,int msg_status,VSS_WRITER_STATE eWriterStatus,char * writer_name)185 static void JmsgVssWriterStatus(JobControlRecord* jcr,
186                                 int msg_status,
187                                 VSS_WRITER_STATE eWriterStatus,
188                                 char* writer_name)
189 {
190   const char* errmsg;
191 
192   /*
193    * The following are normal states
194    */
195   if (eWriterStatus == VSS_WS_STABLE ||
196       eWriterStatus == VSS_WS_WAITING_FOR_BACKUP_COMPLETE) {
197     return;
198   }
199 
200   /*
201    * Potential errors
202    */
203   switch (eWriterStatus) {
204     default:
205     case VSS_WS_UNKNOWN:
206       errmsg = "The writer's state is not known. This is a writer error.";
207       break;
208     case VSS_WS_WAITING_FOR_FREEZE:
209       errmsg = "The writer is waiting for the freeze state.";
210       break;
211     case VSS_WS_WAITING_FOR_THAW:
212       errmsg = "The writer is waiting for the thaw state.";
213       break;
214     case VSS_WS_WAITING_FOR_POST_SNAPSHOT:
215       errmsg = "The writer is waiting for the PostSnapshot state.";
216       break;
217     case VSS_WS_WAITING_FOR_BACKUP_COMPLETE:
218       errmsg =
219           "The writer is waiting for the requester to finish its backup "
220           "operation.";
221       break;
222     case VSS_WS_FAILED_AT_IDENTIFY:
223       errmsg =
224           "The writer vetoed the shadow copy creation process at the writer "
225           "identification state.";
226       break;
227     case VSS_WS_FAILED_AT_PREPARE_BACKUP:
228       errmsg =
229           "The writer vetoed the shadow copy creation process during the "
230           "backup preparation state.";
231       break;
232     case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
233       errmsg =
234           "The writer vetoed the shadow copy creation process during the "
235           "PrepareForSnapshot state.";
236       break;
237     case VSS_WS_FAILED_AT_FREEZE:
238       errmsg =
239           "The writer vetoed the shadow copy creation process during the "
240           "freeze state.";
241       break;
242     case VSS_WS_FAILED_AT_THAW:
243       errmsg =
244           "The writer vetoed the shadow copy creation process during the thaw "
245           "state.";
246       break;
247     case VSS_WS_FAILED_AT_POST_SNAPSHOT:
248       errmsg =
249           "The writer vetoed the shadow copy creation process during the "
250           "PostSnapshot state.";
251       break;
252     case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
253       errmsg =
254           "The shadow copy has been created and the writer failed during the "
255           "BackupComplete state.";
256       break;
257     case VSS_WS_FAILED_AT_PRE_RESTORE:
258       errmsg = "The writer failed during the PreRestore state.";
259       break;
260     case VSS_WS_FAILED_AT_POST_RESTORE:
261       errmsg = "The writer failed during the PostRestore state.";
262       break;
263     case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
264       errmsg =
265           "The writer failed during the shutdown of the backup application.";
266   }
267   Jmsg(jcr, msg_status, 0, "VSS Writer \"%s\" has invalid state. ERR=%s\n",
268        writer_name, errmsg);
269 }
270 
271 /*
272  * Some helper functions
273  */
274 
275 /*
276  * strdup a wchar_t string.
277  */
wbstrdup(const wchar_t * str)278 static inline wchar_t* wbstrdup(const wchar_t* str)
279 {
280   int len;
281   wchar_t* dup;
282 
283   len = wcslen(str) + 1;
284   dup = (wchar_t*)malloc(len * sizeof(wchar_t));
285   memcpy(dup, str, len * sizeof(wchar_t));
286 
287   return dup;
288 }
289 
290 /*
291  * Append a backslash to the current string.
292  */
AppendBackslash(wstring str)293 static inline wstring AppendBackslash(wstring str)
294 {
295   if (str.length() == 0) { return wstring(L"\\"); }
296   if (str[str.length() - 1] == L'\\') { return str; }
297   return str.append(L"\\");
298 }
299 
300 /*
301  * Get the unique volume name for the given path.
302  */
GetUniqueVolumeNameForPath(wstring path)303 static inline wstring GetUniqueVolumeNameForPath(wstring path)
304 {
305   wchar_t volumeRootPath[MAX_PATH];
306   wchar_t volumeName[MAX_PATH];
307   wchar_t volumeUniqueName[MAX_PATH];
308 
309   if (path.length() <= 0) { return L""; }
310 
311   /*
312    * Add the backslash termination, if needed.
313    */
314   path = AppendBackslash(path);
315 
316   /*
317    * Get the root path of the volume.
318    */
319   if (!p_GetVolumePathNameW ||
320       !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH)) {
321     return L"";
322   }
323 
324   /*
325    * Get the volume name alias (might be different from the unique volume name
326    * in rare cases).
327    */
328   if (!p_GetVolumeNameForVolumeMountPointW ||
329       !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName,
330                                            MAX_PATH)) {
331     return L"";
332   }
333 
334   /*
335    * Get the unique volume name.
336    */
337   if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName,
338                                            MAX_PATH)) {
339     return L"";
340   }
341 
342   return volumeUniqueName;
343 }
344 
GetMountedVolumeForMountPointPath(POOLMEM * volumepath,POOLMEM * mountpoint)345 static inline POOLMEM* GetMountedVolumeForMountPointPath(POOLMEM* volumepath,
346                                                          POOLMEM* mountpoint)
347 {
348   POOLMEM *fullPath, *buf, *vol;
349   int len;
350 
351   /*
352    * GetUniqueVolumeNameForPath() should be used here
353    */
354   len = strlen(volumepath) + 1;
355   fullPath = GetPoolMemory(PM_FNAME);
356   PmStrcpy(fullPath, volumepath);
357   PmStrcat(fullPath, mountpoint);
358 
359   buf = GetPoolMemory(PM_FNAME);
360   GetVolumeNameForVolumeMountPoint(fullPath, buf, len);
361 
362   Dmsg3(200, "%s%s mounts volume %s\n", volumepath, mountpoint, buf);
363 
364   vol = GetPoolMemory(PM_FNAME);
365   UTF8_2_wchar(vol, buf);
366 
367   FreePoolMemory(fullPath);
368   FreePoolMemory(buf);
369 
370   return vol;
371 }
372 
HandleVolumeMountPoint(VSSClientGeneric * pVssClient,IVssBackupComponents * pVssObj,POOLMEM * & volumepath,POOLMEM * & mountpoint)373 static inline bool HandleVolumeMountPoint(VSSClientGeneric* pVssClient,
374                                           IVssBackupComponents* pVssObj,
375                                           POOLMEM*& volumepath,
376                                           POOLMEM*& mountpoint)
377 {
378   bool retval = false;
379   HRESULT hr;
380   POOLMEM* vol = NULL;
381   POOLMEM* pvol;
382   VSS_ID pid;
383 
384   vol = GetMountedVolumeForMountPointPath(volumepath, mountpoint);
385   hr = pVssObj->AddToSnapshotSet((LPWSTR)vol, GUID_NULL, &pid);
386 
387   pvol = GetPoolMemory(PM_FNAME);
388   wchar_2_UTF8(pvol, (wchar_t*)vol);
389 
390   if (SUCCEEDED(hr)) {
391     pVssClient->AddVolumeMountPointSnapshots(pVssObj, (wchar_t*)vol);
392     Dmsg1(200, "%s added to snapshotset \n", pvol);
393     retval = true;
394   } else if ((unsigned)hr == VSS_ERROR_OBJECT_ALREADY_EXISTS) {
395     Dmsg1(200, "%s already in snapshotset, skipping.\n", pvol);
396   } else {
397     Dmsg3(200,
398           "%s with vmp %s could not be added to snapshotset, COM ERROR: 0x%X\n",
399           vol, mountpoint, hr);
400   }
401 
402   FreePoolMemory(pvol);
403   if (vol) { FreePoolMemory(vol); }
404 
405   return retval;
406 }
407 
408 /*
409  * Helper macro for quick treatment of case statements for error codes
410  */
411 #define GEN_MERGE(A, B) A##B
412 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
413 
414 #define CHECK_CASE_FOR_CONSTANT(value) \
415   case value:                          \
416     return (GEN_MAKE_W(#value));
417 
418 /*
419  * Convert a writer status into a string
420  */
GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)421 static inline const wchar_t* GetStringFromWriterStatus(
422     VSS_WRITER_STATE eWriterStatus)
423 {
424   switch (eWriterStatus) {
425     CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
426     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
427     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
428     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
429     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
430     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
431     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
432     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
433     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
434     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
435     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
436     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
437     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
438     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
439     default:
440       return L"Error or Undefined";
441   }
442 }
443 
444 #ifdef HAVE_VSS64
445 /* 64 bit entrypoint name */
446 #define VSSVBACK_ENTRY \
447   "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
448 #else
449 /* 32 bit entrypoint name */
450 #define VSSVBACK_ENTRY \
451   "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
452 #endif
453 
454 /*
455  * Constructor
456  */
VSSClientGeneric()457 VSSClientGeneric::VSSClientGeneric()
458 {
459   hLib_ = LoadLibraryA("VSSAPI.DLL");
460   if (hLib_) {
461     CreateVssBackupComponents_ =
462         (t_CreateVssBackupComponents)GetProcAddress(hLib_, VSSVBACK_ENTRY);
463     VssFreeSnapshotProperties_ = (t_VssFreeSnapshotProperties)GetProcAddress(
464         hLib_, "VssFreeSnapshotProperties");
465   }
466 }
467 
468 /*
469  * Destructor
470  */
~VSSClientGeneric()471 VSSClientGeneric::~VSSClientGeneric()
472 {
473   if (hLib_) { FreeLibrary(hLib_); }
474 }
475 
476 /*
477  * Initialize the COM infrastructure and the internal pointers
478  */
Initialize(DWORD dwContext,bool bDuringRestore)479 bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore)
480 {
481   VMPs = 0;
482   VMP_snapshots = 0;
483   HRESULT hr = S_OK;
484   CComPtr<IVssAsync> pAsync1;
485   IVssBackupComponents* pVssObj = (IVssBackupComponents*)pVssObject_;
486 
487   if (!(CreateVssBackupComponents_ && VssFreeSnapshotProperties_)) {
488     Dmsg2(0,
489           "VSSClientGeneric::Initialize: CreateVssBackupComponents_=0x%08X, "
490           "VssFreeSnapshotProperties_=0x%08X\n",
491           CreateVssBackupComponents_, VssFreeSnapshotProperties_);
492     Jmsg(jcr_, M_FATAL, 0,
493          "Entry point CreateVssBackupComponents or VssFreeSnapshotProperties "
494          "missing.\n");
495     return false;
496   }
497 
498   /*
499    * Initialize COM
500    */
501   if (!bCoInitializeCalled_) {
502     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
503     if (FAILED(hr)) {
504       Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeEx returned 0x%08X\n",
505             hr);
506       JmsgVssApiStatus(jcr_, M_FATAL, hr, "CoInitializeEx");
507       errno = b_errno_win32;
508       return false;
509     }
510     bCoInitializeCalled_ = true;
511   }
512 
513   /*
514    * Initialize COM security
515    */
516   if (!InitializeComSecurity()) {
517     JmsgVssApiStatus(jcr_, M_FATAL, hr, "CoInitializeSecurity");
518     return false;
519   }
520 
521   /*
522    * Release the any old IVssBackupComponents interface
523    */
524   if (pVssObj) {
525     pVssObj->Release();
526     pVssObject_ = NULL;
527   }
528 
529   /*
530    * Create new internal backup components object
531    */
532   hr = CreateVssBackupComponents_((IVssBackupComponents**)&pVssObject_);
533   if (FAILED(hr)) {
534     BErrNo be;
535     Dmsg2(0,
536           "VSSClientGeneric::Initialize: CreateVssBackupComponents returned "
537           "0x%08X. ERR=%s\n",
538           hr, be.bstrerror(b_errno_win32));
539     JmsgVssApiStatus(jcr_, M_FATAL, hr, "CreateVssBackupComponents");
540     errno = b_errno_win32;
541     return false;
542   }
543 
544   /*
545    * Define shorthand VssObject with time
546    */
547   pVssObj = (IVssBackupComponents*)pVssObject_;
548 
549   if (!bDuringRestore) {
550 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
551     if (dwContext != VSS_CTX_BACKUP) {
552       hr = pVssObj->SetContext(dwContext);
553       if (FAILED(hr)) {
554         Dmsg1(0,
555               "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext "
556               "returned 0x%08X\n",
557               hr);
558         JmsgVssApiStatus(jcr_, M_FATAL, hr, "SetContext");
559         errno = b_errno_win32;
560         return false;
561       }
562     }
563 #endif
564 
565     /*
566      * 1. InitializeForBackup
567      */
568     hr = pVssObj->InitializeForBackup();
569     if (FAILED(hr)) {
570       Dmsg1(0,
571             "VSSClientGeneric::Initialize: "
572             "IVssBackupComponents->InitializeForBackup returned 0x%08X\n",
573             hr);
574       JmsgVssApiStatus(jcr_, M_FATAL, hr, "InitializeForBackup");
575       errno = b_errno_win32;
576       return false;
577     }
578 
579     /*
580      * 2. SetBackupState
581      *
582      * Generate a bEventVssSetBackupState event and if none of the plugins
583      * give back a bRC_Skip it means this will not be performed by any plugin
584      * and we should do the generic handling ourself in the core.
585      */
586     if (GeneratePluginEvent(jcr_, bEventVssSetBackupState) != bRC_Skip) {
587       VSS_BACKUP_TYPE backup_type;
588 
589       switch (jcr_->getJobLevel()) {
590         case L_FULL:
591           backup_type = VSS_BT_FULL;
592           break;
593         case L_DIFFERENTIAL:
594           backup_type = VSS_BT_DIFFERENTIAL;
595           break;
596         case L_INCREMENTAL:
597           backup_type = VSS_BT_INCREMENTAL;
598           break;
599         default:
600           Dmsg1(0, "VSSClientGeneric::Initialize: unknown backup level %d\n",
601                 jcr_->getJobLevel());
602           backup_type = VSS_BT_FULL;
603           break;
604       }
605 
606       hr = pVssObj->SetBackupState(true,        /* bSelectComponents */
607                                    true,        /* bBackupBootableSystemState */
608                                    backup_type, /* backupType */
609                                    false        /* bPartialFileSupport */
610       );
611       if (FAILED(hr)) {
612         Dmsg1(0,
613               "VSSClientGeneric::Initialize: "
614               "IVssBackupComponents->SetBackupState returned 0x%08X\n",
615               hr);
616         JmsgVssApiStatus(jcr_, M_FATAL, hr, "SetBackupState");
617         errno = b_errno_win32;
618         return false;
619       }
620     }
621 
622     /*
623      * 3. GatherWriterMetaData
624      */
625     hr = pVssObj->GatherWriterMetadata(&pAsync1.p);
626     if (FAILED(hr)) {
627       Dmsg1(0,
628             "VSSClientGeneric::Initialize: "
629             "IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n",
630             hr);
631       JmsgVssApiStatus(jcr_, M_FATAL, hr, "GatherWriterMetadata");
632       errno = b_errno_win32;
633       return false;
634     }
635 
636     /*
637      * Wait for the async operation to finish and checks the result
638      */
639     if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
640       /*
641        * Error message already printed
642        */
643       errno = b_errno_win32;
644       return false;
645     }
646   }
647 
648   /*
649    * We are during restore now?
650    */
651   bDuringRestore_ = bDuringRestore;
652 
653   /*
654    * Keep the context
655    */
656   dwContext_ = dwContext;
657 
658   return true;
659 }
660 
WaitAndCheckForAsyncOperation(IVssAsync * pAsync)661 bool VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
662 {
663   HRESULT hr;
664   HRESULT hrReturned = S_OK;
665   int timeout = 600; /* 10 minutes.... */
666   int queryErrors = 0;
667 
668   /*
669    * Wait until the async operation finishes
670    * unfortunately we can't use a timeout here yet.
671    * the interface would allow it on W2k3,
672    * but it is not implemented yet....
673    */
674   do {
675     if (hrReturned != S_OK) { Sleep(1000); }
676     hrReturned = S_OK;
677     hr = pAsync->QueryStatus(&hrReturned, NULL);
678 
679     if (FAILED(hr)) { queryErrors++; }
680   } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
681 
682   /*
683    * Check the result of the asynchronous operation
684    */
685   if (hrReturned == VSS_S_ASYNC_FINISHED) { return true; }
686 
687   JmsgVssApiStatus(jcr_, M_FATAL, hr,
688                    "Query Async Status after 10 minute wait");
689 
690   return false;
691 }
692 
693 /*
694  * Add all drive letters that need to be snapshotted.
695  */
AddDriveSnapshots(IVssBackupComponents * pVssObj,char * szDriveLetters,bool onefs_disabled)696 void VSSClientGeneric::AddDriveSnapshots(IVssBackupComponents* pVssObj,
697                                          char* szDriveLetters,
698                                          bool onefs_disabled)
699 {
700   wstring volume;
701   wchar_t szDrive[3];
702   VSS_ID pid;
703 
704   szDrive[1] = ':';
705   szDrive[2] = 0;
706 
707   /*
708    * szDriveLetters contains all drive letters in uppercase
709    * If a drive can not being added, it's converted to lowercase in
710    * szDriveLetters
711    */
712   for (size_t i = 0; i < strlen(szDriveLetters); i++) {
713     szDrive[0] = szDriveLetters[i];
714     volume = GetUniqueVolumeNameForPath(szDrive);
715 
716     /*
717      * Store uniquevolumname.
718      */
719 
720     if (SUCCEEDED(pVssObj->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL,
721                                             &pid))) {
722       if (debug_level >= 200) {
723         POOLMEM* szBuf = GetPoolMemory(PM_FNAME);
724 
725         wchar_2_UTF8(szBuf, volume.c_str());
726         Dmsg2(200, "%s added to snapshotset (Drive %s:\\)\n", szBuf, szDrive);
727         FreePoolMemory(szBuf);
728       }
729       wcsncpy(wszUniqueVolumeName_[szDriveLetters[i] - 'A'],
730               (LPWSTR)volume.c_str(), MAX_PATH);
731     } else {
732       szDriveLetters[i] = tolower(szDriveLetters[i]);
733     }
734     if (onefs_disabled) {
735       AddVolumeMountPointSnapshots(pVssObj, (LPWSTR)volume.c_str());
736     } else {
737       Jmsg(jcr_, M_INFO, 0,
738            "VolumeMountpoints are not processed as onefs = yes.\n");
739     }
740   }
741 }
742 
743 /*
744  * Add all volume mountpoints that need to be snapshotted.
745  * Volumes can be mounted multiple times, but can only be added to the
746  * snapshotset once. So we skip adding a volume if it is already in snapshotset.
747  * We count the total number of vmps and the number of volumes we added to the
748  * snapshotset.
749  */
AddVolumeMountPointSnapshots(IVssBackupComponents * pVssObj,LPWSTR volume)750 void VSSClientGeneric::AddVolumeMountPointSnapshots(
751     IVssBackupComponents* pVssObj,
752     LPWSTR volume)
753 {
754   BOOL b;
755   int len;
756   HANDLE hMount;
757   POOLMEM *mp, *path;
758 
759   mp = GetPoolMemory(PM_FNAME);
760   path = GetPoolMemory(PM_FNAME);
761 
762   wchar_2_UTF8(path, volume);
763 
764   len = wcslen(volume) + 1;
765 
766   hMount = FindFirstVolumeMountPoint(path, mp, len);
767   if (hMount != INVALID_HANDLE_VALUE) {
768     /*
769      * Count number of vmps.
770      */
771     VMPs += 1;
772     if (HandleVolumeMountPoint(this, pVssObj, path, mp)) {
773       /*
774        * Count vmps that were snapshotted
775        */
776       VMP_snapshots += 1;
777     }
778 
779     while ((b = FindNextVolumeMountPoint(hMount, mp, len))) {
780       /*
781        * Count number of vmps.
782        */
783       VMPs += 1;
784       if (HandleVolumeMountPoint(this, pVssObj, path, mp)) {
785         /*
786          * Count vmps that were snapshotted
787          */
788         VMP_snapshots += 1;
789       }
790     }
791   }
792 
793   FindVolumeMountPointClose(hMount);
794 
795   FreePoolMemory(path);
796   FreePoolMemory(mp);
797 }
798 
ShowVolumeMountPointStats(JobControlRecord * jcr)799 void VSSClientGeneric::ShowVolumeMountPointStats(JobControlRecord* jcr)
800 {
801   if (VMPs) {
802     Jmsg(jcr, M_INFO, 0,
803          _("Volume Mount Points found: %d, added to snapshotset: %d\n"), VMPs,
804          VMP_snapshots);
805   }
806 }
807 
CreateSnapshots(char * szDriveLetters,bool onefs_disabled)808 bool VSSClientGeneric::CreateSnapshots(char* szDriveLetters,
809                                        bool onefs_disabled)
810 {
811   IVssBackupComponents* pVssObj;
812   CComPtr<IVssAsync> pAsync1;
813   CComPtr<IVssAsync> pAsync2;
814   HRESULT hr;
815 
816   /*
817    * See
818    * http://msdn.microsoft.com/en-us/library/windows/desktop/aa382870%28v=vs.85%29.aspx.
819    */
820   if (!pVssObject_ || bBackupIsInitialized_) {
821     Jmsg(jcr_, M_FATAL, 0,
822          "No pointer to VssObject or Backup is not Initialized\n");
823     errno = ENOSYS;
824     return false;
825   }
826 
827   uidCurrentSnapshotSet_ = GUID_NULL;
828 
829   pVssObj = (IVssBackupComponents*)pVssObject_;
830 
831   /*
832    * startSnapshotSet
833    */
834   hr = pVssObj->StartSnapshotSet(&uidCurrentSnapshotSet_);
835   while ((unsigned)hr == VSS_E_SNAPSHOT_SET_IN_PROGRESS) {
836     Bmicrosleep(5, 0);
837     Jmsg(jcr_, M_INFO, 0, "VSS_E_SNAPSHOT_SET_IN_PROGRESS, retrying ...\n");
838     hr = pVssObj->StartSnapshotSet(&uidCurrentSnapshotSet_);
839   }
840 
841   if (FAILED(hr)) {
842     JmsgVssApiStatus(jcr_, M_FATAL, hr, "StartSnapshotSet");
843     errno = ENOSYS;
844     return false;
845   }
846 
847   /*
848    * AddToSnapshotSet
849    */
850   if (szDriveLetters) {
851     AddDriveSnapshots(pVssObj, szDriveLetters, onefs_disabled);
852   }
853 
854   /*
855    * PrepareForBackup
856    */
857   GeneratePluginEvent(jcr_, bEventVssPrepareSnapshot);
858   hr = pVssObj->PrepareForBackup(&pAsync1.p);
859   if (FAILED(hr)) {
860     JmsgVssApiStatus(jcr_, M_FATAL, hr, "PrepareForBackup");
861     errno = b_errno_win32;
862     return false;
863   }
864 
865   /*
866    * Wait for the async operation to finish and checks the result.
867    */
868   if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
869     errno = b_errno_win32;
870     return false;
871   }
872 
873   /*
874    * Get latest info about writer status.
875    */
876   if (!CheckWriterStatus()) {
877     errno = b_errno_win32; /* Error already printed */
878     return false;
879   }
880 
881   /*
882    * DoSnapShotSet
883    */
884   hr = pVssObj->DoSnapshotSet(&pAsync2.p);
885   if (FAILED(hr)) {
886     JmsgVssApiStatus(jcr_, M_FATAL, hr, "DoSnapshotSet");
887     errno = b_errno_win32;
888     return false;
889   }
890 
891   /*
892    * Waits for the async operation to finish and checks the result.
893    */
894   if (!WaitAndCheckForAsyncOperation(pAsync2.p)) {
895     errno = b_errno_win32;
896     return false;
897   }
898 
899   /*
900    * Get latest info about writer status.
901    */
902   if (!CheckWriterStatus()) {
903     errno = b_errno_win32; /* Error already printed */
904     return false;
905   }
906 
907   /*
908    * Query snapshot info.
909    */
910   QuerySnapshotSet(uidCurrentSnapshotSet_);
911 
912   bBackupIsInitialized_ = true;
913 
914   return true;
915 }
916 
CloseBackup()917 bool VSSClientGeneric::CloseBackup()
918 {
919   bool bRet = false;
920   HRESULT hr;
921   BSTR xml;
922   IVssBackupComponents* pVssObj = (IVssBackupComponents*)pVssObject_;
923 
924   if (!pVssObject_) {
925     Jmsg(jcr_, M_FATAL, 0, "VssObject is NULL.\n");
926     errno = ENOSYS;
927     return bRet;
928   }
929   CComPtr<IVssAsync> pAsync;
930 
931   bBackupIsInitialized_ = false;
932 
933   hr = pVssObj->BackupComplete(&pAsync.p);
934   if (SUCCEEDED(hr)) {
935     /*
936      * Wait for the async operation to finish and checks the result.
937      */
938     WaitAndCheckForAsyncOperation(pAsync.p);
939     bRet = true;
940   } else {
941     JmsgVssApiStatus(jcr_, M_ERROR, hr, "BackupComplete");
942     errno = b_errno_win32;
943     pVssObj->AbortBackup();
944   }
945 
946   /*
947    * Get latest info about writer status.
948    */
949   CheckWriterStatus();
950 
951   hr = pVssObj->SaveAsXML(&xml);
952   if (SUCCEEDED(hr)) {
953     metadata_ = xml;
954   } else {
955     metadata_ = NULL;
956   }
957 
958   /*
959    * FIXME?: The docs
960    * http://msdn.microsoft.com/en-us/library/aa384582%28v=VS.85%29.aspx say this
961    * isn't required...
962    */
963   if (uidCurrentSnapshotSet_ != GUID_NULL) {
964     VSS_ID idNonDeletedSnapshotID = GUID_NULL;
965     LONG lSnapshots;
966 
967     pVssObj->DeleteSnapshots(uidCurrentSnapshotSet_, VSS_OBJECT_SNAPSHOT_SET,
968                              false, &lSnapshots, &idNonDeletedSnapshotID);
969 
970     uidCurrentSnapshotSet_ = GUID_NULL;
971   }
972 
973   if (bWriterStatusCurrent_) {
974     bWriterStatusCurrent_ = false;
975     pVssObj->FreeWriterStatus();
976   }
977 
978   pVssObj->Release();
979   pVssObject_ = NULL;
980 
981   /*
982    * Call CoUninitialize if the CoInitializeEx was performed sucesfully
983    */
984   if (bCoInitializeCalled_) {
985     CoUninitialize();
986     bCoInitializeCalled_ = false;
987   }
988 
989   return bRet;
990 }
991 
GetMetadata()992 wchar_t* VSSClientGeneric::GetMetadata() { return metadata_; }
993 
CloseRestore()994 bool VSSClientGeneric::CloseRestore()
995 {
996   IVssBackupComponents* pVssObj = (IVssBackupComponents*)pVssObject_;
997   CComPtr<IVssAsync> pAsync;
998 
999   if (!pVssObj) {
1000     errno = ENOSYS;
1001     return false;
1002   }
1003   return true;
1004 }
1005 
1006 /*
1007  * Query all the shadow copies in the given set
1008  */
QuerySnapshotSet(GUID snapshotSetID)1009 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
1010 {
1011   if (!(CreateVssBackupComponents_ && VssFreeSnapshotProperties_)) {
1012     Jmsg(jcr_, M_FATAL, 0,
1013          "CreateVssBackupComponents or VssFreeSnapshotProperties API is "
1014          "NULL.\n");
1015     errno = ENOSYS;
1016     return;
1017   }
1018 
1019   memset(szShadowCopyName_, 0, sizeof(szShadowCopyName_));
1020 
1021   if (snapshotSetID == GUID_NULL || pVssObject_ == NULL) {
1022     Jmsg(jcr_, M_FATAL, 0, "snapshotSetID == NULL or VssObject is NULL.\n");
1023     errno = ENOSYS;
1024     return;
1025   }
1026 
1027   IVssBackupComponents* pVssObj = (IVssBackupComponents*)pVssObject_;
1028 
1029   /*
1030    * Get list all shadow copies.
1031    */
1032   CComPtr<IVssEnumObject> pIEnumSnapshots;
1033   HRESULT hr = pVssObj->Query(GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT,
1034                               (IVssEnumObject**)(&pIEnumSnapshots));
1035 
1036   /*
1037    * If there are no shadow copies, just return
1038    */
1039   if (FAILED(hr)) {
1040     Jmsg(jcr_, M_FATAL, 0, "No Volume Shadow copies made.\n");
1041     errno = b_errno_win32;
1042     return;
1043   }
1044 
1045   /*
1046    * Enumerate all shadow copies.
1047    */
1048   VSS_OBJECT_PROP Prop;
1049   VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
1050 
1051   while (true) {
1052     /*
1053      * Get the next element
1054      */
1055     ULONG ulFetched;
1056     hr = (pIEnumSnapshots.p)->Next(1, &Prop, &ulFetched);
1057 
1058     /*
1059      * We reached the end of list
1060      */
1061     if (ulFetched == 0) break;
1062 
1063     /*
1064      * Print the shadow copy (if not filtered out)
1065      */
1066     if (Snap.m_SnapshotSetId == snapshotSetID) {
1067       for (int ch = 'A' - 'A'; ch <= 'Z' - 'A'; ch++) {
1068         if (wcscmp(Snap.m_pwszOriginalVolumeName, wszUniqueVolumeName_[ch]) ==
1069             0) {
1070           wcsncpy(szShadowCopyName_[ch], Snap.m_pwszSnapshotDeviceObject,
1071                   MAX_PATH - 1);
1072           break;
1073         }
1074       }
1075     }
1076     VssFreeSnapshotProperties_(&Snap);
1077   }
1078   errno = 0;
1079 }
1080 
1081 /*
1082  * Check the status for all selected writers
1083  */
CheckWriterStatus()1084 bool VSSClientGeneric::CheckWriterStatus()
1085 {
1086   /*
1087    * See
1088    * http://msdn.microsoft.com/en-us/library/windows/desktop/aa382870%28v=vs.85%29.aspx
1089    */
1090   IVssBackupComponents* pVssObj = (IVssBackupComponents*)pVssObject_;
1091   if (!pVssObj) {
1092     Jmsg(jcr_, M_FATAL, 0, "Cannot get IVssBackupComponents pointer.\n");
1093     errno = ENOSYS;
1094     return false;
1095   }
1096   DestroyWriterInfo();
1097 
1098   if (bWriterStatusCurrent_) {
1099     bWriterStatusCurrent_ = false;
1100     pVssObj->FreeWriterStatus();
1101   }
1102 
1103   /*
1104    * Gather writer status to detect potential errors
1105    */
1106   CComPtr<IVssAsync> pAsync;
1107 
1108   HRESULT hr = pVssObj->GatherWriterStatus(&pAsync.p);
1109   if (FAILED(hr)) {
1110     JmsgVssApiStatus(jcr_, M_FATAL, hr, "GatherWriterStatus");
1111     errno = b_errno_win32;
1112     return false;
1113   }
1114 
1115   /*
1116    * Waits for the async operation to finish and checks the result
1117    */
1118   if (!WaitAndCheckForAsyncOperation(pAsync.p)) {
1119     errno = b_errno_win32;
1120     return false;
1121   }
1122 
1123   bWriterStatusCurrent_ = true;
1124 
1125   unsigned cWriters = 0;
1126 
1127   hr = pVssObj->GetWriterStatusCount(&cWriters);
1128   if (FAILED(hr)) {
1129     JmsgVssApiStatus(jcr_, M_FATAL, hr, "GatherWriterStatusCount");
1130     errno = b_errno_win32;
1131     return false;
1132   }
1133 
1134   int nState;
1135   POOLMEM* szBuf = GetPoolMemory(PM_FNAME);
1136 
1137   /*
1138    * Enumerate each writer
1139    */
1140   for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
1141     VSS_ID idInstance = GUID_NULL;
1142     VSS_ID idWriter = GUID_NULL;
1143     VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
1144     CComBSTR bstrWriterName;
1145     HRESULT hrWriterFailure = S_OK;
1146 
1147     /*
1148      * Get writer status
1149      */
1150     hr = pVssObj->GetWriterStatus(iWriter, &idInstance, &idWriter,
1151                                   &bstrWriterName, &eWriterStatus,
1152                                   &hrWriterFailure);
1153     if (FAILED(hr)) {
1154       /*
1155        * Api failed
1156        */
1157       JmsgVssApiStatus(jcr_, M_WARNING, hr, "GetWriterStatus");
1158       nState = 0; /* Unknown writer state -- API failed */
1159     } else {
1160       switch (eWriterStatus) {
1161         case VSS_WS_FAILED_AT_IDENTIFY:
1162         case VSS_WS_FAILED_AT_PREPARE_BACKUP:
1163         case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
1164         case VSS_WS_FAILED_AT_FREEZE:
1165         case VSS_WS_FAILED_AT_THAW:
1166         case VSS_WS_FAILED_AT_POST_SNAPSHOT:
1167         case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
1168         case VSS_WS_FAILED_AT_PRE_RESTORE:
1169         case VSS_WS_FAILED_AT_POST_RESTORE:
1170 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
1171         case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
1172 #endif
1173           /*
1174            * Writer status problem
1175            */
1176           wchar_2_UTF8(szBuf, bstrWriterName.p);
1177           JmsgVssWriterStatus(jcr_, M_WARNING, eWriterStatus, szBuf);
1178           nState = -1; /* bad writer state */
1179           break;
1180         default:
1181           nState = 1; /* Writer state OK */
1182       }
1183     }
1184 
1185     /*
1186      * store text info
1187      */
1188     char str[1000];
1189     bstrncpy(str, "\"", sizeof(str));
1190     wchar_2_UTF8(szBuf, bstrWriterName.p);
1191     bstrncat(str, szBuf, sizeof(str));
1192     bstrncat(str, "\", State: 0x", sizeof(str));
1193     itoa(eWriterStatus, szBuf, SizeofPoolMemory(szBuf));
1194     bstrncat(str, szBuf, sizeof(str));
1195     bstrncat(str, " (", sizeof(str));
1196     wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus));
1197     bstrncat(str, szBuf, sizeof(str));
1198     bstrncat(str, ")", sizeof(str));
1199     AppendWriterInfo(nState, (const char*)str);
1200   }
1201 
1202   FreePoolMemory(szBuf);
1203   errno = 0;
1204 
1205   return true;
1206 }
1207 
1208 #endif /* WIN32_VSS */
1209