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];
176 GetComputerNameW(context->computer_name, &size);
178 GetComputerNameExW(ComputerNameNetBIOS, context->computer_name, &size);
179 context->current_node = NULL;
180 context->root_node = NULL;
184 static bRC freePlugin(bpContext *ctx)
186 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
188 bfuncs->getBaculaValue(ctx, bVarJobId, (void *)&JobId);
189 _DebugMessage(100, "freePlugin JobId=%d\n", JobId);
194 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value)
196 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
197 _DebugMessage(100, "getPluginValue var=%d\n", var);
201 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value)
203 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
204 _DebugMessage(100, "setPluginValue var=%d\n", var);
208 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
210 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
215 switch (event->eventType) {
217 _DebugMessage(0, "JobStart=%s\n", (char *)value);
220 _DebugMessage(0, "JobEnd\n");
222 case bEventStartBackupJob:
223 _DebugMessage(0, "BackupStart\n");
224 bfuncs->getBaculaValue(ctx, bVarAccurate, (void *)&accurate);
225 context->accurate = accurate;
226 context->job_type = JOB_TYPE_BACKUP;
227 // level should have been specified by now - check it
228 // if level is D or I, since should have been specified too
229 switch (context->job_level)
232 if (context->notrunconfull_option) {
233 context->truncate_logs = false;
235 context->truncate_logs = true;
239 context->truncate_logs = false;
242 context->truncate_logs = false;
245 _DebugMessage(0, "Invalid job level %c\n", context->job_level);
249 case bEventEndBackupJob:
250 _DebugMessage(0, "BackupEnd\n");
253 intval = (intptr_t)value;
254 _DebugMessage(0, "JobLevel=%c %d\n", intval, intval);
255 context->job_level = intval;
258 intval = (intptr_t)value;
259 _DebugMessage(0, "since=%d\n", intval);
260 context->job_since = (time_t)value;
262 case bEventStartRestoreJob:
263 _DebugMessage(0, "StartRestoreJob\n");
264 context->job_type = JOB_TYPE_RESTORE;
266 case bEventEndRestoreJob:
267 _DebugMessage(0, "EndRestoreJob\n");
270 /* Plugin command e.g. plugin = <plugin-name>:<name-space>:command */
271 case bEventRestoreCommand:
272 _DebugMessage(0, "restore\n"); // command=%s\n", (char *)value);
275 case bEventBackupCommand:
277 _DebugMessage(0, "backup command=%s\n", (char *)value);
278 char *command = new char[strlen((char *)value)];
279 strcpy(command, (char *)value);
280 char *plugin_name = strtok((char *)command, ":");
281 char *path = strtok(NULL, ":");
283 while ((option = strtok(NULL, ":")) != NULL)
285 _DebugMessage(100, "option %s\n", option);
286 if (stricmp(option, "notrunconfull") == 0)
288 context->notrunconfull_option = true;
292 _JobMessage(M_WARNING, "Unknown plugin option '%s'\n", option);
295 _DebugMessage(0, "name = %s\n", plugin_name);
296 _DebugMessage(0, "path = %s\n", path);
299 _JobMessage(M_ERROR, "Path does not begin with a '/'\n");
303 for (i = 0; i < 6; i++)
304 context->path_bits[i] = NULL;
306 char *path_bit = strtok(path, "/");
307 for (i = 0; path_bit != NULL && i < 6; i++)
309 context->path_bits[i] = new char[strlen(path_bit) + 1];
310 strcpy(context->path_bits[i], path_bit);
311 path_bit = strtok(NULL, "/");
316 _JobMessage(M_ERROR, "Invalid plugin backup path\n");
319 context->root_node = new root_node_t(context->path_bits[0]);
320 context->current_node = context->root_node;
326 _JobMessage(M_ERROR, "unknown event=%d\n", event->eventType);
328 bfuncs->getBaculaValue(ctx, bVarFDName, (void *)&name);
333 startBackupFile(bpContext *ctx, struct save_pkt *sp)
336 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
337 node_t *current_node;
339 _DebugMessage(100, "startBackupFile, cmd = %s\n", sp->cmd);
340 if (sp->pkt_size != sizeof(struct save_pkt) || sp->pkt_end != sizeof(struct save_pkt))
342 _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);
346 //context->root_node = new root_node_t(PLUGIN_PATH_PREFIX_BASE);
347 //context->current_node = context->root_node;
349 current_node = context->current_node;
350 retval = current_node->startBackupFile(context, sp);
351 if (retval == bRC_Seen)
353 } while (current_node != context->current_node);
354 _DebugMessage(100, "startBackupFile done - type = %d, fname = %s, retval = %d\n", sp->type, sp->fname, retval);
358 static bRC endBackupFile(bpContext *ctx)
361 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
362 node_t *current_node;
364 _DebugMessage(100, "endBackupFile\n");
367 current_node = context->current_node;
368 retval = current_node->endBackupFile(context);
369 } while (current_node != context->current_node);
370 _DebugMessage(100, "endBackupFile done - retval = %d\n", retval);
377 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
380 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
382 if (io->pkt_size != sizeof(struct io_pkt) || io->pkt_end != sizeof(struct io_pkt))
384 _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);
389 _DebugMessage(100, "IO_OPEN\n");
390 retval = context->current_node->pluginIoOpen(context, io);
393 //_DebugMessage(100, "IO_READ buf=%p len=%d\n", io->buf, io->count);
394 retval = context->current_node->pluginIoRead(context, io);
397 //_DebugMessage(100, "IO_WRITE buf=%p len=%d\n", io->buf, io->count);
398 retval = context->current_node->pluginIoWrite(context, io);
401 _DebugMessage(100, "IO_CLOSE\n");
402 retval = context->current_node->pluginIoClose(context, io);
408 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
410 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
411 _DebugMessage(100, "startRestoreFile\n");
416 static bRC endRestoreFile(bpContext *ctx)
419 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
420 node_t *current_node;
422 _DebugMessage(100, "endRestoreFile\n");
425 current_node = context->current_node;
426 retval = current_node->endRestoreFile(context);
427 } while (current_node != context->current_node);
428 _DebugMessage(100, "endRestoreFile done - retval = %d\n", retval);
432 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
435 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
436 node_t *current_node;
442 _DebugMessage(100, "createFile - type = %d, ofname = %s\n", rp->type, rp->ofname);
443 if (rp->pkt_size != sizeof(struct restore_pkt) || rp->pkt_end != sizeof(struct restore_pkt))
445 _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);
448 for (i = 0; i < 6; i++)
450 context->path_bits[i] = NULL;
453 path_bits = splitString((char *)rp->ofname, '/', 7, &count);
455 _DebugMessage(100, "count = %d\n", count);
457 for (i = 1; i < count; i++)
459 _DebugMessage(150, "%d = '%s'\n", i, path_bits[i]);
460 context->path_bits[i - 1] = path_bits[i];
463 if (context->current_node == NULL)
465 context->root_node = new root_node_t(context->path_bits[0]);
466 context->current_node = context->root_node;
470 current_node = context->current_node;
471 retval = current_node->createFile(context, rp);
472 } while (current_node != context->current_node);
473 _DebugMessage(100, "createFile done - retval = %d\n", retval);
477 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
479 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
480 _DebugMessage(100, "setFileAttributes\n");