1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2005-2010 Free Software Foundation Europe e.V.
5    Copyright (C) 2014-2015 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 
37 #include "ms_atl.h"
38 #include <objbase.h>
39 
40 using namespace filedaemon;
41 
42 /*
43  * { b5946137-7b9f-4925-af80-51abd60b20d5 }
44  */
45 static const GUID VSS_SWPRV_ProviderID = {
46    0xb5946137, 0x7b9f, 0x4925, { 0xaf, 0x80, 0x51, 0xab, 0xd6, 0x0b, 0x20, 0xd5 }
47 };
48 
VSSPathConvert(const char * szFilePath,char * szShadowPath,int nBuflen)49 static bool VSSPathConvert(const char *szFilePath, char *szShadowPath, int nBuflen)
50 {
51    JobControlRecord *jcr = get_jcr_from_tsd();
52 
53    if (jcr && jcr->pVSSClient) {
54       return jcr->pVSSClient->GetShadowPath(szFilePath, szShadowPath, nBuflen);
55    }
56 
57    return false;
58 }
59 
VSSPathConvertW(const wchar_t * szFilePath,wchar_t * szShadowPath,int nBuflen)60 static bool VSSPathConvertW(const wchar_t *szFilePath, wchar_t *szShadowPath, int nBuflen)
61 {
62    JobControlRecord *jcr = get_jcr_from_tsd();
63 
64    if (jcr && jcr->pVSSClient) {
65       return jcr->pVSSClient->GetShadowPathW(szFilePath, szShadowPath, nBuflen);
66    }
67 
68    return false;
69 }
70 
VSSInit(JobControlRecord * jcr)71 void VSSInit(JobControlRecord *jcr)
72 {
73    /*
74     * Decide which vss class to initialize
75     */
76    if (g_MajorVersion == 5) {
77       switch (g_MinorVersion) {
78       case 1:
79          jcr->pVSSClient = new VSSClientXP();
80          break;
81       case 2:
82          jcr->pVSSClient = new VSSClient2003();
83          break;
84       }
85    /*
86     * Vista or Longhorn or later
87     */
88    } else if (g_MajorVersion >= 6) {
89       jcr->pVSSClient = new VSSClientVista();
90    }
91 
92    /*
93     * Setup the callback functions.
94     */
95    if (!SetVSSPathConvert(VSSPathConvert, VSSPathConvertW)) {
96       Jmsg(jcr, M_FATAL, 0, "Failed to setup VSS Path Conversion callbacks.\n");
97    }
98 }
99 
100 /*
101  * Constructor
102  */
VSSClient()103 VSSClient::VSSClient()
104 {
105     memset(this, 0, sizeof(VSSClient));
106     pAlistWriterState_ = New(alist(10, not_owned_by_alist));
107     pAlistWriterInfoText_ = New(alist(10, owned_by_alist));
108     uidCurrentSnapshotSet_ = GUID_NULL;
109 }
110 
111 /*
112  * Destructor
113  */
~VSSClient()114 VSSClient::~VSSClient()
115 {
116    /*
117     * Release the IVssBackupComponents interface
118     * WARNING: this must be done BEFORE calling CoUninitialize()
119     */
120    if (pVssObject_) {
121 //      pVssObject_->Release();
122       pVssObject_ = NULL;
123    }
124 
125    DestroyWriterInfo();
126    delete pAlistWriterState_;
127    delete pAlistWriterInfoText_;
128 
129    /*
130     * Call CoUninitialize if the CoInitialize was performed successfully
131     */
132    if (bCoInitializeCalled_) {
133       CoUninitialize();
134    }
135 }
136 
InitializeForBackup(JobControlRecord * jcr)137 bool VSSClient::InitializeForBackup(JobControlRecord *jcr)
138 {
139    jcr_ = jcr;
140 
141    GeneratePluginEvent(jcr, bEventVssInitializeForBackup);
142 
143    return Initialize(0);
144 }
145 
InitializeForRestore(JobControlRecord * jcr)146 bool VSSClient::InitializeForRestore(JobControlRecord *jcr)
147 {
148    metadata_ = NULL;
149    jcr_ = jcr;
150 
151    GeneratePluginEvent(jcr, bEventVssInitializeForRestore);
152 
153    return Initialize(0, true /*=>Restore*/);
154 }
155 
GetShadowPath(const char * szFilePath,char * szShadowPath,int nBuflen)156 bool VSSClient::GetShadowPath(const char *szFilePath, char *szShadowPath, int nBuflen)
157 {
158    if (!bBackupIsInitialized_)
159       return false;
160 
161    /*
162     * Check for valid pathname
163     */
164    bool bIsValidName;
165 
166    bIsValidName = strlen(szFilePath) > 3;
167    if (bIsValidName)
168       bIsValidName &= isalpha (szFilePath[0]) &&
169                       szFilePath[1]==':' &&
170                       szFilePath[2] == '\\';
171 
172    if (bIsValidName) {
173       int nDriveIndex = toupper(szFilePath[0])-'A';
174       if (szShadowCopyName_[nDriveIndex][0] != 0) {
175 
176          if (WideCharToMultiByte(CP_UTF8,0,szShadowCopyName_[nDriveIndex],-1,szShadowPath,nBuflen-1,NULL,NULL)) {
177             nBuflen -= (int)strlen(szShadowPath);
178             bstrncat(szShadowPath, szFilePath+2, nBuflen);
179             return true;
180          }
181       }
182    }
183 
184    bstrncpy(szShadowPath, szFilePath, nBuflen);
185    errno = EINVAL;
186    return false;
187 }
188 
GetShadowPathW(const wchar_t * szFilePath,wchar_t * szShadowPath,int nBuflen)189 bool VSSClient::GetShadowPathW(const wchar_t *szFilePath, wchar_t *szShadowPath, int nBuflen)
190 {
191    if (!bBackupIsInitialized_)
192       return false;
193 
194    /*
195     * Check for valid pathname
196     */
197    bool bIsValidName;
198 
199    bIsValidName = wcslen(szFilePath) > 3;
200    if (bIsValidName)
201       bIsValidName &= iswalpha (szFilePath[0]) &&
202                       szFilePath[1]==':' &&
203                       szFilePath[2] == '\\';
204 
205    if (bIsValidName) {
206       int nDriveIndex = towupper(szFilePath[0])-'A';
207       if (szShadowCopyName_[nDriveIndex][0] != 0) {
208          wcsncpy(szShadowPath, szShadowCopyName_[nDriveIndex], nBuflen);
209          nBuflen -= (int)wcslen(szShadowCopyName_[nDriveIndex]);
210          wcsncat(szShadowPath, szFilePath+2, nBuflen);
211          return true;
212       }
213    }
214 
215    wcsncpy(szShadowPath, szFilePath, nBuflen);
216    errno = EINVAL;
217    return false;
218 }
219 
GetWriterCount()220 const size_t VSSClient::GetWriterCount()
221 {
222    return pAlistWriterInfoText_->size();
223 }
224 
GetWriterInfo(int nIndex)225 const char* VSSClient::GetWriterInfo(int nIndex)
226 {
227    return (char*)pAlistWriterInfoText_->get(nIndex);
228 }
229 
GetWriterState(int nIndex)230 const int VSSClient::GetWriterState(int nIndex)
231 {
232    void *item = pAlistWriterState_->get(nIndex);
233 
234    /*
235     * Eliminate compiler warnings
236     */
237 #ifdef HAVE_VSS64
238    return (int64_t)(char *)item;
239 #else
240    return (int)(char *)item;
241 #endif
242 }
243 
AppendWriterInfo(int nState,const char * pszInfo)244 void VSSClient::AppendWriterInfo(int nState, const char* pszInfo)
245 {
246    pAlistWriterInfoText_->push(bstrdup(pszInfo));
247    pAlistWriterState_->push((void*)nState);
248 }
249 
250 /*
251  * Note, this is called at the end of every job, so release all
252  * the items in the alists, but do not delete the alist.
253  */
DestroyWriterInfo()254 void VSSClient::DestroyWriterInfo()
255 {
256    while (!pAlistWriterInfoText_->empty()) {
257       free(pAlistWriterInfoText_->pop());
258    }
259 
260    while (!pAlistWriterState_->empty()) {
261       pAlistWriterState_->pop();
262    }
263 }
264 #endif
265 
266