comparison libmlk-core/core/save.c @ 243:71b3b7036de7

misc: lot of cleanups, - prefix libraries with libmlk, - move assets from source directories closes #2520, - prefix header guards closes #2519
author David Demelier <markand@malikania.fr>
date Sat, 28 Nov 2020 22:37:30 +0100
parents libcore/core/save.c@76afe639fd72
children f978fa0137ce
comparison
equal deleted inserted replaced
242:4c24604efcab 243:71b3b7036de7
1 /*
2 * save.c -- save functions
3 *
4 * Copyright (c) 2020 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <assert.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <sqlite3.h>
25
26 #include <assets/sql/init.h>
27 #include <assets/sql/property-get.h>
28 #include <assets/sql/property-remove.h>
29 #include <assets/sql/property-set.h>
30
31 #include "core_p.h"
32 #include "error.h"
33 #include "save.h"
34 #include "sys.h"
35 #include "util.h"
36
37 #define SQL_BEGIN "BEGIN EXCLUSIVE TRANSACTION"
38 #define SQL_COMMIT "COMMIT"
39 #define SQL_ROLLBACK "ROLLBACK"
40
41 static bool
42 exec(struct save *db, const char *sql)
43 {
44 if (sqlite3_exec(db->handle, sql, NULL, NULL, NULL) != SQLITE_OK)
45 return errorf("%s", sqlite3_errmsg(db->handle));
46
47 return true;
48 }
49
50 static const char *
51 path(unsigned int idx)
52 {
53 return pprintf("%s/%u", sys_dir(SYS_DIR_SAVE), idx);
54 }
55
56 static bool
57 execu(struct save *db, const unsigned char *sql)
58 {
59 return exec(db, (const char *)sql);
60 }
61
62 bool
63 save_open(struct save *db, unsigned int idx, enum save_mode mode)
64 {
65 assert(db);
66
67 return save_open_path(db, path(idx), mode);
68 }
69
70 bool
71 verify(struct save *db)
72 {
73 struct {
74 time_t *date;
75 struct save_property prop;
76 } table[] = {
77 { .date = &db->created, { .key = "molko.create-date" } },
78 { .date = &db->updated, { .key = "molko.update-date" } },
79 };
80
81 /* Ensure create and update dates are present. */
82 for (size_t i = 0; i < NELEM(table); ++i) {
83 if (!save_get_property(db, &table[i].prop)) {
84 sqlite3_close(db->handle);
85 return errorf(_("database not initialized correctly"));
86 }
87
88 *table[i].date = strtoull(table[i].prop.value, NULL, 10);
89 }
90
91 return true;
92 }
93
94 bool
95 save_open_path(struct save *db, const char *path, enum save_mode mode)
96 {
97 assert(db);
98 assert(path);
99
100 int flags = 0;
101
102 switch (mode) {
103 case SAVE_MODE_WRITE:
104 flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
105 break;
106 default:
107 flags = SQLITE_OPEN_READONLY;
108 break;
109 }
110
111 if (sqlite3_open_v2(path, (sqlite3**)&db->handle, flags, NULL) != SQLITE_OK)
112 return errorf("%s", sqlite3_errmsg(db->handle));
113
114 if (mode == SAVE_MODE_WRITE) {
115 if (!execu(db, sql_init)) {
116 sqlite3_close(db->handle);
117 return false;
118 }
119 }
120
121 return verify(db);
122 }
123
124 bool
125 save_set_property(struct save *db, const struct save_property *prop)
126 {
127 assert(db);
128 assert(prop);
129
130 sqlite3_stmt *stmt = NULL;
131
132 if (!exec(db, SQL_BEGIN))
133 return false;
134 if (sqlite3_prepare(db->handle, (const char *)sql_property_set, -1, &stmt, NULL) != SQLITE_OK)
135 goto sqlite3_err;
136 if (sqlite3_bind_text(stmt, 1, prop->key, -1, NULL) != SQLITE_OK ||
137 sqlite3_bind_text(stmt, 2, prop->value, -1, NULL) != SQLITE_OK)
138 goto sqlite3_err;
139 if (sqlite3_step(stmt) != SQLITE_DONE)
140 goto sqlite3_err;
141
142 sqlite3_finalize(stmt);
143
144 return exec(db, SQL_COMMIT);
145
146 sqlite3_err:
147 errorf("%s", sqlite3_errmsg(db->handle));
148
149 if (stmt)
150 sqlite3_finalize(stmt);
151
152 exec(db, SQL_ROLLBACK);
153
154 return false;
155 }
156
157 bool
158 save_get_property(struct save *db, struct save_property *prop)
159 {
160 assert(db);
161 assert(prop);
162
163 sqlite3_stmt *stmt = NULL;
164 bool ret = true;
165
166 if (sqlite3_prepare(db->handle, (const char *)sql_property_get,
167 sizeof (sql_property_get), &stmt, NULL) != SQLITE_OK)
168 goto sqlite3_err;
169 if (sqlite3_bind_text(stmt, 1, prop->key, -1, NULL) != SQLITE_OK)
170 goto sqlite3_err;
171
172 switch (sqlite3_step(stmt)) {
173 case SQLITE_DONE:
174 /* Not found. */
175 ret = errorf(_("property '%s' was not found"), prop->key);
176 break;
177 case SQLITE_ROW:
178 /* Found. */
179 snprintf(prop->value, sizeof (prop->value), "%s", sqlite3_column_text(stmt, 0));
180 break;
181 default:
182 /* Error. */
183 goto sqlite3_err;
184 }
185
186 sqlite3_finalize(stmt);
187
188 return ret;
189
190 sqlite3_err:
191 errorf("%s", sqlite3_errmsg(db->handle));
192
193 if (stmt)
194 sqlite3_finalize(stmt);
195
196 return false;
197 }
198
199 bool
200 save_remove_property(struct save *db, const struct save_property *prop)
201 {
202 assert(db);
203 assert(prop);
204
205 sqlite3_stmt *stmt = NULL;
206
207 if (!exec(db, SQL_BEGIN))
208 return false;
209 if (sqlite3_prepare(db->handle, (const char *)sql_property_remove,
210 sizeof (sql_property_remove), &stmt, NULL) != SQLITE_OK)
211 goto sqlite3_err;
212 if (sqlite3_bind_text(stmt, 1, prop->key, -1, NULL) != SQLITE_OK)
213 goto sqlite3_err;
214 if (sqlite3_step(stmt) != SQLITE_DONE)
215 goto sqlite3_err;
216
217 sqlite3_finalize(stmt);
218
219 return exec(db, SQL_COMMIT);
220
221 sqlite3_err:
222 errorf("%s", sqlite3_errmsg(db->handle));
223
224 if (stmt)
225 sqlite3_finalize(stmt);
226
227 exec(db, SQL_ROLLBACK);
228
229 return false;
230 }
231
232 void
233 save_finish(struct save *db)
234 {
235 assert(db);
236
237 if (db->handle)
238 sqlite3_close(db->handle);
239
240 memset(db, 0, sizeof (*db));
241 }