mut_fname.c_str());
}
+ void delete_cached_file(const char *fname) {
+ auto mut_fname = std::string{fname};
+ std::size_t sz;
+
+ rspamd_normalize_path_inplace(mut_fname.data(), mut_fname.size(), &sz);
+ mut_fname.resize(sz);
+
+ if (mut_fname.empty()) {
+ msg_err_hyperscan("attempt to remove an empty hyperscan file!");
+ return;
+ }
+
+ if (access(mut_fname.c_str(), R_OK) != -1) {
+ if (unlink(mut_fname.c_str()) == -1) {
+ msg_err_hyperscan("cannot remove hyperscan file %s: %s",
+ mut_fname.c_str(), strerror(errno));
+ }
+ else {
+ msg_debug_hyperscan("removed hyperscan file %s", mut_fname.c_str());
+ }
+ }
+ else {
+ msg_err_hyperscan("attempt to remove non-existent hyperscan file %s: %s",
+ mut_fname.c_str(), strerror(errno));
+ }
+
+ known_cached_files.erase(mut_fname);
+ }
+
auto cleanup_maybe() -> void {
auto env_cleanup_disable = std::getenv("RSPAMD_NO_CLEANUP");
/* We clean dir merely if we are running from the main process */
struct hs_shared_database {
hs_database_t *db = nullptr; /**< internal database (might be in a shared memory) */
std::optional<raii_mmaped_file> maybe_map;
+ std::string cached_path;
~hs_shared_database() {
if (!maybe_map) {
// Otherwise, handled by maybe_map dtor
}
- explicit hs_shared_database(raii_mmaped_file &&map, hs_database_t *db) : db(db), maybe_map(std::move(map)) {}
- explicit hs_shared_database(hs_database_t *db) : db(db), maybe_map(std::nullopt) {}
+ explicit hs_shared_database(raii_mmaped_file &&map, hs_database_t *db) : db(db), maybe_map(std::move(map)) {
+ cached_path = maybe_map.value().get_file().get_name();
+ }
+ explicit hs_shared_database(hs_database_t *db, const char *fname) : db(db), maybe_map(std::nullopt), cached_path{fname} {}
hs_shared_database(const hs_shared_database &other) = delete;
hs_shared_database() = default;
hs_shared_database(hs_shared_database &&other) noexcept {
return tl::make_unexpected(error {"cannot deserialize database", ret});
}
- return tl::expected<hs_shared_database, error>{tl::in_place, target};
+ return tl::expected<hs_shared_database, error>{tl::in_place, target, map.get_file().get_name().data()};
}
auto load_cached_hs_file(const char *fname, std::int64_t offset = 0) -> tl::expected<hs_shared_database, error>
}
rspamd_hyperscan_t *
-rspamd_hyperscan_from_raw_db(hs_database_t *db)
+rspamd_hyperscan_from_raw_db(hs_database_t *db, const char *fname)
{
- auto *ndb = new rspamd::util::hs_shared_database{db};
+ auto *ndb = new rspamd::util::hs_shared_database{db, fname};
return C_DB_FROM_CXX(ndb);
}
void
-rspamd_hyperscan_free(rspamd_hyperscan_t *db)
+rspamd_hyperscan_free(rspamd_hyperscan_t *db, bool invalid)
{
auto *real_db = CXX_DB_FROM_C(db);
+ if (invalid) {
+ rspamd::util::hs_known_files_cache::get().delete_cached_file(real_db->cached_path.c_str());
+ }
delete real_db;
}
* @param filename
* @return
*/
-rspamd_hyperscan_t *rspamd_hyperscan_from_raw_db(hs_database_t *db);
+rspamd_hyperscan_t *rspamd_hyperscan_from_raw_db(hs_database_t *db, const char *fname);
/**
* Get the internal database
* @param db
* Free the database
* @param db
*/
-void rspamd_hyperscan_free(rspamd_hyperscan_t *db);
+void rspamd_hyperscan_free(rspamd_hyperscan_t *db, bool invalid);
/**
* Notice a known hyperscan file (e.g. externally serialized)
hs_free_scratch (re_map->hs_scratch);
}
if (re_map->hs_db) {
- rspamd_hyperscan_free(re_map->hs_db);
+ rspamd_hyperscan_free(re_map->hs_db, false);
}
if (re_map->patterns) {
for (i = 0; i < re_map->regexps->len; i ++) {
return;
}
- re_map->hs_db = rspamd_hyperscan_from_raw_db(hs_db);
+ if (re_map->map->cfg->hs_cache_dir) {
+ char fpath[PATH_MAX];
+ rspamd_snprintf(fpath, sizeof(fpath), "%s/%*xs.hsmc",
+ re_map->map->cfg->hs_cache_dir,
+ (gint) rspamd_cryptobox_HASHBYTES / 2, re_map->re_digest);
+ re_map->hs_db = rspamd_hyperscan_from_raw_db(hs_db, fpath);
+ }
+ else {
+ re_map->hs_db = rspamd_hyperscan_from_raw_db(hs_db, NULL);
+ }
ts1 = (rspamd_get_ticks (FALSE) - ts1) * 1000.0;
msg_info_map ("hyperscan compiled %d regular expressions from %s in %.1f ms",
if (hs_alloc_scratch (rspamd_hyperscan_get_database(re_map->hs_db), &re_map->hs_scratch) != HS_SUCCESS) {
msg_err_map ("cannot allocate scratch space for hyperscan");
- rspamd_hyperscan_free(re_map->hs_db);
+ rspamd_hyperscan_free(re_map->hs_db, true);
re_map->hs_db = NULL;
}
}
#ifdef WITH_HYPERSCAN
if (re_class->hs_db) {
- rspamd_hyperscan_free(re_class->hs_db);
+ rspamd_hyperscan_free(re_class->hs_db, false);
}
if (re_class->hs_scratch) {
hs_free_scratch (re_class->hs_scratch);
}
if (re_class->hs_db != NULL) {
- rspamd_hyperscan_free (re_class->hs_db);
+ rspamd_hyperscan_free (re_class->hs_db, false);
}
if (re_class->hs_ids) {
if ((ret = hs_alloc_scratch (rspamd_hyperscan_get_database(re_class->hs_db),
&re_class->hs_scratch)) != HS_SUCCESS) {
- rspamd_hyperscan_free (re_class->hs_db);
if (!try_load) {
msg_err_re_cache ("bad hs database in %s; error code: %d", path, ret);
}
g_free (hs_ids);
g_free (hs_flags);
+ rspamd_hyperscan_free (re_class->hs_db, true);
re_class->hs_ids = NULL;
re_class->hs_scratch = NULL;
re_class->hs_db = NULL;
return FALSE;
}
- mp->hs_db = rspamd_hyperscan_from_raw_db(db);
+
+ if (hs_cache_dir != NULL) {
+ char fpath[PATH_MAX];
+ rspamd_snprintf (fpath, sizeof (fpath), "%s/%*xs.hsmp", hs_cache_dir,
+ (gint)rspamd_cryptobox_HASHBYTES / 2, hash);
+ mp->hs_db = rspamd_hyperscan_from_raw_db(db, fpath);
+ }
+ else {
+ /* Should not happen in the real life */
+ mp->hs_db = rspamd_hyperscan_from_raw_db(db, NULL);
+ }
}
rspamd_multipattern_try_save_hs (mp, hash);
+ for (i = 0; i < MAX_SCRATCH; i ++) {
+ mp->scratch[i] = NULL;
+ }
+
for (i = 0; i < MAX_SCRATCH; i ++) {
int ret;
+
if ((ret = hs_alloc_scratch (rspamd_hyperscan_get_database(mp->hs_db), &mp->scratch[i])) != HS_SUCCESS) {
- msg_err("fatal error: cannot allocate scratch space for hyperscan: %d", ret);
- g_abort();
+ msg_err("cannot allocate scratch space for hyperscan: error code %d", ret);
+
+ /* Clean all scratches that are non-NULL */
+ for (int ii = 0; ii < MAX_SCRATCH; ii ++) {
+ if (mp->scratch[ii] != NULL) {
+ hs_free_scratch(mp->scratch[ii]);
+ }
+ }
+ g_set_error (err, rspamd_multipattern_quark (), EINVAL,
+ "cannot allocate scratch space for hyperscan: error code %d", ret);
+
+ rspamd_hyperscan_free(mp->hs_db, true);
+ mp->hs_db = NULL;
+
+ return FALSE;
}
}
}
}
if (mp->hs_db) {
- rspamd_hyperscan_free(mp->hs_db);
+ rspamd_hyperscan_free(mp->hs_db, false);
}
}