X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/e7eb3a2744aa45179daea235800753d3d1955338..b88fd7912fc173b50b4638fb1e25155999568990:/lib/trackdb.c diff --git a/lib/trackdb.c b/lib/trackdb.c index 42ba36e..5536b73 100644 --- a/lib/trackdb.c +++ b/lib/trackdb.c @@ -157,6 +157,13 @@ DB *trackdb_scheduledb; */ DB *trackdb_usersdb; +/** @brief The playlists database + * - Keys are playlist names + * - Values are encoded key-value pairs + * - Data is user data and cannot be reconstructed + */ +DB *trackdb_playlistsdb; + static pid_t db_deadlock_pid = -1; /* deadlock manager PID */ static pid_t rescan_pid = -1; /* rescanner PID */ static int initialized, opened; /* state */ @@ -354,7 +361,7 @@ static DB *open_db(const char *path, DBTYPE dbtype, u_int32_t openflags, int mode) { - int err; + int err, err2; DB *db; D(("open %s", path)); @@ -369,8 +376,14 @@ static DB *open_db(const char *path, fatal(0, "db->set_bt_compare %s: %s", path, db_strerror(err)); if((err = db->open(db, 0, path, 0, dbtype, openflags | DB_AUTO_COMMIT, mode))) { - if((openflags & DB_CREATE) || errno != ENOENT) + if((openflags & DB_CREATE) || errno != ENOENT) { + if((err2 = db->close(db, 0))) + error(0, "db->close: %s", db_strerror(err2)); + trackdb_close(); + trackdb_env->close(trackdb_env,0); + trackdb_env = 0; fatal(0, "db->open %s: %s", path, db_strerror(err)); + } db->close(db, 0); db = 0; } @@ -466,7 +479,8 @@ void trackdb_open(int flags) { trackdb_noticeddb = open_db("noticed.db", DB_DUPSORT, DB_BTREE, dbflags, 0666); trackdb_scheduledb = open_db("schedule.db", 0, DB_HASH, dbflags, 0666); - if(!trackdb_existing_database) { + trackdb_playlistsdb = open_db("playlists.db", 0, DB_HASH, dbflags, 0666); + if(!trackdb_existing_database && !(flags & TRACKDB_READ_ONLY)) { /* Stash the database version */ char buf[32]; @@ -484,24 +498,20 @@ void trackdb_close(void) { /* sanity checks */ assert(opened == 1); --opened; - if((err = trackdb_tracksdb->close(trackdb_tracksdb, 0))) - fatal(0, "error closing tracks.db: %s", db_strerror(err)); - if((err = trackdb_searchdb->close(trackdb_searchdb, 0))) - fatal(0, "error closing search.db: %s", db_strerror(err)); - if((err = trackdb_tagsdb->close(trackdb_tagsdb, 0))) - fatal(0, "error closing tags.db: %s", db_strerror(err)); - if((err = trackdb_prefsdb->close(trackdb_prefsdb, 0))) - fatal(0, "error closing prefs.db: %s", db_strerror(err)); - if((err = trackdb_globaldb->close(trackdb_globaldb, 0))) - fatal(0, "error closing global.db: %s", db_strerror(err)); - if((err = trackdb_noticeddb->close(trackdb_noticeddb, 0))) - fatal(0, "error closing noticed.db: %s", db_strerror(err)); - if((err = trackdb_scheduledb->close(trackdb_scheduledb, 0))) - fatal(0, "error closing schedule.db: %s", db_strerror(err)); - if((err = trackdb_usersdb->close(trackdb_usersdb, 0))) - fatal(0, "error closing users.db: %s", db_strerror(err)); - trackdb_tracksdb = trackdb_searchdb = trackdb_prefsdb = 0; - trackdb_tagsdb = trackdb_globaldb = 0; +#define CLOSE(N, V) do { \ + if(V && (err = V->close(V, 0))) \ + fatal(0, "error closing %s: %s", N, db_strerror(err)); \ + V = 0; \ +} while(0) + CLOSE("tracks.db", trackdb_tracksdb); + CLOSE("search.db", trackdb_searchdb); + CLOSE("tags.db", trackdb_tagsdb); + CLOSE("prefs.db", trackdb_prefsdb); + CLOSE("global.db", trackdb_globaldb); + CLOSE("noticed.db", trackdb_noticeddb); + CLOSE("schedule.db", trackdb_scheduledb); + CLOSE("users.db", trackdb_usersdb); + CLOSE("playlists.db", trackdb_playlistsdb); D(("closed databases")); } @@ -1399,7 +1409,9 @@ void trackdb_stats_subprocess(ev_source *ev, pid = subprogram(ev, p[1], "disorder-stats", (char *)0); xclose(p[1]); ev_child(ev, pid, 0, stats_finished, d); - ev_reader_new(ev, p[0], stats_read, stats_error, d, "disorder-stats reader"); + if(!ev_reader_new(ev, p[0], stats_read, stats_error, d, + "disorder-stats reader")) + fatal(0, "ev_reader_new for disorder-stats reader failed"); } /** @brief Parse a track name part preference @@ -1755,8 +1767,9 @@ int trackdb_request_random(ev_source *ev, choose_callback = callback; choose_output.nvec = 0; choose_complete = 0; - ev_reader_new(ev, p[0], choose_readable, choose_read_error, 0, - "disorder-choose reader"); /* owns p[0] */ + if(!ev_reader_new(ev, p[0], choose_readable, choose_read_error, 0, + "disorder-choose reader")) /* owns p[0] */ + fatal(0, "ev_reader_new for disorder-choose reader failed"); ev_child(ev, choose_pid, 0, choose_exited, 0); /* owns the subprocess */ return 0; } @@ -2246,7 +2259,7 @@ static int reap_rescan(ev_source attribute((unused)) *ev, * @param ev Event loop or 0 to block * @param recheck 1 to recheck lengths, 0 to suppress check * @param rescanned Called on completion (if not NULL) - * @param u Passed to @p rescanned + * @param ru Passed to @p rescanned */ void trackdb_rescan(ev_source *ev, int recheck, void (*rescanned)(void *ru), @@ -2549,8 +2562,10 @@ static int trusted(const char *user) { * Currently we only allow the letters and digits in ASCII. We could be more * liberal than this but it is a nice simple test. It is critical that * semicolons are never allowed. + * + * NB also used by playlist_parse_name() to validate playlist names! */ -static int valid_username(const char *user) { +int valid_username(const char *user) { if(!*user) return 0; while(*user) {