1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2018 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Written by James Harper, October 2008
21 */
22
23 #include "exchange-fd.h"
24
storage_group_node_t(char * name,node_t * parent_node)25 storage_group_node_t::storage_group_node_t(char *name, node_t *parent_node) : node_t(name, NODE_TYPE_STORAGE_GROUP, parent_node)
26 {
27 ibi = NULL;
28 store_node = NULL;
29 current_dbi = 0;
30 restore_environment = NULL;
31 saved_log_path = NULL;
32 next = NULL;
33 }
34
~storage_group_node_t()35 storage_group_node_t::~storage_group_node_t()
36 {
37 /*
38 if (dbi_node != NULL)
39 delete dbi_node;
40
41 if (file_node != NULL)
42 delete file_node;
43 */
44 }
45
46 bRC
startBackupFile(exchange_fd_context_t * context,struct save_pkt * sp)47 storage_group_node_t::startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp)
48 {
49 HRESULT result;
50 int len;
51 WCHAR *tmp_logfiles, *tmp_logfile_ptr;
52 char *tmp;
53
54 for(;;)
55 {
56 _DebugMessage(100, "startBackupNode_STORAGE_GROUP state = %d, name = %s\n", state, name);
57 switch(state)
58 {
59 case 0:
60 current_dbi = 0;
61 store_node = NULL;
62 logfile_ptr = NULL;
63 if (context->job_level == 'F')
64 {
65 _DebugMessage(100, "Calling HrESEBackupSetup (BACKUP_TYPE_FULL)\n");
66 result = HrESEBackupSetup(hccx, ibi->hInstanceId, BACKUP_TYPE_FULL);
67 state = 1;
68 }
69 else
70 {
71 _DebugMessage(100, "Calling HrESEBackupSetup (BACKUP_TYPE_LOGS_ONLY)\n");
72 result = HrESEBackupSetup(hccx, ibi->hInstanceId, BACKUP_TYPE_LOGS_ONLY);
73 if (context->accurate)
74 state = 1;
75 else
76 state = 2;
77 }
78 if (result != 0)
79 {
80 _JobMessage(M_FATAL, "HrESEBackupSetup failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
81 state = 999;
82 return bRC_Error;
83 }
84 break;
85 case 1:
86 if (context->path_bits[level + 1] == NULL)
87 {
88 _DebugMessage(100, "No specific database specified - backing them all up\n");
89 DATABASE_BACKUP_INFO *dbi = &ibi->rgDatabase[current_dbi];
90 char *tmp = new char[wcslen(dbi->wszDatabaseDisplayName) + 1];
91 wcstombs(tmp, dbi->wszDatabaseDisplayName, wcslen(dbi->wszDatabaseDisplayName) + 1);
92 store_node = new store_node_t(tmp, this);
93 store_node->dbi = dbi;
94 store_node->hccx = hccx;
95 context->current_node = store_node;
96 }
97 else
98 {
99 DATABASE_BACKUP_INFO *dbi = NULL;
100 char *tmp = NULL;
101 for (current_dbi = 0; current_dbi < ibi->cDatabase; current_dbi++)
102 {
103 dbi = &ibi->rgDatabase[current_dbi];
104 char *tmp = new char[wcslen(dbi->wszDatabaseDisplayName) + 1];
105 wcstombs(tmp, dbi->wszDatabaseDisplayName, wcslen(dbi->wszDatabaseDisplayName) + 1);
106 if (stricmp(tmp, context->path_bits[level + 1]) == 0)
107 break;
108 delete tmp;
109 }
110 if (current_dbi == ibi->cDatabase)
111 {
112 _JobMessage(M_FATAL, "Invalid Database '%s'\n", context->path_bits[level + 1]);
113 return bRC_Error;
114 }
115 store_node = new store_node_t(tmp, this);
116 _DebugMessage(100, "Database name = %s\n", store_node->name);
117 delete tmp;
118 store_node->hccx = hccx;
119 store_node->dbi = dbi;
120 context->current_node = store_node;
121 }
122 return bRC_OK;
123 case 2:
124 _DebugMessage(100, "Calling HrESEBackupGetLogAndPatchFiles\n");
125 result = HrESEBackupGetLogAndPatchFiles(hccx, &tmp_logfiles);
126 if (result != 0)
127 {
128 _JobMessage(M_FATAL, "HrESEBackupGetLogAndPatchFiles failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
129 return bRC_Error;
130 }
131 for (len = 0, tmp_logfile_ptr = tmp_logfiles; *tmp_logfile_ptr != 0; tmp_logfile_ptr += wcslen(tmp_logfile_ptr) + 1)
132 {
133 len += wcslen(tmp_logfile_ptr) + 1;
134 }
135 logfiles = new WCHAR[len + 1];
136 logfile_ptr = logfiles;
137 for (tmp_logfile_ptr = tmp_logfiles; *tmp_logfile_ptr != 0; tmp_logfile_ptr += wcslen(tmp_logfile_ptr) + 1)
138 {
139 // check file modification date
140 HANDLE handle;
141 FILETIME modified_time;
142 //int64_t tmp_time;
143 __int64 tmp_time;
144 bool include_file;
145 include_file = false;
146 handle = INVALID_HANDLE_VALUE;
147 if (context->job_since == 0)
148 include_file = true;
149 if (!include_file)
150 {
151 handle = CreateFileW(tmp_logfile_ptr, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
152 if (handle == INVALID_HANDLE_VALUE)
153 {
154 //_JobMessage(M_WARNING, "Could not open '%S' to check last modified date (0x%08x), including anyway\n", tmp_logfile_ptr, GetLastError());
155 include_file = true;
156 }
157 }
158 if (!include_file)
159 {
160 if (GetFileTime(handle, NULL, NULL, &modified_time) == 0)
161 {
162 //_JobMessage(M_WARNING, "Could not check last modified date for '%S' (0x%08x), including anyway\n", tmp_logfile_ptr, GetLastError());
163 include_file = true;
164 }
165 }
166 if (!include_file)
167 {
168 tmp_time = (((int64_t)modified_time.dwHighDateTime) << 32) | modified_time.dwLowDateTime;
169 tmp_time -= 116444736000000000LL;
170 tmp_time /= 10000000;
171 if (tmp_time > context->job_since)
172 {
173 include_file = true;
174 }
175 }
176 if (include_file)
177 {
178 memcpy(logfile_ptr, tmp_logfile_ptr, (wcslen(tmp_logfile_ptr) + 1) * 2);
179 logfile_ptr += wcslen(logfile_ptr) + 1;
180 //_DebugMessage(100, "Including file %S\n", logfile_ptr);
181 }
182 #if 0
183 /* this is handled via checkFile now */
184 else
185 {
186 if (context->accurate) {
187 tmp = new char[strlen(full_path) + wcslen(tmp_logfile_ptr) + 1];
188 strcpy(tmp, full_path);
189 wcstombs(tmp + strlen(full_path), tmp_logfile_ptr, wcslen(tmp_logfile_ptr) + 1);
190 bfuncs->setBaculaValue(context->bpContext, bVarFileSeen, (void *)tmp);
191 delete tmp;
192 }
193 }
194 #endif
195
196 if (handle != INVALID_HANDLE_VALUE)
197 CloseHandle(handle);
198
199 }
200 *logfile_ptr = 0;
201 logfile_ptr = logfiles;
202 state = 3;
203 break;
204 case 3:
205 tmp = new char[wcslen(logfile_ptr) + 1];
206 wcstombs(tmp, logfile_ptr, wcslen(logfile_ptr) + 1);
207 file_node = new file_node_t(tmp, this);
208 delete tmp;
209 file_node->hccx = hccx;
210 file_node->filename = logfile_ptr;
211 context->current_node = file_node;
212 return bRC_OK;
213 case 4:
214 time_t now = time(NULL);
215 sp->fname = full_path;
216 sp->link = full_path;
217 _DebugMessage(100, "fname = %s\n", sp->fname);
218 sp->statp.st_mode = 0700 | S_IFDIR;
219 sp->statp.st_ctime = now;
220 sp->statp.st_mtime = now;
221 sp->statp.st_atime = now;
222 sp->statp.st_size = 0;
223 //sp->statp.st_blocks = 0;
224 sp->type = FT_DIREND;
225 return bRC_OK;
226 }
227 }
228 }
229
230 bRC
endBackupFile(exchange_fd_context_t * context)231 storage_group_node_t::endBackupFile(exchange_fd_context_t *context)
232 {
233 HRESULT result;
234 bRC retval = bRC_Error;
235
236 _DebugMessage(100, "endBackupNode_STORAGE_GROUP state = %d\n", state);
237
238 switch(state)
239 {
240 case 0:
241 // should never happen
242 break;
243 case 1:
244 // free node->storage_group_node
245 if (context->path_bits[level + 1] == NULL)
246 {
247 current_dbi++;
248 if (current_dbi == ibi->cDatabase)
249 state = 2;
250 }
251 else
252 state = 2;
253 retval = bRC_More;
254 break;
255 case 2:
256 // should never happen
257 break;
258 case 3:
259 delete file_node;
260 logfile_ptr += wcslen(logfile_ptr) + 1;
261 if (*logfile_ptr == 0)
262 state = 4;
263 retval = bRC_More;
264 break;
265 case 4:
266 if (context->truncate_logs)
267 {
268 _DebugMessage(100, "Calling HrESEBackupTruncateLogs\n");
269 result = HrESEBackupTruncateLogs(hccx);
270 if (result != 0)
271 {
272 _JobMessage(M_FATAL, "HrESEBackupTruncateLogs failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
273 }
274 else
275 {
276 _JobMessage(M_INFO, "Truncated database logs for Storage Group %s\n", name);
277 }
278 }
279 else
280 {
281 _JobMessage(M_INFO, "Did NOT truncate database logs for Storage Group %s\n", name);
282 }
283 _DebugMessage(100, "Calling HrESEBackupInstanceEnd\n");
284 result = HrESEBackupInstanceEnd(hccx, ESE_BACKUP_INSTANCE_END_SUCCESS);
285 if (result != 0)
286 {
287 _JobMessage(M_FATAL, "HrESEBackupInstanceEnd failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
288 return bRC_Error;
289 }
290 retval = bRC_OK;
291 context->current_node = parent;
292 break;
293 }
294 return retval;
295 }
296
297 bRC
createFile(exchange_fd_context_t * context,struct restore_pkt * rp)298 storage_group_node_t::createFile(exchange_fd_context_t *context, struct restore_pkt *rp)
299 {
300 HRESULT result;
301 int len;
302
303 _DebugMessage(100, "createFile_STORAGE_GROUP state = %d\n", state);
304
305 if (strcmp(context->path_bits[level], name) != 0)
306 {
307 _DebugMessage(100, "Different storage group - switching back to parent\n", state);
308 saved_log_path = new WCHAR[wcslen(restore_environment->m_wszRestoreLogPath) + 1];
309 wcscpy(saved_log_path, restore_environment->m_wszRestoreLogPath);
310 _DebugMessage(100, "Calling HrESERestoreSaveEnvironment\n");
311 result = HrESERestoreSaveEnvironment(hccx);
312 if (result != 0)
313 {
314 _JobMessage(M_FATAL, "HrESERestoreSaveEnvironment failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
315 state = 999;
316 rp->create_status = CF_CREATED;
317 return bRC_OK;
318 }
319 _DebugMessage(100, "Calling HrESERestoreClose\n");
320 result = HrESERestoreClose(hccx, RESTORE_CLOSE_NORMAL);
321 if (result != 0)
322 {
323 _JobMessage(M_FATAL, "HrESERestoreClose failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
324 state = 999;
325 rp->create_status = CF_CREATED;
326 return bRC_OK;
327 }
328 context->current_node = parent;
329 return bRC_OK;
330 }
331 if (saved_log_path != NULL)
332 {
333 _DebugMessage(100, "Calling HrESERestoreReopen\n");
334 result = HrESERestoreReopen(context->computer_name, service_name, saved_log_path, &hccx);
335 if (result != 0)
336 {
337 _JobMessage(M_FATAL, "HrESERestoreReopen failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
338 state = 999;
339 saved_log_path = NULL;
340 rp->create_status = CF_CREATED;
341 return bRC_OK;
342 }
343 _DebugMessage(100, "Calling HrESERestoreGetEnvironment\n");
344 result = HrESERestoreGetEnvironment(hccx, &restore_environment);
345 if (result != 0)
346 {
347 _JobMessage(M_FATAL, "HrESERestoreGetEnvironment failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
348 state = 999;
349 saved_log_path = NULL;
350 rp->create_status = CF_CREATED;
351 return bRC_OK;
352 }
353 saved_log_path = NULL;
354 }
355
356 for (;;)
357 {
358 switch (state)
359 {
360 case 0:
361 if (context->path_bits[level + 2] == NULL)
362 {
363 _JobMessage(M_ERROR, "Unexpected log file '%s%s' - expecting database\n", full_path, context->path_bits[level + 1]);
364 state = 999;
365 break;
366 }
367 service_name = new WCHAR[strlen(parent->name) + 1];
368 storage_group_name = new WCHAR[strlen(name) + 1];
369 mbstowcs(service_name, parent->name, strlen(parent->name) + 1);
370 mbstowcs(storage_group_name, name, strlen(name) + 1);
371 _DebugMessage(100, "Calling HrESERestoreOpen\n");
372 result = HrESERestoreOpen(context->computer_name, service_name, storage_group_name, NULL, &hccx);
373 if (result != 0)
374 {
375 _JobMessage(M_FATAL, "HrESERestoreOpen failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
376 state = 999;
377 break;
378 }
379 _DebugMessage(100, "Calling HrESERestoreGetEnvironment\n");
380 result = HrESERestoreGetEnvironment(hccx, &restore_environment);
381 if (result != 0)
382 {
383 _JobMessage(M_FATAL, "HrESERestoreGetEnvironment failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
384 state = 999;
385 break;
386 }
387 state = 1;
388 break;
389 case 1:
390 if (context->path_bits[level + 2] == NULL)
391 {
392 state = 2;
393 break;
394 }
395 store_node = new store_node_t(bstrdup(context->path_bits[level + 1]), this);
396 store_node->hccx = hccx;
397 context->current_node = store_node;
398 return bRC_OK;
399 case 2:
400 if (context->path_bits[level + 2] != NULL)
401 {
402 _JobMessage(M_ERROR, "Unexpected file '%s'\n", full_path);
403 state = 999;
404 break;
405 }
406 if (context->path_bits[level + 1] == NULL)
407 {
408 state = 3;
409 break;
410 }
411 state = 2;
412 file_node = new file_node_t(bstrdup(context->path_bits[level + 1]), this);
413 file_node->hccx = hccx;
414 int i;
415 for (i = strlen(file_node->name) - 1; i >= 0; i--)
416 {
417 if (file_node->name[i] == '\\')
418 {
419 i++;
420 break;
421 }
422 }
423 len = wcslen(restore_environment->m_wszRestoreLogPath) + strlen(file_node->name + i) + 1 + 1;
424 file_node->filename = new WCHAR[len];
425 wcscpy(file_node->filename, restore_environment->m_wszRestoreLogPath);
426 wcscat(file_node->filename, L"\\");
427 mbstowcs(&file_node->filename[wcslen(file_node->filename)], file_node->name + i, strlen(file_node->name + i) + 1);
428 context->current_node = file_node;
429 return bRC_OK;
430 case 3:
431 if (rp->type != FT_DIREND)
432 {
433 _JobMessage(M_ERROR, "Unexpected file '%s'\n", full_path);
434 state = 999;
435 break;
436 }
437 // must be the storage group node
438 _DebugMessage(100, "Calling HrESERestoreSaveEnvironment\n");
439 result = HrESERestoreSaveEnvironment(hccx);
440 if (result != 0)
441 {
442 _JobMessage(M_FATAL, "HrESERestoreSaveEnvironment failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
443 state = 999;
444 break;
445 }
446
447 _DebugMessage(100, "Calling HrESERestoreComplete\n");
448 result = HrESERestoreComplete(hccx, restore_environment->m_wszRestoreLogPath,
449 restore_environment->m_wszRestoreLogPath, storage_group_name, ESE_RESTORE_COMPLETE_ATTACH_DBS);
450 if (result != 0)
451 {
452 _JobMessage(M_FATAL, "HrESERestoreComplete failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
453 _DebugMessage(100, "Calling HrESERestoreClose\n");
454 result = HrESERestoreClose(hccx, RESTORE_CLOSE_NORMAL);
455 state = 999;
456 break;
457 }
458 else
459 {
460 _JobMessage(M_INFO, "Storage Group '%s' restored successfully\n", name);
461 }
462
463 _DebugMessage(100, "Calling HrESERestoreClose\n");
464 result = HrESERestoreClose(hccx, RESTORE_CLOSE_NORMAL);
465 if (result != 0)
466 {
467 _JobMessage(M_FATAL, "HrESERestoreClose failed with error 0x%08x - %s\n", result, ESEErrorMessage(result));
468 state = 999;
469 break;
470 }
471
472 rp->create_status = CF_CREATED;
473 return bRC_OK;
474 case 999:
475 rp->create_status = CF_CREATED;
476 return bRC_OK;
477 }
478 }
479 }
480
481 bRC
endRestoreFile(exchange_fd_context_t * context)482 storage_group_node_t::endRestoreFile(exchange_fd_context_t *context)
483 {
484 _DebugMessage(100, "endRestoreFile_STORAGE_GROUP state = %d\n", state);
485 switch (state)
486 {
487 case 0:
488 return bRC_Error;
489 case 1:
490 return bRC_OK;
491 case 2:
492 return bRC_OK;
493 case 3:
494 context->current_node = parent;
495 return bRC_OK;
496 case 999:
497 context->current_node = parent;
498 return bRC_OK;
499 }
500
501 return bRC_Error;
502 }
503