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 <errno.h> 2553a5a1b3Sopenharmony_ci#include <gdbm.h> 2653a5a1b3Sopenharmony_ci 2753a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 2853a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 2953a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 3053a5a1b3Sopenharmony_ci 3153a5a1b3Sopenharmony_ci#include "database.h" 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#define MAKE_GDBM_FILE(x) ((GDBM_FILE) (x)) 3453a5a1b3Sopenharmony_ci 3553a5a1b3Sopenharmony_cistatic inline datum* datum_to_gdbm(datum *to, const pa_datum *from) { 3653a5a1b3Sopenharmony_ci pa_assert(from); 3753a5a1b3Sopenharmony_ci pa_assert(to); 3853a5a1b3Sopenharmony_ci 3953a5a1b3Sopenharmony_ci to->dptr = from->data; 4053a5a1b3Sopenharmony_ci to->dsize = from->size; 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci return to; 4353a5a1b3Sopenharmony_ci} 4453a5a1b3Sopenharmony_ci 4553a5a1b3Sopenharmony_cistatic inline pa_datum* datum_from_gdbm(pa_datum *to, const datum *from) { 4653a5a1b3Sopenharmony_ci pa_assert(from); 4753a5a1b3Sopenharmony_ci pa_assert(to); 4853a5a1b3Sopenharmony_ci 4953a5a1b3Sopenharmony_ci to->data = from->dptr; 5053a5a1b3Sopenharmony_ci to->size = from->dsize; 5153a5a1b3Sopenharmony_ci 5253a5a1b3Sopenharmony_ci return to; 5353a5a1b3Sopenharmony_ci} 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_civoid pa_datum_free(pa_datum *d) { 5653a5a1b3Sopenharmony_ci pa_assert(d); 5753a5a1b3Sopenharmony_ci 5853a5a1b3Sopenharmony_ci free(d->data); /* gdbm uses raw malloc/free hence we should do that here, too */ 5953a5a1b3Sopenharmony_ci pa_zero(d); 6053a5a1b3Sopenharmony_ci} 6153a5a1b3Sopenharmony_ci 6253a5a1b3Sopenharmony_ciconst char* pa_database_get_filename_suffix(void) { 6353a5a1b3Sopenharmony_ci return ".gdbm"; 6453a5a1b3Sopenharmony_ci} 6553a5a1b3Sopenharmony_ci 6653a5a1b3Sopenharmony_cipa_database* pa_database_open_internal(const char *path, bool for_write) { 6753a5a1b3Sopenharmony_ci GDBM_FILE f; 6853a5a1b3Sopenharmony_ci int gdbm_cache_size; 6953a5a1b3Sopenharmony_ci 7053a5a1b3Sopenharmony_ci pa_assert(path); 7153a5a1b3Sopenharmony_ci 7253a5a1b3Sopenharmony_ci errno = 0; 7353a5a1b3Sopenharmony_ci 7453a5a1b3Sopenharmony_ci /* We need to set the block size explicitly here, since otherwise 7553a5a1b3Sopenharmony_ci * gdbm takes the native block size of the underlying file system 7653a5a1b3Sopenharmony_ci * which might be incredibly large. */ 7753a5a1b3Sopenharmony_ci f = gdbm_open((char*) path, 1024, GDBM_NOLOCK | (for_write ? GDBM_WRCREAT : GDBM_READER), 0644, NULL); 7853a5a1b3Sopenharmony_ci 7953a5a1b3Sopenharmony_ci if (f) 8053a5a1b3Sopenharmony_ci pa_log_debug("Opened GDBM database '%s'", path); 8153a5a1b3Sopenharmony_ci 8253a5a1b3Sopenharmony_ci if (!f) { 8353a5a1b3Sopenharmony_ci if (errno == 0) 8453a5a1b3Sopenharmony_ci errno = EIO; 8553a5a1b3Sopenharmony_ci return NULL; 8653a5a1b3Sopenharmony_ci } 8753a5a1b3Sopenharmony_ci 8853a5a1b3Sopenharmony_ci /* By default the cache of gdbm is rather large, let's reduce it a bit to save memory */ 8953a5a1b3Sopenharmony_ci gdbm_cache_size = 10; 9053a5a1b3Sopenharmony_ci gdbm_setopt(f, GDBM_CACHESIZE, &gdbm_cache_size, sizeof(gdbm_cache_size)); 9153a5a1b3Sopenharmony_ci 9253a5a1b3Sopenharmony_ci return (pa_database*) f; 9353a5a1b3Sopenharmony_ci} 9453a5a1b3Sopenharmony_ci 9553a5a1b3Sopenharmony_civoid pa_database_close(pa_database *db) { 9653a5a1b3Sopenharmony_ci pa_assert(db); 9753a5a1b3Sopenharmony_ci 9853a5a1b3Sopenharmony_ci gdbm_close(MAKE_GDBM_FILE(db)); 9953a5a1b3Sopenharmony_ci} 10053a5a1b3Sopenharmony_ci 10153a5a1b3Sopenharmony_cipa_datum* pa_database_get(pa_database *db, const pa_datum *key, pa_datum* data) { 10253a5a1b3Sopenharmony_ci datum gdbm_key, gdbm_data; 10353a5a1b3Sopenharmony_ci 10453a5a1b3Sopenharmony_ci pa_assert(db); 10553a5a1b3Sopenharmony_ci pa_assert(key); 10653a5a1b3Sopenharmony_ci pa_assert(data); 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci gdbm_data = gdbm_fetch(MAKE_GDBM_FILE(db), *datum_to_gdbm(&gdbm_key, key)); 10953a5a1b3Sopenharmony_ci 11053a5a1b3Sopenharmony_ci return gdbm_data.dptr ? 11153a5a1b3Sopenharmony_ci datum_from_gdbm(data, &gdbm_data) : 11253a5a1b3Sopenharmony_ci NULL; 11353a5a1b3Sopenharmony_ci} 11453a5a1b3Sopenharmony_ci 11553a5a1b3Sopenharmony_ciint pa_database_set(pa_database *db, const pa_datum *key, const pa_datum* data, bool overwrite) { 11653a5a1b3Sopenharmony_ci datum gdbm_key, gdbm_data; 11753a5a1b3Sopenharmony_ci 11853a5a1b3Sopenharmony_ci pa_assert(db); 11953a5a1b3Sopenharmony_ci pa_assert(key); 12053a5a1b3Sopenharmony_ci pa_assert(data); 12153a5a1b3Sopenharmony_ci 12253a5a1b3Sopenharmony_ci return gdbm_store(MAKE_GDBM_FILE(db), 12353a5a1b3Sopenharmony_ci *datum_to_gdbm(&gdbm_key, key), 12453a5a1b3Sopenharmony_ci *datum_to_gdbm(&gdbm_data, data), 12553a5a1b3Sopenharmony_ci overwrite ? GDBM_REPLACE : GDBM_INSERT) != 0 ? -1 : 0; 12653a5a1b3Sopenharmony_ci} 12753a5a1b3Sopenharmony_ci 12853a5a1b3Sopenharmony_ciint pa_database_unset(pa_database *db, const pa_datum *key) { 12953a5a1b3Sopenharmony_ci datum gdbm_key; 13053a5a1b3Sopenharmony_ci 13153a5a1b3Sopenharmony_ci pa_assert(db); 13253a5a1b3Sopenharmony_ci pa_assert(key); 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci return gdbm_delete(MAKE_GDBM_FILE(db), *datum_to_gdbm(&gdbm_key, key)) != 0 ? -1 : 0; 13553a5a1b3Sopenharmony_ci} 13653a5a1b3Sopenharmony_ci 13753a5a1b3Sopenharmony_ciint pa_database_clear(pa_database *db) { 13853a5a1b3Sopenharmony_ci datum gdbm_key; 13953a5a1b3Sopenharmony_ci 14053a5a1b3Sopenharmony_ci pa_assert(db); 14153a5a1b3Sopenharmony_ci 14253a5a1b3Sopenharmony_ci gdbm_key = gdbm_firstkey(MAKE_GDBM_FILE(db)); 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_ci while (gdbm_key.dptr) { 14553a5a1b3Sopenharmony_ci datum next; 14653a5a1b3Sopenharmony_ci 14753a5a1b3Sopenharmony_ci next = gdbm_nextkey(MAKE_GDBM_FILE(db), gdbm_key); 14853a5a1b3Sopenharmony_ci 14953a5a1b3Sopenharmony_ci gdbm_delete(MAKE_GDBM_FILE(db), gdbm_key); 15053a5a1b3Sopenharmony_ci 15153a5a1b3Sopenharmony_ci free(gdbm_key.dptr); 15253a5a1b3Sopenharmony_ci gdbm_key = next; 15353a5a1b3Sopenharmony_ci } 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_ci return gdbm_reorganize(MAKE_GDBM_FILE(db)) == 0 ? 0 : -1; 15653a5a1b3Sopenharmony_ci} 15753a5a1b3Sopenharmony_ci 15853a5a1b3Sopenharmony_cisigned pa_database_size(pa_database *db) { 15953a5a1b3Sopenharmony_ci datum gdbm_key; 16053a5a1b3Sopenharmony_ci unsigned n = 0; 16153a5a1b3Sopenharmony_ci 16253a5a1b3Sopenharmony_ci pa_assert(db); 16353a5a1b3Sopenharmony_ci 16453a5a1b3Sopenharmony_ci /* This sucks */ 16553a5a1b3Sopenharmony_ci 16653a5a1b3Sopenharmony_ci gdbm_key = gdbm_firstkey(MAKE_GDBM_FILE(db)); 16753a5a1b3Sopenharmony_ci 16853a5a1b3Sopenharmony_ci while (gdbm_key.dptr) { 16953a5a1b3Sopenharmony_ci datum next; 17053a5a1b3Sopenharmony_ci 17153a5a1b3Sopenharmony_ci n++; 17253a5a1b3Sopenharmony_ci 17353a5a1b3Sopenharmony_ci next = gdbm_nextkey(MAKE_GDBM_FILE(db), gdbm_key); 17453a5a1b3Sopenharmony_ci free(gdbm_key.dptr); 17553a5a1b3Sopenharmony_ci gdbm_key = next; 17653a5a1b3Sopenharmony_ci } 17753a5a1b3Sopenharmony_ci 17853a5a1b3Sopenharmony_ci return (signed) n; 17953a5a1b3Sopenharmony_ci} 18053a5a1b3Sopenharmony_ci 18153a5a1b3Sopenharmony_cipa_datum* pa_database_first(pa_database *db, pa_datum *key, pa_datum *data) { 18253a5a1b3Sopenharmony_ci datum gdbm_key, gdbm_data; 18353a5a1b3Sopenharmony_ci 18453a5a1b3Sopenharmony_ci pa_assert(db); 18553a5a1b3Sopenharmony_ci pa_assert(key); 18653a5a1b3Sopenharmony_ci 18753a5a1b3Sopenharmony_ci gdbm_key = gdbm_firstkey(MAKE_GDBM_FILE(db)); 18853a5a1b3Sopenharmony_ci 18953a5a1b3Sopenharmony_ci if (!gdbm_key.dptr) 19053a5a1b3Sopenharmony_ci return NULL; 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_ci if (data) { 19353a5a1b3Sopenharmony_ci gdbm_data = gdbm_fetch(MAKE_GDBM_FILE(db), gdbm_key); 19453a5a1b3Sopenharmony_ci 19553a5a1b3Sopenharmony_ci if (!gdbm_data.dptr) { 19653a5a1b3Sopenharmony_ci free(gdbm_key.dptr); 19753a5a1b3Sopenharmony_ci return NULL; 19853a5a1b3Sopenharmony_ci } 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci datum_from_gdbm(data, &gdbm_data); 20153a5a1b3Sopenharmony_ci } 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci datum_from_gdbm(key, &gdbm_key); 20453a5a1b3Sopenharmony_ci 20553a5a1b3Sopenharmony_ci return key; 20653a5a1b3Sopenharmony_ci} 20753a5a1b3Sopenharmony_ci 20853a5a1b3Sopenharmony_cipa_datum* pa_database_next(pa_database *db, const pa_datum *key, pa_datum *next, pa_datum *data) { 20953a5a1b3Sopenharmony_ci datum gdbm_key, gdbm_data; 21053a5a1b3Sopenharmony_ci 21153a5a1b3Sopenharmony_ci pa_assert(db); 21253a5a1b3Sopenharmony_ci pa_assert(key); 21353a5a1b3Sopenharmony_ci pa_assert(next); 21453a5a1b3Sopenharmony_ci 21553a5a1b3Sopenharmony_ci if (!key) 21653a5a1b3Sopenharmony_ci return pa_database_first(db, next, data); 21753a5a1b3Sopenharmony_ci 21853a5a1b3Sopenharmony_ci gdbm_key = gdbm_nextkey(MAKE_GDBM_FILE(db), *datum_to_gdbm(&gdbm_key, key)); 21953a5a1b3Sopenharmony_ci 22053a5a1b3Sopenharmony_ci if (!gdbm_key.dptr) 22153a5a1b3Sopenharmony_ci return NULL; 22253a5a1b3Sopenharmony_ci 22353a5a1b3Sopenharmony_ci if (data) { 22453a5a1b3Sopenharmony_ci gdbm_data = gdbm_fetch(MAKE_GDBM_FILE(db), gdbm_key); 22553a5a1b3Sopenharmony_ci 22653a5a1b3Sopenharmony_ci if (!gdbm_data.dptr) { 22753a5a1b3Sopenharmony_ci free(gdbm_key.dptr); 22853a5a1b3Sopenharmony_ci return NULL; 22953a5a1b3Sopenharmony_ci } 23053a5a1b3Sopenharmony_ci 23153a5a1b3Sopenharmony_ci datum_from_gdbm(data, &gdbm_data); 23253a5a1b3Sopenharmony_ci } 23353a5a1b3Sopenharmony_ci 23453a5a1b3Sopenharmony_ci datum_from_gdbm(next, &gdbm_key); 23553a5a1b3Sopenharmony_ci 23653a5a1b3Sopenharmony_ci return next; 23753a5a1b3Sopenharmony_ci} 23853a5a1b3Sopenharmony_ci 23953a5a1b3Sopenharmony_ciint pa_database_sync(pa_database *db) { 24053a5a1b3Sopenharmony_ci pa_assert(db); 24153a5a1b3Sopenharmony_ci 24253a5a1b3Sopenharmony_ci gdbm_sync(MAKE_GDBM_FILE(db)); 24353a5a1b3Sopenharmony_ci return 0; 24453a5a1b3Sopenharmony_ci} 245