Mercurial > paster
comparison database.c @ 38:48834441dc86
pasterd: generate smaller identifiers, closes #2480 @1h
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 12 Feb 2020 20:55:00 +0100 |
parents | 4f60cf394839 |
children | 62361336c415 |
comparison
equal
deleted
inserted
replaced
37:e05b26209ad3 | 38:48834441dc86 |
---|---|
114 dup(const unsigned char *s) | 114 dup(const unsigned char *s) |
115 { | 115 { |
116 return estrdup(s ? (const char *)(s) : ""); | 116 return estrdup(s ? (const char *)(s) : ""); |
117 } | 117 } |
118 | 118 |
119 static const char * | |
120 create_id(void) | |
121 { | |
122 static char uuid[256]; | |
123 | |
124 /* | |
125 * Not a very strong generation but does not require to link against | |
126 * util-linux. | |
127 * | |
128 * See https://stackoverflow.com/questions/2174768/generating-random-uuids-in-linux | |
129 */ | |
130 sprintf(uuid, "%x%x-%x-%x-%x-%x%x%x", | |
131 rand(), rand(), | |
132 rand(), | |
133 ((rand() & 0x0fff) | 0x4000), | |
134 rand() % 0x3fff + 0x8000, | |
135 rand(), rand(), rand()); | |
136 | |
137 return uuid; | |
138 } | |
139 | |
140 static void | 119 static void |
141 convert(sqlite3_stmt *stmt, struct paste *paste) | 120 convert(sqlite3_stmt *stmt, struct paste *paste) |
142 { | 121 { |
143 paste->uuid = dup(sqlite3_column_text(stmt, 0)); | 122 paste->id = dup(sqlite3_column_text(stmt, 0)); |
144 paste->title = dup(sqlite3_column_text(stmt, 1)); | 123 paste->title = dup(sqlite3_column_text(stmt, 1)); |
145 paste->author = dup(sqlite3_column_text(stmt, 2)); | 124 paste->author = dup(sqlite3_column_text(stmt, 2)); |
146 paste->language = dup(sqlite3_column_text(stmt, 3)); | 125 paste->language = dup(sqlite3_column_text(stmt, 3)); |
147 paste->code = dup(sqlite3_column_text(stmt, 4)); | 126 paste->code = dup(sqlite3_column_text(stmt, 4)); |
148 paste->timestamp = sqlite3_column_int64(stmt, 5); | 127 paste->timestamp = sqlite3_column_int64(stmt, 5); |
149 paste->visible = sqlite3_column_int(stmt, 6); | 128 paste->visible = sqlite3_column_int(stmt, 6); |
150 paste->duration = sqlite3_column_int64(stmt, 7); | 129 paste->duration = sqlite3_column_int64(stmt, 7); |
151 } | 130 } |
152 | 131 |
132 static bool | |
133 exists(const char *id) | |
134 { | |
135 assert(id); | |
136 | |
137 sqlite3_stmt *stmt = NULL; | |
138 bool ret = false; | |
139 | |
140 if (sqlite3_prepare(db, sql_get, -1, &stmt, NULL) != SQLITE_OK) { | |
141 log_warn("database: error (exists): %s", sqlite3_errmsg(db)); | |
142 return false; | |
143 } | |
144 | |
145 ret = sqlite3_step(stmt) == SQLITE_ROW; | |
146 sqlite3_finalize(stmt); | |
147 | |
148 return ret; | |
149 } | |
150 | |
151 static const char * | |
152 create_id(void) | |
153 { | |
154 static const char table[] = "abcdefghijklmnopqrstuvwxyz1234567890"; | |
155 static char id[12]; | |
156 | |
157 for (int i = 0; i < sizeof (id); ++i) | |
158 id[i] = table[rand() % (sizeof (table))]; | |
159 | |
160 return id; | |
161 } | |
162 | |
163 static bool | |
164 set_id(struct paste *paste) | |
165 { | |
166 assert(paste); | |
167 | |
168 paste->id = NULL; | |
169 | |
170 /* | |
171 * Avoid infinite loop, we only try to create a new id in 30 steps. | |
172 */ | |
173 int tries = 0; | |
174 | |
175 do { | |
176 free(paste->id); | |
177 paste->id = estrdup(create_id()); | |
178 } while (++tries < 30 && exists(paste->id)); | |
179 | |
180 return tries < 30; | |
181 } | |
182 | |
153 bool | 183 bool |
154 database_open(const char *path) | 184 database_open(const char *path) |
155 { | 185 { |
156 assert(path); | 186 assert(path); |
157 | 187 |
250 bool | 280 bool |
251 database_insert(struct paste *paste) | 281 database_insert(struct paste *paste) |
252 { | 282 { |
253 assert(paste); | 283 assert(paste); |
254 | 284 |
255 sqlite3_stmt* stmt = NULL; | 285 sqlite3_stmt *stmt = NULL; |
286 | |
256 log_debug("database: creating new paste"); | 287 log_debug("database: creating new paste"); |
257 | 288 |
258 if (sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL, NULL) != SQLITE_OK) { | 289 if (sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL, NULL) != SQLITE_OK) { |
259 log_warn("database: could not lock database: %s", sqlite3_errmsg(db)); | 290 log_warn("database: could not lock database: %s", sqlite3_errmsg(db)); |
260 return false; | 291 return false; |
261 } | 292 } |
262 | 293 |
294 if (!set_id(paste)) { | |
295 log_warn("database: unable to randomize unique identifier"); | |
296 sqlite3_exec(db, "END TRANSACTION", NULL, NULL, NULL); | |
297 return false; | |
298 } | |
299 | |
263 if (sqlite3_prepare(db, sql_insert, -1, &stmt, NULL) != SQLITE_OK) | 300 if (sqlite3_prepare(db, sql_insert, -1, &stmt, NULL) != SQLITE_OK) |
264 goto sqlite_err; | 301 goto sqlite_err; |
265 | 302 |
266 /* Create a new uuid first. */ | 303 sqlite3_bind_text(stmt, 1, paste->id, -1, SQLITE_STATIC); |
267 paste->uuid = estrdup(create_id()); | |
268 | |
269 sqlite3_bind_text(stmt, 1, paste->uuid, -1, SQLITE_STATIC); | |
270 sqlite3_bind_text(stmt, 2, paste->title, -1, SQLITE_STATIC); | 304 sqlite3_bind_text(stmt, 2, paste->title, -1, SQLITE_STATIC); |
271 sqlite3_bind_text(stmt, 3, paste->author, -1, SQLITE_STATIC); | 305 sqlite3_bind_text(stmt, 3, paste->author, -1, SQLITE_STATIC); |
272 sqlite3_bind_text(stmt, 4, paste->language, -1, SQLITE_STATIC); | 306 sqlite3_bind_text(stmt, 4, paste->language, -1, SQLITE_STATIC); |
273 sqlite3_bind_text(stmt, 5, paste->code, -1, SQLITE_STATIC); | 307 sqlite3_bind_text(stmt, 5, paste->code, -1, SQLITE_STATIC); |
274 sqlite3_bind_int(stmt, 6, paste->visible); | 308 sqlite3_bind_int(stmt, 6, paste->visible); |
279 | 313 |
280 sqlite3_exec(db, "COMMIT", NULL, NULL, NULL); | 314 sqlite3_exec(db, "COMMIT", NULL, NULL, NULL); |
281 sqlite3_finalize(stmt); | 315 sqlite3_finalize(stmt); |
282 | 316 |
283 log_info("database: new paste (%s) from %s expires in one %lld seconds", | 317 log_info("database: new paste (%s) from %s expires in one %lld seconds", |
284 paste->uuid, paste->author, paste->duration); | 318 paste->id, paste->author, paste->duration); |
285 | 319 |
286 return true; | 320 return true; |
287 | 321 |
288 sqlite_err: | 322 sqlite_err: |
289 log_warn("database: error (insert): %s", sqlite3_errmsg(db)); | 323 log_warn("database: error (insert): %s", sqlite3_errmsg(db)); |
290 sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); | 324 sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); |
291 | 325 |
292 if (stmt) | 326 if (stmt) |
293 sqlite3_finalize(stmt); | 327 sqlite3_finalize(stmt); |
294 | 328 |
295 free(paste->uuid); | 329 free(paste->id); |
296 paste->uuid = NULL; | 330 paste->id = NULL; |
297 | 331 |
298 return false; | 332 return false; |
299 } | 333 } |
300 | 334 |
301 bool | 335 bool |