From: Radosław Korzeniewski Date: Wed, 7 Apr 2021 15:33:41 +0000 (+0200) Subject: metaplugin: Add checkFile() callback. X-Git-Tag: Release-11.3.2~601 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=561b15f2f422da38fbf5846a4693b8e912c530da;p=thirdparty%2Fbacula.git metaplugin: Add checkFile() callback. --- diff --git a/bacula/src/plugins/fd/pluginlib/Makefile b/bacula/src/plugins/fd/pluginlib/Makefile index b890b46ce..c5172670f 100644 --- a/bacula/src/plugins/fd/pluginlib/Makefile +++ b/bacula/src/plugins/fd/pluginlib/Makefile @@ -11,6 +11,7 @@ include ../Makefile.inc UNITTESTSOBJ = $(LIBDIR)/unittests.lo LIBBACOBJ = $(LIBDIR)/libbac.la +LIBBACCFGOBJ = $(LIBDIR)/libbaccfg.la PLUGINLIBSSRC = pluginlib.cpp pluginlib.h PLUGINLIBSOBJ = $(filter %.lo,$(PLUGINLIBSSRC:.cpp=.lo)) @@ -36,6 +37,8 @@ SMARTALISTTEST = smartalist_test.cpp $(SMARTALISTSRC) $(PLUGINLIBSOBJ) $(UNITTES SMARTALISTTESTOBJ = $(filter %.lo,$(SMARTALISTTEST:.cpp=.lo)) SMARTPTRTEST = smartptr_test.cpp $(SMARTPTRSRC) $(PLUGINLIBSOBJ) $(UNITTESTSOBJ) SMARTPTRTESTOBJ = $(filter %.lo,$(SMARTPTRTEST:.cpp=.lo)) +METAPLUGINTEST = metaplugin_test.cpp $(METAPLUGINSRC) +METAPLUGINTESTOBJ = $(filter %.lo,$(METAPLUGINTEST:.cpp=.lo)) $(PTCOMMOBJ) $(PLUGINLIBSOBJ) $(METAPLUGINOBJ) $(UNITTESTSOBJ) TESTMETAPLUGINBACKENDSRC = test_metaplugin_backend.c TESTMETAPLUGINBACKENDOBJ = $(TESTMETAPLUGINBACKENDSRC:.c=.lo) @@ -67,7 +70,10 @@ $(UNITTESTSOBJ): $(LIBBACOBJ): $(MAKE) -C $(LIBDIR) libbac.la -test_metaplugin_backend.lo: Makefile $(TESTMETAPLUGINBACKENDSRC) +$(LIBBACCFGOBJ): + $(MAKE) -C $(LIBDIR) libbaccfg.la + +test_metaplugin_backend.lo: $(TESTMETAPLUGINBACKENDSRC) @echo "Compiling backend $< ..." $(NO_ECHO)$(LIBTOOL_COMPILE) $(CXX) $(DEFS) $(DEBUG) $(CPPFLAGS) $(CFLAGS) -I${SRCDIR} -I${FDDIR} -DLOGDIR=\"$(DESTDIR)$(working_dir)\" -c $< @@ -91,6 +97,12 @@ iso8601_test: Makefile $(ISO8601TESTOBJ) $(ISO8601SRC) $(UNITTESTSOBJ) $(LIBBACO @echo "Building $@ ..." $(NO_ECHO)$(LIBTOOL_LINK) --silent $(CXX) $(LDFLAGS) -L$(LIBDIR) -lbac $(PLUGINLIBSTESTOBJ) -o $@ +metaplugin_test: $(METAPLUGINTESTOBJ) $(LIBBACOBJ) + @echo "Building $@ ..." + $(LIBTOOL_LINK) --silent $(CXX) $(LDFLAGS) -L$(LIBDIR) $(LIBBACCFGOBJ) $(LIBBACOBJ) $(METAPLUGINTESTOBJ) -o $@ + +#$(NO_ECHO) + install: all $(MKDIR) $(DESTDIR)$(plugindir) diff --git a/bacula/src/plugins/fd/pluginlib/metaplugin.cpp b/bacula/src/plugins/fd/pluginlib/metaplugin.cpp index 2982e1bb1..852c48d2d 100644 --- a/bacula/src/plugins/fd/pluginlib/metaplugin.cpp +++ b/bacula/src/plugins/fd/pluginlib/metaplugin.cpp @@ -61,7 +61,7 @@ static bRC startRestoreFile(bpContext *ctx, const char *cmd); static bRC endRestoreFile(bpContext *ctx); static bRC createFile(bpContext *ctx, struct restore_pkt *rp); static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp); -// Not used! static bRC checkFile(bpContext *ctx, char *fname); +static bRC metaplugincheckFile(bpContext *ctx, char *fname); static bRC handleXACLdata(bpContext *ctx, struct xacl_pkt *xacl); static bRC queryParameter(bpContext *ctx, struct query_pkt *qp); static bRC metadataRestore(bpContext *ctx, struct meta_pkt *mp); @@ -88,7 +88,7 @@ static pFuncs pluginFuncs = pluginIO, createFile, setFileAttributes, - NULL, + metaplugincheckFile, handleXACLdata, NULL, /* No restore file list */ NULL, /* No checkStream */ @@ -165,7 +165,6 @@ METAPLUGIN::METAPLUGIN(bpContext *bpctx) : pluginobjectsent(false), readacl(false), readxattr(false), - accurate_warning(false), fname(PM_FNAME), lname(PM_FNAME), robjbuf(NULL), @@ -2428,7 +2427,6 @@ bRC METAPLUGIN::metadataRestore(bpContext *ctx, struct meta_pkt *mp) if (mp->buf != NULL && mp->buf_len > 0){ /* send command METADATA */ - // pm_strcpy(cmd, "METADATA_STREAM\n"); pm_strcpy(cmd, prepare_metadata_type(mp->type)); backend.ctx->write_command(ctx, cmd.c_str()); /* send metadata stream data */ @@ -2447,6 +2445,28 @@ bRC METAPLUGIN::metadataRestore(bpContext *ctx, struct meta_pkt *mp) return bRC_OK; } +/** + * @brief Implements default metaplugin checkFile() callback. + * When fname match plugin configured namespace then it return bRC_Seen by default + * or calls custom checkFile() callback defined by backend developer. + * + * @param ctx for Bacula debug and jobinfo messages + * @param fname file name to check + * @return bRC bRC_Seen or bRC_OK + */ +bRC METAPLUGIN::checkFile(bpContext * ctx, char *fname) +{ + if ((!CUSTOMNAMESPACE && isourpluginfname(PLUGINPREFIX, fname)) || (CUSTOMNAMESPACE && isourpluginfname(PLUGINNAMESPACE, fname))) + { + if (::checkFile != NULL){ + return ::checkFile(ctx, fname); + } + return bRC_Seen; + } + + return bRC_OK; +} + /* * Called here to make a new instance of the plugin -- i.e. when * a new Job is started. There can be multiple instances of @@ -2665,3 +2685,17 @@ static bRC metadataRestore(bpContext *ctx, struct meta_pkt *mp) METAPLUGIN *self = pluginclass(ctx); return self->metadataRestore(ctx, mp); } + +/* + * checkFile used for accurate mode backup + * + * TODO: currently it is not working because a checking is performed against ldap plugin, not msad + */ +static bRC metaplugincheckFile(bpContext * ctx, char *fname) +{ + ASSERT_CTX; + + DMSG(ctx, D3, "checkFile for: %s\n", fname); + METAPLUGIN *self = pluginclass(ctx); + return self->checkFile(ctx, fname); +} diff --git a/bacula/src/plugins/fd/pluginlib/metaplugin.h b/bacula/src/plugins/fd/pluginlib/metaplugin.h index 167b4d85a..f17fcabf2 100644 --- a/bacula/src/plugins/fd/pluginlib/metaplugin.h +++ b/bacula/src/plugins/fd/pluginlib/metaplugin.h @@ -55,6 +55,10 @@ extern const bool CUSTOMNAMESPACE; extern const char *PLUGINAPI; extern const char *BACKEND_CMD; +// custom checkFile() callback +typedef bRC (*checkFile_t)(bpContext *ctx, char *fname); +extern checkFile_t checkFile; + // The list of restore options saved to the RestoreObject. extern struct ini_items plugin_items_dump[]; @@ -101,6 +105,7 @@ public: bRC pluginIO(bpContext *ctx, struct io_pkt *io); bRC createFile(bpContext *ctx, struct restore_pkt *rp); bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp); + bRC checkFile(bpContext *ctx, char *fname); bRC handleXACLdata(bpContext *ctx, struct xacl_pkt *xacl); bRC queryParameter(bpContext *ctx, struct query_pkt *qp); bRC metadataRestore(bpContext *ctx, struct meta_pkt *mp); @@ -142,7 +147,6 @@ private: bool pluginobjectsent; // set when startBackupFile handled plugin object and endBackupFile has to check for nextfile bool readacl; // got ACL data from backend bool readxattr; // got XATTR data from backend - bool accurate_warning; // for sending accurate mode warning once */ COMMCTX backend; // the backend context list for multiple backend execution for a single job POOL_MEM fname; // current file name to backup (grabbed from backend) POOL_MEM lname; // current LSTAT data if any diff --git a/bacula/src/plugins/fd/pluginlib/metaplugin_test.cpp b/bacula/src/plugins/fd/pluginlib/metaplugin_test.cpp new file mode 100644 index 000000000..ff0391b5c --- /dev/null +++ b/bacula/src/plugins/fd/pluginlib/metaplugin_test.cpp @@ -0,0 +1,113 @@ +/* + Bacula(R) - The Network Backup Solution + + Copyright (C) 2000-2020 Kern Sibbald + + The original author of Bacula is Kern Sibbald, with contributions + from many others, a complete list can be found in the file AUTHORS. + + You may use this file and others of this release according to the + license defined in the LICENSE file, which includes the Affero General + Public License, v3.0 ("AGPLv3") and some additional permissions and + terms pursuant to its AGPLv3 Section 7. + + This notice must be preserved when any source code is + conveyed and/or propagated. + + Bacula(R) is a registered trademark of Kern Sibbald. +*/ +/** + * @file metaplugin_tests.cpp + * @author Radosław Korzeniewski (radoslaw@korzeniewski.net) + * @brief This is a Bacula metaplugin unittests + * @version 1.0.0 + * @date 2021-04-07 + * + * @copyright Copyright (c) 2021 All rights reserved. + * IP transferred to Bacula Systems according to agreement. + */ + +#include "metaplugin.h" +#include "bacula.h" +#include "unittests.h" + +/* Plugin Info definitions */ +const char *PLUGIN_LICENSE = "AGPLv3"; +const char *PLUGIN_AUTHOR = "Radoslaw Korzeniewski"; +const char *PLUGIN_DATE = "April 2021"; +const char *PLUGIN_VERSION = "1.0.0"; +const char *PLUGIN_DESCRIPTION = "Bacula Enterprise MetaPlugin"; + +/* Plugin compile time variables */ +const char *PLUGINPREFIX = "metaplugin:"; +const char *PLUGINNAME = "metaplugin"; +const char *PLUGINNAMESPACE = "@metaplugin"; +const bool CUSTOMNAMESPACE = true; +const char *PLUGINAPI = "3"; +const char *BACKEND_CMD = "/bin/true"; + +static bRC mycheckFile(bpContext *ctx, char *fname); +checkFile_t checkFile = NULL; +// checkFile_t checkFile = mycheckFile; + +struct ini_items plugin_items_dump[] = { {NULL, NULL, NULL, 0, NULL} }; +const char * valid_params[] = { NULL }; + +#ifdef DEVELOPER +const metadataTypeMap plugin_metadata_map[] = {{"METADATA_STREAM", plugin_meta_blob}}; +#else +const metadataTypeMap plugin_metadata_map[] = {{NULL, plugin_meta_invalid}}; +#endif + +/* In order to link with libbaccfg */ +int32_t r_last; +int32_t r_first; +RES_HEAD **res_head; +bool save_resource(RES_HEAD **rhead, int type, RES_ITEM *items, int pass){return false;} +bool save_resource(CONFIG*, int, RES_ITEM*, int) {return false;} +void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock){} +void free_resource(RES *rres, int type){} +union URES {}; +RES_TABLE resources[] = {}; +URES res_all; + +static bRC mycheckFile(bpContext *ctx, char *fname) +{ + return bRC_Error; +} + +struct vectstruct +{ + const char *fname; + bRC status; +}; + +static const vectstruct testvect1[] = { + {"/etc/passwd", bRC_OK}, + {"/@MYSQL/", bRC_OK}, + {"/@metaplugin/test/file", bRC_Seen}, + {"/@kubernetes/namespace/test", bRC_OK}, + {"@metaplugin/other", bRC_Seen}, + {"test/file", bRC_OK}, + {NULL, bRC_Error}, +}; + +int main() +{ + Unittests metaplugin_test("metaplugin_test"); + + struct bpContext bpctx = {}; + bpContext *bpctxp = &bpctx; + POOL_MEM testfname(PM_FNAME); + METAPLUGIN mp(bpctxp); + + for (int i = 0; testvect1[i].fname != NULL; i++){ + pm_strcpy(testfname, testvect1[i].fname); + bRC status = mp.checkFile(bpctxp, testfname.c_str()); + ok(status == testvect1[i].status, testfname.c_str()); + } + + checkFile = mycheckFile; + pm_strcpy(testfname, "@metaplugin/"); + ok(mp.checkFile(bpctxp, testfname.c_str()) == bRC_Error, "custom mycheckFile()"); +} diff --git a/bacula/src/plugins/fd/pluginlib/pluginlib.h b/bacula/src/plugins/fd/pluginlib/pluginlib.h index 0c79cc56e..cf6567fd9 100644 --- a/bacula/src/plugins/fd/pluginlib/pluginlib.h +++ b/bacula/src/plugins/fd/pluginlib/pluginlib.h @@ -156,6 +156,31 @@ inline bool isourplugincommand(const char *pluginprefix, const char *command) return false; } +/** + * @brief Checks if fname is a part of pluginprefix namespace + * + * @param pluginprefix plugin namespace prefix + * @param fname file name to check + * @return true when it matches + * @return false when not + */ +inline bool isourpluginfname(const char *pluginprefix, const char *fname) +{ + /* check if it is our Plugin fname */ + if (strncmp(pluginprefix, fname, strlen(pluginprefix)) == 0){ + return true; + } + char _fn[strlen(pluginprefix) + 2]; + _fn[0] = '/'; + _fn[1] = '\0'; + strcat(_fn, pluginprefix); + if (strncmp(_fn, fname, strlen(_fn)) == 0){ + return true; + } + + return false; +} + alist * plugutil_str_split_to_alist(const char * str, const char sep = '.'); /* plugin parameters manipulation */