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