]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/filed/plugins/exchange-fd.c
Attempt to disactivate old exchange-fd.dll if no plugin= line in FileSet
[bacula/bacula] / bacula / src / win32 / filed / plugins / exchange-fd.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2010-2011 Bacula Systems(R) SA
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 three of the GNU Affero 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 Affero 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 AGPLv3"
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       printf("Cannot load Exchange DLL\n");
131       return retval;
132    }
133    return retval;
134 }
135
136 bRC DLL_IMP_EXP
137 unloadPlugin()
138 {
139    return bRC_OK;
140 }
141
142 }
143 /*
144 void *
145 b_malloc(const char *file, int lone, size_t size)
146 {
147    return NULL;
148 }
149
150 void *
151 sm_malloc(const char *file, int lone, size_t size)
152 {
153    return NULL;
154 }
155 */
156
157 static bRC newPlugin(bpContext *ctx)
158 {
159    exchange_fd_context_t *context;
160    bRC retval = bRC_OK;
161    DWORD size;
162
163    int JobId = 0;
164    ctx->pContext = new exchange_fd_context_t;
165    context = (exchange_fd_context_t *)ctx->pContext;
166    context->bpContext = ctx;
167    context->job_since = 0;
168    context->notrunconfull_option = false;
169    context->plugin_active = 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    /*
176    GetComputerNameW(context->computer_name, &size);
177    */
178    GetComputerNameExW(ComputerNameNetBIOS, context->computer_name, &size);
179    context->current_node = NULL;
180    context->root_node = NULL;
181    return retval;
182 }
183
184 static bRC freePlugin(bpContext *ctx)
185 {
186    exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
187    int JobId = 0;
188    bfuncs->getBaculaValue(ctx, bVarJobId, (void *)&JobId);
189    _DebugMessage(100, "freePlugin JobId=%d\n", JobId);
190    delete context;
191    return bRC_OK;
192 }
193
194 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value) 
195 {
196    exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
197    _DebugMessage(100, "getPluginValue var=%d\n", var);
198    return bRC_OK;
199 }
200
201 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value) 
202 {
203    exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
204    _DebugMessage(100, "setPluginValue var=%d\n", var);
205    return bRC_OK;
206 }
207
208 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
209 {
210    exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
211    char *name;
212    int i, intval;
213    int accurate;
214    char *command;
215    char *plugin_name;
216
217    switch (event->eventType) {
218    case bEventJobStart:
219       _DebugMessage(0, "JobStart=%s\n", (char *)value);
220       context->plugin_active = false;
221       break;
222    case bEventJobEnd:
223       _DebugMessage(0, "JobEnd\n");
224       break;
225    case bEventPluginCommand:
226       _DebugMessage(0, "bEventPluginCommand %s\n", value);
227       command = bstrdup((char *)value);
228       /* this isn't really unused */
229       plugin_name = strtok((char *)command, ":");
230       if (strcmp(plugin_name, "exchange") != 0) {
231          context->plugin_active = false;
232       } else {
233          context->plugin_active = true;
234       }
235       free(command);
236       break;
237    case bEventStartBackupJob:
238       if (!context->plugin_active) {
239          break;
240       }
241       _DebugMessage(0, "BackupStart\n");
242       bfuncs->getBaculaValue(ctx, bVarAccurate, (void *)&accurate);
243       context->accurate = accurate;
244       context->job_type = JOB_TYPE_BACKUP;
245       // level should have been specified by now - check it
246       // if level is D or I, since should have been specified too
247       switch (context->job_level) {
248       case 'F':
249          if (context->notrunconfull_option) {
250             context->truncate_logs = false;
251          } else {
252             context->truncate_logs = true;
253          }
254          break;
255       case 'D':
256          context->truncate_logs = false;
257          break;
258       case 'I':
259          context->truncate_logs = false;
260          break;
261       default:
262          _DebugMessage(0, "Invalid job level %c\n", context->job_level);
263          return bRC_Error;
264       }
265       break;
266    case bEventEndBackupJob:
267       _DebugMessage(0, "BackupEnd\n");
268       if (!context->plugin_active) {
269          break;
270       }
271       break;
272    case bEventLevel:
273       if (!context->plugin_active) {
274          break;
275       }
276       intval = (intptr_t)value;
277       _DebugMessage(0, "JobLevel=%c %d\n", intval, intval);
278       context->job_level = intval;
279       break;
280    case bEventSince:
281       if (!context->plugin_active) {
282          break;
283       }
284       intval = (intptr_t)value;
285       _DebugMessage(0, "since=%d\n", intval);
286       context->job_since = (time_t)value;
287       break;
288    case bEventStartRestoreJob:
289       _DebugMessage(0, "StartRestoreJob\n");
290       context->job_type = JOB_TYPE_RESTORE;
291       context->plugin_active = true;
292       break;
293    case bEventEndRestoreJob:
294       if (!context->plugin_active) {
295          break;
296       }
297       _DebugMessage(0, "EndRestoreJob\n");
298       context->plugin_active = false;
299       break;
300    
301    /* Plugin command e.g. plugin = <plugin-name>:<name-space>:command */
302    case bEventRestoreCommand:
303       _DebugMessage(0, "restore\n"); // command=%s\n", (char *)value);
304       if (!context->plugin_active) {
305          break;
306       }
307       break;
308
309    case bEventBackupCommand:
310       if (!context->plugin_active) {
311          break;
312       }
313       {
314       _DebugMessage(0, "backup command=%s\n", (char *)value);    
315       char *command = new char[strlen((char *)value)];
316       strcpy(command, (char *)value);
317       char *plugin_name = strtok((char *)command, ":");
318       char *path = strtok(NULL, ":");
319       char *option;
320       while ((option = strtok(NULL, ":")) != NULL) {
321          _DebugMessage(100, "option %s\n", option);
322          if (stricmp(option, "notrunconfull") == 0) {
323             context->notrunconfull_option = true;
324          } else {
325             _JobMessage(M_WARNING, "Unknown plugin option '%s'\n", option);
326          }
327       }
328       _DebugMessage(0, "name = %s\n", plugin_name);
329       _DebugMessage(0, "path = %s\n", path);
330       if (*path != '/') {
331          _JobMessage(M_FATAL, "Path does not begin with a '/'\n");
332          return bRC_Error;
333       }
334
335       for (i = 0; i < 6; i++) {
336          context->path_bits[i] = NULL;
337       }
338
339       char *path_bit = strtok(path, "/");
340       for (i = 0; path_bit != NULL && i < 6; i++) {
341          context->path_bits[i] = new char[strlen(path_bit) + 1];
342          strcpy(context->path_bits[i], path_bit);
343          path_bit = strtok(NULL, "/");
344       }
345
346       if (i < 2 || i > 4) {
347          _JobMessage(M_FATAL, "Invalid plugin backup path\n");
348          return bRC_Error;
349       }
350       context->root_node = new root_node_t(context->path_bits[0]);
351       context->current_node = context->root_node;
352
353       }
354       break;
355
356    default:
357       _JobMessage(M_FATAL, "unknown event=%d\n", event->eventType);
358    }
359    bfuncs->getBaculaValue(ctx, bVarFDName, (void *)&name);
360    return bRC_OK;
361 }
362
363 static bRC
364 startBackupFile(bpContext *ctx, struct save_pkt *sp)
365 {
366    bRC retval;
367    exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
368    node_t *current_node;
369
370    _DebugMessage(100, "startBackupFile, cmd = %s\n", sp->cmd);
371    if (sp->pkt_size != sizeof(struct save_pkt) || sp->pkt_end != sizeof(struct save_pkt)) {
372       _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);
373       return bRC_Error;
374    }
375
376    //context->root_node = new root_node_t(PLUGIN_PATH_PREFIX_BASE);
377    //context->current_node = context->root_node;
378    do {
379       current_node  = context->current_node;
380       retval = current_node->startBackupFile(context, sp);
381       if (retval == bRC_Seen)
382          endBackupFile(ctx);
383    } while (current_node != context->current_node);
384    _DebugMessage(100, "startBackupFile done - type = %d, fname = %s, retval = %d\n", sp->type, sp->fname, retval);
385    return retval;
386 }
387
388 static bRC endBackupFile(bpContext *ctx)
389
390    bRC retval;
391    exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
392    node_t *current_node;
393
394    _DebugMessage(100, "endBackupFile\n");
395
396    do {
397       current_node  = context->current_node;
398       retval = current_node->endBackupFile(context);
399    } while (current_node != context->current_node);
400    _DebugMessage(100, "endBackupFile done - retval = %d\n", retval);
401    return retval;
402 }
403
404 /*
405  * Do actual I/O
406  */
407 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
408 {
409    bRC retval = bRC_OK;
410    exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
411
412    if (io->pkt_size != sizeof(struct io_pkt) || io->pkt_end != sizeof(struct io_pkt))
413    {
414       _JobMessage(M_FATAL, "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);
415    }
416
417    switch(io->func) {
418    case IO_OPEN:
419       _DebugMessage(100, "IO_OPEN\n");
420       retval = context->current_node->pluginIoOpen(context, io);
421       break;
422    case IO_READ:
423       //_DebugMessage(100, "IO_READ buf=%p len=%d\n", io->buf, io->count);
424       retval = context->current_node->pluginIoRead(context, io);
425       break;
426    case IO_WRITE:
427       //_DebugMessage(100, "IO_WRITE buf=%p len=%d\n", io->buf, io->count);
428       retval = context->current_node->pluginIoWrite(context, io);
429       break;
430    case IO_CLOSE:
431       _DebugMessage(100, "IO_CLOSE\n");
432       retval = context->current_node->pluginIoClose(context, io);
433       break;
434    }
435    return retval;
436 }
437
438 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
439 {
440    exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
441    _DebugMessage(100, "startRestoreFile\n");
442
443    return bRC_OK;
444 }
445
446 static bRC endRestoreFile(bpContext *ctx)
447 {
448    bRC retval;
449    exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
450    node_t *current_node;
451
452    _DebugMessage(100, "endRestoreFile\n");
453
454    do {
455       current_node  = context->current_node;
456       retval = current_node->endRestoreFile(context);
457    } while (current_node != context->current_node);
458    _DebugMessage(100, "endRestoreFile done - retval = %d\n", retval);
459    return retval;
460 }
461
462 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
463 {
464    bRC retval;
465    exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
466    node_t *current_node;
467    char **path_bits;
468    int count;
469    int i;
470
471
472    _DebugMessage(100, "createFile - type = %d, ofname = %s\n", rp->type, rp->ofname);
473    if (rp->pkt_size != sizeof(struct restore_pkt) || rp->pkt_end != sizeof(struct restore_pkt))
474    {
475       _JobMessage(M_FATAL, "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);
476       return bRC_Error;
477    }
478
479    for (i = 0; i < 6; i++)
480    {
481       context->path_bits[i] = NULL;
482    }
483
484    path_bits = splitString((char *)rp->ofname, '/', 7, &count);
485
486    _DebugMessage(100, "count = %d\n", count);
487
488    for (i = 1; i < count; i++)
489    {
490       _DebugMessage(150, "%d = '%s'\n", i, path_bits[i]);
491       context->path_bits[i - 1] = path_bits[i];
492    }
493
494    if (context->current_node == NULL)
495    {
496       context->root_node = new root_node_t(context->path_bits[0]);
497       context->current_node = context->root_node;
498    }
499
500    do {
501       current_node  = context->current_node;
502       retval = current_node->createFile(context, rp);
503    } while (current_node != context->current_node);
504    _DebugMessage(100, "createFile done - retval = %d\n", retval);
505    return retval;
506 }
507
508 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
509 {
510    exchange_fd_context_t *context = (exchange_fd_context_t *)ctx->pContext;
511    _DebugMessage(100, "setFileAttributes\n");
512    return bRC_OK;
513 }