1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2011-2015 Planets Communications B.V.
5 Copyright (C) 2013-2018 Bareos GmbH & Co. KG
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation, which is
10 listed in the file LICENSE.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * Marco van Wieringen, August 2012
24 */
25 /**
26 * @file
27 * Python plugin for the Bareos File Daemon
28 */
29 #define BUILD_PLUGIN
30
31 #include "include/bareos.h"
32 #include <Python.h>
33 #include "filed/fd_plugins.h"
34 #include "plugins/filed/fd_common.h"
35 #include "python-fd.h"
36
37 namespace filedaemon {
38
39 #if (PY_VERSION_HEX < 0x02060000)
40 #error "Need at least Python version 2.6 or newer"
41 #endif
42
43 #if (PY_VERSION_HEX > 0x03050000)
44 #define PyInt_AsLong PyLong_AsLong
45 #define PyInt_FromLong PyLong_FromLong
46 #define PyString_AsString PyUnicode_AsUTF8
47 #define PyString_FromString PyUnicode_FromString
48 #define PyString_Check PyBytes_Check
49 #endif
50
51 static const int debuglevel = 150;
52
53 #define PLUGIN_LICENSE "Bareos AGPLv3"
54 #define PLUGIN_AUTHOR "Marco van Wieringen"
55 #define PLUGIN_DATE "May 2014"
56 #define PLUGIN_VERSION "3"
57 #define PLUGIN_DESCRIPTION "Python File Daemon Plugin"
58 #define PLUGIN_USAGE "python:module_path=<path-to-python-modules>:module_name=<python-module-to-load>:..."
59
60 /**
61 * Forward referenced functions
62 */
63 static bRC newPlugin(bpContext *ctx);
64 static bRC freePlugin(bpContext *ctx);
65 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value);
66 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value);
67 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value);
68 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp);
69 static bRC endBackupFile(bpContext *ctx);
70 static bRC pluginIO(bpContext *ctx, struct io_pkt *io);
71 static bRC startRestoreFile(bpContext *ctx, const char *cmd);
72 static bRC endRestoreFile(bpContext *ctx);
73 static bRC createFile(bpContext *ctx, struct restore_pkt *rp);
74 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
75 static bRC checkFile(bpContext *ctx, char *fname);
76 static bRC getAcl(bpContext *ctx, acl_pkt *ap);
77 static bRC setAcl(bpContext *ctx, acl_pkt *ap);
78 static bRC getXattr(bpContext *ctx, xattr_pkt *xp);
79 static bRC setXattr(bpContext *ctx, xattr_pkt *xp);
80 static bRC parse_plugin_definition(bpContext *ctx, void *value, PoolMem &plugin_options);
81
82 static void PyErrorHandler(bpContext *ctx, int msgtype);
83 static bRC PyLoadModule(bpContext *ctx, void *value);
84 static bRC PyParsePluginDefinition(bpContext *ctx, void *value);
85 static bRC PyGetPluginValue(bpContext *ctx, pVariable var, void *value);
86 static bRC PySetPluginValue(bpContext *ctx, pVariable var, void *value);
87 static bRC PyHandlePluginEvent(bpContext *ctx, bEvent *event, void *value);
88 static bRC PyStartBackupFile(bpContext *ctx, struct save_pkt *sp);
89 static bRC PyEndBackupFile(bpContext *ctx);
90 static bRC PyPluginIO(bpContext *ctx, struct io_pkt *io);
91 static bRC PyStartRestoreFile(bpContext *ctx, const char *cmd);
92 static bRC PyEndRestoreFile(bpContext *ctx);
93 static bRC PyCreateFile(bpContext *ctx, struct restore_pkt *rp);
94 static bRC PySetFileAttributes(bpContext *ctx, struct restore_pkt *rp);
95 static bRC PyCheckFile(bpContext *ctx, char *fname);
96 static bRC PyGetAcl(bpContext *ctx, acl_pkt *ap);
97 static bRC PySetAcl(bpContext *ctx, acl_pkt *ap);
98 static bRC PyGetXattr(bpContext *ctx, xattr_pkt *xp);
99 static bRC PySetXattr(bpContext *ctx, xattr_pkt *xp);
100 static bRC PyRestoreObjectData(bpContext *ctx, struct restore_object_pkt *rop);
101 static bRC PyHandleBackupFile(bpContext *ctx, struct save_pkt *sp);
102
103 /**
104 * Pointers to Bareos functions
105 */
106 static bFuncs *bfuncs = NULL;
107 static bInfo *binfo = NULL;
108
109 static genpInfo pluginInfo = {
110 sizeof(pluginInfo),
111 FD_PLUGIN_INTERFACE_VERSION,
112 FD_PLUGIN_MAGIC,
113 PLUGIN_LICENSE,
114 PLUGIN_AUTHOR,
115 PLUGIN_DATE,
116 PLUGIN_VERSION,
117 PLUGIN_DESCRIPTION,
118 PLUGIN_USAGE
119 };
120
121 static pFuncs pluginFuncs = {
122 sizeof(pluginFuncs),
123 FD_PLUGIN_INTERFACE_VERSION,
124
125 /* Entry points into plugin */
126 newPlugin, /* new plugin instance */
127 freePlugin, /* free plugin instance */
128 getPluginValue,
129 setPluginValue,
130 handlePluginEvent,
131 startBackupFile,
132 endBackupFile,
133 startRestoreFile,
134 endRestoreFile,
135 pluginIO,
136 createFile,
137 setFileAttributes,
138 checkFile,
139 getAcl,
140 setAcl,
141 getXattr,
142 setXattr
143 };
144
145 /**
146 * Plugin private context
147 */
148 struct plugin_ctx {
149 int32_t backup_level; /* Backup level e.g. Full/Differential/Incremental */
150 utime_t since; /* Since time for Differential/Incremental */
151 bool python_loaded; /* Plugin has python module loaded ? */
152 bool python_path_set; /* Python plugin search path is set ? */
153 char *plugin_options; /* Plugin Option string */
154 char *module_path; /* Plugin Module Path */
155 char *module_name; /* Plugin Module Name */
156 char *fname; /* Next filename to save */
157 char *link; /* Target symlink points to */
158 char *object_name; /* Restore Object Name */
159 char *object; /* Restore Object Content */
160 PyThreadState *interpreter; /* Python interpreter for this instance of the plugin */
161 PyObject *pInstance; /* Python Module instance */
162 PyObject *pModule; /* Python Module entry point */
163 PyObject *pDict; /* Python Dictionary */
164 PyObject *bpContext; /* Python representation of plugin context */
165 };
166
167 /**
168 * We don't actually use this but we need it to tear down the
169 * final python interpreter on unload of the plugin. Each instance of
170 * the plugin get its own interpreter.
171 */
172 static PyThreadState *mainThreadState;
173
174 #if (PY_VERSION_HEX > 0x03050000)
175 static struct PyModuleDef BareosFDModuleDef = {
176 PyModuleDef_HEAD_INIT,
177 "bareosfd",
178 NULL,
179 -1,
180 BareosFDMethods,
181 NULL,
182 NULL,
183 NULL,
184 NULL
185 };
186 #endif
187
188 #ifdef __cplusplus
189 extern "C" {
190 #endif
191
192 /**
193 * Plugin called here when it is first loaded
194 */
loadPlugin(bInfo * lbinfo,bFuncs * lbfuncs,genpInfo ** pinfo,pFuncs ** pfuncs)195 bRC loadPlugin(bInfo *lbinfo,
196 bFuncs *lbfuncs,
197 genpInfo **pinfo,
198 pFuncs **pfuncs)
199 {
200 bfuncs = lbfuncs; /* Set Bareos funct pointers */
201 binfo = lbinfo;
202
203 *pinfo = &pluginInfo; /* Return pointer to our info */
204 *pfuncs = &pluginFuncs; /* Return pointer to our functions */
205
206 /*
207 * Setup Python
208 */
209 Py_InitializeEx(0);
210 PyEval_InitThreads();
211 mainThreadState = PyEval_SaveThread();
212
213 return bRC_OK;
214 }
215
216 /**
217 * Plugin called here when it is unloaded, normally when Bareos is going to exit.
218 */
unloadPlugin()219 bRC unloadPlugin()
220 {
221 /*
222 * Terminate Python
223 */
224 PyEval_RestoreThread(mainThreadState);
225 Py_Finalize();
226
227 return bRC_OK;
228 }
229
230 #ifdef __cplusplus
231 }
232 #endif
233
234 /**
235 * Called here to make a new instance of the plugin -- i.e. when
236 * a new Job is started. There can be multiple instances of
237 * each plugin that are running at the same time. Your
238 * plugin instance must be thread safe and keep its own
239 * local data.
240 */
newPlugin(bpContext * ctx)241 static bRC newPlugin(bpContext *ctx)
242 {
243 struct plugin_ctx *p_ctx;
244
245 p_ctx = (struct plugin_ctx *)malloc(sizeof(struct plugin_ctx));
246 if (!p_ctx) {
247 return bRC_Error;
248 }
249 memset(p_ctx, 0, sizeof(struct plugin_ctx));
250 ctx->pContext = (void *)p_ctx; /* set our context pointer */
251
252 /*
253 * For each plugin instance we instantiate a new Python interpreter.
254 */
255 PyEval_AcquireLock();
256 p_ctx->interpreter = Py_NewInterpreter();
257 PyEval_ReleaseThread(p_ctx->interpreter);
258
259 /*
260 * Always register some events the python plugin itself can register
261 * any other events it is interested in.
262 */
263 bfuncs->registerBareosEvents(ctx,
264 9,
265 bEventLevel,
266 bEventSince,
267 bEventNewPluginOptions,
268 bEventPluginCommand,
269 bEventJobStart,
270 bEventRestoreCommand,
271 bEventEstimateCommand,
272 bEventBackupCommand,
273 bEventRestoreObject);
274
275 return bRC_OK;
276 }
277
278 /**
279 * Release everything concerning a particular instance of a
280 * plugin. Normally called when the Job terminates.
281 */
freePlugin(bpContext * ctx)282 static bRC freePlugin(bpContext *ctx)
283 {
284 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
285
286 if (!p_ctx) {
287 return bRC_Error;
288 }
289
290 if (p_ctx->plugin_options) {
291 free(p_ctx->plugin_options);
292 }
293
294 if (p_ctx->module_path) {
295 free(p_ctx->module_path);
296 }
297
298 if (p_ctx->module_name) {
299 free(p_ctx->module_name);
300 }
301
302 if (p_ctx->fname) {
303 free(p_ctx->fname);
304 }
305
306 if (p_ctx->link) {
307 free(p_ctx->link);
308 }
309
310 if (p_ctx->object_name) {
311 free(p_ctx->object_name);
312 }
313
314 if (p_ctx->object) {
315 free(p_ctx->object);
316 }
317
318 /*
319 * Stop any sub interpreter started per plugin instance.
320 */
321 PyEval_AcquireThread(p_ctx->interpreter);
322
323 /*
324 * Do python cleanup calls.
325 */
326 if (p_ctx->bpContext) {
327 Py_DECREF(p_ctx->bpContext);
328 }
329
330 if (p_ctx->pModule) {
331 Py_DECREF(p_ctx->pModule);
332 }
333
334 Py_EndInterpreter(p_ctx->interpreter);
335 PyEval_ReleaseLock();
336
337 free(p_ctx);
338 ctx->pContext = NULL;
339
340 return bRC_OK;
341 }
342
343 /**
344 * Called by core code to get a variable from the plugin.
345 * Not currently used.
346 */
getPluginValue(bpContext * ctx,pVariable var,void * value)347 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value)
348 {
349 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
350 bRC retval = bRC_Error;
351
352 if (!p_ctx) {
353 goto bail_out;
354 }
355
356 PyEval_AcquireThread(p_ctx->interpreter);
357 retval = PyGetPluginValue(ctx, var, value);
358 PyEval_ReleaseThread(p_ctx->interpreter);
359
360 bail_out:
361 return retval;
362 }
363
364 /**
365 * Called by core code to set a plugin variable.
366 * Not currently used.
367 */
setPluginValue(bpContext * ctx,pVariable var,void * value)368 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value)
369 {
370 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
371 bRC retval = bRC_Error;
372
373 if (!p_ctx) {
374 return bRC_Error;
375 }
376
377 PyEval_AcquireThread(p_ctx->interpreter);
378 retval = PySetPluginValue(ctx, var, value);
379 PyEval_ReleaseThread(p_ctx->interpreter);
380
381 return retval;
382 }
383
384 /**
385 * Called by Bareos when there are certain events that the
386 * plugin might want to know. The value depends on the event.
387 */
handlePluginEvent(bpContext * ctx,bEvent * event,void * value)388 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
389 {
390 bRC retval = bRC_Error;
391 bool event_dispatched = false;
392 PoolMem plugin_options(PM_FNAME);
393 plugin_ctx *p_ctx = (plugin_ctx *)ctx->pContext;
394
395 if (!p_ctx) {
396 goto bail_out;
397 }
398
399 /*
400 * First handle some events internally before calling python if it
401 * want to do some special handling on the event triggered.
402 */
403 switch (event->eventType) {
404 case bEventLevel:
405 p_ctx->backup_level = (int64_t)value;
406 break;
407 case bEventSince:
408 p_ctx->since = (int64_t)value;
409 break;
410 case bEventBackupCommand:
411 /*
412 * Fall-through wanted
413 */
414 case bEventRestoreCommand:
415 /*
416 * Fall-through wanted
417 */
418 case bEventEstimateCommand:
419 /*
420 * Fall-through wanted
421 */
422 case bEventPluginCommand:
423 event_dispatched = true;
424 retval = parse_plugin_definition(ctx, value, plugin_options);
425 break;
426 case bEventNewPluginOptions:
427 /*
428 * Free any previous value.
429 */
430 if (p_ctx->plugin_options) {
431 free(p_ctx->plugin_options);
432 p_ctx->plugin_options = NULL;
433 }
434
435 event_dispatched = true;
436 retval = parse_plugin_definition(ctx, value, plugin_options);
437
438 /*
439 * Save that we got a plugin override.
440 */
441 p_ctx->plugin_options = bstrdup((char *)value);
442 break;
443 case bEventRestoreObject: {
444 struct restore_object_pkt *rop;
445
446 rop = (struct restore_object_pkt *)value;
447
448 /*
449 * Only use the plugin definition of a restore object if we
450 * didn't get any other plugin definition from some other source before.
451 */
452 if (!p_ctx->python_loaded) {
453 if (rop && *rop->plugin_name) {
454 event_dispatched = true;
455 retval = parse_plugin_definition(ctx, rop->plugin_name, plugin_options);
456 }
457 }
458 break;
459 }
460 default:
461 break;
462 }
463
464 /*
465 * See if we have been triggered in the previous switch if not we have to
466 * always dispatch the event. If we already processed the event internally
467 * we only do a dispatch to the python entry point when that internal processing
468 * was successfull (e.g. retval == bRC_OK).
469 */
470 if (!event_dispatched || retval == bRC_OK) {
471 PyEval_AcquireThread(p_ctx->interpreter);
472
473 /*
474 * Now dispatch the event to Python.
475 * First the calls that need special handling.
476 */
477 switch (event->eventType) {
478 case bEventBackupCommand:
479 /*
480 * Fall-through wanted
481 */
482 case bEventRestoreCommand:
483 /*
484 * Fall-through wanted
485 */
486 case bEventEstimateCommand:
487 /*
488 * Fall-through wanted
489 */
490 case bEventPluginCommand:
491 /*
492 * Fall-through wanted
493 */
494 case bEventNewPluginOptions:
495 /*
496 * See if we already loaded the Python modules.
497 */
498 if (!p_ctx->python_loaded) {
499 retval = PyLoadModule(ctx, plugin_options.c_str());
500 }
501
502 /*
503 * Only try to call when the loading succeeded.
504 */
505 if (retval == bRC_OK) {
506 retval = PyParsePluginDefinition(ctx, plugin_options.c_str());
507 }
508 break;
509 case bEventRestoreObject: {
510 struct restore_object_pkt *rop;
511
512 rop = (struct restore_object_pkt *)value;
513 if (!rop) {
514 /*
515 * If rop == NULL this means we got the last restore object.
516 * No need to call into python so just return.
517 */
518 retval = bRC_OK;
519 } else {
520 /*
521 * See if we already loaded the Python modules.
522 */
523 if (!p_ctx->python_loaded && *rop->plugin_name) {
524 retval = PyLoadModule(ctx, plugin_options.c_str());
525
526 /*
527 * Only try to call when the loading succeeded.
528 */
529 if (retval == bRC_OK) {
530 retval = PyParsePluginDefinition(ctx, plugin_options.c_str());
531 if (retval == bRC_OK) {
532 retval = PyRestoreObjectData(ctx, rop);
533 }
534 }
535 } else {
536 retval = PyRestoreObjectData(ctx, rop);
537 }
538 }
539 break;
540 }
541 case bEventHandleBackupFile:
542 retval = PyHandleBackupFile(ctx, (struct save_pkt *)value);
543 break;
544 default:
545 /*
546 * Handle the generic events e.g. the ones which are just passed on.
547 * We only try to call Python when we loaded the right module until
548 * that time we pretend the call succeeded.
549 */
550 if (p_ctx->python_loaded) {
551 retval = PyHandlePluginEvent(ctx, event, value);
552 } else {
553 retval = bRC_OK;
554 }
555 break;
556 }
557
558 PyEval_ReleaseThread(p_ctx->interpreter);
559 }
560
561 bail_out:
562 return retval;
563 }
564
565 /**
566 * Called when starting to backup a file. Here the plugin must
567 * return the "stat" packet for the directory/file and provide
568 * certain information so that Bareos knows what the file is.
569 * The plugin can create "Virtual" files by giving them a
570 * name that is not normally found on the file system.
571 */
startBackupFile(bpContext * ctx,struct save_pkt * sp)572 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
573 {
574 bRC retval = bRC_Error;
575 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
576
577 if (!p_ctx) {
578 goto bail_out;
579 }
580
581 PyEval_AcquireThread(p_ctx->interpreter);
582 retval = PyStartBackupFile(ctx, sp);
583 PyEval_ReleaseThread(p_ctx->interpreter);
584
585 /*
586 * For Incremental and Differential backups use checkChanges method to
587 * see if we need to backup this file.
588 */
589 switch (p_ctx->backup_level) {
590 case L_INCREMENTAL:
591 case L_DIFFERENTIAL:
592 /*
593 * If the plugin didn't set a save_time but we have a since time
594 * from the bEventSince event we use that as basis for the actual
595 * save_time to check.
596 */
597 if (sp->save_time == 0 && p_ctx->since) {
598 sp->save_time = p_ctx->since;
599 }
600
601 switch (bfuncs->checkChanges(ctx, sp)) {
602 case bRC_Seen:
603 switch (sp->type) {
604 case FT_DIRBEGIN:
605 sp->type = FT_DIRNOCHG;
606 break;
607 default:
608 sp->type = FT_NOCHG;
609 break;
610 }
611 break;
612 default:
613 break;
614 }
615 }
616
617 bail_out:
618 return retval;
619 }
620
621 /**
622 * Done backing up a file.
623 */
endBackupFile(bpContext * ctx)624 static bRC endBackupFile(bpContext *ctx)
625 {
626 bRC retval = bRC_Error;
627 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
628
629 if (!p_ctx) {
630 goto bail_out;
631 }
632
633 PyEval_AcquireThread(p_ctx->interpreter);
634 retval = PyEndBackupFile(ctx);
635 PyEval_ReleaseThread(p_ctx->interpreter);
636
637 bail_out:
638 return retval;
639 }
640
641 /**
642 * Do actual I/O. Bareos calls this after startBackupFile
643 * or after startRestoreFile to do the actual file
644 * input or output.
645 */
pluginIO(bpContext * ctx,struct io_pkt * io)646 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
647 {
648 bRC retval = bRC_Error;
649 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
650
651 if (!p_ctx) {
652 goto bail_out;
653 }
654
655 if (!p_ctx->python_loaded) {
656 goto bail_out;
657 }
658
659 PyEval_AcquireThread(p_ctx->interpreter);
660 retval = PyPluginIO(ctx, io);
661 PyEval_ReleaseThread(p_ctx->interpreter);
662
663 bail_out:
664 return retval;
665 }
666
667 /**
668 * Start restore of a file.
669 */
startRestoreFile(bpContext * ctx,const char * cmd)670 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
671 {
672 bRC retval = bRC_Error;
673 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
674
675 if (!p_ctx) {
676 goto bail_out;
677 }
678
679 PyEval_AcquireThread(p_ctx->interpreter);
680 retval = PyStartRestoreFile(ctx, cmd);
681 PyEval_ReleaseThread(p_ctx->interpreter);
682
683 bail_out:
684 return retval;
685 }
686
687 /**
688 * Done restoring a file.
689 */
endRestoreFile(bpContext * ctx)690 static bRC endRestoreFile(bpContext *ctx)
691 {
692 bRC retval = bRC_Error;
693 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
694
695 if (!p_ctx) {
696 goto bail_out;
697 }
698
699 PyEval_AcquireThread(p_ctx->interpreter);
700 retval = PyEndRestoreFile(ctx);
701 PyEval_ReleaseThread(p_ctx->interpreter);
702
703 bail_out:
704 return retval;
705 }
706
707 /**
708 * Called here to give the plugin the information needed to
709 * re-create the file on a restore. It basically gets the
710 * stat packet that was created during the backup phase.
711 * This data is what is needed to create the file, but does
712 * not contain actual file data.
713 */
createFile(bpContext * ctx,struct restore_pkt * rp)714 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
715 {
716 bRC retval = bRC_Error;
717 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
718
719 if (!p_ctx) {
720 goto bail_out;
721 }
722
723 PyEval_AcquireThread(p_ctx->interpreter);
724 retval = PyCreateFile(ctx, rp);
725 PyEval_ReleaseThread(p_ctx->interpreter);
726
727 bail_out:
728 return retval;
729 }
730
731 /**
732 * Called after the file has been restored. This can be used to
733 * set directory permissions, ...
734 */
setFileAttributes(bpContext * ctx,struct restore_pkt * rp)735 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
736 {
737 bRC retval = bRC_Error;
738 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
739
740 if (!p_ctx) {
741 goto bail_out;
742 }
743
744 PyEval_AcquireThread(p_ctx->interpreter);
745 retval = PySetFileAttributes(ctx, rp);
746 PyEval_ReleaseThread(p_ctx->interpreter);
747
748 bail_out:
749 return retval;
750 }
751
752 /**
753 * When using Incremental dump, all previous dumps are necessary
754 */
checkFile(bpContext * ctx,char * fname)755 static bRC checkFile(bpContext *ctx, char *fname)
756 {
757 bRC retval = bRC_Error;
758 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
759
760 if (!p_ctx) {
761 goto bail_out;
762 }
763
764 if (!p_ctx->python_loaded) {
765 return bRC_OK;
766 }
767
768 PyEval_AcquireThread(p_ctx->interpreter);
769 retval = PyCheckFile(ctx, fname);
770 PyEval_ReleaseThread(p_ctx->interpreter);
771
772 bail_out:
773 return retval;
774 }
775
776 /**
777 */
getAcl(bpContext * ctx,acl_pkt * ap)778 static bRC getAcl(bpContext *ctx, acl_pkt *ap)
779 {
780 bRC retval = bRC_Error;
781 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
782
783 if (!p_ctx) {
784 goto bail_out;
785 }
786
787 PyEval_AcquireThread(p_ctx->interpreter);
788 retval = PyGetAcl(ctx, ap);
789 PyEval_ReleaseThread(p_ctx->interpreter);
790
791 bail_out:
792 return retval;
793 }
794
795 /**
796 */
setAcl(bpContext * ctx,acl_pkt * ap)797 static bRC setAcl(bpContext *ctx, acl_pkt *ap)
798 {
799 bRC retval = bRC_Error;
800 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
801
802 if (!p_ctx) {
803 goto bail_out;
804 }
805
806 PyEval_AcquireThread(p_ctx->interpreter);
807 retval = PySetAcl(ctx, ap);
808 PyEval_ReleaseThread(p_ctx->interpreter);
809
810 bail_out:
811 return retval;
812 }
813
814 /**
815 */
getXattr(bpContext * ctx,xattr_pkt * xp)816 static bRC getXattr(bpContext *ctx, xattr_pkt *xp)
817 {
818 bRC retval = bRC_Error;
819 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
820
821 if (!p_ctx) {
822 goto bail_out;
823 }
824
825 PyEval_AcquireThread(p_ctx->interpreter);
826 retval = PyGetXattr(ctx, xp);
827 PyEval_ReleaseThread(p_ctx->interpreter);
828
829 bail_out:
830 return retval;
831 }
832
833 /**
834 */
setXattr(bpContext * ctx,xattr_pkt * xp)835 static bRC setXattr(bpContext *ctx, xattr_pkt *xp)
836 {
837 bRC retval = bRC_Error;
838 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
839
840 if (!p_ctx) {
841 goto bail_out;
842 }
843
844 PyEval_AcquireThread(p_ctx->interpreter);
845 retval = PySetXattr(ctx, xp);
846 PyEval_ReleaseThread(p_ctx->interpreter);
847
848 bail_out:
849 return retval;
850 }
851
852 /**
853 * Strip any backslashes in the string.
854 */
StripBackSlashes(char * value)855 static inline void StripBackSlashes(char *value)
856 {
857 char *bp;
858
859 bp = value;
860 while (*bp) {
861 switch (*bp) {
862 case '\\':
863 bstrinlinecpy(bp, bp + 1);
864 break;
865 default:
866 break;
867 }
868
869 bp++;
870 }
871 }
872
873 /**
874 * Parse a boolean value e.g. check if its yes or true anything else translates to false.
875 */
ParseBoolean(const char * argument_value)876 static inline bool ParseBoolean(const char *argument_value)
877 {
878 if (Bstrcasecmp(argument_value, "yes") ||
879 Bstrcasecmp(argument_value, "true")) {
880 return true;
881 } else {
882 return false;
883 }
884 }
885
886 /**
887 * Only set destination to value when it has no previous setting.
888 */
SetStringIfNull(char ** destination,char * value)889 static inline void SetStringIfNull(char **destination, char *value)
890 {
891 if (!*destination) {
892 *destination = bstrdup(value);
893 StripBackSlashes(*destination);
894 }
895 }
896
897 /**
898 * Always set destination to value and clean any previous one.
899 */
SetString(char ** destination,char * value)900 static inline void SetString(char **destination, char *value)
901 {
902 if (*destination) {
903 free(*destination);
904 }
905
906 *destination = bstrdup(value);
907 StripBackSlashes(*destination);
908 }
909
910 /**
911 * Parse the plugin definition passed in.
912 *
913 * The definition is in this form:
914 *
915 * python:module_path=<path>:module_name=<python_module_name>:...
916 */
parse_plugin_definition(bpContext * ctx,void * value,PoolMem & plugin_options)917 static bRC parse_plugin_definition(bpContext *ctx, void *value, PoolMem &plugin_options)
918 {
919 bool found;
920 int i, cnt;
921 bool keep_existing;
922 PoolMem plugin_definition(PM_FNAME);
923 char *bp, *argument, *argument_value;
924 plugin_ctx *p_ctx = (plugin_ctx *)ctx->pContext;
925
926 if (!value) {
927 return bRC_Error;
928 }
929
930 /*
931 * Skip this plugin when getting plugin definition "*all*"
932 * This allows to restore a Windows Backup on a Linux FD with
933 * Python Plugins enabled.
934 */
935 if (bstrcmp((char *)value, "*all*")) {
936 Dmsg(ctx, debuglevel, "python-fd: Got plugin definition %s, skipping to ignore\n", (char *)value);
937 return bRC_Skip;
938 }
939
940 keep_existing = (p_ctx->plugin_options) ? true : false;
941
942 /*
943 * Parse the plugin definition.
944 * Make a private copy of the whole string.
945 */
946 if (!p_ctx->python_loaded && p_ctx->plugin_options) {
947 int len;
948
949 /*
950 * We got some option string which got pushed before we actual were able to send
951 * it to the python module as the entry point was not instantiated. So we prepend
952 * that now in the option string and append the new option string with the first
953 * argument being the pluginname removed as that is already part of the other
954 * plugin option string.
955 */
956 len = strlen(p_ctx->plugin_options);
957 PmStrcpy(plugin_definition, p_ctx->plugin_options);
958
959 bp = strchr((char *)value, ':');
960 if (!bp) {
961 Jmsg(ctx, M_FATAL, "python-fd: Illegal plugin definition %s\n", (char *)value);
962 Dmsg(ctx, debuglevel, "python-fd: Illegal plugin definition %s\n", (char *)value);
963 goto bail_out;
964 }
965
966 /*
967 * See if option string end with ':'
968 */
969 if (p_ctx->plugin_options[len - 1] != ':') {
970 PmStrcat(plugin_definition, (char *)bp);
971 } else {
972 PmStrcat(plugin_definition, (char *)bp + 1);
973 }
974 } else {
975 PmStrcpy(plugin_definition, (char *)value);
976 }
977
978 bp = strchr(plugin_definition.c_str(), ':');
979 if (!bp) {
980 Jmsg(ctx, M_FATAL, "python-fd: Illegal plugin definition %s\n", plugin_definition.c_str());
981 Dmsg(ctx, debuglevel, "python-fd: Illegal plugin definition %s\n", plugin_definition.c_str());
982 goto bail_out;
983 }
984
985 /*
986 * Skip the first ':'
987 */
988 bp++;
989
990 cnt = 0;
991 while (bp) {
992 if (strlen(bp) == 0) {
993 break;
994 }
995
996 /*
997 * Each argument is in the form:
998 * <argument> = <argument_value>
999 *
1000 * So we setup the right pointers here, argument to the beginning
1001 * of the argument, argument_value to the beginning of the argument_value.
1002 */
1003 argument = bp;
1004 argument_value = strchr(bp, '=');
1005 if (!argument_value) {
1006 Jmsg(ctx, M_FATAL, "python-fd: Illegal argument %s without value\n", argument);
1007 Dmsg(ctx, debuglevel, "python-fd: Illegal argument %s without value\n", argument);
1008 goto bail_out;
1009 }
1010 *argument_value++ = '\0';
1011
1012 /*
1013 * See if there are more arguments and setup for the next run.
1014 */
1015 bp = argument_value;
1016 do {
1017 bp = strchr(bp, ':');
1018 if (bp) {
1019 if (*(bp - 1) != '\\') {
1020 *bp++ = '\0';
1021 break;
1022 } else {
1023 bp++;
1024 }
1025 }
1026 } while (bp);
1027
1028 found = false;
1029 for (i = 0; plugin_arguments[i].name; i++) {
1030 if (Bstrcasecmp(argument, plugin_arguments[i].name)) {
1031 char **str_destination = NULL;
1032 bool *bool_destination = NULL;
1033
1034 switch (plugin_arguments[i].type) {
1035 case argument_module_path:
1036 str_destination = &p_ctx->module_path;
1037 break;
1038 case argument_module_name:
1039 str_destination = &p_ctx->module_name;
1040 break;
1041 default:
1042 break;
1043 }
1044
1045 /*
1046 * Keep the first value, ignore any next setting.
1047 */
1048 if (str_destination) {
1049 if (keep_existing) {
1050 SetStringIfNull(str_destination, argument_value);
1051 } else {
1052 SetString(str_destination, argument_value);
1053 }
1054 }
1055
1056 /*
1057 * Set any boolean variable.
1058 */
1059 if (bool_destination) {
1060 *bool_destination = ParseBoolean(argument_value);
1061 }
1062
1063 /*
1064 * When we have a match break the loop.
1065 */
1066 found = true;
1067 break;
1068 }
1069 }
1070
1071 /*
1072 * If we didn't consume this parameter we add it to the plugin_options list.
1073 */
1074 if (!found) {
1075 PoolMem option(PM_FNAME);
1076
1077 if (cnt) {
1078 Mmsg(option, ":%s=%s", argument, argument_value);
1079 PmStrcat(plugin_options, option.c_str());
1080 } else {
1081 Mmsg(option, "%s=%s", argument, argument_value);
1082 PmStrcat(plugin_options, option.c_str());
1083 }
1084 cnt++;
1085 }
1086 }
1087
1088 if (cnt > 0) {
1089 PmStrcat(plugin_options, ":");
1090 }
1091
1092 return bRC_OK;
1093
1094 bail_out:
1095 return bRC_Error;
1096 }
1097
1098 /**
1099 * Work around API changes in Python versions.
1100 * These function abstract the storage and retrieval of the bpContext
1101 * which is passed to the Python methods and which the method can pass
1102 * back and which allow the callback function to understand what bpContext
1103 * its talking about.
1104 */
1105 #if ((PY_VERSION_HEX < 0x02070000) || \
1106 ((PY_VERSION_HEX >= 0x03000000) && \
1107 (PY_VERSION_HEX < 0x03010000)))
1108 /**
1109 * Python version before 2.7 and 3.0.
1110 */
PyCreatebpContext(bpContext * ctx)1111 static PyObject *PyCreatebpContext(bpContext *ctx)
1112 {
1113 /*
1114 * Setup a new CObject which holds the bpContext structure used here internally.
1115 */
1116 return PyCObject_FromVoidPtr((void *)ctx, NULL);
1117 }
1118
PyGetbpContext(PyObject * pyCtx)1119 static bpContext *PyGetbpContext(PyObject *pyCtx)
1120 {
1121 return (bpContext *)PyCObject_AsVoidPtr(pyCtx);
1122 }
1123 #else
1124 /**
1125 * Python version after 2.6 and 3.1.
1126 */
PyCreatebpContext(bpContext * ctx)1127 static PyObject *PyCreatebpContext(bpContext *ctx)
1128 {
1129 /*
1130 * Setup a new Capsule which holds the bpContext structure used here internally.
1131 */
1132 return PyCapsule_New((void *)ctx, "bareos.bpContext", NULL);
1133 }
1134
PyGetbpContext(PyObject * pyCtx)1135 static bpContext *PyGetbpContext(PyObject *pyCtx)
1136 {
1137 return (bpContext *)PyCapsule_GetPointer(pyCtx, "bareos.bpContext");
1138 }
1139 #endif
1140
1141 /**
1142 * Convert a return value into a bRC enum value.
1143 */
conv_python_retval(PyObject * pRetVal)1144 static inline bRC conv_python_retval(PyObject *pRetVal)
1145 {
1146 return (bRC)PyInt_AsLong(pRetVal);
1147 }
1148
1149 /**
1150 * Convert a return value from bRC enum value into Python Object.
1151 */
conv_retval_python(bRC retval)1152 static inline PyObject *conv_retval_python(bRC retval)
1153 {
1154 return (PyObject *)PyInt_FromLong((int)retval);
1155 }
1156
1157 /**
1158 * Handle a Python error.
1159 *
1160 * Python equivalent:
1161 *
1162 * import traceback, sys
1163 * return "".join(traceback.format_exception(sys.exc_type,
1164 * sys.exc_value, sys.exc_traceback))
1165 */
PyErrorHandler(bpContext * ctx,int msgtype)1166 static void PyErrorHandler(bpContext *ctx, int msgtype)
1167 {
1168 PyObject *type, *value, *traceback;
1169 PyObject *tracebackModule;
1170 char *error_string;
1171
1172 PyErr_Fetch(&type, &value, &traceback);
1173
1174 tracebackModule = PyImport_ImportModule("traceback");
1175 if (tracebackModule != NULL) {
1176 PyObject *tbList, *emptyString, *strRetval;
1177
1178 tbList = PyObject_CallMethod(tracebackModule,
1179 (char *)"format_exception",
1180 (char *)"OOO",
1181 type,
1182 value == NULL ? Py_None : value,
1183 traceback == NULL ? Py_None : traceback);
1184
1185 emptyString = PyString_FromString("");
1186 strRetval = PyObject_CallMethod(emptyString,
1187 (char *)"join",
1188 (char *)"O", tbList);
1189
1190 error_string = bstrdup(PyString_AsString(strRetval));
1191
1192 Py_DECREF(tbList);
1193 Py_DECREF(emptyString);
1194 Py_DECREF(strRetval);
1195 Py_DECREF(tracebackModule);
1196 } else {
1197 error_string = bstrdup("Unable to import traceback module.");
1198 }
1199
1200 Py_DECREF(type);
1201 Py_XDECREF(value);
1202 Py_XDECREF(traceback);
1203
1204 Dmsg(ctx, debuglevel, "python-fd: %s\n", error_string);
1205 if (msgtype) {
1206 Jmsg(ctx, msgtype, "python-fd: %s\n", error_string);
1207 }
1208
1209 free(error_string);
1210 }
1211
1212 /**
1213 * Initial load of the Python module.
1214 *
1215 * Based on the parsed plugin options we set some prerequisits like the
1216 * module path and the module to load. We also load the dictionary used
1217 * for looking up the Python methods.
1218 */
PyLoadModule(bpContext * ctx,void * value)1219 static bRC PyLoadModule(bpContext *ctx, void *value)
1220 {
1221 bRC retval = bRC_Error;
1222 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
1223 PyObject *sysPath,
1224 *mPath,
1225 *pName,
1226 *pFunc;
1227
1228 /*
1229 * See if we already setup the python search path.
1230 */
1231 if (!p_ctx->python_path_set) {
1232 /*
1233 * Extend the Python search path with the given module_path.
1234 */
1235 if (p_ctx->module_path) {
1236 sysPath = PySys_GetObject((char *)"path");
1237 mPath = PyString_FromString(p_ctx->module_path);
1238 PyList_Append(sysPath, mPath);
1239 Py_DECREF(mPath);
1240 p_ctx->python_path_set = true;
1241 }
1242 }
1243
1244 /*
1245 * See if we already setup the module structure.
1246 */
1247 if (!p_ctx->pInstance) {
1248 /*
1249 * Make our callback methods available for Python.
1250 */
1251 #if (PY_VERSION_HEX > 0x03050000)
1252 p_ctx->pInstance = PyModule_Create(&BareosFDModuleDef);
1253 #else
1254 p_ctx->pInstance = Py_InitModule("bareosfd", BareosFDMethods);
1255 #endif
1256
1257 /*
1258 * Fill in the slots of PyRestoreObject
1259 */
1260 PyRestoreObjectType.tp_new = PyType_GenericNew;
1261 if (PyType_Ready(&PyRestoreObjectType) < 0) {
1262 goto cleanup;
1263 }
1264
1265 /*
1266 * Fill in the slots of PyStatPacket
1267 */
1268 PyStatPacketType.tp_new = PyType_GenericNew;
1269 if (PyType_Ready(&PyStatPacketType) < 0) {
1270 goto cleanup;
1271 }
1272
1273 /*
1274 * Fill in the slots of PySavePacket
1275 */
1276 PySavePacketType.tp_new = PyType_GenericNew;
1277 if (PyType_Ready(&PySavePacketType) < 0) {
1278 goto cleanup;
1279 }
1280
1281 /*
1282 * Fill in the slots of PyRestorePacket
1283 */
1284 PyRestorePacketType.tp_new = PyType_GenericNew;
1285 if (PyType_Ready(&PyRestorePacketType) < 0) {
1286 goto cleanup;
1287 }
1288
1289 /*
1290 * Fill in the slots of PyIoPacketType
1291 */
1292 PyIoPacketType.tp_new = PyType_GenericNew;
1293 if (PyType_Ready(&PyIoPacketType) < 0) {
1294 goto cleanup;
1295 }
1296
1297 /*
1298 * Fill in the slots of PyAclPacketType
1299 */
1300 PyAclPacketType.tp_new = PyType_GenericNew;
1301 if (PyType_Ready(&PyAclPacketType) < 0) {
1302 goto cleanup;
1303 }
1304
1305 /*
1306 * Fill in the slots of PyXattrPacketType
1307 */
1308 PyXattrPacketType.tp_new = PyType_GenericNew;
1309 if (PyType_Ready(&PyXattrPacketType) < 0) {
1310 goto cleanup;
1311 }
1312
1313 /*
1314 * Add the types to the module
1315 */
1316 Py_INCREF(&PyRestoreObjectType);
1317 PyModule_AddObject(p_ctx->pInstance, "RestoreObject", (PyObject *)&PyRestoreObjectType);
1318
1319 Py_INCREF(&PyStatPacketType);
1320 PyModule_AddObject(p_ctx->pInstance, "StatPacket", (PyObject *)&PyStatPacketType);
1321
1322 Py_INCREF(&PySavePacketType);
1323 PyModule_AddObject(p_ctx->pInstance, "SavePacket", (PyObject *)&PySavePacketType);
1324
1325 Py_INCREF(&PyRestorePacketType);
1326 PyModule_AddObject(p_ctx->pInstance, "RestorePacket", (PyObject *)&PyRestorePacketType);
1327
1328 Py_INCREF(&PyIoPacketType);
1329 PyModule_AddObject(p_ctx->pInstance, "IoPacket", (PyObject *)&PyIoPacketType);
1330
1331 Py_INCREF(&PyAclPacketType);
1332 PyModule_AddObject(p_ctx->pInstance, "AclPacket", (PyObject *)&PyAclPacketType);
1333
1334 Py_INCREF(&PyXattrPacketType);
1335 PyModule_AddObject(p_ctx->pInstance, "XattrPacket", (PyObject *)&PyXattrPacketType);
1336 }
1337
1338 /*
1339 * Try to load the Python module by name.
1340 */
1341 if (p_ctx->module_name) {
1342 Dmsg(ctx, debuglevel, "python-fd: Trying to load module with name %s\n", p_ctx->module_name);
1343 pName = PyString_FromString(p_ctx->module_name);
1344 p_ctx->pModule = PyImport_Import(pName);
1345 Py_DECREF(pName);
1346
1347 if (!p_ctx->pModule) {
1348 Dmsg(ctx, debuglevel, "python-fd: Failed to load module with name %s\n", p_ctx->module_name);
1349 goto bail_out;
1350 }
1351
1352 Dmsg(ctx, debuglevel, "python-fd: Successfully loaded module with name %s\n", p_ctx->module_name);
1353
1354 /*
1355 * Get the Python dictionary for lookups in the Python namespace.
1356 */
1357 p_ctx->pDict = PyModule_GetDict(p_ctx->pModule); /* Borrowed reference */
1358
1359 /*
1360 * Encode the bpContext so a Python method can pass it in on calling back.
1361 */
1362 p_ctx->bpContext = PyCreatebpContext(ctx);
1363
1364 /*
1365 * Lookup the load_bareos_plugin() function in the python module.
1366 */
1367 pFunc = PyDict_GetItemString(p_ctx->pDict, "load_bareos_plugin"); /* Borrowed reference */
1368 if (pFunc && PyCallable_Check(pFunc)) {
1369 PyObject *pPluginDefinition,
1370 *pRetVal;
1371
1372 pPluginDefinition = PyString_FromString((char *)value);
1373 if (!pPluginDefinition) {
1374 goto bail_out;
1375 }
1376
1377 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pPluginDefinition, NULL);
1378 Py_DECREF(pPluginDefinition);
1379
1380 if (!pRetVal) {
1381 goto bail_out;
1382 } else {
1383 retval = conv_python_retval(pRetVal);
1384 Py_DECREF(pRetVal);
1385 }
1386 } else {
1387 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named load_bareos_plugins()\n");
1388 goto bail_out;
1389 }
1390
1391 /*
1392 * Keep track we successfully loaded.
1393 */
1394 p_ctx->python_loaded = true;
1395 }
1396
1397 return retval;
1398
1399 cleanup:
1400 p_ctx->pInstance = NULL;
1401
1402 bail_out:
1403 if (PyErr_Occurred()) {
1404 PyErrorHandler(ctx, M_FATAL);
1405 }
1406
1407 return retval;
1408 }
1409
1410 /**
1411 * Any plugin options which are passed in are dispatched here to a Python method and it
1412 * can parse the plugin options. This function is also called after PyLoadModule() has
1413 * loaded the Python module and made sure things are operational. Normally you would only get
1414 * one set of plugin options but for a restore overrides can be passed in before the actual
1415 * plugin options are restored as part of the restore stream handling.
1416 */
PyParsePluginDefinition(bpContext * ctx,void * value)1417 static bRC PyParsePluginDefinition(bpContext *ctx, void *value)
1418 {
1419 bRC retval = bRC_Error;
1420 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
1421 PyObject *pFunc;
1422
1423 /*
1424 * Lookup the parse_plugin_definition() function in the python module.
1425 */
1426 pFunc = PyDict_GetItemString(p_ctx->pDict, "parse_plugin_definition"); /* Borrowed reference */
1427 if (pFunc && PyCallable_Check(pFunc)) {
1428 PyObject *pPluginDefinition,
1429 *pRetVal;
1430
1431 pPluginDefinition = PyString_FromString((char *)value);
1432 if (!pPluginDefinition) {
1433 goto bail_out;
1434 }
1435
1436 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pPluginDefinition, NULL);
1437 Py_DECREF(pPluginDefinition);
1438
1439 if (!pRetVal) {
1440 goto bail_out;
1441 } else {
1442 retval = conv_python_retval(pRetVal);
1443 Py_DECREF(pRetVal);
1444 }
1445
1446 return retval;
1447 } else {
1448 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named parse_plugin_definition()\n");
1449 return bRC_Error;
1450 }
1451
1452 bail_out:
1453 if (PyErr_Occurred()) {
1454 PyErrorHandler(ctx, M_FATAL);
1455 }
1456
1457 return retval;
1458 }
1459
PyGetPluginValue(bpContext * ctx,pVariable var,void * value)1460 static bRC PyGetPluginValue(bpContext *ctx, pVariable var, void *value)
1461 {
1462 return bRC_OK;
1463 }
1464
PySetPluginValue(bpContext * ctx,pVariable var,void * value)1465 static bRC PySetPluginValue(bpContext *ctx, pVariable var, void *value)
1466 {
1467 return bRC_OK;
1468 }
1469
PyHandlePluginEvent(bpContext * ctx,bEvent * event,void * value)1470 static bRC PyHandlePluginEvent(bpContext *ctx, bEvent *event, void *value)
1471 {
1472 bRC retval = bRC_Error;
1473 plugin_ctx *p_ctx = (plugin_ctx *)ctx->pContext;
1474 PyObject *pFunc;
1475
1476 /*
1477 * Lookup the handle_plugin_event() function in the python module.
1478 */
1479 pFunc = PyDict_GetItemString(p_ctx->pDict, "handle_plugin_event"); /* Borrowed reference */
1480 if (pFunc && PyCallable_Check(pFunc)) {
1481 PyObject *pEventType,
1482 *pRetVal;
1483
1484 pEventType = PyInt_FromLong(event->eventType);
1485
1486 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pEventType, NULL);
1487 Py_DECREF(pEventType);
1488
1489 if (!pRetVal) {
1490 goto bail_out;
1491 } else {
1492 retval = conv_python_retval(pRetVal);
1493 Py_DECREF(pRetVal);
1494 }
1495 } else {
1496 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named handle_plugin_event()\n");
1497 }
1498
1499 return retval;
1500
1501 bail_out:
1502 if (PyErr_Occurred()) {
1503 PyErrorHandler(ctx, M_FATAL);
1504 }
1505
1506 return retval;
1507 }
1508
NativeToPyStatPacket(struct stat * statp)1509 static inline PyStatPacket *NativeToPyStatPacket(struct stat *statp)
1510 {
1511 PyStatPacket *pStatp = PyObject_New(PyStatPacket, &PyStatPacketType);
1512
1513 if (pStatp) {
1514 pStatp->dev = statp->st_dev;
1515 pStatp->ino = statp->st_ino;
1516 pStatp->mode = statp->st_mode;
1517 pStatp->nlink = statp->st_nlink;
1518 pStatp->uid = statp->st_uid;
1519 pStatp->gid = statp->st_gid;
1520 pStatp->rdev = statp->st_rdev;
1521 pStatp->size = statp->st_size;
1522 pStatp->atime = statp->st_atime;
1523 pStatp->mtime = statp->st_mtime;
1524 pStatp->ctime = statp->st_ctime;
1525 pStatp->blksize = statp->st_blksize;
1526 pStatp->blocks = statp->st_blocks;
1527 }
1528
1529 return pStatp;
1530 }
1531
PyStatPacketToNative(PyStatPacket * pStatp,struct stat * statp)1532 static inline void PyStatPacketToNative(PyStatPacket *pStatp, struct stat *statp)
1533 {
1534 statp->st_dev = pStatp->dev;
1535 statp->st_ino = pStatp->ino;
1536 statp->st_mode = pStatp->mode;
1537 statp->st_nlink = pStatp->nlink;
1538 statp->st_uid = pStatp->uid;
1539 statp->st_gid = pStatp->gid;
1540 statp->st_rdev = pStatp->rdev;
1541 statp->st_size = pStatp->size;
1542 statp->st_atime = pStatp->atime;
1543 statp->st_mtime = pStatp->mtime;
1544 statp->st_ctime = pStatp->ctime;
1545 statp->st_blksize = pStatp->blksize;
1546 statp->st_blocks = pStatp->blocks;
1547 }
1548
NativeToPySavePacket(struct save_pkt * sp)1549 static inline PySavePacket *NativeToPySavePacket(struct save_pkt *sp)
1550 {
1551 PySavePacket *pSavePkt = PyObject_New(PySavePacket, &PySavePacketType);
1552
1553 if (pSavePkt) {
1554 /*
1555 * Initialize the Python SavePkt with the data we got passed in.
1556 */
1557 if (sp->fname) {
1558 pSavePkt->fname = PyString_FromString(sp->fname);
1559 } else {
1560 pSavePkt->fname = NULL;
1561 }
1562
1563 if (sp->link) {
1564 pSavePkt->link = PyString_FromString(sp->link);
1565 } else {
1566 pSavePkt->link = NULL;
1567 }
1568
1569 if (sp->statp.st_mode) {
1570 pSavePkt->statp = (PyObject *)NativeToPyStatPacket(&sp->statp);
1571 } else {
1572 pSavePkt->statp = NULL;
1573 }
1574
1575 pSavePkt->type = sp->type;
1576 pSavePkt->flags = PyByteArray_FromStringAndSize(sp->flags, sizeof(sp->flags));
1577 pSavePkt->no_read = sp->no_read;
1578 pSavePkt->portable = sp->portable;
1579 pSavePkt->accurate_found = sp->accurate_found;
1580 pSavePkt->cmd = sp->cmd;
1581 pSavePkt->save_time = sp->save_time;
1582 pSavePkt->delta_seq = sp->delta_seq;
1583 pSavePkt->object_name = NULL;
1584 pSavePkt->object = NULL;
1585 pSavePkt->object_len = sp->object_len;
1586 pSavePkt->object_index = sp->index;
1587 }
1588
1589 return pSavePkt;
1590 }
1591
PySavePacketToNative(PySavePacket * pSavePkt,struct save_pkt * sp,struct plugin_ctx * p_ctx,bool is_options_plugin)1592 static inline bool PySavePacketToNative(PySavePacket *pSavePkt, struct save_pkt *sp,
1593 struct plugin_ctx *p_ctx, bool is_options_plugin)
1594 {
1595 /*
1596 * See if this is for an Options Plugin.
1597 */
1598 if (!is_options_plugin) {
1599 /*
1600 * Only copy back the arguments that are allowed to change.
1601 */
1602 if (pSavePkt->fname) {
1603 /*
1604 * As this has to linger as long as the backup is running we save it in our plugin context.
1605 */
1606 if (PyString_Check(pSavePkt->fname)) {
1607 if (p_ctx->fname) {
1608 free(p_ctx->fname);
1609 }
1610 p_ctx->fname = bstrdup(PyString_AsString(pSavePkt->fname));
1611 sp->fname = p_ctx->fname;
1612 }
1613 } else {
1614 goto bail_out;
1615 }
1616
1617 /*
1618 * Optional field.
1619 */
1620 if (pSavePkt->link) {
1621 /*
1622 * As this has to linger as long as the backup is running we save it in our plugin context.
1623 */
1624 if (PyString_Check(pSavePkt->link)) {
1625 if (p_ctx->link) {
1626 free(p_ctx->link);
1627 }
1628 p_ctx->link = bstrdup(PyString_AsString(pSavePkt->link));
1629 sp->link = p_ctx->link;
1630 }
1631 }
1632
1633 /*
1634 * Handle the stat structure.
1635 */
1636 if (pSavePkt->statp) {
1637 PyStatPacketToNative((PyStatPacket *)pSavePkt->statp, &sp->statp);
1638 } else {
1639 goto bail_out;
1640 }
1641
1642 sp->type = pSavePkt->type;
1643
1644 if (PyByteArray_Check(pSavePkt->flags)) {
1645 char *flags;
1646
1647 if (PyByteArray_Size(pSavePkt->flags) != sizeof(sp->flags)) {
1648 goto bail_out;
1649 }
1650
1651 if ((flags = PyByteArray_AsString(pSavePkt->flags))) {
1652 memcpy(sp->flags, flags, sizeof(sp->flags));
1653 } else {
1654 goto bail_out;
1655 }
1656 } else {
1657 goto bail_out;
1658 }
1659
1660 /*
1661 * Special code for handling restore objects.
1662 */
1663 if (IS_FT_OBJECT(sp->type)) {
1664 /*
1665 * See if a proper restore object was created.
1666 */
1667 if (pSavePkt->object_len > 0) {
1668 /*
1669 * As this has to linger as long as the backup is running we save it in our plugin context.
1670 */
1671 if (pSavePkt->object_name &&
1672 pSavePkt->object &&
1673 PyString_Check(pSavePkt->object_name) &&
1674 PyByteArray_Check(pSavePkt->object)) {
1675 char *buf;
1676
1677 if (p_ctx->object_name) {
1678 free(p_ctx->object_name);
1679 }
1680 p_ctx->object_name = bstrdup(PyString_AsString(pSavePkt->object_name));
1681 sp->object_name = p_ctx->object_name;
1682
1683 sp->object_len = pSavePkt->object_len;
1684 sp->index = pSavePkt->object_index;
1685
1686 if ((buf = PyByteArray_AsString(pSavePkt->object))) {
1687 if (p_ctx->object) {
1688 free(p_ctx->object);
1689 }
1690 p_ctx->object = (char *)malloc(pSavePkt->object_len);
1691 memcpy(p_ctx->object, buf, pSavePkt->object_len);
1692 sp->object = p_ctx->object;
1693 } else {
1694 goto bail_out;
1695 }
1696 } else {
1697 goto bail_out;
1698 }
1699 } else {
1700 goto bail_out;
1701 }
1702 } else {
1703 sp->no_read = pSavePkt->no_read;
1704 sp->delta_seq = pSavePkt->delta_seq;
1705 }
1706 } else {
1707 sp->no_read = pSavePkt->no_read;
1708 sp->delta_seq = pSavePkt->delta_seq;
1709
1710 if (PyByteArray_Check(pSavePkt->flags)) {
1711 char *flags;
1712
1713 if (PyByteArray_Size(pSavePkt->flags) != sizeof(sp->flags)) {
1714 goto bail_out;
1715 }
1716
1717 if ((flags = PyByteArray_AsString(pSavePkt->flags))) {
1718 memcpy(sp->flags, flags, sizeof(sp->flags));
1719 } else {
1720 goto bail_out;
1721 }
1722 } else {
1723 goto bail_out;
1724 }
1725 }
1726
1727 return true;
1728
1729 bail_out:
1730 return false;
1731 }
1732
1733 /**
1734 * Called when starting to backup a file. Here the plugin must
1735 * return the "stat" packet for the directory/file and provide
1736 * certain information so that Bareos knows what the file is.
1737 * The plugin can create "Virtual" files by giving them a
1738 * name that is not normally found on the file system.
1739 */
PyStartBackupFile(bpContext * ctx,struct save_pkt * sp)1740 static bRC PyStartBackupFile(bpContext *ctx, struct save_pkt *sp)
1741 {
1742 bRC retval = bRC_Error;
1743 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
1744 PyObject *pFunc;
1745
1746 /*
1747 * Lookup the start_backup_file() function in the python module.
1748 */
1749 pFunc = PyDict_GetItemString(p_ctx->pDict, "start_backup_file"); /* Borrowed reference */
1750 if (pFunc && PyCallable_Check(pFunc)) {
1751 PySavePacket *pSavePkt;
1752 PyObject *pRetVal;
1753
1754 pSavePkt = NativeToPySavePacket(sp);
1755 if (!pSavePkt) {
1756 goto bail_out;
1757 }
1758
1759 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, (PyObject *)pSavePkt, NULL);
1760 if (!pRetVal) {
1761 Py_DECREF((PyObject *)pSavePkt);
1762 goto bail_out;
1763 } else {
1764 retval = conv_python_retval(pRetVal);
1765 Py_DECREF(pRetVal);
1766
1767 if (!PySavePacketToNative(pSavePkt, sp, p_ctx, false)) {
1768 Py_DECREF((PyObject *)pSavePkt);
1769 goto bail_out;
1770 }
1771 Py_DECREF((PyObject *)pSavePkt);
1772 }
1773 } else {
1774 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named start_backup_file()\n");
1775 }
1776
1777 return retval;
1778
1779 bail_out:
1780 if (PyErr_Occurred()) {
1781 PyErrorHandler(ctx, M_FATAL);
1782 }
1783
1784 return retval;
1785 }
1786
1787 /**
1788 * Called at the end of backing up a file for a command plugin.
1789 * If the plugin's work is done, it should return bRC_OK.
1790 * If the plugin wishes to create another file and back it up,
1791 * then it must return bRC_More (not yet implemented).
1792 */
PyEndBackupFile(bpContext * ctx)1793 static bRC PyEndBackupFile(bpContext *ctx)
1794 {
1795 bRC retval = bRC_Error;
1796 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
1797 PyObject *pFunc;
1798
1799 /*
1800 * Lookup the end_backup_file() function in the python module.
1801 */
1802 pFunc = PyDict_GetItemString(p_ctx->pDict, "end_backup_file"); /* Borrowed reference */
1803 if (pFunc && PyCallable_Check(pFunc)) {
1804 PyObject *pRetVal;
1805
1806 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, NULL);
1807 if (!pRetVal) {
1808 goto bail_out;
1809 } else {
1810 retval = conv_python_retval(pRetVal);
1811 }
1812 } else {
1813 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named end_backup_file()\n");
1814 }
1815
1816 return retval;
1817
1818 bail_out:
1819 if (PyErr_Occurred()) {
1820 PyErrorHandler(ctx, M_FATAL);
1821 }
1822
1823 return retval;
1824 }
1825
NativeToPyIoPacket(struct io_pkt * io)1826 static inline PyIoPacket *NativeToPyIoPacket(struct io_pkt *io)
1827 {
1828 PyIoPacket *pIoPkt = PyObject_New(PyIoPacket, &PyIoPacketType);
1829
1830 if (pIoPkt) {
1831 /*
1832 * Initialize the Python IoPkt with the data we got passed in.
1833 */
1834 pIoPkt->func = io->func;
1835 pIoPkt->count = io->count;
1836 pIoPkt->flags = io->flags;
1837 pIoPkt->mode = io->mode;
1838 pIoPkt->fname = io->fname;
1839 pIoPkt->whence = io->whence;
1840 pIoPkt->offset = io->offset;
1841 if (io->func == IO_WRITE && io->count > 0) {
1842 /*
1843 * Only initialize the buffer with read data when we are writing and there is data.
1844 */
1845 pIoPkt->buf = PyByteArray_FromStringAndSize(io->buf, io->count);
1846 if (!pIoPkt->buf) {
1847 Py_DECREF((PyObject *)pIoPkt);
1848 return (PyIoPacket *)NULL;
1849 }
1850 } else {
1851 pIoPkt->buf = NULL;
1852 }
1853
1854 /*
1855 * These must be set by the Python function but we initialize them to zero
1856 * to be sure they have some valid setting an not random data.
1857 */
1858 pIoPkt->io_errno = 0;
1859 pIoPkt->lerror = 0;
1860 pIoPkt->win32 = false;
1861 pIoPkt->status = 0;
1862 }
1863
1864 return pIoPkt;
1865 }
1866
PyIoPacketToNative(PyIoPacket * pIoPkt,struct io_pkt * io)1867 static inline bool PyIoPacketToNative(PyIoPacket *pIoPkt, struct io_pkt *io)
1868 {
1869 /*
1870 * Only copy back the arguments that are allowed to change.
1871 */
1872 io->io_errno = pIoPkt->io_errno;
1873 io->lerror = pIoPkt->lerror;
1874 io->win32 = pIoPkt->win32;
1875 io->status = pIoPkt->status;
1876 if (io->func == IO_READ && io->status > 0) {
1877 /*
1878 * Only copy back the data when doing a read and there is data.
1879 */
1880 if (PyByteArray_Check(pIoPkt->buf)) {
1881 char *buf;
1882
1883 if (PyByteArray_Size(pIoPkt->buf) > io->count || io->status > io->count) {
1884 return false;
1885 }
1886
1887 if (!(buf = PyByteArray_AsString(pIoPkt->buf))) {
1888 return false;
1889 }
1890 memcpy(io->buf, buf, io->status);
1891 }
1892 }
1893
1894 return true;
1895 }
1896
1897 /**
1898 * Do actual I/O. Bareos calls this after startBackupFile
1899 * or after startRestoreFile to do the actual file
1900 * input or output.
1901 */
PyPluginIO(bpContext * ctx,struct io_pkt * io)1902 static bRC PyPluginIO(bpContext *ctx, struct io_pkt *io)
1903 {
1904 bRC retval = bRC_Error;
1905 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
1906 PyObject *pFunc;
1907
1908 /*
1909 * Lookup the plugin_io() function in the python module.
1910 */
1911 pFunc = PyDict_GetItemString(p_ctx->pDict, "plugin_io"); /* Borrowed reference */
1912 if (pFunc && PyCallable_Check(pFunc)) {
1913 PyIoPacket *pIoPkt;
1914 PyObject *pRetVal;
1915
1916 pIoPkt = NativeToPyIoPacket(io);
1917 if (!pIoPkt) {
1918 goto bail_out;
1919 }
1920
1921 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, (PyObject *)pIoPkt, NULL);
1922 if (!pRetVal) {
1923 Py_DECREF((PyObject *)pIoPkt);
1924 goto bail_out;
1925 } else {
1926 retval = conv_python_retval(pRetVal);
1927 Py_DECREF(pRetVal);
1928
1929 if (!PyIoPacketToNative(pIoPkt, io)) {
1930 Py_DECREF((PyObject *)pIoPkt);
1931 goto bail_out;
1932 }
1933 }
1934 Py_DECREF((PyObject *)pIoPkt);
1935 } else {
1936 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named plugin_io()\n");
1937 }
1938
1939 return retval;
1940
1941 bail_out:
1942 if (PyErr_Occurred()) {
1943 PyErrorHandler(ctx, M_FATAL);
1944 }
1945
1946 io->status = -1;
1947
1948 return retval;
1949 }
1950
1951 /**
1952 * Called when the first record is read from the Volume that was previously written by the command plugin.
1953 */
PyStartRestoreFile(bpContext * ctx,const char * cmd)1954 static bRC PyStartRestoreFile(bpContext *ctx, const char *cmd)
1955 {
1956 bRC retval = bRC_Error;
1957 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
1958 PyObject *pFunc;
1959
1960 /*
1961 * Lookup the start_restore_file() function in the python module.
1962 */
1963 pFunc = PyDict_GetItemString(p_ctx->pDict, "start_restore_file"); /* Borrowed reference */
1964 if (pFunc && PyCallable_Check(pFunc)) {
1965 PyObject *pCmd,
1966 *pRetVal;
1967
1968 pCmd = PyString_FromString(cmd);
1969 if (!pCmd) {
1970 goto bail_out;
1971 }
1972
1973 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pCmd, NULL);
1974 Py_DECREF(pCmd);
1975
1976 if (!pRetVal) {
1977 goto bail_out;
1978 } else {
1979 retval = conv_python_retval(pRetVal);
1980 Py_DECREF(pRetVal);
1981 }
1982 } else {
1983 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named start_restore_file()\n");
1984 }
1985
1986 return retval;
1987
1988 bail_out:
1989 if (PyErr_Occurred()) {
1990 PyErrorHandler(ctx, M_FATAL);
1991 }
1992
1993 return retval;
1994 }
1995
1996 /**
1997 * Called when a command plugin is done restoring a file.
1998 */
PyEndRestoreFile(bpContext * ctx)1999 static bRC PyEndRestoreFile(bpContext *ctx)
2000 {
2001 bRC retval = bRC_Error;
2002 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
2003 PyObject *pFunc;
2004
2005 /*
2006 * Lookup the end_restore_file() function in the python module.
2007 */
2008 pFunc = PyDict_GetItemString(p_ctx->pDict, "end_restore_file"); /* Borrowed reference */
2009 if (pFunc && PyCallable_Check(pFunc)) {
2010 PyObject *pRetVal;
2011
2012 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, NULL);
2013 if (!pRetVal) {
2014 goto bail_out;
2015 } else {
2016 retval = conv_python_retval(pRetVal);
2017 }
2018 } else {
2019 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named end_restore_file()\n");
2020 }
2021
2022 return retval;
2023
2024 bail_out:
2025 if (PyErr_Occurred()) {
2026 PyErrorHandler(ctx, M_FATAL);
2027 }
2028
2029 return retval;
2030 }
2031
NativeToPyRestorePacket(struct restore_pkt * rp)2032 static inline PyRestorePacket *NativeToPyRestorePacket(struct restore_pkt *rp)
2033 {
2034 PyRestorePacket *pRestorePacket = PyObject_New(PyRestorePacket, &PyRestorePacketType);
2035
2036 if (pRestorePacket) {
2037 pRestorePacket->stream = rp->stream;
2038 pRestorePacket->data_stream = rp->data_stream;
2039 pRestorePacket->type = rp->type;
2040 pRestorePacket->file_index = rp->file_index;
2041 pRestorePacket->LinkFI = rp->LinkFI;
2042 pRestorePacket->uid = rp->uid;
2043 pRestorePacket->statp = (PyObject *)NativeToPyStatPacket(&rp->statp);
2044 pRestorePacket->attrEx = rp->attrEx;
2045 pRestorePacket->ofname = rp->ofname;
2046 pRestorePacket->olname = rp->olname;
2047 pRestorePacket->where = rp->where;
2048 pRestorePacket->RegexWhere = rp->RegexWhere;
2049 pRestorePacket->replace = rp->replace;
2050 pRestorePacket->create_status = rp->create_status;
2051 }
2052
2053 return pRestorePacket;
2054 }
2055
PyRestorePacketToNative(PyRestorePacket * pRestorePacket,struct restore_pkt * rp)2056 static inline void PyRestorePacketToNative(PyRestorePacket *pRestorePacket, struct restore_pkt *rp)
2057 {
2058 /*
2059 * Only copy back the fields that are allowed to be changed.
2060 */
2061 rp->create_status = pRestorePacket->create_status;
2062 }
2063
2064 /**
2065 * Called for a command plugin to create a file during a Restore job before restoring the data.
2066 * This entry point is called before any I/O is done on the file. After this call,
2067 * Bareos will call pluginIO() to open the file for write.
2068 *
2069 * We must return in rp->create_status:
2070 *
2071 * CF_ERROR -- error
2072 * CF_SKIP -- skip processing this file
2073 * CF_EXTRACT -- extract the file (i.e.call i/o routines)
2074 * CF_CREATED -- created, but no content to extract (typically directories)
2075 */
PyCreateFile(bpContext * ctx,struct restore_pkt * rp)2076 static bRC PyCreateFile(bpContext *ctx, struct restore_pkt *rp)
2077 {
2078 bRC retval = bRC_Error;
2079 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
2080 PyObject *pFunc;
2081
2082 if (!rp) {
2083 return bRC_Error;
2084 }
2085
2086 /*
2087 * Lookup the create_file() function in the python module.
2088 */
2089 pFunc = PyDict_GetItemString(p_ctx->pDict, "create_file"); /* Borrowed reference */
2090 if (pFunc && PyCallable_Check(pFunc)) {
2091 PyRestorePacket *pRestorePacket;
2092 PyObject *pRetVal;
2093
2094 pRestorePacket = NativeToPyRestorePacket(rp);
2095 if (!pRestorePacket) {
2096 goto bail_out;
2097 }
2098
2099 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pRestorePacket, NULL);
2100 if (!pRetVal) {
2101 Py_DECREF(pRestorePacket);
2102 goto bail_out;
2103 } else {
2104 retval = conv_python_retval(pRetVal);
2105 Py_DECREF(pRetVal);
2106
2107 PyRestorePacketToNative(pRestorePacket, rp);
2108 Py_DECREF(pRestorePacket);
2109 }
2110 } else {
2111 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named create_file()\n");
2112 }
2113
2114 return retval;
2115
2116 bail_out:
2117 if (PyErr_Occurred()) {
2118 PyErrorHandler(ctx, M_FATAL);
2119 }
2120
2121 return retval;
2122 }
2123
PySetFileAttributes(bpContext * ctx,struct restore_pkt * rp)2124 static bRC PySetFileAttributes(bpContext *ctx, struct restore_pkt *rp)
2125 {
2126 bRC retval = bRC_Error;
2127 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
2128 PyObject *pFunc;
2129
2130 if (!rp) {
2131 return bRC_Error;
2132 }
2133
2134 /*
2135 * Lookup the set_file_attributes() function in the python module.
2136 */
2137 pFunc = PyDict_GetItemString(p_ctx->pDict, "set_file_attributes"); /* Borrowed reference */
2138 if (pFunc && PyCallable_Check(pFunc)) {
2139 PyRestorePacket *pRestorePacket;
2140 PyObject *pRetVal;
2141
2142 pRestorePacket = NativeToPyRestorePacket(rp);
2143 if (!pRestorePacket) {
2144 goto bail_out;
2145 }
2146
2147 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pRestorePacket, NULL);
2148 if (!pRetVal) {
2149 Py_DECREF(pRestorePacket);
2150 goto bail_out;
2151 } else {
2152 retval = conv_python_retval(pRetVal);
2153 Py_DECREF(pRetVal);
2154 Py_DECREF(pRestorePacket);
2155 }
2156 } else {
2157 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named set_file_attributes()\n");
2158 }
2159
2160 return retval;
2161
2162 bail_out:
2163 if (PyErr_Occurred()) {
2164 PyErrorHandler(ctx, M_FATAL);
2165 }
2166
2167 return retval;
2168 }
2169
PyCheckFile(bpContext * ctx,char * fname)2170 static bRC PyCheckFile(bpContext *ctx, char *fname)
2171 {
2172 bRC retval = bRC_Error;
2173 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
2174 PyObject *pFunc;
2175
2176 if (!fname) {
2177 return bRC_Error;
2178 }
2179
2180 /*
2181 * Lookup the check_file() function in the python module.
2182 */
2183 pFunc = PyDict_GetItemString(p_ctx->pDict, "check_file"); /* Borrowed reference */
2184 if (pFunc && PyCallable_Check(pFunc)) {
2185 PyObject *pFname,
2186 *pRetVal;
2187
2188 pFname = PyString_FromString(fname);
2189 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pFname, NULL);
2190 Py_DECREF(pFname);
2191
2192 if (!pRetVal) {
2193 goto bail_out;
2194 } else {
2195 retval = conv_python_retval(pRetVal);
2196 Py_DECREF(pRetVal);
2197 }
2198 } else {
2199 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named check_file()\n");
2200 }
2201
2202 return retval;
2203
2204 bail_out:
2205 if (PyErr_Occurred()) {
2206 PyErrorHandler(ctx, M_FATAL);
2207 }
2208
2209 return retval;
2210 }
2211
NativeToPyAclPacket(struct acl_pkt * ap)2212 static inline PyAclPacket *NativeToPyAclPacket(struct acl_pkt *ap)
2213 {
2214 PyAclPacket *pAclPacket = PyObject_New(PyAclPacket, &PyAclPacketType);
2215
2216 if (pAclPacket) {
2217 pAclPacket->fname = ap->fname;
2218
2219 if (ap->content_length && ap->content) {
2220 pAclPacket->content = PyByteArray_FromStringAndSize(ap->content, ap->content_length);
2221 } else {
2222 pAclPacket->content = NULL;
2223 }
2224 }
2225
2226 return pAclPacket;
2227 }
2228
PyAclPacketToNative(PyAclPacket * pAclPacket,struct acl_pkt * ap)2229 static inline bool PyAclPacketToNative(PyAclPacket *pAclPacket, struct acl_pkt *ap)
2230 {
2231 if (!pAclPacket->content) {
2232 return true;
2233 }
2234
2235 if (PyByteArray_Check(pAclPacket->content)) {
2236 char *buf;
2237
2238 ap->content_length = PyByteArray_Size(pAclPacket->content);
2239 if (ap->content_length <= 0 || !(buf = PyByteArray_AsString(pAclPacket->content))) {
2240 return false;
2241 }
2242
2243 if (ap->content) {
2244 free(ap->content);
2245 }
2246 ap->content = (char *)malloc(ap->content_length);
2247 memcpy(ap->content, buf, ap->content_length);
2248 }
2249
2250 return true;
2251 }
2252
PyGetAcl(bpContext * ctx,acl_pkt * ap)2253 static bRC PyGetAcl(bpContext *ctx, acl_pkt *ap)
2254 {
2255 bRC retval = bRC_Error;
2256 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
2257 PyObject *pFunc;
2258
2259 if (!ap) {
2260 return bRC_Error;
2261 }
2262
2263 /*
2264 * Lookup the get_acl() function in the python module.
2265 */
2266 pFunc = PyDict_GetItemString(p_ctx->pDict, "get_acl"); /* Borrowed reference */
2267 if (pFunc && PyCallable_Check(pFunc)) {
2268 PyAclPacket *pAclPkt;
2269 PyObject *pRetVal;
2270
2271 pAclPkt = NativeToPyAclPacket(ap);
2272 if (!pAclPkt) {
2273 goto bail_out;
2274 }
2275
2276 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pAclPkt, NULL);
2277 if (!pRetVal) {
2278 Py_DECREF((PyObject *)pAclPkt);
2279 goto bail_out;
2280 } else {
2281 retval = conv_python_retval(pRetVal);
2282 Py_DECREF(pRetVal);
2283
2284 if (!PyAclPacketToNative(pAclPkt, ap)) {
2285 Py_DECREF((PyObject *)pAclPkt);
2286 goto bail_out;
2287 }
2288 Py_DECREF(pAclPkt);
2289 }
2290 } else {
2291 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named get_acl()\n");
2292 }
2293
2294 return retval;
2295
2296 bail_out:
2297 if (PyErr_Occurred()) {
2298 PyErrorHandler(ctx, M_FATAL);
2299 }
2300
2301 return retval;
2302 }
2303
PySetAcl(bpContext * ctx,acl_pkt * ap)2304 static bRC PySetAcl(bpContext *ctx, acl_pkt *ap)
2305 {
2306 bRC retval = bRC_Error;
2307 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
2308 PyObject *pFunc;
2309
2310 if (!ap) {
2311 return bRC_Error;
2312 }
2313
2314 /*
2315 * Lookup the set_acl() function in the python module.
2316 */
2317 pFunc = PyDict_GetItemString(p_ctx->pDict, "set_acl"); /* Borrowed reference */
2318 if (pFunc && PyCallable_Check(pFunc)) {
2319 PyAclPacket *pAclPkt;
2320 PyObject *pRetVal;
2321
2322 pAclPkt = NativeToPyAclPacket(ap);
2323 if (!pAclPkt) {
2324 goto bail_out;
2325 }
2326
2327 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pAclPkt, NULL);
2328 Py_DECREF(pAclPkt);
2329
2330 if (!pRetVal) {
2331 goto bail_out;
2332 } else {
2333 retval = conv_python_retval(pRetVal);
2334 Py_DECREF(pRetVal);
2335 }
2336 } else {
2337 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named set_acl()\n");
2338 }
2339
2340 return retval;
2341
2342 bail_out:
2343 if (PyErr_Occurred()) {
2344 PyErrorHandler(ctx, M_FATAL);
2345 }
2346
2347 return retval;
2348 }
2349
NativeToPyXattrPacket(struct xattr_pkt * xp)2350 static inline PyXattrPacket *NativeToPyXattrPacket(struct xattr_pkt *xp)
2351 {
2352 PyXattrPacket *pXattrPacket = PyObject_New(PyXattrPacket, &PyXattrPacketType);
2353
2354 if (pXattrPacket) {
2355 pXattrPacket->fname = xp->fname;
2356
2357 if (xp->name_length && xp->name) {
2358 pXattrPacket->name = PyByteArray_FromStringAndSize(xp->name, xp->name_length);
2359 } else {
2360 pXattrPacket->name = NULL;
2361 }
2362 if (xp->value_length && xp->value) {
2363 pXattrPacket->value = PyByteArray_FromStringAndSize(xp->value, xp->value_length);
2364 } else {
2365 pXattrPacket->value = NULL;
2366 }
2367 }
2368
2369 return pXattrPacket;
2370 }
2371
PyXattrPacketToNative(PyXattrPacket * pXattrPacket,struct xattr_pkt * xp)2372 static inline bool PyXattrPacketToNative(PyXattrPacket *pXattrPacket, struct xattr_pkt *xp)
2373 {
2374 if (!pXattrPacket->name) {
2375 return true;
2376 }
2377
2378 if (PyByteArray_Check(pXattrPacket->name)) {
2379 char *buf;
2380
2381 xp->name_length = PyByteArray_Size(pXattrPacket->name);
2382 if (xp->name_length <= 0 || !(buf = PyByteArray_AsString(pXattrPacket->name))) {
2383 return false;
2384 }
2385
2386 if (xp->name) {
2387 free(xp->name);
2388 }
2389 xp->name = (char *)malloc(xp->name_length);
2390 memcpy(xp->name, buf, xp->name_length);
2391 }
2392
2393 if (pXattrPacket->value && PyByteArray_Check(pXattrPacket->value)) {
2394 char *buf;
2395
2396 xp->value_length = PyByteArray_Size(pXattrPacket->value);
2397 if (xp->name_length <= 0 || !(buf = PyByteArray_AsString(pXattrPacket->name))) {
2398 return false;
2399 }
2400
2401 if (xp->value) {
2402 free(xp->value);
2403 }
2404 xp->value = (char *)malloc(xp->value_length);
2405 memcpy(xp->value, buf, xp->value_length);
2406 } else {
2407 if (xp->value) {
2408 free(xp->value);
2409 }
2410 xp->value = NULL;
2411 }
2412
2413 return true;
2414 }
2415
PyGetXattr(bpContext * ctx,xattr_pkt * xp)2416 static bRC PyGetXattr(bpContext *ctx, xattr_pkt *xp)
2417 {
2418 bRC retval = bRC_Error;
2419 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
2420 PyObject *pFunc;
2421
2422 if (!xp) {
2423 return bRC_Error;
2424 }
2425
2426 /*
2427 * Lookup the get_xattr() function in the python module.
2428 */
2429 pFunc = PyDict_GetItemString(p_ctx->pDict, "get_xattr"); /* Borrowed reference */
2430 if (pFunc && PyCallable_Check(pFunc)) {
2431 PyXattrPacket *pXattrPkt;
2432 PyObject *pRetVal;
2433
2434 pXattrPkt = NativeToPyXattrPacket(xp);
2435 if (!pXattrPkt) {
2436 goto bail_out;
2437 }
2438
2439 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pXattrPkt, NULL);
2440 if (!pRetVal) {
2441 Py_DECREF((PyObject *)pXattrPkt);
2442 goto bail_out;
2443 } else {
2444 retval = conv_python_retval(pRetVal);
2445 Py_DECREF(pRetVal);
2446
2447 if (!PyXattrPacketToNative(pXattrPkt, xp)) {
2448 Py_DECREF((PyObject *)pXattrPkt);
2449 goto bail_out;
2450 }
2451 Py_DECREF(pXattrPkt);
2452 }
2453 } else {
2454 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named get_xattr()\n");
2455 }
2456
2457 return retval;
2458
2459 bail_out:
2460 if (PyErr_Occurred()) {
2461 PyErrorHandler(ctx, M_FATAL);
2462 }
2463
2464 return retval;
2465 }
2466
PySetXattr(bpContext * ctx,xattr_pkt * xp)2467 static bRC PySetXattr(bpContext *ctx, xattr_pkt *xp)
2468 {
2469 bRC retval = bRC_Error;
2470 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
2471 PyObject *pFunc;
2472
2473 if (!xp) {
2474 return bRC_Error;
2475 }
2476
2477 /*
2478 * Lookup the set_acl() function in the python module.
2479 */
2480 pFunc = PyDict_GetItemString(p_ctx->pDict, "set_xattr"); /* Borrowed reference */
2481 if (pFunc && PyCallable_Check(pFunc)) {
2482 PyXattrPacket *pXattrPkt;
2483 PyObject *pRetVal;
2484
2485 pXattrPkt = NativeToPyXattrPacket(xp);
2486 if (!pXattrPkt) {
2487 goto bail_out;
2488 }
2489
2490 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pXattrPkt, NULL);
2491 Py_DECREF(pXattrPkt);
2492
2493 if (!pRetVal) {
2494 goto bail_out;
2495 } else {
2496 retval = conv_python_retval(pRetVal);
2497 Py_DECREF(pRetVal);
2498 }
2499 } else {
2500 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named set_xattr()\n");
2501 }
2502
2503 return retval;
2504 bail_out:
2505 if (PyErr_Occurred()) {
2506 PyErrorHandler(ctx, M_FATAL);
2507 }
2508
2509 return retval;
2510 }
2511
NativeToPyRestoreObject(struct restore_object_pkt * rop)2512 static inline PyRestoreObject *NativeToPyRestoreObject(struct restore_object_pkt *rop)
2513 {
2514 PyRestoreObject *pRestoreObject = PyObject_New(PyRestoreObject, &PyRestoreObjectType);
2515
2516 if (pRestoreObject) {
2517 pRestoreObject->object_name = PyString_FromString(rop->object_name);
2518 pRestoreObject->object = PyByteArray_FromStringAndSize(rop->object, rop->object_len);
2519 pRestoreObject->plugin_name = rop->plugin_name;
2520 pRestoreObject->object_type = rop->object_type;
2521 pRestoreObject->object_len = rop->object_len;
2522 pRestoreObject->object_full_len = rop->object_full_len;
2523 pRestoreObject->object_index = rop->object_index;
2524 pRestoreObject->object_compression = rop->object_compression;
2525 pRestoreObject->stream = rop->stream;
2526 pRestoreObject->JobId = rop->JobId;
2527 }
2528
2529 return pRestoreObject;
2530 }
2531
PyRestoreObjectData(bpContext * ctx,struct restore_object_pkt * rop)2532 static bRC PyRestoreObjectData(bpContext *ctx, struct restore_object_pkt *rop)
2533 {
2534 bRC retval = bRC_Error;
2535 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
2536 PyObject *pFunc;
2537
2538 if (!rop) {
2539 return bRC_OK;
2540 }
2541
2542 /*
2543 * Lookup the restore_object_data() function in the python module.
2544 */
2545 pFunc = PyDict_GetItemString(p_ctx->pDict, "restore_object_data"); /* Borrowed reference */
2546 if (pFunc && PyCallable_Check(pFunc)) {
2547 PyRestoreObject *pRestoreObject;
2548 PyObject *pRetVal;
2549
2550 pRestoreObject = NativeToPyRestoreObject(rop);
2551 if (!pRestoreObject) {
2552 goto bail_out;
2553 }
2554
2555 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pRestoreObject, NULL);
2556 Py_DECREF(pRestoreObject);
2557
2558 if (!pRetVal) {
2559 goto bail_out;
2560 } else {
2561 retval = conv_python_retval(pRetVal);
2562 Py_DECREF(pRetVal);
2563 }
2564 } else {
2565 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named start_restore_file()\n");
2566 }
2567
2568 return retval;
2569
2570 bail_out:
2571 if (PyErr_Occurred()) {
2572 PyErrorHandler(ctx, M_FATAL);
2573 }
2574
2575 return retval;
2576 }
2577
PyHandleBackupFile(bpContext * ctx,struct save_pkt * sp)2578 static bRC PyHandleBackupFile(bpContext *ctx, struct save_pkt *sp)
2579 {
2580 bRC retval = bRC_Error;
2581 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
2582 PyObject *pFunc;
2583
2584 if (!sp) {
2585 return bRC_Error;
2586 }
2587
2588 /*
2589 * Lookup the handle_backup_file() function in the python module.
2590 */
2591 pFunc = PyDict_GetItemString(p_ctx->pDict, "handle_backup_file"); /* Borrowed reference */
2592 if (pFunc && PyCallable_Check(pFunc)) {
2593 PySavePacket *pSavePkt;
2594 PyObject *pRetVal;
2595
2596 pSavePkt = NativeToPySavePacket(sp);
2597 if (!pSavePkt) {
2598 goto bail_out;
2599 }
2600
2601 pRetVal = PyObject_CallFunctionObjArgs(pFunc, p_ctx->bpContext, pSavePkt, NULL);
2602 if (!pRetVal) {
2603 Py_DECREF((PyObject *)pSavePkt);
2604 goto bail_out;
2605 } else {
2606 retval = conv_python_retval(pRetVal);
2607 Py_DECREF(pRetVal);
2608
2609 if (!PySavePacketToNative(pSavePkt, sp, p_ctx, true)) {
2610 Py_DECREF((PyObject *)pSavePkt);
2611 goto bail_out;
2612 }
2613 Py_DECREF(pSavePkt);
2614 }
2615 } else {
2616 Dmsg(ctx, debuglevel, "python-fd: Failed to find function named handle_backup_file()\n");
2617 }
2618
2619 return retval;
2620
2621 bail_out:
2622 if (PyErr_Occurred()) {
2623 PyErrorHandler(ctx, M_FATAL);
2624 }
2625
2626 return retval;
2627 }
2628
2629 /**
2630 * Callback function which is exposed as a part of the additional methods which allow
2631 * a Python plugin to get certain internal values of the current Job.
2632 */
PyBareosGetValue(PyObject * self,PyObject * args)2633 static PyObject *PyBareosGetValue(PyObject *self, PyObject *args)
2634 {
2635 int var;
2636 bpContext *ctx = NULL;
2637 PyObject *pyCtx;
2638 PyObject *pRetVal = NULL;
2639
2640 if (!PyArg_ParseTuple(args, "Oi:BareosGetValue", &pyCtx, &var)) {
2641 return NULL;
2642 }
2643
2644 switch (var) {
2645 case bVarFDName:
2646 case bVarWorkingDir:
2647 case bVarExePath:
2648 case bVarVersion:
2649 case bVarDistName: {
2650 char *value = NULL;
2651
2652 if (bfuncs->getBareosValue(ctx, (bVariable)var, &value) == bRC_OK) {
2653 if (value) {
2654 pRetVal = PyString_FromString(value);
2655 }
2656 }
2657 break;
2658 }
2659 case bVarJobId:
2660 case bVarLevel:
2661 case bVarType:
2662 case bVarJobStatus:
2663 case bVarSinceTime:
2664 case bVarAccurate:
2665 case bVarPrefixLinks: {
2666 int value = 0;
2667
2668 ctx = PyGetbpContext(pyCtx);
2669 if (bfuncs->getBareosValue(ctx, (bVariable)var, &value) == bRC_OK) {
2670 pRetVal = PyInt_FromLong(value);
2671 }
2672 break;
2673 }
2674 case bVarClient:
2675 case bVarJobName:
2676 case bVarPrevJobName:
2677 case bVarWhere:
2678 case bVarRegexWhere: {
2679 char *value = NULL;
2680
2681 ctx = PyGetbpContext(pyCtx);
2682 if (bfuncs->getBareosValue(ctx, (bVariable)var, &value) == bRC_OK) {
2683 if (value) {
2684 pRetVal = PyString_FromString(value);
2685 }
2686 }
2687 break;
2688 }
2689 case bVarFileSeen:
2690 break; /* a write only variable, ignore read request */
2691 default:
2692 ctx = PyGetbpContext(pyCtx);
2693 Dmsg(ctx, debuglevel, "python-fd: PyBareosGetValue unknown variable requested %d\n", var);
2694 break;
2695 }
2696
2697 if (!pRetVal) {
2698 Py_INCREF(Py_None);
2699 pRetVal = Py_None;
2700 }
2701
2702 return pRetVal;
2703 }
2704
2705 /**
2706 * Callback function which is exposed as a part of the additional methods which allow
2707 * a Python plugin to get certain internal values of the current Job.
2708 */
PyBareosSetValue(PyObject * self,PyObject * args)2709 static PyObject *PyBareosSetValue(PyObject *self, PyObject *args)
2710 {
2711 int var;
2712 bpContext *ctx = NULL;
2713 bRC retval = bRC_Error;
2714 PyObject *pyCtx, *pyValue;
2715
2716 if (!PyArg_ParseTuple(args, "OiO:BareosSetValue", &pyCtx, &var, &pyValue)) {
2717 goto bail_out;
2718 }
2719
2720 switch (var) {
2721 case bVarLevel: {
2722 int value = 0;
2723
2724 value = PyInt_AsLong(pyValue);
2725 if (value) {
2726 retval = bfuncs->setBareosValue(ctx, (bVariable)var, &value);
2727 }
2728 break;
2729 }
2730 case bVarFileSeen: {
2731 char *value;
2732
2733 #if (PY_VERSION_HEX > 0x03050000)
2734 value = bstrdup(PyString_AsString(pyValue));
2735 #else
2736 value = PyString_AsString(pyValue);
2737 #endif
2738 if (value) {
2739 retval = bfuncs->setBareosValue(ctx, (bVariable)var, value);
2740 }
2741 break;
2742 }
2743 default:
2744 ctx = PyGetbpContext(pyCtx);
2745 Dmsg(ctx, debuglevel, "python-fd: PyBareosSetValue unknown variable requested %d\n", var);
2746 break;
2747 }
2748
2749 bail_out:
2750 return conv_retval_python(retval);
2751 }
2752
2753 /**
2754 * Callback function which is exposed as a part of the additional methods which allow
2755 * a Python plugin to issue debug messages using the Bareos debug message facility.
2756 */
PyBareosDebugMessage(PyObject * self,PyObject * args)2757 static PyObject *PyBareosDebugMessage(PyObject *self, PyObject *args)
2758 {
2759 int level;
2760 char *dbgmsg = NULL;
2761 bpContext *ctx;
2762 PyObject *pyCtx;
2763
2764 if (!PyArg_ParseTuple(args, "Oi|z:BareosDebugMessage", &pyCtx, &level, &dbgmsg)) {
2765 return NULL;
2766 }
2767
2768 if (dbgmsg) {
2769 ctx = PyGetbpContext(pyCtx);
2770 Dmsg(ctx, level, "python-fd: %s", dbgmsg);
2771 }
2772
2773 Py_INCREF(Py_None);
2774 return Py_None;
2775 }
2776
2777 /**
2778 * Callback function which is exposed as a part of the additional methods which allow
2779 * a Python plugin to issue Job messages using the Bareos Job message facility.
2780 */
PyBareosJobMessage(PyObject * self,PyObject * args)2781 static PyObject *PyBareosJobMessage(PyObject *self, PyObject *args)
2782 {
2783 int type;
2784 char *jobmsg = NULL;
2785 bpContext *ctx;
2786 PyObject *pyCtx;
2787
2788 if (!PyArg_ParseTuple(args, "Oi|z:BareosJobMessage", &pyCtx, &type, &jobmsg)) {
2789 return NULL;
2790 }
2791
2792 if (jobmsg) {
2793 ctx = PyGetbpContext(pyCtx);
2794 Jmsg(ctx, type, "python-fd: %s", jobmsg);
2795 }
2796
2797 Py_INCREF(Py_None);
2798 return Py_None;
2799 }
2800
2801 /**
2802 * Callback function which is exposed as a part of the additional methods which allow
2803 * a Python plugin to issue a Register Event to register additional events it wants
2804 * to receive.
2805 */
PyBareosRegisterEvents(PyObject * self,PyObject * args)2806 static PyObject *PyBareosRegisterEvents(PyObject *self, PyObject *args)
2807 {
2808 int len, event;
2809 bpContext *ctx;
2810 bRC retval = bRC_Error;
2811 PyObject *pyCtx, *pyEvents, *pySeq, *pyEvent;
2812
2813 if (!PyArg_ParseTuple(args, "OO:BareosRegisterEvents", &pyCtx, &pyEvents)) {
2814 goto bail_out;
2815 }
2816
2817 pySeq = PySequence_Fast(pyEvents, "Expected a sequence of events");
2818 if (!pySeq) {
2819 goto bail_out;
2820 }
2821
2822 len = PySequence_Fast_GET_SIZE(pySeq);
2823
2824 ctx = PyGetbpContext(pyCtx);
2825 for (int i = 0; i < len; i++) {
2826 pyEvent = PySequence_Fast_GET_ITEM(pySeq, i);
2827 event = PyInt_AsLong(pyEvent);
2828
2829 if (event >= bEventJobStart && event <= FD_NR_EVENTS) {
2830 Dmsg(ctx, debuglevel, "python-fd: PyBareosRegisterEvents registering event %d\n", event);
2831 retval = bfuncs->registerBareosEvents(ctx, 1, event);
2832
2833 if (retval != bRC_OK) {
2834 break;
2835 }
2836 }
2837 }
2838
2839 Py_DECREF(pySeq);
2840
2841 bail_out:
2842 return conv_retval_python(retval);
2843 }
2844
2845 /**
2846 * Callback function which is exposed as a part of the additional methods which allow
2847 * a Python plugin to issue an Unregister Event to unregister events it doesn't want to
2848 * receive anymore.
2849 */
PyBareosUnRegisterEvents(PyObject * self,PyObject * args)2850 static PyObject *PyBareosUnRegisterEvents(PyObject *self, PyObject *args)
2851 {
2852 int len, event;
2853 bpContext *ctx;
2854 bRC retval = bRC_Error;
2855 PyObject *pyCtx, *pyEvents, *pySeq, *pyEvent;
2856
2857 if (!PyArg_ParseTuple(args, "OO:BareosUnRegisterEvents", &pyCtx, &pyEvents)) {
2858 goto bail_out;
2859 }
2860
2861 pySeq = PySequence_Fast(pyEvents, "Expected a sequence of events");
2862 if (!pySeq) {
2863 goto bail_out;
2864 }
2865
2866 len = PySequence_Fast_GET_SIZE(pySeq);
2867
2868 ctx = PyGetbpContext(pyCtx);
2869 for (int i = 0; i < len; i++) {
2870 pyEvent = PySequence_Fast_GET_ITEM(pySeq, i);
2871 event = PyInt_AsLong(pyEvent);
2872
2873 if (event >= bEventJobStart && event <= FD_NR_EVENTS) {
2874 Dmsg(ctx, debuglevel, "PyBareosUnRegisterEvents: unregistering event %d\n", event);
2875 retval = bfuncs->unregisterBareosEvents(ctx, 1, event);
2876 }
2877 }
2878
2879 Py_DECREF(pySeq);
2880
2881 bail_out:
2882 return conv_retval_python(retval);
2883 }
2884
2885 /**
2886 * Callback function which is exposed as a part of the additional methods which allow
2887 * a Python plugin to issue a GetInstanceCount to retrieve the number of instances of
2888 * the current plugin being loaded into the daemon.
2889 */
PyBareosGetInstanceCount(PyObject * self,PyObject * args)2890 static PyObject *PyBareosGetInstanceCount(PyObject *self, PyObject *args)
2891 {
2892 int value;
2893 bpContext *ctx = NULL;
2894 PyObject *pyCtx;
2895 PyObject *pRetVal = NULL;
2896
2897 if (!PyArg_ParseTuple(args, "O:BareosGetInstanceCount", &pyCtx)) {
2898 return NULL;
2899 }
2900
2901 ctx = PyGetbpContext(pyCtx);
2902 if (bfuncs->getInstanceCount(ctx, &value) == bRC_OK) {
2903 pRetVal = PyInt_FromLong(value);
2904 }
2905
2906 if (!pRetVal) {
2907 Py_INCREF(Py_None);
2908 pRetVal = Py_None;
2909 }
2910
2911 return pRetVal;
2912 }
2913
2914 /**
2915 * Callback function which is exposed as a part of the additional methods which allow
2916 * a Python plugin to issue a Add Exclude pattern to the fileset.
2917 */
PyBareosAddExclude(PyObject * self,PyObject * args)2918 static PyObject *PyBareosAddExclude(PyObject *self, PyObject *args)
2919 {
2920 char *file = NULL;
2921 bpContext *ctx;
2922 PyObject *pyCtx;
2923 bRC retval = bRC_Error;
2924
2925 if (!PyArg_ParseTuple(args, "O|z:BareosAddExclude", &pyCtx, &file)) {
2926 goto bail_out;
2927 }
2928
2929 if (file) {
2930 ctx = PyGetbpContext(pyCtx);
2931 retval = bfuncs->AddExclude(ctx, file);
2932 }
2933
2934 bail_out:
2935 return conv_retval_python(retval);
2936 }
2937
2938 /**
2939 * Callback function which is exposed as a part of the additional methods which allow
2940 * a Python plugin to issue a Add Include pattern to the fileset.
2941 */
PyBareosAddInclude(PyObject * self,PyObject * args)2942 static PyObject *PyBareosAddInclude(PyObject *self, PyObject *args)
2943 {
2944 char *file = NULL;
2945 bpContext *ctx;
2946 PyObject *pyCtx;
2947 bRC retval = bRC_Error;
2948
2949 if (!PyArg_ParseTuple(args, "O|z:BareosAddInclude", &pyCtx, &file)) {
2950 goto bail_out;
2951 }
2952
2953 if (file) {
2954 ctx = PyGetbpContext(pyCtx);
2955 retval = bfuncs->AddInclude(ctx, file);
2956 }
2957
2958 bail_out:
2959 return conv_retval_python(retval);
2960 }
2961
2962 /**
2963 * Callback function which is exposed as a part of the additional methods which allow
2964 * a Python plugin to issue a Add Include Options to the fileset.
2965 */
PyBareosAddOptions(PyObject * self,PyObject * args)2966 static PyObject *PyBareosAddOptions(PyObject *self, PyObject *args)
2967 {
2968 char *opts = NULL;
2969 bpContext *ctx;
2970 PyObject *pyCtx;
2971 bRC retval = bRC_Error;
2972
2973 if (!PyArg_ParseTuple(args, "O|z:BareosAddOptions", &pyCtx, &opts)) {
2974 goto bail_out;
2975 }
2976
2977 if (opts) {
2978 ctx = PyGetbpContext(pyCtx);
2979 retval = bfuncs->AddOptions(ctx, opts);
2980 }
2981
2982 bail_out:
2983 return conv_retval_python(retval);
2984 }
2985
2986 /**
2987 * Callback function which is exposed as a part of the additional methods which allow
2988 * a Python plugin to issue a Add Regex to the fileset.
2989 */
PyBareosAddRegex(PyObject * self,PyObject * args)2990 static PyObject *PyBareosAddRegex(PyObject *self, PyObject *args)
2991 {
2992 int type;
2993 char *item = NULL;
2994 bpContext *ctx;
2995 PyObject *pyCtx;
2996 bRC retval = bRC_Error;
2997
2998 if (!PyArg_ParseTuple(args, "O|zi:BareosAddRegex", &pyCtx, &item, &type)) {
2999 goto bail_out;
3000 }
3001
3002 if (item) {
3003 ctx = PyGetbpContext(pyCtx);
3004 retval = bfuncs->AddRegex(ctx, item, type);
3005 }
3006
3007 bail_out:
3008 return conv_retval_python(retval);
3009 }
3010
3011 /**
3012 * Callback function which is exposed as a part of the additional methods which allow
3013 * a Python plugin to issue a Add Wildcard to the fileset.
3014 */
PyBareosAddWild(PyObject * self,PyObject * args)3015 static PyObject *PyBareosAddWild(PyObject *self, PyObject *args)
3016 {
3017 int type;
3018 char *item = NULL;
3019 bpContext *ctx;
3020 PyObject *pyCtx;
3021 bRC retval = bRC_Error;
3022
3023 if (!PyArg_ParseTuple(args, "O|zi:BareosAddWild", &pyCtx, &item, &type)) {
3024 goto bail_out;
3025 }
3026
3027 if (item) {
3028 ctx = PyGetbpContext(pyCtx);
3029 retval = bfuncs->AddWild(ctx, item, type);
3030 }
3031
3032 bail_out:
3033 return conv_retval_python(retval);
3034 }
3035
3036 /**
3037 * Callback function which is exposed as a part of the additional methods which allow
3038 * a Python plugin to issue a Add New Option block.
3039 */
PyBareosNewOptions(PyObject * self,PyObject * args)3040 static PyObject *PyBareosNewOptions(PyObject *self, PyObject *args)
3041 {
3042 bpContext *ctx;
3043 PyObject *pyCtx;
3044 bRC retval = bRC_Error;
3045
3046 if (!PyArg_ParseTuple(args, "O:BareosNewOptions", &pyCtx)) {
3047 goto bail_out;
3048 }
3049
3050 ctx = PyGetbpContext(pyCtx);
3051 retval = bfuncs->NewOptions(ctx);
3052
3053 bail_out:
3054 return conv_retval_python(retval);
3055 }
3056
3057 /**
3058 * Callback function which is exposed as a part of the additional methods which allow
3059 * a Python plugin to issue a Add New Include block.
3060 */
PyBareosNewInclude(PyObject * self,PyObject * args)3061 static PyObject *PyBareosNewInclude(PyObject *self, PyObject *args)
3062 {
3063 bpContext *ctx;
3064 PyObject *pyCtx;
3065 bRC retval = bRC_Error;
3066
3067 if (!PyArg_ParseTuple(args, "O:BareosNewInclude", &pyCtx)) {
3068 goto bail_out;
3069 }
3070
3071 ctx = PyGetbpContext(pyCtx);
3072 retval = bfuncs->NewInclude(ctx);
3073
3074 bail_out:
3075 return conv_retval_python(retval);
3076 }
3077
3078 /**
3079 * Callback function which is exposed as a part of the additional methods which allow
3080 * a Python plugin to issue a Add New Pre Include block.
3081 */
PyBareosNewPreInclude(PyObject * self,PyObject * args)3082 static PyObject *PyBareosNewPreInclude(PyObject *self, PyObject *args)
3083 {
3084 bpContext *ctx;
3085 PyObject *pyCtx;
3086 bRC retval = bRC_Error;
3087
3088 if (!PyArg_ParseTuple(args, "O:BareosNewPreInclude", &pyCtx)) {
3089 goto bail_out;
3090 }
3091
3092 ctx = PyGetbpContext(pyCtx);
3093 retval = bfuncs->NewPreInclude(ctx);
3094
3095 bail_out:
3096 return conv_retval_python(retval);
3097 }
3098
3099 /**
3100 * Callback function which is exposed as a part of the additional methods which allow
3101 * a Python plugin to issue a check if a file have to be backuped using Accurate code.
3102 */
PyBareosCheckChanges(PyObject * self,PyObject * args)3103 static PyObject *PyBareosCheckChanges(PyObject *self, PyObject *args)
3104 {
3105 bpContext *ctx;
3106 PyObject *pyCtx;
3107 struct save_pkt sp;
3108 bRC retval = bRC_Error;
3109 PySavePacket *pSavePkt;
3110
3111 if (!PyArg_ParseTuple(args, "OO:BareosCheckChanges", &pyCtx, &pSavePkt)) {
3112 goto bail_out;
3113 }
3114
3115 ctx = PyGetbpContext(pyCtx);
3116
3117 /*
3118 * CheckFile only has a need for a limited version of the PySavePacket so we handle
3119 * that here separately and don't call PySavePacketToNative().
3120 */
3121 sp.type = pSavePkt->type;
3122 if (pSavePkt->fname) {
3123 if (PyString_Check(pSavePkt->fname)) {
3124 #if (PY_VERSION_HEX > 0x03050000)
3125 sp.fname = bstrdup(PyString_AsString(pSavePkt->fname));
3126 #else
3127 sp.fname = PyString_AsString(pSavePkt->fname);
3128 #endif
3129 } else {
3130 goto bail_out;
3131 }
3132 } else {
3133 goto bail_out;
3134 }
3135 if (pSavePkt->link) {
3136 if (PyString_Check(pSavePkt->link)) {
3137 #if (PY_VERSION_HEX > 0x03050000)
3138 sp.link = bstrdup(PyString_AsString(pSavePkt->link));
3139 #else
3140 sp.link = PyString_AsString(pSavePkt->link);
3141 #endif
3142 } else {
3143 goto bail_out;
3144 }
3145 }
3146 sp.save_time = pSavePkt->save_time;
3147
3148 retval = bfuncs->checkChanges(ctx, &sp);
3149
3150 /*
3151 * Copy back the two fields that are changed by checkChanges().
3152 */
3153 pSavePkt->delta_seq = sp.delta_seq;
3154 pSavePkt->accurate_found = sp.accurate_found;
3155
3156 bail_out:
3157 return conv_retval_python(retval);
3158 }
3159
3160 /**
3161 * Callback function which is exposed as a part of the additional methods which allow
3162 * a Python plugin to issue a check if a file would be saved using current Include/Exclude code.
3163 */
PyBareosAcceptFile(PyObject * self,PyObject * args)3164 static PyObject *PyBareosAcceptFile(PyObject *self, PyObject *args)
3165 {
3166 bpContext *ctx;
3167 PyObject *pyCtx;
3168 struct save_pkt sp;
3169 bRC retval = bRC_Error;
3170 PySavePacket *pSavePkt;
3171
3172 if (!PyArg_ParseTuple(args, "OO:BareosAcceptFile", &pyCtx, &pSavePkt)) {
3173 goto bail_out;
3174 }
3175
3176 ctx = PyGetbpContext(pyCtx);
3177
3178 /*
3179 * Acceptfile only needs fname and statp from PySavePacket so we handle
3180 * that here separately and don't call PySavePacketToNative().
3181 */
3182 if (pSavePkt->fname) {
3183 if (PyString_Check(pSavePkt->fname)) {
3184 #if (PY_VERSION_HEX > 0x03050000)
3185 sp.fname = bstrdup(PyString_AsString(pSavePkt->fname));
3186 #else
3187 sp.fname = PyString_AsString(pSavePkt->fname);
3188 #endif
3189 } else {
3190 goto bail_out;
3191 }
3192 } else {
3193 goto bail_out;
3194 }
3195
3196 if (pSavePkt->statp) {
3197 PyStatPacketToNative((PyStatPacket *)pSavePkt->statp, &sp.statp);
3198 } else {
3199 goto bail_out;
3200 }
3201
3202 retval = bfuncs->AcceptFile(ctx, &sp);
3203
3204 bail_out:
3205 return conv_retval_python(retval);
3206 }
3207
3208 /**
3209 * Callback function which is exposed as a part of the additional methods which allow
3210 * a Python plugin to issue a Set bit in the Accurate Seen bitmap.
3211 */
PyBareosSetSeenBitmap(PyObject * self,PyObject * args)3212 static PyObject *PyBareosSetSeenBitmap(PyObject *self, PyObject *args)
3213 {
3214 bool all;
3215 bpContext *ctx;
3216 char *fname = NULL;
3217 bRC retval = bRC_Error;
3218 PyObject *pyCtx, *pyBool;
3219
3220 if (!PyArg_ParseTuple(args, "OO|s:BareosSetSeenBitmap", &pyCtx, &pyBool, &fname)) {
3221 goto bail_out;
3222 }
3223
3224 ctx = PyGetbpContext(pyCtx);
3225 all = PyObject_IsTrue(pyBool);
3226 retval = bfuncs->SetSeenBitmap(ctx, all, fname);
3227
3228 bail_out:
3229 return conv_retval_python(retval);
3230 }
3231
3232 /**
3233 * Callback function which is exposed as a part of the additional methods which allow
3234 * a Python plugin to issue a Clear bit in the Accurate Seen bitmap.
3235 */
PyBareosClearSeenBitmap(PyObject * self,PyObject * args)3236 static PyObject *PyBareosClearSeenBitmap(PyObject *self, PyObject *args)
3237 {
3238 bool all;
3239 bpContext *ctx;
3240 char *fname = NULL;
3241 bRC retval = bRC_Error;
3242 PyObject *pyCtx, *pyBool;
3243
3244 if (!PyArg_ParseTuple(args, "OO|s:BareosClearSeenBitmap", &pyCtx, &pyBool, &fname)) {
3245 goto bail_out;
3246 }
3247
3248 ctx = PyGetbpContext(pyCtx);
3249 all = PyObject_IsTrue(pyBool);
3250 retval = bfuncs->ClearSeenBitmap(ctx, all, fname);
3251
3252 bail_out:
3253 return conv_retval_python(retval);
3254 }
3255
3256 /**
3257 * Some helper functions.
3258 */
PyGetStringValue(PyObject * object)3259 static inline char *PyGetStringValue(PyObject *object)
3260 {
3261 if (!object || !PyString_Check(object)) {
3262 return (char *)"";
3263 }
3264 #if (PY_VERSION_HEX > 0x03050000)
3265 return bstrdup(PyString_AsString(object));
3266 #else
3267 return PyString_AsString(object);
3268 #endif
3269 }
3270
PyGetByteArrayValue(PyObject * object)3271 static inline char *PyGetByteArrayValue(PyObject *object)
3272 {
3273 if (!object || !PyByteArray_Check(object)) {
3274 return (char *)"";
3275 }
3276
3277 return PyByteArray_AsString(object);
3278 }
3279
3280 /**
3281 * Python specific handlers for PyRestoreObject structure mapping.
3282 */
3283
3284 /**
3285 * Representation.
3286 */
PyRestoreObject_repr(PyRestoreObject * self)3287 static PyObject *PyRestoreObject_repr(PyRestoreObject *self)
3288 {
3289 PyObject *s;
3290 PoolMem buf(PM_MESSAGE);
3291
3292 Mmsg(buf, "RestoreObject(object_name=\"%s\", object=\"%s\", plugin_name=\"%s\", "
3293 "object_type=%d, object_len=%d, object_full_len=%d, "
3294 "object_index=%d, object_compression=%d, stream=%d, jobid=%u)",
3295 PyGetStringValue(self->object_name), PyGetByteArrayValue(self->object), self->plugin_name,
3296 self->object_type, self->object_len, self->object_full_len,
3297 self->object_index, self->object_compression, self->stream, self->JobId);
3298 s = PyString_FromString(buf.c_str());
3299
3300 return s;
3301 }
3302
3303 /**
3304 * Initialization.
3305 */
PyRestoreObject_init(PyRestoreObject * self,PyObject * args,PyObject * kwds)3306 static int PyRestoreObject_init(PyRestoreObject *self, PyObject *args, PyObject *kwds)
3307 {
3308 static char *kwlist[] = {
3309 (char *)"object_name",
3310 (char *)"object",
3311 (char *)"plugin_name",
3312 (char *)"object_type",
3313 (char *)"object_len",
3314 (char *)"object_full_len",
3315 (char *)"object_index",
3316 (char *)"object_compression",
3317 (char *)"stream",
3318 (char *)"jobid",
3319 NULL
3320 };
3321
3322 self->object_name = NULL;
3323 self->object = NULL;
3324 self->plugin_name = NULL;
3325 self->object_type = 0;
3326 self->object_len = 0;
3327 self->object_full_len = 0;
3328 self->object_index = 0;
3329 self->object_compression = 0;
3330 self->stream = 0;
3331 self->JobId = 0;
3332
3333 if (!PyArg_ParseTupleAndKeywords(args,
3334 kwds,
3335 "|oosiiiiiiI",
3336 kwlist,
3337 &self->object_name,
3338 &self->object,
3339 &self->plugin_name,
3340 &self->object_type,
3341 &self->object_len,
3342 &self->object_full_len,
3343 &self->object_index,
3344 &self->object_compression,
3345 &self->stream,
3346 &self->JobId)) {
3347 return -1;
3348 }
3349
3350 return 0;
3351 }
3352
3353 /**
3354 * Destructor.
3355 */
PyRestoreObject_dealloc(PyRestoreObject * self)3356 static void PyRestoreObject_dealloc(PyRestoreObject *self)
3357 {
3358 if (self->object_name) {
3359 Py_XDECREF(self->object_name);
3360 }
3361 if (self->object) {
3362 Py_XDECREF(self->object);
3363 }
3364 PyObject_Del(self);
3365 }
3366
3367 /**
3368 * Python specific handlers for PyStatPacket structure mapping.
3369 */
3370
3371 /**
3372 * Representation.
3373 */
PyStatPacket_repr(PyStatPacket * self)3374 static PyObject *PyStatPacket_repr(PyStatPacket *self)
3375 {
3376 PyObject *s;
3377 PoolMem buf(PM_MESSAGE);
3378
3379 Mmsg(buf, "StatPacket(dev=%ld, ino=%lld, mode=%04o, nlink=%d, "
3380 "uid=%ld, gid=%ld, rdev=%ld, size=%lld, "
3381 "atime=%ld, mtime=%ld, ctime=%ld, blksize=%ld, blocks=%lld)",
3382 self->dev, self->ino, (self->mode & ~S_IFMT), self->nlink,
3383 self->uid, self->gid, self->rdev, self->size,
3384 self->atime, self->mtime, self->ctime, self->blksize, self->blocks);
3385
3386 s = PyString_FromString(buf.c_str());
3387
3388 return s;
3389 }
3390
3391 /**
3392 * Initialization.
3393 */
PyStatPacket_init(PyStatPacket * self,PyObject * args,PyObject * kwds)3394 static int PyStatPacket_init(PyStatPacket *self, PyObject *args, PyObject *kwds)
3395 {
3396 time_t now;
3397 static char *kwlist[] = {
3398 (char *)"dev",
3399 (char *)"ino",
3400 (char *)"mode",
3401 (char *)"nlink",
3402 (char *)"uid",
3403 (char *)"gid",
3404 (char *)"rdev",
3405 (char *)"size",
3406 (char *)"atime",
3407 (char *)"mtime",
3408 (char *)"ctime",
3409 (char *)"blksize",
3410 (char *)"blocks",
3411 NULL
3412 };
3413
3414 now = time(NULL);
3415 self->dev = 0;
3416 self->ino = 0;
3417 self->mode = 0700 | S_IFREG;
3418 self->nlink = 0;
3419 self->uid = 0;
3420 self->gid = 0;
3421 self->rdev = 0;
3422 self->size = -1;
3423 self->atime = now;
3424 self->mtime = now;
3425 self->ctime = now;
3426 self->blksize = 4096;
3427 self->blocks = 1;
3428
3429 if (!PyArg_ParseTupleAndKeywords(args,
3430 kwds,
3431 "|IKHHIIIKIIIIK",
3432 kwlist,
3433 &self->dev,
3434 &self->ino,
3435 &self->mode,
3436 &self->nlink,
3437 &self->uid,
3438 &self->gid,
3439 &self->rdev,
3440 &self->size,
3441 &self->atime,
3442 &self->mtime,
3443 &self->ctime,
3444 &self->blksize,
3445 &self->blocks)) {
3446 return -1;
3447 }
3448
3449 return 0;
3450 }
3451
3452 /**
3453 * Destructor.
3454 */
PyStatPacket_dealloc(PyStatPacket * self)3455 static void PyStatPacket_dealloc(PyStatPacket *self)
3456 {
3457 PyObject_Del(self);
3458 }
3459
3460 /**
3461 * Python specific handlers for PySavePacket structure mapping.
3462 */
3463
3464 /**
3465 * Representation.
3466 */
print_flags_bitmap(PyObject * bitmap)3467 static inline const char *print_flags_bitmap(PyObject *bitmap)
3468 {
3469 static char visual_bitmap[FO_MAX + 1];
3470
3471 if (PyByteArray_Check(bitmap)) {
3472 int cnt;
3473 char *flags;
3474
3475 if (PyByteArray_Size(bitmap) == FOPTS_BYTES) {
3476 if ((flags = PyByteArray_AsString(bitmap))) {
3477 memset(visual_bitmap, 0, sizeof(visual_bitmap));
3478 for (cnt = 0; cnt <= FO_MAX; cnt++) {
3479 if (BitIsSet(cnt, flags)) {
3480 visual_bitmap[cnt] = '1';
3481 } else {
3482 visual_bitmap[cnt] = '0';
3483 }
3484 }
3485
3486 return visual_bitmap;
3487 }
3488 }
3489 }
3490
3491 return "Unknown";
3492 }
3493
PySavePacket_repr(PySavePacket * self)3494 static PyObject *PySavePacket_repr(PySavePacket *self)
3495 {
3496 PyObject *s;
3497 PoolMem buf(PM_MESSAGE);
3498
3499 Mmsg(buf, "SavePacket(fname=\"%s\", link=\"%s\", type=%ld, flags=%s, "
3500 "no_read=%d, portable=%d, accurate_found=%d, "
3501 "cmd=\"%s\", save_time=%ld, delta_seq=%ld, object_name=\"%s\", "
3502 "object=\"%s\", object_len=%ld, object_index=%ld)",
3503 PyGetStringValue(self->fname), PyGetStringValue(self->link),
3504 self->type, print_flags_bitmap(self->flags), self->no_read, self->portable,
3505 self->accurate_found, self->cmd, self->save_time, self->delta_seq,
3506 PyGetStringValue(self->object_name), PyGetByteArrayValue(self->object),
3507 self->object_len, self->object_index);
3508
3509 s = PyString_FromString(buf.c_str());
3510
3511 return s;
3512 }
3513
3514 /**
3515 * Initialization.
3516 */
PySavePacket_init(PySavePacket * self,PyObject * args,PyObject * kwds)3517 static int PySavePacket_init(PySavePacket *self, PyObject *args, PyObject *kwds)
3518 {
3519 static char *kwlist[] = {
3520 (char *)"fname",
3521 (char *)"link",
3522 (char *)"type",
3523 (char *)"flags",
3524 (char *)"no_read",
3525 (char *)"portable",
3526 (char *)"accurate_found",
3527 (char *)"cmd",
3528 (char *)"save_time",
3529 (char *)"delta_seq",
3530 (char *)"object_name",
3531 (char *)"object",
3532 (char *)"object_len",
3533 (char *)"object_index",
3534 NULL
3535 };
3536
3537 self->fname = NULL;
3538 self->link = NULL;
3539 self->type = 0;
3540 self->flags = NULL;
3541 self->no_read = false;
3542 self->portable = false;
3543 self->accurate_found = false;
3544 self->cmd = NULL;
3545 self->save_time = 0;
3546 self->delta_seq = 0;
3547 self->object_name = NULL;
3548 self->object = NULL;
3549 self->object_len = 0;
3550 self->object_index = 0;
3551
3552 if (!PyArg_ParseTupleAndKeywords(args,
3553 kwds,
3554 "|ooiocccsiiooii",
3555 kwlist,
3556 &self->fname,
3557 &self->link,
3558 &self->type,
3559 &self->flags,
3560 &self->no_read,
3561 &self->portable,
3562 &self->accurate_found,
3563 &self->cmd,
3564 &self->save_time,
3565 &self->delta_seq,
3566 &self->object_name,
3567 &self->object,
3568 &self->object_len,
3569 &self->object_index)) {
3570 return -1;
3571 }
3572
3573 return 0;
3574 }
3575
3576 /**
3577 * Destructor.
3578 */
PySavePacket_dealloc(PySavePacket * self)3579 static void PySavePacket_dealloc(PySavePacket *self)
3580 {
3581 if (self->fname) {
3582 Py_XDECREF(self->fname);
3583 }
3584 if (self->link) {
3585 Py_XDECREF(self->link);
3586 }
3587 if (self->flags) {
3588 Py_XDECREF(self->flags);
3589 }
3590 if (self->object_name) {
3591 Py_XDECREF(self->object_name);
3592 }
3593 if (self->object) {
3594 Py_XDECREF(self->object);
3595 }
3596 PyObject_Del(self);
3597 }
3598
3599 /**
3600 * Python specific handlers for PyRestorePacket structure mapping.
3601 */
3602
3603 /**
3604 * Representation.
3605 */
PyRestorePacket_repr(PyRestorePacket * self)3606 static PyObject *PyRestorePacket_repr(PyRestorePacket *self)
3607 {
3608 PyObject *stat_repr, *s;
3609 PoolMem buf(PM_MESSAGE);
3610
3611 stat_repr = PyObject_Repr(self->statp);
3612 Mmsg(buf, "RestorePacket(stream=%d, data_stream=%ld, type=%ld, file_index=%ld, "
3613 "linkFI=%ld, uid=%ld, statp=\"%s\", attrEx=\"%s\", ofname=\"%s\", "
3614 "olname=\"%s\", where=\"%s\", RegexWhere=\"%s\", replace=%d, create_status=%d)",
3615 self->stream, self->data_stream, self->type, self->file_index,
3616 self->LinkFI, self->uid, PyGetStringValue(stat_repr), self->attrEx, self->ofname,
3617 self->olname, self->where, self->RegexWhere, self->replace, self->create_status);
3618
3619 s = PyString_FromString(buf.c_str());
3620 Py_DECREF(stat_repr);
3621
3622 return s;
3623 }
3624
3625 /**
3626 * Initialization.
3627 */
PyRestorePacket_init(PyRestorePacket * self,PyObject * args,PyObject * kwds)3628 static int PyRestorePacket_init(PyRestorePacket *self, PyObject *args, PyObject *kwds)
3629 {
3630 static char *kwlist[] = {
3631 (char *)"stream",
3632 (char *)"data_stream",
3633 (char *)"type",
3634 (char *)"file_index",
3635 (char *)"linkFI",
3636 (char *)"uid",
3637 (char *)"statp",
3638 (char *)"attrEX",
3639 (char *)"ofname",
3640 (char *)"olname",
3641 (char *)"where",
3642 (char *)"regexwhere",
3643 (char *)"replace",
3644 (char *)"create_status",
3645 NULL
3646 };
3647
3648 self->stream = 0;
3649 self->data_stream = 0;
3650 self->type = 0;
3651 self->file_index = 0;
3652 self->LinkFI = 0;
3653 self->uid = 0;
3654 self->statp = NULL;
3655 self->attrEx = NULL;
3656 self->ofname = NULL;
3657 self->olname = NULL;
3658 self->where = NULL;
3659 self->RegexWhere = NULL;
3660 self->replace = 0;
3661 self->create_status = 0;
3662
3663 if (!PyArg_ParseTupleAndKeywords(args,
3664 kwds,
3665 "|iiiiiIosssssii",
3666 kwlist,
3667 &self->stream,
3668 &self->data_stream,
3669 &self->type,
3670 &self->file_index,
3671 &self->LinkFI,
3672 &self->uid,
3673 &self->statp,
3674 &self->attrEx,
3675 &self->ofname,
3676 &self->olname,
3677 &self->where,
3678 &self->RegexWhere,
3679 &self->replace,
3680 &self->create_status)) {
3681 return -1;
3682 }
3683
3684 return 0;
3685 }
3686
3687 /**
3688 * Destructor.
3689 */
PyRestorePacket_dealloc(PyRestorePacket * self)3690 static void PyRestorePacket_dealloc(PyRestorePacket *self)
3691 {
3692 PyObject_Del(self);
3693 }
3694
3695 /**
3696 * Python specific handlers for PyIoPacket structure mapping.
3697 */
3698
3699 /**
3700 * Representation.
3701 */
PyIoPacket_repr(PyIoPacket * self)3702 static PyObject *PyIoPacket_repr(PyIoPacket *self)
3703 {
3704 PyObject *s;
3705 PoolMem buf(PM_MESSAGE);
3706
3707 Mmsg(buf, "IoPacket(func=%d, count=%ld, flags=%ld, mode=%04o, "
3708 "buf=\"%s\", fname=\"%s\", status=%ld, io_errno=%ld, lerror=%ld, "
3709 "whence=%ld, offset=%lld, win32=%d)",
3710 self->func, self->count, self->flags, (self->mode & ~S_IFMT),
3711 PyGetByteArrayValue(self->buf), self->fname, self->status,
3712 self->io_errno, self->lerror,
3713 self->whence, self->offset, self->win32);
3714 s = PyString_FromString(buf.c_str());
3715
3716 return s;
3717 }
3718
3719 /**
3720 * Initialization.
3721 */
PyIoPacket_init(PyIoPacket * self,PyObject * args,PyObject * kwds)3722 static int PyIoPacket_init(PyIoPacket *self, PyObject *args, PyObject *kwds)
3723 {
3724 static char *kwlist[] = {
3725 (char *)"func",
3726 (char *)"count",
3727 (char *)"flags",
3728 (char *)"mode",
3729 (char *)"buf",
3730 (char *)"fname",
3731 (char *)"status",
3732 (char *)"io_errno",
3733 (char *)"lerror",
3734 (char *)"whence",
3735 (char *)"offset",
3736 (char *)"win32",
3737 NULL
3738 };
3739
3740 self->func = 0;
3741 self->count = 0;
3742 self->flags = 0;
3743 self->mode = 0;
3744 self->buf = NULL;
3745 self->fname = NULL;
3746 self->status = 0;
3747 self->io_errno = 0;
3748 self->lerror = 0;
3749 self->whence = 0;
3750 self->offset = 0;
3751 self->win32 = false;
3752
3753 if (!PyArg_ParseTupleAndKeywords(args,
3754 kwds,
3755 "|Hiiiosiiiilc",
3756 kwlist,
3757 &self->func,
3758 &self->count,
3759 &self->flags,
3760 &self->mode,
3761 &self->buf,
3762 &self->fname,
3763 &self->status,
3764 &self->io_errno,
3765 &self->lerror,
3766 &self->whence,
3767 &self->offset,
3768 &self->win32)) {
3769 return -1;
3770 }
3771
3772 return 0;
3773 }
3774
3775 /**
3776 * Destructor.
3777 */
PyIoPacket_dealloc(PyIoPacket * self)3778 static void PyIoPacket_dealloc(PyIoPacket *self)
3779 {
3780 if (self->buf) {
3781 Py_XDECREF(self->buf);
3782 }
3783 PyObject_Del(self);
3784 }
3785
3786 /**
3787 * Python specific handlers for PyAclPacket structure mapping.
3788 */
3789
3790 /**
3791 * Representation.
3792 */
PyAclPacket_repr(PyAclPacket * self)3793 static PyObject *PyAclPacket_repr(PyAclPacket *self)
3794 {
3795 PyObject *s;
3796 PoolMem buf(PM_MESSAGE);
3797
3798 Mmsg(buf, "AclPacket(fname=\"%s\", content=\"%s\")",
3799 self->fname, PyGetByteArrayValue(self->content));
3800 s = PyString_FromString(buf.c_str());
3801
3802 return s;
3803 }
3804
3805 /**
3806 * Initialization.
3807 */
PyAclPacket_init(PyAclPacket * self,PyObject * args,PyObject * kwds)3808 static int PyAclPacket_init(PyAclPacket *self, PyObject *args, PyObject *kwds)
3809 {
3810 static char *kwlist[] = {
3811 (char *)"fname",
3812 (char *)"content",
3813 NULL
3814 };
3815
3816 self->fname = NULL;
3817 self->content = NULL;
3818
3819 if (!PyArg_ParseTupleAndKeywords(args,
3820 kwds,
3821 "|so",
3822 kwlist,
3823 &self->fname,
3824 &self->content)) {
3825 return -1;
3826 }
3827
3828 return 0;
3829 }
3830
3831 /**
3832 * Destructor.
3833 */
PyAclPacket_dealloc(PyAclPacket * self)3834 static void PyAclPacket_dealloc(PyAclPacket *self)
3835 {
3836 if (self->content) {
3837 Py_XDECREF(self->content);
3838 }
3839 PyObject_Del(self);
3840 }
3841
3842 /**
3843 * Python specific handlers for PyIOPacket structure mapping.
3844 */
3845
3846 /**
3847 * Representation.
3848 */
PyXattrPacket_repr(PyXattrPacket * self)3849 static PyObject *PyXattrPacket_repr(PyXattrPacket *self)
3850 {
3851 PyObject *s;
3852 PoolMem buf(PM_MESSAGE);
3853
3854 Mmsg(buf, "XattrPacket(fname=\"%s\", name=\"%s\", value=\"%s\")",
3855 self->fname, PyGetByteArrayValue(self->name), PyGetByteArrayValue(self->value));
3856 s = PyString_FromString(buf.c_str());
3857
3858 return s;
3859 }
3860
3861 /**
3862 * Initialization.
3863 */
PyXattrPacket_init(PyXattrPacket * self,PyObject * args,PyObject * kwds)3864 static int PyXattrPacket_init(PyXattrPacket *self, PyObject *args, PyObject *kwds)
3865 {
3866 static char *kwlist[] = {
3867 (char *)"fname",
3868 (char *)"name",
3869 (char *)"value",
3870 NULL
3871 };
3872
3873 self->fname = NULL;
3874 self->name = NULL;
3875 self->value = NULL;
3876
3877 if (!PyArg_ParseTupleAndKeywords(args,
3878 kwds,
3879 "|soo",
3880 kwlist,
3881 &self->fname,
3882 &self->name,
3883 &self->value)) {
3884 return -1;
3885 }
3886
3887 return 0;
3888 }
3889
3890 /**
3891 * Destructor.
3892 */
PyXattrPacket_dealloc(PyXattrPacket * self)3893 static void PyXattrPacket_dealloc(PyXattrPacket *self)
3894 {
3895 if (self->value) {
3896 Py_XDECREF(self->value);
3897 }
3898 if (self->name) {
3899 Py_XDECREF(self->name);
3900 }
3901 PyObject_Del(self);
3902 }
3903 } /* namespace filedaemon */
3904