|
Packit |
3ae693 |
/*-*- Mode: C; c-basic-offset: 8 -*-*/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/***
|
|
Packit |
3ae693 |
This file is part of libcanberra.
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
Copyright 2008 Lennart Poettering
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
libcanberra is free software; you can redistribute it and/or modify
|
|
Packit |
3ae693 |
it under the terms of the GNU Lesser General Public License as
|
|
Packit |
3ae693 |
published by the Free Software Foundation, either version 2.1 of the
|
|
Packit |
3ae693 |
License, or (at your option) any later version.
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
libcanberra is distributed in the hope that it will be useful, but
|
|
Packit |
3ae693 |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
3ae693 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
3ae693 |
Lesser General Public License for more details.
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
3ae693 |
License along with libcanberra. If not, see
|
|
Packit |
3ae693 |
<http://www.gnu.org/licenses/>.
|
|
Packit |
3ae693 |
***/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
3ae693 |
#include <config.h>
|
|
Packit |
3ae693 |
#endif
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#include <sys/stat.h>
|
|
Packit |
3ae693 |
#include <sys/types.h>
|
|
Packit |
3ae693 |
#include <signal.h>
|
|
Packit |
3ae693 |
#include <fcntl.h>
|
|
Packit |
3ae693 |
#include <unistd.h>
|
|
Packit |
3ae693 |
#include <pthread.h>
|
|
Packit |
3ae693 |
#include <errno.h>
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#include <tdb.h>
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#include "malloc.h"
|
|
Packit |
3ae693 |
#include "macro.h"
|
|
Packit |
3ae693 |
#include "mutex.h"
|
|
Packit |
3ae693 |
#include "canberra.h"
|
|
Packit |
3ae693 |
#include "sound-theme-spec.h"
|
|
Packit |
3ae693 |
#include "cache.h"
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#define FILENAME "event-sound-cache.tdb"
|
|
Packit |
3ae693 |
#define UPDATE_INTERVAL 10
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* This part is not portable due to pthread_once usage, should be abstracted
|
|
Packit |
3ae693 |
* when we port this to platforms that do not have POSIX threading */
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static ca_mutex *mutex = NULL;
|
|
Packit |
3ae693 |
static struct tdb_context *database = NULL;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static void allocate_mutex_once(void) {
|
|
Packit |
3ae693 |
mutex = ca_mutex_new();
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static int allocate_mutex(void) {
|
|
Packit |
3ae693 |
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (pthread_once(&once, allocate_mutex_once) != 0)
|
|
Packit |
3ae693 |
return CA_ERROR_OOM;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!mutex)
|
|
Packit |
3ae693 |
return CA_ERROR_OOM;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return 0;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static int get_cache_home(char **e) {
|
|
Packit |
3ae693 |
const char *env, *subdir;
|
|
Packit |
3ae693 |
char *r;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(e, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((env = getenv("XDG_CACHE_HOME")) && *env == '/')
|
|
Packit |
3ae693 |
subdir = "";
|
|
Packit |
3ae693 |
else if ((env = getenv("HOME")) && *env == '/')
|
|
Packit |
3ae693 |
subdir = "/.cache";
|
|
Packit |
3ae693 |
else {
|
|
Packit |
3ae693 |
*e = NULL;
|
|
Packit |
3ae693 |
return CA_SUCCESS;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(r = ca_new(char, strlen(env) + strlen(subdir) + 1)))
|
|
Packit |
3ae693 |
return CA_ERROR_OOM;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
sprintf(r, "%s%s", env, subdir);
|
|
Packit |
3ae693 |
*e = r;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return CA_SUCCESS;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static int sensible_gethostbyname(char *n, size_t l) {
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (gethostname(n, l) < 0)
|
|
Packit |
3ae693 |
return -1;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
n[l-1] = 0;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (strlen(n) >= l-1) {
|
|
Packit |
3ae693 |
errno = ENAMETOOLONG;
|
|
Packit |
3ae693 |
return -1;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!n[0]) {
|
|
Packit |
3ae693 |
errno = ENOENT;
|
|
Packit |
3ae693 |
return -1;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return 0;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static int get_machine_id(char **id) {
|
|
Packit |
3ae693 |
FILE *f;
|
|
Packit |
3ae693 |
size_t l;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(id, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* First we try the D-Bus machine id */
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((f = fopen(CA_MACHINE_ID, "r"))) {
|
|
Packit |
3ae693 |
char ln[34] = "", *r;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
r = fgets(ln, sizeof(ln)-1, f);
|
|
Packit |
3ae693 |
fclose(f);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (r) {
|
|
Packit |
3ae693 |
ln[strcspn(ln, " \n\r\t")] = 0;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(*id = ca_strdup(ln)))
|
|
Packit |
3ae693 |
return CA_ERROR_OOM;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return CA_SUCCESS;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* Then we try the host name */
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
l = 100;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
for (;;) {
|
|
Packit |
3ae693 |
if (!(*id = ca_new(char, l)))
|
|
Packit |
3ae693 |
return CA_ERROR_OOM;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (sensible_gethostbyname(*id, l) >= 0)
|
|
Packit |
3ae693 |
return CA_SUCCESS;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_free(*id);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (errno != EINVAL && errno != ENAMETOOLONG)
|
|
Packit |
3ae693 |
break;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
l *= 2;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* Then we use the POSIX host id */
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
*id = ca_sprintf_malloc("%08lx", (unsigned long) gethostid());
|
|
Packit |
3ae693 |
return CA_SUCCESS;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static int db_open(void) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
char *c, *id, *pn;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = allocate_mutex()) < 0)
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_lock(mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (database) {
|
|
Packit |
3ae693 |
ret = CA_SUCCESS;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = get_cache_home(&c)) < 0)
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!c) {
|
|
Packit |
3ae693 |
ret = CA_ERROR_NOTFOUND;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* Try to create, just in case it doesn't exist yet. We don't do
|
|
Packit |
3ae693 |
* this recursively however. */
|
|
Packit |
3ae693 |
mkdir(c, 0755);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = get_machine_id(&id)) < 0) {
|
|
Packit |
3ae693 |
ca_free(c);
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* This data is machine specific, hence we include some kind of
|
|
Packit |
3ae693 |
* stable machine id here in the name. Also, we don't want to care
|
|
Packit |
3ae693 |
* abouth endianess/packing issues, hence we include the compiler
|
|
Packit |
3ae693 |
* target in the name, too. */
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
pn = ca_sprintf_malloc("%s/" FILENAME ".%s." CANONICAL_HOST, c, id);
|
|
Packit |
3ae693 |
ca_free(c);
|
|
Packit |
3ae693 |
ca_free(id);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!pn) {
|
|
Packit |
3ae693 |
ret = CA_ERROR_OOM;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* We pass TDB_NOMMAP here as long as rhbz 460851 is not fixed in
|
|
Packit |
3ae693 |
* tdb. */
|
|
Packit |
3ae693 |
database = tdb_open(pn, 0, TDB_NOMMAP, O_RDWR|O_CREAT|O_NOCTTY
|
|
Packit |
3ae693 |
#ifdef O_CLOEXEC
|
|
Packit |
3ae693 |
| O_CLOEXEC
|
|
Packit |
3ae693 |
#endif
|
|
Packit |
3ae693 |
, 0644);
|
|
Packit |
3ae693 |
ca_free(pn);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!database) {
|
|
Packit |
3ae693 |
ret = CA_ERROR_CORRUPT;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = CA_SUCCESS;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
finish:
|
|
Packit |
3ae693 |
ca_mutex_unlock(mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#ifdef CA_GCC_DESTRUCTOR
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static void db_close(void) CA_GCC_DESTRUCTOR;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static void db_close(void) {
|
|
Packit |
3ae693 |
/* Only here to make this valgrind clean */
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!getenv("VALGRIND"))
|
|
Packit |
3ae693 |
return;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (mutex) {
|
|
Packit |
3ae693 |
ca_mutex_free(mutex);
|
|
Packit |
3ae693 |
mutex = NULL;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (database) {
|
|
Packit |
3ae693 |
tdb_close(database);
|
|
Packit |
3ae693 |
database = NULL;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#endif
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static int db_lookup(const void *key, size_t klen, void **data, size_t *dlen) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
TDB_DATA k, d;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(key, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(klen > 0, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(data, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(dlen, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = db_open()) < 0)
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
k.dptr = (void*) key;
|
|
Packit |
3ae693 |
k.dsize = klen;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_lock(mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert(database);
|
|
Packit |
3ae693 |
d = tdb_fetch(database, k);
|
|
Packit |
3ae693 |
if (!d.dptr) {
|
|
Packit |
3ae693 |
ret = CA_ERROR_NOTFOUND;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
*data = d.dptr;
|
|
Packit |
3ae693 |
*dlen = d.dsize;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
finish:
|
|
Packit |
3ae693 |
ca_mutex_unlock(mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static int db_store(const void *key, size_t klen, const void *data, size_t dlen) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
TDB_DATA k, d;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(key, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(klen > 0, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(data || dlen == 0, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = db_open()) < 0)
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
k.dptr = (void*) key;
|
|
Packit |
3ae693 |
k.dsize = klen;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
d.dptr = (void*) data;
|
|
Packit |
3ae693 |
d.dsize = dlen;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_lock(mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert(database);
|
|
Packit |
3ae693 |
if (tdb_store(database, k, d, TDB_REPLACE) < 0) {
|
|
Packit |
3ae693 |
ret = CA_ERROR_CORRUPT;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = CA_SUCCESS;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
finish:
|
|
Packit |
3ae693 |
ca_mutex_unlock(mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static int db_remove(const void *key, size_t klen) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
TDB_DATA k;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(key, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(klen > 0, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = db_open()) < 0)
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
k.dptr = (void*) key;
|
|
Packit |
3ae693 |
k.dsize = klen;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_lock(mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert(database);
|
|
Packit |
3ae693 |
if (tdb_delete(database, k) < 0) {
|
|
Packit |
3ae693 |
ret = CA_ERROR_CORRUPT;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = CA_SUCCESS;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
finish:
|
|
Packit |
3ae693 |
ca_mutex_unlock(mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static char *build_key(
|
|
Packit |
3ae693 |
const char *theme,
|
|
Packit |
3ae693 |
const char *name,
|
|
Packit |
3ae693 |
const char *locale,
|
|
Packit |
3ae693 |
const char *profile,
|
|
Packit |
3ae693 |
size_t *klen) {
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
char *key, *k;
|
|
Packit |
3ae693 |
size_t tl, nl, ll, pl;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
tl = strlen(theme);
|
|
Packit |
3ae693 |
nl = strlen(name);
|
|
Packit |
3ae693 |
ll = strlen(locale);
|
|
Packit |
3ae693 |
pl = strlen(profile);
|
|
Packit |
3ae693 |
*klen = tl+1+nl+1+ll+1+pl+1;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(key = ca_new(char, *klen)))
|
|
Packit |
3ae693 |
return NULL;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
k = key;
|
|
Packit |
3ae693 |
strcpy(k, theme);
|
|
Packit |
3ae693 |
k += tl+1;
|
|
Packit |
3ae693 |
strcpy(k, name);
|
|
Packit |
3ae693 |
k += nl+1;
|
|
Packit |
3ae693 |
strcpy(k, locale);
|
|
Packit |
3ae693 |
k += ll+1;
|
|
Packit |
3ae693 |
strcpy(k, profile);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return key;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static int get_last_change(time_t *t) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
char *e, *k;
|
|
Packit |
3ae693 |
struct stat st;
|
|
Packit |
3ae693 |
static time_t last_check = 0, last_change = 0;
|
|
Packit |
3ae693 |
time_t now;
|
|
Packit |
3ae693 |
const char *g;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(t, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = allocate_mutex()) < 0)
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_lock(mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert_se(time(&now) != (time_t) -1);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (now < last_check + UPDATE_INTERVAL) {
|
|
Packit |
3ae693 |
*t = last_change;
|
|
Packit |
3ae693 |
ret = CA_SUCCESS;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = ca_get_data_home(&e)) < 0)
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
*t = 0;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (e) {
|
|
Packit |
3ae693 |
if (!(k = ca_new(char, strlen(e) + sizeof("/sounds")))) {
|
|
Packit |
3ae693 |
ca_free(e);
|
|
Packit |
3ae693 |
ret = CA_ERROR_OOM;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
sprintf(k, "%s/sounds", e);
|
|
Packit |
3ae693 |
ca_free(e);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (stat(k, &st) >= 0)
|
|
Packit |
3ae693 |
*t = st.st_mtime;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_free(k);
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
g = ca_get_data_dirs();
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
for (;;) {
|
|
Packit |
3ae693 |
size_t j = strcspn(g, ":");
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (g[0] == '/' && j > 0) {
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(k = ca_new(char, j + sizeof("/sounds")))) {
|
|
Packit |
3ae693 |
ret = CA_ERROR_OOM;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
memcpy(k, g, j);
|
|
Packit |
3ae693 |
strcpy(k+j, "/sounds");
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (stat(k, &st) >= 0)
|
|
Packit |
3ae693 |
if (st.st_mtime >= *t)
|
|
Packit |
3ae693 |
*t = st.st_mtime;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_free(k);
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (g[j] == 0)
|
|
Packit |
3ae693 |
break;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
g += j+1;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
last_change = *t;
|
|
Packit |
3ae693 |
last_check = now;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = 0;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
finish:
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_unlock(mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
int ca_cache_lookup_sound(
|
|
Packit |
3ae693 |
ca_sound_file **f,
|
|
Packit |
3ae693 |
ca_sound_file_open_callback_t sfopen,
|
|
Packit |
3ae693 |
char **sound_path,
|
|
Packit |
3ae693 |
const char *theme,
|
|
Packit |
3ae693 |
const char *name,
|
|
Packit |
3ae693 |
const char *locale,
|
|
Packit |
3ae693 |
const char *profile) {
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
char *key = NULL;
|
|
Packit |
3ae693 |
void *data = NULL;
|
|
Packit |
3ae693 |
size_t klen, dlen;
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
uint32_t timestamp;
|
|
Packit |
3ae693 |
time_t last_change, now;
|
|
Packit |
3ae693 |
ca_bool_t remove_entry = FALSE;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(f, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(sfopen, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(theme, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(name && *name, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(locale, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(profile, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (sound_path)
|
|
Packit |
3ae693 |
*sound_path = NULL;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(key = build_key(theme, name, locale, profile, &klen)))
|
|
Packit |
3ae693 |
return CA_ERROR_OOM;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = db_lookup(key, klen, &data, &dlen);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (ret < 0)
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert(data);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (dlen < sizeof(uint32_t) ||
|
|
Packit |
3ae693 |
(dlen > sizeof(uint32_t) && ((char*) data)[dlen-1] != 0)) {
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* Corrupt entry */
|
|
Packit |
3ae693 |
ret = CA_ERROR_NOTFOUND;
|
|
Packit |
3ae693 |
remove_entry = TRUE;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
memcpy(×tamp, data, sizeof(timestamp));
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = get_last_change(&last_change)) < 0)
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert_se(time(&now) != (time_t) -1);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* Hmm, is the entry older than the last change to our sound theme
|
|
Packit |
3ae693 |
* dirs? Also, check for clock skews */
|
|
Packit |
3ae693 |
if ((time_t) timestamp < last_change || ((time_t) timestamp > now)) {
|
|
Packit |
3ae693 |
remove_entry = TRUE;
|
|
Packit |
3ae693 |
ret = CA_ERROR_NOTFOUND;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (dlen <= sizeof(uint32_t)) {
|
|
Packit |
3ae693 |
/* Negative caching entry. */
|
|
Packit |
3ae693 |
*f = NULL;
|
|
Packit |
3ae693 |
ret = CA_SUCCESS;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (sound_path) {
|
|
Packit |
3ae693 |
if (!(*sound_path = ca_strdup((const char*) data + sizeof(uint32_t)))) {
|
|
Packit |
3ae693 |
ret = CA_ERROR_OOM;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = sfopen(f, (const char*) data + sizeof(uint32_t))) < 0)
|
|
Packit |
3ae693 |
remove_entry = TRUE;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
finish:
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (remove_entry)
|
|
Packit |
3ae693 |
db_remove(key, klen);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (sound_path && ret < 0)
|
|
Packit |
3ae693 |
ca_free(*sound_path);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_free(key);
|
|
Packit |
3ae693 |
ca_free(data);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
int ca_cache_store_sound(
|
|
Packit |
3ae693 |
const char *theme,
|
|
Packit |
3ae693 |
const char *name,
|
|
Packit |
3ae693 |
const char *locale,
|
|
Packit |
3ae693 |
const char *profile,
|
|
Packit |
3ae693 |
const char *fname) {
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
char *key;
|
|
Packit |
3ae693 |
void *data;
|
|
Packit |
3ae693 |
size_t klen, dlen;
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
time_t now;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(theme, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(name && *name, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(locale, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(profile, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(key = build_key(theme, name, locale, profile, &klen)))
|
|
Packit |
3ae693 |
return CA_ERROR_OOM;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
dlen = sizeof(uint32_t) + (fname ? strlen(fname) + 1 : 0);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(data = ca_malloc(dlen))) {
|
|
Packit |
3ae693 |
ca_free(key);
|
|
Packit |
3ae693 |
return CA_ERROR_OOM;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert_se(time(&now) != (time_t) -1);
|
|
Packit |
3ae693 |
*(uint32_t*) data = (uint32_t) now;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (fname)
|
|
Packit |
3ae693 |
strcpy((char*) data + sizeof(uint32_t), fname);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = db_store(key, klen, data, dlen);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_free(key);
|
|
Packit |
3ae693 |
ca_free(data);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|