diff --git a/include/rpm/rpmplugin.h b/include/rpm/rpmplugin.h index fab4b3e83c..72538b2b8c 100644 --- a/include/rpm/rpmplugin.h +++ b/include/rpm/rpmplugin.h @@ -60,6 +60,12 @@ typedef rpmRC (*plugin_fsm_file_prepare_func)(rpmPlugin plugin, rpmfi fi, int fd, const char* path, const char *dest, mode_t file_mode, rpmFsmOp op); +typedef rpmRC (*plugin_fsm_file_install_func)(rpmPlugin plugin, rpmfi fi, int dirfd, + const char *path, mode_t file_mode, rpmFsmOp op); +typedef rpmRC (*plugin_fsm_file_archive_reader_func)(rpmPlugin plugin, + FD_t payload, + rpmfiles files, rpmfi *fi); + typedef struct rpmPluginHooks_s * rpmPluginHooks; struct rpmPluginHooks_s { @@ -80,6 +86,8 @@ struct rpmPluginHooks_s { plugin_fsm_file_pre_func fsm_file_pre; plugin_fsm_file_post_func fsm_file_post; plugin_fsm_file_prepare_func fsm_file_prepare; + plugin_fsm_file_install_func fsm_file_install; + plugin_fsm_file_archive_reader_func fsm_file_archive_reader; }; #ifdef __cplusplus diff --git a/include/rpm/rpmtypes.h b/include/rpm/rpmtypes.h index e5ac7a39d6..b8458eef71 100644 --- a/include/rpm/rpmtypes.h +++ b/include/rpm/rpmtypes.h @@ -103,11 +103,12 @@ typedef struct FD_s * FD_t; * Package read return codes. */ typedef enum rpmRC_e { - RPMRC_OK = 0, /*!< Generic success code */ - RPMRC_NOTFOUND = 1, /*!< Generic not found code. */ - RPMRC_FAIL = 2, /*!< Generic failure code. */ - RPMRC_NOTTRUSTED = 3, /*!< Signature is OK, but key is not trusted. */ - RPMRC_NOKEY = 4 /*!< Public key is unavailable. */ + RPMRC_OK = 0, /*!< Generic success code */ + RPMRC_NOTFOUND = 1, /*!< Generic not found code. */ + RPMRC_FAIL = 2, /*!< Generic failure code. */ + RPMRC_NOTTRUSTED = 3, /*!< Signature is OK, but key is not trusted. */ + RPMRC_NOKEY = 4, /*!< Public key is unavailable. */ + RPMRC_PLUGIN_CONTENTS = 5, /*!< fsm_file_pre plugin is handling content */ } rpmRC; #ifdef __cplusplus diff --git a/lib/fsm.cc b/lib/fsm.cc index 63580c25ad..137e9da3dd 100644 --- a/lib/fsm.cc +++ b/lib/fsm.cc @@ -892,6 +892,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, struct filedata_s *fdata = (struct filedata_s *)xcalloc(fc, sizeof(*fdata)); struct filedata_s *firstlink = NULL; struct diriter_s di = { -1, -1 }; + rpmRC plugin_rc; /* transaction id used for temporary path suffix while installing */ rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); @@ -926,12 +927,27 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, if (rc) goto exit; - fi = fsmIter(payload, files, - payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di); - - if (fi == NULL) { - rc = RPMERR_BAD_MAGIC; - goto exit; + plugin_rc = rpmpluginsCallFsmFileArchiveReader(plugins, payload, files, &fi); + switch (plugin_rc) { + case RPMRC_PLUGIN_CONTENTS: + if (fi == NULL) { + rc = RPMERR_BAD_MAGIC; + goto exit; + } + rc = RPMRC_OK; + break; + case RPMRC_OK: + fi = fsmIter(payload, files, + payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di); + if (fi == NULL) { + rc = RPMERR_BAD_MAGIC; + goto exit; + } + rc = RPMRC_OK; + break; + default: + rc = RPMRC_FAIL; + goto exit; } /* Process the payload */ @@ -989,7 +1005,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, if (fp->action == FA_TOUCH) goto setmeta; - if (S_ISREG(fp->sb.st_mode)) { + plugin_rc = rpmpluginsCallFsmFileInstall(plugins, fi, di.dirfd, fp->fpath, fp->sb.st_mode, fp->action); + if(!(plugin_rc == RPMRC_PLUGIN_CONTENTS || plugin_rc == RPMRC_OK)){ + rc = plugin_rc; + } else if(plugin_rc == RPMRC_PLUGIN_CONTENTS){ + rc = RPMRC_OK; + /* A plugin could handle hardlink differently, set metadata to be safe. */ + fp->setmeta = 1; + } else if (S_ISREG(fp->sb.st_mode)) { if (rc == RPMERR_ENOENT) { rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, &firstlink, &firstlinkfile, &di.firstdir, diff --git a/lib/rpmplugins.cc b/lib/rpmplugins.cc index bd5e83d992..c403a821c3 100644 --- a/lib/rpmplugins.cc +++ b/lib/rpmplugins.cc @@ -352,13 +352,28 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path, { plugin_fsm_file_pre_func hookFunc; rpmRC rc = RPMRC_OK; + rpmRC hook_rc; char *apath = abspath(fi, path); for (auto & plugin : plugins->plugins) { RPMPLUGINS_SET_HOOK_FUNC(fsm_file_pre); - if (hookFunc && hookFunc(plugin, fi, apath, file_mode, op) == RPMRC_FAIL) { - rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name); - rc = RPMRC_FAIL; + if (hookFunc) { + hook_rc = hookFunc(plugin, fi, apath, file_mode, op); + if (hook_rc == RPMRC_FAIL) { + rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name); + rc = RPMRC_FAIL; + } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) { + if (rc == RPMRC_PLUGIN_CONTENTS) { + /* Another plugin already said it'd handle contents. It's + * undefined how these would combine, so treat this as a + * failure condition. + */ + rc = RPMRC_FAIL; + } else { + /* Plugin will handle content */ + rc = RPMRC_PLUGIN_CONTENTS; + } + } } } free(apath); @@ -403,3 +418,67 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi, return rc; } + +rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, int dirfd, + const char *path, mode_t file_mode, rpmFsmOp op) +{ + plugin_fsm_file_install_func hookFunc; + rpmRC rc = RPMRC_OK; + rpmRC hook_rc; + + for (auto & plugin : plugins->plugins) { + RPMPLUGINS_SET_HOOK_FUNC(fsm_file_install); + if (hookFunc) { + hook_rc = hookFunc(plugin, fi, dirfd, path, file_mode, op); + if (hook_rc == RPMRC_FAIL) { + rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_install failed\n", plugin->name); + rc = RPMRC_FAIL; + } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) { + if (rc == RPMRC_PLUGIN_CONTENTS) { + /* Another plugin already said it'd handle contents. It's + * undefined how these would combine, so treat this as a + * failure condition. + */ + rc = RPMRC_FAIL; + } else { + /* Plugin will handle content */ + rc = RPMRC_PLUGIN_CONTENTS; + } + } + } + } + + return rc; +} + +rpmRC rpmpluginsCallFsmFileArchiveReader(rpmPlugins plugins, FD_t payload, + rpmfiles files, rpmfi *fi) +{ + plugin_fsm_file_archive_reader_func hookFunc; + rpmRC rc = RPMRC_OK; + rpmRC hook_rc; + + for (auto & plugin : plugins->plugins) { + RPMPLUGINS_SET_HOOK_FUNC(fsm_file_archive_reader); + if (hookFunc) { + hook_rc = hookFunc(plugin, payload, files, fi); + if (hook_rc == RPMRC_FAIL) { + rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_archive_reader failed\n", plugin->name); + rc = RPMRC_FAIL; + } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) { + if (rc == RPMRC_PLUGIN_CONTENTS) { + /* Another plugin already said it'd handle contents. It's + * undefined how these would combine, so treat this as a + * failure condition. + */ + rc = RPMRC_FAIL; + } else { + /* Plugin will handle content */ + rc = RPMRC_PLUGIN_CONTENTS; + } + } + } + } + + return rc; +} diff --git a/lib/rpmplugins.hh b/lib/rpmplugins.hh index 97a9eb7ccc..015cc1e550 100644 --- a/lib/rpmplugins.hh +++ b/lib/rpmplugins.hh @@ -164,4 +164,23 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi, int fd, const char *path, const char *dest, mode_t mode, rpmFsmOp op); +/** \ingroup rpmplugins + * Call the fsm file install plugin hook + * @param plugins plugins structure + * @param fi file info iterator (or NULL) + * @param dirfd file object directory file descriptor + * @param path file object path + * @param file_mode file object mode + * @param op file operation + associated flags + * @return RPMRC_OK on success, RPMRC_FAIL otherwise + */ +RPM_GNUC_INTERNAL +rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, + int dirfd, const char *path, + mode_t file_mode, rpmFsmOp op); + +RPM_GNUC_INTERNAL +rpmRC rpmpluginsCallFsmFileArchiveReader(rpmPlugins plugins, FD_t payload, + rpmfiles files, rpmfi *fi); + #endif /* _PLUGINS_H */