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