/src/samba/lib/util/util_tdb.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | |
4 | | tdb utility functions |
5 | | |
6 | | Copyright (C) Andrew Tridgell 1992-2006 |
7 | | Copyright (C) Volker Lendecke 2007-2011 |
8 | | |
9 | | This program is free software; you can redistribute it and/or modify |
10 | | it under the terms of the GNU General Public License as published by |
11 | | the Free Software Foundation; either version 3 of the License, or |
12 | | (at your option) any later version. |
13 | | |
14 | | This program is distributed in the hope that it will be useful, |
15 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | GNU General Public License for more details. |
18 | | |
19 | | You should have received a copy of the GNU General Public License |
20 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | #include "replace.h" |
24 | | #include <talloc.h> |
25 | | #include "libcli/util/ntstatus.h" |
26 | | #include "lib/util/memory.h" |
27 | | #include "lib/util/byteorder.h" |
28 | | #include "system/filesys.h" |
29 | | #include "../lib/tdb/include/tdb.h" |
30 | | #include "../lib/util/util_tdb.h" |
31 | | |
32 | | /* these are little tdb utility functions that are meant to make |
33 | | dealing with a tdb database a little less cumbersome in Samba */ |
34 | | |
35 | | /*************************************************************** |
36 | | Make a TDB_DATA and keep the const warning in one place |
37 | | ****************************************************************/ |
38 | | |
39 | | TDB_DATA make_tdb_data(const uint8_t *dptr, size_t dsize) |
40 | 0 | { |
41 | 0 | TDB_DATA ret; |
42 | 0 | ret.dptr = discard_const_p(uint8_t, dptr); |
43 | 0 | ret.dsize = dsize; |
44 | 0 | return ret; |
45 | 0 | } |
46 | | |
47 | | bool tdb_data_equal(TDB_DATA t1, TDB_DATA t2) |
48 | 0 | { |
49 | 0 | if (t1.dsize != t2.dsize) { |
50 | 0 | return false; |
51 | 0 | } |
52 | 0 | return (memcmp(t1.dptr, t2.dptr, t1.dsize) == 0); |
53 | 0 | } |
54 | | |
55 | | bool tdb_data_is_empty(TDB_DATA d) |
56 | 0 | { |
57 | 0 | return (d.dsize == 0) || (d.dptr == NULL); |
58 | 0 | } |
59 | | |
60 | | TDB_DATA string_tdb_data(const char *string) |
61 | 0 | { |
62 | 0 | return make_tdb_data((const uint8_t *)string, string ? strlen(string) : 0 ); |
63 | 0 | } |
64 | | |
65 | | TDB_DATA string_term_tdb_data(const char *string) |
66 | 0 | { |
67 | 0 | return make_tdb_data((const uint8_t *)string, string ? strlen(string) + 1 : 0); |
68 | 0 | } |
69 | | |
70 | 0 | TDB_DATA tdb_data_talloc_copy(TALLOC_CTX* mem_ctx, TDB_DATA data) { |
71 | 0 | TDB_DATA ret = { |
72 | 0 | .dptr = (uint8_t *)talloc_size(mem_ctx, data.dsize+1), |
73 | 0 | .dsize = data.dsize |
74 | 0 | }; |
75 | 0 | if (ret.dptr == NULL) { |
76 | 0 | ret.dsize = 0; |
77 | 0 | } else { |
78 | 0 | memcpy(ret.dptr, data.dptr, data.dsize); |
79 | 0 | ret.dptr[ret.dsize] = '\0'; |
80 | 0 | } |
81 | 0 | return ret; |
82 | 0 | } |
83 | | |
84 | | |
85 | | /**************************************************************************** |
86 | | Lock a chain by string. Return non-zero if lock failed. |
87 | | ****************************************************************************/ |
88 | | |
89 | | int tdb_lock_bystring(struct tdb_context *tdb, const char *keyval) |
90 | 0 | { |
91 | 0 | TDB_DATA key = string_term_tdb_data(keyval); |
92 | |
|
93 | 0 | return tdb_chainlock(tdb, key); |
94 | 0 | } |
95 | | |
96 | | /**************************************************************************** |
97 | | Unlock a chain by string. |
98 | | ****************************************************************************/ |
99 | | |
100 | | void tdb_unlock_bystring(struct tdb_context *tdb, const char *keyval) |
101 | 0 | { |
102 | 0 | TDB_DATA key = string_term_tdb_data(keyval); |
103 | |
|
104 | 0 | tdb_chainunlock(tdb, key); |
105 | 0 | } |
106 | | |
107 | | /**************************************************************************** |
108 | | Read lock a chain by string. Return non-zero if lock failed. |
109 | | ****************************************************************************/ |
110 | | |
111 | | int tdb_read_lock_bystring(struct tdb_context *tdb, const char *keyval) |
112 | 0 | { |
113 | 0 | TDB_DATA key = string_term_tdb_data(keyval); |
114 | |
|
115 | 0 | return tdb_chainlock_read(tdb, key); |
116 | 0 | } |
117 | | |
118 | | /**************************************************************************** |
119 | | Read unlock a chain by string. |
120 | | ****************************************************************************/ |
121 | | |
122 | | void tdb_read_unlock_bystring(struct tdb_context *tdb, const char *keyval) |
123 | 0 | { |
124 | 0 | TDB_DATA key = string_term_tdb_data(keyval); |
125 | |
|
126 | 0 | tdb_chainunlock_read(tdb, key); |
127 | 0 | } |
128 | | |
129 | | |
130 | | /**************************************************************************** |
131 | | Fetch a int32_t value by a arbitrary blob key, return -1 if not found. |
132 | | Output is int32_t in native byte order. |
133 | | ****************************************************************************/ |
134 | | |
135 | | static int fetch_int32_parser(TDB_DATA key, TDB_DATA data, void *private_data) |
136 | 0 | { |
137 | 0 | if (data.dsize == sizeof(int32_t)) { |
138 | 0 | *((int32_t *)private_data) = PULL_LE_I32(data.dptr, 0); |
139 | 0 | } |
140 | 0 | return 0; |
141 | 0 | } |
142 | | |
143 | | static int32_t tdb_fetch_int32_byblob(struct tdb_context *tdb, TDB_DATA key) |
144 | 0 | { |
145 | 0 | int32_t v = -1; |
146 | 0 | int32_t ret = tdb_parse_record(tdb, key, fetch_int32_parser, &v); |
147 | 0 | if (ret == -1) { |
148 | 0 | return ret; |
149 | 0 | } |
150 | 0 | return v; |
151 | 0 | } |
152 | | |
153 | | /**************************************************************************** |
154 | | Fetch a int32_t value by string key, return -1 if not found. |
155 | | Output is int32_t in native byte order. |
156 | | ****************************************************************************/ |
157 | | |
158 | | int32_t tdb_fetch_int32(struct tdb_context *tdb, const char *keystr) |
159 | 0 | { |
160 | 0 | return tdb_fetch_int32_byblob(tdb, string_term_tdb_data(keystr)); |
161 | 0 | } |
162 | | |
163 | | /**************************************************************************** |
164 | | Store a int32_t value by an arbitrary blob key, return 0 on success, -ve on failure. |
165 | | Input is int32_t in native byte order. Output in tdb is in little-endian. |
166 | | ****************************************************************************/ |
167 | | |
168 | | static int tdb_store_int32_byblob(struct tdb_context *tdb, TDB_DATA key, |
169 | | int32_t v) |
170 | 0 | { |
171 | 0 | TDB_DATA data; |
172 | 0 | int32_t v_store; |
173 | |
|
174 | 0 | SIVAL(&v_store,0,v); |
175 | 0 | data.dptr = (unsigned char *)&v_store; |
176 | 0 | data.dsize = sizeof(int32_t); |
177 | |
|
178 | 0 | return tdb_store(tdb, key, data, TDB_REPLACE); |
179 | 0 | } |
180 | | |
181 | | /**************************************************************************** |
182 | | Store a int32_t value by string key, return 0 on success, -ve on failure. |
183 | | Input is int32_t in native byte order. Output in tdb is in little-endian. |
184 | | ****************************************************************************/ |
185 | | |
186 | | int tdb_store_int32(struct tdb_context *tdb, const char *keystr, int32_t v) |
187 | 0 | { |
188 | 0 | return tdb_store_int32_byblob(tdb, string_term_tdb_data(keystr), v); |
189 | 0 | } |
190 | | |
191 | | /**************************************************************************** |
192 | | Fetch a uint32_t value by a arbitrary blob key, return false if not found. |
193 | | Output is uint32_t in native byte order. |
194 | | ****************************************************************************/ |
195 | | |
196 | | static int fetch_uint32_parser(TDB_DATA key, TDB_DATA data, void *private_data) |
197 | 0 | { |
198 | 0 | if (data.dsize != sizeof(uint32_t)) { |
199 | 0 | return -1; |
200 | 0 | } |
201 | 0 | *((uint32_t *)private_data) = PULL_LE_U32(data.dptr, 0); |
202 | 0 | return 0; |
203 | 0 | } |
204 | | |
205 | | static bool tdb_fetch_uint32_byblob(struct tdb_context *tdb, TDB_DATA key, |
206 | | uint32_t *value) |
207 | 0 | { |
208 | 0 | int ret = tdb_parse_record(tdb, key, fetch_uint32_parser, value); |
209 | |
|
210 | 0 | if (ret == -1) { |
211 | 0 | return false; |
212 | 0 | } |
213 | | |
214 | 0 | return true; |
215 | 0 | } |
216 | | |
217 | | /**************************************************************************** |
218 | | Fetch a uint32_t value by string key, return false if not found. |
219 | | Output is uint32_t in native byte order. |
220 | | ****************************************************************************/ |
221 | | |
222 | | bool tdb_fetch_uint32(struct tdb_context *tdb, const char *keystr, uint32_t *value) |
223 | 0 | { |
224 | 0 | return tdb_fetch_uint32_byblob(tdb, string_term_tdb_data(keystr), value); |
225 | 0 | } |
226 | | |
227 | | /**************************************************************************** |
228 | | Store a uint32_t value by an arbitrary blob key, return true on success, false on failure. |
229 | | Input is uint32_t in native byte order. Output in tdb is in little-endian. |
230 | | ****************************************************************************/ |
231 | | |
232 | | static bool tdb_store_uint32_byblob(struct tdb_context *tdb, TDB_DATA key, |
233 | | uint32_t value) |
234 | 0 | { |
235 | 0 | TDB_DATA data; |
236 | 0 | uint32_t v_store; |
237 | 0 | bool ret = true; |
238 | |
|
239 | 0 | SIVAL(&v_store, 0, value); |
240 | 0 | data.dptr = (unsigned char *)&v_store; |
241 | 0 | data.dsize = sizeof(uint32_t); |
242 | |
|
243 | 0 | if (tdb_store(tdb, key, data, TDB_REPLACE) != 0) |
244 | 0 | ret = false; |
245 | |
|
246 | 0 | return ret; |
247 | 0 | } |
248 | | |
249 | | /**************************************************************************** |
250 | | Store a uint32_t value by string key, return true on success, false on failure. |
251 | | Input is uint32_t in native byte order. Output in tdb is in little-endian. |
252 | | ****************************************************************************/ |
253 | | |
254 | | bool tdb_store_uint32(struct tdb_context *tdb, const char *keystr, uint32_t value) |
255 | 0 | { |
256 | 0 | return tdb_store_uint32_byblob(tdb, string_term_tdb_data(keystr), value); |
257 | 0 | } |
258 | | |
259 | | /**************************************************************************** |
260 | | Fetch a int64_t value by a arbitrary blob key, return -1 if not found. |
261 | | ****************************************************************************/ |
262 | | |
263 | | static int fetch_int64_parser(TDB_DATA key, TDB_DATA data, void *private_data) |
264 | 0 | { |
265 | 0 | if (data.dsize == sizeof(int64_t)) { |
266 | 0 | *((int64_t *)private_data) = PULL_LE_I64(data.dptr, 0); |
267 | 0 | return 0; |
268 | 0 | } |
269 | 0 | return -1; |
270 | 0 | } |
271 | | |
272 | | /**************************************************************************** |
273 | | Fetch a int64_t value by string key, return -1 if not found. |
274 | | ****************************************************************************/ |
275 | | |
276 | | int tdb_fetch_int64(struct tdb_context *tdb, const char *keystr, int64_t *value) |
277 | 0 | { |
278 | 0 | return tdb_parse_record(tdb, string_term_tdb_data(keystr), fetch_int64_parser, value); |
279 | 0 | } |
280 | | |
281 | | /**************************************************************************** |
282 | | Store a int64_t value by an arbitrary blob key, return 0 on success, -ve on failure. |
283 | | Input is int64_t in native byte order. Output in tdb is in little-endian. |
284 | | ****************************************************************************/ |
285 | | |
286 | | static int tdb_store_int64_byblob(struct tdb_context *tdb, TDB_DATA key, |
287 | | int64_t v) |
288 | 0 | { |
289 | 0 | int64_t v_store; |
290 | 0 | TDB_DATA data = { .dptr = (unsigned char *)&v_store, .dsize = sizeof(v_store), }; |
291 | |
|
292 | 0 | PUSH_LE_I64(&v_store, 0, v); |
293 | 0 | return tdb_store(tdb, key, data, TDB_REPLACE); |
294 | 0 | } |
295 | | |
296 | | /**************************************************************************** |
297 | | Store a int64_t value by string key, return 0 on success, -ve on failure. |
298 | | Input is int64_t in native byte order. Output in tdb is in little-endian. |
299 | | ****************************************************************************/ |
300 | | |
301 | | int tdb_store_int64(struct tdb_context *tdb, const char *keystr, int64_t v) |
302 | 0 | { |
303 | 0 | return tdb_store_int64_byblob(tdb, string_term_tdb_data(keystr), v); |
304 | 0 | } |
305 | | |
306 | | /**************************************************************************** |
307 | | Fetch a uint64_t value by a arbitrary blob key, return -1 in case of error. |
308 | | Output is uint64_t in native byte order. |
309 | | ****************************************************************************/ |
310 | | |
311 | | static int fetch_uint64_parser(TDB_DATA key, TDB_DATA data, void *private_data) |
312 | 0 | { |
313 | 0 | if (data.dsize != sizeof(uint64_t)) { |
314 | 0 | return -1; |
315 | 0 | } |
316 | 0 | *((uint64_t *)private_data) = PULL_LE_U64(data.dptr, 0); |
317 | 0 | return 0; |
318 | 0 | } |
319 | | |
320 | | /**************************************************************************** |
321 | | Fetch a uint64_t value by string key, return -1 if not found. |
322 | | Output is uint64_t in native byte order. |
323 | | ****************************************************************************/ |
324 | | |
325 | | int tdb_fetch_uint64(struct tdb_context *tdb, const char *keystr, uint64_t *value) |
326 | 0 | { |
327 | 0 | return tdb_parse_record(tdb, string_term_tdb_data(keystr), fetch_uint64_parser, value); |
328 | 0 | } |
329 | | |
330 | | /**************************************************************************** |
331 | | Store a uint64_t value by an arbitrary blob key, return 0 on success, -1 on failure. |
332 | | Input is uint64_t in native byte order. Output in tdb is in little-endian. |
333 | | ****************************************************************************/ |
334 | | |
335 | | static int tdb_store_uint64_byblob(struct tdb_context *tdb, TDB_DATA key, |
336 | | uint64_t value) |
337 | 0 | { |
338 | 0 | uint64_t v_store; |
339 | 0 | TDB_DATA data = { .dptr = (unsigned char *)&v_store, .dsize = sizeof(v_store), }; |
340 | |
|
341 | 0 | PUSH_LE_U64(&v_store, 0, value); |
342 | 0 | return tdb_store(tdb, key, data, TDB_REPLACE); |
343 | 0 | } |
344 | | |
345 | | /**************************************************************************** |
346 | | Store a uint64_t value by string key, return 0 on success, -1 on failure. |
347 | | Input is uint64_t in native byte order. Output in tdb is in little-endian. |
348 | | ****************************************************************************/ |
349 | | |
350 | | int tdb_store_uint64(struct tdb_context *tdb, const char *keystr, uint64_t value) |
351 | 0 | { |
352 | 0 | return tdb_store_uint64_byblob(tdb, string_term_tdb_data(keystr), value); |
353 | 0 | } |
354 | | |
355 | | /**************************************************************************** |
356 | | Store a buffer by a null terminated string key. Return 0 on success, -ve |
357 | | on failure. |
358 | | ****************************************************************************/ |
359 | | |
360 | | int tdb_store_bystring(struct tdb_context *tdb, const char *keystr, TDB_DATA data, int flags) |
361 | 0 | { |
362 | 0 | TDB_DATA key = string_term_tdb_data(keystr); |
363 | |
|
364 | 0 | return tdb_store(tdb, key, data, flags); |
365 | 0 | } |
366 | | |
367 | | /**************************************************************************** |
368 | | Fetch a buffer using a null terminated string key. Don't forget to call |
369 | | free() on the result dptr. |
370 | | ****************************************************************************/ |
371 | | |
372 | | TDB_DATA tdb_fetch_bystring(struct tdb_context *tdb, const char *keystr) |
373 | 0 | { |
374 | 0 | TDB_DATA key = string_term_tdb_data(keystr); |
375 | |
|
376 | 0 | return tdb_fetch(tdb, key); |
377 | 0 | } |
378 | | |
379 | | /**************************************************************************** |
380 | | Delete an entry using a null terminated string key. |
381 | | ****************************************************************************/ |
382 | | |
383 | | int tdb_delete_bystring(struct tdb_context *tdb, const char *keystr) |
384 | 0 | { |
385 | 0 | TDB_DATA key = string_term_tdb_data(keystr); |
386 | |
|
387 | 0 | return tdb_delete(tdb, key); |
388 | 0 | } |
389 | | |
390 | | /**************************************************************************** |
391 | | Atomic integer change. Returns old value. To create, set initial value in *oldval. |
392 | | ****************************************************************************/ |
393 | | |
394 | | int32_t tdb_change_int32_atomic(struct tdb_context *tdb, const char *keystr, int32_t *oldval, int32_t change_val) |
395 | 0 | { |
396 | 0 | int32_t val; |
397 | 0 | int32_t ret = -1; |
398 | |
|
399 | 0 | if (tdb_lock_bystring(tdb, keystr) != 0) |
400 | 0 | return -1; |
401 | | |
402 | 0 | if ((val = tdb_fetch_int32(tdb, keystr)) == -1) { |
403 | | /* The lookup failed */ |
404 | 0 | if (tdb_error(tdb) != TDB_ERR_NOEXIST) { |
405 | | /* but not because it didn't exist */ |
406 | 0 | goto err_out; |
407 | 0 | } |
408 | | |
409 | | /* Start with 'old' value */ |
410 | 0 | val = *oldval; |
411 | |
|
412 | 0 | } else { |
413 | | /* It worked, set return value (oldval) to tdb data */ |
414 | 0 | *oldval = val; |
415 | 0 | } |
416 | | |
417 | | /* Increment value for storage and return next time */ |
418 | 0 | val += change_val; |
419 | |
|
420 | 0 | if (tdb_store_int32(tdb, keystr, val) != 0) |
421 | 0 | goto err_out; |
422 | | |
423 | 0 | ret = 0; |
424 | |
|
425 | 0 | err_out: |
426 | |
|
427 | 0 | tdb_unlock_bystring(tdb, keystr); |
428 | 0 | return ret; |
429 | 0 | } |
430 | | |
431 | | /**************************************************************************** |
432 | | Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval. |
433 | | ****************************************************************************/ |
434 | | |
435 | | bool tdb_change_uint32_atomic(struct tdb_context *tdb, const char *keystr, uint32_t *oldval, uint32_t change_val) |
436 | 0 | { |
437 | 0 | uint32_t val; |
438 | 0 | bool ret = false; |
439 | |
|
440 | 0 | if (tdb_lock_bystring(tdb, keystr) != 0) |
441 | 0 | return false; |
442 | | |
443 | 0 | if (!tdb_fetch_uint32(tdb, keystr, &val)) { |
444 | | /* It failed */ |
445 | 0 | if (tdb_error(tdb) != TDB_ERR_NOEXIST) { |
446 | | /* and not because it didn't exist */ |
447 | 0 | goto err_out; |
448 | 0 | } |
449 | | |
450 | | /* Start with 'old' value */ |
451 | 0 | val = *oldval; |
452 | |
|
453 | 0 | } else { |
454 | | /* it worked, set return value (oldval) to tdb data */ |
455 | 0 | *oldval = val; |
456 | |
|
457 | 0 | } |
458 | | |
459 | | /* get a new value to store */ |
460 | 0 | val += change_val; |
461 | |
|
462 | 0 | if (!tdb_store_uint32(tdb, keystr, val)) |
463 | 0 | goto err_out; |
464 | | |
465 | 0 | ret = true; |
466 | |
|
467 | 0 | err_out: |
468 | |
|
469 | 0 | tdb_unlock_bystring(tdb, keystr); |
470 | 0 | return ret; |
471 | 0 | } |
472 | | |
473 | | /**************************************************************************** |
474 | | Return an NTSTATUS from a TDB_ERROR |
475 | | ****************************************************************************/ |
476 | | |
477 | | NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err) |
478 | 0 | { |
479 | 0 | NTSTATUS result; |
480 | |
|
481 | 0 | switch (err) { |
482 | 0 | case TDB_SUCCESS: |
483 | 0 | result = NT_STATUS_OK; |
484 | 0 | break; |
485 | 0 | case TDB_ERR_CORRUPT: |
486 | 0 | result = NT_STATUS_INTERNAL_DB_CORRUPTION; |
487 | 0 | break; |
488 | 0 | case TDB_ERR_IO: |
489 | 0 | result = NT_STATUS_UNEXPECTED_IO_ERROR; |
490 | 0 | break; |
491 | 0 | case TDB_ERR_OOM: |
492 | 0 | result = NT_STATUS_NO_MEMORY; |
493 | 0 | break; |
494 | 0 | case TDB_ERR_EXISTS: |
495 | 0 | result = NT_STATUS_OBJECT_NAME_COLLISION; |
496 | 0 | break; |
497 | | |
498 | 0 | case TDB_ERR_LOCK: |
499 | | /* |
500 | | * TDB_ERR_LOCK is very broad, we could for example |
501 | | * distinguish between fcntl locks and invalid lock |
502 | | * sequences. So NT_STATUS_FILE_LOCK_CONFLICT is a |
503 | | * compromise. |
504 | | */ |
505 | 0 | result = NT_STATUS_FILE_LOCK_CONFLICT; |
506 | 0 | break; |
507 | | |
508 | 0 | case TDB_ERR_NOLOCK: |
509 | 0 | case TDB_ERR_LOCK_TIMEOUT: |
510 | | /* |
511 | | * These two ones in the enum are not actually used |
512 | | */ |
513 | 0 | result = NT_STATUS_FILE_LOCK_CONFLICT; |
514 | 0 | break; |
515 | 0 | case TDB_ERR_NOEXIST: |
516 | 0 | result = NT_STATUS_NOT_FOUND; |
517 | 0 | break; |
518 | 0 | case TDB_ERR_EINVAL: |
519 | 0 | result = NT_STATUS_INVALID_PARAMETER; |
520 | 0 | break; |
521 | 0 | case TDB_ERR_RDONLY: |
522 | 0 | result = NT_STATUS_ACCESS_DENIED; |
523 | 0 | break; |
524 | 0 | case TDB_ERR_NESTING: |
525 | 0 | result = NT_STATUS_INTERNAL_ERROR; |
526 | 0 | break; |
527 | 0 | default: |
528 | 0 | result = NT_STATUS_INTERNAL_ERROR; |
529 | 0 | break; |
530 | 0 | }; |
531 | 0 | return result; |
532 | 0 | } |
533 | | |
534 | | int map_unix_error_from_tdb(enum TDB_ERROR err) |
535 | 0 | { |
536 | 0 | int result = EINVAL; |
537 | |
|
538 | 0 | switch (err) { |
539 | 0 | case TDB_SUCCESS: |
540 | 0 | result = 0; |
541 | 0 | break; |
542 | 0 | case TDB_ERR_CORRUPT: |
543 | 0 | result = EILSEQ; |
544 | 0 | break; |
545 | 0 | case TDB_ERR_IO: |
546 | 0 | result = EIO; |
547 | 0 | break; |
548 | 0 | case TDB_ERR_OOM: |
549 | 0 | result = ENOMEM; |
550 | 0 | break; |
551 | 0 | case TDB_ERR_EXISTS: |
552 | 0 | result = EEXIST; |
553 | 0 | break; |
554 | | |
555 | 0 | case TDB_ERR_LOCK: |
556 | | /* |
557 | | * TDB_ERR_LOCK is very broad, we could for example |
558 | | * distinguish between fcntl locks and invalid lock |
559 | | * sequences. EWOULDBLOCK is wrong, but there is no real |
560 | | * generic lock error code in errno.h |
561 | | */ |
562 | 0 | result = EWOULDBLOCK; |
563 | 0 | break; |
564 | | |
565 | 0 | case TDB_ERR_NOLOCK: |
566 | 0 | case TDB_ERR_LOCK_TIMEOUT: |
567 | | /* |
568 | | * These two ones in the enum are not actually used |
569 | | */ |
570 | 0 | result = ENOLCK; |
571 | 0 | break; |
572 | 0 | case TDB_ERR_NOEXIST: |
573 | 0 | result = ENOENT; |
574 | 0 | break; |
575 | 0 | case TDB_ERR_EINVAL: |
576 | 0 | result = EINVAL; |
577 | 0 | break; |
578 | 0 | case TDB_ERR_RDONLY: |
579 | 0 | result = EROFS; |
580 | 0 | break; |
581 | 0 | case TDB_ERR_NESTING: |
582 | | /* |
583 | | * Well, this db is already busy... |
584 | | */ |
585 | 0 | result = EBUSY; |
586 | 0 | break; |
587 | 0 | }; |
588 | 0 | return result; |
589 | 0 | } |
590 | | |
591 | | struct tdb_fetch_talloc_state { |
592 | | TALLOC_CTX *mem_ctx; |
593 | | uint8_t *buf; |
594 | | }; |
595 | | |
596 | | static int tdb_fetch_talloc_parser(TDB_DATA key, TDB_DATA data, |
597 | | void *private_data) |
598 | 0 | { |
599 | 0 | struct tdb_fetch_talloc_state *state = private_data; |
600 | 0 | state->buf = talloc_memdup(state->mem_ctx, data.dptr, data.dsize); |
601 | 0 | return 0; |
602 | 0 | } |
603 | | |
604 | | int tdb_fetch_talloc(struct tdb_context *tdb, TDB_DATA key, |
605 | | TALLOC_CTX *mem_ctx, uint8_t **buf) |
606 | 0 | { |
607 | 0 | struct tdb_fetch_talloc_state state = { .mem_ctx = mem_ctx }; |
608 | 0 | int ret; |
609 | |
|
610 | 0 | ret = tdb_parse_record(tdb, key, tdb_fetch_talloc_parser, &state); |
611 | 0 | if (ret == -1) { |
612 | 0 | enum TDB_ERROR err = tdb_error(tdb); |
613 | 0 | return map_unix_error_from_tdb(err); |
614 | 0 | } |
615 | | |
616 | 0 | if (state.buf == NULL) { |
617 | 0 | return ENOMEM; |
618 | 0 | } |
619 | | |
620 | 0 | *buf = state.buf; |
621 | 0 | return 0; |
622 | 0 | } |