2 This file is part of PulseAudio.
4 Copyright 2009 Nokia Corporation
5 Contact: Maemo Multimedia <multimedia@maemo.org>
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
26 #include <sys/types.h>
30 #include <pulse/xmalloc.h>
31 #include <pulsecore/core-util.h>
32 #include <pulsecore/log.h>
33 #include <pulsecore/core-error.h>
34 #include <pulsecore/hashmap.h>
38 typedef struct simple_data {
45 typedef struct entry {
50 void pa_datum_free(pa_datum *d) {
58 static int compare_func(const void *a, const void *b) {
59 const pa_datum *aa, *bb;
61 aa = (const pa_datum*)a;
62 bb = (const pa_datum*)b;
64 if (aa->size != bb->size)
65 return aa->size > bb->size ? 1 : -1;
67 return memcmp(aa->data, bb->data, aa->size);
70 /* pa_idxset_string_hash_func modified for our use */
71 static unsigned hash_func(const void *p) {
77 d = (const pa_datum*)p;
80 for (i = 0; i < d->size; i++) {
81 hash = 31 * hash + (unsigned) *c;
88 static entry* new_entry(const pa_datum *key, const pa_datum *data) {
94 e = pa_xnew0(entry, 1);
95 e->key.data = key->size > 0 ? pa_xmemdup(key->data, key->size) : NULL;
96 e->key.size = key->size;
97 e->data.data = data->size > 0 ? pa_xmemdup(data->data, data->size) : NULL;
98 e->data.size = data->size;
102 static void free_entry(entry *e) {
105 pa_xfree(e->key.data);
107 pa_xfree(e->data.data);
112 static int read_uint(FILE *f, uint32_t *res) {
118 items = fread(&values, sizeof(values), sizeof(uint8_t), f);
120 if (feof(f)) /* EOF */
126 for (i = 0; i < 4; ++i) {
128 *res += (tmp << (i*8));
134 static int read_data(FILE *f, void **data, ssize_t *length) {
136 uint32_t data_len = 0;
143 if ((items = read_uint(f, &data_len)) <= 0)
147 *data = pa_xmalloc0(data_len);
148 items = fread(*data, data_len, 1, f);
150 if (feof(f)) /* EOF */
158 } else { /* no data? */
171 static int fill_data(simple_data *db, FILE *f) {
177 enum { FIELD_KEY = 0, FIELD_DATA } field = FIELD_KEY;
187 while (!read_data(f, &d, &l)) {
203 entry *e = pa_xnew0(entry, 1);
204 e->key.data = key.data;
205 e->key.size = key.size;
206 e->data.data = data.data;
207 e->data.size = data.size;
208 pa_hashmap_put(db->map, &e->key, e);
215 pa_log_warn("read error. %s", pa_cstrerror(errno));
216 pa_database_clear((pa_database*)db);
219 if (field == FIELD_DATA && d)
222 return pa_hashmap_size(db->map);
225 const char* pa_database_get_filename_suffix(void) {
229 pa_database* pa_database_open_internal(const char *path, bool for_write) {
237 f = pa_fopen_cloexec(path, "r");
239 if (f || errno == ENOENT) { /* file not found is ok */
240 db = pa_xnew0(simple_data, 1);
241 db->map = pa_hashmap_new_full(hash_func, compare_func, NULL, (pa_free_cb_t) free_entry);
242 db->filename = pa_xstrdup(path);
243 db->tmp_filename = pa_sprintf_malloc(".%s.tmp", db->filename);
244 db->read_only = !for_write;
256 return (pa_database*) db;
259 void pa_database_close(pa_database *database) {
260 simple_data *db = (simple_data*)database;
263 pa_database_sync(database);
264 pa_xfree(db->filename);
265 pa_xfree(db->tmp_filename);
266 pa_hashmap_free(db->map);
270 pa_datum* pa_database_get(pa_database *database, const pa_datum *key, pa_datum* data) {
271 simple_data *db = (simple_data*)database;
278 e = pa_hashmap_get(db->map, key);
283 data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
284 data->size = e->data.size;
289 int pa_database_set(pa_database *database, const pa_datum *key, const pa_datum* data, bool overwrite) {
290 simple_data *db = (simple_data*)database;
301 e = new_entry(key, data);
303 if (pa_hashmap_put(db->map, &e->key, e) < 0) {
304 /* entry with same key exists in hashmap */
307 r = pa_hashmap_remove(db->map, key);
308 pa_hashmap_put(db->map, &e->key, e);
310 /* won't overwrite, so clean new entry */
321 int pa_database_unset(pa_database *database, const pa_datum *key) {
322 simple_data *db = (simple_data*)database;
327 return pa_hashmap_remove_and_free(db->map, key);
330 int pa_database_clear(pa_database *database) {
331 simple_data *db = (simple_data*)database;
335 pa_hashmap_remove_all(db->map);
340 signed pa_database_size(pa_database *database) {
341 simple_data *db = (simple_data*)database;
344 return (signed) pa_hashmap_size(db->map);
347 pa_datum* pa_database_first(pa_database *database, pa_datum *key, pa_datum *data) {
348 simple_data *db = (simple_data*)database;
354 e = pa_hashmap_first(db->map);
359 key->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL;
360 key->size = e->key.size;
363 data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
364 data->size = e->data.size;
370 pa_datum* pa_database_next(pa_database *database, const pa_datum *key, pa_datum *next, pa_datum *data) {
371 simple_data *db = (simple_data*)database;
381 return pa_database_first(database, next, data);
383 search = pa_hashmap_get(db->map, key);
388 while ((e = pa_hashmap_iterate(db->map, &state, NULL))) {
399 next->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL;
400 next->size = e->key.size;
403 data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
404 data->size = e->data.size;
410 static int write_uint(FILE *f, const uint32_t num) {
416 for (i = 0; i < 4; i++)
417 values[i] = (num >> (i*8)) & 0xFF;
419 items = fwrite(&values, sizeof(values), sizeof(uint8_t), f);
427 static int write_data(FILE *f, void *data, const size_t length) {
432 if ((items = write_uint(f, len)) <= 0)
435 items = fwrite(data, length, 1, f);
437 if (ferror(f) || items != 1)
443 static int write_entry(FILE *f, const entry *e) {
447 if (write_data(f, e->key.data, e->key.size) < 0)
449 if (write_data(f, e->data.data, e->data.size) < 0)
455 int pa_database_sync(pa_database *database) {
456 simple_data *db = (simple_data*)database;
468 f = pa_fopen_cloexec(db->tmp_filename, "w");
474 while((e = pa_hashmap_iterate(db->map, &state, NULL))) {
475 if (write_entry(f, e) < 0) {
476 pa_log_warn("error while writing to file. %s", pa_cstrerror(errno));
484 if (rename(db->tmp_filename, db->filename) < 0) {
485 pa_log_warn("error while renaming file. %s", pa_cstrerror(errno));