Bug Summary

File:cache.c
Warning:line 429, column 35
the computation of the size of the memory allocation may overflow

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cache.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -fapprox-func -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -D HAVE_CONFIG_H -I . -I .. -D KA_PLUGIN_PATH="/usr/local/lib/libkanberra-0.31" -D KA_MACHINE_ID="/usr/local/var/lib/dbus/machine-id" -D PIC -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-long-long -Wno-overlength-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -fconst-strings -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2022-12-26-200720-18488-1 -x c cache.c
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
50static ka_mutex *mutex = NULL((void*)0);
51static struct tdb_context *database = NULL((void*)0);
52
53static void allocate_mutex_once(void) {
54 mutex = ka_mutex_new();
55}
56
57static 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
69static 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
93static 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
113static 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
162static 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
223finish:
224 ka_mutex_unlock(mutex);
225
226 return ret;
227}
228
229#ifdef KA_GCC_DESTRUCTOR__attribute__ ((destructor))
230
231static void db_close(void) KA_GCC_DESTRUCTOR__attribute__ ((destructor));
232
233static 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
252static 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
279finish:
280 ka_mutex_unlock(mutex);
281
282 return ret;
283}
284
285static 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
312finish:
313 ka_mutex_unlock(mutex);
314
315 return ret;
316}
317
318static 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
341finish:
342 ka_mutex_unlock(mutex);
343
344 return ret;
345}
346
347static 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
378static 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
455finish:
456
457 ka_mutex_unlock(mutex);
458
459 return ret;
460}
461
462int 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(&timestamp, 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
540finish:
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
554int 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}