]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/filed/plugins/exchange-fd.c
Updated Exchange plugin to support accurate mode
[bacula/bacula] / bacula / src / win32 / filed / plugins / exchange-fd.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2008-2009 Free Software Foundation Europe e.V.
5
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.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /* 
29  *  Written by James Harper, October 2008
30  */
31
32 #include "exchange-fd.h"
33
34 /* Pointers to Bacula functions */
35 bFuncs *bfuncs = NULL;
36 bInfo  *binfo = NULL;
37
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"
43
44 static pInfo pluginInfo = {
45    sizeof(pluginInfo),
46    FD_PLUGIN_INTERFACE_VERSION,
47    FD_PLUGIN_MAGIC,
48    PLUGIN_LICENSE,
49    PLUGIN_AUTHOR,
50    PLUGIN_DATE,
51    PLUGIN_VERSION,
52    PLUGIN_DESCRIPTION,
53 };
54
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);
68
69 static pFuncs pluginFuncs = {
70    sizeof(pluginFuncs),
71    FD_PLUGIN_INTERFACE_VERSION,
72
73    /* Entry points into plugin */
74    newPlugin,                         /* new plugin instance */
75    freePlugin,                        /* free plugin instance */
76    getPluginValue,
77    setPluginValue,
78    handlePluginEvent,
79    startBackupFile,
80    endBackupFile,
81    startRestoreFile,
82    endRestoreFile,
83    pluginIO,
84    createFile,
85    setFileAttributes
86 };
87
88 extern "C" {
89
90 static char **
91 splitString(char *string, char split, int maxParts, int *count)
92 {
93   char **RetVal;
94   char *first;
95   char *last;
96
97   //KdPrint((__DRIVER_NAME "     a\n"));
98
99   *count = 0;
100
101   RetVal = (char **)malloc((maxParts + 1) * sizeof(char *));
102   last = string;
103   do
104   {
105     if (*count == maxParts)
106       break;
107     first = last;
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;
112     (*count)++;
113     if (*last == split)
114       last++;
115   } while (*last != 0);
116   RetVal[*count] = NULL;
117   return RetVal;
118 }
119
120 bRC DLL_IMP_EXP
121 loadPlugin(bInfo *lbinfo, bFuncs *lbfuncs, pInfo **pinfo, pFuncs **pfuncs)
122 {
123         bRC retval;
124         bfuncs = lbfuncs;                  /* set Bacula funct pointers */
125         binfo  = lbinfo;
126         *pinfo = &pluginInfo;
127         *pfuncs = &pluginFuncs;
128         retval = loadExchangeApi();
129         if (retval != bRC_OK)
130         {
131                 printf("Cannot load Exchange DLL\n");
132                 return retval;
133         }
134         return retval;
135 }
136
137 bRC DLL_IMP_EXP
138 unloadPlugin()
139 {
140         return bRC_OK;
141 }
142
143 }
144 /*
145 void *
146 b_malloc(const char *file, int lone, size_t size)
147 {
148         return NULL;
149 }
150
151 void *
152 sm_malloc(const char *file, int lone, size_t size)
153 {
154         return NULL;
155 }
156 */
157
158 static bRC newPlugin(bpContext *ctx)
159 {
160         exchange_fd_context_t *context;
161         bRC retval = bRC_OK;
162         DWORD size;
163
164         int JobId = 0;
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;
178         return retval;
179 }
180
181 static bRC freePlugin(bpContext *ctx)
182 {
183         exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
184         int JobId = 0;
185         bfuncs->getBaculaValue(ctx, bVarJobId, (void *)&JobId);
186         _DebugMessage(100, "freePlugin JobId=%d\n", JobId);
187         delete context;
188         return bRC_OK;
189 }
190
191 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value) 
192 {
193         exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
194         _DebugMessage(100, "getPluginValue var=%d\n", var);
195         return bRC_OK;
196 }
197
198 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value) 
199 {
200         exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
201         _DebugMessage(100, "setPluginValue var=%d\n", var);
202         return bRC_OK;
203 }
204
205 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
206 {
207         exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
208         char *name;
209         int i, intval;
210         int accurate;
211
212         switch (event->eventType) {
213         case bEventJobStart:
214                 _DebugMessage(0, "JobStart=%s\n", (char *)value);
215                 break;
216         case bEventJobEnd:
217                 _DebugMessage(0, "JobEnd\n");
218                 break;
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)
227                 {
228                 case 'F':
229                         if (context->notrunconfull_option) {
230                                 context->truncate_logs = false;
231                         } else {
232                                 context->truncate_logs = true;
233                         }
234                         break;
235                 case 'D':
236                         context->truncate_logs = false;
237                         break;
238                 case 'I':
239                         context->truncate_logs = false;
240                         break;
241                 default:
242                         _DebugMessage(0, "Invalid job level %c\n", context->job_level);
243                         return bRC_Error;
244                 }
245                 break;
246         case bEventEndBackupJob:
247                 _DebugMessage(0, "BackupEnd\n");
248                 break;
249         case bEventLevel:
250                 intval = (intptr_t)value;
251                 _DebugMessage(0, "JobLevel=%c %d\n", intval, intval);
252                 context->job_level = intval;
253                 break;
254         case bEventSince:
255                 intval = (intptr_t)value;
256                 _DebugMessage(0, "since=%d\n", intval);
257                 context->job_since = (time_t)value;
258                 break;
259         case bEventStartRestoreJob:
260                 _DebugMessage(0, "StartRestoreJob\n");
261                 context->job_type = JOB_TYPE_RESTORE;
262                 break;
263         case bEventEndRestoreJob:
264                 _DebugMessage(0, "EndRestoreJob\n");
265                 break;
266         
267         /* Plugin command e.g. plugin = <plugin-name>:<name-space>:command */
268         case bEventRestoreCommand:
269                 _DebugMessage(0, "restore\n"); // command=%s\n", (char *)value);
270                 break;
271
272         case bEventBackupCommand:
273                 {
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, ":");
279                 char *option;
280                 while ((option = strtok(NULL, ":")) != NULL)
281                 {
282                         _DebugMessage(100, "option %s\n", option);
283                         if (stricmp(option, "notrunconfull") == 0)
284                         {
285                                 context->notrunconfull_option = true;
286                         }
287                         else
288                         {
289                                 _JobMessage(M_WARNING, "Unknown plugin option '%s'\n", option);
290                         }
291                 }
292                 _DebugMessage(0, "name = %s\n", plugin_name);
293                 _DebugMessage(0, "path = %s\n", path);
294                 if (*path != '/')
295                 {
296                         _JobMessage(M_ERROR, "Path does not begin with a '/'\n");
297                         return bRC_Error;
298                 }
299
300                 for (i = 0; i < 6; i++)
301                         context->path_bits[i] = NULL;
302
303                 char *path_bit = strtok(path, "/");
304                 for (i = 0; path_bit != NULL && i < 6; i++)
305                 {
306                         context->path_bits[i] = new char[strlen(path_bit) + 1];
307                         strcpy(context->path_bits[i], path_bit);
308                         path_bit = strtok(NULL, "/");
309                 }
310
311                 if (i < 2 || i > 4)
312                 {
313                         _JobMessage(M_ERROR, "Invalid plugin backup path\n");
314                         return bRC_Error;
315                 }
316                 context->root_node = new root_node_t(context->path_bits[0]);
317                 context->current_node = context->root_node;
318
319                 }
320                 break;
321
322    default:
323            _JobMessage(M_ERROR, "unknown event=%d\n", event->eventType);
324    }
325    bfuncs->getBaculaValue(ctx, bVarFDName, (void *)&name);
326    return bRC_OK;
327 }
328
329 static bRC
330 startBackupFile(bpContext *ctx, struct save_pkt *sp)
331 {
332         bRC retval;
333         exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
334         node_t *current_node;
335
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))
338         {
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);
340                 return bRC_Error;
341         }
342
343         //context->root_node = new root_node_t(PLUGIN_PATH_PREFIX_BASE);
344         //context->current_node = context->root_node;
345         do {
346                 current_node  = context->current_node;
347                 retval = current_node->startBackupFile(context, sp);
348                 if (retval == bRC_Seen)
349                         endBackupFile(ctx);
350         } while (current_node != context->current_node);
351         _DebugMessage(100, "startBackupFile done - type = %d, fname = %s, retval = %d\n", sp->type, sp->fname, retval);
352         return retval;
353 }
354
355 static bRC endBackupFile(bpContext *ctx)
356
357         bRC retval;
358         exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
359         node_t *current_node;
360
361         _DebugMessage(100, "endBackupFile\n");
362
363         do {
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);
368         return retval;
369 }
370
371 /*
372  * Do actual I/O
373  */
374 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
375 {
376         bRC retval = bRC_OK;
377         exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
378
379         if (io->pkt_size != sizeof(struct io_pkt) || io->pkt_end != sizeof(struct io_pkt))
380         {
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);
382         }
383
384         switch(io->func) {
385         case IO_OPEN:
386                 _DebugMessage(100, "IO_OPEN\n");
387                 retval = context->current_node->pluginIoOpen(context, io);
388                 break;
389         case IO_READ:
390                 //_DebugMessage(100, "IO_READ buf=%p len=%d\n", io->buf, io->count);
391                 retval = context->current_node->pluginIoRead(context, io);
392                 break;
393         case IO_WRITE:
394                 //_DebugMessage(100, "IO_WRITE buf=%p len=%d\n", io->buf, io->count);
395                 retval = context->current_node->pluginIoWrite(context, io);
396                 break;
397         case IO_CLOSE:
398                 _DebugMessage(100, "IO_CLOSE\n");
399                 retval = context->current_node->pluginIoClose(context, io);
400                 break;
401         }
402         return retval;
403 }
404
405 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
406 {
407         exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
408         _DebugMessage(100, "startRestoreFile\n");
409
410         return bRC_OK;
411 }
412
413 static bRC endRestoreFile(bpContext *ctx)
414 {
415         bRC retval;
416         exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
417         node_t *current_node;
418
419         _DebugMessage(100, "endRestoreFile\n");
420
421         do {
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);
426         return retval;
427 }
428
429 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
430 {
431         bRC retval;
432         exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
433         node_t *current_node;
434         char **path_bits;
435         int count;
436         int i;
437
438
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))
441         {
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);
443         }
444
445         for (i = 0; i < 6; i++)
446         {
447                 context->path_bits[i] = NULL;
448         }
449
450         path_bits = splitString((char *)rp->ofname, '/', 7, &count);
451
452         _DebugMessage(100, "count = %d\n", count);
453
454         for (i = 1; i < count; i++)
455         {
456                 _DebugMessage(150, "%d = '%s'\n", i, path_bits[i]);
457                 context->path_bits[i - 1] = path_bits[i];
458         }
459
460         if (context->current_node == NULL)
461         {
462                 context->root_node = new root_node_t(context->path_bits[0]);
463                 context->current_node = context->root_node;
464         }
465
466         do {
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);
471         return retval;
472 }
473
474 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
475 {
476         exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
477         _DebugMessage(100, "setFileAttributes\n");
478         return bRC_OK;
479 }