From: Kern Sibbald Date: Thu, 23 Oct 2008 13:28:05 +0000 (+0000) Subject: Integrate James Harper's Exchange Win32 plugin patch. X-Git-Tag: Release-3.0.0~721 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=e486ad2ee0f43f7afbb20034d28753dc952920be;p=bacula%2Fbacula Integrate James Harper's Exchange Win32 plugin patch. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@7880 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/win32/Makefile b/bacula/src/win32/Makefile index 4fd6cd1fe3..0a45c275a9 100644 --- a/bacula/src/win32/Makefile +++ b/bacula/src/win32/Makefile @@ -3,6 +3,7 @@ c+ECHO_CMD=@ DIRS= dll \ cats \ filed \ + filed/plugins \ dird \ stored \ console \ diff --git a/bacula/src/win32/filed/plugins/Makefile b/bacula/src/win32/filed/plugins/Makefile new file mode 100644 index 0000000000..cdf84c5e8b --- /dev/null +++ b/bacula/src/win32/filed/plugins/Makefile @@ -0,0 +1,93 @@ +# +# Makefile for win32 bacula executables +# Using MinGW cross-compiler on GNU/Linux +# +# Written by James Harper, October 2008 +# Patterned after a Makefile by Robert Nelson, June 2006 +# + +include ../../Makefile.inc + +INCLUDES = \ + $(INCLUDE_PTHREADS) \ + $(INCLUDE_BACULA) \ + $(INCLUDE_ZLIB) \ + $(INCLUDE_OPENSSL) \ + -I$(MAINDIR)/src \ + -I$(MAINDIR)/src/filed + +DEFINES = \ + $(HAVES) + +#vpath %.c $(BUILDDIR)/compat $(MAINDIR)/src/findlib $(MAINDIR)/src/lib +#vpath %.cpp $(BUILDDIR)/compat $(MAINDIR)/src/findlib $(MAINDIR)/src/lib + +###################################################################### + +# Files files in src/win32/filed/plugins + +EXCHANGE_OBJS = \ + $(OBJDIR)/exchange-fd.o \ + $(OBJDIR)/api.o \ + $(OBJDIR)/node.o \ + $(OBJDIR)/root_node.o \ + $(OBJDIR)/service_node.o \ + $(OBJDIR)/storage_group_node.o \ + $(OBJDIR)/store_node.o \ + $(OBJDIR)/dbi_node.o \ + $(OBJDIR)/file_node.o + +LIBS_DLL = \ + $(LIBS_SSL) \ + $(LIBS_CRYPTO) \ + $(LIBS_PTHREADS) \ + $(LIBS_ZLIB) \ + -lwsock32 \ + -lole32 \ + -loleaut32 \ + -luuid + +###################################################################### + +# Targets + +.PHONY: all clean + +all: $(BINDIR)/exchange-fd.dll + +clean: + @echo "Cleaning `pwd`" + $(call clean_obj,$(EXCHANGE_OBJS)) + $(call clean_exe,$(BINDIR)/exchange-fd.dll) + $(ECHO_CMD)rm -f $(OBJDIR)/exchange-fd.a $(LIBDIR)/libexchange-fd.a + +# +# Rules for generating from ../lib +# + +#$(LIBDIR)/libexchange-fd.a: DLL_DEFINE=USING_DLL + +#$(LIBDIR)/libexchange-fd.a: $(BINDIR)/exchange-fd.dll $(STATIC_OBJS) +# @echo "Updating archive $@" +# $(call checkdir,$@) +# $(ECHO_CMD)cp $(OBJDIR)/exchange-fd.a $@ +# $(ECHO_CMD)$(AR) rsv $@ $(filter %.o,$^) + +$(BINDIR)/exchange-fd.dll: DLL_DEFINE=BUILDING_DLL + +$(BINDIR)/exchange-fd.dll: $(EXCHANGE_OBJS) exchange-fd.def + @echo "Linking $@" + $(call checkdir,$@) + $(ECHO_CMD)$(CXX) $(LDFLAGS) -mdll -mwindows -Wl,--out-implib,$(OBJDIR)/exchange-fd.a $^ $(LIBS_DLL) -o $@ + +include ../../Makefile.rules + +$(OBJDIR)/%.o: %.c + @echo "Compiling $<" + $(call checkdir,$@) + $(ECHO_CMD)$(CXX) -D$(DLL_DEFINE) $(CFLAGS) -c $< -o $@ + +$(OBJDIR)/%.o: %.cpp + @echo "Compiling $<" + $(call checkdir,$@) + $(ECHO_CMD)$(CXX) -D$(DLL_DEFINE) $(CFLAGS) -c $< -o $@ diff --git a/bacula/src/win32/filed/plugins/api.c b/bacula/src/win32/filed/plugins/api.c new file mode 100644 index 0000000000..7d06cc8765 --- /dev/null +++ b/bacula/src/win32/filed/plugins/api.c @@ -0,0 +1,142 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +#include "exchange-fd.h" + +HrESEBackupRestoreGetNodes_t HrESEBackupRestoreGetNodes; +HrESEBackupPrepare_t HrESEBackupPrepare; +HrESEBackupGetLogAndPatchFiles_t HrESEBackupGetLogAndPatchFiles; +HrESEBackupTruncateLogs_t HrESEBackupTruncateLogs; +HrESEBackupEnd_t HrESEBackupEnd; +HrESEBackupSetup_t HrESEBackupSetup; +HrESEBackupInstanceEnd_t HrESEBackupInstanceEnd; +HrESEBackupOpenFile_t HrESEBackupOpenFile; +HrESEBackupReadFile_t HrESEBackupReadFile; +HrESEBackupCloseFile_t HrESEBackupCloseFile; + +HrESERestoreOpen_t HrESERestoreOpen; +HrESERestoreReopen_t HrESERestoreReopen; +HrESERestoreComplete_t HrESERestoreComplete; +HrESERestoreClose_t HrESERestoreClose; +HrESERestoreGetEnvironment_t HrESERestoreGetEnvironment; +HrESERestoreSaveEnvironment_t HrESERestoreSaveEnvironment; +HrESERestoreAddDatabase_t HrESERestoreAddDatabase; +HrESERestoreOpenFile_t HrESERestoreOpenFile; + +bRC +loadExchangeApi() +{ + HMODULE h; + LONG status; + HKEY key_handle; + WCHAR *buf; + DWORD buf_len; + DWORD type; + + status = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\BackupRestore\\DLLPaths", &key_handle); + if (status != ERROR_SUCCESS) + { + _JobMessageNull(M_ERROR, "Cannot get key for Exchange DLL path, result = %08x\n", status); + return bRC_Error; + } + + type = REG_EXPAND_SZ; + status = RegQueryValueExW(key_handle, L"esebcli2", NULL, &type, NULL, &buf_len); + if (status != ERROR_SUCCESS) + { + _JobMessageNull(M_ERROR, "Cannot get key for Exchange DLL path, result = %08x\n", status); + return bRC_Error; + } + buf_len += 2; + buf = new WCHAR[buf_len]; + + type = REG_EXPAND_SZ; + status = RegQueryValueExW(key_handle, L"esebcli2", NULL, &type, (LPBYTE)buf, &buf_len); + if (status != ERROR_SUCCESS) + { + _JobMessageNull(M_ERROR, "Cannot get key for Exchange DLL path, result = %08x\n", status); + delete buf; + return bRC_Error; + } + +printf("Got value %S\n", buf); + + // strictly speaking, a REG_EXPAND_SZ should be run through ExpandEnvironmentStrings + + h = LoadLibraryW(buf); + delete buf; + if (!h) { + return bRC_Error; + } + HrESEBackupRestoreGetNodes = (HrESEBackupRestoreGetNodes_t)GetProcAddress(h, "HrESEBackupRestoreGetNodes"); + HrESEBackupPrepare = (HrESEBackupPrepare_t)GetProcAddress(h, "HrESEBackupPrepare"); + HrESEBackupEnd = (HrESEBackupEnd_t)GetProcAddress(h, "HrESEBackupEnd"); + HrESEBackupSetup = (HrESEBackupSetup_t)GetProcAddress(h, "HrESEBackupSetup"); + HrESEBackupGetLogAndPatchFiles = (HrESEBackupGetLogAndPatchFiles_t)GetProcAddress(h, "HrESEBackupGetLogAndPatchFiles"); + HrESEBackupTruncateLogs = (HrESEBackupTruncateLogs_t)GetProcAddress(h, "HrESEBackupTruncateLogs"); + HrESEBackupInstanceEnd = (HrESEBackupInstanceEnd_t)GetProcAddress(h, "HrESEBackupInstanceEnd"); + HrESEBackupOpenFile = (HrESEBackupOpenFile_t)GetProcAddress(h, "HrESEBackupOpenFile"); + HrESEBackupReadFile = (HrESEBackupReadFile_t)GetProcAddress(h, "HrESEBackupReadFile"); + HrESEBackupCloseFile = (HrESEBackupCloseFile_t)GetProcAddress(h, "HrESEBackupCloseFile"); + HrESERestoreOpen = (HrESERestoreOpen_t)GetProcAddress(h, "HrESERestoreOpen"); + HrESERestoreReopen = (HrESERestoreReopen_t)GetProcAddress(h, "HrESERestoreReopen"); + HrESERestoreComplete = (HrESERestoreComplete_t)GetProcAddress(h, "HrESERestoreComplete"); + HrESERestoreClose = (HrESERestoreClose_t)GetProcAddress(h, "HrESERestoreClose"); + HrESERestoreSaveEnvironment = (HrESERestoreSaveEnvironment_t)GetProcAddress(h, "HrESERestoreSaveEnvironment"); + HrESERestoreGetEnvironment = (HrESERestoreGetEnvironment_t)GetProcAddress(h, "HrESERestoreGetEnvironment"); + HrESERestoreAddDatabase = (HrESERestoreAddDatabase_t)GetProcAddress(h, "HrESERestoreAddDatabase"); + HrESERestoreOpenFile = (HrESERestoreOpenFile_t)GetProcAddress(h, "HrESERestoreOpenFile"); + return bRC_OK; +} + +char * +ESEErrorMessage(HRESULT result) +{ + switch (result) + { + case 0: + return "No error."; + case hrLogfileHasBadSignature: + return "Log file has bad signature. Check that no stale files are left in the Exchange data/log directories."; + case hrCBDatabaseInUse: + return "Database in use. Make sure database is dismounted."; + case hrRestoreAtFileLevel: + return "File must be restored using Windows file I/O calls."; + case hrMissingFullBackup: + return "Exchange reports that no previous full backup has been done."; + case hrBackupInProgress: + return "Exchange backup already in progress."; + case hrLogfileNotContiguous: + return "Existing log file is not contiguous. Check that no stale files are left in the Exchange data/log directories."; + default: + return "Unknown error."; + } +} diff --git a/bacula/src/win32/filed/plugins/api.h b/bacula/src/win32/filed/plugins/api.h new file mode 100644 index 0000000000..a5934fdb1f --- /dev/null +++ b/bacula/src/win32/filed/plugins/api.h @@ -0,0 +1,281 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +//#include + +extern "C" { + +#define BACKUP_NODE_TYPE_MACHINE 0x001 +#define BACKUP_NODE_TYPE_ANNOTATION 0x010 +#define BACKUP_NODE_TYPE_DISPLAY 0x100 + +#define ESE_BACKUP_INSTANCE_END_ERROR 0x0 +#define ESE_BACKUP_INSTANCE_END_SUCCESS 0x1 + +#define BACKUP_TYPE_FULL 0x1 +#define BACKUP_TYPE_LOGS_ONLY 0x2 +#define BACKUP_TYPE_FULL_WITH_ALL_LOGS 0x3 + +#define RESTORE_CLOSE_ABORT 0x1 +#define RESTORE_CLOSE_NORMAL 0x0 + +#define ESE_RESTORE_COMPLETE_NOWAIT 0x00010000 +#define ESE_RESTORE_COMPLETE_ATTACH_DBS 0x00000001 +#define ESE_RESTORE_KEEP_LOG_FILES 0x00020000 + +//#include + +struct ESE_ICON_DESCRIPTION { + uint32_t ulSize; + char *pvData; +}; + +struct BACKUP_NODE_TREE { + WCHAR *wszName; + uint32_t fFlags; + ESE_ICON_DESCRIPTION iconDescription; + struct BACKUP_NODE_TREE *pNextNode; + struct BACKUP_NODE_TREE *pChildNode; +}; + +struct DATABASE_BACKUP_INFO { + WCHAR *wszDatabaseDisplayName; + uint32_t cwDatabaseStreams; + WCHAR *wszDatabaseStreams; + GUID rguidDatabase; + uint32_t *rgIconIndexDatabase; + uint32_t fDatabaseFlags; +}; + +struct INSTANCE_BACKUP_INFO { + uint64_t hInstanceId; + //RPC_STRING wszInstanceName; + WCHAR *wszInstanceName; + uint32_t ulIconIndexInstance; + uint32_t cDatabase; + DATABASE_BACKUP_INFO *rgDatabase; + uint32_t cIconDescription; + ESE_ICON_DESCRIPTION *rgIconDescription; +}; + +enum RECOVER_STATUS { + recoverInvalid = 0, + recoverNotStarted = 1, + recoverStarted = 2, + recoverEnded = 3, + recoverStatusMax +}; + +struct RESTORE_ENVIRONMENT { + WCHAR * m_wszRestoreLogPath; + WCHAR * m_wszSrcInstanceName; + uint32_t m_cDatabases; + WCHAR **m_wszDatabaseDisplayName; + GUID * m_rguidDatabase; + WCHAR * m_wszRestoreInstanceSystemPath; + WCHAR * m_wszRestoreInstanceLogPath; + WCHAR * m_wszTargetInstanceName; + WCHAR ** m_wszDatabaseStreamsS; + WCHAR ** m_wszDatabaseStreamsD; + uint32_t m_ulGenLow; + uint32_t m_ulGenHigh; + WCHAR * m_wszLogBaseName; + time_t m_timeLastRestore; + RECOVER_STATUS m_statusLastRecover; + HRESULT m_hrLastRecover; + time_t m_timeLastRecover; + WCHAR * m_wszAnnotation; +}; + +typedef HANDLE HCCX; + +typedef HRESULT (WINAPI *HrESEBackupRestoreGetNodes_t) +( + WCHAR* wszComputerName, + BACKUP_NODE_TREE* pBackupNodeTree +); + +typedef HRESULT (WINAPI *HrESEBackupPrepare_t) +( + WCHAR* wszBackupServer, + WCHAR* wszBackupAnnotation, + uint32_t *pcInstanceInfo, + INSTANCE_BACKUP_INFO **paInstanceInfo, + HCCX *phccxBackupContext +); + +typedef HRESULT (WINAPI *HrESEBackupEnd_t) +( + HCCX hccsBackupContext +); + +typedef HRESULT (WINAPI *HrESEBackupSetup_t) +( + HCCX hccsBackupContext, + uint64_t hInstanceID, + uint32_t btBackupType +); + +typedef HRESULT (WINAPI *HrESEBackupGetLogAndPatchFiles_t) +( + HCCX hccsBackupContext, + WCHAR** pwszFiles +); + +typedef HRESULT (WINAPI *HrESEBackupInstanceEnd_t) +( + HCCX hccsBackupContext, + uint32_t fFlags +); + +typedef HRESULT (WINAPI *HrESEBackupOpenFile_t) +( + HCCX hccsBackupContext, + WCHAR* wszFileName, + uint32_t cbReadHintSize, + uint32_t cSections, + void** rghFile, + uint64_t* rgliSectionSize +); + +typedef HRESULT (WINAPI *HrESEBackupReadFile_t) +( + HCCX hccsBackupContext, + void* hFile, + void* pvBuffer, + uint32_t cbBuffer, + uint32_t* pcbRead +); + +typedef HRESULT (WINAPI *HrESEBackupCloseFile_t) +( + HCCX hccsBackupContext, + void* hFile +); + +typedef HRESULT (WINAPI *HrESEBackupTruncateLogs_t) +( + HCCX hccsBackupContext +); + +typedef HRESULT (WINAPI *HrESERestoreOpen_t) +( + WCHAR* wszBackupServer, + WCHAR* wszBackupAnnotation, + WCHAR* wszSrcInstanceName, + WCHAR* wszRestoreLogPath, + HCCX* phccxRestoreContext +); + +typedef HRESULT (WINAPI *HrESERestoreReopen_t) +( + WCHAR* wszBackupServer, + WCHAR* wszBackupAnnotation, + WCHAR* wszRestoreLogPath, + HCCX* phccxRestoreContext +); + +typedef HRESULT (WINAPI *HrESERestoreClose_t) +( + HCCX phccxRestoreContext, + uint32_t fRestoreAbort +); + +typedef HRESULT (WINAPI *HrESERestoreComplete_t) +( + HCCX phccxRestoreContext, + WCHAR* wszCheckpointFilePath, + WCHAR* wszLogFilePath, + WCHAR* wszTargetInstanceName, + uint32_t fFlags +); + +typedef HRESULT (WINAPI *HrESERestoreSaveEnvironment_t) +( + HCCX phccxRestoreContext +); + +typedef HRESULT (WINAPI *HrESERestoreGetEnvironment_t) +( + HCCX phccxRestoreContext, + RESTORE_ENVIRONMENT **ppRestoreEnvironment +); + +typedef HRESULT (WINAPI *HrESERestoreAddDatabase_t) +( + HCCX phccxRestoreContext, + WCHAR* wszDatabaseDisplayName, + GUID guidDatabase, + WCHAR* wszDatabaseStreamsS, + WCHAR** wszDatabaseStreamsD +); + +typedef HRESULT (WINAPI *HrESERestoreOpenFile_t) +( + HCCX phccxRestoreContext, + WCHAR* wszFileName, + uint32_t cSections, + void* rghFile +); + +bRC +loadExchangeApi(); + +char * +ESEErrorMessage(HRESULT result); + +#define hrLogfileHasBadSignature (HRESULT)0xC8000262L +#define hrLogfileNotContiguous (HRESULT)0xC8000263L +#define hrCBDatabaseInUse (HRESULT)0xC7FE1F41L +#define hrRestoreAtFileLevel (HRESULT)0xC7FF0FA5L +#define hrMissingFullBackup (HRESULT)0xC8000230L +#define hrBackupInProgress (HRESULT)0xC80001F9L + +extern HrESEBackupRestoreGetNodes_t HrESEBackupRestoreGetNodes; +extern HrESEBackupPrepare_t HrESEBackupPrepare; +extern HrESEBackupGetLogAndPatchFiles_t HrESEBackupGetLogAndPatchFiles; +extern HrESEBackupTruncateLogs_t HrESEBackupTruncateLogs; +extern HrESEBackupEnd_t HrESEBackupEnd; +extern HrESEBackupSetup_t HrESEBackupSetup; +extern HrESEBackupInstanceEnd_t HrESEBackupInstanceEnd; +extern HrESEBackupOpenFile_t HrESEBackupOpenFile; +extern HrESEBackupReadFile_t HrESEBackupReadFile; +extern HrESEBackupCloseFile_t HrESEBackupCloseFile; + +extern HrESERestoreOpen_t HrESERestoreOpen; +extern HrESERestoreReopen_t HrESERestoreReopen; +extern HrESERestoreComplete_t HrESERestoreComplete; +extern HrESERestoreClose_t HrESERestoreClose; +extern HrESERestoreGetEnvironment_t HrESERestoreGetEnvironment; +extern HrESERestoreSaveEnvironment_t HrESERestoreSaveEnvironment; +extern HrESERestoreAddDatabase_t HrESERestoreAddDatabase; +extern HrESERestoreOpenFile_t HrESERestoreOpenFile; +} diff --git a/bacula/src/win32/filed/plugins/dbi_node.c b/bacula/src/win32/filed/plugins/dbi_node.c new file mode 100644 index 0000000000..7744b040f5 --- /dev/null +++ b/bacula/src/win32/filed/plugins/dbi_node.c @@ -0,0 +1,286 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +#include "exchange-fd.h" + +dbi_node_t::dbi_node_t(char *name, node_t *parent_node) : node_t(name, NODE_TYPE_DATABASE_INFO, parent_node) +{ + restore_display_name = NULL; + restore_input_streams = NULL; + buffer = NULL; +} + +dbi_node_t::~dbi_node_t() +{ + if (buffer != NULL) + delete buffer; + if (restore_input_streams != NULL) + delete restore_input_streams; + if (restore_display_name != NULL) + delete restore_display_name; +} + +bRC +dbi_node_t::startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp) +{ + time_t now = time(NULL); + + _DebugMessage(100, "startBackupNode_DBI state = %d\n", state); + + sp->fname = full_path; + sp->link = full_path; + sp->statp.st_mode = 0700 | S_IFREG; + sp->statp.st_ctime = now; + sp->statp.st_mtime = now; + sp->statp.st_atime = now; + sp->statp.st_size = (uint64_t)-1; + sp->type = FT_REG; + + return bRC_OK; +} + +bRC +dbi_node_t::endBackupFile(exchange_fd_context_t *context) +{ + _DebugMessage(100, "endBackupNode_DBI state = %d\n", state); + + context->current_node = parent; + + return bRC_OK; +} + +bRC +dbi_node_t::createFile(exchange_fd_context_t *context, struct restore_pkt *rp) +{ + _DebugMessage(0, "createFile_DBI state = %d\n", state); + + rp->create_status = CF_EXTRACT; + + return bRC_OK; +} + +bRC +dbi_node_t::endRestoreFile(exchange_fd_context_t *context) +{ + _DebugMessage(0, "endRestoreFile_DBI state = %d\n", state); + + context->current_node = parent; + + return bRC_OK; +} + +bRC +dbi_node_t::pluginIoOpen(exchange_fd_context_t *context, struct io_pkt *io) +{ + uint32_t len; + WCHAR *ptr; + WCHAR *stream; + //char tmp[512]; + + buffer_pos = 0; + buffer_size = 65536; + buffer = new char[buffer_size]; + + if (context->job_type == JOB_TYPE_BACKUP) + { + ptr = (WCHAR *)buffer; + len = snwprintf(ptr, (buffer_size - buffer_pos) / 2, L"DatabaseBackupInfo\n"); + if (len < 0) + goto fail; + buffer_pos += len * 2; + ptr += len; + + len = snwprintf(ptr, (buffer_size - buffer_pos) / 2, L"%d\n", EXCHANGE_PLUGIN_VERSION); + if (len < 0) + goto fail; + buffer_pos += len * 2; + ptr += len; + + len = snwprintf(ptr, (buffer_size - buffer_pos) / 2, L"%s\n", dbi->wszDatabaseDisplayName); + if (len < 0) + goto fail; + buffer_pos += len * 2; + ptr += len; + + len = snwprintf(ptr, (buffer_size - buffer_pos) / 2, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", + dbi->rguidDatabase.Data1, dbi->rguidDatabase.Data2, dbi->rguidDatabase.Data3, + dbi->rguidDatabase.Data4[0], dbi->rguidDatabase.Data4[1], + dbi->rguidDatabase.Data4[2], dbi->rguidDatabase.Data4[3], + dbi->rguidDatabase.Data4[4], dbi->rguidDatabase.Data4[5], + dbi->rguidDatabase.Data4[6], dbi->rguidDatabase.Data4[7]); + if (len < 0) + goto fail; + buffer_pos += len * 2; + ptr += len; + + stream = dbi->wszDatabaseStreams; + while (*stream) + { + len = snwprintf(ptr, (buffer_size - buffer_pos) / 2, L"%s\n", stream); + if (len < 0) + goto fail; + buffer_pos += len * 2; + ptr += len; + stream += wcslen(stream) + 1; + } + + buffer_size = buffer_pos; + buffer_pos = 0; + } + + io->status = 0; + io->io_errno = 0; + return bRC_OK; + +fail: + io->status = 0; + io->io_errno = 1; + return bRC_Error; +} + +bRC +dbi_node_t::pluginIoRead(exchange_fd_context_t *context, struct io_pkt *io) +{ + io->status = 0; + io->io_errno = 0; + + io->status = min(io->count, (int)(buffer_size - buffer_pos)); + if (io->status == 0) + return bRC_OK; + memcpy(io->buf, buffer + buffer_pos, io->status); + buffer_pos += io->status; + + return bRC_OK; +} + +bRC +dbi_node_t::pluginIoWrite(exchange_fd_context_t *context, struct io_pkt *io) +{ + memcpy(&buffer[buffer_pos], io->buf, io->count); + buffer_pos += io->count; + io->status = io->count; + io->io_errno = 0; + return bRC_OK; +} + +bRC +dbi_node_t::pluginIoClose(exchange_fd_context_t *context, struct io_pkt *io) +{ + WCHAR tmp[128]; + WCHAR *ptr; + WCHAR eol; + int wchars_read; + int version; + int stream_buf_count; + WCHAR *streams_start; + + if (context->job_type == JOB_TYPE_RESTORE) + { + // need to think about making this buffer overflow proof... + _DebugMessage(100, "analyzing DatabaseBackupInfo\n"); + ptr = (WCHAR *)buffer; + + if (swscanf(ptr, L"%127[^\n]%c%n", tmp, &eol, &wchars_read) != 2) + goto restore_fail; + ptr += wchars_read; + _DebugMessage(150, "Header = %S\n", tmp); + // verify that header == "DatabaseBackupInfo" + + if (swscanf(ptr, L"%127[^\n]%c%n", tmp, &eol, &wchars_read) != 2) + goto restore_fail; + if (swscanf(tmp, L"%d%c", &version, &eol) != 1) + { + version = 0; + _DebugMessage(150, "Version = 0 (inferred)\n"); + } + else + { + ptr += wchars_read; + _DebugMessage(150, "Version = %d\n", version); + if (swscanf(ptr, L"%127[^\n]%c%n", tmp, &eol, &wchars_read) != 2) + goto restore_fail; + } + restore_display_name = new WCHAR[wchars_read]; + swscanf(ptr, L"%127[^\n]", restore_display_name); + _DebugMessage(150, "Database Display Name = %S\n", restore_display_name); + ptr += wchars_read; + + if (swscanf(ptr, L"%127[^\n]%c%n", tmp, &eol, &wchars_read) != 2) + goto restore_fail; + + if (swscanf(ptr, L"%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x", + &restore_guid.Data1, &restore_guid.Data2, &restore_guid.Data3, + &restore_guid.Data4[0], &restore_guid.Data4[1], + &restore_guid.Data4[2], &restore_guid.Data4[3], + &restore_guid.Data4[4], &restore_guid.Data4[5], + &restore_guid.Data4[6], &restore_guid.Data4[7]) != 11) + { + goto restore_fail; + } + _DebugMessage(150, "GUID = %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", + restore_guid.Data1, restore_guid.Data2, restore_guid.Data3, + restore_guid.Data4[0], restore_guid.Data4[1], + restore_guid.Data4[2], restore_guid.Data4[3], + restore_guid.Data4[4], restore_guid.Data4[5], + restore_guid.Data4[6], restore_guid.Data4[7]); + + ptr += wchars_read; + + stream_buf_count = 1; + streams_start = ptr; + while (ptr < (WCHAR *)(buffer + buffer_pos) && swscanf(ptr, L"%127[^\n]%c%n", tmp, &eol, &wchars_read) == 2) + { + _DebugMessage(150, "File = %S\n", tmp); + ptr += wchars_read; + stream_buf_count += wchars_read; + } + restore_input_streams = new WCHAR[stream_buf_count]; + ptr = streams_start; + stream_buf_count = 0; + while (ptr < (WCHAR *)(buffer + buffer_pos) && swscanf(ptr, L"%127[^\n]%c%n", tmp, &eol, &wchars_read) == 2) + { + snwprintf(&restore_input_streams[stream_buf_count], 65535, L"%s", tmp); + ptr += wchars_read; + stream_buf_count += wchars_read; + } + restore_input_streams[stream_buf_count] = 0; + + _DebugMessage(100, "done analyzing DatabasePluginInfo\n"); + } + delete buffer; + buffer = NULL; + return bRC_OK; +restore_fail: + _JobMessage(M_ERROR, "Format of %s is incorrect", full_path); + delete buffer; + buffer = NULL; + return bRC_Error; +} diff --git a/bacula/src/win32/filed/plugins/exchange-fd.c b/bacula/src/win32/filed/plugins/exchange-fd.c new file mode 100644 index 0000000000..a2e3fa4060 --- /dev/null +++ b/bacula/src/win32/filed/plugins/exchange-fd.c @@ -0,0 +1,471 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +#include "exchange-fd.h" + +/* Pointers to Bacula functions */ +bFuncs *bfuncs = NULL; +bInfo *binfo = NULL; + +#define PLUGIN_LICENSE "GPL" +#define PLUGIN_AUTHOR "James Harper" +#define PLUGIN_DATE "September 2008" +#define PLUGIN_VERSION "1" +#define PLUGIN_DESCRIPTION "Exchange Plugin" + +static pInfo pluginInfo = { + sizeof(pluginInfo), + FD_PLUGIN_INTERFACE_VERSION, + FD_PLUGIN_MAGIC, + PLUGIN_LICENSE, + PLUGIN_AUTHOR, + PLUGIN_DATE, + PLUGIN_VERSION, + PLUGIN_DESCRIPTION, +}; + +/* Forward referenced functions */ +static bRC newPlugin(bpContext *ctx); +static bRC freePlugin(bpContext *ctx); +static bRC getPluginValue(bpContext *ctx, pVariable var, void *value); +static bRC setPluginValue(bpContext *ctx, pVariable var, void *value); +static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value); +static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp); +static bRC endBackupFile(bpContext *ctx); +static bRC pluginIO(bpContext *ctx, struct io_pkt *io); +static bRC startRestoreFile(bpContext *ctx, const char *cmd); +static bRC endRestoreFile(bpContext *ctx); +static bRC createFile(bpContext *ctx, struct restore_pkt *rp); +static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp); + +static pFuncs pluginFuncs = { + sizeof(pluginFuncs), + FD_PLUGIN_INTERFACE_VERSION, + + /* Entry points into plugin */ + newPlugin, /* new plugin instance */ + freePlugin, /* free plugin instance */ + getPluginValue, + setPluginValue, + handlePluginEvent, + startBackupFile, + endBackupFile, + startRestoreFile, + endRestoreFile, + pluginIO, + createFile, + setFileAttributes +}; + +extern "C" { + +static char ** +splitString(char *string, char split, int maxParts, int *count) +{ + char **RetVal; + char *first; + char *last; + + //KdPrint((__DRIVER_NAME " a\n")); + + *count = 0; + + RetVal = (char **)malloc((maxParts + 1) * sizeof(char *)); + last = string; + do + { + if (*count == maxParts) + break; + first = last; + for (last = first; *last != '\0' && *last != split; last++); + RetVal[*count] = (char *)malloc(last - first + 1); + strncpy(RetVal[*count], first, last - first); + RetVal[*count][last - first] = 0; + (*count)++; + if (*last == split) + last++; + } while (*last != 0); + RetVal[*count] = NULL; + return RetVal; +} + +bRC DLLEXPORT +loadPlugin(bInfo *lbinfo, bFuncs *lbfuncs, pInfo **pinfo, pFuncs **pfuncs) +{ + bRC retval; + bfuncs = lbfuncs; /* set Bacula funct pointers */ + binfo = lbinfo; + *pinfo = &pluginInfo; + *pfuncs = &pluginFuncs; + retval = loadExchangeApi(); + if (retval != bRC_OK) + { + printf("Cannot load Exchange DLL\n"); + return retval; + } + return retval; +} + +bRC DLLEXPORT +unloadPlugin() +{ + return bRC_OK; +} + +} + +void * +b_malloc(const char *file, int lone, size_t size) +{ + return NULL; +} + +void * +sm_malloc(const char *file, int lone, size_t size) +{ + return NULL; +} + +static bRC newPlugin(bpContext *ctx) +{ + exchange_fd_context_t *context; + bRC retval = bRC_OK; + DWORD size; + + int JobId = 0; + ctx->pContext = new exchange_fd_context_t; + context = (exchange_fd_context_t *)ctx->pContext; + context->bpContext = ctx; + context->job_since = 0; + context->notrunconfull_option = false; + bfuncs->getBaculaValue(ctx, bVarJobId, (void *)&JobId); + _DebugMessage(0, "newPlugin JobId=%d\n", JobId); + bfuncs->registerBaculaEvents(ctx, 1, 2, 0); + size = MAX_COMPUTERNAME_LENGTH + 1; + context->computer_name = new WCHAR[size]; + GetComputerNameW(context->computer_name, &size); + context->current_node = NULL; + context->root_node = NULL; + return retval; +} + +static bRC freePlugin(bpContext *ctx) +{ + exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext; + int JobId = 0; + bfuncs->getBaculaValue(ctx, bVarJobId, (void *)&JobId); + _DebugMessage(100, "freePlugin JobId=%d\n", JobId); + delete context; + return bRC_OK; +} + +static bRC getPluginValue(bpContext *ctx, pVariable var, void *value) +{ + exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext; + _DebugMessage(100, "getPluginValue var=%d\n", var); + return bRC_OK; +} + +static bRC setPluginValue(bpContext *ctx, pVariable var, void *value) +{ + exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext; + _DebugMessage(100, "setPluginValue var=%d\n", var); + return bRC_OK; +} + +static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value) +{ + exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext; + char *name; + int i; + + switch (event->eventType) { + case bEventJobStart: + _DebugMessage(0, "JobStart=%s\n", (char *)value); + break; + case bEventJobEnd: + _DebugMessage(0, "JobEnd\n"); + break; + case bEventStartBackupJob: + _DebugMessage(0, "BackupStart\n"); + context->job_type = JOB_TYPE_BACKUP; + // level should have been specified by now - check it + // if level is D or I, since should have been specified too + switch (context->job_level) + { + case 'F': + if (context->notrunconfull_option) { + context->truncate_logs = false; + } else { + context->truncate_logs = true; + } + break; + case 'D': + context->truncate_logs = false; + break; + case 'I': + context->truncate_logs = false; + break; + default: + _DebugMessage(0, "Invalid job level %c\n", context->job_level); + return bRC_Error; + } + break; + case bEventEndBackupJob: + _DebugMessage(0, "BackupEnd\n"); + break; + case bEventLevel: + _DebugMessage(0, "JobLevel=%c %d\n", (int)value, (int)value); + context->job_level = (int)value; + break; + case bEventSince: + _DebugMessage(0, "since=%d\n", (int)value); + context->job_since = (time_t)value; + break; + case bEventStartRestoreJob: + _DebugMessage(0, "StartRestoreJob\n"); + context->job_type = JOB_TYPE_RESTORE; + break; + case bEventEndRestoreJob: + _DebugMessage(0, "EndRestoreJob\n"); + break; + + /* Plugin command e.g. plugin = ::command */ + case bEventRestoreCommand: + _DebugMessage(0, "restore\n"); // command=%s\n", (char *)value); + break; + + case bEventBackupCommand: + { + _DebugMessage(0, "backup command=%s\n", (char *)value); + char *command = new char[strlen((char *)value)]; + strcpy(command, (char *)value); + char *plugin_name = strtok((char *)command, ":"); + char *path = strtok(NULL, ":"); + char *option; + while ((option = strtok(NULL, ":")) != NULL) + { + _DebugMessage(100, "option %s\n", option); + if (stricmp(option, "notrunconfull") == 0) + { + context->notrunconfull_option = true; + } + else + { + _JobMessage(M_WARNING, "Unknown plugin option '%s'\n", option); + } + } + _DebugMessage(0, "name = %s\n", plugin_name); + _DebugMessage(0, "path = %s\n", path); + if (*path != '/') + { + _JobMessage(M_ERROR, "Path does not begin with a '/'\n"); + return bRC_Error; + } + + for (i = 0; i < 6; i++) + context->path_bits[i] = NULL; + + char *path_bit = strtok(path, "/"); + for (i = 0; path_bit != NULL && i < 6; i++) + { + context->path_bits[i] = new char[strlen(path_bit) + 1]; + strcpy(context->path_bits[i], path_bit); + path_bit = strtok(NULL, "/"); + } + + if (i < 2 || i > 4) + { + _JobMessage(M_ERROR, "Invalid plugin backup path\n"); + return bRC_Error; + } + context->root_node = new root_node_t(context->path_bits[0]); + context->current_node = context->root_node; + + } + break; + + default: + _JobMessage(M_ERROR, "unknown event=%d\n", event->eventType); + } + bfuncs->getBaculaValue(ctx, bVarFDName, (void *)&name); + return bRC_OK; +} + +static bRC +startBackupFile(bpContext *ctx, struct save_pkt *sp) +{ + bRC retval; + exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext; + node_t *current_node; + + _DebugMessage(100, "startBackupFile, cmd = %s\n", sp->cmd); + if (sp->pkt_size != sizeof(struct save_pkt) || sp->pkt_end != sizeof(struct save_pkt)) + { + _JobMessage(M_FATAL, "save_pkt size mismatch - sizeof(struct save_pkt) = %d, pkt_size = %d, pkt_end = %d\n", sizeof(struct save_pkt), sp->pkt_size, sp->pkt_end); + return bRC_Error; + } + + //context->root_node = new root_node_t(PLUGIN_PATH_PREFIX_BASE); + //context->current_node = context->root_node; + do { + current_node = context->current_node; + retval = current_node->startBackupFile(context, sp); + } while (current_node != context->current_node); + _DebugMessage(100, "startBackupFile done - type = %d, fname = %s, retval = %d\n", sp->type, sp->fname, retval); + return retval; +} + +static bRC endBackupFile(bpContext *ctx) +{ + bRC retval; + exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext; + node_t *current_node; + + _DebugMessage(100, "endBackupFile\n"); + + do { + current_node = context->current_node; + retval = current_node->endBackupFile(context); + } while (current_node != context->current_node); + _DebugMessage(100, "endBackupFile done - retval = %d\n", retval); + return retval; +} + +/* + * Do actual I/O + */ +static bRC pluginIO(bpContext *ctx, struct io_pkt *io) +{ + bRC retval = bRC_OK; + exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext; + + if (io->pkt_size != sizeof(struct io_pkt) || io->pkt_end != sizeof(struct io_pkt)) + { + _JobMessage(M_ERROR, "io_pkt size mismatch - sizeof(struct io_pkt) = %d, pkt_size = %d, pkt_end = %d\n", sizeof(struct io_pkt), io->pkt_size, io->pkt_end); + } + + switch(io->func) { + case IO_OPEN: + _DebugMessage(100, "IO_OPEN\n"); + retval = context->current_node->pluginIoOpen(context, io); + break; + case IO_READ: + //_DebugMessage(100, "IO_READ buf=%p len=%d\n", io->buf, io->count); + retval = context->current_node->pluginIoRead(context, io); + break; + case IO_WRITE: + //_DebugMessage(100, "IO_WRITE buf=%p len=%d\n", io->buf, io->count); + retval = context->current_node->pluginIoWrite(context, io); + break; + case IO_CLOSE: + _DebugMessage(100, "IO_CLOSE\n"); + retval = context->current_node->pluginIoClose(context, io); + break; + } + return retval; +} + +static bRC startRestoreFile(bpContext *ctx, const char *cmd) +{ + exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext; + _DebugMessage(100, "startRestoreFile\n"); + + return bRC_OK; +} + +static bRC endRestoreFile(bpContext *ctx) +{ + bRC retval; + exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext; + node_t *current_node; + + _DebugMessage(100, "endRestoreFile\n"); + + do { + current_node = context->current_node; + retval = current_node->endRestoreFile(context); + } while (current_node != context->current_node); + _DebugMessage(100, "endRestoreFile done - retval = %d\n", retval); + return retval; +} + +static bRC createFile(bpContext *ctx, struct restore_pkt *rp) +{ + bRC retval; + exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext; + node_t *current_node; + char **path_bits; + int count; + int i; + + + _DebugMessage(100, "createFile - type = %d, ofname = %s\n", rp->type, rp->ofname); + if (rp->pkt_size != sizeof(struct restore_pkt) || rp->pkt_end != sizeof(struct restore_pkt)) + { + _JobMessage(M_ERROR, "restore_pkt size mismatch - sizeof(struct restore_pkt) = %d, pkt_size = %d, pkt_end = %d\n", sizeof(struct restore_pkt), rp->pkt_size, rp->pkt_end); + } + + for (i = 0; i < 6; i++) + { + context->path_bits[i] = NULL; + } + + path_bits = splitString((char *)rp->ofname, '/', 7, &count); + + _DebugMessage(100, "count = %d\n", count); + + for (i = 1; i < count; i++) + { + _DebugMessage(150, "%d = '%s'\n", i, path_bits[i]); + context->path_bits[i - 1] = path_bits[i]; + } + + if (context->current_node == NULL) + { + context->root_node = new root_node_t(context->path_bits[0]); + context->current_node = context->root_node; + } + + do { + current_node = context->current_node; + retval = current_node->createFile(context, rp); + } while (current_node != context->current_node); + _DebugMessage(100, "createFile done - retval = %d\n", retval); + return retval; +} + +static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp) +{ + exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext; + _DebugMessage(100, "setFileAttributes\n"); + return bRC_OK; +} diff --git a/bacula/src/win32/filed/plugins/exchange-fd.def b/bacula/src/win32/filed/plugins/exchange-fd.def new file mode 100644 index 0000000000..77ab2d1f1f --- /dev/null +++ b/bacula/src/win32/filed/plugins/exchange-fd.def @@ -0,0 +1,15 @@ +LIBRARY bacula.dll +EXPORTS + +; compat.o +;_Z10open_bpipePciPKc +;_Z11close_bpipeP5BPIPE +;_Z11close_wpipeP5BPIPE + +;console_command DATA +;plugin_list DATA +;plugin_bopen DATA +;plugin_bclose DATA +;plugin_bwrite DATA +;plugin_bread DATA +;plugin_blseek DATA diff --git a/bacula/src/win32/filed/plugins/exchange-fd.h b/bacula/src/win32/filed/plugins/exchange-fd.h new file mode 100644 index 0000000000..248274ce32 --- /dev/null +++ b/bacula/src/win32/filed/plugins/exchange-fd.h @@ -0,0 +1,96 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +#ifndef _EXCHANGE_FD_H +#define _EXCHANGE_FD_H + +#include +#include +#include +#include "bacula.h" +#include "fd_plugins.h" +#include "api.h" + +#define EXCHANGE_PLUGIN_VERSION 1 + +#define DLLEXPORT __declspec(dllexport) + +#define JOB_TYPE_BACKUP 1 +#define JOB_TYPE_RESTORE 2 + +#define JOB_LEVEL_FULL ((int)'F') +#define JOB_LEVEL_INCREMENTAL ((int)'I') +#define JOB_LEVEL_DIFFERENTIAL ((int)'D') + +struct exchange_fd_context_t; + +#include "node.h" + +struct exchange_fd_context_t { + struct bpContext *bpContext; + WCHAR *computer_name; + char *path_bits[6]; + root_node_t *root_node; + node_t *current_node; + int job_type; + int job_level; + time_t job_since; + bool notrunconfull_option; + bool truncate_logs; +}; + +static inline char *tocharstring(WCHAR *src) +{ + char *tmp = new char[wcslen(src) + 1]; + wcstombs(tmp, src, wcslen(src) + 1); + return tmp; +} + +static inline WCHAR *towcharstring(char *src) +{ + WCHAR *tmp = new WCHAR[strlen(src) + 1]; + mbstowcs(tmp, src, strlen(src) + 1); + return tmp; +} + + +extern bFuncs *bfuncs; +extern bInfo *binfo; + +#define _DebugMessage(level, message, ...) bfuncs->DebugMessage(context->bpContext, __FILE__, __LINE__, level, message, ##__VA_ARGS__) +#define _JobMessage(type, message, ...) bfuncs->JobMessage(context->bpContext, __FILE__, __LINE__, type, 0, message, ##__VA_ARGS__) +#define _JobMessageNull(type, message, ...) bfuncs->JobMessage(NULL, __FILE__, __LINE__, type, 0, message, ##__VA_ARGS__) + +#define PLUGIN_PATH_PREFIX_BASE "@EXCHANGE" +#define PLUGIN_PATH_PREFIX_SERVICE "Microsoft Information Store" +#define PLUGIN_PATH_PREFIX_SERVICE_W L"Microsoft Information Store" + +#endif /* _EXCHANGE_FD_H */ diff --git a/bacula/src/win32/filed/plugins/file_node.c b/bacula/src/win32/filed/plugins/file_node.c new file mode 100644 index 0000000000..6af291d130 --- /dev/null +++ b/bacula/src/win32/filed/plugins/file_node.c @@ -0,0 +1,229 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +#include "exchange-fd.h" + +file_node_t::file_node_t(char *name, node_t *parent_node) : node_t(name, NODE_TYPE_FILE, parent_node) +{ + backup_file_handle = INVALID_HANDLE_VALUE; + restore_file_handle = INVALID_HANDLE_VALUE; + restore_at_file_level = FALSE; +} + +file_node_t::~file_node_t() +{ + if (backup_file_handle != INVALID_HANDLE_VALUE) + { + //_DebugMessage(100, "closing file handle in destructor\n"); + CloseHandle(backup_file_handle); + } + if (restore_file_handle != INVALID_HANDLE_VALUE) + { + //_DebugMessage(100, "closing file handle in destructor\n"); + if (restore_at_file_level) + { + CloseHandle(restore_file_handle); + } + else + { + // maybe one day + } + } +} + +bRC +file_node_t::startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp) +{ + time_t now = time(NULL); + _DebugMessage(100, "startBackupNode_FILE state = %d\n", state); + + sp->fname = full_path; + sp->link = full_path; + _DebugMessage(100, "fname = %s\n", sp->fname); + sp->statp.st_mode = 0700 | S_IFREG; + sp->statp.st_ctime = now; + sp->statp.st_mtime = now; + sp->statp.st_atime = now; + sp->statp.st_size = (uint64_t)-1; + sp->type = FT_REG; + + return bRC_OK; +} + +bRC +file_node_t::endBackupFile(exchange_fd_context_t *context) +{ + _DebugMessage(100, "endBackupNode_FILE state = %d\n", state); + + context->current_node = parent; + + return bRC_OK; +} + +bRC +file_node_t::createFile(exchange_fd_context_t *context, struct restore_pkt *rp) +{ + //HrESERestoreOpenFile with name of log file + + _DebugMessage(0, "createFile_FILE state = %d\n", state); + rp->create_status = CF_EXTRACT; + return bRC_OK; +} + +bRC +file_node_t::endRestoreFile(exchange_fd_context_t *context) +{ + _DebugMessage(0, "endRestoreFile_FILE state = %d\n", state); + context->current_node = parent; + return bRC_OK; +} + +bRC +file_node_t::pluginIoOpen(exchange_fd_context_t *context, struct io_pkt *io) +{ + HRESULT result; + HANDLE handle; + + _DebugMessage(100, "pluginIoOpen_FILE - filename = %S\n", filename); + io->status = 0; + io->io_errno = 0; + if (context->job_type == JOB_TYPE_BACKUP) + { + _DebugMessage(100, "Calling HrESEBackupOpenFile\n"); + result = HrESEBackupOpenFile(hccx, filename, 65535, 1, &backup_file_handle, §ion_size); + if (result) + { + _JobMessage(M_ERROR, "HrESEBackupOpenFile failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + backup_file_handle = INVALID_HANDLE_VALUE; + io->io_errno = 1; + return bRC_Error; + } + } + else + { + _DebugMessage(100, "Calling HrESERestoreOpenFile\n"); + result = HrESERestoreOpenFile(hccx, filename, 1, &restore_file_handle); + if (result == hrRestoreAtFileLevel) + { + restore_at_file_level = true; + handle = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (handle == INVALID_HANDLE_VALUE) + { + _JobMessage(M_ERROR, "CreateFile failed"); + return bRC_Error; + } + restore_file_handle = (void *)handle; + return bRC_OK; + } + else if (result == 0) + { + _JobMessage(M_ERROR, "Exchange File IO API not yet supported for restore\n"); + restore_at_file_level = false; + return bRC_Error; + } + else + { + _JobMessage(M_ERROR, "HrESERestoreOpenFile failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + return bRC_Error; + } + } + return bRC_OK; +} + +bRC +file_node_t::pluginIoRead(exchange_fd_context_t *context, struct io_pkt *io) +{ + HRESULT result; + uint32_t readLength; + + io->status = 0; + io->io_errno = 0; + _DebugMessage(200, "Calling HrESEBackupReadFile\n"); + result = HrESEBackupReadFile(hccx, backup_file_handle, io->buf, io->count, &readLength); + if (result) + { + io->io_errno = 1; + return bRC_Error; + } + io->status = readLength; + size += readLength; + return bRC_OK; +} + +bRC +file_node_t::pluginIoWrite(exchange_fd_context_t *context, struct io_pkt *io) +{ + DWORD bytes_written; + + io->io_errno = 0; + if (!restore_at_file_level) + return bRC_Error; + + if (!WriteFile(restore_file_handle, io->buf, io->count, &bytes_written, NULL)) + { + _JobMessage(M_ERROR, "Write Error"); + return bRC_Error; + } + + if (bytes_written != (DWORD)io->count) + { + _JobMessage(M_ERROR, "Short write"); + return bRC_Error; + } + io->status = bytes_written; + + return bRC_OK; +} + +bRC +file_node_t::pluginIoClose(exchange_fd_context_t *context, struct io_pkt *io) +{ + if (context->job_type == JOB_TYPE_BACKUP) + { + _DebugMessage(100, "Calling HrESEBackupCloseFile\n"); + HrESEBackupCloseFile(hccx, backup_file_handle); + backup_file_handle = INVALID_HANDLE_VALUE; + return bRC_OK; + } + else + { + if (restore_at_file_level) + { + CloseHandle(restore_file_handle); + restore_file_handle = INVALID_HANDLE_VALUE; + return bRC_OK; + } + else + { + return bRC_OK; + } + } +} diff --git a/bacula/src/win32/filed/plugins/node.c b/bacula/src/win32/filed/plugins/node.c new file mode 100644 index 0000000000..eb52e01552 --- /dev/null +++ b/bacula/src/win32/filed/plugins/node.c @@ -0,0 +1,127 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +#include "exchange-fd.h" + +node_t::node_t(char *name, int type) +{ + this->type = type; + state = 0; + parent = NULL; + this->name = bstrdup(name); + full_path = make_full_path(); + size = 0; + level = 0; +} + +node_t::node_t(char *name, int type, node_t *parent_node) +{ + this->type = type; + state = 0; + parent = parent_node; + this->name = bstrdup(name); + full_path = make_full_path(); + size = 0; + level = parent->level + 1; +} + +node_t::~node_t() +{ + delete name; + delete full_path; +} + +char * +node_t::make_full_path() +{ + node_t *curr_node; + int len; + char *retval; + + for (len = 0, curr_node = this; curr_node != NULL; curr_node = curr_node->parent) + { + len += strlen(curr_node->name) + 1; + } + if (type == NODE_TYPE_FILE || type == NODE_TYPE_DATABASE_INFO) + { + retval = new char[len + 1]; + retval[len] = 0; + } + else + { + retval = new char[len + 2]; + retval[len] = '/'; + retval[len + 1] = 0; + } + for (curr_node = this; curr_node != NULL; curr_node = curr_node->parent) + { + len -= strlen(curr_node->name); + memcpy(retval + len, curr_node->name, strlen(curr_node->name)); + retval[--len] = '/'; + } + return retval; +} + +bRC +node_t::pluginIoOpen(exchange_fd_context_t *context, struct io_pkt *io) +{ + _DebugMessage(100, "pluginIoOpen_Node\n"); + io->status = 0; + io->io_errno = 0; + return bRC_OK; +} + +bRC +node_t::pluginIoRead(exchange_fd_context_t *context, struct io_pkt *io) +{ + _DebugMessage(100, "pluginIoRead_Node\n"); + io->status = 0; + io->io_errno = 0; + return bRC_OK; +} + +bRC +node_t::pluginIoWrite(exchange_fd_context_t *context, struct io_pkt *io) +{ + _DebugMessage(100, "pluginIoWrite_Node\n"); + io->status = 0; + io->io_errno = 1; + return bRC_Error; +} + +bRC +node_t::pluginIoClose(exchange_fd_context_t *context, struct io_pkt *io) +{ + _DebugMessage(100, "pluginIoClose_Node\n"); + io->status = 0; + io->io_errno = 0; + return bRC_OK; +} diff --git a/bacula/src/win32/filed/plugins/node.h b/bacula/src/win32/filed/plugins/node.h new file mode 100644 index 0000000000..f17e2d1b7d --- /dev/null +++ b/bacula/src/win32/filed/plugins/node.h @@ -0,0 +1,186 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +#define NODE_TYPE_UNKNOWN 0 +#define NODE_TYPE_ROOT 1 +#define NODE_TYPE_SERVICE 2 +#define NODE_TYPE_STORAGE_GROUP 3 +#define NODE_TYPE_STORE 4 +#define NODE_TYPE_DATABASE_INFO 5 +#define NODE_TYPE_FILE 6 + +class node_t { +public: + int type; + int state; + node_t *parent; + char *name; + char *full_path; + size_t size; + int level; + + node_t(char *name, int type); + node_t(char *name, int type, node_t *parent_node); + virtual ~node_t(); + + char *make_full_path(); + + virtual bRC startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp) = 0; + virtual bRC endBackupFile(exchange_fd_context_t *context) = 0; + + virtual bRC createFile(exchange_fd_context_t *context, struct restore_pkt *rp) = 0; + virtual bRC endRestoreFile(exchange_fd_context_t *context) = 0; + + virtual bRC pluginIoOpen(exchange_fd_context_t *context, struct io_pkt *io); + virtual bRC pluginIoRead(exchange_fd_context_t *context, struct io_pkt *io); + virtual bRC pluginIoWrite(exchange_fd_context_t *context, struct io_pkt *io); + virtual bRC pluginIoClose(exchange_fd_context_t *context, struct io_pkt *io); +}; + +class file_node_t : public node_t { +public: + WCHAR *filename; + HCCX hccx; + VOID *backup_file_handle; + VOID *restore_file_handle; + uint64_t section_size; + bool restore_at_file_level; + + file_node_t(char *name, node_t *parent_node); + virtual ~file_node_t(); + bRC startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp); + bRC endBackupFile(exchange_fd_context_t *context); + + bRC createFile(exchange_fd_context_t *context, struct restore_pkt *rp); + bRC endRestoreFile(exchange_fd_context_t *context); + + bRC pluginIoOpen(exchange_fd_context_t *context, struct io_pkt *io); + bRC pluginIoRead(exchange_fd_context_t *context, struct io_pkt *io); + bRC pluginIoWrite(exchange_fd_context_t *context, struct io_pkt *io); + bRC pluginIoClose(exchange_fd_context_t *context, struct io_pkt *io); +}; + +class dbi_node_t : public node_t { +public: + DATABASE_BACKUP_INFO *dbi; + char *buffer; + uint32_t buffer_size; + uint32_t buffer_pos; + WCHAR *restore_display_name; + GUID restore_guid; + WCHAR *restore_input_streams; + WCHAR *restore_output_streams; + + dbi_node_t(char *name, node_t *parent_node); + virtual ~dbi_node_t(); + bRC startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp); + bRC endBackupFile(exchange_fd_context_t *context); + + bRC createFile(exchange_fd_context_t *context, struct restore_pkt *rp); + bRC endRestoreFile(exchange_fd_context_t *context); + + bRC pluginIoOpen(exchange_fd_context_t *context, struct io_pkt *io); + bRC pluginIoRead(exchange_fd_context_t *context, struct io_pkt *io); + bRC pluginIoWrite(exchange_fd_context_t *context, struct io_pkt *io); + bRC pluginIoClose(exchange_fd_context_t *context, struct io_pkt *io); +}; + +class store_node_t : public node_t { +public: + HCCX hccx; + DATABASE_BACKUP_INFO *dbi; + WCHAR *stream_ptr; + file_node_t *file_node; + dbi_node_t *dbi_node; + WCHAR *out_stream_ptr; + + store_node_t(char *name, node_t *parent_node); + virtual ~store_node_t(); + bRC startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp); + bRC endBackupFile(exchange_fd_context_t *context); + + bRC createFile(exchange_fd_context_t *context, struct restore_pkt *rp); + bRC endRestoreFile(exchange_fd_context_t *context); +}; + +class storage_group_node_t : public node_t { +public: + HCCX hccx; + INSTANCE_BACKUP_INFO *ibi; + store_node_t *store_node; + file_node_t *file_node; + uint32_t current_dbi; + WCHAR *logfiles; + WCHAR *logfile_ptr; + RESTORE_ENVIRONMENT *restore_environment; + WCHAR *service_name; + WCHAR *storage_group_name; + WCHAR *saved_log_path; + storage_group_node_t *next; + + storage_group_node_t(char *name, node_t *parent_node); + virtual ~storage_group_node_t(); + bRC startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp); + bRC endBackupFile(exchange_fd_context_t *context); + + bRC createFile(exchange_fd_context_t *context, struct restore_pkt *rp); + bRC endRestoreFile(exchange_fd_context_t *context); +}; + +class service_node_t : public node_t { +public: + uint32_t ibi_count; + INSTANCE_BACKUP_INFO *ibi; + HCCX hccx; + uint32_t current_ibi; + storage_group_node_t *first_storage_group_node; + + service_node_t(char *name, node_t *parent_node); + virtual ~service_node_t(); + bRC startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp); + bRC endBackupFile(exchange_fd_context_t *context); + + bRC createFile(exchange_fd_context_t *context, struct restore_pkt *rp); + bRC endRestoreFile(exchange_fd_context_t *context); +}; + +class root_node_t : public node_t { +public: + service_node_t *service_node; + + root_node_t(char *name); + virtual ~root_node_t(); + bRC startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp); + bRC endBackupFile(exchange_fd_context_t *context); + + bRC createFile(exchange_fd_context_t *context, struct restore_pkt *rp); + bRC endRestoreFile(exchange_fd_context_t *context); +}; diff --git a/bacula/src/win32/filed/plugins/root_node.c b/bacula/src/win32/filed/plugins/root_node.c new file mode 100644 index 0000000000..26619fb212 --- /dev/null +++ b/bacula/src/win32/filed/plugins/root_node.c @@ -0,0 +1,157 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +#include "exchange-fd.h" + +root_node_t::root_node_t(char *name) : node_t(name, NODE_TYPE_ROOT) +{ + service_node = NULL; +} + +root_node_t::~root_node_t() +{ +} + +bRC +root_node_t::startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp) +{ + bRC retval = bRC_OK; + time_t now; + + _DebugMessage(100, "startBackupNode_ROOT state = %d\n", state); + switch(state) + { + case 0: + if (strcmp(PLUGIN_PATH_PREFIX_BASE, name) != 0) + { + _JobMessage(M_ERROR, "Invalid backup path specified, must start with '/" PLUGIN_PATH_PREFIX_BASE "/'\n"); + state = 999; + return bRC_Error; + } + // check that service_node == NULL + service_node = new service_node_t(bstrdup(context->path_bits[level + 1]), this); + state = 1; + // fall through + case 1: + context->current_node = service_node; + break; + case 2: + now = time(NULL); + sp->fname = full_path; + sp->link = full_path; + sp->statp.st_mode = 0700 | S_IFDIR; + sp->statp.st_ctime = now; + sp->statp.st_mtime = now; + sp->statp.st_atime = now; + sp->statp.st_size = 0; + sp->type = FT_DIREND; + break; + case 999: + return bRC_Error; + default: + _JobMessage(M_ERROR, "Invalid state %d", state); + state = 999; + } + return retval; +} + +bRC +root_node_t::endBackupFile(exchange_fd_context_t *context) +{ + bRC retval = bRC_OK; + + _DebugMessage(100, "endBackupNode_ROOT state = %d\n", state); + switch(state) + { + case 1: + state = 2; + retval = bRC_More; + // free service_node here? + break; + case 2: + retval = bRC_OK; + break; + case 999: + retval = bRC_Error; + default: + _JobMessage(M_ERROR, "Invalid state %d", state); + state = 999; + return bRC_Error; + } + return retval; +} + +bRC +root_node_t::createFile(exchange_fd_context_t *context, struct restore_pkt *rp) +{ + _DebugMessage(0, "createFile_ROOT state = %d\n", state); + switch (state) + { + case 0: + if (strcmp(name, PLUGIN_PATH_PREFIX_BASE) != 0) + { + _JobMessage(M_ERROR, "Invalid restore path specified, must start with '/" PLUGIN_PATH_PREFIX_BASE "/'\n"); + state = 999; + return bRC_Error; + } + service_node = new service_node_t(bstrdup(context->path_bits[level + 1]), this); + context->current_node = service_node; + return bRC_OK; + case 1: + rp->create_status = CF_CREATED; + return bRC_OK; + case 999: + return bRC_Error; + default: + _JobMessage(M_ERROR, "Invalid state %d", state); + state = 999; + } + return bRC_Error; +} + +bRC +root_node_t::endRestoreFile(exchange_fd_context_t *context) +{ + _DebugMessage(0, "endRestoreFile_ROOT state = %d\n", state); + switch (state) + { + case 0: + delete service_node; + state = 1; + return bRC_OK; + case 1: + return bRC_OK; + default: + _JobMessage(M_ERROR, "Invalid state %d", state); + state = 999; + } + return bRC_Error; +} diff --git a/bacula/src/win32/filed/plugins/service_node.c b/bacula/src/win32/filed/plugins/service_node.c new file mode 100644 index 0000000000..9d3a267d97 --- /dev/null +++ b/bacula/src/win32/filed/plugins/service_node.c @@ -0,0 +1,226 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +#include "exchange-fd.h" + +service_node_t::service_node_t(char *name, node_t *parent_node) : node_t(name, NODE_TYPE_SERVICE, parent_node) +{ + current_ibi = 0; + hccx = NULL; + ibi = NULL; + ibi_count = 0; + first_storage_group_node = NULL; +} + +service_node_t::~service_node_t() +{ +} + +bRC +service_node_t::startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp) +{ + HRESULT result; + + _DebugMessage(100, "startBackupNode_SERVICE state = %d\n", state); + switch(state) + { + case 0: + if (strcmp(PLUGIN_PATH_PREFIX_SERVICE, name) != 0) + { + _JobMessage(M_ERROR, "Invalid restore path specified, must start with /" PLUGIN_PATH_PREFIX_BASE "/" PLUGIN_PATH_PREFIX_SERVICE "/\n"); + return bRC_Error; + } + // convert name to a wide string + + _DebugMessage(100, "Calling HrESEBackupPrepare\n"); + result = HrESEBackupPrepare(context->computer_name, PLUGIN_PATH_PREFIX_SERVICE_W, &ibi_count, &ibi, &hccx); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESEBackupPrepare failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + return bRC_Error; + } + state = 1; + // fall through + case 1: + if (context->path_bits[level + 1] == NULL) + { + _DebugMessage(100, "No specific storage group specified - backing them all up\n"); + char *tmp = new char[wcslen(ibi[current_ibi].wszInstanceName) + 1]; + wcstombs(tmp, ibi[current_ibi].wszInstanceName, wcslen(ibi[current_ibi].wszInstanceName) + 1); + first_storage_group_node = new storage_group_node_t(tmp, this); + delete tmp; + _DebugMessage(100, "storage group name = %s\n", first_storage_group_node->name); + first_storage_group_node->ibi = &ibi[current_ibi]; + first_storage_group_node->hccx = hccx; + context->current_node = first_storage_group_node; + } + else + { + char *tmp = NULL; + for (current_ibi = 0; current_ibi < ibi_count; current_ibi++) + { + tmp = new char[wcslen(ibi[current_ibi].wszInstanceName) + 1]; + wcstombs(tmp, ibi[current_ibi].wszInstanceName, wcslen(ibi[current_ibi].wszInstanceName) + 1); + if (stricmp(tmp, context->path_bits[level + 1]) == 0) + break; + } + first_storage_group_node = new storage_group_node_t(tmp, this); + delete tmp; + if (current_ibi == ibi_count) + { + _JobMessage(M_ERROR, "Invalid Storage Group '%s'\n", context->path_bits[level + 1]); + return bRC_Error; + } + _DebugMessage(100, "storage group name = %s\n", first_storage_group_node->name); + first_storage_group_node->ibi = &ibi[current_ibi]; + first_storage_group_node->hccx = hccx; + context->current_node = first_storage_group_node; + } + break; + case 2: + time_t now = time(NULL); + sp->fname = full_path; + sp->link = full_path; + sp->statp.st_mode = 0700 | S_IFDIR; + sp->statp.st_ctime = now; + sp->statp.st_mtime = now; + sp->statp.st_atime = now; + sp->statp.st_size = 0; + sp->statp.st_nlink = 1; + //sp->statp.st_blocks = 0; + sp->type = FT_DIREND; + break; + } + _DebugMessage(100, "ending startBackupNode_SERVICE state = %d\n", state); + return bRC_OK; +} + +bRC +service_node_t::endBackupFile(exchange_fd_context_t *context) +{ + HRESULT result; + bRC retval = bRC_OK; + + _DebugMessage(100, "endBackupNode_SERVICE state = %d\n", state); + switch(state) + { + case 0: + // should never happen + break; + case 1: + // free node->storage_group_node + if (context->path_bits[level + 1] == NULL) + { + current_ibi++; + if (current_ibi == ibi_count) + state = 2; + } + else + state = 2; + retval = bRC_More; + break; + case 2: + _DebugMessage(100, "calling HrESEBackupEnd\n"); + result = HrESEBackupEnd(hccx); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESEBackupEnd failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + return bRC_Error; + } + + context->current_node = parent; + retval = bRC_OK; + break; + } + return retval; +} + +bRC +service_node_t::createFile(exchange_fd_context_t *context, struct restore_pkt *rp) +{ + storage_group_node_t *curr_sg, *prev_sg; + + _DebugMessage(0, "createFile_SERVICE state = %d\n", state); + if (strcmp(name, "Microsoft Information Store") != 0) + { + _JobMessage(M_ERROR, "Invalid restore path specified, must start with '/" PLUGIN_PATH_PREFIX_BASE "/" PLUGIN_PATH_PREFIX_SERVICE "/'\n", state); + return bRC_Error; + } + for(;;) + { + switch (state) + { + case 0: + if (context->path_bits[level + 1] == NULL) + { + state = 1; + break; + } + for (prev_sg = NULL, curr_sg = first_storage_group_node; curr_sg != NULL; prev_sg = curr_sg, curr_sg = curr_sg->next) + { + if (strcmp(curr_sg->name, context->path_bits[level + 1]) == 0) + { + break; + } + } + if (curr_sg == NULL) + { + curr_sg = new storage_group_node_t(bstrdup(context->path_bits[level + 1]), this); + if (prev_sg == NULL) + first_storage_group_node = curr_sg; + else + prev_sg->next = curr_sg; + } + context->current_node = curr_sg; + return bRC_OK; + case 1: + rp->create_status = CF_CREATED; + return bRC_OK; + } + } + return bRC_Error; +} + +bRC +service_node_t::endRestoreFile(exchange_fd_context_t *context) +{ + _DebugMessage(0, "endRestoreFile_SERVICE state = %d\n", state); + switch(state) + { + case 0: + return bRC_Error; + case 1: + context->current_node = parent; + return bRC_OK; + } + + return bRC_Error; +} diff --git a/bacula/src/win32/filed/plugins/storage_group_node.c b/bacula/src/win32/filed/plugins/storage_group_node.c new file mode 100644 index 0000000000..d6c453ed9e --- /dev/null +++ b/bacula/src/win32/filed/plugins/storage_group_node.c @@ -0,0 +1,489 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +#include "exchange-fd.h" + +storage_group_node_t::storage_group_node_t(char *name, node_t *parent_node) : node_t(name, NODE_TYPE_STORAGE_GROUP, parent_node) +{ + ibi = NULL; + store_node = NULL; + current_dbi = 0; + restore_environment = NULL; + saved_log_path = NULL; + next = NULL; +} + +storage_group_node_t::~storage_group_node_t() +{ +/* + if (dbi_node != NULL) + delete dbi_node; + + if (file_node != NULL) + delete file_node; +*/ +} + +bRC +storage_group_node_t::startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp) +{ + HRESULT result; + int len; + WCHAR *tmp_logfiles, *tmp_logfile_ptr; + char *tmp; + + for(;;) + { + _DebugMessage(100, "startBackupNode_STORAGE_GROUP state = %d, name = %s\n", state, name); + switch(state) + { + case 0: + current_dbi = 0; + store_node = NULL; + logfile_ptr = NULL; + if (context->job_level == 'F') + { + _DebugMessage(100, "Calling HrESEBackupSetup\n"); + result = HrESEBackupSetup(hccx, ibi->hInstanceId, BACKUP_TYPE_FULL); + state = 1; + } + else + { + _DebugMessage(100, "Calling HrESEBackupSetup\n"); + result = HrESEBackupSetup(hccx, ibi->hInstanceId, BACKUP_TYPE_LOGS_ONLY); + state = 2; + } + if (result != 0) + { + _JobMessage(M_ERROR, "HrESEBackupSetup failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + return bRC_Error; + } + break; + case 1: + if (context->path_bits[level + 1] == NULL) + { + _DebugMessage(100, "No specific database specified - backing them all up\n"); + DATABASE_BACKUP_INFO *dbi = &ibi->rgDatabase[current_dbi]; + char *tmp = new char[wcslen(dbi->wszDatabaseDisplayName) + 1]; + wcstombs(tmp, dbi->wszDatabaseDisplayName, wcslen(dbi->wszDatabaseDisplayName) + 1); + store_node = new store_node_t(tmp, this); + store_node->dbi = dbi; + store_node->hccx = hccx; + context->current_node = store_node; + } + else + { + DATABASE_BACKUP_INFO *dbi = NULL; + char *tmp = NULL; + for (current_dbi = 0; current_dbi < ibi->cDatabase; current_dbi++) + { + dbi = &ibi->rgDatabase[current_dbi]; + char *tmp = new char[wcslen(dbi->wszDatabaseDisplayName) + 1]; + wcstombs(tmp, dbi->wszDatabaseDisplayName, wcslen(dbi->wszDatabaseDisplayName) + 1); + if (stricmp(tmp, context->path_bits[level + 1]) == 0) + break; + delete tmp; + } + if (current_dbi == ibi->cDatabase) + { + _JobMessage(M_ERROR, "Invalid Database '%s'\n", context->path_bits[level + 1]); + return bRC_Error; + } + store_node = new store_node_t(tmp, this); + _DebugMessage(100, "Database name = %s\n", store_node->name); + delete tmp; + store_node->hccx = hccx; + store_node->dbi = dbi; + context->current_node = store_node; + } + return bRC_OK; + case 2: + _DebugMessage(100, "Calling HrESEBackupGetLogAndPatchFiles\n"); + result = HrESEBackupGetLogAndPatchFiles(hccx, &tmp_logfiles); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESEBackupGetLogAndPatchFiles failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + return bRC_Error; + } + for (len = 0, tmp_logfile_ptr = tmp_logfiles; *tmp_logfile_ptr != 0; tmp_logfile_ptr += wcslen(tmp_logfile_ptr) + 1) + { + len += wcslen(tmp_logfile_ptr) + 1; + } + logfiles = new WCHAR[len + 1]; + logfile_ptr = logfiles; + for (tmp_logfile_ptr = tmp_logfiles; *tmp_logfile_ptr != 0; tmp_logfile_ptr += wcslen(tmp_logfile_ptr) + 1) + { + // check file modification date + HANDLE handle; + FILETIME modified_time; + //int64_t tmp_time; + __int64 tmp_time; + bool include_file; + include_file = false; + handle = INVALID_HANDLE_VALUE; + if (context->job_since == 0) + include_file = true; + if (!include_file) + { + handle = CreateFileW(tmp_logfile_ptr, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (handle == INVALID_HANDLE_VALUE) + { + //_JobMessage(M_WARNING, "Could not open '%S' to check last modified date (0x%08x), including anyway\n", tmp_logfile_ptr, GetLastError()); + include_file = true; + } + } + if (!include_file) + { + if (GetFileTime(handle, NULL, NULL, &modified_time) == 0) + { + //_JobMessage(M_WARNING, "Could check last modified date for '%S' (0x%08x), including anyway\n", tmp_logfile_ptr, GetLastError()); + include_file = true; + } + } + if (!include_file) + { + tmp_time = (((int64_t)modified_time.dwHighDateTime) << 32) | modified_time.dwLowDateTime; + //FIXME: this is too big according to mingw + tmp_time -= 116444736000000000LL; + tmp_time /= 10000000; + if (tmp_time > context->job_since) + { + include_file = true; + } + } + if (include_file) + { + memcpy(logfile_ptr, tmp_logfile_ptr, (wcslen(tmp_logfile_ptr) + 1) * 2); + logfile_ptr += wcslen(logfile_ptr) + 1; + //_DebugMessage(100, "Including file %S\n", logfile_ptr); + } + else + { + //_DebugMessage(100, "NOT including file %S\n", logfile_ptr); + } + + if (handle != INVALID_HANDLE_VALUE) + CloseHandle(handle); + + } + *logfile_ptr = 0; + logfile_ptr = logfiles; + state = 3; + break; + case 3: + tmp = new char[wcslen(logfile_ptr) + 1]; + wcstombs(tmp, logfile_ptr, wcslen(logfile_ptr) + 1); + file_node = new file_node_t(tmp, this); + delete tmp; + file_node->hccx = hccx; + file_node->filename = logfile_ptr; + context->current_node = file_node; + return bRC_OK; + case 4: + time_t now = time(NULL); + sp->fname = full_path; + sp->link = full_path; + _DebugMessage(100, "fname = %s\n", sp->fname); + sp->statp.st_mode = 0700 | S_IFDIR; + sp->statp.st_ctime = now; + sp->statp.st_mtime = now; + sp->statp.st_atime = now; + sp->statp.st_size = 0; + //sp->statp.st_blocks = 0; + sp->type = FT_DIREND; + return bRC_OK; + } + } +} + +bRC +storage_group_node_t::endBackupFile(exchange_fd_context_t *context) +{ + HRESULT result; + bRC retval = bRC_Error; + + _DebugMessage(100, "endBackupNode_STORAGE_GROUP state = %d\n", state); + + switch(state) + { + case 0: + // should never happen + break; + case 1: + // free node->storage_group_node + if (context->path_bits[level + 1] == NULL) + { + current_dbi++; + if (current_dbi == ibi->cDatabase) + state = 2; + } + else + state = 2; + retval = bRC_More; + break; + case 2: + // should never happen + break; + case 3: + delete file_node; + logfile_ptr += wcslen(logfile_ptr) + 1; + if (*logfile_ptr == 0) + state = 4; + retval = bRC_More; + break; + case 4: + if (context->truncate_logs) + { + _DebugMessage(100, "Calling HrESEBackupTruncateLogs\n"); + result = HrESEBackupTruncateLogs(hccx); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESEBackupTruncateLogs failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + } + else + { + _JobMessage(M_INFO, "Truncated database logs for Storage Group %s\n", name); + } + } + else + { + _JobMessage(M_INFO, "Did NOT truncate database logs for Storage Group %s\n", name); + } + _DebugMessage(100, "Calling HrESEBackupInstanceEnd\n"); + result = HrESEBackupInstanceEnd(hccx, ESE_BACKUP_INSTANCE_END_SUCCESS); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESEBackupInstanceEnd failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + return bRC_Error; + } + retval = bRC_OK; + context->current_node = parent; + break; + } + return retval; +} + +bRC +storage_group_node_t::createFile(exchange_fd_context_t *context, struct restore_pkt *rp) +{ + HRESULT result; + int len; + + _DebugMessage(0, "createFile_STORAGE_GROUP state = %d\n", state); + + if (strcmp(context->path_bits[level], name) != 0) + { + _DebugMessage(0, "Different storage group - switching back to parent\n", state); + saved_log_path = new WCHAR[wcslen(restore_environment->m_wszRestoreLogPath) + 1]; + wcscpy(saved_log_path, restore_environment->m_wszRestoreLogPath); + _DebugMessage(100, "Calling HrESERestoreSaveEnvironment\n"); + result = HrESERestoreSaveEnvironment(hccx); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESERestoreSaveEnvironment failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + state = 999; + rp->create_status = CF_CREATED; + return bRC_OK; + } + _DebugMessage(100, "Calling HrESERestoreClose\n"); + result = HrESERestoreClose(hccx, RESTORE_CLOSE_NORMAL); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESERestoreClose failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + state = 999; + rp->create_status = CF_CREATED; + return bRC_OK; + } + context->current_node = parent; + return bRC_OK; + } + if (saved_log_path != NULL) + { + _DebugMessage(0, "Calling HrESERestoreReopen\n"); + result = HrESERestoreReopen(context->computer_name, service_name, saved_log_path, &hccx); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESERestoreReopen failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + state = 999; + saved_log_path = NULL; + rp->create_status = CF_CREATED; + return bRC_OK; + } + _DebugMessage(0, "Calling HrESERestoreGetEnvironment\n"); + result = HrESERestoreGetEnvironment(hccx, &restore_environment); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESERestoreGetEnvironment failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + state = 999; + saved_log_path = NULL; + rp->create_status = CF_CREATED; + return bRC_OK; + } + saved_log_path = NULL; + } + + for (;;) + { + switch (state) + { + case 0: + service_name = new WCHAR[strlen(parent->name) + 1]; + storage_group_name = new WCHAR[strlen(name) + 1]; + mbstowcs(service_name, parent->name, strlen(parent->name) + 1); + mbstowcs(storage_group_name, name, strlen(name) + 1); + _DebugMessage(0, "Calling HrESERestoreOpen\n"); + result = HrESERestoreOpen(context->computer_name, service_name, storage_group_name, NULL, &hccx); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESERestoreOpen failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + state = 999; + break; + } + _DebugMessage(0, "Calling HrESERestoreGetEnvironment\n"); + result = HrESERestoreGetEnvironment(hccx, &restore_environment); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESERestoreGetEnvironment failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + state = 999; + break; + } + state = 1; + break; + case 1: + if (context->path_bits[level + 2] == NULL) + { + state = 2; + break; + } + store_node = new store_node_t(bstrdup(context->path_bits[level + 1]), this); + store_node->hccx = hccx; + context->current_node = store_node; + return bRC_OK; + case 2: + if (context->path_bits[level + 2] != NULL) + { + _JobMessage(M_ERROR, "Unexpected file '%s'\n", full_path); + state = 999; + break; + } + if (context->path_bits[level + 1] == NULL) + { + state = 3; + break; + } + state = 2; + file_node = new file_node_t(bstrdup(context->path_bits[level + 1]), this); + file_node->hccx = hccx; + int i; + for (i = strlen(file_node->name) - 1; i >= 0; i--) + { + if (file_node->name[i] == '\\') + { + i++; + break; + } + } + len = wcslen(restore_environment->m_wszRestoreLogPath) + strlen(file_node->name + i) + 1 + 1; + file_node->filename = new WCHAR[len]; + // FIXME: %S not supported under mingw + //swprintf(file_node->filename, len, L"%s\\%S", restore_environment->m_wszRestoreLogPath, file_node->name + i); + context->current_node = file_node; + return bRC_OK; + case 3: + if (rp->type != FT_DIREND) + { + _JobMessage(M_ERROR, "Unexpected file '%s'\n", full_path); + state = 999; + break; + } + // must be the storage group node + _DebugMessage(100, "Calling HrESERestoreSaveEnvironment\n"); + result = HrESERestoreSaveEnvironment(hccx); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESERestoreSaveEnvironment failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + state = 999; + break; + } + + _DebugMessage(100, "Calling HrESERestoreComplete\n"); + result = HrESERestoreComplete(hccx, restore_environment->m_wszRestoreLogPath, + restore_environment->m_wszRestoreLogPath, storage_group_name, ESE_RESTORE_COMPLETE_ATTACH_DBS); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESERestoreComplete failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + state = 999; + break; + } + else + { + _JobMessage(M_INFO, "Storage Group '%s' restored successfully\n", name); + } + + _DebugMessage(100, "Calling HrESERestoreClose\n"); + result = HrESERestoreClose(hccx, RESTORE_CLOSE_NORMAL); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESERestoreClose failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + state = 999; + break; + } + + rp->create_status = CF_CREATED; + return bRC_OK; + case 999: + rp->create_status = CF_CREATED; + return bRC_OK; + } + } +} + +bRC +storage_group_node_t::endRestoreFile(exchange_fd_context_t *context) +{ + _DebugMessage(0, "endRestoreFile_STORAGE_GROUP state = %d\n", state); + switch (state) + { + case 0: + return bRC_Error; + case 1: + return bRC_OK; + case 2: + return bRC_OK; + case 3: + context->current_node = parent; + return bRC_OK; + case 999: + return bRC_OK; + } + + return bRC_Error; +} diff --git a/bacula/src/win32/filed/plugins/store_node.c b/bacula/src/win32/filed/plugins/store_node.c new file mode 100644 index 0000000000..0b8f538229 --- /dev/null +++ b/bacula/src/win32/filed/plugins/store_node.c @@ -0,0 +1,241 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by James Harper, October 2008 + */ + +#include "exchange-fd.h" + +store_node_t::store_node_t(char *name, node_t *parent_node) : node_t(name, NODE_TYPE_STORE, parent_node) +{ + dbi = NULL; + hccx = NULL; + dbi_node = NULL; + file_node = NULL; +} + +store_node_t::~store_node_t() +{ + if (dbi_node != NULL) + delete dbi_node; + + if (file_node != NULL) + delete file_node; +} + +bRC +store_node_t::startBackupFile(exchange_fd_context_t *context, struct save_pkt *sp) +{ + char *tmp; + + _DebugMessage(100, "startBackupNode_STORE state = %d\n", state); + + switch(state) + { + case 0: + stream_ptr = dbi->wszDatabaseStreams; + state = 1; + // fall through + case 1: + dbi_node = new dbi_node_t("DatabaseBackupInfo", this); + dbi_node->dbi = dbi; + context->current_node = dbi_node; + break; + case 2: + tmp = new char[wcslen(stream_ptr) + 1]; + wcstombs(tmp, stream_ptr, wcslen(stream_ptr) + 1); + file_node = new file_node_t(tmp, this); + file_node->hccx = hccx; + file_node->filename = stream_ptr; + context->current_node = file_node; + break; + case 3: + time_t now = time(NULL); + sp->fname = full_path; + sp->link = full_path; + sp->statp.st_mode = 0700 | S_IFDIR; + sp->statp.st_ctime = now; + sp->statp.st_mtime = now; + sp->statp.st_atime = now; + sp->statp.st_size = 0; + sp->type = FT_DIREND; + break; + } + + return bRC_OK; +} + +bRC +store_node_t::endBackupFile(exchange_fd_context_t *context) +{ + _DebugMessage(100, "endBackupNode_STORE state = %d\n", state); + bRC retval = bRC_OK; + + switch(state) + { + case 0: + // should never happen + break; + case 1: + state = 2; + retval = bRC_More; + break; + case 2: + delete file_node; + stream_ptr += wcslen(stream_ptr) + 1; + if (*stream_ptr == 0) + state = 3; + retval = bRC_More; + break; + case 3: + //delete dbi_node; + context->current_node = parent; + break; + } + return retval; +} + +bRC +store_node_t::createFile(exchange_fd_context_t *context, struct restore_pkt *rp) +{ + _DebugMessage(0, "createFile_STORE state = %d\n", state); + + if (strcmp(context->path_bits[level - 1], parent->name) != 0) + { + _DebugMessage(0, "Different storage group - switching back to parent\n", state); + context->current_node = parent; + return bRC_OK; + } + for (;;) + { + switch (state) + { + case 0: + if (strcmp("DatabaseBackupInfo", context->path_bits[level + 1]) != 0) + { + _JobMessage(M_ERROR, "DatabaseBackupInfo file must exist and must be first in directory\n"); + state = 999; + break; + } + dbi_node = new dbi_node_t(bstrdup(context->path_bits[level + 1]), this); + context->current_node = dbi_node; + return bRC_OK; + case 1: + if (strcmp(context->path_bits[level - 1], parent->name) != 0) + { + _JobMessage(M_ERROR, "Unexpected Storage Group Change\n"); + state = 999; + break; + } + + if (*stream_ptr != 0) + { + // verify that stream_ptr == context->path_bits[level + 1]; + _DebugMessage(150, "stream_ptr = %S\n", stream_ptr); + _DebugMessage(150, "out_stream_ptr = %S\n", out_stream_ptr); + file_node = new file_node_t(bstrdup(context->path_bits[level + 1]), this); + file_node->hccx = hccx; + file_node->filename = out_stream_ptr; + context->current_node = file_node; + return bRC_OK; + } + else + { + _JobMessage(M_ERROR, "Extra file found '%s'\n", full_path); + state = 999; + break; + } + case 2: + if (rp->type != FT_DIREND) + { + _JobMessage(M_ERROR, "Unexpected file '%s'\n", full_path); + state = 999; + break; + } + rp->create_status = CF_CREATED; + return bRC_OK; + case 999: + if (strcmp(context->path_bits[level], name) != 0) + { + _DebugMessage(0, "End of Store when in error state - switching back to parent\n", state); + context->current_node = parent; + return bRC_OK; + } + rp->create_status = CF_CREATED; + return bRC_OK; + } + } +} + +bRC +store_node_t::endRestoreFile(exchange_fd_context_t *context) +{ + HRESULT result; + + _DebugMessage(0, "endRestoreFile_STORE state = %d\n", state); + for (;;) + { + switch (state) + { + case 0: + state = 1; + _DebugMessage(0, "Calling HrESERestoreAddDatabase\n"); + result = HrESERestoreAddDatabase(hccx, dbi_node->restore_display_name, dbi_node->restore_guid, dbi_node->restore_input_streams, &dbi_node->restore_output_streams); + if (result != 0) + { + _JobMessage(M_ERROR, "HrESERestoreAddDatabase failed with error 0x%08x - %s\n", result, ESEErrorMessage(result)); + state = 999; + break; + } + stream_ptr = dbi_node->restore_input_streams; + out_stream_ptr = dbi_node->restore_output_streams; + return bRC_OK; + case 1: + if (*stream_ptr != 0) + { + delete file_node; + file_node = NULL; + stream_ptr += wcslen(stream_ptr) + 1; + out_stream_ptr += wcslen(out_stream_ptr) + 1; + if (*stream_ptr == 0) + state = 2; + return bRC_OK; + } + else + { + state = 999; + break; + } + case 2: + context->current_node = parent; + return bRC_OK; + case 999: + return bRC_OK; + } + } +} diff --git a/bacula/src/win32/installer/winbacula.nsi b/bacula/src/win32/installer/winbacula.nsi index 060b8a2bcf..ba32af14c8 100644 --- a/bacula/src/win32/installer/winbacula.nsi +++ b/bacula/src/win32/installer/winbacula.nsi @@ -564,6 +564,7 @@ Section "File Service" SecFileDaemon SetOutPath "$INSTDIR\bin" File "${SRC_DIR}\bacula-fd.exe" +; File "${SRC_DIR}\exchange-fd.dll" ${If} $InstallType = ${MigrateInstall} ${AndIf} ${FileExists} "$OldInstallDir\bin\bacula-fd.conf" @@ -919,6 +920,7 @@ Section "Uninstall" ${If} $R0 = 1 ; Remove bacula service nsExec::ExecToLog '"$INSTDIR\bin\bacula-fd.exe" /remove' + nsExec::ExecToLog '"$INSTDIR\bin\exchange-fd.dll" /remove' ${EndIf} ReadRegDWORD $R0 HKLM "Software\Bacula" "Service_Bacula-sd" diff --git a/bacula/technotes-2.5 b/bacula/technotes-2.5 index f1c6ebe5d0..7c92cbce7c 100644 --- a/bacula/technotes-2.5 +++ b/bacula/technotes-2.5 @@ -51,6 +51,7 @@ libtool on the configure command line with: General: 23Oct08 +kes Integrate James Harper's Exchange Win32 plugin patch. kes Apply patch from Marco van Wieringen that implements the new Solaris libsec interface for ACLs so that Bacula can save and restore both the new ACLs and old ACLs.