default: esd is obsolete, hence don't load it anymore by default
[pulseaudio-mirror.git] / src / pulsecore / database-simple.c
blob3538127d40acf0200590e601a476d9a1069ec4d3
1 /***
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, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <stdio.h>
32 #include <pulse/xmalloc.h>
33 #include <pulsecore/core-util.h>
34 #include <pulsecore/log.h>
35 #include <pulsecore/core-error.h>
36 #include <pulsecore/hashmap.h>
38 #include "database.h"
41 typedef struct simple_data {
42 char *filename;
43 char *tmp_filename;
44 pa_hashmap *map;
45 pa_bool_t read_only;
46 } simple_data;
48 typedef struct entry {
49 pa_datum key;
50 pa_datum data;
51 } entry;
53 void pa_datum_free(pa_datum *d) {
54 pa_assert(d);
56 pa_xfree(d->data);
57 d->data = NULL;
58 d->size = 0;
61 static int compare_func(const void *a, const void *b) {
62 const pa_datum *aa, *bb;
64 aa = (const pa_datum*)a;
65 bb = (const pa_datum*)b;
67 if (aa->size != bb->size)
68 return aa->size > bb->size ? 1 : -1;
70 return memcmp(aa->data, bb->data, aa->size);
73 /* pa_idxset_string_hash_func modified for our use */
74 static unsigned hash_func(const void *p) {
75 const pa_datum *d;
76 unsigned hash = 0;
77 const char *c;
78 unsigned i;
80 d = (const pa_datum*)p;
81 c = d->data;
83 for (i = 0; i < d->size; i++) {
84 hash = 31 * hash + (unsigned) *c;
85 c++;
88 return hash;
91 static entry* new_entry(const pa_datum *key, const pa_datum *data) {
92 entry *e;
94 pa_assert(key);
95 pa_assert(data);
97 e = pa_xnew0(entry, 1);
98 e->key.data = key->size > 0 ? pa_xmemdup(key->data, key->size) : NULL;
99 e->key.size = key->size;
100 e->data.data = data->size > 0 ? pa_xmemdup(data->data, data->size) : NULL;
101 e->data.size = data->size;
102 return e;
105 static void free_entry(entry *e) {
106 if (e) {
107 if (e->key.data)
108 pa_xfree(e->key.data);
109 if (e->data.data)
110 pa_xfree(e->data.data);
111 pa_xfree(e);
115 static int read_uint(FILE *f, uint32_t *res) {
116 size_t items = 0;
117 uint8_t values[4];
118 uint32_t tmp;
119 int i;
121 items = fread(&values, sizeof(values), sizeof(uint8_t), f);
123 if (feof(f)) /* EOF */
124 return 0;
126 if (ferror(f))
127 return -1;
129 for (i = 0; i < 4; ++i) {
130 tmp = values[i];
131 *res += (tmp << (i*8));
134 return items;
137 static int read_data(FILE *f, void **data, ssize_t *length) {
138 size_t items = 0;
139 uint32_t data_len = 0;
141 pa_assert(f);
143 *data = NULL;
144 *length = 0;
146 if ((items = read_uint(f, &data_len)) <= 0)
147 return -1;
149 if (data_len > 0) {
150 *data = pa_xmalloc0(data_len);
151 items = fread(*data, data_len, 1, f);
153 if (feof(f)) /* EOF */
154 goto reset;
156 if (ferror(f))
157 goto reset;
159 *length = data_len;
161 } else { /* no data? */
162 return -1;
165 return 0;
167 reset:
168 pa_xfree(*data);
169 *data = NULL;
170 *length = 0;
171 return -1;
174 static int fill_data(simple_data *db, FILE *f) {
175 pa_datum key;
176 pa_datum data;
177 void *d = NULL;
178 ssize_t l = 0;
179 pa_bool_t append = FALSE;
180 enum { FIELD_KEY = 0, FIELD_DATA } field = FIELD_KEY;
182 pa_assert(db);
183 pa_assert(db->map);
185 errno = 0;
187 key.size = 0;
188 key.data = NULL;
190 while (!read_data(f, &d, &l)) {
192 switch (field) {
193 case FIELD_KEY:
194 key.data = d;
195 key.size = l;
196 field = FIELD_DATA;
197 break;
198 case FIELD_DATA:
199 data.data = d;
200 data.size = l;
201 append = TRUE;
202 break;
205 if (append) {
206 entry *e = pa_xnew0(entry, 1);
207 e->key.data = key.data;
208 e->key.size = key.size;
209 e->data.data = data.data;
210 e->data.size = data.size;
211 pa_hashmap_put(db->map, &e->key, e);
212 append = FALSE;
213 field = FIELD_KEY;
217 if (ferror(f)) {
218 pa_log_warn("read error. %s", pa_cstrerror(errno));
219 pa_database_clear((pa_database*)db);
222 if (field == FIELD_DATA && d)
223 pa_xfree(d);
225 return pa_hashmap_size(db->map);
228 pa_database* pa_database_open(const char *fn, pa_bool_t for_write) {
229 FILE *f;
230 char *path;
231 simple_data *db;
233 pa_assert(fn);
235 path = pa_sprintf_malloc("%s."CANONICAL_HOST".simple", fn);
236 errno = 0;
238 f = pa_fopen_cloexec(path, "r");
240 if (f || errno == ENOENT) { /* file not found is ok */
241 db = pa_xnew0(simple_data, 1);
242 db->map = pa_hashmap_new(hash_func, compare_func);
243 db->filename = pa_xstrdup(path);
244 db->tmp_filename = pa_sprintf_malloc(".%s.tmp", db->filename);
245 db->read_only = !for_write;
247 if (f) {
248 fill_data(db, f);
249 fclose(f);
251 } else {
252 if (errno == 0)
253 errno = EIO;
254 db = NULL;
257 pa_xfree(path);
259 return (pa_database*) db;
262 void pa_database_close(pa_database *database) {
263 simple_data *db = (simple_data*)database;
264 pa_assert(db);
266 pa_database_sync(database);
267 pa_database_clear(database);
268 pa_xfree(db->filename);
269 pa_xfree(db->tmp_filename);
270 pa_hashmap_free(db->map, NULL, NULL);
271 pa_xfree(db);
274 pa_datum* pa_database_get(pa_database *database, const pa_datum *key, pa_datum* data) {
275 simple_data *db = (simple_data*)database;
276 entry *e;
278 pa_assert(db);
279 pa_assert(key);
280 pa_assert(data);
282 e = pa_hashmap_get(db->map, key);
284 if (!e)
285 return NULL;
287 data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
288 data->size = e->data.size;
290 return data;
293 int pa_database_set(pa_database *database, const pa_datum *key, const pa_datum* data, pa_bool_t overwrite) {
294 simple_data *db = (simple_data*)database;
295 entry *e;
296 int ret = 0;
298 pa_assert(db);
299 pa_assert(key);
300 pa_assert(data);
302 if (db->read_only)
303 return -1;
305 e = new_entry(key, data);
307 if (pa_hashmap_put(db->map, &e->key, e) < 0) {
308 /* entry with same key exists in hashmap */
309 entry *r;
310 if (overwrite) {
311 r = pa_hashmap_remove(db->map, key);
312 pa_hashmap_put(db->map, &e->key, e);
313 } else {
314 /* wont't overwrite, so clean new entry */
315 r = e;
316 ret = -1;
319 free_entry(r);
322 return ret;
325 int pa_database_unset(pa_database *database, const pa_datum *key) {
326 simple_data *db = (simple_data*)database;
327 entry *e;
329 pa_assert(db);
330 pa_assert(key);
332 e = pa_hashmap_remove(db->map, key);
333 if (!e)
334 return -1;
336 free_entry(e);
338 return 0;
341 int pa_database_clear(pa_database *database) {
342 simple_data *db = (simple_data*)database;
343 entry *e;
345 pa_assert(db);
347 while ((e = pa_hashmap_steal_first(db->map)))
348 free_entry(e);
350 return 0;
353 signed pa_database_size(pa_database *database) {
354 simple_data *db = (simple_data*)database;
355 pa_assert(db);
357 return (signed) pa_hashmap_size(db->map);
360 pa_datum* pa_database_first(pa_database *database, pa_datum *key, pa_datum *data) {
361 simple_data *db = (simple_data*)database;
362 entry *e;
364 pa_assert(db);
365 pa_assert(key);
367 e = pa_hashmap_first(db->map);
369 if (!e)
370 return NULL;
372 key->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL;
373 key->size = e->key.size;
375 if (data) {
376 data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
377 data->size = e->data.size;
380 return key;
383 pa_datum* pa_database_next(pa_database *database, const pa_datum *key, pa_datum *next, pa_datum *data) {
384 simple_data *db = (simple_data*)database;
385 entry *e;
386 entry *search;
387 void *state;
388 pa_bool_t pick_now;
390 pa_assert(db);
391 pa_assert(next);
393 if (!key)
394 return pa_database_first(database, next, data);
396 search = pa_hashmap_get(db->map, key);
398 state = NULL;
399 pick_now = FALSE;
401 while ((e = pa_hashmap_iterate(db->map, &state, NULL))) {
402 if (pick_now)
403 break;
405 if (search == e)
406 pick_now = TRUE;
409 if (!pick_now || !e)
410 return NULL;
412 next->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL;
413 next->size = e->key.size;
415 if (data) {
416 data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
417 data->size = e->data.size;
420 return next;
423 static int write_uint(FILE *f, const uint32_t num) {
424 size_t items;
425 uint8_t values[4];
426 int i;
427 errno = 0;
429 for (i = 0; i < 4; i++)
430 values[i] = (num >> (i*8)) & 0xFF;
432 items = fwrite(&values, sizeof(values), sizeof(uint8_t), f);
434 if (ferror(f))
435 return -1;
437 return items;
440 static int write_data(FILE *f, void *data, const size_t length) {
441 size_t items;
442 uint32_t len;
444 len = length;
445 if ((items = write_uint(f, len)) <= 0)
446 return -1;
448 items = fwrite(data, length, 1, f);
450 if (ferror(f) || items != 1)
451 return -1;
453 return 0;
456 static int write_entry(FILE *f, const entry *e) {
457 pa_assert(f);
458 pa_assert(e);
460 if (write_data(f, e->key.data, e->key.size) < 0)
461 return -1;
462 if (write_data(f, e->data.data, e->data.size) < 0)
463 return -1;
465 return 0;
468 int pa_database_sync(pa_database *database) {
469 simple_data *db = (simple_data*)database;
470 FILE *f;
471 void *state;
472 entry *e;
474 pa_assert(db);
476 if (db->read_only)
477 return 0;
479 errno = 0;
481 f = pa_fopen_cloexec(db->tmp_filename, "w");
483 if (!f)
484 goto fail;
486 state = NULL;
487 while((e = pa_hashmap_iterate(db->map, &state, NULL))) {
488 if (write_entry(f, e) < 0) {
489 pa_log_warn("error while writing to file. %s", pa_cstrerror(errno));
490 goto fail;
494 fclose(f);
495 f = NULL;
497 if (rename(db->tmp_filename, db->filename) < 0) {
498 pa_log_warn("error while renaming file. %s", pa_cstrerror(errno));
499 goto fail;
502 return 0;
504 fail:
505 if (f)
506 fclose(f);
507 return -1;