Skip to content

Commit b1693c9

Browse files
committed
Implement backup on overwriting migrated file (#5533)
1 parent ec7f117 commit b1693c9

File tree

11 files changed

+176
-5
lines changed

11 files changed

+176
-5
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ peda-session-*
117117
.cache/
118118
test/.tmp/*
119119
test/.sync_disk_db
120+
test/prj/.*.BAK
120121
subprojects/.wraplock
121122
subprojects/capstone-*/
122123
subprojects/pcre2*/

librz/core/core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,6 +1885,7 @@ RZ_API void rz_core_fini(RzCore *c) {
18851885
RZ_FREE_CUSTOM(c->warnings_after, rz_list_free);
18861886
RZ_FREE_CUSTOM(c->sys_path, rz_path_free);
18871887
RZ_FREE_CUSTOM(c->marks, rz_mark_free);
1888+
RZ_FREE_CUSTOM(c->backup, sdb_free);
18881889
}
18891890

18901891
RZ_API void rz_core_free(RzCore *c) {

librz/core/project.c

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,76 @@ RZ_API RzProjectErr rz_project_save(RzCore *core, RzProject *prj, const char *fi
4040
return RZ_PROJECT_ERR_SUCCESS;
4141
}
4242

43+
static unsigned long rz_project_get_version(RzProject *prj) {
44+
const char *version_str = sdb_const_get(prj, RZ_PROJECT_KEY_VERSION);
45+
if (!version_str) {
46+
return ULONG_MAX;
47+
}
48+
return strtoul(version_str, NULL, 0);
49+
}
50+
51+
RZ_API RzProjectErr rz_project_save_backup_file(RzCore *core, const char *file, bool compress) {
52+
char *tmp_file = NULL;
53+
if (!core->backup) {
54+
/* No backup necessary */
55+
return RZ_PROJECT_ERR_SUCCESS;
56+
}
57+
58+
if (compress) {
59+
int mkstemp_fd = rz_file_mkstemp("svprjbu", &tmp_file);
60+
if (mkstemp_fd == -1 || !tmp_file) {
61+
return RZ_PROJECT_ERR_FILE;
62+
}
63+
close(mkstemp_fd);
64+
}
65+
66+
char *dst_path = NULL;
67+
const char *basename = rz_file_basename(file);
68+
char *dirname = rz_file_dirname(file);
69+
unsigned long version = rz_project_get_version(core->backup);
70+
if (!version || version == ULONG_MAX) {
71+
free(dirname);
72+
return RZ_PROJECT_ERR_INVALID_VERSION;
73+
}
74+
75+
int dst_path_len = snprintf(NULL, 0, "%s/.%s_%ld.BAK", dirname, basename, version);
76+
if (dst_path_len < 0) {
77+
free(dirname);
78+
return RZ_PROJECT_ERR_UNKNOWN;
79+
}
80+
81+
dst_path_len++;
82+
dst_path = calloc(dst_path_len, 1);
83+
if (dst_path == NULL) {
84+
free(dirname);
85+
return RZ_PROJECT_ERR_UNKNOWN;
86+
}
87+
88+
if (strlen(dirname) > 0) {
89+
snprintf(dst_path, dst_path_len, "%s/.%s_%ld.BAK", dirname, basename, version);
90+
} else {
91+
snprintf(dst_path, dst_path_len, ".%s_%ld.BAK", basename, version);
92+
}
93+
94+
free(dirname);
95+
96+
const char *save_file = compress ? tmp_file : dst_path;
97+
RzProjectErr err = RZ_PROJECT_ERR_SUCCESS;
98+
99+
if (!sdb_text_save(core->backup, save_file, true)) {
100+
err = RZ_PROJECT_ERR_FILE;
101+
goto tmp_file_err;
102+
}
103+
104+
if (compress && !rz_file_deflate(tmp_file, dst_path)) {
105+
err = RZ_PROJECT_ERR_COMPRESSION_FAILED;
106+
}
107+
108+
tmp_file_err:
109+
free(dst_path);
110+
return err;
111+
}
112+
43113
RZ_API RzProjectErr rz_project_save_file(RzCore *core, const char *file, bool compress) {
44114
char *tmp_file = NULL;
45115

@@ -137,11 +207,7 @@ RZ_API RzProjectErr rz_project_load(RzCore *core, RzProject *prj, bool load_bin_
137207
if (!type || strcmp(type, RZ_PROJECT_TYPE) != 0) {
138208
return RZ_PROJECT_ERR_INVALID_TYPE;
139209
}
140-
const char *version_str = sdb_const_get(prj, RZ_PROJECT_KEY_VERSION);
141-
if (!version_str) {
142-
return RZ_PROJECT_ERR_INVALID_VERSION;
143-
}
144-
unsigned long version = strtoul(version_str, NULL, 0);
210+
unsigned long version = rz_project_get_version(prj);
145211
if (!version || version == ULONG_MAX) {
146212
return RZ_PROJECT_ERR_INVALID_VERSION;
147213
}
@@ -161,6 +227,11 @@ RZ_API RzProjectErr rz_project_load(RzCore *core, RzProject *prj, bool load_bin_
161227
return RZ_PROJECT_ERR_INVALID_CONTENTS;
162228
}
163229

230+
if (prj->backup) {
231+
prj->backup->refs++;
232+
core->backup = prj->backup;
233+
}
234+
164235
rz_config_set(core->config, "prj.file", file);
165236

166237
return RZ_PROJECT_ERR_SUCCESS;

librz/core/project_migrate.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,12 @@ static bool (*const migrations[])(RzProject *prj, RzSerializeResultInfo *res) =
759759
/// Migrate the given project to the current version in-place
760760
RZ_API bool rz_project_migrate(RzProject *prj, unsigned long version, RzSerializeResultInfo *res) {
761761
RZ_STATIC_ASSERT(RZ_ARRAY_SIZE(migrations) + 1 == RZ_PROJECT_VERSION);
762+
763+
if (prj->backup == NULL) {
764+
prj->backup = sdb_new0();
765+
sdb_copy(prj, prj->backup);
766+
}
767+
762768
while (version < RZ_PROJECT_VERSION) {
763769
bool succ = migrations[version - 1](prj, res);
764770
if (!succ) {

librz/include/rz_core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ struct rz_core_t {
398398
int (*rz_main_rz_gg)(int argc, const char **argv);
399399
int (*rz_main_rz_asm)(int argc, const char **argv);
400400
int (*rz_main_rz_ax)(int argc, const char **argv);
401+
402+
Sdb *backup;
401403
};
402404

403405
// maybe move into RzAnalysis

librz/include/rz_project.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ typedef enum rz_project_err {
3030

3131
RZ_API RZ_NONNULL const char *rz_project_err_message(RzProjectErr err);
3232
RZ_API RzProjectErr rz_project_save(RzCore *core, RzProject *prj, const char *file);
33+
RZ_API RzProjectErr rz_project_save_backup_file(RzCore *core, const char *file, bool compress);
3334
RZ_API RzProjectErr rz_project_save_file(RzCore *core, const char *file, bool compress);
3435
RZ_API RzProject *rz_project_load_file_raw(const char *file);
3536
RZ_API void rz_project_free(RzProject *prj);

librz/main/rizin.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,11 +1444,13 @@ RZ_API int rz_main_rizin(int argc, const char **argv) {
14441444
if (no_question_save) {
14451445
if (prj && *prj && y_save_project) {
14461446
prj_err = rz_project_save_file(r, prj, compress);
1447+
rz_project_save_backup_file(r, prj, compress);
14471448
}
14481449
} else {
14491450
question = rz_str_newf("Do you want to save the '%s' project? (Y/n)", prj);
14501451
if (prj && *prj && rz_cons_yesno('y', "%s", question)) {
14511452
prj_err = rz_project_save_file(r, prj, compress);
1453+
rz_project_save_backup_file(r, prj, compress);
14521454
}
14531455
free(question);
14541456
}

librz/util/sdb/src/sdb.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ static void sdb_fini(Sdb *s, int donull) {
194194
free(s->ndump);
195195
free(s->dir);
196196
if (donull) {
197+
if (s->backup) {
198+
sdb_free(s->backup);
199+
};
197200
memset(s, 0, sizeof(Sdb));
198201
}
199202
}

librz/util/sdb/src/sdb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ typedef struct sdb_t {
8181
int ns_lock; // TODO: merge into options?
8282
RzList /*<SdbNs *>*/ *ns;
8383
ut32 depth;
84+
struct sdb_t *backup;
8485
} Sdb;
8586

8687
typedef struct sdb_ns_t {

test/integration/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ if get_option('enable_tests') and cli_enabled
2525
'dwarf_integration',
2626
'glibc_version',
2727
'open_analyse_save_load_project',
28+
'open_migrate_backup_compare_project',
2829
'pdb',
2930
'project_migrate',
3031
'rzpipe',

0 commit comments

Comments
 (0)