@@ -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+
43113RZ_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 ;
0 commit comments