"Fossies" - the Fresh Open Source Software Archive

Member "pulseaudio-14.2/src/pulsecore/database-simple.c" (11 Jan 2021, 10706 Bytes) of package /linux/misc/pulseaudio-14.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "database-simple.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.0_vs_14.2.

    1 /***
    2   This file is part of PulseAudio.
    3 
    4   Copyright 2009 Nokia Corporation
    5   Contact: Maemo Multimedia <multimedia@maemo.org>
    6 
    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.
   11 
   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.
   16 
   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/>.
   19 ***/
   20 
   21 #ifdef HAVE_CONFIG_H
   22 #include <config.h>
   23 #endif
   24 
   25 #include <errno.h>
   26 #include <sys/types.h>
   27 #include <unistd.h>
   28 #include <stdio.h>
   29 
   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>
   35 
   36 #include "database.h"
   37 
   38 typedef struct simple_data {
   39     char *filename;
   40     char *tmp_filename;
   41     pa_hashmap *map;
   42     bool read_only;
   43 } simple_data;
   44 
   45 typedef struct entry {
   46     pa_datum key;
   47     pa_datum data;
   48 } entry;
   49 
   50 void pa_datum_free(pa_datum *d) {
   51     pa_assert(d);
   52 
   53     pa_xfree(d->data);
   54     d->data = NULL;
   55     d->size = 0;
   56 }
   57 
   58 static int compare_func(const void *a, const void *b) {
   59     const pa_datum *aa, *bb;
   60 
   61     aa = (const pa_datum*)a;
   62     bb = (const pa_datum*)b;
   63 
   64     if (aa->size != bb->size)
   65         return aa->size > bb->size ? 1 : -1;
   66 
   67     return memcmp(aa->data, bb->data, aa->size);
   68 }
   69 
   70 /* pa_idxset_string_hash_func modified for our use */
   71 static unsigned hash_func(const void *p) {
   72     const pa_datum *d;
   73     unsigned hash = 0;
   74     const char *c;
   75     unsigned i;
   76 
   77     d = (const pa_datum*)p;
   78     c = d->data;
   79 
   80     for (i = 0; i < d->size; i++) {
   81         hash = 31 * hash + (unsigned) *c;
   82         c++;
   83     }
   84 
   85     return hash;
   86 }
   87 
   88 static entry* new_entry(const pa_datum *key, const pa_datum *data) {
   89     entry *e;
   90 
   91     pa_assert(key);
   92     pa_assert(data);
   93 
   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;
   99     return e;
  100 }
  101 
  102 static void free_entry(entry *e) {
  103     if (e) {
  104         if (e->key.data)
  105             pa_xfree(e->key.data);
  106         if (e->data.data)
  107             pa_xfree(e->data.data);
  108         pa_xfree(e);
  109     }
  110 }
  111 
  112 static int read_uint(FILE *f, uint32_t *res) {
  113     size_t items = 0;
  114     uint8_t values[4];
  115     uint32_t tmp;
  116     int i;
  117 
  118     items = fread(&values, sizeof(values), sizeof(uint8_t), f);
  119 
  120     if (feof(f)) /* EOF */
  121         return 0;
  122 
  123     if (ferror(f))
  124         return -1;
  125 
  126     for (i = 0; i < 4; ++i) {
  127         tmp = values[i];
  128         *res += (tmp << (i*8));
  129     }
  130 
  131     return items;
  132 }
  133 
  134 static int read_data(FILE *f, void **data, ssize_t *length) {
  135     size_t items = 0;
  136     uint32_t data_len = 0;
  137 
  138     pa_assert(f);
  139 
  140     *data = NULL;
  141     *length = 0;
  142 
  143     if ((items = read_uint(f, &data_len)) <= 0)
  144         return -1;
  145 
  146     if (data_len > 0) {
  147         *data = pa_xmalloc0(data_len);
  148         items = fread(*data, data_len, 1, f);
  149 
  150         if (feof(f)) /* EOF */
  151             goto reset;
  152 
  153         if (ferror(f))
  154             goto reset;
  155 
  156         *length = data_len;
  157 
  158     } else { /* no data? */
  159         return -1;
  160     }
  161 
  162     return 0;
  163 
  164 reset:
  165     pa_xfree(*data);
  166     *data = NULL;
  167     *length = 0;
  168     return -1;
  169 }
  170 
  171 static int fill_data(simple_data *db, FILE *f) {
  172     pa_datum key;
  173     pa_datum data;
  174     void *d = NULL;
  175     ssize_t l = 0;
  176     bool append = false;
  177     enum { FIELD_KEY = 0, FIELD_DATA } field = FIELD_KEY;
  178 
  179     pa_assert(db);
  180     pa_assert(db->map);
  181 
  182     errno = 0;
  183 
  184     key.size = 0;
  185     key.data = NULL;
  186 
  187     while (!read_data(f, &d, &l)) {
  188 
  189         switch (field) {
  190             case FIELD_KEY:
  191                 key.data = d;
  192                 key.size = l;
  193                 field = FIELD_DATA;
  194                 break;
  195             case FIELD_DATA:
  196                 data.data = d;
  197                 data.size = l;
  198                 append = true;
  199                 break;
  200         }
  201 
  202         if (append) {
  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);
  209             append = false;
  210             field = FIELD_KEY;
  211         }
  212     }
  213 
  214     if (ferror(f)) {
  215         pa_log_warn("read error. %s", pa_cstrerror(errno));
  216         pa_database_clear((pa_database*)db);
  217     }
  218 
  219     if (field == FIELD_DATA && d)
  220         pa_xfree(d);
  221 
  222     return pa_hashmap_size(db->map);
  223 }
  224 
  225 const char* pa_database_get_filename_suffix(void) {
  226     return ".simple";
  227 }
  228 
  229 pa_database* pa_database_open_internal(const char *path, bool for_write) {
  230     FILE *f;
  231     simple_data *db;
  232 
  233     pa_assert(path);
  234 
  235     errno = 0;
  236 
  237     f = pa_fopen_cloexec(path, "r");
  238 
  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;
  245 
  246         if (f) {
  247             fill_data(db, f);
  248             fclose(f);
  249         }
  250     } else {
  251         if (errno == 0)
  252             errno = EIO;
  253         db = NULL;
  254     }
  255 
  256     return (pa_database*) db;
  257 }
  258 
  259 void pa_database_close(pa_database *database) {
  260     simple_data *db = (simple_data*)database;
  261     pa_assert(db);
  262 
  263     pa_database_sync(database);
  264     pa_xfree(db->filename);
  265     pa_xfree(db->tmp_filename);
  266     pa_hashmap_free(db->map);
  267     pa_xfree(db);
  268 }
  269 
  270 pa_datum* pa_database_get(pa_database *database, const pa_datum *key, pa_datum* data) {
  271     simple_data *db = (simple_data*)database;
  272     entry *e;
  273 
  274     pa_assert(db);
  275     pa_assert(key);
  276     pa_assert(data);
  277 
  278     e = pa_hashmap_get(db->map, key);
  279 
  280     if (!e)
  281         return NULL;
  282 
  283     data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
  284     data->size = e->data.size;
  285 
  286     return data;
  287 }
  288 
  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;
  291     entry *e;
  292     int ret = 0;
  293 
  294     pa_assert(db);
  295     pa_assert(key);
  296     pa_assert(data);
  297 
  298     if (db->read_only)
  299         return -1;
  300 
  301     e = new_entry(key, data);
  302 
  303     if (pa_hashmap_put(db->map, &e->key, e) < 0) {
  304         /* entry with same key exists in hashmap */
  305         entry *r;
  306         if (overwrite) {
  307             r = pa_hashmap_remove(db->map, key);
  308             pa_hashmap_put(db->map, &e->key, e);
  309         } else {
  310             /* won't overwrite, so clean new entry */
  311             r = e;
  312             ret = -1;
  313         }
  314 
  315         free_entry(r);
  316     }
  317 
  318     return ret;
  319 }
  320 
  321 int pa_database_unset(pa_database *database, const pa_datum *key) {
  322     simple_data *db = (simple_data*)database;
  323 
  324     pa_assert(db);
  325     pa_assert(key);
  326 
  327     return pa_hashmap_remove_and_free(db->map, key);
  328 }
  329 
  330 int pa_database_clear(pa_database *database) {
  331     simple_data *db = (simple_data*)database;
  332 
  333     pa_assert(db);
  334 
  335     pa_hashmap_remove_all(db->map);
  336 
  337     return 0;
  338 }
  339 
  340 signed pa_database_size(pa_database *database) {
  341     simple_data *db = (simple_data*)database;
  342     pa_assert(db);
  343 
  344     return (signed) pa_hashmap_size(db->map);
  345 }
  346 
  347 pa_datum* pa_database_first(pa_database *database, pa_datum *key, pa_datum *data) {
  348     simple_data *db = (simple_data*)database;
  349     entry *e;
  350 
  351     pa_assert(db);
  352     pa_assert(key);
  353 
  354     e = pa_hashmap_first(db->map);
  355 
  356     if (!e)
  357         return NULL;
  358 
  359     key->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL;
  360     key->size = e->key.size;
  361 
  362     if (data) {
  363         data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
  364         data->size = e->data.size;
  365     }
  366 
  367     return key;
  368 }
  369 
  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;
  372     entry *e;
  373     entry *search;
  374     void *state;
  375     bool pick_now;
  376 
  377     pa_assert(db);
  378     pa_assert(next);
  379 
  380     if (!key)
  381         return pa_database_first(database, next, data);
  382 
  383     search = pa_hashmap_get(db->map, key);
  384 
  385     state = NULL;
  386     pick_now = false;
  387 
  388     while ((e = pa_hashmap_iterate(db->map, &state, NULL))) {
  389         if (pick_now)
  390             break;
  391 
  392         if (search == e)
  393             pick_now = true;
  394     }
  395 
  396     if (!pick_now || !e)
  397         return NULL;
  398 
  399     next->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL;
  400     next->size = e->key.size;
  401 
  402     if (data) {
  403         data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
  404         data->size = e->data.size;
  405     }
  406 
  407     return next;
  408 }
  409 
  410 static int write_uint(FILE *f, const uint32_t num) {
  411     size_t items;
  412     uint8_t values[4];
  413     int i;
  414     errno = 0;
  415 
  416     for (i = 0; i < 4; i++)
  417         values[i] = (num >> (i*8)) & 0xFF;
  418 
  419     items = fwrite(&values, sizeof(values), sizeof(uint8_t), f);
  420 
  421     if (ferror(f))
  422         return -1;
  423 
  424     return items;
  425 }
  426 
  427 static int write_data(FILE *f, void *data, const size_t length) {
  428     size_t items;
  429     uint32_t len;
  430 
  431     len = length;
  432     if ((items = write_uint(f, len)) <= 0)
  433         return -1;
  434 
  435     items = fwrite(data, length, 1, f);
  436 
  437     if (ferror(f) || items != 1)
  438         return -1;
  439 
  440     return 0;
  441 }
  442 
  443 static int write_entry(FILE *f, const entry *e) {
  444     pa_assert(f);
  445     pa_assert(e);
  446 
  447     if (write_data(f, e->key.data, e->key.size) < 0)
  448         return -1;
  449     if (write_data(f, e->data.data, e->data.size) < 0)
  450         return -1;
  451 
  452     return 0;
  453 }
  454 
  455 int pa_database_sync(pa_database *database) {
  456     simple_data *db = (simple_data*)database;
  457     FILE *f;
  458     void *state;
  459     entry *e;
  460 
  461     pa_assert(db);
  462 
  463     if (db->read_only)
  464         return 0;
  465 
  466     errno = 0;
  467 
  468     f = pa_fopen_cloexec(db->tmp_filename, "w");
  469 
  470     if (!f)
  471         goto fail;
  472 
  473     state = NULL;
  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));
  477             goto fail;
  478         }
  479     }
  480 
  481     fclose(f);
  482     f = NULL;
  483 
  484     if (rename(db->tmp_filename, db->filename) < 0) {
  485         pa_log_warn("error while renaming file. %s", pa_cstrerror(errno));
  486         goto fail;
  487     }
  488 
  489     return 0;
  490 
  491 fail:
  492     if (f)
  493         fclose(f);
  494     return -1;
  495 }