]>
code.delx.au - pulseaudio/blob - src/pulsecore/database-simple.c
91c1b4570b9c24dd96d3b4f42bb3bd8b96cc032b
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
28 #include <sys/types.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>
41 typedef struct simple_data
{
48 typedef struct entry
{
53 void pa_datum_free(pa_datum
*d
) {
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
) {
80 d
= (const pa_datum
*)p
;
83 for (i
= 0; i
< d
->size
; i
++) {
84 hash
= 31 * hash
+ (unsigned) *c
;
91 static entry
* new_entry(const pa_datum
*key
, const pa_datum
*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
;
105 static void free_entry(entry
*e
) {
108 pa_xfree(e
->key
.data
);
110 pa_xfree(e
->data
.data
);
115 static int read_uint(FILE *f
, uint32_t *res
) {
121 items
= fread(&values
, sizeof(values
), sizeof(uint8_t), f
);
123 if (feof(f
)) /* EOF */
129 for (i
= 0; i
< 4; ++i
) {
131 *res
+= (tmp
<< (i
*8));
137 static int read_data(FILE *f
, void **data
, ssize_t
*length
) {
139 uint32_t data_len
= 0;
146 if ((items
= read_uint(f
, &data_len
)) <= 0)
150 *data
= pa_xmalloc0(data_len
);
151 items
= fread(*data
, data_len
, 1, f
);
153 if (feof(f
)) /* EOF */
161 } else { /* no data? */
174 static int fill_data(simple_data
*db
, FILE *f
) {
179 pa_bool_t append
= FALSE
;
180 enum { FIELD_KEY
= 0, FIELD_DATA
} field
= FIELD_KEY
;
190 while (!read_data(f
, &d
, &l
)) {
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
);
218 pa_log_warn("read error. %s", pa_cstrerror(errno
));
219 pa_database_clear((pa_database
*)db
);
222 if (field
== FIELD_DATA
&& d
)
225 return pa_hashmap_size(db
->map
);
228 pa_database
* pa_database_open(const char *fn
, pa_bool_t for_write
) {
235 path
= pa_sprintf_malloc("%s."CANONICAL_HOST
".simple", fn
);
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
;
259 return (pa_database
*) db
;
262 void pa_database_close(pa_database
*database
) {
263 simple_data
*db
= (simple_data
*)database
;
266 pa_database_sync(database
);
267 pa_xfree(db
->filename
);
268 pa_xfree(db
->tmp_filename
);
269 pa_hashmap_free(db
->map
, (pa_free_cb_t
) free_entry
);
273 pa_datum
* pa_database_get(pa_database
*database
, const pa_datum
*key
, pa_datum
* data
) {
274 simple_data
*db
= (simple_data
*)database
;
281 e
= pa_hashmap_get(db
->map
, key
);
286 data
->data
= e
->data
.size
> 0 ? pa_xmemdup(e
->data
.data
, e
->data
.size
) : NULL
;
287 data
->size
= e
->data
.size
;
292 int pa_database_set(pa_database
*database
, const pa_datum
*key
, const pa_datum
* data
, pa_bool_t overwrite
) {
293 simple_data
*db
= (simple_data
*)database
;
304 e
= new_entry(key
, data
);
306 if (pa_hashmap_put(db
->map
, &e
->key
, e
) < 0) {
307 /* entry with same key exists in hashmap */
310 r
= pa_hashmap_remove(db
->map
, key
);
311 pa_hashmap_put(db
->map
, &e
->key
, e
);
313 /* won't overwrite, so clean new entry */
324 int pa_database_unset(pa_database
*database
, const pa_datum
*key
) {
325 simple_data
*db
= (simple_data
*)database
;
331 e
= pa_hashmap_remove(db
->map
, key
);
340 int pa_database_clear(pa_database
*database
) {
341 simple_data
*db
= (simple_data
*)database
;
345 pa_hashmap_remove_all(db
->map
, (pa_free_cb_t
) free_entry
);
350 signed pa_database_size(pa_database
*database
) {
351 simple_data
*db
= (simple_data
*)database
;
354 return (signed) pa_hashmap_size(db
->map
);
357 pa_datum
* pa_database_first(pa_database
*database
, pa_datum
*key
, pa_datum
*data
) {
358 simple_data
*db
= (simple_data
*)database
;
364 e
= pa_hashmap_first(db
->map
);
369 key
->data
= e
->key
.size
> 0 ? pa_xmemdup(e
->key
.data
, e
->key
.size
) : NULL
;
370 key
->size
= e
->key
.size
;
373 data
->data
= e
->data
.size
> 0 ? pa_xmemdup(e
->data
.data
, e
->data
.size
) : NULL
;
374 data
->size
= e
->data
.size
;
380 pa_datum
* pa_database_next(pa_database
*database
, const pa_datum
*key
, pa_datum
*next
, pa_datum
*data
) {
381 simple_data
*db
= (simple_data
*)database
;
391 return pa_database_first(database
, next
, data
);
393 search
= pa_hashmap_get(db
->map
, key
);
398 while ((e
= pa_hashmap_iterate(db
->map
, &state
, NULL
))) {
409 next
->data
= e
->key
.size
> 0 ? pa_xmemdup(e
->key
.data
, e
->key
.size
) : NULL
;
410 next
->size
= e
->key
.size
;
413 data
->data
= e
->data
.size
> 0 ? pa_xmemdup(e
->data
.data
, e
->data
.size
) : NULL
;
414 data
->size
= e
->data
.size
;
420 static int write_uint(FILE *f
, const uint32_t num
) {
426 for (i
= 0; i
< 4; i
++)
427 values
[i
] = (num
>> (i
*8)) & 0xFF;
429 items
= fwrite(&values
, sizeof(values
), sizeof(uint8_t), f
);
437 static int write_data(FILE *f
, void *data
, const size_t length
) {
442 if ((items
= write_uint(f
, len
)) <= 0)
445 items
= fwrite(data
, length
, 1, f
);
447 if (ferror(f
) || items
!= 1)
453 static int write_entry(FILE *f
, const entry
*e
) {
457 if (write_data(f
, e
->key
.data
, e
->key
.size
) < 0)
459 if (write_data(f
, e
->data
.data
, e
->data
.size
) < 0)
465 int pa_database_sync(pa_database
*database
) {
466 simple_data
*db
= (simple_data
*)database
;
478 f
= pa_fopen_cloexec(db
->tmp_filename
, "w");
484 while((e
= pa_hashmap_iterate(db
->map
, &state
, NULL
))) {
485 if (write_entry(f
, e
) < 0) {
486 pa_log_warn("error while writing to file. %s", pa_cstrerror(errno
));
494 if (rename(db
->tmp_filename
, db
->filename
) < 0) {
495 pa_log_warn("error while renaming file. %s", pa_cstrerror(errno
));