Add exclusions to config saving (#6629)

This will be used for future experimental options that are subject to
frequent change and should not pollute projects.
This commit is contained in:
Florian Märkl 2026-07-21 13:03:05 +02:00 committed by GitHub
parent cd1ad98598
commit 9b57c7a8ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 115 additions and 51 deletions

View file

@ -5,15 +5,40 @@
#include <rz_util/rz_serialize.h>
#include "config_internal.h"
static RzSetS *build_exclude_set(const char **strings) {
if (!strings) {
return NULL;
}
HtSP *r = rz_set_s_new(HT_STR_DUP);
if (!r) {
return NULL;
}
for (; *strings; strings++) {
rz_set_s_add(r, *strings);
}
return r;
}
typedef struct serialze_ctx_t {
Sdb *db;
HtSP *exclude;
} SerializeCtx;
static bool config_serialize_to_sdb(const RzConfigEntry *entry, void *user) {
Sdb *db = user;
SerializeCtx *ctx = user;
if (entry->is_variable) {
if (ctx->exclude && rz_set_s_contains(ctx->exclude, entry->var.name)) {
return true;
}
char *value = rz_config_var_as_string(&entry->var);
sdb_set(db, entry->var.name, value);
sdb_set(ctx->db, entry->var.name, value);
free(value);
} else {
const RzConfigNode *node = &entry->node;
sdb_set(db, node->name, node->value);
if (ctx->exclude && rz_set_s_contains(ctx->exclude, node->name)) {
return true;
}
sdb_set(ctx->db, node->name, node->value);
}
return true;
}
@ -28,20 +53,27 @@ static bool config_serialize_to_sdb(const RzConfigEntry *entry, void *user) {
* <name>=<value>
* ...
*
* \param exclude NULL-terminated array of keys to not store in the sdb.
*/
RZ_API void rz_serialize_config_save(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config) {
rz_config_iterate_over(config, config_serialize_to_sdb, db);
RZ_API void rz_serialize_config_save(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config, RZ_NULLABLE const char **exclude) {
rz_return_if_fail(db && config);
SerializeCtx ctx = { .db = db, .exclude = build_exclude_set(exclude) };
if (exclude && !ctx.exclude) {
return;
}
rz_config_iterate_over(config, config_serialize_to_sdb, &ctx);
rz_set_s_free(ctx.exclude);
}
typedef struct deserialize_ctx_s {
typedef struct deserialize_ctx_t {
RzConfig *config;
HtSP *exclude;
RzSetS *exclude;
} DeserializeCtx;
static bool config_deserialize_from_sdb(void *user, const SdbKv *kv) {
DeserializeCtx *ctx = user;
const char *key = sdbkv_key(kv);
if (ctx->exclude && ht_sp_find_kv(ctx->exclude, key, NULL)) {
if (ctx->exclude && rz_set_s_contains(ctx->exclude, key)) {
return true;
}
@ -65,17 +97,11 @@ static bool config_deserialize_from_sdb(void *user, const SdbKv *kv) {
RZ_API bool rz_serialize_config_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config, RZ_NULLABLE const char **exclude) {
rz_return_val_if_fail(db && config, false);
DeserializeCtx ctx = { config, NULL };
if (exclude) {
ctx.exclude = ht_sp_new(HT_STR_DUP, NULL, NULL);
if (!ctx.exclude) {
return false;
}
for (; *exclude; exclude++) {
ht_sp_insert(ctx.exclude, *exclude, NULL);
}
DeserializeCtx ctx = { .config = config, .exclude = build_exclude_set(exclude) };
if (exclude && !ctx.exclude) {
return false;
}
sdb_foreach(db, config_deserialize_from_sdb, &ctx);
ht_sp_free(ctx.exclude);
rz_set_s_free(ctx.exclude);
return true;
}

View file

@ -609,7 +609,7 @@ RZ_API void rz_core_sysenv_begin(RzCore *core) {
rz_sys_setenv("RZ_ENDIAN", rz_asm_is_big_endian_set(core->rasm) ? "big" : "little");
rz_sys_setenv("RZ_BSIZE", rz_strf(tmpbuf, "%d", core->blocksize));
// dump current config file so other r2 tools can use the same options
// dump current config file so other rizin tools can use the same options
char *config_sdb_path = NULL;
int config_sdb_fd = rz_file_mkstemp(NULL, &config_sdb_path);
if (config_sdb_fd >= 0) {
@ -617,7 +617,7 @@ RZ_API void rz_core_sysenv_begin(RzCore *core) {
}
Sdb *config_sdb = sdb_new(NULL, config_sdb_path, 0);
rz_serialize_config_save(config_sdb, core->config);
rz_serialize_config_save(config_sdb, core->config, NULL);
sdb_sync(config_sdb);
sdb_free(config_sdb);
rz_sys_setenv("RZ_CONFIG", config_sdb_path);

View file

@ -28,7 +28,7 @@ static char *config_path(RzCore *core) {
free(path);
return NULL;
}
rz_serialize_config_save(sdb, core->config);
rz_serialize_config_save(sdb, core->config, NULL);
sdb_sync(sdb);
sdb_free(sdb);

View file

@ -22,28 +22,20 @@ static void file_save(RZ_NONNULL Sdb *db, RZ_NONNULL RzCore *core, RZ_NULLABLE c
static bool file_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzCore *core, RZ_NULLABLE const char *prj_file,
RZ_NULLABLE RzSerializeResultInfo *res);
RZ_API void rz_serialize_core_save(RZ_NONNULL Sdb *db, RZ_NONNULL RzCore *core, RZ_NULLABLE const char *prj_file) {
file_save(sdb_ns(db, "file", true), core, prj_file);
rz_serialize_config_save(sdb_ns(db, "config", true), core->config);
rz_serialize_flag_save(sdb_ns(db, "flags", true), core->flags);
rz_serialize_mark_save(sdb_ns(db, "marks", true), core->marks);
rz_serialize_analysis_save(sdb_ns(db, "analysis", true), core->analysis);
rz_serialize_debug_save(sdb_ns(db, "debug", true), core->dbg);
rz_serialize_core_seek_save(sdb_ns(db, "seek", true), core);
/*
* Config Exclusions:
* Most exlusions only affect loading and are still written to the file, in case
* they become interesting to load later, or for informative purposes.
* Some other config vars may be considered experimental and subject to frequent change,
* so they should also be exluded from saving to avoid polluting project files and
* having to introduce migrations.
*/
char buf[0x20];
if (snprintf(buf, sizeof(buf), "0x%" PFMT64x, core->offset) < 0) {
return;
}
sdb_set(db, "offset", buf);
static const char *config_exclude_save[] = {
NULL
};
if (snprintf(buf, sizeof(buf), "0x%" PFMT32x, core->blocksize) < 0) {
return;
}
sdb_set(db, "blocksize", buf);
}
static const char *config_exclude[] = {
static const char *config_exclude_load[] = {
"dir.home",
"dir.libs",
"dir.magic",
@ -70,6 +62,27 @@ static const char *config_exclude[] = {
NULL
};
RZ_API void rz_serialize_core_save(RZ_NONNULL Sdb *db, RZ_NONNULL RzCore *core, RZ_NULLABLE const char *prj_file) {
file_save(sdb_ns(db, "file", true), core, prj_file);
rz_serialize_config_save(sdb_ns(db, "config", true), core->config, config_exclude_save);
rz_serialize_flag_save(sdb_ns(db, "flags", true), core->flags);
rz_serialize_mark_save(sdb_ns(db, "marks", true), core->marks);
rz_serialize_analysis_save(sdb_ns(db, "analysis", true), core->analysis);
rz_serialize_debug_save(sdb_ns(db, "debug", true), core->dbg);
rz_serialize_core_seek_save(sdb_ns(db, "seek", true), core);
char buf[0x20];
if (snprintf(buf, sizeof(buf), "0x%" PFMT64x, core->offset) < 0) {
return;
}
sdb_set(db, "offset", buf);
if (snprintf(buf, sizeof(buf), "0x%" PFMT32x, core->blocksize) < 0) {
return;
}
sdb_set(db, "blocksize", buf);
}
RZ_API bool rz_serialize_core_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzCore *core, bool load_bin_io,
RZ_NULLABLE const char *prj_file, RZ_NULLABLE RzSerializeResultInfo *res) {
Sdb *subdb;
@ -79,7 +92,7 @@ RZ_API bool rz_serialize_core_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzCore *core,
if (load_bin_io) {
SUB("file", file_load(subdb, core, prj_file, res));
}
SUB("config", rz_serialize_config_load(subdb, core->config, config_exclude));
SUB("config", rz_serialize_config_load(subdb, core->config, config_exclude_load));
SUB("flags", rz_serialize_flag_load(subdb, core->flags, res));
SUB("marks", rz_serialize_mark_load(subdb, core->marks, res));
SUB("analysis", rz_serialize_analysis_load(subdb, core->analysis, res));

View file

@ -233,7 +233,7 @@ static inline bool rz_config_node_is_str(const RzConfigNode *node) {
/* serialize */
RZ_API void rz_serialize_config_save(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config);
RZ_API void rz_serialize_config_save(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config, RZ_NULLABLE const char **exclude);
RZ_API bool rz_serialize_config_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config, RZ_NULLABLE const char **exclude);
#endif

View file

@ -5,10 +5,12 @@
#include "minunit.h"
#include "test_sdb.h"
Sdb *ref_db() {
Sdb *ref_db(bool excluded) {
Sdb *db = sdb_new0();
sdb_set(db, "somestring", "somevalue");
sdb_set(db, "someint", "42");
if (!excluded) {
sdb_set(db, "somestring", "somevalue");
sdb_set(db, "someint", "42");
}
sdb_set(db, "somebiggerint", "0x00001337");
return db;
}
@ -20,10 +22,32 @@ bool test_config_save() {
rz_config_set_i(config, "somebiggerint", 0x1337);
Sdb *db = sdb_new0();
rz_serialize_config_save(db, config);
rz_serialize_config_save(db, config, NULL);
rz_config_free(config);
Sdb *expected = ref_db();
Sdb *expected = ref_db(false);
assert_sdb_eq(db, expected, "config save");
sdb_free(db);
sdb_free(expected);
mu_end;
}
bool test_config_save_exclude() {
static const char *exclude[] = {
"somestring",
"someint",
NULL
};
RzConfig *config = rz_config_new(NULL);
rz_config_set(config, "somestring", "somevalue");
rz_config_set_i(config, "someint", 42);
rz_config_set_i(config, "somebiggerint", 0x1337);
Sdb *db = sdb_new0();
rz_serialize_config_save(db, config, exclude);
rz_config_free(config);
Sdb *expected = ref_db(true);
assert_sdb_eq(db, expected, "config save");
sdb_free(db);
sdb_free(expected);
@ -36,7 +60,7 @@ bool test_config_load() {
rz_config_set_i(config, "someint", 0);
rz_config_set_i(config, "somebiggerint", 0);
Sdb *db = ref_db();
Sdb *db = ref_db(false);
sdb_set(db, "sneaky", "not part of config");
bool loaded = rz_serialize_config_load(db, config, NULL);
sdb_free(db);
@ -61,7 +85,7 @@ bool test_config_load_exclude() {
rz_config_set_i(config, "someint", 123);
rz_config_set_i(config, "somebiggerint", 0);
Sdb *db = ref_db();
Sdb *db = ref_db(false); // must load non-excluded here!
bool loaded = rz_serialize_config_load(db, config, exclude);
sdb_free(db);
mu_assert("load success", loaded);
@ -76,9 +100,10 @@ bool test_config_load_exclude() {
int all_tests() {
mu_run_test(test_config_save);
mu_run_test(test_config_save_exclude);
mu_run_test(test_config_load);
mu_run_test(test_config_load_exclude);
return tests_passed != tests_run;
}
mu_main(all_tests)
mu_main(all_tests)