2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2009 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation, which is
11 listed in the file LICENSE.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Written by James Harper, October 2008
32 #include "exchange-fd.h"
34 /* Pointers to Bacula functions */
35 bFuncs *bfuncs = NULL;
38 #define PLUGIN_LICENSE "Bacula GPLv2"
39 #define PLUGIN_AUTHOR "James Harper"
40 #define PLUGIN_DATE "September 2008"
41 #define PLUGIN_VERSION "1"
42 #define PLUGIN_DESCRIPTION "Exchange Plugin"
44 static pInfo pluginInfo = {
46 FD_PLUGIN_INTERFACE_VERSION,
55 /* Forward referenced functions */
56 static bRC newPlugin(bpContext *ctx);
57 static bRC freePlugin(bpContext *ctx);
58 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value);
59 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value);
60 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value);
61 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp);
62 static bRC endBackupFile(bpContext *ctx);
63 static bRC pluginIO(bpContext *ctx, struct io_pkt *io);
64 static bRC startRestoreFile(bpContext *ctx, const char *cmd);
65 static bRC endRestoreFile(bpContext *ctx);
66 static bRC createFile(bpContext *ctx, struct restore_pkt *rp);
67 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
69 static pFuncs pluginFuncs = {
71 FD_PLUGIN_INTERFACE_VERSION,
73 /* Entry points into plugin */
74 newPlugin, /* new plugin instance */
75 freePlugin, /* free plugin instance */
91 splitString(char *string, char split, int maxParts, int *count)
97 //KdPrint((__DRIVER_NAME " a\n"));
101 RetVal = (char **)malloc((maxParts + 1) * sizeof(char *));
105 if (*count == maxParts)
108 for (last = first; *last != '\0' && *last != split; last++);
109 RetVal[*count] = (char *)malloc(last - first + 1);
110 strncpy(RetVal[*count], first, last - first);
111 RetVal[*count][last - first] = 0;
115 } while (*last != 0);
116 RetVal[*count] = NULL;
121 loadPlugin(bInfo *lbinfo, bFuncs *lbfuncs, pInfo **pinfo, pFuncs **pfuncs)
124 bfuncs = lbfuncs; /* set Bacula funct pointers */
126 *pinfo = &pluginInfo;
127 *pfuncs = &pluginFuncs;
128 retval = loadExchangeApi();
129 if (retval != bRC_OK)
131 printf("Cannot load Exchange DLL\n");
146 b_malloc(const char *file, int lone, size_t size)
152 sm_malloc(const char *file, int lone, size_t size)
158 static bRC newPlugin(bpContext *ctx)
160 exchange_fd_context_t *context;
165 ctx->pContext = new exchange_fd_context_t;
166 context = (exchange_fd_context_t *)ctx->pContext;
167 context->bpContext = ctx;
168 context->job_since = 0;
169 context->notrunconfull_option = false;
170 bfuncs->getBaculaValue(ctx, bVarJobId, (void *)&JobId);
171 _DebugMessage(0, "newPlugin JobId=%d\n", JobId);
172 bfuncs->registerBaculaEvents(ctx, 1, 2, 0);
173 size = MAX_COMPUTERNAME_LENGTH + 1;
174 context->computer_name = new WCHAR[size];
175 GetComputerNameW(context->computer_name, &size);
176 context->current_node = NULL;
177 context->root_node = NULL;
181 static bRC freePlugin(bpContext *ctx)
183 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
185 bfuncs->getBaculaValue(ctx, bVarJobId, (void *)&JobId);
186 _DebugMessage(100, "freePlugin JobId=%d\n", JobId);
191 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value)
193 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
194 _DebugMessage(100, "getPluginValue var=%d\n", var);
198 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value)
200 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
201 _DebugMessage(100, "setPluginValue var=%d\n", var);
205 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
207 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
211 switch (event->eventType) {
213 _DebugMessage(0, "JobStart=%s\n", (char *)value);
216 _DebugMessage(0, "JobEnd\n");
218 case bEventStartBackupJob:
219 _DebugMessage(0, "BackupStart\n");
220 context->job_type = JOB_TYPE_BACKUP;
221 // level should have been specified by now - check it
222 // if level is D or I, since should have been specified too
223 switch (context->job_level)
226 if (context->notrunconfull_option) {
227 context->truncate_logs = false;
229 context->truncate_logs = true;
233 context->truncate_logs = false;
236 context->truncate_logs = false;
239 _DebugMessage(0, "Invalid job level %c\n", context->job_level);
243 case bEventEndBackupJob:
244 _DebugMessage(0, "BackupEnd\n");
247 intval = (intptr_t)value;
248 _DebugMessage(0, "JobLevel=%c %d\n", intval, intval);
249 context->job_level = intval;
252 intval = (intptr_t)value;
253 _DebugMessage(0, "since=%d\n", intval);
254 context->job_since = (time_t)value;
256 case bEventStartRestoreJob:
257 _DebugMessage(0, "StartRestoreJob\n");
258 context->job_type = JOB_TYPE_RESTORE;
260 case bEventEndRestoreJob:
261 _DebugMessage(0, "EndRestoreJob\n");
264 /* Plugin command e.g. plugin = <plugin-name>:<name-space>:command */
265 case bEventRestoreCommand:
266 _DebugMessage(0, "restore\n"); // command=%s\n", (char *)value);
269 case bEventBackupCommand:
271 _DebugMessage(0, "backup command=%s\n", (char *)value);
272 char *command = new char[strlen((char *)value)];
273 strcpy(command, (char *)value);
274 char *plugin_name = strtok((char *)command, ":");
275 char *path = strtok(NULL, ":");
277 while ((option = strtok(NULL, ":")) != NULL)
279 _DebugMessage(100, "option %s\n", option);
280 if (stricmp(option, "notrunconfull") == 0)
282 context->notrunconfull_option = true;
286 _JobMessage(M_WARNING, "Unknown plugin option '%s'\n", option);
289 _DebugMessage(0, "name = %s\n", plugin_name);
290 _DebugMessage(0, "path = %s\n", path);
293 _JobMessage(M_ERROR, "Path does not begin with a '/'\n");
297 for (i = 0; i < 6; i++)
298 context->path_bits[i] = NULL;
300 char *path_bit = strtok(path, "/");
301 for (i = 0; path_bit != NULL && i < 6; i++)
303 context->path_bits[i] = new char[strlen(path_bit) + 1];
304 strcpy(context->path_bits[i], path_bit);
305 path_bit = strtok(NULL, "/");
310 _JobMessage(M_ERROR, "Invalid plugin backup path\n");
313 context->root_node = new root_node_t(context->path_bits[0]);
314 context->current_node = context->root_node;
320 _JobMessage(M_ERROR, "unknown event=%d\n", event->eventType);
322 bfuncs->getBaculaValue(ctx, bVarFDName, (void *)&name);
327 startBackupFile(bpContext *ctx, struct save_pkt *sp)
330 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
331 node_t *current_node;
333 _DebugMessage(100, "startBackupFile, cmd = %s\n", sp->cmd);
334 if (sp->pkt_size != sizeof(struct save_pkt) || sp->pkt_end != sizeof(struct save_pkt))
336 _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);
340 //context->root_node = new root_node_t(PLUGIN_PATH_PREFIX_BASE);
341 //context->current_node = context->root_node;
343 current_node = context->current_node;
344 retval = current_node->startBackupFile(context, sp);
345 } while (current_node != context->current_node);
346 _DebugMessage(100, "startBackupFile done - type = %d, fname = %s, retval = %d\n", sp->type, sp->fname, retval);
350 static bRC endBackupFile(bpContext *ctx)
353 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
354 node_t *current_node;
356 _DebugMessage(100, "endBackupFile\n");
359 current_node = context->current_node;
360 retval = current_node->endBackupFile(context);
361 } while (current_node != context->current_node);
362 _DebugMessage(100, "endBackupFile done - retval = %d\n", retval);
369 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
372 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
374 if (io->pkt_size != sizeof(struct io_pkt) || io->pkt_end != sizeof(struct io_pkt))
376 _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);
381 _DebugMessage(100, "IO_OPEN\n");
382 retval = context->current_node->pluginIoOpen(context, io);
385 //_DebugMessage(100, "IO_READ buf=%p len=%d\n", io->buf, io->count);
386 retval = context->current_node->pluginIoRead(context, io);
389 //_DebugMessage(100, "IO_WRITE buf=%p len=%d\n", io->buf, io->count);
390 retval = context->current_node->pluginIoWrite(context, io);
393 _DebugMessage(100, "IO_CLOSE\n");
394 retval = context->current_node->pluginIoClose(context, io);
400 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
402 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
403 _DebugMessage(100, "startRestoreFile\n");
408 static bRC endRestoreFile(bpContext *ctx)
411 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
412 node_t *current_node;
414 _DebugMessage(100, "endRestoreFile\n");
417 current_node = context->current_node;
418 retval = current_node->endRestoreFile(context);
419 } while (current_node != context->current_node);
420 _DebugMessage(100, "endRestoreFile done - retval = %d\n", retval);
424 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
427 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
428 node_t *current_node;
434 _DebugMessage(100, "createFile - type = %d, ofname = %s\n", rp->type, rp->ofname);
435 if (rp->pkt_size != sizeof(struct restore_pkt) || rp->pkt_end != sizeof(struct restore_pkt))
437 _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);
440 for (i = 0; i < 6; i++)
442 context->path_bits[i] = NULL;
445 path_bits = splitString((char *)rp->ofname, '/', 7, &count);
447 _DebugMessage(100, "count = %d\n", count);
449 for (i = 1; i < count; i++)
451 _DebugMessage(150, "%d = '%s'\n", i, path_bits[i]);
452 context->path_bits[i - 1] = path_bits[i];
455 if (context->current_node == NULL)
457 context->root_node = new root_node_t(context->path_bits[0]);
458 context->current_node = context->root_node;
462 current_node = context->current_node;
463 retval = current_node->createFile(context, rp);
464 } while (current_node != context->current_node);
465 _DebugMessage(100, "createFile done - retval = %d\n", retval);
469 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
471 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
472 _DebugMessage(100, "setFileAttributes\n");