File: | cache.c |
Warning: | line 429, column 35 the computation of the size of the memory allocation may overflow |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /*-*- Mode: C; c-basic-offset: 8 -*-*/ |
2 | |
3 | /*** |
4 | This file is part of libkanberra. |
5 | |
6 | Copyright 2008 Lennart Poettering |
7 | |
8 | libkanberra is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU Lesser General Public License as |
10 | published by the Free Software Foundation, either version 2.1 of the |
11 | License, or (at your option) any later version. |
12 | |
13 | libkanberra is distributed in the hope that it will be useful, but |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | Lesser General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU Lesser General Public |
19 | License along with libkanberra. If not, see |
20 | <http://www.gnu.org/licenses/>. |
21 | ***/ |
22 | |
23 | #ifdef HAVE_CONFIG_H1 |
24 | #include <config.h> |
25 | #endif |
26 | |
27 | #include <sys/stat.h> |
28 | #include <sys/types.h> |
29 | #include <signal.h> |
30 | #include <fcntl.h> |
31 | #include <unistd.h> |
32 | #include <pthread.h> |
33 | #include <errno(*__errno_location ()).h> |
34 | |
35 | #include <tdb.h> |
36 | |
37 | #include "malloc.h" |
38 | #include "macro.h" |
39 | #include "mutex.h" |
40 | #include "kanberra.h" |
41 | #include "sound-theme-spec.h" |
42 | #include "cache.h" |
43 | |
44 | #define FILENAME"event-sound-cache.tdb" "event-sound-cache.tdb" |
45 | #define UPDATE_INTERVAL10 10 |
46 | |
47 | /* This part is not portable due to pthread_once usage, should be abstracted |
48 | * when we port this to platforms that do not have POSIX threading */ |
49 | |
50 | static ka_mutex *mutex = NULL((void*)0); |
51 | static struct tdb_context *database = NULL((void*)0); |
52 | |
53 | static void allocate_mutex_once(void) { |
54 | mutex = ka_mutex_new(); |
55 | } |
56 | |
57 | static int allocate_mutex(void) { |
58 | static pthread_once_t once = PTHREAD_ONCE_INIT0; |
59 | |
60 | if (pthread_once(&once, allocate_mutex_once) != 0) |
61 | return KA_ERROR_OOM; |
62 | |
63 | if (!mutex) |
64 | return KA_ERROR_OOM; |
65 | |
66 | return 0; |
67 | } |
68 | |
69 | static int get_cache_home(char **e) { |
70 | const char *env, *subdir; |
71 | char *r; |
72 | |
73 | ka_return_val_if_fail(e, KA_ERROR_INVALID)do { if ((__builtin_expect((!(e)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "e" , "cache.c", 73, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
74 | |
75 | if ((env = getenv("XDG_CACHE_HOME")) && *env == '/') |
76 | subdir = ""; |
77 | else if ((env = getenv("HOME")) && *env == '/') |
78 | subdir = "/.cache"; |
79 | else { |
80 | *e = NULL((void*)0); |
81 | return KA_SUCCESS; |
82 | } |
83 | |
84 | if (!(r = ka_new(char, strlen(env) + strlen(subdir) + 1)((char*) malloc(sizeof(char)*(strlen(env) + strlen(subdir) + 1 ))))) |
85 | return KA_ERROR_OOM; |
86 | |
87 | sprintf(r, "%s%s", env, subdir); |
88 | *e = r; |
89 | |
90 | return KA_SUCCESS; |
91 | } |
92 | |
93 | static int sensible_gethostbyname(char *n, size_t l) { |
94 | |
95 | if (gethostname(n, l) < 0) |
96 | return -1; |
97 | |
98 | n[l-1] = 0; |
99 | |
100 | if (strlen(n) >= l-1) { |
101 | errno(*__errno_location ()) = ENAMETOOLONG36; |
102 | return -1; |
103 | } |
104 | |
105 | if (!n[0]) { |
106 | errno(*__errno_location ()) = ENOENT2; |
107 | return -1; |
108 | } |
109 | |
110 | return 0; |
111 | } |
112 | |
113 | static int get_machine_id(char **id) { |
114 | FILE *f; |
115 | size_t l; |
116 | |
117 | ka_return_val_if_fail(id, KA_ERROR_INVALID)do { if ((__builtin_expect((!(id)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "id" , "cache.c", 117, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
118 | |
119 | /* First we try the D-Bus machine id */ |
120 | |
121 | if ((f = fopen(KA_MACHINE_ID"/usr/local/var/lib/dbus/machine-id", "r"))) { |
122 | char ln[34] = "", *r; |
123 | |
124 | r = fgets(ln, sizeof(ln)-1, f); |
125 | fclose(f); |
126 | |
127 | if (r) { |
128 | ln[strcspn(ln, " \n\r\t")] = 0; |
129 | |
130 | if (!(*id = ka_strdupstrdup(ln))) |
131 | return KA_ERROR_OOM; |
132 | |
133 | return KA_SUCCESS; |
134 | } |
135 | } |
136 | |
137 | /* Then we try the host name */ |
138 | |
139 | l = 100; |
140 | |
141 | for (;;) { |
142 | if (!(*id = ka_new(char, l)((char*) malloc(sizeof(char)*(l))))) |
143 | return KA_ERROR_OOM; |
144 | |
145 | if (sensible_gethostbyname(*id, l) >= 0) |
146 | return KA_SUCCESS; |
147 | |
148 | ka_freefree(*id); |
149 | |
150 | if (errno(*__errno_location ()) != EINVAL22 && errno(*__errno_location ()) != ENAMETOOLONG36) |
151 | break; |
152 | |
153 | l *= 2; |
154 | } |
155 | |
156 | /* Then we use the POSIX host id */ |
157 | |
158 | *id = ka_sprintf_malloc("%08lx", (unsigned long) gethostid()); |
159 | return KA_SUCCESS; |
160 | } |
161 | |
162 | static int db_open(void) { |
163 | int ret; |
164 | char *c, *id, *pn; |
165 | |
166 | if ((ret = allocate_mutex()) < 0) |
167 | return ret; |
168 | |
169 | ka_mutex_lock(mutex); |
170 | |
171 | if (database) { |
172 | ret = KA_SUCCESS; |
173 | goto finish; |
174 | } |
175 | |
176 | if ((ret = get_cache_home(&c)) < 0) |
177 | goto finish; |
178 | |
179 | if (!c) { |
180 | ret = KA_ERROR_NOTFOUND; |
181 | goto finish; |
182 | } |
183 | |
184 | /* Try to create, just in case it doesn't exist yet. We don't do |
185 | * this recursively however. */ |
186 | mkdir(c, 0755); |
187 | |
188 | if ((ret = get_machine_id(&id)) < 0) { |
189 | ka_freefree(c); |
190 | goto finish; |
191 | } |
192 | |
193 | /* This data is machine specific, hence we include some kind of |
194 | * stable machine id here in the name. Also, we don't want to care |
195 | * abouth endianess/packing issues, hence we include the compiler |
196 | * target in the name, too. */ |
197 | |
198 | pn = ka_sprintf_malloc("%s/" FILENAME"event-sound-cache.tdb" ".%s." CANONICAL_HOST"x86_64-pc-linux-gnu", c, id); |
199 | ka_freefree(c); |
200 | ka_freefree(id); |
201 | |
202 | if (!pn) { |
203 | ret = KA_ERROR_OOM; |
204 | goto finish; |
205 | } |
206 | |
207 | /* We pass TDB_NOMMAP here as long as rhbz 460851 is not fixed in |
208 | * tdb. */ |
209 | database = tdb_open(pn, 0, TDB_NOMMAP8, O_RDWR02|O_CREAT0100|O_NOCTTY0400 |
210 | #ifdef O_CLOEXEC02000000 |
211 | | O_CLOEXEC02000000 |
212 | #endif |
213 | , 0644); |
214 | ka_freefree(pn); |
215 | |
216 | if (!database) { |
217 | ret = KA_ERROR_CORRUPT; |
218 | goto finish; |
219 | } |
220 | |
221 | ret = KA_SUCCESS; |
222 | |
223 | finish: |
224 | ka_mutex_unlock(mutex); |
225 | |
226 | return ret; |
227 | } |
228 | |
229 | #ifdef KA_GCC_DESTRUCTOR__attribute__ ((destructor)) |
230 | |
231 | static void db_close(void) KA_GCC_DESTRUCTOR__attribute__ ((destructor)); |
232 | |
233 | static void db_close(void) { |
234 | /* Only here to make this valgrind clean */ |
235 | |
236 | if (!getenv("VALGRIND")) |
237 | return; |
238 | |
239 | if (mutex) { |
240 | ka_mutex_free(mutex); |
241 | mutex = NULL((void*)0); |
242 | } |
243 | |
244 | if (database) { |
245 | tdb_close(database); |
246 | database = NULL((void*)0); |
247 | } |
248 | } |
249 | |
250 | #endif |
251 | |
252 | static int db_lookup(const void *key, size_t klen, void **data, size_t *dlen) { |
253 | int ret; |
254 | TDB_DATA k, d; |
255 | |
256 | ka_return_val_if_fail(key, KA_ERROR_INVALID)do { if ((__builtin_expect((!(key)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "key" , "cache.c", 256, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
257 | ka_return_val_if_fail(klen > 0, KA_ERROR_INVALID)do { if ((__builtin_expect((!(klen > 0)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "klen > 0" , "cache.c", 257, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID); } } while((0)); |
258 | ka_return_val_if_fail(data, KA_ERROR_INVALID)do { if ((__builtin_expect((!(data)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "data" , "cache.c", 258, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
259 | ka_return_val_if_fail(dlen, KA_ERROR_INVALID)do { if ((__builtin_expect((!(dlen)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "dlen" , "cache.c", 259, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
260 | |
261 | if ((ret = db_open()) < 0) |
262 | return ret; |
263 | |
264 | k.dptr = (void*) key; |
265 | k.dsize = klen; |
266 | |
267 | ka_mutex_lock(mutex); |
268 | |
269 | ka_assert(database)do { if ((__builtin_expect((!(database)),0))) { fprintf(stderr , "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "database" , "cache.c", 269, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
270 | d = tdb_fetch(database, k); |
271 | if (!d.dptr) { |
272 | ret = KA_ERROR_NOTFOUND; |
273 | goto finish; |
274 | } |
275 | |
276 | *data = d.dptr; |
277 | *dlen = d.dsize; |
278 | |
279 | finish: |
280 | ka_mutex_unlock(mutex); |
281 | |
282 | return ret; |
283 | } |
284 | |
285 | static int db_store(const void *key, size_t klen, const void *data, size_t dlen) { |
286 | int ret; |
287 | TDB_DATA k, d; |
288 | |
289 | ka_return_val_if_fail(key, KA_ERROR_INVALID)do { if ((__builtin_expect((!(key)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "key" , "cache.c", 289, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
290 | ka_return_val_if_fail(klen > 0, KA_ERROR_INVALID)do { if ((__builtin_expect((!(klen > 0)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "klen > 0" , "cache.c", 290, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID); } } while((0)); |
291 | ka_return_val_if_fail(data || dlen == 0, KA_ERROR_INVALID)do { if ((__builtin_expect((!(data || dlen == 0)),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "data || dlen == 0" , "cache.c", 291, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID); } } while((0)); |
292 | |
293 | if ((ret = db_open()) < 0) |
294 | return ret; |
295 | |
296 | k.dptr = (void*) key; |
297 | k.dsize = klen; |
298 | |
299 | d.dptr = (void*) data; |
300 | d.dsize = dlen; |
301 | |
302 | ka_mutex_lock(mutex); |
303 | |
304 | ka_assert(database)do { if ((__builtin_expect((!(database)),0))) { fprintf(stderr , "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "database" , "cache.c", 304, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
305 | if (tdb_store(database, k, d, TDB_REPLACE1) < 0) { |
306 | ret = KA_ERROR_CORRUPT; |
307 | goto finish; |
308 | } |
309 | |
310 | ret = KA_SUCCESS; |
311 | |
312 | finish: |
313 | ka_mutex_unlock(mutex); |
314 | |
315 | return ret; |
316 | } |
317 | |
318 | static int db_remove(const void *key, size_t klen) { |
319 | int ret; |
320 | TDB_DATA k; |
321 | |
322 | ka_return_val_if_fail(key, KA_ERROR_INVALID)do { if ((__builtin_expect((!(key)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "key" , "cache.c", 322, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
323 | ka_return_val_if_fail(klen > 0, KA_ERROR_INVALID)do { if ((__builtin_expect((!(klen > 0)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "klen > 0" , "cache.c", 323, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID); } } while((0)); |
324 | |
325 | if ((ret = db_open()) < 0) |
326 | return ret; |
327 | |
328 | k.dptr = (void*) key; |
329 | k.dsize = klen; |
330 | |
331 | ka_mutex_lock(mutex); |
332 | |
333 | ka_assert(database)do { if ((__builtin_expect((!(database)),0))) { fprintf(stderr , "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "database" , "cache.c", 333, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
334 | if (tdb_delete(database, k) < 0) { |
335 | ret = KA_ERROR_CORRUPT; |
336 | goto finish; |
337 | } |
338 | |
339 | ret = KA_SUCCESS; |
340 | |
341 | finish: |
342 | ka_mutex_unlock(mutex); |
343 | |
344 | return ret; |
345 | } |
346 | |
347 | static char *build_key( |
348 | const char *theme, |
349 | const char *name, |
350 | const char *locale, |
351 | const char *profile, |
352 | size_t *klen) { |
353 | |
354 | char *key, *k; |
355 | size_t tl, nl, ll, pl; |
356 | |
357 | tl = strlen(theme); |
358 | nl = strlen(name); |
359 | ll = strlen(locale); |
360 | pl = strlen(profile); |
361 | *klen = tl+1+nl+1+ll+1+pl+1; |
362 | |
363 | if (!(key = ka_new(char, *klen)((char*) malloc(sizeof(char)*(*klen))))) |
364 | return NULL((void*)0); |
365 | |
366 | k = key; |
367 | strcpy(k, theme); |
368 | k += tl+1; |
369 | strcpy(k, name); |
370 | k += nl+1; |
371 | strcpy(k, locale); |
372 | k += ll+1; |
373 | strcpy(k, profile); |
374 | |
375 | return key; |
376 | } |
377 | |
378 | static int get_last_change(time_t *t) { |
379 | int ret; |
380 | char *e, *k; |
381 | struct stat st; |
382 | static time_t last_check = 0, last_change = 0; |
383 | time_t now; |
384 | const char *g; |
385 | |
386 | ka_return_val_if_fail(t, KA_ERROR_INVALID)do { if ((__builtin_expect((!(t)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "t" , "cache.c", 386, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
387 | |
388 | if ((ret = allocate_mutex()) < 0) |
389 | return ret; |
390 | |
391 | ka_mutex_lock(mutex); |
392 | |
393 | ka_assert_se(time(&now) != (time_t) -1)do { if ((__builtin_expect((!(time(&now) != (time_t) -1)) ,0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "time(&now) != (time_t) -1" , "cache.c", 393, __PRETTY_FUNCTION__ ); abort(); } } while ((0)); |
394 | |
395 | if (now < last_check + UPDATE_INTERVAL10) { |
396 | *t = last_change; |
397 | ret = KA_SUCCESS; |
398 | goto finish; |
399 | } |
400 | |
401 | if ((ret = ka_get_data_home(&e)) < 0) |
402 | goto finish; |
403 | |
404 | *t = 0; |
405 | |
406 | if (e) { |
407 | if (!(k = ka_new(char, strlen(e) + sizeof("/sounds"))((char*) malloc(sizeof(char)*(strlen(e) + sizeof("/sounds"))) ))) { |
408 | ka_freefree(e); |
409 | ret = KA_ERROR_OOM; |
410 | goto finish; |
411 | } |
412 | |
413 | sprintf(k, "%s/sounds", e); |
414 | ka_freefree(e); |
415 | |
416 | if (stat(k, &st) >= 0) |
417 | *t = st.st_mtimest_mtim.tv_sec; |
418 | |
419 | ka_freefree(k); |
420 | } |
421 | |
422 | g = ka_get_data_dirs(); |
423 | |
424 | for (;;) { |
425 | size_t j = strcspn(g, ":"); |
426 | |
427 | if (g[0] == '/' && j > 0) { |
428 | |
429 | if (!(k = ka_new(char, j + sizeof("/sounds"))((char*) malloc(sizeof(char)*(j + sizeof("/sounds")))))) { |
the computation of the size of the memory allocation may overflow | |
430 | ret = KA_ERROR_OOM; |
431 | goto finish; |
432 | } |
433 | |
434 | memcpy(k, g, j); |
435 | strcpy(k+j, "/sounds"); |
436 | |
437 | if (stat(k, &st) >= 0) |
438 | if (st.st_mtimest_mtim.tv_sec >= *t) |
439 | *t = st.st_mtimest_mtim.tv_sec; |
440 | |
441 | ka_freefree(k); |
442 | } |
443 | |
444 | if (g[j] == 0) |
445 | break; |
446 | |
447 | g += j+1; |
448 | } |
449 | |
450 | last_change = *t; |
451 | last_check = now; |
452 | |
453 | ret = 0; |
454 | |
455 | finish: |
456 | |
457 | ka_mutex_unlock(mutex); |
458 | |
459 | return ret; |
460 | } |
461 | |
462 | int ka_cache_lookup_sound( |
463 | ka_sound_file **f, |
464 | ka_sound_file_open_callback_t sfopen, |
465 | char **sound_path, |
466 | const char *theme, |
467 | const char *name, |
468 | const char *locale, |
469 | const char *profile) { |
470 | |
471 | char *key = NULL((void*)0); |
472 | void *data = NULL((void*)0); |
473 | size_t klen, dlen; |
474 | int ret; |
475 | uint32_t timestamp; |
476 | time_t last_change, now; |
477 | ka_bool_t remove_entry = FALSE(0); |
478 | |
479 | ka_return_val_if_fail(f, KA_ERROR_INVALID)do { if ((__builtin_expect((!(f)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "f" , "cache.c", 479, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
480 | ka_return_val_if_fail(sfopen, KA_ERROR_INVALID)do { if ((__builtin_expect((!(sfopen)),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "sfopen" , "cache.c", 480, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
481 | ka_return_val_if_fail(theme, KA_ERROR_INVALID)do { if ((__builtin_expect((!(theme)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "theme" , "cache.c", 481, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
482 | ka_return_val_if_fail(name && *name, KA_ERROR_INVALID)do { if ((__builtin_expect((!(name && *name)),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "name && *name" , "cache.c", 482, __PRETTY_FUNCTION__ ); return (KA_ERROR_INVALID); } } while((0)); |
483 | ka_return_val_if_fail(locale, KA_ERROR_INVALID)do { if ((__builtin_expect((!(locale)),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "locale" , "cache.c", 483, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
484 | ka_return_val_if_fail(profile, KA_ERROR_INVALID)do { if ((__builtin_expect((!(profile)),0))) { if (ka_debug() ) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "profile" , "cache.c", 484, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
485 | |
486 | if (sound_path) |
487 | *sound_path = NULL((void*)0); |
488 | |
489 | if (!(key = build_key(theme, name, locale, profile, &klen))) |
490 | return KA_ERROR_OOM; |
491 | |
492 | ret = db_lookup(key, klen, &data, &dlen); |
493 | |
494 | if (ret < 0) |
495 | goto finish; |
496 | |
497 | ka_assert(data)do { if ((__builtin_expect((!(data)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "data" , "cache.c", 497, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
498 | |
499 | if (dlen < sizeof(uint32_t) || |
500 | (dlen > sizeof(uint32_t) && ((char*) data)[dlen-1] != 0)) { |
501 | |
502 | /* Corrupt entry */ |
503 | ret = KA_ERROR_NOTFOUND; |
504 | remove_entry = TRUE(!(0)); |
505 | goto finish; |
506 | } |
507 | |
508 | memcpy(×tamp, data, sizeof(timestamp)); |
509 | |
510 | if ((ret = get_last_change(&last_change)) < 0) |
511 | goto finish; |
512 | |
513 | ka_assert_se(time(&now) != (time_t) -1)do { if ((__builtin_expect((!(time(&now) != (time_t) -1)) ,0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "time(&now) != (time_t) -1" , "cache.c", 513, __PRETTY_FUNCTION__ ); abort(); } } while ((0)); |
514 | |
515 | /* Hmm, is the entry older than the last change to our sound theme |
516 | * dirs? Also, check for clock skews */ |
517 | if ((time_t) timestamp < last_change || ((time_t) timestamp > now)) { |
518 | remove_entry = TRUE(!(0)); |
519 | ret = KA_ERROR_NOTFOUND; |
520 | goto finish; |
521 | } |
522 | |
523 | if (dlen <= sizeof(uint32_t)) { |
524 | /* Negative caching entry. */ |
525 | *f = NULL((void*)0); |
526 | ret = KA_SUCCESS; |
527 | goto finish; |
528 | } |
529 | |
530 | if (sound_path) { |
531 | if (!(*sound_path = ka_strdupstrdup((const char*) data + sizeof(uint32_t)))) { |
532 | ret = KA_ERROR_OOM; |
533 | goto finish; |
534 | } |
535 | } |
536 | |
537 | if ((ret = sfopen(f, (const char*) data + sizeof(uint32_t))) < 0) |
538 | remove_entry = TRUE(!(0)); |
539 | |
540 | finish: |
541 | |
542 | if (remove_entry) |
543 | db_remove(key, klen); |
544 | |
545 | if (sound_path && ret < 0) |
546 | ka_freefree(*sound_path); |
547 | |
548 | ka_freefree(key); |
549 | ka_freefree(data); |
550 | |
551 | return ret; |
552 | } |
553 | |
554 | int ka_cache_store_sound( |
555 | const char *theme, |
556 | const char *name, |
557 | const char *locale, |
558 | const char *profile, |
559 | const char *fname) { |
560 | |
561 | char *key; |
562 | void *data; |
563 | size_t klen, dlen; |
564 | int ret; |
565 | time_t now; |
566 | |
567 | ka_return_val_if_fail(theme, KA_ERROR_INVALID)do { if ((__builtin_expect((!(theme)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "theme" , "cache.c", 567, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
568 | ka_return_val_if_fail(name && *name, KA_ERROR_INVALID)do { if ((__builtin_expect((!(name && *name)),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "name && *name" , "cache.c", 568, __PRETTY_FUNCTION__ ); return (KA_ERROR_INVALID); } } while((0)); |
569 | ka_return_val_if_fail(locale, KA_ERROR_INVALID)do { if ((__builtin_expect((!(locale)),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "locale" , "cache.c", 569, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
570 | ka_return_val_if_fail(profile, KA_ERROR_INVALID)do { if ((__builtin_expect((!(profile)),0))) { if (ka_debug() ) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "profile" , "cache.c", 570, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
571 | |
572 | if (!(key = build_key(theme, name, locale, profile, &klen))) |
573 | return KA_ERROR_OOM; |
574 | |
575 | dlen = sizeof(uint32_t) + (fname ? strlen(fname) + 1 : 0); |
576 | |
577 | if (!(data = ka_mallocmalloc(dlen))) { |
578 | ka_freefree(key); |
579 | return KA_ERROR_OOM; |
580 | } |
581 | |
582 | ka_assert_se(time(&now) != (time_t) -1)do { if ((__builtin_expect((!(time(&now) != (time_t) -1)) ,0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "time(&now) != (time_t) -1" , "cache.c", 582, __PRETTY_FUNCTION__ ); abort(); } } while ((0)); |
583 | *(uint32_t*) data = (uint32_t) now; |
584 | |
585 | if (fname) |
586 | strcpy((char*) data + sizeof(uint32_t), fname); |
587 | |
588 | ret = db_store(key, klen, data, dlen); |
589 | |
590 | ka_freefree(key); |
591 | ka_freefree(data); |
592 | |
593 | return ret; |
594 | } |