1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2005-2010 Free Software Foundation Europe e.V.
5    Copyright (C) 2014-2019 Bareos GmbH & Co. KG
6 
7    This program is Free Software; you can redistribute it and/or
8    modify it under the terms of version three of the GNU Affero General Public
9    License as published by the Free Software Foundation and included
10    in the file LICENSE.
11 
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15    Affero General Public License for more details.
16 
17    You should have received a copy of the GNU Affero General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301, USA.
21 */
22 /*
23  Copyright transferred from MATRIX-Computer GmbH to
24    Kern Sibbald by express permission.
25  Author          : Thorsten Engel
26  Created On      : Fri May 06 21:44:00 2005
27 */
28 /* @file
29  Interface to Volume Shadow Copies (VSS)
30 */
31 
32 #ifdef WIN32_VSS
33 
34 #  include "include/bareos.h"
35 #  include "filed/filed.h"
36 #  include "filed/jcr_private.h"
37 #  include "lib/thread_specific_data.h"
38 
39 #  include "ms_atl.h"
40 #  include <objbase.h>
41 
42 using namespace filedaemon;
43 
44 /*
45  * { b5946137-7b9f-4925-af80-51abd60b20d5 }
46  */
47 static const GUID VSS_SWPRV_ProviderID
48     = {0xb5946137,
49        0x7b9f,
50        0x4925,
51        {0xaf, 0x80, 0x51, 0xab, 0xd6, 0x0b, 0x20, 0xd5}};
52 
VSSPathConvert(const char * szFilePath,char * szShadowPath,int nBuflen)53 static bool VSSPathConvert(const char* szFilePath,
54                            char* szShadowPath,
55                            int nBuflen)
56 {
57   JobControlRecord* jcr = GetJcrFromThreadSpecificData();
58 
59   if (jcr && jcr->impl->pVSSClient) {
60     return jcr->impl->pVSSClient->GetShadowPath(szFilePath, szShadowPath,
61                                                 nBuflen);
62   }
63 
64   return false;
65 }
66 
VSSPathConvertW(const wchar_t * szFilePath,wchar_t * szShadowPath,int nBuflen)67 static bool VSSPathConvertW(const wchar_t* szFilePath,
68                             wchar_t* szShadowPath,
69                             int nBuflen)
70 {
71   JobControlRecord* jcr = GetJcrFromThreadSpecificData();
72 
73   if (jcr && jcr->impl->pVSSClient) {
74     return jcr->impl->pVSSClient->GetShadowPathW(szFilePath, szShadowPath,
75                                                  nBuflen);
76   }
77 
78   return false;
79 }
80 
VSSInit(JobControlRecord * jcr)81 void VSSInit(JobControlRecord* jcr)
82 {
83   /*
84    * Decide which vss class to initialize
85    */
86   if (g_MajorVersion == 5) {
87     switch (g_MinorVersion) {
88       case 1:
89         jcr->impl->pVSSClient = new VSSClientXP();
90         break;
91       case 2:
92         jcr->impl->pVSSClient = new VSSClient2003();
93         break;
94     }
95     /*
96      * Vista or Longhorn or later
97      */
98   } else if (g_MajorVersion >= 6) {
99     jcr->impl->pVSSClient = new VSSClientVista();
100   }
101 
102   /*
103    * Setup the callback functions.
104    */
105   if (!SetVSSPathConvert(VSSPathConvert, VSSPathConvertW)) {
106     Jmsg(jcr, M_FATAL, 0, "Failed to setup VSS Path Conversion callbacks.\n");
107   }
108 }
109 
110 /*
111  * Destructor
112  */
~VSSClient()113 VSSClient::~VSSClient()
114 {
115   /*
116    * Release the IVssBackupComponents interface
117    * WARNING: this must be done BEFORE calling CoUninitialize()
118    */
119   if (pVssObject_) {
120     //      pVssObject_->Release();
121     pVssObject_ = NULL;
122   }
123 
124   DestroyWriterInfo();
125 
126   /*
127    * Call CoUninitialize if the CoInitialize was performed successfully
128    */
129   if (bCoInitializeCalled_) { CoUninitialize(); }
130 }
131 
InitializeForBackup(JobControlRecord * jcr)132 bool VSSClient::InitializeForBackup(JobControlRecord* jcr)
133 {
134   jcr_ = jcr;
135 
136   GeneratePluginEvent(jcr, bEventVssInitializeForBackup);
137 
138   return Initialize(0);
139 }
140 
InitializeForRestore(JobControlRecord * jcr)141 bool VSSClient::InitializeForRestore(JobControlRecord* jcr)
142 {
143   metadata_ = NULL;
144   jcr_ = jcr;
145 
146   GeneratePluginEvent(jcr, bEventVssInitializeForRestore);
147 
148   return Initialize(0, true /*=>Restore*/);
149 }
150 
GetShadowPath(const char * szFilePath,char * szShadowPath,int nBuflen)151 bool VSSClient::GetShadowPath(const char* szFilePath,
152                               char* szShadowPath,
153                               int nBuflen)
154 {
155   if (!bBackupIsInitialized_) return false;
156 
157   /*
158    * Check for valid pathname
159    */
160   bool bIsValidName;
161 
162   bIsValidName = strlen(szFilePath) > 3;
163   if (bIsValidName)
164     bIsValidName &= isalpha(szFilePath[0]) && szFilePath[1] == ':'
165                     && szFilePath[2] == '\\';
166 
167   if (bIsValidName) {
168     int nDriveIndex = toupper(szFilePath[0]) - 'A';
169     if (szShadowCopyName_[nDriveIndex][0] != 0) {
170       if (WideCharToMultiByte(CP_UTF8, 0, szShadowCopyName_[nDriveIndex], -1,
171                               szShadowPath, nBuflen - 1, NULL, NULL)) {
172         nBuflen -= (int)strlen(szShadowPath);
173         bstrncat(szShadowPath, szFilePath + 2, nBuflen);
174         return true;
175       }
176     }
177   }
178 
179   bstrncpy(szShadowPath, szFilePath, nBuflen);
180   errno = EINVAL;
181   return false;
182 }
183 
GetShadowPathW(const wchar_t * szFilePath,wchar_t * szShadowPath,int nBuflen)184 bool VSSClient::GetShadowPathW(const wchar_t* szFilePath,
185                                wchar_t* szShadowPath,
186                                int nBuflen)
187 {
188   if (!bBackupIsInitialized_) return false;
189 
190   /*
191    * Check for valid pathname
192    */
193   bool bIsValidName;
194 
195   bIsValidName = wcslen(szFilePath) > 3;
196   if (bIsValidName)
197     bIsValidName &= iswalpha(szFilePath[0]) && szFilePath[1] == ':'
198                     && szFilePath[2] == '\\';
199 
200   if (bIsValidName) {
201     int nDriveIndex = towupper(szFilePath[0]) - 'A';
202     if (szShadowCopyName_[nDriveIndex][0] != 0) {
203       wcsncpy(szShadowPath, szShadowCopyName_[nDriveIndex], nBuflen);
204       nBuflen -= (int)wcslen(szShadowCopyName_[nDriveIndex]);
205       wcsncat(szShadowPath, szFilePath + 2, nBuflen);
206       return true;
207     }
208   }
209 
210   wcsncpy(szShadowPath, szFilePath, nBuflen);
211   errno = EINVAL;
212   return false;
213 }
214 
GetWriterCount() const215 size_t VSSClient::GetWriterCount() const { return writer_info_.size(); }
216 
GetWriterInfo(size_t nIndex) const217 const char* VSSClient::GetWriterInfo(size_t nIndex) const
218 {
219   if (nIndex < writer_info_.size()) {
220     return writer_info_[nIndex].info_text_.c_str();
221   }
222   return nullptr;
223 }
224 
GetWriterState(size_t nIndex) const225 int VSSClient::GetWriterState(size_t nIndex) const
226 {
227   if (nIndex < writer_info_.size()) { return writer_info_[nIndex].state_; }
228   return 0;
229 }
230 
AppendWriterInfo(int nState,const char * pszInfo)231 void VSSClient::AppendWriterInfo(int nState, const char* pszInfo)
232 {
233   WriterInfo info;
234   info.state_ = nState;
235   info.info_text_ = pszInfo;
236   writer_info_.push_back(info);
237 }
238 
239 /*
240  * Note, this is called at the end of every job, so release all items
241  */
DestroyWriterInfo()242 void VSSClient::DestroyWriterInfo() { writer_info_.clear(); }
243 #endif
244