1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2007-2012 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2018 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation, which is
11    listed in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    Affero General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 */
23 /*
24  * Kern Sibbald, October 2007
25  */
26 /**
27  * @file
28  * Bareos pluginloader
29  */
30 #include "include/bareos.h"
31 #include "filed/filed.h"
32 #include "filed/filed_globals.h"
33 #include "filed/accurate.h"
34 #include "filed/heartbeat.h"
35 #include "filed/fileset.h"
36 #include "filed/heartbeat.h"
37 #include "findlib/attribs.h"
38 #include "findlib/find.h"
39 #include "findlib/find_one.h"
40 #include "findlib/hardlink.h"
41 
42 /**
43  * Function pointers to be set here (findlib)
44  */
45 extern int (*plugin_bopen)(BareosWinFilePacket *bfd, const char *fname, int flags, mode_t mode);
46 extern int (*plugin_bclose)(BareosWinFilePacket *bfd);
47 extern ssize_t (*plugin_bread)(BareosWinFilePacket *bfd, void *buf, size_t count);
48 extern ssize_t (*plugin_bwrite)(BareosWinFilePacket *bfd, void *buf, size_t count);
49 extern boffset_t (*plugin_blseek)(BareosWinFilePacket *bfd, boffset_t offset, int whence);
50 
51 extern char *exepath;
52 extern char *version;
53 extern char *dist_name;
54 
55 namespace filedaemon {
56 
57 const int debuglevel = 150;
58 #ifdef HAVE_WIN32
59 const char *plugin_type = "-fd.dll";
60 #else
61 const char *plugin_type = "-fd.so";
62 #endif
63 static alist *fd_plugin_list = NULL;
64 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
65 
66 extern int SaveFile(JobControlRecord *jcr, FindFilesPacket *ff_pkt, bool top_level);
67 
68 /**
69  * Forward referenced functions
70  */
71 static bRC bareosGetValue(bpContext *ctx, bVariable var, void *value);
72 static bRC bareosSetValue(bpContext *ctx, bVariable var, void *value);
73 static bRC bareosRegisterEvents(bpContext *ctx, int nr_events, ...);
74 static bRC bareosUnRegisterEvents(bpContext *ctx, int nr_events, ...);
75 static bRC bareosJobMsg(bpContext *ctx, const char *fname, int line,
76                         int type, utime_t mtime, const char *fmt, ...);
77 static bRC bareosDebugMsg(bpContext *ctx, const char *fname, int line,
78                           int level, const char *fmt, ...);
79 static void *bareosMalloc(bpContext *ctx, const char *fname, int line,
80                           size_t size);
81 static void bareosFree(bpContext *ctx, const char *file, int line, void *mem);
82 static bRC bareosAddExclude(bpContext *ctx, const char *file);
83 static bRC bareosAddInclude(bpContext *ctx, const char *file);
84 static bRC bareosAddOptions(bpContext *ctx, const char *opts);
85 static bRC bareosAddRegex(bpContext *ctx, const char *item, int type);
86 static bRC bareosAddWild(bpContext *ctx, const char *item, int type);
87 static bRC bareosNewOptions(bpContext *ctx);
88 static bRC bareosNewInclude(bpContext *ctx);
89 static bRC bareosNewPreInclude(bpContext *ctx);
90 static bool IsPluginCompatible(Plugin *plugin);
91 static bool GetPluginName(JobControlRecord *jcr, char *cmd, int *ret);
92 static bRC bareosCheckChanges(bpContext *ctx, struct save_pkt *sp);
93 static bRC bareosAcceptFile(bpContext *ctx, struct save_pkt *sp);
94 static bRC bareosSetSeenBitmap(bpContext *ctx, bool all, char *fname);
95 static bRC bareosClearSeenBitmap(bpContext *ctx, bool all, char *fname);
96 static bRC bareosGetInstanceCount(bpContext *ctx, int *ret);
97 
98 /**
99  * These will be plugged into the global pointer structure for the findlib.
100  */
101 static int MyPluginBopen(BareosWinFilePacket *bfd, const char *fname, int flags, mode_t mode);
102 static int MyPluginBclose(BareosWinFilePacket *bfd);
103 static ssize_t MyPluginBread(BareosWinFilePacket *bfd, void *buf, size_t count);
104 static ssize_t MyPluginBwrite(BareosWinFilePacket *bfd, void *buf, size_t count);
105 static boffset_t MyPluginBlseek(BareosWinFilePacket *bfd, boffset_t offset, int whence);
106 
107 /* Bareos info */
108 static bInfo binfo = {
109    sizeof(bInfo),
110    FD_PLUGIN_INTERFACE_VERSION
111 };
112 
113 /* Bareos entry points */
114 static bFuncs bfuncs = {
115    sizeof(bFuncs),
116    FD_PLUGIN_INTERFACE_VERSION,
117    bareosRegisterEvents,
118    bareosUnRegisterEvents,
119    bareosGetInstanceCount,
120    bareosGetValue,
121    bareosSetValue,
122    bareosJobMsg,
123    bareosDebugMsg,
124    bareosMalloc,
125    bareosFree,
126    bareosAddExclude,
127    bareosAddInclude,
128    bareosAddOptions,
129    bareosAddRegex,
130    bareosAddWild,
131    bareosNewOptions,
132    bareosNewInclude,
133    bareosNewPreInclude,
134    bareosCheckChanges,
135    bareosAcceptFile,
136    bareosSetSeenBitmap,
137    bareosClearSeenBitmap
138 };
139 
140 /**
141  * Bareos private context
142  */
143 struct b_plugin_ctx {
144    JobControlRecord *jcr;                                       /* jcr for plugin */
145    bRC ret;                                        /* last return code */
146    bool disabled;                                  /* set if plugin disabled */
147    bool restoreFileStarted;
148    bool createFileCalled;
149    char events[NbytesForBits(FD_NR_EVENTS + 1)]; /* enabled events bitmask */
150    findIncludeExcludeItem *exclude;                            /* pointer to exclude files */
151    findIncludeExcludeItem *include;                            /* pointer to include/exclude files */
152    Plugin *plugin;                                 /* pointer to plugin of which this is an instance off */
153 };
154 
IsEventEnabled(bpContext * ctx,bEventType eventType)155 static inline bool IsEventEnabled(bpContext *ctx, bEventType eventType)
156 {
157    b_plugin_ctx *b_ctx;
158 
159    if (!ctx) {
160       return false;
161    }
162 
163    b_ctx = (b_plugin_ctx *)ctx->bContext;
164    if (!b_ctx) {
165       return false;
166    }
167 
168    return BitIsSet(eventType, b_ctx->events);
169 }
170 
IsPluginDisabled(bpContext * ctx)171 static inline bool IsPluginDisabled(bpContext *ctx)
172 {
173    b_plugin_ctx *b_ctx;
174 
175    if (!ctx) {
176       return true;
177    }
178 
179    b_ctx = (b_plugin_ctx *)ctx->bContext;
180    if (!b_ctx) {
181       return true;
182    }
183 
184    return b_ctx->disabled;
185 }
186 
IsCtxGood(bpContext * ctx,JobControlRecord * & jcr,b_plugin_ctx * & bctx)187 static bool IsCtxGood(bpContext *ctx, JobControlRecord *&jcr, b_plugin_ctx *&bctx)
188 {
189    if (!ctx) {
190       return false;
191    }
192 
193    bctx = (b_plugin_ctx *)ctx->bContext;
194    if (!bctx) {
195       return false;
196    }
197 
198    jcr = bctx->jcr;
199    if (!jcr) {
200       return false;
201    }
202 
203    return true;
204 }
205 
206 /**
207  * Test if event is for this plugin
208  */
for_thIsPlugin(Plugin * plugin,char * name,int len)209 static bool for_thIsPlugin(Plugin *plugin, char *name, int len)
210 {
211    Dmsg4(debuglevel, "name=%s len=%d plugin=%s plen=%d\n", name, len, plugin->file, plugin->file_len);
212    if (!name) {   /* if no plugin name, all plugins get it */
213       return true;
214    }
215 
216    /*
217     * Return global VSS job metadata to all plugins
218     */
219    if (bstrcmp("job", name)) {  /* old V4.0 name for VSS job metadata */
220       return true;
221    }
222 
223    if (bstrcmp("*all*", name)) { /* new v6.0 name for VSS job metadata */
224       return true;
225    }
226 
227    /*
228     * Check if this is the correct plugin
229     */
230    if (len == plugin->file_len && bstrncmp(plugin->file, name, len)) {
231       return true;
232    }
233 
234    return false;
235 }
236 
237 /**
238  * Raise a certain plugin event.
239  */
trigger_plugin_event(JobControlRecord * jcr,bEventType eventType,bEvent * event,bpContext * ctx,void * value,alist * plugin_ctx_list,int * index,bRC * rc)240 static inline bool trigger_plugin_event(JobControlRecord *jcr, bEventType eventType,
241                                         bEvent *event, bpContext *ctx,
242                                         void *value, alist *plugin_ctx_list,
243                                         int *index, bRC *rc)
244 
245 {
246    bool stop = false;
247 
248    if (!IsEventEnabled(ctx, eventType)) {
249       Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
250       if (rc) {
251          *rc = bRC_OK;
252       }
253       goto bail_out;
254    }
255 
256    if (IsPluginDisabled(ctx)) {
257       if (rc) {
258          *rc = bRC_OK;
259       }
260       goto bail_out;
261    }
262 
263    if (eventType == bEventEndRestoreJob) {
264       b_plugin_ctx *b_ctx = (b_plugin_ctx *)ctx->bContext;
265 
266       Dmsg0(50, "eventType == bEventEndRestoreJob\n");
267       if (b_ctx && b_ctx->restoreFileStarted) {
268          PlugFunc(ctx->plugin)->endRestoreFile(ctx);
269       }
270 
271       if (b_ctx) {
272          b_ctx->restoreFileStarted = false;
273          b_ctx->createFileCalled = false;
274       }
275    }
276 
277    /*
278     * See if we should care about the return code.
279     */
280    if (rc) {
281       *rc = PlugFunc(ctx->plugin)->handlePluginEvent(ctx, event, value);
282       switch (*rc) {
283       case bRC_OK:
284          break;
285       case bRC_Stop:
286       case bRC_Error:
287          stop = true;
288          break;
289       case bRC_More:
290          break;
291       case bRC_Term:
292          /*
293           * Request to unload this plugin.
294           * As we remove the plugin from the list of plugins we decrement
295           * the running index value so the next plugin gets triggered as
296           * that moved back a position in the alist.
297           */
298          if (index) {
299             UnloadPlugin(plugin_ctx_list, ctx->plugin, *index);
300             *index = ((*index) - 1);
301          }
302          break;
303       case bRC_Seen:
304          break;
305       case bRC_Core:
306          break;
307       case bRC_Skip:
308          stop = true;
309          break;
310       case bRC_Cancel:
311          break;
312       default:
313          break;
314       }
315    } else {
316       PlugFunc(ctx->plugin)->handlePluginEvent(ctx, event, value);
317    }
318 
319 bail_out:
320    return stop;
321 }
322 
323 /**
324  * Create a plugin event When receiving bEventCancelCommand, this function is called by another thread.
325  */
GeneratePluginEvent(JobControlRecord * jcr,bEventType eventType,void * value,bool reverse)326 bRC GeneratePluginEvent(JobControlRecord *jcr, bEventType eventType, void *value, bool reverse)
327 {
328    bEvent event;
329    char *name = NULL;
330    int i;
331    int len = 0;
332    bool call_if_canceled = false;
333    restore_object_pkt *rop;
334    bpContext *ctx = nullptr;
335    alist *plugin_ctx_list;
336    bRC rc = bRC_OK;
337 
338    if (!fd_plugin_list) {
339       Dmsg0(debuglevel, "No bplugin_list: GeneratePluginEvent ignored.\n");
340       goto bail_out;
341    }
342 
343    if (!jcr) {
344       Dmsg0(debuglevel, "No jcr: GeneratePluginEvent ignored.\n");
345       goto bail_out;
346    }
347 
348    if (!jcr->plugin_ctx_list) {
349       Dmsg0(debuglevel, "No plugin_ctx_list: GeneratePluginEvent ignored.\n");
350       goto bail_out;
351    }
352 
353    plugin_ctx_list = jcr->plugin_ctx_list;
354 
355    /*
356     * Some events are sent to only a particular plugin or must be called even if the job is canceled.
357     */
358    switch(eventType) {
359    case bEventPluginCommand:
360    case bEventOptionPlugin:
361       name = (char *)value;
362       if (!GetPluginName(jcr, name, &len)) {
363          goto bail_out;
364       }
365       break;
366    case bEventRestoreObject:
367       /*
368        * After all RestoreObject, we have it one more time with value = NULL
369        */
370       if (value) {
371          /*
372           * Some RestoreObjects may not have a plugin name
373           */
374          rop = (restore_object_pkt *)value;
375          if (*rop->plugin_name) {
376             name = rop->plugin_name;
377             if (!GetPluginName(jcr, name, &len)) {
378                goto bail_out;
379             }
380          }
381       }
382       break;
383    case bEventEndBackupJob:
384    case bEventEndVerifyJob:
385       call_if_canceled = true; /* plugin *must* see this call */
386       break;
387    case bEventStartRestoreJob:
388       foreach_alist(ctx, plugin_ctx_list) {
389          ((b_plugin_ctx *)ctx->bContext)->restoreFileStarted = false;
390          ((b_plugin_ctx *)ctx->bContext)->createFileCalled = false;
391       }
392       break;
393    case bEventEndRestoreJob:
394       call_if_canceled = true; /* plugin *must* see this call */
395       break;
396    default:
397       break;
398    }
399 
400    /*
401     * If call_if_canceled is set, we call the plugin anyway
402     */
403    if (!call_if_canceled && jcr->IsJobCanceled()) {
404       goto bail_out;
405    }
406 
407    event.eventType = eventType;
408 
409    Dmsg2(debuglevel, "plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
410 
411    /*
412     * Pass event to every plugin that has requested this event type (except if name is set).
413     * If name is set, we pass it only to the plugin with that name.
414     *
415     * See if we need to trigger the loaded plugins in reverse order.
416     */
417    if (reverse) {
418       foreach_alist_rindex(i, ctx, plugin_ctx_list) {
419          if (!for_thIsPlugin(ctx->plugin, name, len)) {
420             Dmsg2(debuglevel, "Not for this plugin name=%s NULL=%d\n", name, (name == NULL) ? 1 : 0);
421             continue;
422          }
423 
424          if (trigger_plugin_event(jcr, eventType, &event, ctx, value, plugin_ctx_list, &i, &rc)) {
425             break;
426          }
427       }
428    } else {
429       foreach_alist_index(i, ctx, plugin_ctx_list) {
430          if (!for_thIsPlugin(ctx->plugin, name, len)) {
431             Dmsg2(debuglevel, "Not for this plugin name=%s NULL=%d\n", name, (name == NULL) ? 1 : 0);
432             continue;
433          }
434 
435          if (trigger_plugin_event(jcr, eventType, &event, ctx, value, plugin_ctx_list, &i, &rc)) {
436             break;
437          }
438       }
439    }
440 
441    if (jcr->IsJobCanceled()) {
442       Dmsg0(debuglevel, "Cancel return from GeneratePluginEvent\n");
443       rc = bRC_Cancel;
444    }
445 
446 bail_out:
447    return rc;
448 }
449 
450 /**
451  * Check if file was seen for accurate
452  */
PluginCheckFile(JobControlRecord * jcr,char * fname)453 bool PluginCheckFile(JobControlRecord *jcr, char *fname)
454 {
455    bpContext *ctx = nullptr;
456    alist *plugin_ctx_list;
457    int retval = bRC_OK;
458 
459    if (!fd_plugin_list || !jcr || !jcr->plugin_ctx_list || jcr->IsJobCanceled()) {
460       return false;                      /* Return if no plugins loaded */
461    }
462 
463    plugin_ctx_list = jcr->plugin_ctx_list;
464    Dmsg2(debuglevel, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
465 
466    /*
467     * Pass event to every plugin
468     */
469    foreach_alist(ctx, plugin_ctx_list) {
470       if (IsPluginDisabled(ctx)) {
471          continue;
472       }
473 
474       jcr->plugin_ctx = ctx;
475       if (PlugFunc(ctx->plugin)->checkFile == NULL) {
476          continue;
477       }
478 
479       retval = PlugFunc(ctx->plugin)->checkFile(ctx, fname);
480       if (retval == bRC_Seen) {
481          break;
482       }
483    }
484 
485    return retval == bRC_Seen;
486 }
487 
488 /**
489  * Get the first part of the the plugin command
490  *  systemstate:/@SYSTEMSTATE/
491  * => ret = 11
492  * => can use for_thIsPlugin(plug, cmd, ret);
493  *
494  * The plugin command can contain only the plugin name
495  *  Plugin = alldrives
496  * => ret = 9
497  */
GetPluginName(JobControlRecord * jcr,char * cmd,int * ret)498 static bool GetPluginName(JobControlRecord *jcr, char *cmd, int *ret)
499 {
500    char *p;
501    int len;
502 
503    if (!cmd || (*cmd == '\0')) {
504       return false;
505    }
506 
507    /*
508     * Handle plugin command here backup
509     */
510    Dmsg1(debuglevel, "plugin cmd=%s\n", cmd);
511    if ((p = strchr(cmd, ':')) == NULL) {
512       if (strchr(cmd, ' ') == NULL) { /* we have just the plugin name */
513          len = strlen(cmd);
514       } else {
515          Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
516          return false;
517       }
518    } else {                     /* plugin:argument */
519       len = p - cmd;
520       if (len <= 0) {
521          return false;
522       }
523    }
524    *ret = len;
525 
526    return true;
527 }
528 
PluginUpdateFfPkt(FindFilesPacket * ff_pkt,struct save_pkt * sp)529 void PluginUpdateFfPkt(FindFilesPacket *ff_pkt, struct save_pkt *sp)
530 {
531    ff_pkt->no_read = sp->no_read;
532    ff_pkt->delta_seq = sp->delta_seq;
533 
534    if (BitIsSet(FO_DELTA, sp->flags)) {
535       SetBit(FO_DELTA, ff_pkt->flags);
536       ff_pkt->delta_seq++;            /* make new delta sequence number */
537    } else {
538       ClearBit(FO_DELTA, ff_pkt->flags);
539       ff_pkt->delta_seq = 0;          /* clean delta sequence number */
540    }
541 
542    if (BitIsSet(FO_OFFSETS, sp->flags)) {
543       SetBit(FO_OFFSETS, ff_pkt->flags);
544    } else {
545       ClearBit(FO_OFFSETS, ff_pkt->flags);
546    }
547 
548    /*
549     * Sparse code doesn't work with plugins
550     * that use FIFO or STDOUT/IN to communicate
551     */
552    if (BitIsSet(FO_SPARSE, sp->flags)) {
553       SetBit(FO_SPARSE, ff_pkt->flags);
554    } else {
555       ClearBit(FO_SPARSE, ff_pkt->flags);
556    }
557 
558    if (BitIsSet(FO_PORTABLE_DATA, sp->flags)) {
559       SetBit(FO_PORTABLE_DATA, ff_pkt->flags);
560    } else {
561       ClearBit(FO_PORTABLE_DATA, ff_pkt->flags);
562    }
563 
564    SetBit(FO_PLUGIN, ff_pkt->flags); /* data from plugin */
565 }
566 
567 /**
568  * Ask to a Option Plugin what to do with the current file
569  */
PluginOptionHandleFile(JobControlRecord * jcr,FindFilesPacket * ff_pkt,struct save_pkt * sp)570 bRC PluginOptionHandleFile(JobControlRecord *jcr, FindFilesPacket *ff_pkt, struct save_pkt *sp)
571 {
572    int len;
573    char *cmd;
574    bRC retval = bRC_Core;
575    bEvent event;
576    bEventType eventType;
577    bpContext *ctx = nullptr;
578    alist *plugin_ctx_list;
579 
580    cmd = ff_pkt->plugin;
581    eventType = bEventHandleBackupFile;
582    event.eventType = eventType;
583 
584    memset(sp, 0, sizeof(struct save_pkt));
585    sp->pkt_size = sp->pkt_end = sizeof(struct save_pkt);
586    sp->portable = true;
587    CopyBits(FO_MAX, ff_pkt->flags, sp->flags);
588    sp->cmd = cmd;
589    sp->link = ff_pkt->link;
590    sp->statp = ff_pkt->statp;
591    sp->type = ff_pkt->type;
592    sp->fname = ff_pkt->fname;
593    sp->delta_seq = ff_pkt->delta_seq;
594    sp->accurate_found = ff_pkt->accurate_found;
595 
596    plugin_ctx_list = jcr->plugin_ctx_list;
597    if (!fd_plugin_list || !plugin_ctx_list || jcr->IsJobCanceled()) {
598       Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd);
599       goto bail_out;         /* Return if no plugins loaded */
600    }
601 
602    if (!GetPluginName(jcr, cmd, &len)) {
603       goto bail_out;
604    }
605 
606    /*
607     * Note, we stop the loop on the first plugin that matches the name
608     */
609    foreach_alist(ctx, plugin_ctx_list) {
610       Dmsg4(debuglevel, "plugin=%s plen=%d cmd=%s len=%d\n", ctx->plugin->file, ctx->plugin->file_len, cmd, len);
611       if (!for_thIsPlugin(ctx->plugin, cmd, len)) {
612          continue;
613       }
614 
615       if (!IsEventEnabled(ctx, eventType)) {
616          Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
617          continue;
618       }
619 
620       if (IsPluginDisabled(ctx)) {
621          goto bail_out;
622       }
623 
624       jcr->plugin_ctx = ctx;
625       retval = PlugFunc(ctx->plugin)->handlePluginEvent(ctx, &event, sp);
626 
627       goto bail_out;
628    } /* end foreach loop */
629 
630 bail_out:
631    return retval;
632 }
633 
634 /**
635  * Sequence of calls for a backup:
636  * 1. PluginSave() here is called with ff_pkt
637  * 2. we find the plugin requested on the command string
638  * 3. we generate a bEventBackupCommand event to the specified plugin
639  *    and pass it the command string.
640  * 4. we make a startPluginBackup call to the plugin, which gives
641  *    us the data we need in save_pkt
642  * 5. we call Bareos's SaveFile() subroutine to save the specified
643  *    file.  The plugin will be called at pluginIO() to supply the
644  *    file data.
645  *
646  * Sequence of calls for restore:
647  *   See subroutine PluginNameStream() below.
648  */
PluginSave(JobControlRecord * jcr,FindFilesPacket * ff_pkt,bool top_level)649 int PluginSave(JobControlRecord *jcr, FindFilesPacket *ff_pkt, bool top_level)
650 {
651    int len;
652    bRC retval;
653    char *cmd;
654    bEvent event;
655    bpContext *ctx = nullptr;
656    struct save_pkt sp;
657    bEventType eventType;
658    PoolMem fname(PM_FNAME);
659    PoolMem link(PM_FNAME);
660    alist *plugin_ctx_list;
661    char flags[FOPTS_BYTES];
662 
663    cmd = ff_pkt->top_fname;
664    plugin_ctx_list = jcr->plugin_ctx_list;
665    if (!fd_plugin_list || !plugin_ctx_list || jcr->IsJobCanceled()) {
666       Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd);
667       return 1;                            /* Return if no plugins loaded */
668    }
669 
670    jcr->cmd_plugin = true;
671    eventType = bEventBackupCommand;
672    event.eventType = eventType;
673 
674    if (!GetPluginName(jcr, cmd, &len)) {
675       goto bail_out;
676    }
677 
678    /*
679     * Note, we stop the loop on the first plugin that matches the name
680     */
681    foreach_alist(ctx, plugin_ctx_list) {
682       Dmsg4(debuglevel, "plugin=%s plen=%d cmd=%s len=%d\n", ctx->plugin->file, ctx->plugin->file_len, cmd, len);
683       if (!for_thIsPlugin(ctx->plugin, cmd, len)) {
684          continue;
685       }
686 
687       /*
688        * We put the current plugin pointer, and the plugin context into the jcr, because during SaveFile(),
689        * the plugin will be called many times and these values are needed.
690        */
691       if (!IsEventEnabled(ctx, eventType)) {
692          Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
693          continue;
694       }
695 
696       if (IsPluginDisabled(ctx)) {
697          goto bail_out;
698       }
699 
700       jcr->plugin_ctx = ctx;
701 
702       /*
703        * Send the backup command to the right plugin
704        */
705       Dmsg1(debuglevel, "Command plugin = %s\n", cmd);
706       if (PlugFunc(ctx->plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) {
707          goto bail_out;
708       }
709 
710       /*
711        * Loop getting filenames to backup then saving them
712        */
713       while (!jcr->IsJobCanceled()) {
714          memset(&sp, 0, sizeof(sp));
715          sp.pkt_size = sizeof(sp);
716          sp.pkt_end = sizeof(sp);
717          sp.portable = true;
718          sp.no_read = false;
719          CopyBits(FO_MAX, ff_pkt->flags, sp.flags);
720          sp.cmd = cmd;
721          Dmsg3(debuglevel, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks, &sp);
722 
723          /*
724           * Get the file save parameters. I.e. the stat pkt ...
725           */
726          if (PlugFunc(ctx->plugin)->startBackupFile(ctx, &sp) != bRC_OK) {
727             goto bail_out;
728          }
729 
730          if (sp.type == 0) {
731             Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no type in startBackupFile packet.\n"), cmd);
732             goto bail_out;
733          }
734 
735          jcr->plugin_sp = &sp;
736          ff_pkt = jcr->ff;
737 
738          /*
739           * Save original flags.
740           */
741          CopyBits(FO_MAX, ff_pkt->flags, flags);
742 
743          /*
744           * Copy fname and link because SaveFile() zaps them.  This avoids zaping the plugin's strings.
745           */
746          ff_pkt->type = sp.type;
747          if (IS_FT_OBJECT(sp.type)) {
748             if (!sp.object_name) {
749                Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no object_name in startBackupFile packet.\n"), cmd);
750                goto bail_out;
751             }
752             ff_pkt->fname = cmd;                 /* full plugin string */
753             ff_pkt->object_name = sp.object_name;
754             ff_pkt->object_index = sp.index;     /* restore object index */
755             ff_pkt->object_compression = 0;      /* no compression for now */
756             ff_pkt->object = sp.object;
757             ff_pkt->object_len = sp.object_len;
758          } else {
759             if (!sp.fname) {
760                Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no fname in startBackupFile packet.\n"), cmd);
761                goto bail_out;
762             }
763 
764             PmStrcpy(fname, sp.fname);
765             PmStrcpy(link, sp.link);
766 
767             ff_pkt->fname = fname.c_str();
768             ff_pkt->link = link.c_str();
769 
770             PluginUpdateFfPkt(ff_pkt, &sp);
771          }
772 
773          memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
774          Dmsg2(debuglevel, "startBackup returned type=%d, fname=%s\n", sp.type, sp.fname);
775          if (sp.object) {
776             Dmsg2(debuglevel, "index=%d object=%s\n", sp.index, sp.object);
777          }
778 
779          /*
780           * Handle hard linked files
781           *
782           * Maintain a list of hard linked files already backed up. This allows us to ensure
783           * that the data of each file gets backed up only once.
784           */
785          ff_pkt->LinkFI = 0;
786          if (!BitIsSet(FO_NO_HARDLINK, ff_pkt->flags) && ff_pkt->statp.st_nlink > 1) {
787             CurLink *hl;
788 
789             switch (ff_pkt->statp.st_mode & S_IFMT) {
790             case S_IFREG:
791             case S_IFCHR:
792             case S_IFBLK:
793             case S_IFIFO:
794 #ifdef S_IFSOCK
795             case S_IFSOCK:
796 #endif
797                hl = lookup_hardlink(jcr, ff_pkt, ff_pkt->statp.st_ino, ff_pkt->statp.st_dev);
798                if (hl) {
799                   /*
800                    * If we have already backed up the hard linked file don't do it again
801                    */
802                   if (bstrcmp(hl->name, sp.fname)) {
803                      Dmsg2(400, "== Name identical skip FI=%d file=%s\n", hl->FileIndex, fname.c_str());
804                      ff_pkt->no_read = true;
805                   } else {
806                      ff_pkt->link = hl->name;
807                      ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
808                      ff_pkt->LinkFI = hl->FileIndex;
809                      ff_pkt->linked = NULL;
810                      ff_pkt->digest = hl->digest;
811                      ff_pkt->digest_stream = hl->digest_stream;
812                      ff_pkt->digest_len = hl->digest_len;
813 
814                      Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n", ff_pkt->FileIndex, hl->FileIndex, hl->name);
815 
816                      ff_pkt->no_read = true;
817                   }
818                } else {
819                   /*
820                    * File not previously dumped. Chain it into our list.
821                    */
822                   hl = new_hardlink(jcr, ff_pkt, sp.fname, ff_pkt->statp.st_ino, ff_pkt->statp.st_dev);
823                   ff_pkt->linked = hl;              /* Mark saved link */
824                   Dmsg2(400, "Added to hash FI=%d file=%s\n", ff_pkt->FileIndex, hl->name);
825                }
826                break;
827             default:
828                ff_pkt->linked = NULL;
829                break;
830             }
831          } else {
832             ff_pkt->linked = NULL;
833          }
834 
835          /*
836           * Call Bareos core code to backup the plugin's file
837           */
838          SaveFile(jcr, ff_pkt, true);
839 
840          /*
841           * Restore original flags.
842           */
843          CopyBits(FO_MAX, flags, ff_pkt->flags);
844 
845          retval = PlugFunc(ctx->plugin)->endBackupFile(ctx);
846          if (retval == bRC_More || retval == bRC_OK) {
847             AccurateMarkFileAsSeen(jcr, fname.c_str());
848          }
849 
850          if (retval == bRC_More) {
851             continue;
852          }
853 
854          goto bail_out;
855       } /* end while loop */
856 
857       goto bail_out;
858    } /* end loop over all plugins */
859    Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not found.\n", cmd);
860 
861 bail_out:
862    jcr->cmd_plugin = false;
863 
864    return 1;
865 }
866 
867 /**
868  * Sequence of calls for a estimate:
869  * 1. PluginEstimate() here is called with ff_pkt
870  * 2. we find the plugin requested on the command string
871  * 3. we generate a bEventEstimateCommand event to the specified plugin
872  *    and pass it the command string.
873  * 4. we make a startPluginBackup call to the plugin, which gives
874  *    us the data we need in save_pkt
875  *
876  */
PluginEstimate(JobControlRecord * jcr,FindFilesPacket * ff_pkt,bool top_level)877 int PluginEstimate(JobControlRecord *jcr, FindFilesPacket *ff_pkt, bool top_level)
878 {
879    int len;
880    char *cmd = ff_pkt->top_fname;
881    struct save_pkt sp;
882    bEvent event;
883    bEventType eventType;
884    PoolMem fname(PM_FNAME);
885    PoolMem link(PM_FNAME);
886    bpContext *ctx = nullptr;
887    alist *plugin_ctx_list;
888    Attributes attr;
889 
890    plugin_ctx_list = jcr->plugin_ctx_list;
891    if (!fd_plugin_list || !plugin_ctx_list) {
892       Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd);
893       return 1;                            /* Return if no plugins loaded */
894    }
895 
896    jcr->cmd_plugin = true;
897    eventType = bEventEstimateCommand;
898    event.eventType = eventType;
899 
900    if (!GetPluginName(jcr, cmd, &len)) {
901       goto bail_out;
902    }
903 
904    /*
905     * Note, we stop the loop on the first plugin that matches the name
906     */
907    foreach_alist(ctx, plugin_ctx_list) {
908       Dmsg4(debuglevel, "plugin=%s plen=%d cmd=%s len=%d\n", ctx->plugin->file, ctx->plugin->file_len, cmd, len);
909       if (!for_thIsPlugin(ctx->plugin, cmd, len)) {
910          continue;
911       }
912 
913       /*
914        * We put the current plugin pointer, and the plugin context into the jcr, because during SaveFile(),
915        * the plugin will be called many times and these values are needed.
916        */
917       if (!IsEventEnabled(ctx, eventType)) {
918          Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
919          continue;
920       }
921 
922       if (IsPluginDisabled(ctx)) {
923          goto bail_out;
924       }
925 
926       jcr->plugin_ctx = ctx;
927 
928       /*
929        * Send the backup command to the right plugin
930        */
931       Dmsg1(debuglevel, "Command plugin = %s\n", cmd);
932       if (PlugFunc(ctx->plugin)->handlePluginEvent(ctx, &event, cmd) != bRC_OK) {
933          goto bail_out;
934       }
935 
936       /*
937        * Loop getting filenames to backup then saving them
938        */
939       while (!jcr->IsJobCanceled()) {
940          memset(&sp, 0, sizeof(sp));
941          sp.pkt_size = sizeof(sp);
942          sp.pkt_end = sizeof(sp);
943          sp.portable = true;
944          CopyBits(FO_MAX, ff_pkt->flags, sp.flags);
945          sp.cmd = cmd;
946          Dmsg3(debuglevel, "startBackup st_size=%p st_blocks=%p sp=%p\n",
947                &sp.statp.st_size, &sp.statp.st_blocks, &sp);
948 
949          /*
950           * Get the file save parameters. I.e. the stat pkt ...
951           */
952          if (PlugFunc(ctx->plugin)->startBackupFile(ctx, &sp) != bRC_OK) {
953             goto bail_out;
954          }
955 
956          if (sp.type == 0) {
957             Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no type in startBackupFile packet.\n"), cmd);
958             goto bail_out;
959          }
960 
961          if (!IS_FT_OBJECT(sp.type)) {
962             if (!sp.fname) {
963                Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no fname in startBackupFile packet.\n"),
964                   cmd);
965                goto bail_out;
966             }
967 
968             /*
969              * Count only files backed up
970              */
971             switch (sp.type) {
972             case FT_REGE:
973             case FT_REG:
974             case FT_LNK:
975             case FT_DIREND:
976             case FT_SPEC:
977             case FT_RAW:
978             case FT_FIFO:
979             case FT_LNKSAVED:
980                jcr->JobFiles++;        /* increment number of files backed up */
981                break;
982             default:
983                break;
984             }
985             jcr->num_files_examined++;
986 
987             if (sp.type != FT_LNKSAVED && S_ISREG(sp.statp.st_mode)) {
988                if (sp.statp.st_size > 0) {
989                   jcr->JobBytes += sp.statp.st_size;
990                }
991             }
992 
993             if (jcr->listing) {
994                memcpy(&attr.statp, &sp.statp, sizeof(struct stat));
995                attr.type = sp.type;
996                attr.ofname = (POOLMEM *)sp.fname;
997                attr.olname = (POOLMEM *)sp.link;
998                PrintLsOutput(jcr, &attr);
999             }
1000          }
1001 
1002          Dmsg2(debuglevel, "startBackup returned type=%d, fname=%s\n", sp.type, sp.fname);
1003          if (sp.object) {
1004             Dmsg2(debuglevel, "index=%d object=%s\n", sp.index, sp.object);
1005          }
1006 
1007          bRC retval = PlugFunc(ctx->plugin)->endBackupFile(ctx);
1008          if (retval == bRC_More || retval == bRC_OK) {
1009             AccurateMarkFileAsSeen(jcr, sp.fname);
1010          }
1011 
1012          if (retval == bRC_More) {
1013             continue;
1014          }
1015 
1016          goto bail_out;
1017       } /* end while loop */
1018 
1019       goto bail_out;
1020    } /* end loop over all plugins */
1021    Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not found.\n", cmd);
1022 
1023 bail_out:
1024    jcr->cmd_plugin = false;
1025 
1026    return 1;
1027 }
1028 
1029 /**
1030  * Send plugin name start/end record to SD
1031  */
SendPluginName(JobControlRecord * jcr,BareosSocket * sd,bool start)1032 bool SendPluginName(JobControlRecord *jcr, BareosSocket *sd, bool start)
1033 {
1034    int status;
1035    int index = jcr->JobFiles;
1036    struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
1037 
1038    if (!sp) {
1039       Jmsg0(jcr, M_FATAL, 0, _("Plugin save packet not found.\n"));
1040       return false;
1041    }
1042    if (jcr->IsJobCanceled()) {
1043       return false;
1044    }
1045 
1046    if (start) {
1047       index++;                  /* JobFiles not incremented yet */
1048    }
1049    Dmsg1(debuglevel, "SendPluginName=%s\n", sp->cmd);
1050 
1051    /*
1052     * Send stream header
1053     */
1054    if (!sd->fsend("%ld %d 0", index, STREAM_PLUGIN_NAME)) {
1055      Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
1056      return false;
1057    }
1058    Dmsg1(debuglevel, "send plugin name hdr: %s\n", sd->msg);
1059 
1060    if (start) {
1061       /*
1062        * Send data -- not much
1063        */
1064       status = sd->fsend("%ld 1 %d %s%c", index, sp->portable, sp->cmd, 0);
1065    } else {
1066       /*
1067        * Send end of data
1068        */
1069       status = sd->fsend("%ld 0", jcr->JobFiles);
1070    }
1071    if (!status) {
1072       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
1073          return false;
1074    }
1075    Dmsg1(debuglevel, "send plugin start/end: %s\n", sd->msg);
1076    sd->signal(BNET_EOD);            /* indicate end of plugin name data */
1077 
1078    return true;
1079 }
1080 
1081 /**
1082  * Plugin name stream found during restore.  The record passed in argument name was
1083  * generated in SendPluginName() above.
1084  *
1085  * Returns: true  if start of stream
1086  *          false if end of steam
1087  */
PluginNameStream(JobControlRecord * jcr,char * name)1088 bool PluginNameStream(JobControlRecord *jcr, char *name)
1089 {
1090    int len;
1091    char *cmd;
1092    char *p = name;
1093    bool start;
1094    bpContext *ctx = nullptr;
1095    alist *plugin_ctx_list;
1096 
1097    Dmsg1(debuglevel, "Read plugin stream string=%s\n", name);
1098    SkipNonspaces(&p);             /* skip over jcr->JobFiles */
1099    SkipSpaces(&p);
1100    start = *p == '1';
1101    if (start) {
1102       /*
1103        * Start of plugin data
1104        */
1105       SkipNonspaces(&p);          /* skip start/end flag */
1106       SkipSpaces(&p);
1107       SkipNonspaces(&p);          /* skip portable flag */
1108       SkipSpaces(&p);
1109       cmd = p;
1110    } else {
1111       /*
1112        * End of plugin data, notify plugin, then clear flags
1113        */
1114       if (jcr->plugin_ctx) {
1115          Plugin *plugin = jcr->plugin_ctx->plugin;
1116          b_plugin_ctx *b_ctx = (b_plugin_ctx *)jcr->plugin_ctx->bContext;
1117 
1118          Dmsg2(debuglevel, "End plugin data plugin=%p ctx=%p\n", plugin, jcr->plugin_ctx);
1119          if (b_ctx->restoreFileStarted) {
1120             PlugFunc(plugin)->endRestoreFile(jcr->plugin_ctx);
1121          }
1122          b_ctx->restoreFileStarted = false;
1123          b_ctx->createFileCalled = false;
1124       }
1125 
1126       goto bail_out;
1127    }
1128 
1129    plugin_ctx_list = jcr->plugin_ctx_list;
1130    if (!plugin_ctx_list) {
1131       goto bail_out;
1132    }
1133 
1134    /*
1135     * After this point, we are dealing with a restore start
1136     */
1137    if (!GetPluginName(jcr, cmd, &len)) {
1138       goto bail_out;
1139    }
1140 
1141    /*
1142     * Search for correct plugin as specified on the command
1143     */
1144    foreach_alist(ctx, plugin_ctx_list) {
1145       bEvent event;
1146       bEventType eventType;
1147       b_plugin_ctx *b_ctx;
1148 
1149       Dmsg3(debuglevel, "plugin=%s cmd=%s len=%d\n", ctx->plugin->file, cmd, len);
1150       if (!for_thIsPlugin(ctx->plugin, cmd, len)) {
1151          continue;
1152       }
1153 
1154       if (IsPluginDisabled(ctx)) {
1155          Dmsg1(debuglevel, "Plugin %s disabled\n", cmd);
1156          goto bail_out;
1157       }
1158 
1159       Dmsg1(debuglevel, "Restore Command plugin = %s\n", cmd);
1160       eventType = bEventRestoreCommand;
1161       event.eventType = eventType;
1162 
1163       if (!IsEventEnabled(ctx, eventType)) {
1164          Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
1165          continue;
1166       }
1167 
1168       jcr->plugin_ctx = ctx;
1169       jcr->cmd_plugin = true;
1170       b_ctx = (b_plugin_ctx *)ctx->bContext;
1171 
1172       if (PlugFunc(ctx->plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) {
1173          Dmsg1(debuglevel, "Handle event failed. Plugin=%s\n", cmd);
1174          goto bail_out;
1175       }
1176 
1177       if (b_ctx->restoreFileStarted) {
1178          Jmsg2(jcr, M_FATAL, 0, "Second call to startRestoreFile. plugin=%s cmd=%s\n", ctx->plugin->file, cmd);
1179          b_ctx->restoreFileStarted = false;
1180          goto bail_out;
1181       }
1182 
1183       if (PlugFunc(ctx->plugin)->startRestoreFile(jcr->plugin_ctx, cmd) == bRC_OK) {
1184          b_ctx->restoreFileStarted = true;
1185          goto bail_out;
1186       } else {
1187          Dmsg1(debuglevel, "startRestoreFile failed. plugin=%s\n", cmd);
1188          goto bail_out;
1189       }
1190    }
1191    Jmsg1(jcr, M_WARNING, 0, _("Plugin=%s not found.\n"), cmd);
1192 
1193 bail_out:
1194    return start;
1195 }
1196 
1197 /**
1198  * Tell the plugin to create the file. this is called only during Restore.
1199  * Return values are:
1200  *
1201  * CF_ERROR    -> error
1202  * CF_SKIP     -> skip processing this file
1203  * CF_EXTRACT  -> extract the file (i.e.call i/o routines)
1204  * CF_CREATED  -> created, but no content to extract (typically directories)
1205  */
PluginCreateFile(JobControlRecord * jcr,Attributes * attr,BareosWinFilePacket * bfd,int replace)1206 int PluginCreateFile(JobControlRecord *jcr, Attributes *attr, BareosWinFilePacket *bfd, int replace)
1207 {
1208    int flags;
1209    int retval;
1210    int status;
1211    Plugin *plugin;
1212    struct restore_pkt rp;
1213    bpContext *ctx = jcr->plugin_ctx;
1214    b_plugin_ctx *b_ctx = (b_plugin_ctx *)jcr->plugin_ctx->bContext;
1215 
1216    if (!ctx || !SetCmdPlugin(bfd, jcr) || jcr->IsJobCanceled()) {
1217       return CF_ERROR;
1218    }
1219    plugin = ctx->plugin;
1220 
1221    rp.pkt_size = sizeof(rp);
1222    rp.pkt_end = sizeof(rp);
1223    rp.delta_seq = attr->delta_seq;
1224    rp.stream = attr->stream;
1225    rp.data_stream = attr->data_stream;
1226    rp.type = attr->type;
1227    rp.file_index = attr->file_index;
1228    rp.LinkFI = attr->LinkFI;
1229    rp.uid = attr->uid;
1230    memcpy(&rp.statp, &attr->statp, sizeof(rp.statp));
1231    rp.attrEx = attr->attrEx;
1232    rp.ofname = attr->ofname;
1233    rp.olname = attr->olname;
1234    rp.where = jcr->where;
1235    rp.RegexWhere = jcr->RegexWhere;
1236    rp.replace = jcr->replace;
1237    rp.create_status = CF_ERROR;
1238 
1239    Dmsg4(debuglevel, "call plugin createFile stream=%d type=%d LinkFI=%d File=%s\n",
1240          rp.stream, rp.type, rp.LinkFI, rp.ofname);
1241    if (rp.attrEx) {
1242       Dmsg1(debuglevel, "attrEx=\"%s\"\n", rp.attrEx);
1243    }
1244 
1245    if (!b_ctx->restoreFileStarted || b_ctx->createFileCalled) {
1246       Jmsg2(jcr, M_FATAL, 0, "Unbalanced call to createFile=%d %d\n",
1247             b_ctx->createFileCalled, b_ctx->restoreFileStarted);
1248       b_ctx->createFileCalled = false;
1249       return CF_ERROR;
1250    }
1251 
1252    retval = PlugFunc(plugin)->createFile(ctx, &rp);
1253    if (retval != bRC_OK) {
1254       Qmsg2(jcr, M_ERROR, 0, _("Plugin createFile call failed. Stat=%d file=%s\n"), retval, attr->ofname);
1255       return CF_ERROR;
1256    }
1257 
1258    switch (rp.create_status) {
1259    case CF_ERROR:
1260       Qmsg1(jcr, M_ERROR, 0, _("Plugin createFile call failed. Returned CF_ERROR file=%s\n"), attr->ofname);
1261       /*
1262        * FALLTHROUGH
1263        */
1264    case CF_SKIP:
1265       /*
1266        * FALLTHROUGH
1267        */
1268    case CF_CORE:
1269       /*
1270        * FALLTHROUGH
1271        */
1272    case CF_CREATED:
1273       return rp.create_status;
1274    }
1275 
1276    flags =  O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
1277    Dmsg0(debuglevel, "call bopen\n");
1278 
1279    status = bopen(bfd, attr->ofname, flags, S_IRUSR | S_IWUSR, attr->statp.st_rdev);
1280    Dmsg1(debuglevel, "bopen status=%d\n", status);
1281 
1282    if (status < 0) {
1283       BErrNo be;
1284 
1285       be.SetErrno(bfd->BErrNo);
1286       Qmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"),
1287             attr->ofname, be.bstrerror());
1288       Dmsg2(debuglevel,"Could not bopen file %s: ERR=%s\n", attr->ofname, be.bstrerror());
1289       return CF_ERROR;
1290    }
1291 
1292    if (!IsBopen(bfd)) {
1293       Dmsg0(000, "===== BFD is not open!!!!\n");
1294    }
1295 
1296    return CF_EXTRACT;
1297 }
1298 
1299 /**
1300  * Reset the file attributes after all file I/O is done -- this allows the previous access time/dates
1301  * to be set properly, and it also allows us to properly set directory permissions.
1302  */
PluginSetAttributes(JobControlRecord * jcr,Attributes * attr,BareosWinFilePacket * ofd)1303 bool PluginSetAttributes(JobControlRecord *jcr, Attributes *attr, BareosWinFilePacket *ofd)
1304 {
1305    Plugin *plugin;
1306    struct restore_pkt rp;
1307 
1308    Dmsg0(debuglevel, "PluginSetAttributes\n");
1309 
1310    if (!jcr->plugin_ctx) {
1311       return false;
1312    }
1313    plugin = (Plugin *)jcr->plugin_ctx->plugin;
1314 
1315    memset(&rp, 0, sizeof(rp));
1316    rp.pkt_size = sizeof(rp);
1317    rp.pkt_end = sizeof(rp);
1318    rp.stream = attr->stream;
1319    rp.data_stream = attr->data_stream;
1320    rp.type = attr->type;
1321    rp.file_index = attr->file_index;
1322    rp.LinkFI = attr->LinkFI;
1323    rp.uid = attr->uid;
1324    memcpy(&rp.statp, &attr->statp, sizeof(rp.statp));
1325    rp.attrEx = attr->attrEx;
1326    rp.ofname = attr->ofname;
1327    rp.olname = attr->olname;
1328    rp.where = jcr->where;
1329    rp.RegexWhere = jcr->RegexWhere;
1330    rp.replace = jcr->replace;
1331    rp.create_status = CF_ERROR;
1332 
1333    PlugFunc(plugin)->setFileAttributes(jcr->plugin_ctx, &rp);
1334 
1335    if (rp.create_status == CF_CORE) {
1336       SetAttributes(jcr, attr, ofd);
1337    } else {
1338       if (IsBopen(ofd)) {
1339          bclose(ofd);
1340       }
1341       PmStrcpy(attr->ofname, "*None*");
1342    }
1343 
1344    return true;
1345 }
1346 
1347 /**
1348  * Plugin specific callback for getting ACL information.
1349  */
PluginBuildAclStreams(JobControlRecord * jcr,acl_data_t * acl_data,FindFilesPacket * ff_pkt)1350 bacl_exit_code PluginBuildAclStreams(JobControlRecord *jcr,
1351                                         acl_data_t *acl_data,
1352                                         FindFilesPacket *ff_pkt)
1353 {
1354    Plugin *plugin;
1355 
1356    Dmsg0(debuglevel, "PluginBuildAclStreams\n");
1357 
1358    if (!jcr->plugin_ctx) {
1359       return bacl_exit_ok;
1360    }
1361    plugin = (Plugin *)jcr->plugin_ctx->plugin;
1362 
1363    if (PlugFunc(plugin)->getAcl == NULL) {
1364       return bacl_exit_ok;
1365    } else {
1366       bacl_exit_code retval = bacl_exit_error;
1367 #if defined(HAVE_ACL)
1368       struct acl_pkt ap;
1369 
1370       memset(&ap, 0, sizeof(ap));
1371       ap.pkt_size = ap.pkt_end = sizeof(struct acl_pkt);
1372       ap.fname = acl_data->last_fname;
1373 
1374       switch (PlugFunc(plugin)->getAcl(jcr->plugin_ctx, &ap)) {
1375       case bRC_OK:
1376          if (ap.content_length && ap.content) {
1377             acl_data->u.build->content = CheckPoolMemorySize(acl_data->u.build->content, ap.content_length);
1378             memcpy(acl_data->u.build->content, ap.content, ap.content_length);
1379             acl_data->u.build->content_length = ap.content_length;
1380             free(ap.content);
1381             retval = SendAclStream(jcr, acl_data, STREAM_ACL_PLUGIN);
1382          } else {
1383             retval = bacl_exit_ok;
1384          }
1385          break;
1386       default:
1387          break;
1388       }
1389 #endif
1390 
1391       return retval;
1392    }
1393 }
1394 
1395 /**
1396  * Plugin specific callback for setting ACL information.
1397  */
plugin_parse_acl_streams(JobControlRecord * jcr,acl_data_t * acl_data,int stream,char * content,uint32_t content_length)1398 bacl_exit_code plugin_parse_acl_streams(JobControlRecord *jcr,
1399                                         acl_data_t *acl_data,
1400                                         int stream,
1401                                         char *content,
1402                                         uint32_t content_length)
1403 {
1404    Plugin *plugin;
1405 
1406    Dmsg0(debuglevel, "plugin_parse_acl_streams\n");
1407 
1408    if (!jcr->plugin_ctx) {
1409       return bacl_exit_ok;
1410    }
1411    plugin = (Plugin *)jcr->plugin_ctx->plugin;
1412 
1413    if (PlugFunc(plugin)->setAcl == NULL) {
1414       return bacl_exit_error;
1415    } else {
1416       bacl_exit_code retval = bacl_exit_error;
1417 #if defined(HAVE_ACL)
1418       struct acl_pkt ap;
1419 
1420       memset(&ap, 0, sizeof(ap));
1421       ap.pkt_size = ap.pkt_end = sizeof(struct acl_pkt);
1422       ap.fname = acl_data->last_fname;
1423       ap.content = content;
1424       ap.content_length = content_length;
1425 
1426       switch (PlugFunc(plugin)->setAcl(jcr->plugin_ctx, &ap)) {
1427       case bRC_OK:
1428          retval = bacl_exit_ok;
1429          break;
1430       default:
1431          break;
1432       }
1433 #endif
1434 
1435       return retval;
1436    }
1437 }
1438 
1439 /**
1440  * Plugin specific callback for getting XATTR information.
1441  */
PluginBuildXattrStreams(JobControlRecord * jcr,struct xattr_data_t * xattr_data,FindFilesPacket * ff_pkt)1442 BxattrExitCode PluginBuildXattrStreams(JobControlRecord *jcr,
1443                                             struct xattr_data_t *xattr_data,
1444                                             FindFilesPacket *ff_pkt)
1445 {
1446    Plugin *plugin;
1447 #if defined(HAVE_XATTR)
1448    alist *xattr_value_list = NULL;
1449 #endif
1450    BxattrExitCode retval = BxattrExitCode::kError;
1451 
1452    Dmsg0(debuglevel, "PluginBuildXattrStreams\n");
1453 
1454    if (!jcr->plugin_ctx) {
1455       return BxattrExitCode::kSuccess;
1456    }
1457    plugin = (Plugin *)jcr->plugin_ctx->plugin;
1458 
1459    if (PlugFunc(plugin)->getXattr == NULL) {
1460       return BxattrExitCode::kSuccess;
1461    } else {
1462 #if defined(HAVE_XATTR)
1463       bool more;
1464       int xattr_count = 0;
1465       xattr_t *current_xattr;
1466       struct xattr_pkt xp;
1467       uint32_t expected_serialize_len = 0;
1468 
1469       while (1) {
1470          memset(&xp, 0, sizeof(xp));
1471          xp.pkt_size = xp.pkt_end = sizeof(struct xattr_pkt);
1472          xp.fname = xattr_data->last_fname;
1473 
1474          switch (PlugFunc(plugin)->getXattr(jcr->plugin_ctx, &xp)) {
1475          case bRC_OK:
1476             more = false;
1477             break;
1478          case bRC_More:
1479             more = true;
1480             break;
1481          default:
1482             goto bail_out;
1483          }
1484 
1485          /*
1486           * Make sure the plugin filled a XATTR name.
1487           * The name and value returned by the plugin need to be in allocated memory
1488           * and are freed by XattrDropInternalTable() function when we are done
1489           * processing the data.
1490           */
1491          if (xp.name_length && xp.name) {
1492             /*
1493              * Each xattr valuepair starts with a magic so we can parse it easier.
1494              */
1495             current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1496             current_xattr->magic = XATTR_MAGIC;
1497             expected_serialize_len += sizeof(current_xattr->magic);
1498 
1499             current_xattr->name_length = xp.name_length;
1500             current_xattr->name = xp.name;
1501             expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1502 
1503             current_xattr->value_length = xp.value_length;
1504             current_xattr->value = xp.value;
1505             expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1506 
1507             if (xattr_value_list == NULL) {
1508                xattr_value_list = New(alist(10, not_owned_by_alist));
1509             }
1510 
1511             xattr_value_list->append(current_xattr);
1512             xattr_count++;
1513 
1514             /*
1515              * Protect ourself against things getting out of hand.
1516              */
1517             if (expected_serialize_len >= MAX_XATTR_STREAM) {
1518                Mmsg2(jcr->errmsg,
1519                      _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1520                      xattr_data->last_fname, MAX_XATTR_STREAM);
1521                goto bail_out;
1522             }
1523          }
1524 
1525          /*
1526           * Does the plugin have more xattrs ?
1527           */
1528          if (!more) {
1529             break;
1530          }
1531       }
1532 
1533       /*
1534        * If we found any xattr send them to the SD.
1535        */
1536       if (xattr_count > 0) {
1537          /*
1538           * Serialize the datastream.
1539           */
1540          if (SerializeXattrStream(jcr,
1541                                     xattr_data,
1542                                     expected_serialize_len,
1543                                     xattr_value_list) < expected_serialize_len) {
1544             Mmsg1(jcr->errmsg,
1545                   _("Failed to Serialize extended attributes on file \"%s\"\n"),
1546                   xattr_data->last_fname);
1547             Dmsg1(100, "Failed to Serialize extended attributes on file \"%s\"\n",
1548                   xattr_data->last_fname);
1549             goto bail_out;
1550          }
1551 
1552          /*
1553           * Send the datastream to the SD.
1554           */
1555          retval = SendXattrStream(jcr, xattr_data, STREAM_XATTR_PLUGIN);
1556       } else {
1557          retval = BxattrExitCode::kSuccess;
1558       }
1559 #endif
1560    }
1561 
1562 #if defined(HAVE_XATTR)
1563 bail_out:
1564    if (xattr_value_list) {
1565       XattrDropInternalTable(xattr_value_list);
1566    }
1567 #endif
1568 
1569    return retval;
1570 }
1571 
1572 /**
1573  * Plugin specific callback for setting XATTR information.
1574  */
PluginParseXattrStreams(JobControlRecord * jcr,struct xattr_data_t * xattr_data,int stream,char * content,uint32_t content_length)1575 BxattrExitCode PluginParseXattrStreams(JobControlRecord *jcr,
1576                                             struct xattr_data_t *xattr_data,
1577                                             int stream,
1578                                             char *content,
1579                                             uint32_t content_length)
1580 {
1581 #if defined(HAVE_XATTR)
1582    Plugin *plugin;
1583    alist *xattr_value_list = NULL;
1584 #endif
1585    BxattrExitCode retval = BxattrExitCode::kError;
1586 
1587    Dmsg0(debuglevel, "PluginParseXattrStreams\n");
1588 
1589    if (!jcr->plugin_ctx) {
1590       return BxattrExitCode::kSuccess;
1591    }
1592 
1593 #if defined(HAVE_XATTR)
1594    plugin = (Plugin *)jcr->plugin_ctx->plugin;
1595    if (PlugFunc(plugin)->setXattr != NULL) {
1596       xattr_t *current_xattr = nullptr;
1597       struct xattr_pkt xp;
1598 
1599       xattr_value_list = New(alist(10, not_owned_by_alist));
1600 
1601       if (UnSerializeXattrStream(jcr,
1602                                    xattr_data,
1603                                    content,
1604                                    content_length,
1605                                    xattr_value_list) != BxattrExitCode::kSuccess) {
1606          goto bail_out;
1607       }
1608 
1609       memset(&xp, 0, sizeof(xp));
1610       xp.pkt_size = xp.pkt_end = sizeof(struct xattr_pkt);
1611       xp.fname = xattr_data->last_fname;
1612 
1613       foreach_alist(current_xattr, xattr_value_list) {
1614          xp.name = current_xattr->name;
1615          xp.name_length = current_xattr->name_length;
1616          xp.value = current_xattr->value;
1617          xp.value_length = current_xattr->value_length;
1618 
1619          switch (PlugFunc(plugin)->setXattr(jcr->plugin_ctx, &xp)) {
1620          case bRC_OK:
1621             break;
1622          default:
1623             goto bail_out;
1624          }
1625       }
1626 
1627       retval = BxattrExitCode::kSuccess;
1628    }
1629 
1630 bail_out:
1631    if (xattr_value_list) {
1632       XattrDropInternalTable(xattr_value_list);
1633    }
1634 #endif
1635 
1636    return retval;
1637 }
1638 
1639 /**
1640  * Print to file the plugin info.
1641  */
DumpFdPlugin(Plugin * plugin,FILE * fp)1642 static void DumpFdPlugin(Plugin *plugin, FILE *fp)
1643 {
1644    genpInfo *info;
1645 
1646    if (!plugin) {
1647       return ;
1648    }
1649 
1650    info = (genpInfo *)plugin->pinfo;
1651    fprintf(fp, "\tversion=%d\n", info->version);
1652    fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
1653    fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
1654    fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
1655    fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
1656    fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
1657    fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
1658 }
1659 
DumpFdPlugins(FILE * fp)1660 static void DumpFdPlugins(FILE *fp)
1661 {
1662    DumpPlugins(fd_plugin_list, fp);
1663 }
1664 
1665 /**
1666  * This entry point is called internally by Bareos to ensure that the plugin IO calls come into this code.
1667  */
LoadFdPlugins(const char * plugin_dir,alist * plugin_names)1668 void LoadFdPlugins(const char *plugin_dir, alist *plugin_names)
1669 {
1670    Plugin *plugin;
1671    int i;
1672 
1673    if (!plugin_dir) {
1674       Dmsg0(debuglevel, "plugin dir is NULL\n");
1675       return;
1676    }
1677 
1678    fd_plugin_list = New(alist(10, not_owned_by_alist));
1679    if (!LoadPlugins((void *)&binfo, (void *)&bfuncs, fd_plugin_list,
1680                      plugin_dir, plugin_names, plugin_type, IsPluginCompatible)) {
1681       /*
1682        * Either none found, or some error
1683        */
1684       if (fd_plugin_list->size() == 0) {
1685          delete fd_plugin_list;
1686          fd_plugin_list = NULL;
1687          Dmsg0(debuglevel, "No plugins loaded\n");
1688          return;
1689       }
1690    }
1691 
1692    /*
1693     * Plug entry points called from findlib
1694     */
1695    plugin_bopen  = MyPluginBopen;
1696    plugin_bclose = MyPluginBclose;
1697    plugin_bread  = MyPluginBread;
1698    plugin_bwrite = MyPluginBwrite;
1699    plugin_blseek = MyPluginBlseek;
1700 
1701    /*
1702     * Verify that the plugin is acceptable, and print information about it.
1703     */
1704    foreach_alist_index(i, plugin, fd_plugin_list) {
1705       Dmsg1(debuglevel, "Loaded plugin: %s\n", plugin->file);
1706    }
1707 
1708    DbgPluginAddHook(DumpFdPlugin);
1709    DbgPrintPluginAddHook(DumpFdPlugins);
1710 }
1711 
UnloadFdPlugins(void)1712 void UnloadFdPlugins(void)
1713 {
1714    UnloadPlugins(fd_plugin_list);
1715    delete fd_plugin_list;
1716    fd_plugin_list = NULL;
1717 }
1718 
ListFdPlugins(PoolMem & msg)1719 int ListFdPlugins(PoolMem &msg)
1720 {
1721    return ListPlugins(fd_plugin_list, msg);
1722 }
1723 
1724 /**
1725  * Check if a plugin is compatible.  Called by the load_plugin function to allow us to verify the plugin.
1726  */
IsPluginCompatible(Plugin * plugin)1727 static bool IsPluginCompatible(Plugin *plugin)
1728 {
1729    genpInfo *info = (genpInfo *)plugin->pinfo;
1730    Dmsg0(debuglevel, "IsPluginCompatible called\n");
1731    if (debug_level >= 50) {
1732       DumpFdPlugin(plugin, stdin);
1733    }
1734    if (!bstrcmp(info->plugin_magic, FD_PLUGIN_MAGIC)) {
1735       Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
1736            plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
1737       Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
1738            plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
1739 
1740       return false;
1741    }
1742    if (info->version != FD_PLUGIN_INTERFACE_VERSION) {
1743       Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
1744            plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
1745       Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
1746            plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
1747       return false;
1748    }
1749    if (!Bstrcasecmp(info->plugin_license, "Bareos AGPLv3") &&
1750        !Bstrcasecmp(info->plugin_license, "AGPLv3")) {
1751       Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
1752            plugin->file, info->plugin_license);
1753       Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
1754            plugin->file, info->plugin_license);
1755       return false;
1756    }
1757    if (info->size != sizeof(genpInfo)) {
1758       Jmsg(NULL, M_ERROR, 0,
1759            _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"),
1760            plugin->file, sizeof(genpInfo), info->size);
1761       return false;
1762    }
1763 
1764    return true;
1765 }
1766 
1767 /**
1768  * Instantiate a new plugin instance.
1769  */
instantiate_plugin(JobControlRecord * jcr,Plugin * plugin,char instance)1770 static inline bpContext *instantiate_plugin(JobControlRecord *jcr, Plugin *plugin, char instance)
1771 {
1772    bpContext *ctx;
1773    b_plugin_ctx *b_ctx;
1774 
1775    b_ctx = (b_plugin_ctx *)malloc(sizeof(b_plugin_ctx));
1776    b_ctx = (b_plugin_ctx *)memset(b_ctx, 0, sizeof(b_plugin_ctx));
1777    b_ctx->jcr = jcr;
1778    b_ctx->plugin = plugin;
1779 
1780    ctx = (bpContext *)malloc(sizeof(bpContext));
1781    ctx->instance = instance;
1782    ctx->plugin = plugin;
1783    ctx->bContext = (void *)b_ctx;
1784    ctx->pContext = NULL;
1785 
1786    jcr->plugin_ctx_list->append(ctx);
1787 
1788    if (PlugFunc(plugin)->newPlugin(ctx) != bRC_OK) {
1789       b_ctx->disabled = true;
1790    }
1791 
1792    return ctx;
1793 }
1794 
1795 /**
1796  * Create a new instance of each plugin for this Job
1797  *
1798  * Note, fd_plugin_list can exist but jcr->plugin_ctx_list can be NULL if no plugins were loaded.
1799  */
NewPlugins(JobControlRecord * jcr)1800 void NewPlugins(JobControlRecord *jcr)
1801 {
1802    int i, num;
1803    Plugin *plugin;
1804 
1805    if (!fd_plugin_list) {
1806       Dmsg0(debuglevel, "plugin list is NULL\n");
1807       return;
1808    }
1809 
1810    if (jcr->IsJobCanceled()) {
1811       return;
1812    }
1813 
1814    num = fd_plugin_list->size();
1815    if (num == 0) {
1816       Dmsg0(debuglevel, "No plugins loaded\n");
1817       return;
1818    }
1819 
1820    jcr->plugin_ctx_list = New(alist(10, owned_by_alist));
1821    Dmsg2(debuglevel, "Instantiate plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
1822    foreach_alist_index(i, plugin, fd_plugin_list) {
1823       /*
1824        * Start a new instance of each plugin
1825        */
1826       instantiate_plugin(jcr, plugin, 0);
1827    }
1828 }
1829 
1830 /**
1831  * Free the plugin instances for this Job
1832  */
FreePlugins(JobControlRecord * jcr)1833 void FreePlugins(JobControlRecord *jcr)
1834 {
1835    bpContext *ctx = nullptr;
1836 
1837    if (!fd_plugin_list || !jcr->plugin_ctx_list) {
1838       return;
1839    }
1840 
1841    Dmsg2(debuglevel, "Free instance fd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
1842    foreach_alist(ctx, jcr->plugin_ctx_list) {
1843       /*
1844        * Free the plugin instance
1845        */
1846       PlugFunc(ctx->plugin)->freePlugin(ctx);
1847       free(ctx->bContext);                   /* Free BAREOS private context */
1848    }
1849 
1850    delete jcr->plugin_ctx_list;
1851    jcr->plugin_ctx_list = NULL;
1852 }
1853 
1854 /**
1855  * Entry point for opening the file this is a wrapper around the pluginIO entry point in the plugin.
1856  */
MyPluginBopen(BareosWinFilePacket * bfd,const char * fname,int flags,mode_t mode)1857 static int MyPluginBopen(BareosWinFilePacket *bfd, const char *fname, int flags, mode_t mode)
1858 {
1859    Plugin *plugin;
1860    struct io_pkt io;
1861    JobControlRecord *jcr = bfd->jcr;
1862 
1863    Dmsg1(debuglevel, "plugin_bopen flags=%08o\n", flags);
1864    if (!jcr->plugin_ctx) {
1865       return 0;
1866    }
1867    plugin = (Plugin *)jcr->plugin_ctx->plugin;
1868 
1869    memset(&io, 0, sizeof(io));
1870    io.pkt_size = sizeof(io);
1871    io.pkt_end = sizeof(io);
1872 
1873    io.func = IO_OPEN;
1874    io.fname = fname;
1875    io.flags = flags;
1876    io.mode = mode;
1877 
1878    PlugFunc(plugin)->pluginIO(jcr->plugin_ctx, &io);
1879    bfd->BErrNo = io.io_errno;
1880 
1881    if (io.win32) {
1882       errno = b_errno_win32;
1883    } else {
1884       errno = io.io_errno;
1885       bfd->lerror = io.lerror;
1886    }
1887 
1888    Dmsg1(debuglevel, "Return from plugin open status=%d\n", io.status);
1889 
1890    return io.status;
1891 }
1892 
1893 /**
1894  * Entry point for closing the file this is a wrapper around the pluginIO entry point in the plugin.
1895  */
MyPluginBclose(BareosWinFilePacket * bfd)1896 static int MyPluginBclose(BareosWinFilePacket *bfd)
1897 {
1898    Plugin *plugin;
1899    struct io_pkt io;
1900    JobControlRecord *jcr = bfd->jcr;
1901 
1902    Dmsg0(debuglevel, "===== plugin_bclose\n");
1903    if (!jcr->plugin_ctx) {
1904       return 0;
1905    }
1906    plugin = (Plugin *)jcr->plugin_ctx->plugin;
1907 
1908    memset(&io, 0, sizeof(io));
1909    io.pkt_size = sizeof(io);
1910    io.pkt_end = sizeof(io);
1911 
1912    io.func = IO_CLOSE;
1913 
1914    PlugFunc(plugin)->pluginIO(jcr->plugin_ctx, &io);
1915    bfd->BErrNo = io.io_errno;
1916 
1917    if (io.win32) {
1918       errno = b_errno_win32;
1919    } else {
1920       errno = io.io_errno;
1921       bfd->lerror = io.lerror;
1922    }
1923 
1924    Dmsg1(debuglevel, "plugin_bclose stat=%d\n", io.status);
1925 
1926    return io.status;
1927 }
1928 
1929 /**
1930  * Entry point for reading from the file this is a wrapper around the pluginIO entry point in the plugin.
1931  */
MyPluginBread(BareosWinFilePacket * bfd,void * buf,size_t count)1932 static ssize_t MyPluginBread(BareosWinFilePacket *bfd, void *buf, size_t count)
1933 {
1934    Plugin *plugin;
1935    struct io_pkt io;
1936    JobControlRecord *jcr = bfd->jcr;
1937 
1938    Dmsg0(debuglevel, "plugin_bread\n");
1939    if (!jcr->plugin_ctx) {
1940       return 0;
1941    }
1942    plugin = (Plugin *)jcr->plugin_ctx->plugin;
1943 
1944    memset(&io, 0, sizeof(io));
1945    io.pkt_size = sizeof(io);
1946    io.pkt_end = sizeof(io);
1947 
1948    io.func = IO_READ;
1949    io.count = count;
1950    io.buf = (char *)buf;
1951 
1952    PlugFunc(plugin)->pluginIO(jcr->plugin_ctx, &io);
1953    bfd->offset = io.offset;
1954    bfd->BErrNo = io.io_errno;
1955 
1956    if (io.win32) {
1957       errno = b_errno_win32;
1958    } else {
1959       errno = io.io_errno;
1960       bfd->lerror = io.lerror;
1961    }
1962 
1963    return (ssize_t)io.status;
1964 }
1965 
1966 /**
1967  * Entry point for writing to the file this is a wrapper around the pluginIO entry point in the plugin.
1968  */
MyPluginBwrite(BareosWinFilePacket * bfd,void * buf,size_t count)1969 static ssize_t MyPluginBwrite(BareosWinFilePacket *bfd, void *buf, size_t count)
1970 {
1971    Plugin *plugin;
1972    struct io_pkt io;
1973    JobControlRecord *jcr = bfd->jcr;
1974 
1975    Dmsg0(debuglevel, "plugin_bwrite\n");
1976    if (!jcr->plugin_ctx) {
1977       Dmsg0(0, "No plugin context\n");
1978       return 0;
1979    }
1980    plugin = (Plugin *)jcr->plugin_ctx->plugin;
1981 
1982    memset(&io, 0, sizeof(io));
1983    io.pkt_size = sizeof(io);
1984    io.pkt_end = sizeof(io);
1985 
1986    io.func = IO_WRITE;
1987    io.count = count;
1988    io.buf = (char *)buf;
1989 
1990    PlugFunc(plugin)->pluginIO(jcr->plugin_ctx, &io);
1991    bfd->BErrNo = io.io_errno;
1992 
1993    if (io.win32) {
1994       errno = b_errno_win32;
1995    } else {
1996       errno = io.io_errno;
1997       bfd->lerror = io.lerror;
1998    }
1999 
2000    return (ssize_t)io.status;
2001 }
2002 
2003 /**
2004  * Entry point for seeking in the file this is a wrapper around the pluginIO entry point in the plugin.
2005  */
MyPluginBlseek(BareosWinFilePacket * bfd,boffset_t offset,int whence)2006 static boffset_t MyPluginBlseek(BareosWinFilePacket *bfd, boffset_t offset, int whence)
2007 {
2008    Plugin *plugin;
2009    struct io_pkt io;
2010    JobControlRecord *jcr = bfd->jcr;
2011 
2012    Dmsg0(debuglevel, "plugin_bseek\n");
2013    if (!jcr->plugin_ctx) {
2014       return 0;
2015    }
2016    plugin = (Plugin *)jcr->plugin_ctx->plugin;
2017 
2018    io.pkt_size = sizeof(io);
2019    io.pkt_end = sizeof(io);
2020    io.func = IO_SEEK;
2021    io.offset = offset;
2022    io.whence = whence;
2023    io.win32 = false;
2024    io.lerror = 0;
2025    PlugFunc(plugin)->pluginIO(jcr->plugin_ctx, &io);
2026    bfd->BErrNo = io.io_errno;
2027    if (io.win32) {
2028       errno = b_errno_win32;
2029    } else {
2030       errno = io.io_errno;
2031       bfd->lerror = io.lerror;
2032    }
2033 
2034    return (boffset_t)io.offset;
2035 }
2036 
2037 /* ==============================================================
2038  *
2039  * Callbacks from the plugin
2040  *
2041  * ==============================================================
2042  */
bareosGetValue(bpContext * ctx,bVariable var,void * value)2043 static bRC bareosGetValue(bpContext *ctx, bVariable var, void *value)
2044 {
2045    JobControlRecord *jcr = NULL;
2046    if (!value) {
2047       return bRC_Error;
2048    }
2049 
2050    switch (var) {               /* General variables, no need of ctx */
2051    case bVarFDName:
2052       *((char **)value) = my_name;
2053       break;
2054    case bVarWorkingDir:
2055       *(void **)value = me->working_directory;
2056       break;
2057    case bVarExePath:
2058       *(char **)value = exepath;
2059       break;
2060    case bVarVersion:
2061       *(char **)value = version;
2062       break;
2063    case bVarDistName:
2064       *(char **)value = dist_name;
2065       break;
2066    default:
2067       if (!ctx) {               /* Other variables need context */
2068          return bRC_Error;
2069       }
2070 
2071       jcr = ((b_plugin_ctx *)ctx->bContext)->jcr;
2072       if (!jcr) {
2073          return bRC_Error;
2074       }
2075       break;
2076    }
2077 
2078    if (jcr) {
2079       switch (var) {
2080       case bVarJobId:
2081          *((int *)value) = jcr->JobId;
2082          Dmsg1(debuglevel, "fd-plugin: return bVarJobId=%d\n", jcr->JobId);
2083          break;
2084       case bVarLevel:
2085          *((int *)value) = jcr->getJobLevel();
2086          Dmsg1(debuglevel, "fd-plugin: return bVarJobLevel=%d\n", jcr->getJobLevel());
2087          break;
2088       case bVarType:
2089          *((int *)value) = jcr->getJobType();
2090          Dmsg1(debuglevel, "fd-plugin: return bVarJobType=%d\n", jcr->getJobType());
2091          break;
2092       case bVarClient:
2093          *((char **)value) = jcr->client_name;
2094          Dmsg1(debuglevel, "fd-plugin: return bVarClient=%s\n", NPRT(*((char **)value)));
2095          break;
2096       case bVarJobName:
2097          *((char **)value) = jcr->Job;
2098          Dmsg1(debuglevel, "fd-plugin: return bVarJobName=%s\n", NPRT(*((char **)value)));
2099          break;
2100       case bVarPrevJobName:
2101          *((char **)value) = jcr->PrevJob;
2102          Dmsg1(debuglevel, "fd-plugin: return bVarPrevJobName=%s\n", NPRT(*((char **)value)));
2103          break;
2104       case bVarJobStatus:
2105          *((int *)value) = jcr->JobStatus;
2106          Dmsg1(debuglevel, "fd-plugin: return bVarJobStatus=%d\n", jcr->JobStatus);
2107          break;
2108       case bVarSinceTime:
2109          *((int *)value) = (int)jcr->mtime;
2110          Dmsg1(debuglevel, "fd-plugin: return bVarSinceTime=%d\n", (int)jcr->mtime);
2111          break;
2112       case bVarAccurate:
2113          *((int *)value) = (int)jcr->accurate;
2114          Dmsg1(debuglevel, "fd-plugin: return bVarAccurate=%d\n", (int)jcr->accurate);
2115          break;
2116       case bVarFileSeen:
2117          break;                 /* a write only variable, ignore read request */
2118       case bVarVssClient:
2119 #ifdef HAVE_WIN32
2120          if (jcr->pVSSClient) {
2121             *(void **)value = jcr->pVSSClient;
2122             Dmsg1(debuglevel, "fd-plugin: return bVarVssClient=%p\n", *(void **)value);
2123             break;
2124          }
2125 #endif
2126          return bRC_Error;
2127       case bVarWhere:
2128          *(char **)value = jcr->where;
2129          Dmsg1(debuglevel, "fd-plugin: return bVarWhere=%s\n", NPRT(*((char **)value)));
2130          break;
2131       case bVarRegexWhere:
2132          *(char **)value = jcr->RegexWhere;
2133          Dmsg1(debuglevel, "fd-plugin: return bVarRegexWhere=%s\n", NPRT(*((char **)value)));
2134          break;
2135       case bVarPrefixLinks:
2136          *(int *)value = (int)jcr->prefix_links;
2137          Dmsg1(debuglevel, "fd-plugin: return bVarPrefixLinks=%d\n", (int)jcr->prefix_links);
2138          break;
2139       default:
2140          break;
2141       }
2142    }
2143 
2144    return bRC_OK;
2145 }
2146 
bareosSetValue(bpContext * ctx,bVariable var,void * value)2147 static bRC bareosSetValue(bpContext *ctx, bVariable var, void *value)
2148 {
2149    JobControlRecord *jcr;
2150 
2151    if (!value || !ctx) {
2152       return bRC_Error;
2153    }
2154 
2155    jcr = ((b_plugin_ctx *)ctx->bContext)->jcr;
2156    if (!jcr) {
2157       return bRC_Error;
2158    }
2159 
2160    switch (var) {
2161    case bVarLevel:
2162       jcr->setJobLevel(*(int *)value);
2163       break;
2164    case bVarFileSeen:
2165       if (!AccurateMarkFileAsSeen(jcr, (char *)value)) {
2166          return bRC_Error;
2167       }
2168       break;
2169    default:
2170       break;
2171    }
2172 
2173    return bRC_OK;
2174 }
2175 
bareosRegisterEvents(bpContext * ctx,int nr_events,...)2176 static bRC bareosRegisterEvents(bpContext *ctx, int nr_events, ...)
2177 {
2178    int i;
2179    va_list args;
2180    uint32_t event;
2181    b_plugin_ctx *b_ctx;
2182 
2183    if (!ctx) {
2184       return bRC_Error;
2185    }
2186    b_ctx = (b_plugin_ctx *)ctx->bContext;
2187 
2188    va_start(args, nr_events);
2189    for (i = 0; i < nr_events; i++) {
2190       event = va_arg(args, uint32_t);
2191       Dmsg1(debuglevel, "fd-plugin: Plugin registered event=%u\n", event);
2192       SetBit(event, b_ctx->events);
2193    }
2194    va_end(args);
2195 
2196    return bRC_OK;
2197 }
2198 
2199 /**
2200  * Get the number of instaces instantiated of a certain plugin.
2201  */
bareosGetInstanceCount(bpContext * ctx,int * ret)2202 static bRC bareosGetInstanceCount(bpContext *ctx, int *ret)
2203 {
2204    int cnt;
2205    JobControlRecord *jcr, *njcr;
2206    bpContext *nctx;
2207    b_plugin_ctx *bctx;
2208    bRC retval = bRC_Error;
2209 
2210    if (!IsCtxGood(ctx, jcr, bctx)) {
2211       goto bail_out;
2212    }
2213 
2214    P(mutex);
2215 
2216    cnt = 0;
2217    foreach_jcr(njcr) {
2218       if (jcr->plugin_ctx_list) {
2219          foreach_alist(nctx, jcr->plugin_ctx_list) {
2220             if (nctx->plugin == bctx->plugin) {
2221                cnt++;
2222             }
2223          }
2224       }
2225    }
2226    endeach_jcr(njcr);
2227 
2228    V(mutex);
2229 
2230    *ret = cnt;
2231    retval = bRC_OK;
2232 
2233 bail_out:
2234    return retval;
2235 }
2236 
bareosUnRegisterEvents(bpContext * ctx,int nr_events,...)2237 static bRC bareosUnRegisterEvents(bpContext *ctx, int nr_events, ...)
2238 {
2239    int i;
2240    va_list args;
2241    uint32_t event;
2242    b_plugin_ctx *b_ctx;
2243 
2244    if (!ctx) {
2245       return bRC_Error;
2246    }
2247    b_ctx = (b_plugin_ctx *)ctx->bContext;
2248 
2249    va_start(args, nr_events);
2250    for (i = 0; i < nr_events; i++) {
2251       event = va_arg(args, uint32_t);
2252       Dmsg1(debuglevel, "fd-plugin: Plugin unregistered event=%u\n", event);
2253       ClearBit(event, b_ctx->events);
2254    }
2255    va_end(args);
2256 
2257    return bRC_OK;
2258 }
2259 
bareosJobMsg(bpContext * ctx,const char * fname,int line,int type,utime_t mtime,const char * fmt,...)2260 static bRC bareosJobMsg(bpContext *ctx, const char *fname, int line,
2261                         int type, utime_t mtime, const char *fmt, ...)
2262 {
2263    JobControlRecord *jcr;
2264    va_list arg_ptr;
2265    PoolMem buffer(PM_MESSAGE);
2266 
2267    if (ctx) {
2268       jcr = ((b_plugin_ctx *)ctx->bContext)->jcr;
2269    } else {
2270       jcr = NULL;
2271    }
2272 
2273    va_start(arg_ptr, fmt);
2274    buffer.Bvsprintf(fmt, arg_ptr);
2275    va_end(arg_ptr);
2276    Jmsg(jcr, type, mtime, "%s", buffer.c_str());
2277 
2278    return bRC_OK;
2279 }
2280 
bareosDebugMsg(bpContext * ctx,const char * fname,int line,int level,const char * fmt,...)2281 static bRC bareosDebugMsg(bpContext *ctx, const char *fname, int line,
2282                           int level, const char *fmt, ...)
2283 {
2284    va_list arg_ptr;
2285    PoolMem buffer(PM_MESSAGE);
2286 
2287    va_start(arg_ptr, fmt);
2288    buffer.Bvsprintf(fmt, arg_ptr);
2289    va_end(arg_ptr);
2290    d_msg(fname, line, level, "%s", buffer.c_str());
2291 
2292    return bRC_OK;
2293 }
2294 
bareosMalloc(bpContext * ctx,const char * fname,int line,size_t size)2295 static void *bareosMalloc(bpContext *ctx, const char *fname, int line, size_t size)
2296 {
2297 #ifdef SMARTALLOC
2298    return sm_malloc(fname, line, size);
2299 #else
2300    return malloc(size);
2301 #endif
2302 }
2303 
bareosFree(bpContext * ctx,const char * fname,int line,void * mem)2304 static void bareosFree(bpContext *ctx, const char *fname, int line, void *mem)
2305 {
2306 #ifdef SMARTALLOC
2307    sm_free(fname, line, mem);
2308 #else
2309    free(mem);
2310 #endif
2311 }
2312 
2313 /**
2314  * Let the plugin define files/directories to be excluded from the main backup.
2315  */
bareosAddExclude(bpContext * ctx,const char * fname)2316 static bRC bareosAddExclude(bpContext *ctx, const char *fname)
2317 {
2318    JobControlRecord *jcr;
2319    findIncludeExcludeItem *old;
2320    b_plugin_ctx *bctx;
2321 
2322    if (!IsCtxGood(ctx, jcr, bctx)) {
2323       return bRC_Error;
2324    }
2325    if (!fname) {
2326       return bRC_Error;
2327    }
2328 
2329    /*
2330     * Save the include context
2331     */
2332    old = get_incexe(jcr);
2333 
2334    /*
2335     * Not right time to add exlude
2336     */
2337    if (!old) {
2338       return bRC_Error;
2339    }
2340 
2341    if (!bctx->exclude) {
2342       bctx->exclude = new_exclude(jcr->ff->fileset);
2343    }
2344 
2345    /*
2346     * Set the Exclude context
2347     */
2348    SetIncexe(jcr, bctx->exclude);
2349 
2350    AddFileToFileset(jcr, fname, true);
2351 
2352    /*
2353     * Restore the current context
2354     */
2355    SetIncexe(jcr, old);
2356 
2357    Dmsg1(100, "Add exclude file=%s\n", fname);
2358 
2359    return bRC_OK;
2360 }
2361 
2362 /**
2363  * Let the plugin define files/directories to be excluded from the main backup.
2364  */
bareosAddInclude(bpContext * ctx,const char * fname)2365 static bRC bareosAddInclude(bpContext *ctx, const char *fname)
2366 {
2367    JobControlRecord *jcr;
2368    findIncludeExcludeItem *old;
2369    b_plugin_ctx *bctx;
2370 
2371    if (!IsCtxGood(ctx, jcr, bctx)) {
2372       return bRC_Error;
2373    }
2374 
2375    if (!fname) {
2376       return bRC_Error;
2377    }
2378 
2379    /*
2380     * Save the include context
2381     */
2382    old = get_incexe(jcr);
2383 
2384    /*
2385     * Not right time to add include
2386     */
2387    if (!old) {
2388       return bRC_Error;
2389    }
2390 
2391    if (!bctx->include) {
2392       bctx->include = old;
2393    }
2394 
2395    SetIncexe(jcr, bctx->include);
2396    AddFileToFileset(jcr, fname, true);
2397 
2398    /*
2399     * Restore the current context
2400     */
2401    SetIncexe(jcr, old);
2402 
2403    Dmsg1(100, "Add include file=%s\n", fname);
2404 
2405    return bRC_OK;
2406 }
2407 
bareosAddOptions(bpContext * ctx,const char * opts)2408 static bRC bareosAddOptions(bpContext *ctx, const char *opts)
2409 {
2410    JobControlRecord *jcr;
2411    b_plugin_ctx *bctx;
2412 
2413    if (!IsCtxGood(ctx, jcr, bctx)) {
2414       return bRC_Error;
2415    }
2416 
2417    if (!opts) {
2418       return bRC_Error;
2419    }
2420    AddOptionsToFileset(jcr, opts);
2421    Dmsg1(1000, "Add options=%s\n", opts);
2422 
2423    return bRC_OK;
2424 }
2425 
bareosAddRegex(bpContext * ctx,const char * item,int type)2426 static bRC bareosAddRegex(bpContext *ctx, const char *item, int type)
2427 {
2428    JobControlRecord *jcr;
2429    b_plugin_ctx *bctx;
2430 
2431    if (!IsCtxGood(ctx, jcr, bctx)) {
2432       return bRC_Error;
2433    }
2434 
2435    if (!item) {
2436       return bRC_Error;
2437    }
2438    AddRegexToFileset(jcr, item, type);
2439    Dmsg1(100, "Add regex=%s\n", item);
2440 
2441    return bRC_OK;
2442 }
2443 
bareosAddWild(bpContext * ctx,const char * item,int type)2444 static bRC bareosAddWild(bpContext *ctx, const char *item, int type)
2445 {
2446    JobControlRecord *jcr;
2447    b_plugin_ctx *bctx;
2448 
2449    if (!IsCtxGood(ctx, jcr, bctx)) {
2450       return bRC_Error;
2451    }
2452 
2453    if (!item) {
2454       return bRC_Error;
2455    }
2456    AddWildToFileset(jcr, item, type);
2457    Dmsg1(100, "Add wild=%s\n", item);
2458 
2459    return bRC_OK;
2460 }
2461 
bareosNewOptions(bpContext * ctx)2462 static bRC bareosNewOptions(bpContext *ctx)
2463 {
2464    JobControlRecord *jcr;
2465    b_plugin_ctx *bctx;
2466 
2467    if (!IsCtxGood(ctx, jcr, bctx)) {
2468       return bRC_Error;
2469    }
2470    (void)NewOptions(jcr->ff, jcr->ff->fileset->incexe);
2471 
2472    return bRC_OK;
2473 }
2474 
bareosNewInclude(bpContext * ctx)2475 static bRC bareosNewInclude(bpContext *ctx)
2476 {
2477    JobControlRecord *jcr;
2478    b_plugin_ctx *bctx;
2479 
2480    if (!IsCtxGood(ctx, jcr, bctx)) {
2481       return bRC_Error;
2482    }
2483    (void)new_include(jcr->ff->fileset);
2484 
2485    return bRC_OK;
2486 }
2487 
bareosNewPreInclude(bpContext * ctx)2488 static bRC bareosNewPreInclude(bpContext *ctx)
2489 {
2490    JobControlRecord *jcr;
2491    b_plugin_ctx *bctx;
2492 
2493    if (!IsCtxGood(ctx, jcr, bctx)) {
2494       return bRC_Error;
2495    }
2496 
2497    bctx->include = new_preinclude(jcr->ff->fileset);
2498    NewOptions(jcr->ff, bctx->include);
2499    SetIncexe(jcr, bctx->include);
2500 
2501    return bRC_OK;
2502 }
2503 
2504 /**
2505  * Check if a file have to be backuped using Accurate code
2506  */
bareosCheckChanges(bpContext * ctx,struct save_pkt * sp)2507 static bRC bareosCheckChanges(bpContext *ctx, struct save_pkt *sp)
2508 {
2509    JobControlRecord *jcr;
2510    b_plugin_ctx *bctx;
2511    FindFilesPacket *ff_pkt;
2512    bRC retval = bRC_Error;
2513 
2514    if (!IsCtxGood(ctx, jcr, bctx)) {
2515       goto bail_out;
2516    }
2517 
2518    if (!sp) {
2519       goto bail_out;
2520    }
2521 
2522    ff_pkt = jcr->ff;
2523    /*
2524     * Copy fname and link because SaveFile() zaps them.
2525     * This avoids zaping the plugin's strings.
2526     */
2527    ff_pkt->type = sp->type;
2528    if (!sp->fname) {
2529       Jmsg0(jcr, M_FATAL, 0, _("Command plugin: no fname in bareosCheckChanges packet.\n"));
2530       goto bail_out;
2531    }
2532 
2533    ff_pkt->fname = sp->fname;
2534    ff_pkt->link = sp->link;
2535    if (sp->save_time) {
2536       ff_pkt->save_time = sp->save_time;
2537       ff_pkt->incremental = true;
2538    }
2539    memcpy(&ff_pkt->statp, &sp->statp, sizeof(ff_pkt->statp));
2540 
2541    if (CheckChanges(jcr, ff_pkt))  {
2542       retval = bRC_OK;
2543    } else {
2544       retval = bRC_Seen;
2545    }
2546 
2547    /*
2548     * CheckChanges() can update delta sequence number, return it to the plugin
2549     */
2550    sp->delta_seq = ff_pkt->delta_seq;
2551    sp->accurate_found = ff_pkt->accurate_found;
2552 
2553 bail_out:
2554    Dmsg1(100, "checkChanges=%i\n", retval);
2555    return retval;
2556 }
2557 
2558 /**
2559  * Check if a file would be saved using current Include/Exclude code
2560  */
bareosAcceptFile(bpContext * ctx,struct save_pkt * sp)2561 static bRC bareosAcceptFile(bpContext *ctx, struct save_pkt *sp)
2562 {
2563    JobControlRecord *jcr;
2564    FindFilesPacket *ff_pkt;
2565    b_plugin_ctx *bctx;
2566    bRC retval = bRC_Error;
2567 
2568    if (!IsCtxGood(ctx, jcr, bctx)) {
2569       goto bail_out;
2570    }
2571    if (!sp) {
2572       goto bail_out;
2573    }
2574 
2575    ff_pkt = jcr->ff;
2576 
2577    ff_pkt->fname = sp->fname;
2578    memcpy(&ff_pkt->statp, &sp->statp, sizeof(ff_pkt->statp));
2579 
2580    if (AcceptFile(ff_pkt)) {
2581       retval = bRC_OK;
2582    } else {
2583       retval = bRC_Skip;
2584    }
2585 
2586 bail_out:
2587    return retval;
2588 }
2589 
2590 /**
2591  * Manipulate the accurate seen bitmap for setting bits
2592  */
bareosSetSeenBitmap(bpContext * ctx,bool all,char * fname)2593 static bRC bareosSetSeenBitmap(bpContext *ctx, bool all, char *fname)
2594 {
2595    JobControlRecord *jcr;
2596    b_plugin_ctx *bctx;
2597    bRC retval = bRC_Error;
2598 
2599    if (!IsCtxGood(ctx, jcr, bctx)) {
2600       goto bail_out;
2601    }
2602 
2603    if (all && fname) {
2604       Dmsg0(debuglevel, "fd-plugin: API error in call to SetSeenBitmap, both all and fname set!!!\n");
2605       goto bail_out;
2606    }
2607 
2608    if (all) {
2609       if (AccurateMarkAllFilesAsSeen(jcr)) {
2610          retval = bRC_OK;
2611       }
2612    } else if (fname) {
2613       if (AccurateMarkFileAsSeen(jcr, fname)) {
2614          retval = bRC_OK;
2615       }
2616    }
2617 
2618 bail_out:
2619    return retval;
2620 }
2621 
2622 /**
2623  * Manipulate the accurate seen bitmap for clearing bits
2624  */
bareosClearSeenBitmap(bpContext * ctx,bool all,char * fname)2625 static bRC bareosClearSeenBitmap(bpContext *ctx, bool all, char *fname)
2626 {
2627    JobControlRecord *jcr;
2628    b_plugin_ctx *bctx;
2629    bRC retval = bRC_Error;
2630 
2631    if (!IsCtxGood(ctx, jcr, bctx)) {
2632       goto bail_out;
2633    }
2634 
2635    if (all && fname) {
2636       Dmsg0(debuglevel, "fd-plugin: API error in call to ClearSeenBitmap, both all and fname set!!!\n");
2637       goto bail_out;
2638    }
2639 
2640    if (all) {
2641       if (accurate_unMarkAllFilesAsSeen(jcr)) {
2642          retval = bRC_OK;
2643       }
2644    } else if (fname) {
2645       if (accurate_unMarkFileAsSeen(jcr, fname)) {
2646          retval = bRC_OK;
2647       }
2648    }
2649 
2650 bail_out:
2651    return retval;
2652 }
2653 
2654 #ifdef TEST_PROGRAM
2655 /* Exported variables */
2656 ClientResource *me;                        /* my resource */
2657 
SaveFile(JobControlRecord * jcr,FindFilesPacket * ff_pkt,bool top_level)2658 int SaveFile(JobControlRecord *jcr, FindFilesPacket *ff_pkt, bool top_level)
2659 {
2660    return 0;
2661 }
2662 
AccurateMarkFileAsSeen(JobControlRecord * jcr,char * fname)2663 bool AccurateMarkFileAsSeen(JobControlRecord *jcr, char *fname)
2664 {
2665    return true;
2666 }
2667 
SetCmdPlugin(BareosWinFilePacket * bfd,JobControlRecord * jcr)2668 bool SetCmdPlugin(BareosWinFilePacket *bfd, JobControlRecord *jcr)
2669 {
2670    return true;
2671 }
2672 
main(int argc,char * argv[])2673 int main(int argc, char *argv[])
2674 {
2675    char plugin_dir[PATH_MAX];
2676    JobControlRecord mjcr1, mjcr2;
2677    JobControlRecord *jcr1 = &mjcr1;
2678    JobControlRecord *jcr2 = &mjcr2;
2679 
2680    MyNameIs(argc, argv, "plugtest");
2681    InitMsg(NULL, NULL);
2682 
2683    OSDependentInit();
2684 
2685    if (argc != 1) {
2686       bstrncpy(plugin_dir, argv[1], sizeof(plugin_dir));
2687    } else {
2688       getcwd(plugin_dir, sizeof(plugin_dir)-1);
2689    }
2690    LoadFdPlugins(plugin_dir, NULL);
2691 
2692    jcr1->JobId = 111;
2693    NewPlugins(jcr1);
2694 
2695    jcr2->JobId = 222;
2696    NewPlugins(jcr2);
2697 
2698    GeneratePluginEvent(jcr1, bEventJobStart, (void *)"Start Job 1");
2699    GeneratePluginEvent(jcr1, bEventJobEnd);
2700    GeneratePluginEvent(jcr2, bEventJobStart, (void *)"Start Job 2");
2701    FreePlugins(jcr1);
2702    GeneratePluginEvent(jcr2, bEventJobEnd);
2703    FreePlugins(jcr2);
2704 
2705    UnloadFdPlugins();
2706 
2707    Dmsg0(debuglevel, "bareos: OK ...\n");
2708 
2709    TermMsg();
2710    CloseMemoryPool();
2711    LmgrCleanupMain();
2712    sm_dump(false);
2713    exit(0);
2714 }
2715 
2716 #endif /* TEST_PROGRAM */
2717 } /* namespace filedaemon */
2718