Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2009 Lennart Poettering
5 : :
6 : : PulseAudio is free software; you can redistribute it and/or modify
7 : : it under the terms of the GNU Lesser General Public License as
8 : : published by the Free Software Foundation; either version 2.1 of the
9 : : License, or (at your option) any later version.
10 : :
11 : : PulseAudio is distributed in the hope that it will be useful, but
12 : : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : Lesser General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU Lesser General Public
17 : : License along with PulseAudio; if not, write to the Free Software
18 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 : : USA.
20 : : ***/
21 : :
22 : : #ifdef HAVE_CONFIG_H
23 : : #include <config.h>
24 : : #endif
25 : :
26 : : #include <fcntl.h>
27 : : #include <unistd.h>
28 : : #include <errno.h>
29 : :
30 : : /* Some versions of tdb lack inclusion of signal.h in the header files but use sigatomic_t */
31 : : #include <signal.h>
32 : : #include <tdb.h>
33 : :
34 : : #include <pulse/xmalloc.h>
35 : : #include <pulsecore/core-util.h>
36 : : #include <pulsecore/log.h>
37 : :
38 : : #include "database.h"
39 : :
40 : : #define MAKE_TDB_CONTEXT(x) ((struct tdb_context*) (x))
41 : :
42 : 0 : static inline TDB_DATA* datum_to_tdb(TDB_DATA *to, const pa_datum *from) {
43 [ # # ]: 0 : pa_assert(from);
44 [ # # ]: 0 : pa_assert(to);
45 : :
46 : 0 : to->dptr = from->data;
47 : 0 : to->dsize = from->size;
48 : :
49 : 0 : return to;
50 : : }
51 : :
52 : 0 : static inline pa_datum* datum_from_tdb(pa_datum *to, const TDB_DATA *from) {
53 [ # # ]: 0 : pa_assert(from);
54 [ # # ]: 0 : pa_assert(to);
55 : :
56 : 0 : to->data = from->dptr;
57 : 0 : to->size = from->dsize;
58 : :
59 : 0 : return to;
60 : : }
61 : :
62 : 0 : void pa_datum_free(pa_datum *d) {
63 [ # # ]: 0 : pa_assert(d);
64 : :
65 : 0 : free(d->data); /* tdb uses raw malloc/free hence we should do that here, too */
66 : : pa_zero(d);
67 : 0 : }
68 : :
69 : : static struct tdb_context *tdb_open_cloexec(
70 : : const char *name,
71 : : int hash_size,
72 : : int tdb_flags,
73 : : int open_flags,
74 : : mode_t mode) {
75 : :
76 : : /* Mimics pa_open_cloexec() */
77 : :
78 : : struct tdb_context *c;
79 : :
80 : : #ifdef O_NOCTTY
81 : 0 : open_flags |= O_NOCTTY;
82 : : #endif
83 : :
84 : : #ifdef O_CLOEXEC
85 : 0 : errno = 0;
86 [ # # ]: 0 : if ((c = tdb_open(name, hash_size, tdb_flags, open_flags | O_CLOEXEC, mode)))
87 : : goto finish;
88 : :
89 [ # # ]: 0 : if (errno != EINVAL)
90 : : return NULL;
91 : : #endif
92 : :
93 : 0 : errno = 0;
94 [ # # ]: 0 : if (!(c = tdb_open(name, hash_size, tdb_flags, open_flags, mode)))
95 : : return NULL;
96 : :
97 : : finish:
98 : 0 : pa_make_fd_cloexec(tdb_fd(c));
99 : : return c;
100 : : }
101 : :
102 : 0 : pa_database* pa_database_open(const char *fn, pa_bool_t for_write) {
103 : : struct tdb_context *c;
104 : : char *path;
105 : :
106 [ # # ]: 0 : pa_assert(fn);
107 : :
108 : 0 : path = pa_sprintf_malloc("%s.tdb", fn);
109 [ # # ][ # # ]: 0 : if ((c = tdb_open_cloexec(path, 0, TDB_NOSYNC|TDB_NOLOCK, (for_write ? O_RDWR|O_CREAT : O_RDONLY), 0644)))
110 : 0 : pa_log_debug("Opened TDB database '%s'", path);
111 : :
112 : 0 : pa_xfree(path);
113 : :
114 [ # # ]: 0 : if (!c) {
115 [ # # ]: 0 : if (errno == 0)
116 : 0 : errno = EIO;
117 : : return NULL;
118 : : }
119 : :
120 : : return (pa_database*) c;
121 : : }
122 : :
123 : 0 : void pa_database_close(pa_database *db) {
124 [ # # ]: 0 : pa_assert(db);
125 : :
126 : 0 : tdb_close(MAKE_TDB_CONTEXT(db));
127 : 0 : }
128 : :
129 : 0 : pa_datum* pa_database_get(pa_database *db, const pa_datum *key, pa_datum* data) {
130 : : TDB_DATA tdb_key, tdb_data;
131 : :
132 [ # # ]: 0 : pa_assert(db);
133 [ # # ]: 0 : pa_assert(key);
134 [ # # ]: 0 : pa_assert(data);
135 : :
136 : 0 : tdb_data = tdb_fetch(MAKE_TDB_CONTEXT(db), *datum_to_tdb(&tdb_key, key));
137 : :
138 : 0 : return tdb_data.dptr ?
139 [ # # ]: 0 : datum_from_tdb(data, &tdb_data) :
140 : : NULL;
141 : : }
142 : :
143 : 0 : int pa_database_set(pa_database *db, const pa_datum *key, const pa_datum* data, pa_bool_t overwrite) {
144 : : TDB_DATA tdb_key, tdb_data;
145 : :
146 [ # # ]: 0 : pa_assert(db);
147 [ # # ]: 0 : pa_assert(key);
148 [ # # ]: 0 : pa_assert(data);
149 : :
150 [ # # ]: 0 : return tdb_store(MAKE_TDB_CONTEXT(db),
151 : 0 : *datum_to_tdb(&tdb_key, key),
152 : 0 : *datum_to_tdb(&tdb_data, data),
153 [ # # ]: 0 : overwrite ? TDB_REPLACE : TDB_INSERT) != 0 ? -1 : 0;
154 : : }
155 : :
156 : 0 : int pa_database_unset(pa_database *db, const pa_datum *key) {
157 : : TDB_DATA tdb_key;
158 : :
159 [ # # ]: 0 : pa_assert(db);
160 [ # # ]: 0 : pa_assert(key);
161 : :
162 [ # # ]: 0 : return tdb_delete(MAKE_TDB_CONTEXT(db), *datum_to_tdb(&tdb_key, key)) != 0 ? -1 : 0;
163 : : }
164 : :
165 : 0 : int pa_database_clear(pa_database *db) {
166 [ # # ]: 0 : pa_assert(db);
167 : :
168 [ # # ]: 0 : return tdb_wipe_all(MAKE_TDB_CONTEXT(db)) != 0 ? -1 : 0;
169 : : }
170 : :
171 : 0 : signed pa_database_size(pa_database *db) {
172 : : TDB_DATA tdb_key;
173 : 0 : unsigned n = 0;
174 : :
175 [ # # ]: 0 : pa_assert(db);
176 : :
177 : : /* This sucks */
178 : :
179 : 0 : tdb_key = tdb_firstkey(MAKE_TDB_CONTEXT(db));
180 : :
181 [ # # ]: 0 : while (tdb_key.dptr) {
182 : : TDB_DATA next;
183 : :
184 : 0 : n++;
185 : :
186 : 0 : next = tdb_nextkey(MAKE_TDB_CONTEXT(db), tdb_key);
187 : 0 : free(tdb_key.dptr);
188 : 0 : tdb_key = next;
189 : : }
190 : :
191 : 0 : return (signed) n;
192 : : }
193 : :
194 : 0 : pa_datum* pa_database_first(pa_database *db, pa_datum *key, pa_datum *data) {
195 : : TDB_DATA tdb_key, tdb_data;
196 : :
197 [ # # ]: 0 : pa_assert(db);
198 [ # # ]: 0 : pa_assert(key);
199 : :
200 : 0 : tdb_key = tdb_firstkey(MAKE_TDB_CONTEXT(db));
201 : :
202 [ # # ]: 0 : if (!tdb_key.dptr)
203 : : return NULL;
204 : :
205 [ # # ]: 0 : if (data) {
206 : 0 : tdb_data = tdb_fetch(MAKE_TDB_CONTEXT(db), tdb_key);
207 : :
208 [ # # ]: 0 : if (!tdb_data.dptr) {
209 : 0 : free(tdb_key.dptr);
210 : 0 : return NULL;
211 : : }
212 : :
213 : 0 : datum_from_tdb(data, &tdb_data);
214 : : }
215 : :
216 : 0 : datum_from_tdb(key, &tdb_key);
217 : :
218 : 0 : return key;
219 : : }
220 : :
221 : 0 : pa_datum* pa_database_next(pa_database *db, const pa_datum *key, pa_datum *next, pa_datum *data) {
222 : : TDB_DATA tdb_key, tdb_data;
223 : :
224 [ # # ]: 0 : pa_assert(db);
225 [ # # ]: 0 : pa_assert(key);
226 : :
227 : 0 : tdb_key = tdb_nextkey(MAKE_TDB_CONTEXT(db), *datum_to_tdb(&tdb_key, key));
228 : :
229 [ # # ]: 0 : if (!tdb_key.dptr)
230 : : return NULL;
231 : :
232 [ # # ]: 0 : if (data) {
233 : 0 : tdb_data = tdb_fetch(MAKE_TDB_CONTEXT(db), tdb_key);
234 : :
235 [ # # ]: 0 : if (!tdb_data.dptr) {
236 : 0 : free(tdb_key.dptr);
237 : 0 : return NULL;
238 : : }
239 : :
240 : 0 : datum_from_tdb(data, &tdb_data);
241 : : }
242 : :
243 : 0 : datum_from_tdb(next, &tdb_key);
244 : :
245 : 0 : return next;
246 : : }
247 : :
248 : 0 : int pa_database_sync(pa_database *db) {
249 [ # # ]: 0 : pa_assert(db);
250 : :
251 : 0 : return 0;
252 : : }
|