]>
code.delx.au - pulseaudio/blob - src/pulsecore/database-simple.c
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>
40 typedef struct simple_data
{
47 typedef struct entry
{
52 void pa_datum_free(pa_datum
*d
) {
60 static int compare_func(const void *a
, const void *b
) {
61 const pa_datum
*aa
, *bb
;
63 aa
= (const pa_datum
*)a
;
64 bb
= (const pa_datum
*)b
;
66 if (aa
->size
!= bb
->size
)
67 return aa
->size
> bb
->size
? 1 : -1;
69 return memcmp(aa
->data
, bb
->data
, aa
->size
);
72 /* pa_idxset_string_hash_func modified for our use */
73 static unsigned hash_func(const void *p
) {
79 d
= (const pa_datum
*)p
;
82 for (i
= 0; i
< d
->size
; i
++) {
83 hash
= 31 * hash
+ (unsigned) *c
;
90 static entry
* new_entry(const pa_datum
*key
, const pa_datum
*data
) {
96 e
= pa_xnew0(entry
, 1);
97 e
->key
.data
= key
->size
> 0 ? pa_xmemdup(key
->data
, key
->size
) : NULL
;
98 e
->key
.size
= key
->size
;
99 e
->data
.data
= data
->size
> 0 ? pa_xmemdup(data
->data
, data
->size
) : NULL
;
100 e
->data
.size
= data
->size
;
104 static void free_entry(entry
*e
) {
107 pa_xfree(e
->key
.data
);
109 pa_xfree(e
->data
.data
);
114 static int read_uint(FILE *f
, uint32_t *res
) {
120 items
= fread(&values
, sizeof(values
), sizeof(uint8_t), f
);
122 if (feof(f
)) /* EOF */
128 for (i
= 0; i
< 4; ++i
) {
130 *res
+= (tmp
<< (i
*8));
136 static int read_data(FILE *f
, void **data
, ssize_t
*length
) {
138 uint32_t data_len
= 0;
145 if ((items
= read_uint(f
, &data_len
)) <= 0)
149 *data
= pa_xmalloc0(data_len
);
150 items
= fread(*data
, data_len
, 1, f
);
152 if (feof(f
)) /* EOF */
160 } else { /* no data? */
173 static int fill_data(simple_data
*db
, FILE *f
) {
179 enum { FIELD_KEY
= 0, FIELD_DATA
} field
= FIELD_KEY
;
189 while (!read_data(f
, &d
, &l
)) {
205 entry
*e
= pa_xnew0(entry
, 1);
206 e
->key
.data
= key
.data
;
207 e
->key
.size
= key
.size
;
208 e
->data
.data
= data
.data
;
209 e
->data
.size
= data
.size
;
210 pa_hashmap_put(db
->map
, &e
->key
, e
);
217 pa_log_warn("read error. %s", pa_cstrerror(errno
));
218 pa_database_clear((pa_database
*)db
);
221 if (field
== FIELD_DATA
&& d
)
224 return pa_hashmap_size(db
->map
);
227 pa_database
* pa_database_open(const char *fn
, bool for_write
) {
234 path
= pa_sprintf_malloc("%s."CANONICAL_HOST
".simple", fn
);
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
;
258 return (pa_database
*) db
;
261 void pa_database_close(pa_database
*database
) {
262 simple_data
*db
= (simple_data
*)database
;
265 pa_database_sync(database
);
266 pa_xfree(db
->filename
);
267 pa_xfree(db
->tmp_filename
);
268 pa_hashmap_free(db
->map
);
272 pa_datum
* pa_database_get(pa_database
*database
, const pa_datum
*key
, pa_datum
* data
) {
273 simple_data
*db
= (simple_data
*)database
;
280 e
= pa_hashmap_get(db
->map
, key
);
285 data
->data
= e
->data
.size
> 0 ? pa_xmemdup(e
->data
.data
, e
->data
.size
) : NULL
;
286 data
->size
= e
->data
.size
;
291 int pa_database_set(pa_database
*database
, const pa_datum
*key
, const pa_datum
* data
, bool overwrite
) {
292 simple_data
*db
= (simple_data
*)database
;
303 e
= new_entry(key
, data
);
305 if (pa_hashmap_put(db
->map
, &e
->key
, e
) < 0) {
306 /* entry with same key exists in hashmap */
309 r
= pa_hashmap_remove(db
->map
, key
);
310 pa_hashmap_put(db
->map
, &e
->key
, e
);
312 /* won't overwrite, so clean new entry */
323 int pa_database_unset(pa_database
*database
, const pa_datum
*key
) {
324 simple_data
*db
= (simple_data
*)database
;
329 return pa_hashmap_remove_and_free(db
->map
, key
);
332 int pa_database_clear(pa_database
*database
) {
333 simple_data
*db
= (simple_data
*)database
;
337 pa_hashmap_remove_all(db
->map
);
342 signed pa_database_size(pa_database
*database
) {
343 simple_data
*db
= (simple_data
*)database
;
346 return (signed) pa_hashmap_size(db
->map
);
349 pa_datum
* pa_database_first(pa_database
*database
, pa_datum
*key
, pa_datum
*data
) {
350 simple_data
*db
= (simple_data
*)database
;
356 e
= pa_hashmap_first(db
->map
);
361 key
->data
= e
->key
.size
> 0 ? pa_xmemdup(e
->key
.data
, e
->key
.size
) : NULL
;
362 key
->size
= e
->key
.size
;
365 data
->data
= e
->data
.size
> 0 ? pa_xmemdup(e
->data
.data
, e
->data
.size
) : NULL
;
366 data
->size
= e
->data
.size
;
372 pa_datum
* pa_database_next(pa_database
*database
, const pa_datum
*key
, pa_datum
*next
, pa_datum
*data
) {
373 simple_data
*db
= (simple_data
*)database
;
383 return pa_database_first(database
, next
, data
);
385 search
= pa_hashmap_get(db
->map
, key
);
390 while ((e
= pa_hashmap_iterate(db
->map
, &state
, NULL
))) {
401 next
->data
= e
->key
.size
> 0 ? pa_xmemdup(e
->key
.data
, e
->key
.size
) : NULL
;
402 next
->size
= e
->key
.size
;
405 data
->data
= e
->data
.size
> 0 ? pa_xmemdup(e
->data
.data
, e
->data
.size
) : NULL
;
406 data
->size
= e
->data
.size
;
412 static int write_uint(FILE *f
, const uint32_t num
) {
418 for (i
= 0; i
< 4; i
++)
419 values
[i
] = (num
>> (i
*8)) & 0xFF;
421 items
= fwrite(&values
, sizeof(values
), sizeof(uint8_t), f
);
429 static int write_data(FILE *f
, void *data
, const size_t length
) {
434 if ((items
= write_uint(f
, len
)) <= 0)
437 items
= fwrite(data
, length
, 1, f
);
439 if (ferror(f
) || items
!= 1)
445 static int write_entry(FILE *f
, const entry
*e
) {
449 if (write_data(f
, e
->key
.data
, e
->key
.size
) < 0)
451 if (write_data(f
, e
->data
.data
, e
->data
.size
) < 0)
457 int pa_database_sync(pa_database
*database
) {
458 simple_data
*db
= (simple_data
*)database
;
470 f
= pa_fopen_cloexec(db
->tmp_filename
, "w");
476 while((e
= pa_hashmap_iterate(db
->map
, &state
, NULL
))) {
477 if (write_entry(f
, e
) < 0) {
478 pa_log_warn("error while writing to file. %s", pa_cstrerror(errno
));
486 if (rename(db
->tmp_filename
, db
->filename
) < 0) {
487 pa_log_warn("error while renaming file. %s", pa_cstrerror(errno
));