153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2009 Lennart Poettering 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 853a5a1b3Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of the 953a5a1b3Sopenharmony_ci License, or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci Lesser General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public 1753a5a1b3Sopenharmony_ci License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci#include <fcntl.h> 2553a5a1b3Sopenharmony_ci#include <unistd.h> 2653a5a1b3Sopenharmony_ci#include <errno.h> 2753a5a1b3Sopenharmony_ci 2853a5a1b3Sopenharmony_ci/* Some versions of tdb lack inclusion of signal.h in the header files but use sigatomic_t */ 2953a5a1b3Sopenharmony_ci#include <signal.h> 3053a5a1b3Sopenharmony_ci#include <tdb.h> 3153a5a1b3Sopenharmony_ci 3253a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3353a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 3453a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 3553a5a1b3Sopenharmony_ci 3653a5a1b3Sopenharmony_ci#include "database.h" 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci#define MAKE_TDB_CONTEXT(x) ((struct tdb_context*) (x)) 3953a5a1b3Sopenharmony_ci 4053a5a1b3Sopenharmony_cistatic inline TDB_DATA* datum_to_tdb(TDB_DATA *to, const pa_datum *from) { 4153a5a1b3Sopenharmony_ci pa_assert(from); 4253a5a1b3Sopenharmony_ci pa_assert(to); 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_ci to->dptr = from->data; 4553a5a1b3Sopenharmony_ci to->dsize = from->size; 4653a5a1b3Sopenharmony_ci 4753a5a1b3Sopenharmony_ci return to; 4853a5a1b3Sopenharmony_ci} 4953a5a1b3Sopenharmony_ci 5053a5a1b3Sopenharmony_cistatic inline pa_datum* datum_from_tdb(pa_datum *to, const TDB_DATA *from) { 5153a5a1b3Sopenharmony_ci pa_assert(from); 5253a5a1b3Sopenharmony_ci pa_assert(to); 5353a5a1b3Sopenharmony_ci 5453a5a1b3Sopenharmony_ci to->data = from->dptr; 5553a5a1b3Sopenharmony_ci to->size = from->dsize; 5653a5a1b3Sopenharmony_ci 5753a5a1b3Sopenharmony_ci return to; 5853a5a1b3Sopenharmony_ci} 5953a5a1b3Sopenharmony_ci 6053a5a1b3Sopenharmony_civoid pa_datum_free(pa_datum *d) { 6153a5a1b3Sopenharmony_ci pa_assert(d); 6253a5a1b3Sopenharmony_ci 6353a5a1b3Sopenharmony_ci free(d->data); /* tdb uses raw malloc/free hence we should do that here, too */ 6453a5a1b3Sopenharmony_ci pa_zero(d); 6553a5a1b3Sopenharmony_ci} 6653a5a1b3Sopenharmony_ci 6753a5a1b3Sopenharmony_cistatic struct tdb_context *tdb_open_cloexec( 6853a5a1b3Sopenharmony_ci const char *name, 6953a5a1b3Sopenharmony_ci int hash_size, 7053a5a1b3Sopenharmony_ci int tdb_flags, 7153a5a1b3Sopenharmony_ci int open_flags, 7253a5a1b3Sopenharmony_ci mode_t mode) { 7353a5a1b3Sopenharmony_ci 7453a5a1b3Sopenharmony_ci /* Mimics pa_open_cloexec() */ 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_ci struct tdb_context *c; 7753a5a1b3Sopenharmony_ci 7853a5a1b3Sopenharmony_ci#ifdef O_NOCTTY 7953a5a1b3Sopenharmony_ci open_flags |= O_NOCTTY; 8053a5a1b3Sopenharmony_ci#endif 8153a5a1b3Sopenharmony_ci 8253a5a1b3Sopenharmony_ci#ifdef O_CLOEXEC 8353a5a1b3Sopenharmony_ci errno = 0; 8453a5a1b3Sopenharmony_ci if ((c = tdb_open(name, hash_size, tdb_flags, open_flags | O_CLOEXEC, mode))) 8553a5a1b3Sopenharmony_ci goto finish; 8653a5a1b3Sopenharmony_ci 8753a5a1b3Sopenharmony_ci if (errno != EINVAL) 8853a5a1b3Sopenharmony_ci return NULL; 8953a5a1b3Sopenharmony_ci#endif 9053a5a1b3Sopenharmony_ci 9153a5a1b3Sopenharmony_ci errno = 0; 9253a5a1b3Sopenharmony_ci if (!(c = tdb_open(name, hash_size, tdb_flags, open_flags, mode))) 9353a5a1b3Sopenharmony_ci return NULL; 9453a5a1b3Sopenharmony_ci 9553a5a1b3Sopenharmony_cifinish: 9653a5a1b3Sopenharmony_ci pa_make_fd_cloexec(tdb_fd(c)); 9753a5a1b3Sopenharmony_ci return c; 9853a5a1b3Sopenharmony_ci} 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ciconst char* pa_database_get_filename_suffix(void) { 10153a5a1b3Sopenharmony_ci return ".tdb"; 10253a5a1b3Sopenharmony_ci} 10353a5a1b3Sopenharmony_ci 10453a5a1b3Sopenharmony_cipa_database* pa_database_open_internal(const char *path, bool for_write) { 10553a5a1b3Sopenharmony_ci struct tdb_context *c; 10653a5a1b3Sopenharmony_ci 10753a5a1b3Sopenharmony_ci pa_assert(path); 10853a5a1b3Sopenharmony_ci 10953a5a1b3Sopenharmony_ci if ((c = tdb_open_cloexec(path, 0, TDB_NOSYNC|TDB_NOLOCK, (for_write ? O_RDWR|O_CREAT : O_RDONLY), 0644))) 11053a5a1b3Sopenharmony_ci pa_log_debug("Opened TDB database '%s'", path); 11153a5a1b3Sopenharmony_ci 11253a5a1b3Sopenharmony_ci if (!c) { 11353a5a1b3Sopenharmony_ci if (errno == 0) 11453a5a1b3Sopenharmony_ci errno = EIO; 11553a5a1b3Sopenharmony_ci return NULL; 11653a5a1b3Sopenharmony_ci } 11753a5a1b3Sopenharmony_ci 11853a5a1b3Sopenharmony_ci return (pa_database*) c; 11953a5a1b3Sopenharmony_ci} 12053a5a1b3Sopenharmony_ci 12153a5a1b3Sopenharmony_civoid pa_database_close(pa_database *db) { 12253a5a1b3Sopenharmony_ci pa_assert(db); 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_ci tdb_close(MAKE_TDB_CONTEXT(db)); 12553a5a1b3Sopenharmony_ci} 12653a5a1b3Sopenharmony_ci 12753a5a1b3Sopenharmony_cipa_datum* pa_database_get(pa_database *db, const pa_datum *key, pa_datum* data) { 12853a5a1b3Sopenharmony_ci TDB_DATA tdb_key, tdb_data; 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci pa_assert(db); 13153a5a1b3Sopenharmony_ci pa_assert(key); 13253a5a1b3Sopenharmony_ci pa_assert(data); 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci tdb_data = tdb_fetch(MAKE_TDB_CONTEXT(db), *datum_to_tdb(&tdb_key, key)); 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci return tdb_data.dptr ? 13753a5a1b3Sopenharmony_ci datum_from_tdb(data, &tdb_data) : 13853a5a1b3Sopenharmony_ci NULL; 13953a5a1b3Sopenharmony_ci} 14053a5a1b3Sopenharmony_ci 14153a5a1b3Sopenharmony_ciint pa_database_set(pa_database *db, const pa_datum *key, const pa_datum* data, bool overwrite) { 14253a5a1b3Sopenharmony_ci TDB_DATA tdb_key, tdb_data; 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_ci pa_assert(db); 14553a5a1b3Sopenharmony_ci pa_assert(key); 14653a5a1b3Sopenharmony_ci pa_assert(data); 14753a5a1b3Sopenharmony_ci 14853a5a1b3Sopenharmony_ci return tdb_store(MAKE_TDB_CONTEXT(db), 14953a5a1b3Sopenharmony_ci *datum_to_tdb(&tdb_key, key), 15053a5a1b3Sopenharmony_ci *datum_to_tdb(&tdb_data, data), 15153a5a1b3Sopenharmony_ci overwrite ? TDB_REPLACE : TDB_INSERT) != 0 ? -1 : 0; 15253a5a1b3Sopenharmony_ci} 15353a5a1b3Sopenharmony_ci 15453a5a1b3Sopenharmony_ciint pa_database_unset(pa_database *db, const pa_datum *key) { 15553a5a1b3Sopenharmony_ci TDB_DATA tdb_key; 15653a5a1b3Sopenharmony_ci 15753a5a1b3Sopenharmony_ci pa_assert(db); 15853a5a1b3Sopenharmony_ci pa_assert(key); 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci return tdb_delete(MAKE_TDB_CONTEXT(db), *datum_to_tdb(&tdb_key, key)) != 0 ? -1 : 0; 16153a5a1b3Sopenharmony_ci} 16253a5a1b3Sopenharmony_ci 16353a5a1b3Sopenharmony_ciint pa_database_clear(pa_database *db) { 16453a5a1b3Sopenharmony_ci pa_assert(db); 16553a5a1b3Sopenharmony_ci 16653a5a1b3Sopenharmony_ci return tdb_wipe_all(MAKE_TDB_CONTEXT(db)) != 0 ? -1 : 0; 16753a5a1b3Sopenharmony_ci} 16853a5a1b3Sopenharmony_ci 16953a5a1b3Sopenharmony_cisigned pa_database_size(pa_database *db) { 17053a5a1b3Sopenharmony_ci TDB_DATA tdb_key; 17153a5a1b3Sopenharmony_ci unsigned n = 0; 17253a5a1b3Sopenharmony_ci 17353a5a1b3Sopenharmony_ci pa_assert(db); 17453a5a1b3Sopenharmony_ci 17553a5a1b3Sopenharmony_ci /* This sucks */ 17653a5a1b3Sopenharmony_ci 17753a5a1b3Sopenharmony_ci tdb_key = tdb_firstkey(MAKE_TDB_CONTEXT(db)); 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci while (tdb_key.dptr) { 18053a5a1b3Sopenharmony_ci TDB_DATA next; 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_ci n++; 18353a5a1b3Sopenharmony_ci 18453a5a1b3Sopenharmony_ci next = tdb_nextkey(MAKE_TDB_CONTEXT(db), tdb_key); 18553a5a1b3Sopenharmony_ci free(tdb_key.dptr); 18653a5a1b3Sopenharmony_ci tdb_key = next; 18753a5a1b3Sopenharmony_ci } 18853a5a1b3Sopenharmony_ci 18953a5a1b3Sopenharmony_ci return (signed) n; 19053a5a1b3Sopenharmony_ci} 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_cipa_datum* pa_database_first(pa_database *db, pa_datum *key, pa_datum *data) { 19353a5a1b3Sopenharmony_ci TDB_DATA tdb_key, tdb_data; 19453a5a1b3Sopenharmony_ci 19553a5a1b3Sopenharmony_ci pa_assert(db); 19653a5a1b3Sopenharmony_ci pa_assert(key); 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_ci tdb_key = tdb_firstkey(MAKE_TDB_CONTEXT(db)); 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci if (!tdb_key.dptr) 20153a5a1b3Sopenharmony_ci return NULL; 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci if (data) { 20453a5a1b3Sopenharmony_ci tdb_data = tdb_fetch(MAKE_TDB_CONTEXT(db), tdb_key); 20553a5a1b3Sopenharmony_ci 20653a5a1b3Sopenharmony_ci if (!tdb_data.dptr) { 20753a5a1b3Sopenharmony_ci free(tdb_key.dptr); 20853a5a1b3Sopenharmony_ci return NULL; 20953a5a1b3Sopenharmony_ci } 21053a5a1b3Sopenharmony_ci 21153a5a1b3Sopenharmony_ci datum_from_tdb(data, &tdb_data); 21253a5a1b3Sopenharmony_ci } 21353a5a1b3Sopenharmony_ci 21453a5a1b3Sopenharmony_ci datum_from_tdb(key, &tdb_key); 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_ci return key; 21753a5a1b3Sopenharmony_ci} 21853a5a1b3Sopenharmony_ci 21953a5a1b3Sopenharmony_cipa_datum* pa_database_next(pa_database *db, const pa_datum *key, pa_datum *next, pa_datum *data) { 22053a5a1b3Sopenharmony_ci TDB_DATA tdb_key, tdb_data; 22153a5a1b3Sopenharmony_ci 22253a5a1b3Sopenharmony_ci pa_assert(db); 22353a5a1b3Sopenharmony_ci pa_assert(key); 22453a5a1b3Sopenharmony_ci 22553a5a1b3Sopenharmony_ci tdb_key = tdb_nextkey(MAKE_TDB_CONTEXT(db), *datum_to_tdb(&tdb_key, key)); 22653a5a1b3Sopenharmony_ci 22753a5a1b3Sopenharmony_ci if (!tdb_key.dptr) 22853a5a1b3Sopenharmony_ci return NULL; 22953a5a1b3Sopenharmony_ci 23053a5a1b3Sopenharmony_ci if (data) { 23153a5a1b3Sopenharmony_ci tdb_data = tdb_fetch(MAKE_TDB_CONTEXT(db), tdb_key); 23253a5a1b3Sopenharmony_ci 23353a5a1b3Sopenharmony_ci if (!tdb_data.dptr) { 23453a5a1b3Sopenharmony_ci free(tdb_key.dptr); 23553a5a1b3Sopenharmony_ci return NULL; 23653a5a1b3Sopenharmony_ci } 23753a5a1b3Sopenharmony_ci 23853a5a1b3Sopenharmony_ci datum_from_tdb(data, &tdb_data); 23953a5a1b3Sopenharmony_ci } 24053a5a1b3Sopenharmony_ci 24153a5a1b3Sopenharmony_ci datum_from_tdb(next, &tdb_key); 24253a5a1b3Sopenharmony_ci 24353a5a1b3Sopenharmony_ci return next; 24453a5a1b3Sopenharmony_ci} 24553a5a1b3Sopenharmony_ci 24653a5a1b3Sopenharmony_ciint pa_database_sync(pa_database *db) { 24753a5a1b3Sopenharmony_ci pa_assert(db); 24853a5a1b3Sopenharmony_ci 24953a5a1b3Sopenharmony_ci return 0; 25053a5a1b3Sopenharmony_ci} 251