1 /*
2 Unix SMB/CIFS implementation.
3
4 trivial database library
5
6 Copyright (C) Andrew Tridgell 1999-2005
7 Copyright (C) Paul `Rusty' Russell 2000
8 Copyright (C) Jeremy Allison 2000-2003
9
10 ** NOTE! The following LGPL license applies to the tdb
11 ** library. This does NOT imply that all of Samba is released
12 ** under the LGPL
13
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of the GNU Lesser General Public
16 License as published by the Free Software Foundation; either
17 version 3 of the License, or (at your option) any later version.
18
19 This library is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 Lesser General Public License for more details.
23
24 You should have received a copy of the GNU Lesser General Public
25 License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 */
27
28
29 #include "tdb_private.h"
30
31 /*
32 * We prepend the mutex area, so fixup offsets. See mutex.c for details.
33 * tdb->hdr_ofs is 0 or header.mutex_size.
34 *
35 * Note: that we only have the 4GB limit of tdb_off_t for
36 * tdb->map_size. The file size on disk can be 4GB + tdb->hdr_ofs!
37 */
38
tdb_adjust_offset(struct tdb_context * tdb,off_t * off)39 static bool tdb_adjust_offset(struct tdb_context *tdb, off_t *off)
40 {
41 off_t tmp = tdb->hdr_ofs + *off;
42
43 if ((tmp < tdb->hdr_ofs) || (tmp < *off)) {
44 errno = EIO;
45 return false;
46 }
47
48 *off = tmp;
49 return true;
50 }
51
tdb_pwrite(struct tdb_context * tdb,const void * buf,size_t count,off_t offset)52 static ssize_t tdb_pwrite(struct tdb_context *tdb, const void *buf,
53 size_t count, off_t offset)
54 {
55 ssize_t ret;
56
57 if (!tdb_adjust_offset(tdb, &offset)) {
58 return -1;
59 }
60
61 do {
62 ret = pwrite(tdb->fd, buf, count, offset);
63 } while ((ret == -1) && (errno == EINTR));
64
65 return ret;
66 }
67
tdb_pread(struct tdb_context * tdb,void * buf,size_t count,off_t offset)68 static ssize_t tdb_pread(struct tdb_context *tdb, void *buf,
69 size_t count, off_t offset)
70 {
71 ssize_t ret;
72
73 if (!tdb_adjust_offset(tdb, &offset)) {
74 return -1;
75 }
76
77 do {
78 ret = pread(tdb->fd, buf, count, offset);
79 } while ((ret == -1) && (errno == EINTR));
80
81 return ret;
82 }
83
tdb_ftruncate(struct tdb_context * tdb,off_t length)84 static int tdb_ftruncate(struct tdb_context *tdb, off_t length)
85 {
86 ssize_t ret;
87
88 if (!tdb_adjust_offset(tdb, &length)) {
89 return -1;
90 }
91
92 do {
93 ret = ftruncate(tdb->fd, length);
94 } while ((ret == -1) && (errno == EINTR));
95
96 return ret;
97 }
98
99 #ifdef HAVE_POSIX_FALLOCATE
tdb_posix_fallocate(struct tdb_context * tdb,off_t offset,off_t len)100 static int tdb_posix_fallocate(struct tdb_context *tdb, off_t offset,
101 off_t len)
102 {
103 ssize_t ret;
104
105 if (!tdb_adjust_offset(tdb, &offset)) {
106 return -1;
107 }
108
109 do {
110 ret = posix_fallocate(tdb->fd, offset, len);
111 } while ((ret == -1) && (errno == EINTR));
112
113 return ret;
114 }
115 #endif
116
tdb_fstat(struct tdb_context * tdb,struct stat * buf)117 static int tdb_fstat(struct tdb_context *tdb, struct stat *buf)
118 {
119 int ret;
120
121 ret = fstat(tdb->fd, buf);
122 if (ret == -1) {
123 return -1;
124 }
125
126 if (buf->st_size < tdb->hdr_ofs) {
127 errno = EIO;
128 return -1;
129 }
130 buf->st_size -= tdb->hdr_ofs;
131
132 return ret;
133 }
134
135 /* check for an out of bounds access - if it is out of bounds then
136 see if the database has been expanded by someone else and expand
137 if necessary
138 */
tdb_oob(struct tdb_context * tdb,tdb_off_t off,tdb_len_t len,int probe)139 static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len,
140 int probe)
141 {
142 struct stat st;
143 if (len + off < len) {
144 if (!probe) {
145 /* Ensure ecode is set for log fn. */
146 tdb->ecode = TDB_ERR_IO;
147 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob off %u len %u wrap\n",
148 off, len));
149 }
150 return -1;
151 }
152
153 if (off + len <= tdb->map_size)
154 return 0;
155 if (tdb->flags & TDB_INTERNAL) {
156 if (!probe) {
157 /* Ensure ecode is set for log fn. */
158 tdb->ecode = TDB_ERR_IO;
159 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond internal malloc size %u\n",
160 (int)(off + len), (int)tdb->map_size));
161 }
162 return -1;
163 }
164
165 if (tdb_fstat(tdb, &st) == -1) {
166 tdb->ecode = TDB_ERR_IO;
167 return -1;
168 }
169
170 /* Beware >4G files! */
171 if ((tdb_off_t)st.st_size != st.st_size) {
172 /* Ensure ecode is set for log fn. */
173 tdb->ecode = TDB_ERR_IO;
174 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_oob len %llu too large!\n",
175 (long long)st.st_size));
176 return -1;
177 }
178
179 /* Unmap, update size, remap. We do this unconditionally, to handle
180 * the unusual case where the db is truncated.
181 *
182 * This can happen to a child using tdb_reopen_all(true) on a
183 * TDB_CLEAR_IF_FIRST tdb whose parent crashes: the next
184 * opener will truncate the database. */
185 if (tdb_munmap(tdb) == -1) {
186 tdb->ecode = TDB_ERR_IO;
187 return -1;
188 }
189 tdb->map_size = st.st_size;
190 if (tdb_mmap(tdb) != 0) {
191 return -1;
192 }
193
194 if (st.st_size < (size_t)off + len) {
195 if (!probe) {
196 /* Ensure ecode is set for log fn. */
197 tdb->ecode = TDB_ERR_IO;
198 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond eof at %u\n",
199 (int)(off + len), (int)st.st_size));
200 }
201 return -1;
202 }
203 return 0;
204 }
205
206 /* write a lump of data at a specified offset */
tdb_write(struct tdb_context * tdb,tdb_off_t off,const void * buf,tdb_len_t len)207 static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
208 const void *buf, tdb_len_t len)
209 {
210 if (len == 0) {
211 return 0;
212 }
213
214 if (tdb->read_only || tdb->traverse_read) {
215 tdb->ecode = TDB_ERR_RDONLY;
216 return -1;
217 }
218
219 if (tdb->methods->tdb_oob(tdb, off, len, 0) != 0)
220 return -1;
221
222 if (tdb->map_ptr) {
223 memcpy(off + (char *)tdb->map_ptr, buf, len);
224 } else {
225 #ifdef HAVE_INCOHERENT_MMAP
226 tdb->ecode = TDB_ERR_IO;
227 return -1;
228 #else
229 ssize_t written;
230
231 written = tdb_pwrite(tdb, buf, len, off);
232
233 if ((written != (ssize_t)len) && (written != -1)) {
234 /* try once more */
235 tdb->ecode = TDB_ERR_IO;
236 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: wrote only "
237 "%zi of %u bytes at %u, trying once more\n",
238 written, len, off));
239 written = tdb_pwrite(tdb, (const char *)buf+written,
240 len-written, off+written);
241 }
242 if (written == -1) {
243 /* Ensure ecode is set for log fn. */
244 tdb->ecode = TDB_ERR_IO;
245 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %u "
246 "len=%u (%s)\n", off, len, strerror(errno)));
247 return -1;
248 } else if (written != (ssize_t)len) {
249 tdb->ecode = TDB_ERR_IO;
250 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: failed to "
251 "write %u bytes at %u in two attempts\n",
252 len, off));
253 return -1;
254 }
255 #endif
256 }
257 return 0;
258 }
259
260 /* Endian conversion: we only ever deal with 4 byte quantities */
tdb_convert(void * buf,uint32_t size)261 void *tdb_convert(void *buf, uint32_t size)
262 {
263 uint32_t i, *p = (uint32_t *)buf;
264 for (i = 0; i < size / 4; i++)
265 p[i] = TDB_BYTEREV(p[i]);
266 return buf;
267 }
268
269
270 /* read a lump of data at a specified offset, maybe convert */
tdb_read(struct tdb_context * tdb,tdb_off_t off,void * buf,tdb_len_t len,int cv)271 static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
272 tdb_len_t len, int cv)
273 {
274 if (tdb->methods->tdb_oob(tdb, off, len, 0) != 0) {
275 return -1;
276 }
277
278 if (tdb->map_ptr) {
279 memcpy(buf, off + (char *)tdb->map_ptr, len);
280 } else {
281 #ifdef HAVE_INCOHERENT_MMAP
282 tdb->ecode = TDB_ERR_IO;
283 return -1;
284 #else
285 ssize_t ret;
286
287 ret = tdb_pread(tdb, buf, len, off);
288 if (ret != (ssize_t)len) {
289 /* Ensure ecode is set for log fn. */
290 tdb->ecode = TDB_ERR_IO;
291 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %u "
292 "len=%u ret=%zi (%s) map_size=%u\n",
293 off, len, ret, strerror(errno),
294 tdb->map_size));
295 return -1;
296 }
297 #endif
298 }
299 if (cv) {
300 tdb_convert(buf, len);
301 }
302 return 0;
303 }
304
305
306
307 /*
308 do an unlocked scan of the hash table heads to find the next non-zero head. The value
309 will then be confirmed with the lock held
310 */
tdb_next_hash_chain(struct tdb_context * tdb,uint32_t * chain)311 static void tdb_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
312 {
313 uint32_t h = *chain;
314 if (tdb->map_ptr) {
315 for (;h < tdb->hash_size;h++) {
316 if (0 != *(uint32_t *)(TDB_HASH_TOP(h) + (unsigned char *)tdb->map_ptr)) {
317 break;
318 }
319 }
320 } else {
321 uint32_t off=0;
322 for (;h < tdb->hash_size;h++) {
323 if (tdb_ofs_read(tdb, TDB_HASH_TOP(h), &off) != 0 || off != 0) {
324 break;
325 }
326 }
327 }
328 (*chain) = h;
329 }
330
331
tdb_munmap(struct tdb_context * tdb)332 int tdb_munmap(struct tdb_context *tdb)
333 {
334 if (tdb->flags & TDB_INTERNAL)
335 return 0;
336
337 #ifdef HAVE_MMAP
338 if (tdb->map_ptr) {
339 int ret;
340
341 ret = munmap(tdb->map_ptr, tdb->map_size);
342 if (ret != 0)
343 return ret;
344 }
345 #endif
346 tdb->map_ptr = NULL;
347 return 0;
348 }
349
350 /* If mmap isn't coherent, *everyone* must always mmap. */
should_mmap(const struct tdb_context * tdb)351 static bool should_mmap(const struct tdb_context *tdb)
352 {
353 #ifdef HAVE_INCOHERENT_MMAP
354 return true;
355 #else
356 return !(tdb->flags & TDB_NOMMAP);
357 #endif
358 }
359
tdb_mmap(struct tdb_context * tdb)360 int tdb_mmap(struct tdb_context *tdb)
361 {
362 if (tdb->flags & TDB_INTERNAL)
363 return 0;
364
365 #ifdef HAVE_MMAP
366 if (should_mmap(tdb)) {
367 tdb->map_ptr = mmap(NULL, tdb->map_size,
368 PROT_READ|(tdb->read_only? 0:PROT_WRITE),
369 MAP_SHARED|MAP_FILE, tdb->fd,
370 tdb->hdr_ofs);
371
372 /*
373 * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
374 */
375
376 if (tdb->map_ptr == MAP_FAILED) {
377 tdb->map_ptr = NULL;
378 TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %u (%s)\n",
379 tdb->map_size, strerror(errno)));
380 #ifdef HAVE_INCOHERENT_MMAP
381 tdb->ecode = TDB_ERR_IO;
382 return -1;
383 #endif
384 }
385 } else {
386 tdb->map_ptr = NULL;
387 }
388 #else
389 tdb->map_ptr = NULL;
390 #endif
391 return 0;
392 }
393
394 /* expand a file. we prefer to use ftruncate, as that is what posix
395 says to use for mmap expansion */
tdb_expand_file(struct tdb_context * tdb,tdb_off_t size,tdb_off_t addition)396 static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t addition)
397 {
398 char buf[8192];
399 tdb_off_t new_size;
400 int ret;
401
402 if (tdb->read_only || tdb->traverse_read) {
403 tdb->ecode = TDB_ERR_RDONLY;
404 return -1;
405 }
406
407 if (!tdb_add_off_t(size, addition, &new_size)) {
408 tdb->ecode = TDB_ERR_OOM;
409 TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
410 "overflow detected current size[%u] addition[%u]!\n",
411 (unsigned)size, (unsigned)addition));
412 errno = ENOSPC;
413 return -1;
414 }
415
416 #ifdef HAVE_POSIX_FALLOCATE
417 ret = tdb_posix_fallocate(tdb, size, addition);
418 if (ret == 0) {
419 return 0;
420 }
421 if (ret == ENOSPC) {
422 /*
423 * The Linux glibc (at least as of 2.24) fallback if
424 * the file system does not support fallocate does not
425 * reset the file size back to where it was. Also, to
426 * me it is unclear from the posix spec of
427 * posix_fallocate whether this is allowed or
428 * not. Better be safe than sorry and "goto fail" but
429 * "return -1" here, leaving the EOF pointer too
430 * large.
431 */
432 goto fail;
433 }
434
435 /*
436 * Retry the "old" way. Possibly unnecessary, but looking at
437 * our configure script there seem to be weird failure modes
438 * for posix_fallocate. See commit 3264a98ff16de, which
439 * probably refers to
440 * https://sourceware.org/bugzilla/show_bug.cgi?id=1083.
441 */
442 #endif
443
444 ret = tdb_ftruncate(tdb, new_size);
445 if (ret == -1) {
446 char b = 0;
447 ssize_t written = tdb_pwrite(tdb, &b, 1, new_size - 1);
448 if (written == 0) {
449 /* try once more, potentially revealing errno */
450 written = tdb_pwrite(tdb, &b, 1, new_size - 1);
451 }
452 if (written == 0) {
453 /* again - give up, guessing errno */
454 errno = ENOSPC;
455 }
456 if (written != 1) {
457 tdb->ecode = TDB_ERR_OOM;
458 TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %u failed (%s)\n",
459 (unsigned)new_size, strerror(errno)));
460 return -1;
461 }
462 }
463
464 /* now fill the file with something. This ensures that the
465 file isn't sparse, which would be very bad if we ran out of
466 disk. This must be done with write, not via mmap */
467 memset(buf, TDB_PAD_BYTE, sizeof(buf));
468 while (addition) {
469 size_t n = addition>sizeof(buf)?sizeof(buf):addition;
470 ssize_t written = tdb_pwrite(tdb, buf, n, size);
471 if (written == 0) {
472 /* prevent infinite loops: try _once_ more */
473 written = tdb_pwrite(tdb, buf, n, size);
474 }
475 if (written == 0) {
476 /* give up, trying to provide a useful errno */
477 tdb->ecode = TDB_ERR_OOM;
478 TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
479 "returned 0 twice: giving up!\n"));
480 errno = ENOSPC;
481 goto fail;
482 }
483 if (written == -1) {
484 tdb->ecode = TDB_ERR_OOM;
485 TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
486 "%u bytes failed (%s)\n", (int)n,
487 strerror(errno)));
488 goto fail;
489 }
490 if (written != n) {
491 TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
492 "only %zu of %zi bytes - retrying\n", written,
493 n));
494 }
495 addition -= written;
496 size += written;
497 }
498 return 0;
499
500 fail:
501 {
502 int err = errno;
503
504 /*
505 * We're holding the freelist lock or are inside a
506 * transaction. Cutting the file is safe, the space we
507 * tried to allocate can't have been used anywhere in
508 * the meantime.
509 */
510
511 ret = tdb_ftruncate(tdb, size);
512 if (ret == -1) {
513 TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: "
514 "retruncate to %ju failed\n",
515 (uintmax_t)size));
516 }
517 errno = err;
518 }
519
520 return -1;
521 }
522
523
524 /* You need 'size', this tells you how much you should expand by. */
tdb_expand_adjust(tdb_off_t map_size,tdb_off_t size,int page_size)525 tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size)
526 {
527 tdb_off_t new_size, top_size, increment;
528 tdb_off_t max_size = UINT32_MAX - map_size;
529
530 if (size > max_size) {
531 /*
532 * We can't round up anymore, just give back
533 * what we're asked for.
534 *
535 * The caller has to take care of the ENOSPC handling.
536 */
537 return size;
538 }
539
540 /* limit size in order to avoid using up huge amounts of memory for
541 * in memory tdbs if an oddball huge record creeps in */
542 if (size > 100 * 1024) {
543 increment = size * 2;
544 } else {
545 increment = size * 100;
546 }
547 if (increment < size) {
548 goto overflow;
549 }
550
551 if (!tdb_add_off_t(map_size, increment, &top_size)) {
552 goto overflow;
553 }
554
555 /* always make room for at least top_size more records, and at
556 least 25% more space. if the DB is smaller than 100MiB,
557 otherwise grow it by 10% only. */
558 if (map_size > 100 * 1024 * 1024) {
559 new_size = map_size * 1.10;
560 } else {
561 new_size = map_size * 1.25;
562 }
563 if (new_size < map_size) {
564 goto overflow;
565 }
566
567 /* Round the database up to a multiple of the page size */
568 new_size = MAX(top_size, new_size);
569
570 if (new_size + page_size < new_size) {
571 /* There's a "+" in TDB_ALIGN that might overflow... */
572 goto overflow;
573 }
574
575 return TDB_ALIGN(new_size, page_size) - map_size;
576
577 overflow:
578 /*
579 * Somewhere in between we went over 4GB. Make one big jump to
580 * exactly 4GB database size.
581 */
582 return max_size;
583 }
584
585 /* expand the database at least size bytes by expanding the underlying
586 file and doing the mmap again if necessary */
tdb_expand(struct tdb_context * tdb,tdb_off_t size)587 int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
588 {
589 struct tdb_record rec;
590 tdb_off_t offset;
591 tdb_off_t new_size;
592
593 if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
594 TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n"));
595 return -1;
596 }
597
598 /* must know about any previous expansions by another process */
599 tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1);
600
601 /*
602 * Note: that we don't care about tdb->hdr_ofs != 0 here
603 *
604 * The 4GB limitation is just related to tdb->map_size
605 * and the offset calculation in the records.
606 *
607 * The file on disk can be up to 4GB + tdb->hdr_ofs
608 */
609 size = tdb_expand_adjust(tdb->map_size, size, tdb->page_size);
610
611 if (!tdb_add_off_t(tdb->map_size, size, &new_size)) {
612 tdb->ecode = TDB_ERR_OOM;
613 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_expand "
614 "overflow detected current map_size[%u] size[%u]!\n",
615 (unsigned)tdb->map_size, (unsigned)size));
616 goto fail;
617 }
618
619 /* form a new freelist record */
620 offset = tdb->map_size;
621 memset(&rec,'\0',sizeof(rec));
622 rec.rec_len = size - sizeof(rec);
623
624 if (tdb->flags & TDB_INTERNAL) {
625 char *new_map_ptr;
626
627 new_map_ptr = (char *)realloc(tdb->map_ptr, new_size);
628 if (!new_map_ptr) {
629 tdb->ecode = TDB_ERR_OOM;
630 goto fail;
631 }
632 tdb->map_ptr = new_map_ptr;
633 tdb->map_size = new_size;
634 } else {
635 int ret;
636
637 /*
638 * expand the file itself
639 */
640 ret = tdb->methods->tdb_expand_file(tdb, tdb->map_size, size);
641 if (ret != 0) {
642 goto fail;
643 }
644
645 /* Explicitly remap: if we're in a transaction, this won't
646 * happen automatically! */
647 tdb_munmap(tdb);
648 tdb->map_size = new_size;
649 if (tdb_mmap(tdb) != 0) {
650 goto fail;
651 }
652 }
653
654 /* link it into the free list */
655 if (tdb_free(tdb, offset, &rec) == -1)
656 goto fail;
657
658 tdb_unlock(tdb, -1, F_WRLCK);
659 return 0;
660 fail:
661 tdb_unlock(tdb, -1, F_WRLCK);
662 return -1;
663 }
664
665 /* read/write a tdb_off_t */
tdb_ofs_read(struct tdb_context * tdb,tdb_off_t offset,tdb_off_t * d)666 int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
667 {
668 return tdb->methods->tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV());
669 }
670
tdb_ofs_write(struct tdb_context * tdb,tdb_off_t offset,tdb_off_t * d)671 int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
672 {
673 tdb_off_t off = *d;
674 return tdb->methods->tdb_write(tdb, offset, CONVERT(off), sizeof(*d));
675 }
676
677
678 /* read a lump of data, allocating the space for it */
tdb_alloc_read(struct tdb_context * tdb,tdb_off_t offset,tdb_len_t len)679 unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len)
680 {
681 unsigned char *buf;
682
683 /* some systems don't like zero length malloc */
684
685 if (!(buf = (unsigned char *)malloc(len ? len : 1))) {
686 /* Ensure ecode is set for log fn. */
687 tdb->ecode = TDB_ERR_OOM;
688 TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%u (%s)\n",
689 len, strerror(errno)));
690 return NULL;
691 }
692 if (tdb->methods->tdb_read(tdb, offset, buf, len, 0) == -1) {
693 SAFE_FREE(buf);
694 return NULL;
695 }
696 return buf;
697 }
698
699 /* Give a piece of tdb data to a parser */
700
tdb_parse_data(struct tdb_context * tdb,TDB_DATA key,tdb_off_t offset,tdb_len_t len,int (* parser)(TDB_DATA key,TDB_DATA data,void * private_data),void * private_data)701 int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
702 tdb_off_t offset, tdb_len_t len,
703 int (*parser)(TDB_DATA key, TDB_DATA data,
704 void *private_data),
705 void *private_data)
706 {
707 TDB_DATA data;
708 int result;
709
710 data.dsize = len;
711
712 if ((tdb->transaction == NULL) && (tdb->map_ptr != NULL)) {
713 /*
714 * Optimize by avoiding the malloc/memcpy/free, point the
715 * parser directly at the mmap area.
716 */
717 if (tdb->methods->tdb_oob(tdb, offset, len, 0) != 0) {
718 return -1;
719 }
720 data.dptr = offset + (unsigned char *)tdb->map_ptr;
721 return parser(key, data, private_data);
722 }
723
724 if (!(data.dptr = tdb_alloc_read(tdb, offset, len))) {
725 return -1;
726 }
727
728 result = parser(key, data, private_data);
729 free(data.dptr);
730 return result;
731 }
732
733 /* read/write a record */
tdb_rec_read(struct tdb_context * tdb,tdb_off_t offset,struct tdb_record * rec)734 int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
735 {
736 int ret;
737 tdb_len_t overall_len;
738
739 if (tdb->methods->tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1)
740 return -1;
741 if (TDB_BAD_MAGIC(rec)) {
742 /* Ensure ecode is set for log fn. */
743 tdb->ecode = TDB_ERR_CORRUPT;
744 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%u\n", rec->magic, offset));
745 return -1;
746 }
747
748 overall_len = rec->key_len + rec->data_len;
749 if (overall_len < rec->data_len) {
750 /* overflow */
751 return -1;
752 }
753
754 if (overall_len > rec->rec_len) {
755 /* invalid record */
756 return -1;
757 }
758
759 ret = tdb->methods->tdb_oob(tdb, offset, rec->key_len, 1);
760 if (ret == -1) {
761 return -1;
762 }
763 ret = tdb->methods->tdb_oob(tdb, offset, rec->data_len, 1);
764 if (ret == -1) {
765 return -1;
766 }
767 ret = tdb->methods->tdb_oob(tdb, offset, rec->rec_len, 1);
768 if (ret == -1) {
769 return -1;
770 }
771
772 return tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 0);
773 }
774
tdb_rec_write(struct tdb_context * tdb,tdb_off_t offset,struct tdb_record * rec)775 int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
776 {
777 struct tdb_record r = *rec;
778 return tdb->methods->tdb_write(tdb, offset, CONVERT(r), sizeof(r));
779 }
780
781 static const struct tdb_methods io_methods = {
782 tdb_read,
783 tdb_write,
784 tdb_next_hash_chain,
785 tdb_oob,
786 tdb_expand_file,
787 };
788
789 /*
790 initialise the default methods table
791 */
tdb_io_init(struct tdb_context * tdb)792 void tdb_io_init(struct tdb_context *tdb)
793 {
794 tdb->methods = &io_methods;
795 }
796