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;
212 switch (event->eventType) {
214 _DebugMessage(0, "JobStart=%s\n", (char *)value);
217 _DebugMessage(0, "JobEnd\n");
219 case bEventStartBackupJob:
220 _DebugMessage(0, "BackupStart\n");
221 bfuncs->getBaculaValue(ctx, bVarAccurate, (void *)&accurate);
222 context->accurate = accurate;
223 context->job_type = JOB_TYPE_BACKUP;
224 // level should have been specified by now - check it
225 // if level is D or I, since should have been specified too
226 switch (context->job_level)
229 if (context->notrunconfull_option) {
230 context->truncate_logs = false;
232 context->truncate_logs = true;
236 context->truncate_logs = false;
239 context->truncate_logs = false;
242 _DebugMessage(0, "Invalid job level %c\n", context->job_level);
246 case bEventEndBackupJob:
247 _DebugMessage(0, "BackupEnd\n");
250 intval = (intptr_t)value;
251 _DebugMessage(0, "JobLevel=%c %d\n", intval, intval);
252 context->job_level = intval;
255 intval = (intptr_t)value;
256 _DebugMessage(0, "since=%d\n", intval);
257 context->job_since = (time_t)value;
259 case bEventStartRestoreJob:
260 _DebugMessage(0, "StartRestoreJob\n");
261 context->job_type = JOB_TYPE_RESTORE;
263 case bEventEndRestoreJob:
264 _DebugMessage(0, "EndRestoreJob\n");
267 /* Plugin command e.g. plugin = <plugin-name>:<name-space>:command */
268 case bEventRestoreCommand:
269 _DebugMessage(0, "restore\n"); // command=%s\n", (char *)value);
272 case bEventBackupCommand:
274 _DebugMessage(0, "backup command=%s\n", (char *)value);
275 char *command = new char[strlen((char *)value)];
276 strcpy(command, (char *)value);
277 char *plugin_name = strtok((char *)command, ":");
278 char *path = strtok(NULL, ":");
280 while ((option = strtok(NULL, ":")) != NULL)
282 _DebugMessage(100, "option %s\n", option);
283 if (stricmp(option, "notrunconfull") == 0)
285 context->notrunconfull_option = true;
289 _JobMessage(M_WARNING, "Unknown plugin option '%s'\n", option);
292 _DebugMessage(0, "name = %s\n", plugin_name);
293 _DebugMessage(0, "path = %s\n", path);
296 _JobMessage(M_ERROR, "Path does not begin with a '/'\n");
300 for (i = 0; i < 6; i++)
301 context->path_bits[i] = NULL;
303 char *path_bit = strtok(path, "/");
304 for (i = 0; path_bit != NULL && i < 6; i++)
306 context->path_bits[i] = new char[strlen(path_bit) + 1];
307 strcpy(context->path_bits[i], path_bit);
308 path_bit = strtok(NULL, "/");
313 _JobMessage(M_ERROR, "Invalid plugin backup path\n");
316 context->root_node = new root_node_t(context->path_bits[0]);
317 context->current_node = context->root_node;
323 _JobMessage(M_ERROR, "unknown event=%d\n", event->eventType);
325 bfuncs->getBaculaValue(ctx, bVarFDName, (void *)&name);
330 startBackupFile(bpContext *ctx, struct save_pkt *sp)
333 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
334 node_t *current_node;
336 _DebugMessage(100, "startBackupFile, cmd = %s\n", sp->cmd);
337 if (sp->pkt_size != sizeof(struct save_pkt) || sp->pkt_end != sizeof(struct save_pkt))
339 _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);
343 //context->root_node = new root_node_t(PLUGIN_PATH_PREFIX_BASE);
344 //context->current_node = context->root_node;
346 current_node = context->current_node;
347 retval = current_node->startBackupFile(context, sp);
348 if (retval == bRC_Seen)
350 } while (current_node != context->current_node);
351 _DebugMessage(100, "startBackupFile done - type = %d, fname = %s, retval = %d\n", sp->type, sp->fname, retval);
355 static bRC endBackupFile(bpContext *ctx)
358 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
359 node_t *current_node;
361 _DebugMessage(100, "endBackupFile\n");
364 current_node = context->current_node;
365 retval = current_node->endBackupFile(context);
366 } while (current_node != context->current_node);
367 _DebugMessage(100, "endBackupFile done - retval = %d\n", retval);
374 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
377 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
379 if (io->pkt_size != sizeof(struct io_pkt) || io->pkt_end != sizeof(struct io_pkt))
381 _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);
386 _DebugMessage(100, "IO_OPEN\n");
387 retval = context->current_node->pluginIoOpen(context, io);
390 //_DebugMessage(100, "IO_READ buf=%p len=%d\n", io->buf, io->count);
391 retval = context->current_node->pluginIoRead(context, io);
394 //_DebugMessage(100, "IO_WRITE buf=%p len=%d\n", io->buf, io->count);
395 retval = context->current_node->pluginIoWrite(context, io);
398 _DebugMessage(100, "IO_CLOSE\n");
399 retval = context->current_node->pluginIoClose(context, io);
405 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
407 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
408 _DebugMessage(100, "startRestoreFile\n");
413 static bRC endRestoreFile(bpContext *ctx)
416 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
417 node_t *current_node;
419 _DebugMessage(100, "endRestoreFile\n");
422 current_node = context->current_node;
423 retval = current_node->endRestoreFile(context);
424 } while (current_node != context->current_node);
425 _DebugMessage(100, "endRestoreFile done - retval = %d\n", retval);
429 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
432 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
433 node_t *current_node;
439 _DebugMessage(100, "createFile - type = %d, ofname = %s\n", rp->type, rp->ofname);
440 if (rp->pkt_size != sizeof(struct restore_pkt) || rp->pkt_end != sizeof(struct restore_pkt))
442 _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);
445 for (i = 0; i < 6; i++)
447 context->path_bits[i] = NULL;
450 path_bits = splitString((char *)rp->ofname, '/', 7, &count);
452 _DebugMessage(100, "count = %d\n", count);
454 for (i = 1; i < count; i++)
456 _DebugMessage(150, "%d = '%s'\n", i, path_bits[i]);
457 context->path_bits[i - 1] = path_bits[i];
460 if (context->current_node == NULL)
462 context->root_node = new root_node_t(context->path_bits[0]);
463 context->current_node = context->root_node;
467 current_node = context->current_node;
468 retval = current_node->createFile(context, rp);
469 } while (current_node != context->current_node);
470 _DebugMessage(100, "createFile done - retval = %d\n", retval);
474 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
476 exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
477 _DebugMessage(100, "setFileAttributes\n");