1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2020-2020 Bareos GmbH & Co. KG
5 
6    This program is Free Software; you can redistribute it and/or
7    modify it under the terms of version three of the GNU Affero General Public
8    License as published by the Free Software Foundation, which is
9    listed in the file LICENSE.
10 
11    This program is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14    Affero General Public License for more details.
15 
16    You should have received a copy of the GNU Affero General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19    02110-1301, USA.
20 */
21 /**
22  * @file
23  * Python module for the Bareos filedaemon plugin
24  */
25 #define PY_SSIZE_T_CLEAN
26 #define BUILD_PLUGIN
27 
28 #if defined(HAVE_WIN32)
29 #  include "include/bareos.h"
30 #  include <Python.h>
31 #else
32 #  include <Python.h>
33 #  include "include/bareos.h"
34 #endif
35 
36 #include "include/version_hex.h"
37 
38 #if PY_VERSION_HEX < VERSION_HEX(3, 0, 0)
39 #  define LOGPREFIX "python-fd-mod: "
40 #else
41 #  define LOGPREFIX "python3-fd-mod: "
42 #endif
43 
44 
45 #include "filed/fd_plugins.h"
46 
47 #include "plugins/include/python3compat.h"
48 
49 #define BAREOSFD_MODULE
50 #include "bareosfd.h"
51 #include "plugins/include/python3compat.h"
52 #include "lib/edit.h"
53 
54 namespace filedaemon {
55 
56 static const int debuglevel = 150;
57 
58 static bRC set_bareos_core_functions(CoreFunctions* new_bareos_core_functions);
59 static bRC set_plugin_context(PluginContext* new_plugin_context);
60 static bRC PyParsePluginDefinition(PluginContext* plugin_ctx, void* value);
61 
62 static bRC PyGetPluginValue(PluginContext* plugin_ctx,
63                             pVariable var,
64                             void* value);
65 static bRC PySetPluginValue(PluginContext* plugin_ctx,
66                             pVariable var,
67                             void* value);
68 static bRC PyHandlePluginEvent(PluginContext* plugin_ctx,
69                                bEvent* event,
70                                void* value);
71 static bRC PyStartBackupFile(PluginContext* plugin_ctx, struct save_pkt* sp);
72 static bRC PyEndBackupFile(PluginContext* plugin_ctx);
73 static bRC PyPluginIO(PluginContext* plugin_ctx, struct io_pkt* io);
74 static bRC PyStartRestoreFile(PluginContext* plugin_ctx, const char* cmd);
75 static bRC PyEndRestoreFile(PluginContext* plugin_ctx);
76 static bRC PyCreateFile(PluginContext* plugin_ctx, struct restore_pkt* rp);
77 static bRC PySetFileAttributes(PluginContext* plugin_ctx,
78                                struct restore_pkt* rp);
79 static bRC PyCheckFile(PluginContext* plugin_ctx, char* fname);
80 static bRC PyGetAcl(PluginContext* plugin_ctx, acl_pkt* ap);
81 static bRC PySetAcl(PluginContext* plugin_ctx, acl_pkt* ap);
82 static bRC PyGetXattr(PluginContext* plugin_ctx, xattr_pkt* xp);
83 static bRC PySetXattr(PluginContext* plugin_ctx, xattr_pkt* xp);
84 static bRC PyRestoreObjectData(PluginContext* plugin_ctx,
85                                struct restore_object_pkt* rop);
86 static bRC PyHandleBackupFile(PluginContext* plugin_ctx, struct save_pkt* sp);
87 
88 /* Pointers to Bareos functions */
89 static CoreFunctions* bareos_core_functions = NULL;
90 
91 #include "plugins/filed/python/plugin_private_context.h"
92 
93 #define NOPLUGINSETGETVALUE 1
94 /* functions common to all plugins */
95 #include "plugins/include/python_plugins_common.inc"
96 
97 
98 /* set the bareos_core_functions pointer to the given value */
set_bareos_core_functions(CoreFunctions * new_bareos_core_functions)99 static bRC set_bareos_core_functions(CoreFunctions* new_bareos_core_functions)
100 {
101   bareos_core_functions = new_bareos_core_functions;
102   return bRC_OK;
103 }
104 
105 /* set the plugin context pointer to the given value */
set_plugin_context(PluginContext * new_plugin_context)106 static bRC set_plugin_context(PluginContext* new_plugin_context)
107 {
108   plugin_context = new_plugin_context;
109   return bRC_OK;
110 }
111 
112 /**
113  * Any plugin options which are passed in are dispatched here to a Python
114  * method and it can parse the plugin options. This function is also called
115  * after PyLoadModule() has loaded the Python module and made sure things are
116  * operational. Normally you would only get one set of plugin options but for
117  * a restore overrides can be passed in before the actual plugin options are
118  * restored as part of the restore stream handling.
119  */
PyParsePluginDefinition(PluginContext * plugin_ctx,void * value)120 static bRC PyParsePluginDefinition(PluginContext* plugin_ctx, void* value)
121 {
122   bRC retval = bRC_Error;
123   struct plugin_private_context* plugin_priv_ctx
124       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
125   PyObject* pFunc;
126 
127   /*
128    * Lookup the parse_plugin_definition() function in the python module.
129    */
130   pFunc = PyDict_GetItemString(
131       plugin_priv_ctx->pyModuleFunctionsDict,
132       "parse_plugin_definition"); /* Borrowed reference */
133   if (pFunc && PyCallable_Check(pFunc)) {
134     PyObject *pPluginDefinition, *pRetVal;
135 
136     pPluginDefinition = PyUnicode_FromString((char*)value);
137     if (!pPluginDefinition) { goto bail_out; }
138 
139     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pPluginDefinition, NULL);
140     Py_DECREF(pPluginDefinition);
141 
142     if (!pRetVal) {
143       goto bail_out;
144     } else {
145       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
146       Py_DECREF(pRetVal);
147     }
148 
149     return retval;
150   } else {
151     Dmsg(plugin_ctx, debuglevel,
152          LOGPREFIX
153          "Failed to find function named "
154          "parse_plugin_definition()\n");
155     return bRC_Error;
156   }
157 
158 bail_out:
159   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
160 
161   return retval;
162 }
163 
PyGetPluginValue(PluginContext * plugin_ctx,pVariable var,void * value)164 static bRC PyGetPluginValue(PluginContext* plugin_ctx,
165                             pVariable var,
166                             void* value)
167 {
168   return bRC_OK;
169 }
170 
PySetPluginValue(PluginContext * plugin_ctx,pVariable var,void * value)171 static bRC PySetPluginValue(PluginContext* plugin_ctx,
172                             pVariable var,
173                             void* value)
174 {
175   return bRC_OK;
176 }
177 
PyHandlePluginEvent(PluginContext * plugin_ctx,bEvent * event,void * value)178 static bRC PyHandlePluginEvent(PluginContext* plugin_ctx,
179                                bEvent* event,
180                                void* value)
181 {
182   bRC retval = bRC_Error;
183   plugin_private_context* plugin_priv_ctx
184       = (plugin_private_context*)plugin_ctx->plugin_private_context;
185   PyObject* pFunc;
186 
187   /*
188    * Lookup the handle_plugin_event() function in the python module.
189    */
190   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
191                                "handle_plugin_event"); /* Borrowed reference */
192   if (pFunc && PyCallable_Check(pFunc)) {
193     PyObject *pEventType, *pRetVal;
194 
195     pEventType = PyLong_FromLong(event->eventType);
196 
197     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pEventType, NULL);
198     Py_DECREF(pEventType);
199 
200     if (!pRetVal) {
201       goto bail_out;
202     } else {
203       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
204       Py_DECREF(pRetVal);
205     }
206   } else {
207     Dmsg(plugin_ctx, debuglevel,
208          LOGPREFIX "Failed to find function named handle_plugin_event()\n");
209   }
210 
211   return retval;
212 
213 bail_out:
214   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
215 
216   return retval;
217 }
218 
NativeToPyStatPacket(struct stat * statp)219 static inline PyStatPacket* NativeToPyStatPacket(struct stat* statp)
220 {
221   PyStatPacket* pStatp = PyObject_New(PyStatPacket, &PyStatPacketType);
222 
223   if (pStatp) {
224     pStatp->dev = statp->st_dev;
225     pStatp->ino = statp->st_ino;
226     pStatp->mode = statp->st_mode;
227     pStatp->nlink = statp->st_nlink;
228     pStatp->uid = statp->st_uid;
229     pStatp->gid = statp->st_gid;
230     pStatp->rdev = statp->st_rdev;
231     pStatp->size = statp->st_size;
232     pStatp->atime = statp->st_atime;
233     pStatp->mtime = statp->st_mtime;
234     pStatp->ctime = statp->st_ctime;
235     pStatp->blksize = statp->st_blksize;
236     pStatp->blocks = statp->st_blocks;
237   }
238 
239   return pStatp;
240 }
241 
PyStatPacketToNative(PyStatPacket * pStatp,struct stat * statp)242 static inline void PyStatPacketToNative(PyStatPacket* pStatp,
243                                         struct stat* statp)
244 {
245   statp->st_dev = pStatp->dev;
246   statp->st_ino = pStatp->ino;
247   statp->st_mode = pStatp->mode;
248   statp->st_nlink = pStatp->nlink;
249   statp->st_uid = pStatp->uid;
250   statp->st_gid = pStatp->gid;
251   statp->st_rdev = pStatp->rdev;
252   statp->st_size = pStatp->size;
253   statp->st_atime = pStatp->atime;
254   statp->st_mtime = pStatp->mtime;
255   statp->st_ctime = pStatp->ctime;
256   statp->st_blksize = pStatp->blksize;
257   statp->st_blocks = pStatp->blocks;
258 }
259 
NativeToPySavePacket(struct save_pkt * sp)260 static inline PySavePacket* NativeToPySavePacket(struct save_pkt* sp)
261 {
262   PySavePacket* pSavePkt = PyObject_New(PySavePacket, &PySavePacketType);
263 
264   if (pSavePkt) {
265     pSavePkt->fname = PyUnicode_FromString(sp->fname ? sp->fname : "");
266     pSavePkt->link = PyUnicode_FromString(sp->link ? sp->link : "");
267     if (sp->statp.st_mode) {
268       pSavePkt->statp = (PyObject*)NativeToPyStatPacket(&sp->statp);
269     } else {
270       pSavePkt->statp = NULL;
271     }
272 
273     pSavePkt->type = sp->type;
274     pSavePkt->flags
275         = PyByteArray_FromStringAndSize(sp->flags, sizeof(sp->flags));
276     pSavePkt->no_read = sp->no_read;
277     pSavePkt->portable = sp->portable;
278     pSavePkt->accurate_found = sp->accurate_found;
279     pSavePkt->cmd = sp->cmd;
280     pSavePkt->save_time = sp->save_time;
281     pSavePkt->delta_seq = sp->delta_seq;
282     pSavePkt->object_name = NULL;
283     pSavePkt->object = NULL;
284     pSavePkt->object_len = sp->object_len;
285     pSavePkt->object_index = sp->index;
286   }
287 
288   return pSavePkt;
289 }  // namespace filedaemon
290 
PySavePacketToNative(PySavePacket * pSavePkt,struct save_pkt * sp,struct plugin_private_context * plugin_priv_ctx,bool is_options_plugin)291 static inline bool PySavePacketToNative(
292     PySavePacket* pSavePkt,
293     struct save_pkt* sp,
294     struct plugin_private_context* plugin_priv_ctx,
295     bool is_options_plugin)
296 {
297   /*
298    * See if this is for an Options Plugin.
299    */
300   if (!is_options_plugin) {
301     /*
302      * Only copy back the arguments that are allowed to change.
303      */
304     if (pSavePkt->fname) {
305       /*
306        * As this has to linger as long as the backup is running we save it in
307        * our plugin context.
308        */
309       if (PyUnicode_Check(pSavePkt->fname)) {
310         if (plugin_priv_ctx->fname) { free(plugin_priv_ctx->fname); }
311         plugin_priv_ctx->fname = strdup(PyUnicode_AsUTF8(pSavePkt->fname));
312         sp->fname = plugin_priv_ctx->fname;
313       }
314     } else {
315       goto bail_out;
316     }
317 
318     /*
319      * Optional field.
320      */
321     if (pSavePkt->link) {
322       /*
323        * As this has to linger as long as the backup is running we save it in
324        * our plugin context.
325        */
326       if (PyUnicode_Check(pSavePkt->link)) {
327         if (plugin_priv_ctx->link) { free(plugin_priv_ctx->link); }
328         plugin_priv_ctx->link = strdup(PyUnicode_AsUTF8(pSavePkt->link));
329         sp->link = plugin_priv_ctx->link;
330       }
331     }
332 
333     /*
334      * Handle the stat structure.
335      */
336     if (pSavePkt->statp) {
337       PyStatPacketToNative((PyStatPacket*)pSavePkt->statp, &sp->statp);
338     } else {
339       goto bail_out;
340     }
341 
342     sp->type = pSavePkt->type;
343 
344     if (PyByteArray_Check(pSavePkt->flags)) {
345       char* flags;
346 
347       if (PyByteArray_Size(pSavePkt->flags) != sizeof(sp->flags)) {
348         goto bail_out;
349       }
350 
351       if ((flags = PyByteArray_AsString(pSavePkt->flags))) {
352         memcpy(sp->flags, flags, sizeof(sp->flags));
353       } else {
354         goto bail_out;
355       }
356     } else {
357       goto bail_out;
358     }
359 
360     /*
361      * Special code for handling restore objects.
362      */
363     if (IS_FT_OBJECT(sp->type)) {
364       /*
365        * See if a proper restore object was created.
366        */
367       if (pSavePkt->object_len > 0) {
368         /*
369          * As this has to linger as long as the backup is running we save it
370          * in our plugin context.
371          */
372         if (pSavePkt->object_name && pSavePkt->object
373             && PyUnicode_Check(pSavePkt->object_name)
374             && PyByteArray_Check(pSavePkt->object)) {
375           char* buf;
376 
377           if (plugin_priv_ctx->object_name) {
378             free(plugin_priv_ctx->object_name);
379           }
380           plugin_priv_ctx->object_name
381               = strdup(PyUnicode_AsUTF8(pSavePkt->object_name));
382           sp->object_name = plugin_priv_ctx->object_name;
383 
384           sp->object_len = pSavePkt->object_len;
385           sp->index = pSavePkt->object_index;
386 
387           if ((buf = PyByteArray_AsString(pSavePkt->object))) {
388             if (plugin_priv_ctx->object) { free(plugin_priv_ctx->object); }
389             plugin_priv_ctx->object = (char*)malloc(pSavePkt->object_len);
390             memcpy(plugin_priv_ctx->object, buf, pSavePkt->object_len);
391             sp->object = plugin_priv_ctx->object;
392           } else {
393             goto bail_out;
394           }
395         } else {
396           goto bail_out;
397         }
398       } else {
399         goto bail_out;
400       }
401     } else {
402       sp->no_read = pSavePkt->no_read;
403       sp->delta_seq = pSavePkt->delta_seq;
404     }
405   } else {
406     sp->no_read = pSavePkt->no_read;
407     sp->delta_seq = pSavePkt->delta_seq;
408 
409     if (PyByteArray_Check(pSavePkt->flags)) {
410       char* flags;
411 
412       if (PyByteArray_Size(pSavePkt->flags) != sizeof(sp->flags)) {
413         goto bail_out;
414       }
415 
416       if ((flags = PyByteArray_AsString(pSavePkt->flags))) {
417         memcpy(sp->flags, flags, sizeof(sp->flags));
418       } else {
419         goto bail_out;
420       }
421     } else {
422       goto bail_out;
423     }
424   }
425 
426   return true;
427 
428 bail_out:
429   return false;
430 }
431 
432 /**
433  * Called when starting to backup a file. Here the plugin must
434  * return the "stat" packet for the directory/file and provide
435  * certain information so that Bareos knows what the file is.
436  * The plugin can create "Virtual" files by giving them a
437  * name that is not normally found on the file system.
438  */
PyStartBackupFile(PluginContext * plugin_ctx,struct save_pkt * sp)439 static bRC PyStartBackupFile(PluginContext* plugin_ctx, struct save_pkt* sp)
440 {
441   bRC retval = bRC_Error;
442   struct plugin_private_context* plugin_priv_ctx
443       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
444   PyObject* pFunc;
445 
446   /*
447    * Lookup the start_backup_file() function in the python module.
448    */
449   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
450                                "start_backup_file"); /* Borrowed reference */
451   if (pFunc && PyCallable_Check(pFunc)) {
452     PySavePacket* pSavePkt;
453     PyObject* pRetVal;
454 
455     pSavePkt = NativeToPySavePacket(sp);
456     if (!pSavePkt) { goto bail_out; }
457 
458     pRetVal = PyObject_CallFunctionObjArgs(pFunc, (PyObject*)pSavePkt, NULL);
459     if (!pRetVal) {
460       Py_DECREF((PyObject*)pSavePkt);
461       goto bail_out;
462     } else {
463       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
464       Py_DECREF(pRetVal);
465 
466       if (!PySavePacketToNative(pSavePkt, sp, plugin_priv_ctx, false)) {
467         Py_DECREF((PyObject*)pSavePkt);
468         goto bail_out;
469       }
470       Py_DECREF((PyObject*)pSavePkt);
471     }
472   } else {
473     Dmsg(plugin_ctx, debuglevel,
474          LOGPREFIX "Failed to find function named start_backup_file()\n");
475   }
476 
477   return retval;
478 
479 bail_out:
480   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
481 
482   return retval;
483 }
484 
485 /**
486  * Called at the end of backing up a file for a command plugin.
487  * If the plugin's work is done, it should return bRC_OK.
488  * If the plugin wishes to create another file and back it up,
489  * then it must return bRC_More (not yet implemented).
490  */
PyEndBackupFile(PluginContext * plugin_ctx)491 static bRC PyEndBackupFile(PluginContext* plugin_ctx)
492 {
493   bRC retval = bRC_Error;
494   struct plugin_private_context* plugin_priv_ctx
495       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
496   PyObject* pFunc;
497 
498   /*
499    * Lookup the end_backup_file() function in the python module.
500    */
501   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
502                                "end_backup_file"); /* Borrowed reference */
503   if (pFunc && PyCallable_Check(pFunc)) {
504     PyObject* pRetVal;
505 
506     pRetVal = PyObject_CallFunctionObjArgs(pFunc, NULL);
507     if (!pRetVal) {
508       goto bail_out;
509     } else {
510       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
511     }
512   } else {
513     Dmsg(plugin_ctx, debuglevel,
514          LOGPREFIX "Failed to find function named end_backup_file()\n");
515   }
516 
517   return retval;
518 
519 bail_out:
520   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
521 
522   return retval;
523 }
524 
NativeToPyIoPacket(struct io_pkt * io)525 static inline PyIoPacket* NativeToPyIoPacket(struct io_pkt* io)
526 {
527   PyIoPacket* pIoPkt = PyObject_New(PyIoPacket, &PyIoPacketType);
528 
529   if (pIoPkt) {
530     /*
531      * Initialize the Python IoPkt with the data we got passed in.
532      */
533     pIoPkt->func = io->func;
534     pIoPkt->count = io->count;
535     pIoPkt->flags = io->flags;
536     pIoPkt->mode = io->mode;
537     pIoPkt->fname = io->fname;
538     pIoPkt->whence = io->whence;
539     pIoPkt->offset = io->offset;
540     if (io->func == IO_WRITE && io->count > 0) {
541       /*
542        * Only initialize the buffer with read data when we are writing and
543        * there is data.
544        */
545       pIoPkt->buf = PyByteArray_FromStringAndSize(io->buf, io->count);
546       if (!pIoPkt->buf) {
547         Py_DECREF((PyObject*)pIoPkt);
548         return (PyIoPacket*)NULL;
549       }
550     } else {
551       pIoPkt->buf = NULL;
552     }
553 
554     /*
555      * These must be set by the Python function but we initialize them to zero
556      * to be sure they have some valid setting an not random data.
557      */
558     pIoPkt->io_errno = 0;
559     pIoPkt->lerror = 0;
560     pIoPkt->win32 = false;
561     pIoPkt->status = 0;
562   }
563 
564   return pIoPkt;
565 }
566 
PyIoPacketToNative(PyIoPacket * pIoPkt,struct io_pkt * io)567 static inline bool PyIoPacketToNative(PyIoPacket* pIoPkt, struct io_pkt* io)
568 {
569   /*
570    * Only copy back the arguments that are allowed to change.
571    */
572   io->io_errno = pIoPkt->io_errno;
573   io->lerror = pIoPkt->lerror;
574   io->win32 = pIoPkt->win32;
575   io->status = pIoPkt->status;
576   if (io->func == IO_READ && io->status > 0) {
577     /*
578      * Only copy back the data when doing a read and there is data.
579      */
580     if (PyByteArray_Check(pIoPkt->buf)) {
581       char* buf;
582 
583       if (PyByteArray_Size(pIoPkt->buf) > io->count || io->status > io->count) {
584         return false;
585       }
586 
587       if (!(buf = PyByteArray_AsString(pIoPkt->buf))) { return false; }
588       memcpy(io->buf, buf, io->status);
589     }
590   }
591 
592   return true;
593 }
594 
595 /**
596  * Do actual I/O. Bareos calls this after startBackupFile
597  * or after startRestoreFile to do the actual file
598  * input or output.
599  */
PyPluginIO(PluginContext * plugin_ctx,struct io_pkt * io)600 static bRC PyPluginIO(PluginContext* plugin_ctx, struct io_pkt* io)
601 {
602   bRC retval = bRC_Error;
603   struct plugin_private_context* plugin_priv_ctx
604       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
605   PyObject* pFunc;
606 
607   /*
608    * Lookup the plugin_io() function in the python module.
609    */
610   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
611                                "plugin_io"); /* Borrowed reference */
612   if (pFunc && PyCallable_Check(pFunc)) {
613     PyIoPacket* pIoPkt;
614     PyObject* pRetVal;
615 
616     pIoPkt = NativeToPyIoPacket(io);
617     if (!pIoPkt) { goto bail_out; }
618 
619     pRetVal = PyObject_CallFunctionObjArgs(pFunc, (PyObject*)pIoPkt, NULL);
620     if (!pRetVal) {
621       Py_DECREF((PyObject*)pIoPkt);
622       goto bail_out;
623     } else {
624       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
625       Py_DECREF(pRetVal);
626 
627       if (!PyIoPacketToNative(pIoPkt, io)) {
628         Py_DECREF((PyObject*)pIoPkt);
629         goto bail_out;
630       }
631     }
632     Py_DECREF((PyObject*)pIoPkt);
633   } else {
634     Dmsg(plugin_ctx, debuglevel,
635          LOGPREFIX "Failed to find function named plugin_io()\n");
636   }
637 
638   return retval;
639 
640 bail_out:
641   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
642 
643   io->status = -1;
644 
645   return retval;
646 }
647 
648 /**
649  * Called when the first record is read from the Volume that was previously
650  * written by the command plugin.
651  */
PyStartRestoreFile(PluginContext * plugin_ctx,const char * cmd)652 static bRC PyStartRestoreFile(PluginContext* plugin_ctx, const char* cmd)
653 {
654   bRC retval = bRC_Error;
655   struct plugin_private_context* plugin_priv_ctx
656       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
657   PyObject* pFunc;
658 
659   /*
660    * Lookup the start_restore_file() function in the python module.
661    */
662   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
663                                "start_restore_file"); /* Borrowed reference */
664   if (pFunc && PyCallable_Check(pFunc)) {
665     PyObject *pCmd, *pRetVal;
666 
667     pCmd = PyUnicode_FromString(cmd);
668     if (!pCmd) { goto bail_out; }
669 
670     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pCmd, NULL);
671     Py_DECREF(pCmd);
672 
673     if (!pRetVal) {
674       goto bail_out;
675     } else {
676       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
677       Py_DECREF(pRetVal);
678     }
679   } else {
680     Dmsg(plugin_ctx, debuglevel,
681          LOGPREFIX "Failed to find function named start_restore_file()\n");
682   }
683 
684   return retval;
685 
686 bail_out:
687   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
688 
689   return retval;
690 }
691 
692 /**
693  * Called when a command plugin is done restoring a file.
694  */
PyEndRestoreFile(PluginContext * plugin_ctx)695 static bRC PyEndRestoreFile(PluginContext* plugin_ctx)
696 {
697   bRC retval = bRC_Error;
698   struct plugin_private_context* plugin_priv_ctx
699       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
700   PyObject* pFunc;
701 
702   /*
703    * Lookup the end_restore_file() function in the python module.
704    */
705   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
706                                "end_restore_file"); /* Borrowed reference */
707   if (pFunc && PyCallable_Check(pFunc)) {
708     PyObject* pRetVal;
709 
710     pRetVal = PyObject_CallFunctionObjArgs(pFunc, NULL);
711     if (!pRetVal) {
712       goto bail_out;
713     } else {
714       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
715     }
716   } else {
717     Dmsg(plugin_ctx, debuglevel,
718          LOGPREFIX "Failed to find function named end_restore_file()\n");
719   }
720 
721   return retval;
722 
723 bail_out:
724   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
725 
726   return retval;
727 }
728 
NativeToPyRestorePacket(struct restore_pkt * rp)729 static inline PyRestorePacket* NativeToPyRestorePacket(struct restore_pkt* rp)
730 {
731   PyRestorePacket* pRestorePacket
732       = PyObject_New(PyRestorePacket, &PyRestorePacketType);
733 
734   if (pRestorePacket) {
735     pRestorePacket->stream = rp->stream;
736     pRestorePacket->data_stream = rp->data_stream;
737     pRestorePacket->type = rp->type;
738     pRestorePacket->file_index = rp->file_index;
739     pRestorePacket->LinkFI = rp->LinkFI;
740     pRestorePacket->uid = rp->uid;
741     pRestorePacket->statp = (PyObject*)NativeToPyStatPacket(&rp->statp);
742     pRestorePacket->attrEx = rp->attrEx;
743     pRestorePacket->ofname = rp->ofname;
744     pRestorePacket->olname = rp->olname;
745     pRestorePacket->where = rp->where;
746     pRestorePacket->RegexWhere = rp->RegexWhere;
747     pRestorePacket->replace = rp->replace;
748     pRestorePacket->create_status = rp->create_status;
749   }
750 
751   return pRestorePacket;
752 }
753 
PyRestorePacketToNative(PyRestorePacket * pRestorePacket,struct restore_pkt * rp)754 static inline void PyRestorePacketToNative(PyRestorePacket* pRestorePacket,
755                                            struct restore_pkt* rp)
756 {
757   /*
758    * Only copy back the fields that are allowed to be changed.
759    */
760   rp->create_status = pRestorePacket->create_status;
761 }
762 
763 /**
764  * Called for a command plugin to create a file during a Restore job before
765  * restoring the data. This entry point is called before any I/O is done on
766  * the file. After this call, Bareos will call pluginIO() to open the file for
767  * write.
768  *
769  * We must return in rp->create_status:
770  *
771  * CF_ERROR    -- error
772  * CF_SKIP     -- skip processing this file
773  * CF_EXTRACT  -- extract the file (i.e.call i/o routines)
774  * CF_CREATED  -- created, but no content to extract (typically directories)
775  */
PyCreateFile(PluginContext * plugin_ctx,struct restore_pkt * rp)776 static bRC PyCreateFile(PluginContext* plugin_ctx, struct restore_pkt* rp)
777 {
778   bRC retval = bRC_Error;
779   struct plugin_private_context* plugin_priv_ctx
780       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
781   PyObject* pFunc;
782 
783   if (!rp) { return bRC_Error; }
784 
785   /*
786    * Lookup the create_file() function in the python module.
787    */
788   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
789                                "create_file"); /* Borrowed reference */
790   if (pFunc && PyCallable_Check(pFunc)) {
791     PyRestorePacket* pRestorePacket;
792     PyObject* pRetVal;
793 
794     pRestorePacket = NativeToPyRestorePacket(rp);
795     if (!pRestorePacket) { goto bail_out; }
796 
797     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pRestorePacket, NULL);
798     if (!pRetVal) {
799       Py_DECREF(pRestorePacket);
800       goto bail_out;
801     } else {
802       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
803       Py_DECREF(pRetVal);
804 
805       PyRestorePacketToNative(pRestorePacket, rp);
806       Py_DECREF(pRestorePacket);
807     }
808   } else {
809     Dmsg(plugin_ctx, debuglevel,
810          LOGPREFIX "Failed to find function named create_file()\n");
811   }
812 
813   return retval;
814 
815 bail_out:
816   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
817 
818   return retval;
819 }
820 
PySetFileAttributes(PluginContext * plugin_ctx,struct restore_pkt * rp)821 static bRC PySetFileAttributes(PluginContext* plugin_ctx,
822                                struct restore_pkt* rp)
823 {
824   bRC retval = bRC_Error;
825   struct plugin_private_context* plugin_priv_ctx
826       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
827   PyObject* pFunc;
828 
829   if (!rp) { return bRC_Error; }
830 
831   /*
832    * Lookup the set_file_attributes() function in the python module.
833    */
834   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
835                                "set_file_attributes"); /* Borrowed reference */
836   if (pFunc && PyCallable_Check(pFunc)) {
837     PyRestorePacket* pRestorePacket;
838     PyObject* pRetVal;
839 
840     pRestorePacket = NativeToPyRestorePacket(rp);
841     if (!pRestorePacket) { goto bail_out; }
842 
843     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pRestorePacket, NULL);
844     if (!pRetVal) {
845       Py_DECREF(pRestorePacket);
846       goto bail_out;
847     } else {
848       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
849       Py_DECREF(pRetVal);
850       Py_DECREF(pRestorePacket);
851     }
852   } else {
853     Dmsg(plugin_ctx, debuglevel,
854          LOGPREFIX "Failed to find function named set_file_attributes()\n");
855   }
856 
857   return retval;
858 
859 bail_out:
860   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
861 
862   return retval;
863 }
864 
PyCheckFile(PluginContext * plugin_ctx,char * fname)865 static bRC PyCheckFile(PluginContext* plugin_ctx, char* fname)
866 {
867   bRC retval = bRC_Error;
868   struct plugin_private_context* plugin_priv_ctx
869       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
870   PyObject* pFunc;
871 
872   if (!fname) { return bRC_Error; }
873 
874   /*
875    * Lookup the check_file() function in the python module.
876    */
877   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
878                                "check_file"); /* Borrowed reference */
879   if (pFunc && PyCallable_Check(pFunc)) {
880     PyObject *pFname, *pRetVal;
881 
882     pFname = PyUnicode_FromString(fname);
883     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pFname, NULL);
884     Py_DECREF(pFname);
885 
886     if (!pRetVal) {
887       goto bail_out;
888     } else {
889       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
890       Py_DECREF(pRetVal);
891     }
892   } else {
893     Dmsg(plugin_ctx, debuglevel,
894          LOGPREFIX "Failed to find function named check_file()\n");
895   }
896 
897   return retval;
898 
899 bail_out:
900   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
901 
902   return retval;
903 }
904 
NativeToPyAclPacket(struct acl_pkt * ap)905 static inline PyAclPacket* NativeToPyAclPacket(struct acl_pkt* ap)
906 {
907   PyAclPacket* pAclPacket = PyObject_New(PyAclPacket, &PyAclPacketType);
908 
909   if (pAclPacket) {
910     pAclPacket->fname = ap->fname;
911 
912     if (ap->content_length && ap->content) {
913       pAclPacket->content
914           = PyByteArray_FromStringAndSize(ap->content, ap->content_length);
915     } else {
916       pAclPacket->content = NULL;
917     }
918   }
919 
920   return pAclPacket;
921 }
922 
PyAclPacketToNative(PyAclPacket * pAclPacket,struct acl_pkt * ap)923 static inline bool PyAclPacketToNative(PyAclPacket* pAclPacket,
924                                        struct acl_pkt* ap)
925 {
926   if (!pAclPacket->content) { return true; }
927 
928   if (PyByteArray_Check(pAclPacket->content)) {
929     char* buf;
930 
931     ap->content_length = PyByteArray_Size(pAclPacket->content);
932     if (ap->content_length <= 0
933         || !(buf = PyByteArray_AsString(pAclPacket->content))) {
934       return false;
935     }
936 
937     if (ap->content) { free(ap->content); }
938     ap->content = (char*)malloc(ap->content_length);
939     memcpy(ap->content, buf, ap->content_length);
940   }
941 
942   return true;
943 }
944 
PyGetAcl(PluginContext * plugin_ctx,acl_pkt * ap)945 static bRC PyGetAcl(PluginContext* plugin_ctx, acl_pkt* ap)
946 {
947   bRC retval = bRC_Error;
948   struct plugin_private_context* plugin_priv_ctx
949       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
950   PyObject* pFunc;
951 
952   if (!ap) { return bRC_Error; }
953 
954   /*
955    * Lookup the get_acl() function in the python module.
956    */
957   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
958                                "get_acl"); /* Borrowed reference */
959   if (pFunc && PyCallable_Check(pFunc)) {
960     PyAclPacket* pAclPkt;
961     PyObject* pRetVal;
962 
963     pAclPkt = NativeToPyAclPacket(ap);
964     if (!pAclPkt) { goto bail_out; }
965 
966     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pAclPkt, NULL);
967     if (!pRetVal) {
968       Py_DECREF((PyObject*)pAclPkt);
969       goto bail_out;
970     } else {
971       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
972       Py_DECREF(pRetVal);
973 
974       if (!PyAclPacketToNative(pAclPkt, ap)) {
975         Py_DECREF((PyObject*)pAclPkt);
976         goto bail_out;
977       }
978       Py_DECREF(pAclPkt);
979     }
980   } else {
981     Dmsg(plugin_ctx, debuglevel,
982          LOGPREFIX "Failed to find function named get_acl()\n");
983   }
984 
985   return retval;
986 
987 bail_out:
988   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
989 
990   return retval;
991 }
992 
PySetAcl(PluginContext * plugin_ctx,acl_pkt * ap)993 static bRC PySetAcl(PluginContext* plugin_ctx, acl_pkt* ap)
994 {
995   bRC retval = bRC_Error;
996   struct plugin_private_context* plugin_priv_ctx
997       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
998   PyObject* pFunc;
999 
1000   if (!ap) { return bRC_Error; }
1001 
1002   /*
1003    * Lookup the set_acl() function in the python module.
1004    */
1005   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
1006                                "set_acl"); /* Borrowed reference */
1007   if (pFunc && PyCallable_Check(pFunc)) {
1008     PyAclPacket* pAclPkt;
1009     PyObject* pRetVal;
1010 
1011     pAclPkt = NativeToPyAclPacket(ap);
1012     if (!pAclPkt) { goto bail_out; }
1013 
1014     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pAclPkt, NULL);
1015     Py_DECREF(pAclPkt);
1016 
1017     if (!pRetVal) {
1018       goto bail_out;
1019     } else {
1020       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
1021       Py_DECREF(pRetVal);
1022     }
1023   } else {
1024     Dmsg(plugin_ctx, debuglevel,
1025          LOGPREFIX "Failed to find function named set_acl()\n");
1026   }
1027 
1028   return retval;
1029 
1030 bail_out:
1031   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
1032 
1033   return retval;
1034 }
1035 
NativeToPyXattrPacket(struct xattr_pkt * xp)1036 static inline PyXattrPacket* NativeToPyXattrPacket(struct xattr_pkt* xp)
1037 {
1038   PyXattrPacket* pXattrPacket = PyObject_New(PyXattrPacket, &PyXattrPacketType);
1039 
1040   if (pXattrPacket) {
1041     pXattrPacket->fname = xp->fname;
1042 
1043     if (xp->name_length && xp->name) {
1044       pXattrPacket->name
1045           = PyByteArray_FromStringAndSize(xp->name, xp->name_length);
1046     } else {
1047       pXattrPacket->name = NULL;
1048     }
1049     if (xp->value_length && xp->value) {
1050       pXattrPacket->value
1051           = PyByteArray_FromStringAndSize(xp->value, xp->value_length);
1052     } else {
1053       pXattrPacket->value = NULL;
1054     }
1055   }
1056 
1057   return pXattrPacket;
1058 }
1059 
PyXattrPacketToNative(PyXattrPacket * pXattrPacket,struct xattr_pkt * xp)1060 static inline bool PyXattrPacketToNative(PyXattrPacket* pXattrPacket,
1061                                          struct xattr_pkt* xp)
1062 {
1063   if (!pXattrPacket->name) { return true; }
1064 
1065   if (PyByteArray_Check(pXattrPacket->name)) {
1066     char* buf;
1067 
1068     xp->name_length = PyByteArray_Size(pXattrPacket->name);
1069     if (xp->name_length <= 0
1070         || !(buf = PyByteArray_AsString(pXattrPacket->name))) {
1071       return false;
1072     }
1073 
1074     if (xp->name) { free(xp->name); }
1075     xp->name = (char*)malloc(xp->name_length);
1076     memcpy(xp->name, buf, xp->name_length);
1077   }
1078 
1079   if (pXattrPacket->value && PyByteArray_Check(pXattrPacket->value)) {
1080     char* buf;
1081 
1082     xp->value_length = PyByteArray_Size(pXattrPacket->value);
1083     if (xp->name_length <= 0
1084         || !(buf = PyByteArray_AsString(pXattrPacket->name))) {
1085       return false;
1086     }
1087 
1088     if (xp->value) { free(xp->value); }
1089     xp->value = (char*)malloc(xp->value_length);
1090     memcpy(xp->value, buf, xp->value_length);
1091   } else {
1092     if (xp->value) { free(xp->value); }
1093     xp->value = NULL;
1094   }
1095 
1096   return true;
1097 }
1098 
PyGetXattr(PluginContext * plugin_ctx,xattr_pkt * xp)1099 static bRC PyGetXattr(PluginContext* plugin_ctx, xattr_pkt* xp)
1100 {
1101   bRC retval = bRC_Error;
1102   struct plugin_private_context* plugin_priv_ctx
1103       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
1104   PyObject* pFunc;
1105 
1106   if (!xp) { return bRC_Error; }
1107 
1108   /*
1109    * Lookup the get_xattr() function in the python module.
1110    */
1111   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
1112                                "get_xattr"); /* Borrowed reference */
1113   if (pFunc && PyCallable_Check(pFunc)) {
1114     PyXattrPacket* pXattrPkt;
1115     PyObject* pRetVal;
1116 
1117     pXattrPkt = NativeToPyXattrPacket(xp);
1118     if (!pXattrPkt) { goto bail_out; }
1119 
1120     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pXattrPkt, NULL);
1121     if (!pRetVal) {
1122       Py_DECREF((PyObject*)pXattrPkt);
1123       goto bail_out;
1124     } else {
1125       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
1126       Py_DECREF(pRetVal);
1127 
1128       if (!PyXattrPacketToNative(pXattrPkt, xp)) {
1129         Py_DECREF((PyObject*)pXattrPkt);
1130         goto bail_out;
1131       }
1132       Py_DECREF(pXattrPkt);
1133     }
1134   } else {
1135     Dmsg(plugin_ctx, debuglevel,
1136          LOGPREFIX "Failed to find function named get_xattr()\n");
1137   }
1138 
1139   return retval;
1140 
1141 bail_out:
1142   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
1143 
1144   return retval;
1145 }
1146 
PySetXattr(PluginContext * plugin_ctx,xattr_pkt * xp)1147 static bRC PySetXattr(PluginContext* plugin_ctx, xattr_pkt* xp)
1148 {
1149   bRC retval = bRC_Error;
1150   struct plugin_private_context* plugin_priv_ctx
1151       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
1152   PyObject* pFunc;
1153 
1154   if (!xp) { return bRC_Error; }
1155 
1156   /*
1157    * Lookup the set_acl() function in the python module.
1158    */
1159   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
1160                                "set_xattr"); /* Borrowed reference */
1161   if (pFunc && PyCallable_Check(pFunc)) {
1162     PyXattrPacket* pXattrPkt;
1163     PyObject* pRetVal;
1164 
1165     pXattrPkt = NativeToPyXattrPacket(xp);
1166     if (!pXattrPkt) { goto bail_out; }
1167 
1168     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pXattrPkt, NULL);
1169     Py_DECREF(pXattrPkt);
1170 
1171     if (!pRetVal) {
1172       goto bail_out;
1173     } else {
1174       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
1175       Py_DECREF(pRetVal);
1176     }
1177   } else {
1178     Dmsg(plugin_ctx, debuglevel,
1179          LOGPREFIX "Failed to find function named set_xattr()\n");
1180   }
1181 
1182   return retval;
1183 bail_out:
1184   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
1185 
1186   return retval;
1187 }
1188 
NativeToPyRestoreObject(struct restore_object_pkt * rop)1189 static inline PyRestoreObject* NativeToPyRestoreObject(
1190     struct restore_object_pkt* rop)
1191 {
1192   PyRestoreObject* pRestoreObject
1193       = PyObject_New(PyRestoreObject, &PyRestoreObjectType);
1194 
1195   if (pRestoreObject) {
1196     pRestoreObject->object_name = PyUnicode_FromString(rop->object_name);
1197     pRestoreObject->object
1198         = PyByteArray_FromStringAndSize(rop->object, rop->object_len);
1199     pRestoreObject->plugin_name = rop->plugin_name;
1200     pRestoreObject->object_type = rop->object_type;
1201     pRestoreObject->object_len = rop->object_len;
1202     pRestoreObject->object_full_len = rop->object_full_len;
1203     pRestoreObject->object_index = rop->object_index;
1204     pRestoreObject->object_compression = rop->object_compression;
1205     pRestoreObject->stream = rop->stream;
1206     pRestoreObject->JobId = rop->JobId;
1207   }
1208 
1209   return pRestoreObject;
1210 }
1211 
PyRestoreObjectData(PluginContext * plugin_ctx,struct restore_object_pkt * rop)1212 static bRC PyRestoreObjectData(PluginContext* plugin_ctx,
1213                                struct restore_object_pkt* rop)
1214 {
1215   bRC retval = bRC_Error;
1216   struct plugin_private_context* plugin_priv_ctx
1217       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
1218   PyObject* pFunc;
1219 
1220   if (!rop) { return bRC_OK; }
1221 
1222   /*
1223    * Lookup the restore_object_data() function in the python module.
1224    */
1225   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
1226                                "restore_object_data"); /* Borrowed reference */
1227   if (pFunc && PyCallable_Check(pFunc)) {
1228     PyRestoreObject* pRestoreObject;
1229     PyObject* pRetVal;
1230 
1231     pRestoreObject = NativeToPyRestoreObject(rop);
1232     if (!pRestoreObject) { goto bail_out; }
1233 
1234     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pRestoreObject, NULL);
1235     Py_DECREF(pRestoreObject);
1236 
1237     if (!pRetVal) {
1238       goto bail_out;
1239     } else {
1240       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
1241       Py_DECREF(pRetVal);
1242     }
1243   } else {
1244     Dmsg(plugin_ctx, debuglevel,
1245          LOGPREFIX "Failed to find function named start_restore_file()\n");
1246   }
1247 
1248   return retval;
1249 
1250 bail_out:
1251   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
1252 
1253   return retval;
1254 }
1255 
PyHandleBackupFile(PluginContext * plugin_ctx,struct save_pkt * sp)1256 static bRC PyHandleBackupFile(PluginContext* plugin_ctx, struct save_pkt* sp)
1257 {
1258   bRC retval = bRC_Error;
1259   struct plugin_private_context* plugin_priv_ctx
1260       = (struct plugin_private_context*)plugin_ctx->plugin_private_context;
1261   PyObject* pFunc;
1262 
1263   if (!sp) { return bRC_Error; }
1264 
1265   /*
1266    * Lookup the handle_backup_file() function in the python module.
1267    */
1268   pFunc = PyDict_GetItemString(plugin_priv_ctx->pyModuleFunctionsDict,
1269                                "handle_backup_file"); /* Borrowed reference */
1270   if (pFunc && PyCallable_Check(pFunc)) {
1271     PySavePacket* pSavePkt;
1272     PyObject* pRetVal;
1273 
1274     pSavePkt = NativeToPySavePacket(sp);
1275     if (!pSavePkt) { goto bail_out; }
1276 
1277     pRetVal = PyObject_CallFunctionObjArgs(pFunc, pSavePkt, NULL);
1278     if (!pRetVal) {
1279       Py_DECREF((PyObject*)pSavePkt);
1280       goto bail_out;
1281     } else {
1282       retval = ConvertPythonRetvalTobRCRetval(pRetVal);
1283       Py_DECREF(pRetVal);
1284 
1285       if (!PySavePacketToNative(pSavePkt, sp, plugin_priv_ctx, true)) {
1286         Py_DECREF((PyObject*)pSavePkt);
1287         goto bail_out;
1288       }
1289       Py_DECREF(pSavePkt);
1290     }
1291   } else {
1292     Dmsg(plugin_ctx, debuglevel,
1293          LOGPREFIX "Failed to find function named handle_backup_file()\n");
1294   }
1295 
1296   return retval;
1297 
1298 bail_out:
1299   if (PyErr_Occurred()) { PyErrorHandler(plugin_ctx, M_FATAL); }
1300 
1301   return retval;
1302 }
1303 
1304 /**
1305  * Callback function which is exposed as a part of the additional methods
1306  * which allow a Python plugin to get certain internal values of the current
1307  * Job.
1308  */
PyBareosGetValue(PyObject * self,PyObject * args)1309 static PyObject* PyBareosGetValue(PyObject* self, PyObject* args)
1310 {
1311   int var;
1312   PluginContext* plugin_ctx = plugin_context;
1313   PyObject* pRetVal = NULL;
1314 
1315   if (!PyArg_ParseTuple(args, "i:BareosGetValue", &var)) { return NULL; }
1316   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1317 
1318   switch (var) {
1319     case bVarFDName:
1320     case bVarWorkingDir:
1321     case bVarExePath:
1322     case bVarVersion:
1323     case bVarDistName: {
1324       char* value = NULL;
1325 
1326       if (bareos_core_functions->getBareosValue(plugin_ctx, (bVariable)var,
1327                                                 &value)
1328           == bRC_OK) {
1329         if (value) { pRetVal = PyUnicode_FromString(value); }
1330       }
1331       break;
1332     }
1333     case bVarJobId:
1334     case bVarLevel:
1335     case bVarType:
1336     case bVarJobStatus:
1337     case bVarSinceTime:
1338     case bVarAccurate:
1339     case bVarPrefixLinks: {
1340       int value = 0;
1341 
1342       if (bareos_core_functions->getBareosValue(plugin_ctx, (bVariable)var,
1343                                                 &value)
1344           == bRC_OK) {
1345         pRetVal = PyLong_FromLong(value);
1346       }
1347       break;
1348     }
1349     case bVarClient:
1350     case bVarJobName:
1351     case bVarPrevJobName:
1352     case bVarWhere:
1353     case bVarRegexWhere: {
1354       char* value = NULL;
1355 
1356       if (bareos_core_functions->getBareosValue(plugin_ctx, (bVariable)var,
1357                                                 &value)
1358           == bRC_OK) {
1359         if (value) { pRetVal = PyUnicode_FromString(value); }
1360       }
1361       break;
1362     }
1363     case bVarFileSeen:
1364       break; /* a write only variable, ignore read request */
1365     default:
1366       Dmsg(plugin_ctx, debuglevel,
1367            LOGPREFIX "PyBareosGetValue unknown variable requested %d\n", var);
1368       break;
1369   }
1370 
1371   if (!pRetVal) { Py_RETURN_NONE; }
1372 
1373   return pRetVal;
1374 }
1375 
1376 /**
1377  * Callback function which is exposed as a part of the additional methods
1378  * which allow a Python plugin to get certain internal values of the current
1379  * Job.
1380  */
PyBareosSetValue(PyObject * self,PyObject * args)1381 static PyObject* PyBareosSetValue(PyObject* self, PyObject* args)
1382 {
1383   int var;
1384   PluginContext* plugin_ctx = plugin_context;
1385   bRC retval = bRC_Error;
1386   PyObject* pyValue;
1387 
1388   if (!PyArg_ParseTuple(args, "iO:BareosSetValue", &var, &pyValue)) {
1389     goto bail_out;
1390   }
1391   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1392 
1393   switch (var) {
1394     case bVarLevel: {
1395       int value = 0;
1396 
1397       value = PyLong_AsLong(pyValue);
1398       if (value) {
1399         retval = bareos_core_functions->setBareosValue(plugin_ctx,
1400                                                        (bVariable)var, &value);
1401       }
1402       break;
1403     }
1404     case bVarFileSeen: {
1405       const char* value = PyUnicode_AsUTF8(pyValue);
1406       if (value) {
1407         retval = bareos_core_functions->setBareosValue(
1408             plugin_ctx, (bVariable)var,
1409             static_cast<void*>(const_cast<char*>(value)));
1410       }
1411       break;
1412     }
1413     default:
1414       Dmsg(plugin_ctx, debuglevel,
1415            LOGPREFIX "PyBareosSetValue unknown variable requested %d\n", var);
1416       break;
1417   }
1418 
1419 bail_out:
1420   return ConvertbRCRetvalToPythonRetval(retval);
1421 }
1422 
1423 /**
1424  * Callback function which is exposed as a part of the additional methods
1425  * which allow a Python plugin to issue debug messages using the Bareos debug
1426  * message facility.
1427  */
PyBareosDebugMessage(PyObject * self,PyObject * args)1428 static PyObject* PyBareosDebugMessage(PyObject* self, PyObject* args)
1429 {
1430   int level;
1431   char* dbgmsg = NULL;
1432   PluginContext* plugin_ctx = plugin_context;
1433   /* plugin_private_context* ppc = */
1434   /*     (plugin_private_context*)plugin_ctx->plugin_private_context;
1435    */
1436 
1437   if (!PyArg_ParseTuple(args, "i|z:BareosDebugMessage", &level, &dbgmsg)) {
1438     return NULL;
1439   }
1440   RETURN_RUNTIME_ERROR_IF_BAREOS_PLUGIN_CTX_UNSET()
1441 
1442   if (dbgmsg) { Dmsg(plugin_ctx, level, LOGPREFIX "%s", dbgmsg); }
1443 
1444   Py_RETURN_NONE;
1445 }
1446 
1447 /**
1448  * Callback function which is exposed as a part of the additional methods
1449  * which allow a Python plugin to issue Job messages using the Bareos Job
1450  * message facility.
1451  */
PyBareosJobMessage(PyObject * self,PyObject * args)1452 static PyObject* PyBareosJobMessage(PyObject* self, PyObject* args)
1453 {
1454   int level;
1455   char* jobmsg = NULL;
1456   PluginContext* plugin_ctx = plugin_context;
1457 
1458   if (!PyArg_ParseTuple(args, "i|z:BareosJobMessage", &level, &jobmsg)) {
1459     return NULL;
1460   }
1461   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1462 
1463   if (jobmsg) { Jmsg(plugin_ctx, level, LOGPREFIX "%s", jobmsg); }
1464 
1465   Py_RETURN_NONE;
1466 }
1467 
1468 /**
1469  * Callback function which is exposed as a part of the additional methods
1470  * which allow a Python plugin to issue a Register Event to register
1471  * additional events it wants to receive.
1472  */
PyBareosRegisterEvents(PyObject * self,PyObject * args)1473 static PyObject* PyBareosRegisterEvents(PyObject* self, PyObject* args)
1474 {
1475   int len, event;
1476   PluginContext* plugin_ctx = plugin_context;
1477   bRC retval = bRC_Error;
1478   PyObject *pyEvents, *pySeq, *pyEvent;
1479 
1480   if (!PyArg_ParseTuple(args, "O:BareosRegisterEvents", &pyEvents)) {
1481     goto bail_out;
1482   }
1483   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1484 
1485   pySeq = PySequence_Fast(pyEvents, "Expected a sequence of events");
1486   if (!pySeq) { goto bail_out; }
1487   len = PySequence_Fast_GET_SIZE(pySeq);
1488 
1489   for (int i = 0; i < len; i++) {
1490     pyEvent = PySequence_Fast_GET_ITEM(pySeq, i);
1491     event = PyLong_AsLong(pyEvent);
1492 
1493     if (event >= bEventJobStart && event <= FD_NR_EVENTS) {
1494       Dmsg(plugin_ctx, debuglevel,
1495            LOGPREFIX "PyBareosRegisterEvents registering event %d\n", event);
1496       retval
1497           = bareos_core_functions->registerBareosEvents(plugin_ctx, 1, event);
1498 
1499       if (retval != bRC_OK) { break; }
1500     }
1501   }
1502 
1503   Py_DECREF(pySeq);
1504 
1505 bail_out:
1506   return ConvertbRCRetvalToPythonRetval(retval);
1507 }
1508 
1509 /**
1510  * Callback function which is exposed as a part of the additional methods
1511  * which allow a Python plugin to issue an Unregister Event to unregister
1512  * events it doesn't want to receive anymore.
1513  */
PyBareosUnRegisterEvents(PyObject * self,PyObject * args)1514 static PyObject* PyBareosUnRegisterEvents(PyObject* self, PyObject* args)
1515 {
1516   int len, event;
1517   PluginContext* plugin_ctx = plugin_context;
1518   bRC retval = bRC_Error;
1519   PyObject *pyEvents, *pySeq, *pyEvent;
1520 
1521   if (!PyArg_ParseTuple(args, "O:BareosUnRegisterEvents", &pyEvents)) {
1522     goto bail_out;
1523   }
1524   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1525 
1526   pySeq = PySequence_Fast(pyEvents, "Expected a sequence of events");
1527   if (!pySeq) { goto bail_out; }
1528 
1529   len = PySequence_Fast_GET_SIZE(pySeq);
1530   for (int i = 0; i < len; i++) {
1531     pyEvent = PySequence_Fast_GET_ITEM(pySeq, i);
1532     event = PyLong_AsLong(pyEvent);
1533 
1534     if (event >= bEventJobStart && event <= FD_NR_EVENTS) {
1535       Dmsg(plugin_ctx, debuglevel,
1536            "PyBareosUnRegisterEvents: unregistering event %d\n", event);
1537       retval
1538           = bareos_core_functions->unregisterBareosEvents(plugin_ctx, 1, event);
1539     }
1540   }
1541 
1542   Py_DECREF(pySeq);
1543 
1544 bail_out:
1545   return ConvertbRCRetvalToPythonRetval(retval);
1546 }
1547 
1548 /**
1549  * Callback function which is exposed as a part of the additional methods
1550  * which allow a Python plugin to issue a GetInstanceCount to retrieve the
1551  * number of instances of the current plugin being loaded into the daemon.
1552  */
PyBareosGetInstanceCount(PyObject * self,PyObject * args)1553 static PyObject* PyBareosGetInstanceCount(PyObject* self, PyObject* args)
1554 {
1555   int value;
1556   PluginContext* plugin_ctx = plugin_context;
1557   PyObject* pRetVal = NULL;
1558 
1559   if (!PyArg_ParseTuple(args, ":BareosGetInstanceCount")) { return NULL; }
1560   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1561 
1562   if (bareos_core_functions->getInstanceCount(plugin_ctx, &value) == bRC_OK) {
1563     pRetVal = PyLong_FromLong(value);
1564   }
1565 
1566   if (!pRetVal) { Py_RETURN_NONE; }
1567 
1568   return pRetVal;
1569 }
1570 
1571 /**
1572  * Callback function which is exposed as a part of the additional methods
1573  * which allow a Python plugin to issue a Add Exclude pattern to the fileset.
1574  */
PyBareosAddExclude(PyObject * self,PyObject * args)1575 static PyObject* PyBareosAddExclude(PyObject* self, PyObject* args)
1576 {
1577   char* file = NULL;
1578   bRC retval = bRC_Error;
1579   PluginContext* plugin_ctx = plugin_context;
1580 
1581   if (!PyArg_ParseTuple(args, "|z:BareosAddExclude", &file)) { goto bail_out; }
1582   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1583 
1584   if (file) { retval = bareos_core_functions->AddExclude(plugin_ctx, file); }
1585 
1586 bail_out:
1587   return ConvertbRCRetvalToPythonRetval(retval);
1588 }
1589 
1590 /**
1591  * Callback function which is exposed as a part of the additional methods
1592  * which allow a Python plugin to issue a Add Include pattern to the fileset.
1593  */
PyBareosAddInclude(PyObject * self,PyObject * args)1594 static PyObject* PyBareosAddInclude(PyObject* self, PyObject* args)
1595 {
1596   char* file = NULL;
1597   bRC retval = bRC_Error;
1598   PluginContext* plugin_ctx = plugin_context;
1599 
1600   if (!PyArg_ParseTuple(args, "|z:BareosAddInclude", &file)) { goto bail_out; }
1601   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1602 
1603   if (file) { retval = bareos_core_functions->AddInclude(plugin_ctx, file); }
1604 
1605 bail_out:
1606   return ConvertbRCRetvalToPythonRetval(retval);
1607 }
1608 
1609 /**
1610  * Callback function which is exposed as a part of the additional methods
1611  * which allow a Python plugin to issue a Add Include Options to the fileset.
1612  */
PyBareosAddOptions(PyObject * self,PyObject * args)1613 static PyObject* PyBareosAddOptions(PyObject* self, PyObject* args)
1614 {
1615   char* opts = NULL;
1616   bRC retval = bRC_Error;
1617   PluginContext* plugin_ctx = plugin_context;
1618 
1619   if (!PyArg_ParseTuple(args, "|z:BareosAddOptions", &opts)) { goto bail_out; }
1620   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1621 
1622   if (opts) { retval = bareos_core_functions->AddOptions(plugin_ctx, opts); }
1623 
1624 bail_out:
1625   return ConvertbRCRetvalToPythonRetval(retval);
1626 }
1627 
1628 /**
1629  * Callback function which is exposed as a part of the additional methods
1630  * which allow a Python plugin to issue a Add Regex to the fileset.
1631  */
PyBareosAddRegex(PyObject * self,PyObject * args)1632 static PyObject* PyBareosAddRegex(PyObject* self, PyObject* args)
1633 {
1634   int type;
1635   char* item = NULL;
1636   bRC retval = bRC_Error;
1637   PluginContext* plugin_ctx = plugin_context;
1638   if (!PyArg_ParseTuple(args, "|zi:BareosAddRegex", &item, &type)) {
1639     goto bail_out;
1640   }
1641   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1642 
1643   if (item) {
1644     retval = bareos_core_functions->AddRegex(plugin_ctx, item, type);
1645   }
1646 
1647 bail_out:
1648   return ConvertbRCRetvalToPythonRetval(retval);
1649 }
1650 
1651 /**
1652  * Callback function which is exposed as a part of the additional methods
1653  * which allow a Python plugin to issue a Add Wildcard to the fileset.
1654  */
PyBareosAddWild(PyObject * self,PyObject * args)1655 static PyObject* PyBareosAddWild(PyObject* self, PyObject* args)
1656 {
1657   int type;
1658   char* item = NULL;
1659   bRC retval = bRC_Error;
1660   PluginContext* plugin_ctx = plugin_context;
1661 
1662   if (!PyArg_ParseTuple(args, "|zi:BareosAddWild", &item, &type)) {
1663     goto bail_out;
1664   }
1665   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1666 
1667   if (item) { retval = bareos_core_functions->AddWild(plugin_ctx, item, type); }
1668 
1669 bail_out:
1670   return ConvertbRCRetvalToPythonRetval(retval);
1671 }
1672 
1673 /**
1674  * Callback function which is exposed as a part of the additional methods
1675  * which allow a Python plugin to issue a Add New Option block.
1676  */
PyBareosNewOptions(PyObject * self,PyObject * args)1677 static PyObject* PyBareosNewOptions(PyObject* self, PyObject* args)
1678 {
1679   PluginContext* plugin_ctx = plugin_context;
1680   bRC retval = bRC_Error;
1681 
1682   if (!PyArg_ParseTuple(args, ":BareosNewOptions")) { goto bail_out; }
1683   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1684 
1685   retval = bareos_core_functions->NewOptions(plugin_ctx);
1686 
1687 bail_out:
1688   return ConvertbRCRetvalToPythonRetval(retval);
1689 }
1690 
1691 /**
1692  * Callback function which is exposed as a part of the additional methods
1693  * which allow a Python plugin to issue a Add New Include block.
1694  */
PyBareosNewInclude(PyObject * self,PyObject * args)1695 static PyObject* PyBareosNewInclude(PyObject* self, PyObject* args)
1696 {
1697   PluginContext* plugin_ctx = plugin_context;
1698   bRC retval = bRC_Error;
1699 
1700   if (!PyArg_ParseTuple(args, ":BareosNewInclude")) { goto bail_out; }
1701   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1702 
1703   retval = bareos_core_functions->NewInclude(plugin_ctx);
1704 
1705 bail_out:
1706   return ConvertbRCRetvalToPythonRetval(retval);
1707 }
1708 
1709 /**
1710  * Callback function which is exposed as a part of the additional methods
1711  * which allow a Python plugin to issue a Add New Pre Include block.
1712  */
PyBareosNewPreInclude(PyObject * self,PyObject * args)1713 static PyObject* PyBareosNewPreInclude(PyObject* self, PyObject* args)
1714 {
1715   PluginContext* plugin_ctx = plugin_context;
1716   bRC retval = bRC_Error;
1717 
1718   if (!PyArg_ParseTuple(args, ":BareosNewPreInclude")) { goto bail_out; }
1719   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1720 
1721   retval = bareos_core_functions->NewPreInclude(plugin_ctx);
1722 
1723 bail_out:
1724   return ConvertbRCRetvalToPythonRetval(retval);
1725 }
1726 
1727 /**
1728  * Callback function which is exposed as a part of the additional methods
1729  * which allow a Python plugin to issue a check if a file have to be backed up
1730  * using Accurate code.
1731  */
PyBareosCheckChanges(PyObject * self,PyObject * args)1732 static PyObject* PyBareosCheckChanges(PyObject* self, PyObject* args)
1733 {
1734   PluginContext* plugin_ctx = plugin_context;
1735 
1736   struct save_pkt sp;
1737   bRC retval = bRC_Error;
1738   PySavePacket* pSavePkt;
1739 
1740   if (!PyArg_ParseTuple(args, "O:BareosCheckChanges", &pSavePkt)) {
1741     goto bail_out;
1742   }
1743   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1744 
1745 
1746   /*
1747    * CheckFile only has a need for a limited version of the PySavePacket so we
1748    * handle that here separately and don't call PySavePacketToNative().
1749    */
1750   sp.type = pSavePkt->type;
1751   if (pSavePkt->fname) {
1752     if (PyUnicode_Check(pSavePkt->fname)) {
1753       sp.fname = const_cast<char*>(PyUnicode_AsUTF8(pSavePkt->fname));
1754     } else {
1755       goto bail_out;
1756     }
1757   } else {
1758     goto bail_out;
1759   }
1760   if (pSavePkt->link) {
1761     if (PyUnicode_Check(pSavePkt->link)) {
1762       sp.link = const_cast<char*>(PyUnicode_AsUTF8(pSavePkt->link));
1763     } else {
1764       goto bail_out;
1765     }
1766   }
1767   sp.save_time = pSavePkt->save_time;
1768 
1769   retval = bareos_core_functions->checkChanges(plugin_ctx, &sp);
1770 
1771   /*
1772    * Copy back the two fields that are changed by checkChanges().
1773    */
1774   pSavePkt->delta_seq = sp.delta_seq;
1775   pSavePkt->accurate_found = sp.accurate_found;
1776 
1777 bail_out:
1778   return ConvertbRCRetvalToPythonRetval(retval);
1779 }
1780 
1781 /**
1782  * Callback function which is exposed as a part of the additional methods
1783  * which allow a Python plugin to issue a check if a file would be saved using
1784  * current Include/Exclude code.
1785  */
PyBareosAcceptFile(PyObject * self,PyObject * args)1786 static PyObject* PyBareosAcceptFile(PyObject* self, PyObject* args)
1787 {
1788   PluginContext* plugin_ctx = plugin_context;
1789   struct save_pkt sp;
1790   bRC retval = bRC_Error;
1791   PySavePacket* pSavePkt;
1792 
1793   if (!PyArg_ParseTuple(args, "O:BareosAcceptFile", &pSavePkt)) {
1794     goto bail_out;
1795   }
1796   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1797 
1798   /*
1799    * Acceptfile only needs fname and statp from PySavePacket so we handle
1800    * that here separately and don't call PySavePacketToNative().
1801    */
1802   if (pSavePkt->fname) {
1803     if (PyUnicode_Check(pSavePkt->fname)) {
1804       sp.fname = const_cast<char*>(PyUnicode_AsUTF8(pSavePkt->fname));
1805     } else {
1806       goto bail_out;
1807     }
1808   } else {
1809     goto bail_out;
1810   }
1811 
1812   if (pSavePkt->statp) {
1813     PyStatPacketToNative((PyStatPacket*)pSavePkt->statp, &sp.statp);
1814   } else {
1815     goto bail_out;
1816   }
1817 
1818   retval = bareos_core_functions->AcceptFile(plugin_ctx, &sp);
1819 
1820 bail_out:
1821   return ConvertbRCRetvalToPythonRetval(retval);
1822 }
1823 
1824 /**
1825  * Callback function which is exposed as a part of the additional methods
1826  * which allow a Python plugin to issue a Set bit in the Accurate Seen bitmap.
1827  */
PyBareosSetSeenBitmap(PyObject * self,PyObject * args)1828 static PyObject* PyBareosSetSeenBitmap(PyObject* self, PyObject* args)
1829 {
1830   bool all;
1831   PluginContext* plugin_ctx = plugin_context;
1832   char* fname = NULL;
1833   bRC retval = bRC_Error;
1834   PyObject* pyBool;
1835 
1836   if (!PyArg_ParseTuple(args, "O|s:BareosSetSeenBitmap", &pyBool, &fname)) {
1837     goto bail_out;
1838   }
1839   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1840 
1841   all = PyObject_IsTrue(pyBool);
1842   retval = bareos_core_functions->SetSeenBitmap(plugin_ctx, all, fname);
1843 
1844 bail_out:
1845   return ConvertbRCRetvalToPythonRetval(retval);
1846 }
1847 
1848 /**
1849  * Callback function which is exposed as a part of the additional methods
1850  * which allow a Python plugin to issue a Clear bit in the Accurate Seen
1851  * bitmap.
1852  */
PyBareosClearSeenBitmap(PyObject * self,PyObject * args)1853 static PyObject* PyBareosClearSeenBitmap(PyObject* self, PyObject* args)
1854 {
1855   bool all;
1856   PluginContext* plugin_ctx = plugin_context;
1857   char* fname = NULL;
1858   bRC retval = bRC_Error;
1859   PyObject* pyBool;
1860 
1861   if (!PyArg_ParseTuple(args, "O|s:BareosClearSeenBitmap", &pyBool, &fname)) {
1862     goto bail_out;
1863   }
1864   RETURN_RUNTIME_ERROR_IF_BFUNC_OR_BAREOS_PLUGIN_CTX_UNSET()
1865 
1866   all = PyObject_IsTrue(pyBool);
1867   retval = bareos_core_functions->ClearSeenBitmap(plugin_ctx, all, fname);
1868 
1869 bail_out:
1870   return ConvertbRCRetvalToPythonRetval(retval);
1871 }
1872 
1873 /**
1874  * Some helper functions.
1875  */
PyGetStringValue(PyObject * object)1876 static inline char* PyGetStringValue(PyObject* object)
1877 {
1878   if (!object || !PyUnicode_Check(object)) { return (char*)""; }
1879 
1880   return const_cast<char*>(PyUnicode_AsUTF8(object));
1881 }
1882 
PyGetByteArrayValue(PyObject * object)1883 static inline char* PyGetByteArrayValue(PyObject* object)
1884 {
1885   if (!object || !PyByteArray_Check(object)) { return (char*)""; }
1886 
1887   return PyByteArray_AsString(object);
1888 }
1889 
1890 /**
1891  * Python specific handlers for PyRestoreObject structure mapping.
1892  */
1893 
1894 /**
1895  * Representation.
1896  */
PyRestoreObject_repr(PyRestoreObject * self)1897 static PyObject* PyRestoreObject_repr(PyRestoreObject* self)
1898 {
1899   PyObject* s;
1900   PoolMem buf(PM_MESSAGE);
1901 
1902   Mmsg(buf,
1903        "RestoreObject(object_name=\"%s\", object=\"%s\", plugin_name=\"%s\", "
1904        "object_type=%d, object_len=%d, object_full_len=%d, "
1905        "object_index=%d, object_compression=%d, stream=%d, jobid=%u)",
1906        PyGetStringValue(self->object_name), PyGetByteArrayValue(self->object),
1907        self->plugin_name, self->object_type, self->object_len,
1908        self->object_full_len, self->object_index, self->object_compression,
1909        self->stream, self->JobId);
1910   s = PyUnicode_FromString(buf.c_str());
1911 
1912   return s;
1913 }
1914 
1915 /**
1916  * Initialization.
1917  */
PyRestoreObject_init(PyRestoreObject * self,PyObject * args,PyObject * kwds)1918 static int PyRestoreObject_init(PyRestoreObject* self,
1919                                 PyObject* args,
1920                                 PyObject* kwds)
1921 {
1922   static char* kwlist[] = {(char*)"object_name",
1923                            (char*)"object",
1924                            (char*)"plugin_name",
1925                            (char*)"object_type",
1926                            (char*)"object_len",
1927                            (char*)"object_full_len",
1928                            (char*)"object_index",
1929                            (char*)"object_compression",
1930                            (char*)"stream",
1931                            (char*)"jobid",
1932                            NULL};
1933 
1934   self->object_name = NULL;
1935   self->object = NULL;
1936   self->plugin_name = NULL;
1937   self->object_type = 0;
1938   self->object_len = 0;
1939   self->object_full_len = 0;
1940   self->object_index = 0;
1941   self->object_compression = 0;
1942   self->stream = 0;
1943   self->JobId = 0;
1944 
1945   if (!PyArg_ParseTupleAndKeywords(
1946           args, kwds, "|oosiiiiiiI", kwlist, &self->object_name, &self->object,
1947           &self->plugin_name, &self->object_type, &self->object_len,
1948           &self->object_full_len, &self->object_index,
1949           &self->object_compression, &self->stream, &self->JobId)) {
1950     return -1;
1951   }
1952 
1953   return 0;
1954 }
1955 
1956 /**
1957  * Destructor.
1958  */
PyRestoreObject_dealloc(PyRestoreObject * self)1959 static void PyRestoreObject_dealloc(PyRestoreObject* self)
1960 {
1961   if (self->object_name) { Py_XDECREF(self->object_name); }
1962   if (self->object) { Py_XDECREF(self->object); }
1963   PyObject_Del(self);
1964 }
1965 
1966 /**
1967  * Python specific handlers for PyStatPacket structure mapping.
1968  */
1969 
1970 /**
1971  * Representation.
1972  */
PyStatPacket_repr(PyStatPacket * self)1973 static PyObject* PyStatPacket_repr(PyStatPacket* self)
1974 {
1975   PyObject* s;
1976   PoolMem buf(PM_MESSAGE);
1977 
1978   Mmsg(buf,
1979        "StatPacket(dev=%ld, ino=%lld, mode=%04o, nlink=%d, "
1980        "uid=%ld, gid=%ld, rdev=%ld, size=%lld, "
1981        "atime=%ld, mtime=%ld, ctime=%ld, blksize=%ld, blocks=%lld)",
1982        self->dev, self->ino, (self->mode & ~S_IFMT), self->nlink, self->uid,
1983        self->gid, self->rdev, self->size, self->atime, self->mtime, self->ctime,
1984        self->blksize, self->blocks);
1985 
1986   s = PyUnicode_FromString(buf.c_str());
1987 
1988   return s;
1989 }
1990 
1991 /**
1992  * Initialization.
1993  */
PyStatPacket_init(PyStatPacket * self,PyObject * args,PyObject * kwds)1994 static int PyStatPacket_init(PyStatPacket* self, PyObject* args, PyObject* kwds)
1995 {
1996   time_t now;
1997   static char* kwlist[] = {(char*)"dev",    (char*)"ino",
1998                            (char*)"mode",   (char*)"nlink",
1999                            (char*)"uid",    (char*)"gid",
2000                            (char*)"rdev",   (char*)"size",
2001                            (char*)"atime",  (char*)"mtime",
2002                            (char*)"ctime",  (char*)"blksize",
2003                            (char*)"blocks", NULL};
2004 
2005   now = time(NULL);
2006   self->dev = 0;
2007   self->ino = 0;
2008   self->mode = 0700 | S_IFREG;
2009   self->nlink = 0;
2010   self->uid = 0;
2011   self->gid = 0;
2012   self->rdev = 0;
2013   self->size = -1;
2014   self->atime = now;
2015   self->mtime = now;
2016   self->ctime = now;
2017   self->blksize = 4096;
2018   self->blocks = 1;
2019 
2020   if (!PyArg_ParseTupleAndKeywords(
2021           args, kwds, "|IKHHIIILIIIIK", kwlist, &self->dev, &self->ino,
2022           &self->mode, &self->nlink, &self->uid, &self->gid, &self->rdev,
2023           &self->size, &self->atime, &self->mtime, &self->ctime, &self->blksize,
2024           &self->blocks)) {
2025     return -1;
2026   }
2027 
2028   return 0;
2029 }
2030 
2031 /**
2032  * Destructor.
2033  */
PyStatPacket_dealloc(PyStatPacket * self)2034 static void PyStatPacket_dealloc(PyStatPacket* self) { PyObject_Del(self); }
2035 
2036 /**
2037  * Python specific handlers for PySavePacket structure mapping.
2038  */
2039 
2040 /**
2041  * Representation.
2042  */
print_flags_bitmap(PyObject * bitmap)2043 static inline const char* print_flags_bitmap(PyObject* bitmap)
2044 {
2045   static char visual_bitmap[FO_MAX + 1];
2046   if (!bitmap) { return "<NULL>"; }
2047   if (PyByteArray_Check(bitmap)) {
2048     int cnt;
2049     char* flags;
2050 
2051     if (PyByteArray_Size(bitmap) == FOPTS_BYTES) {
2052       if ((flags = PyByteArray_AsString(bitmap))) {
2053         memset(visual_bitmap, 0, sizeof(visual_bitmap));
2054         for (cnt = 0; cnt <= FO_MAX; cnt++) {
2055           if (BitIsSet(cnt, flags)) {
2056             visual_bitmap[cnt] = '1';
2057           } else {
2058             visual_bitmap[cnt] = '0';
2059           }
2060         }
2061 
2062         return visual_bitmap;
2063       }
2064     }
2065   }
2066 
2067   return "Unknown";
2068 }
2069 
PySavePacket_repr(PySavePacket * self)2070 static PyObject* PySavePacket_repr(PySavePacket* self)
2071 {
2072   PyObject* s;
2073   PoolMem buf(PM_MESSAGE);
2074 
2075   Mmsg(buf,
2076        "SavePacket(fname=\"%s\", link=\"%s\", type=%ld, flags=%s, "
2077        "no_read=%d, portable=%d, accurate_found=%d, "
2078        "cmd=\"%s\", save_time=%ld, delta_seq=%ld, object_name=\"%s\", "
2079        "object=\"%s\", object_len=%ld, object_index=%ld)",
2080        PyGetStringValue(self->fname), PyGetStringValue(self->link), self->type,
2081        print_flags_bitmap(self->flags), self->no_read, self->portable,
2082        self->accurate_found, self->cmd, self->save_time, self->delta_seq,
2083        PyGetStringValue(self->object_name), PyGetByteArrayValue(self->object),
2084        self->object_len, self->object_index);
2085 
2086   s = PyUnicode_FromString(buf.c_str());
2087 
2088   return s;
2089 }
2090 
2091 /**
2092  * Initialization.
2093  */
PySavePacket_init(PySavePacket * self,PyObject * args,PyObject * kwds)2094 static int PySavePacket_init(PySavePacket* self, PyObject* args, PyObject* kwds)
2095 {
2096   static char* kwlist[]
2097       = {(char*)"fname",          (char*)"link",         (char*)"type",
2098          (char*)"flags",          (char*)"no_read",      (char*)"portable",
2099          (char*)"accurate_found", (char*)"cmd",          (char*)"save_time",
2100          (char*)"delta_seq",      (char*)"object_name",  (char*)"object",
2101          (char*)"object_len",     (char*)"object_index", NULL};
2102   self->fname = NULL;
2103   self->link = NULL;
2104   self->type = 0;
2105   self->flags = NULL;
2106   self->no_read = false;
2107   self->portable = false;
2108   self->accurate_found = false;
2109   self->cmd = NULL;
2110   self->save_time = 0;
2111   self->delta_seq = 0;
2112   self->object_name = NULL;
2113   self->object = NULL;
2114   self->object_len = 0;
2115   self->object_index = 0;
2116 
2117   if (!PyArg_ParseTupleAndKeywords(
2118           args, kwds, "|OOiOpppsiiOOii", kwlist, &self->fname, &self->link,
2119           &self->type, &self->flags, &self->no_read, &self->portable,
2120           &self->accurate_found, &self->cmd, &self->save_time, &self->delta_seq,
2121           &self->object_name, &self->object, &self->object_len,
2122           &self->object_index)) {
2123     return -1;
2124   }
2125   return 0;
2126 }
2127 
2128 /**
2129  * Destructor.
2130  */
PySavePacket_dealloc(PySavePacket * self)2131 static void PySavePacket_dealloc(PySavePacket* self)
2132 {
2133   if (self->fname) { Py_XDECREF(self->fname); }
2134   if (self->link) { Py_XDECREF(self->link); }
2135   if (self->flags) { Py_XDECREF(self->flags); }
2136   if (self->object_name) { Py_XDECREF(self->object_name); }
2137   if (self->object) { Py_XDECREF(self->object); }
2138   if (self->statp) { Py_XDECREF(self->statp); }
2139   PyObject_Del(self);
2140 }
2141 
2142 /**
2143  * Python specific handlers for PyRestorePacket structure mapping.
2144  */
2145 
2146 /**
2147  * Representation.
2148  */
PyRestorePacket_repr(PyRestorePacket * self)2149 static PyObject* PyRestorePacket_repr(PyRestorePacket* self)
2150 {
2151   PyObject *stat_repr, *s;
2152   PoolMem buf(PM_MESSAGE);
2153 
2154   stat_repr = PyObject_Repr(self->statp);
2155   Mmsg(buf,
2156        "RestorePacket(stream=%d, data_stream=%ld, type=%ld, file_index=%ld, "
2157        "linkFI=%ld, uid=%ld, statp=\"%s\", attrEx=\"%s\", ofname=\"%s\", "
2158        "olname=\"%s\", where=\"%s\", RegexWhere=\"%s\", replace=%d, "
2159        "create_status=%d)",
2160        self->stream, self->data_stream, self->type, self->file_index,
2161        self->LinkFI, self->uid, PyGetStringValue(stat_repr), self->attrEx,
2162        self->ofname, self->olname, self->where, self->RegexWhere, self->replace,
2163        self->create_status);
2164 
2165   s = PyUnicode_FromString(buf.c_str());
2166   Py_DECREF(stat_repr);
2167 
2168   return s;
2169 }
2170 
2171 /**
2172  * Initialization.
2173  */
PyRestorePacket_init(PyRestorePacket * self,PyObject * args,PyObject * kwds)2174 static int PyRestorePacket_init(PyRestorePacket* self,
2175                                 PyObject* args,
2176                                 PyObject* kwds)
2177 {
2178   static char* kwlist[]
2179       = {(char*)"stream",     (char*)"data_stream",   (char*)"type",
2180          (char*)"file_index", (char*)"linkFI",        (char*)"uid",
2181          (char*)"statp",      (char*)"attrEX",        (char*)"ofname",
2182          (char*)"olname",     (char*)"where",         (char*)"regexwhere",
2183          (char*)"replace",    (char*)"create_status", NULL};
2184 
2185   self->stream = 0;
2186   self->data_stream = 0;
2187   self->type = 0;
2188   self->file_index = 0;
2189   self->LinkFI = 0;
2190   self->uid = 0;
2191   self->statp = NULL;
2192   self->attrEx = NULL;
2193   self->ofname = NULL;
2194   self->olname = NULL;
2195   self->where = NULL;
2196   self->RegexWhere = NULL;
2197   self->replace = 0;
2198   self->create_status = 0;
2199 
2200   if (!PyArg_ParseTupleAndKeywords(
2201           args, kwds, "|iiiiiIosssssii", kwlist, &self->stream,
2202           &self->data_stream, &self->type, &self->file_index, &self->LinkFI,
2203           &self->uid, &self->statp, &self->attrEx, &self->ofname, &self->olname,
2204           &self->where, &self->RegexWhere, &self->replace,
2205           &self->create_status)) {
2206     return -1;
2207   }
2208 
2209   return 0;
2210 }
2211 
2212 /**
2213  * Destructor.
2214  */
PyRestorePacket_dealloc(PyRestorePacket * self)2215 static void PyRestorePacket_dealloc(PyRestorePacket* self)
2216 {
2217   PyObject_Del(self);
2218 }
2219 
2220 /**
2221  * Python specific handlers for PyIoPacket structure mapping.
2222  */
2223 
2224 /**
2225  * Representation.
2226  */
PyIoPacket_repr(PyIoPacket * self)2227 static PyObject* PyIoPacket_repr(PyIoPacket* self)
2228 {
2229   PyObject* s;
2230   PoolMem buf(PM_MESSAGE);
2231 
2232   Mmsg(buf,
2233        "IoPacket(func=%d, count=%ld, flags=%ld, mode=%04o, "
2234        "buf=\"%s\", fname=\"%s\", status=%ld, io_errno=%ld, lerror=%ld, "
2235        "whence=%ld, offset=%lld, win32=%d)",
2236        self->func, self->count, self->flags, (self->mode & ~S_IFMT),
2237        PyGetByteArrayValue(self->buf), self->fname, self->status,
2238        self->io_errno, self->lerror, self->whence, self->offset, self->win32);
2239   s = PyUnicode_FromString(buf.c_str());
2240 
2241   return s;
2242 }
2243 
2244 /**
2245  * Initialization.
2246  */
PyIoPacket_init(PyIoPacket * self,PyObject * args,PyObject * kwds)2247 static int PyIoPacket_init(PyIoPacket* self, PyObject* args, PyObject* kwds)
2248 {
2249   static char* kwlist[] = {(char*)"func",
2250                            (char*)"count",
2251                            (char*)"flags",
2252                            (char*)"mode",
2253                            (char*)"buf",
2254                            (char*)"fname",
2255                            (char*)"status",
2256                            (char*)"io_errno",
2257                            (char*)"lerror",
2258                            (char*)"whence",
2259                            (char*)"offset",
2260                            (char*)"win32",
2261                            NULL};
2262 
2263   self->func = 0;
2264   self->count = 0;
2265   self->flags = 0;
2266   self->mode = 0;
2267   self->buf = NULL;
2268   self->fname = NULL;
2269   self->status = 0;
2270   self->io_errno = 0;
2271   self->lerror = 0;
2272   self->whence = 0;
2273   self->offset = 0;
2274   self->win32 = false;
2275 
2276   if (!PyArg_ParseTupleAndKeywords(
2277           args, kwds, "|Hiiiosiiiilc", kwlist, &self->func, &self->count,
2278           &self->flags, &self->mode, &self->buf, &self->fname, &self->status,
2279           &self->io_errno, &self->lerror, &self->whence, &self->offset,
2280           &self->win32)) {
2281     return -1;
2282   }
2283 
2284   return 0;
2285 }
2286 
2287 /**
2288  * Destructor.
2289  */
PyIoPacket_dealloc(PyIoPacket * self)2290 static void PyIoPacket_dealloc(PyIoPacket* self)
2291 {
2292   if (self->buf) { Py_XDECREF(self->buf); }
2293   PyObject_Del(self);
2294 }
2295 
2296 /**
2297  * Python specific handlers for PyAclPacket structure mapping.
2298  */
2299 
2300 /**
2301  * Representation.
2302  */
PyAclPacket_repr(PyAclPacket * self)2303 static PyObject* PyAclPacket_repr(PyAclPacket* self)
2304 {
2305   PyObject* s;
2306   PoolMem buf(PM_MESSAGE);
2307 
2308   Mmsg(buf, "AclPacket(fname=\"%s\", content=\"%s\")", self->fname,
2309        PyGetByteArrayValue(self->content));
2310   s = PyUnicode_FromString(buf.c_str());
2311 
2312   return s;
2313 }
2314 
2315 /**
2316  * Initialization.
2317  */
PyAclPacket_init(PyAclPacket * self,PyObject * args,PyObject * kwds)2318 static int PyAclPacket_init(PyAclPacket* self, PyObject* args, PyObject* kwds)
2319 {
2320   static char* kwlist[] = {(char*)"fname", (char*)"content", NULL};
2321 
2322   self->fname = NULL;
2323   self->content = NULL;
2324 
2325   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|so", kwlist, &self->fname,
2326                                    &self->content)) {
2327     return -1;
2328   }
2329 
2330   return 0;
2331 }
2332 
2333 /**
2334  * Destructor.
2335  */
PyAclPacket_dealloc(PyAclPacket * self)2336 static void PyAclPacket_dealloc(PyAclPacket* self)
2337 {
2338   if (self->content) { Py_XDECREF(self->content); }
2339   PyObject_Del(self);
2340 }
2341 
2342 /**
2343  * Python specific handlers for PyIOPacket structure mapping.
2344  */
2345 
2346 /**
2347  * Representation.
2348  */
PyXattrPacket_repr(PyXattrPacket * self)2349 static PyObject* PyXattrPacket_repr(PyXattrPacket* self)
2350 {
2351   PyObject* s;
2352   PoolMem buf(PM_MESSAGE);
2353 
2354   Mmsg(buf, "XattrPacket(fname=\"%s\", name=\"%s\", value=\"%s\")", self->fname,
2355        PyGetByteArrayValue(self->name), PyGetByteArrayValue(self->value));
2356   s = PyUnicode_FromString(buf.c_str());
2357 
2358   return s;
2359 }
2360 
2361 /**
2362  * Initialization.
2363  */
PyXattrPacket_init(PyXattrPacket * self,PyObject * args,PyObject * kwds)2364 static int PyXattrPacket_init(PyXattrPacket* self,
2365                               PyObject* args,
2366                               PyObject* kwds)
2367 {
2368   static char* kwlist[] = {(char*)"fname", (char*)"name", (char*)"value", NULL};
2369 
2370   self->fname = NULL;
2371   self->name = NULL;
2372   self->value = NULL;
2373 
2374   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|soo", kwlist, &self->fname,
2375                                    &self->name, &self->value)) {
2376     return -1;
2377   }
2378 
2379   return 0;
2380 }
2381 
2382 /**
2383  * Destructor.
2384  */
PyXattrPacket_dealloc(PyXattrPacket * self)2385 static void PyXattrPacket_dealloc(PyXattrPacket* self)
2386 {
2387   if (self->value) { Py_XDECREF(self->value); }
2388   if (self->name) { Py_XDECREF(self->name); }
2389   PyObject_Del(self);
2390 }
2391 
2392 } /* namespace filedaemon */
2393