Mercurial > paster
diff 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 |
line wrap: on
line diff
--- a/database.c Wed Feb 12 20:45:00 2020 +0100 +++ b/database.c Wed Feb 12 20:55:00 2020 +0100 @@ -116,31 +116,10 @@ return estrdup(s ? (const char *)(s) : ""); } -static const char * -create_id(void) -{ - static char uuid[256]; - - /* - * Not a very strong generation but does not require to link against - * util-linux. - * - * See https://stackoverflow.com/questions/2174768/generating-random-uuids-in-linux - */ - sprintf(uuid, "%x%x-%x-%x-%x-%x%x%x", - rand(), rand(), - rand(), - ((rand() & 0x0fff) | 0x4000), - rand() % 0x3fff + 0x8000, - rand(), rand(), rand()); - - return uuid; -} - static void convert(sqlite3_stmt *stmt, struct paste *paste) { - paste->uuid = dup(sqlite3_column_text(stmt, 0)); + paste->id = dup(sqlite3_column_text(stmt, 0)); paste->title = dup(sqlite3_column_text(stmt, 1)); paste->author = dup(sqlite3_column_text(stmt, 2)); paste->language = dup(sqlite3_column_text(stmt, 3)); @@ -150,6 +129,57 @@ paste->duration = sqlite3_column_int64(stmt, 7); } +static bool +exists(const char *id) +{ + assert(id); + + sqlite3_stmt *stmt = NULL; + bool ret = false; + + if (sqlite3_prepare(db, sql_get, -1, &stmt, NULL) != SQLITE_OK) { + log_warn("database: error (exists): %s", sqlite3_errmsg(db)); + return false; + } + + ret = sqlite3_step(stmt) == SQLITE_ROW; + sqlite3_finalize(stmt); + + return ret; +} + +static const char * +create_id(void) +{ + static const char table[] = "abcdefghijklmnopqrstuvwxyz1234567890"; + static char id[12]; + + for (int i = 0; i < sizeof (id); ++i) + id[i] = table[rand() % (sizeof (table))]; + + return id; +} + +static bool +set_id(struct paste *paste) +{ + assert(paste); + + paste->id = NULL; + + /* + * Avoid infinite loop, we only try to create a new id in 30 steps. + */ + int tries = 0; + + do { + free(paste->id); + paste->id = estrdup(create_id()); + } while (++tries < 30 && exists(paste->id)); + + return tries < 30; +} + bool database_open(const char *path) { @@ -252,7 +282,8 @@ { assert(paste); - sqlite3_stmt* stmt = NULL; + sqlite3_stmt *stmt = NULL; + log_debug("database: creating new paste"); if (sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL, NULL) != SQLITE_OK) { @@ -260,13 +291,16 @@ return false; } + if (!set_id(paste)) { + log_warn("database: unable to randomize unique identifier"); + sqlite3_exec(db, "END TRANSACTION", NULL, NULL, NULL); + return false; + } + if (sqlite3_prepare(db, sql_insert, -1, &stmt, NULL) != SQLITE_OK) goto sqlite_err; - /* Create a new uuid first. */ - paste->uuid = estrdup(create_id()); - - sqlite3_bind_text(stmt, 1, paste->uuid, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 1, paste->id, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, paste->title, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 3, paste->author, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 4, paste->language, -1, SQLITE_STATIC); @@ -281,7 +315,7 @@ sqlite3_finalize(stmt); log_info("database: new paste (%s) from %s expires in one %lld seconds", - paste->uuid, paste->author, paste->duration); + paste->id, paste->author, paste->duration); return true; @@ -292,8 +326,8 @@ if (stmt) sqlite3_finalize(stmt); - free(paste->uuid); - paste->uuid = NULL; + free(paste->id); + paste->id = NULL; return false; }