2 Unix SMB/CIFS implementation.
4 trivial database library
6 Copyright (C) Andrew Tridgell 1999-2005
7 Copyright (C) Paul `Rusty' Russell 2000
8 Copyright (C) Jeremy Allison 2000-2003
9 Copyright (C) Rusty Russell 2010
11 ** NOTE! The following LGPL license applies to the tdb
12 ** library. This does NOT imply that all of Samba is released
15 This library is free software; you can redistribute it and/or
16 modify it under the terms of the GNU Lesser General Public
17 License as published by the Free Software Foundation; either
18 version 3 of the License, or (at your option) any later version.
20 This library is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 Lesser General Public License for more details.
25 You should have received a copy of the GNU Lesser General Public
26 License along with this library; if not, see <http://www.gnu.org/licenses/>.
30 #include <ccan/likely/likely.h>
32 void tdb_munmap(struct tdb_context *tdb)
34 if (tdb->flags & TDB_INTERNAL)
38 munmap(tdb->map_ptr, tdb->map_size);
43 void tdb_mmap(struct tdb_context *tdb)
45 if (tdb->flags & TDB_INTERNAL)
48 if (tdb->flags & TDB_NOMMAP)
51 tdb->map_ptr = mmap(NULL, tdb->map_size, tdb->mmap_flags,
52 MAP_SHARED, tdb->fd, 0);
55 * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
57 if (tdb->map_ptr == MAP_FAILED) {
59 tdb_logerr(tdb, TDB_SUCCESS, TDB_DEBUG_WARNING,
60 "tdb_mmap failed for size %lld (%s)",
61 (long long)tdb->map_size, strerror(errno));
65 /* check for an out of bounds access - if it is out of bounds then
66 see if the database has been expanded by someone else and expand
68 note that "len" is the minimum length needed for the db
70 static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, bool probe)
74 /* We can't hold pointers during this: we could unmap! */
75 assert(!tdb->direct_access
76 || (tdb->flags & TDB_NOLOCK)
77 || tdb_has_expansion_lock(tdb));
79 if (len <= tdb->map_size)
81 if (tdb->flags & TDB_INTERNAL) {
83 tdb_logerr(tdb, TDB_ERR_IO, TDB_DEBUG_FATAL,
84 "tdb_oob len %lld beyond internal"
87 (long long)tdb->map_size);
92 if (tdb_lock_expand(tdb, F_RDLCK) != 0)
95 if (fstat(tdb->fd, &st) != 0) {
96 tdb_logerr(tdb, TDB_ERR_IO, TDB_DEBUG_FATAL,
97 "Failed to fstat file: %s", strerror(errno));
98 tdb_unlock_expand(tdb, F_RDLCK);
102 tdb_unlock_expand(tdb, F_RDLCK);
104 if (st.st_size < (size_t)len) {
106 tdb_logerr(tdb, TDB_ERR_IO, TDB_DEBUG_FATAL,
107 "tdb_oob len %zu beyond eof at %zu",
108 (size_t)len, st.st_size);
113 /* Unmap, update size, remap */
116 tdb->map_size = st.st_size;
121 /* Endian conversion: we only ever deal with 8 byte quantities */
122 void *tdb_convert(const struct tdb_context *tdb, void *buf, tdb_len_t size)
124 if (unlikely((tdb->flags & TDB_CONVERT)) && buf) {
125 uint64_t i, *p = (uint64_t *)buf;
126 for (i = 0; i < size / 8; i++)
127 p[i] = bswap_64(p[i]);
132 /* FIXME: Return the off? */
133 uint64_t tdb_find_nonzero_off(struct tdb_context *tdb,
134 tdb_off_t base, uint64_t start, uint64_t end)
139 /* Zero vs non-zero is the same unconverted: minor optimization. */
140 val = tdb_access_read(tdb, base + start * sizeof(tdb_off_t),
141 (end - start) * sizeof(tdb_off_t), false);
145 for (i = 0; i < (end - start); i++) {
149 tdb_access_release(tdb, val);
153 /* Return first zero offset in num offset array, or num. */
154 uint64_t tdb_find_zero_off(struct tdb_context *tdb, tdb_off_t off,
160 /* Zero vs non-zero is the same unconverted: minor optimization. */
161 val = tdb_access_read(tdb, off, num * sizeof(tdb_off_t), false);
165 for (i = 0; i < num; i++) {
169 tdb_access_release(tdb, val);
173 int zero_out(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len)
175 char buf[8192] = { 0 };
176 void *p = tdb->methods->direct(tdb, off, len, true);
178 assert(!tdb->read_only);
184 unsigned todo = len < sizeof(buf) ? len : sizeof(buf);
185 if (tdb->methods->write(tdb, off, buf, todo) == -1)
193 tdb_off_t tdb_read_off(struct tdb_context *tdb, tdb_off_t off)
197 if (likely(!(tdb->flags & TDB_CONVERT))) {
198 tdb_off_t *p = tdb->methods->direct(tdb, off, sizeof(*p),
204 if (tdb_read_convert(tdb, off, &ret, sizeof(ret)) == -1)
209 /* Even on files, we can get partial writes due to signals. */
210 bool tdb_pwrite_all(int fd, const void *buf, size_t len, tdb_off_t off)
214 ret = pwrite(fd, buf, len, off);
221 buf = (char *)buf + ret;
228 /* write a lump of data at a specified offset */
229 static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
230 const void *buf, tdb_len_t len)
232 if (tdb->read_only) {
233 tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_DEBUG_WARNING,
234 "Write to read-only database");
238 /* FIXME: Bogus optimization? */
243 if (tdb->methods->oob(tdb, off + len, 0) != 0)
247 memcpy(off + (char *)tdb->map_ptr, buf, len);
249 if (!tdb_pwrite_all(tdb->fd, buf, len, off)) {
250 tdb_logerr(tdb, TDB_ERR_IO, TDB_DEBUG_FATAL,
251 "tdb_write failed at %zu len=%zu (%s)",
252 (size_t)off, (size_t)len, strerror(errno));
259 /* read a lump of data at a specified offset */
260 static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
263 if (tdb->methods->oob(tdb, off + len, 0) != 0) {
268 memcpy(buf, off + (char *)tdb->map_ptr, len);
270 ssize_t r = pread(tdb->fd, buf, len, off);
272 tdb_logerr(tdb, TDB_ERR_IO, TDB_DEBUG_FATAL,
273 "tdb_read failed with %zi at %zu "
274 "len=%zu (%s) map_size=%zu",
275 r, (size_t)off, (size_t)len,
277 (size_t)tdb->map_size);
284 int tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
285 const void *rec, size_t len)
288 if (unlikely((tdb->flags & TDB_CONVERT))) {
289 void *conv = malloc(len);
291 tdb_logerr(tdb, TDB_ERR_OOM, TDB_DEBUG_FATAL,
292 "tdb_write: no memory converting"
296 memcpy(conv, rec, len);
297 ret = tdb->methods->write(tdb, off,
298 tdb_convert(tdb, conv, len), len);
301 ret = tdb->methods->write(tdb, off, rec, len);
306 int tdb_read_convert(struct tdb_context *tdb, tdb_off_t off,
307 void *rec, size_t len)
309 int ret = tdb->methods->read(tdb, off, rec, len);
310 tdb_convert(tdb, rec, len);
314 int tdb_write_off(struct tdb_context *tdb, tdb_off_t off, tdb_off_t val)
316 if (tdb->read_only) {
317 tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_DEBUG_WARNING,
318 "Write to read-only database");
322 if (likely(!(tdb->flags & TDB_CONVERT))) {
323 tdb_off_t *p = tdb->methods->direct(tdb, off, sizeof(*p),
330 return tdb_write_convert(tdb, off, &val, sizeof(val));
333 static void *_tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset,
334 tdb_len_t len, unsigned int prefix)
338 /* some systems don't like zero length malloc */
339 buf = malloc(prefix + len ? prefix + len : 1);
341 tdb_logerr(tdb, TDB_ERR_OOM, TDB_DEBUG_ERROR,
342 "tdb_alloc_read malloc failed len=%zu",
343 (size_t)(prefix + len));
344 } else if (unlikely(tdb->methods->read(tdb, offset, buf+prefix,
352 /* read a lump of data, allocating the space for it */
353 void *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len)
355 return _tdb_alloc_read(tdb, offset, len, 0);
358 static int fill(struct tdb_context *tdb,
359 const void *buf, size_t size,
360 tdb_off_t off, tdb_len_t len)
363 size_t n = len > size ? size : len;
365 if (!tdb_pwrite_all(tdb->fd, buf, n, off)) {
366 tdb_logerr(tdb, TDB_ERR_IO, TDB_DEBUG_FATAL,
367 "fill write failed: giving up!");
376 /* expand a file. we prefer to use ftruncate, as that is what posix
377 says to use for mmap expansion */
378 static int tdb_expand_file(struct tdb_context *tdb, tdb_len_t addition)
382 if (tdb->read_only) {
383 tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_DEBUG_WARNING,
384 "Expand on read-only database");
388 if (tdb->flags & TDB_INTERNAL) {
389 char *new = realloc(tdb->map_ptr, tdb->map_size + addition);
391 tdb_logerr(tdb, TDB_ERR_OOM, TDB_DEBUG_FATAL,
392 "No memory to expand database");
396 tdb->map_size += addition;
398 /* Unmap before trying to write; old TDB claimed OpenBSD had
399 * problem with this otherwise. */
402 /* If this fails, we try to fill anyway. */
403 if (ftruncate(tdb->fd, tdb->map_size + addition))
406 /* now fill the file with something. This ensures that the
407 file isn't sparse, which would be very bad if we ran out of
408 disk. This must be done with write, not via mmap */
409 memset(buf, 0x43, sizeof(buf));
410 if (0 || fill(tdb, buf, sizeof(buf), tdb->map_size, addition) == -1)
412 tdb->map_size += addition;
418 const void *tdb_access_read(struct tdb_context *tdb,
419 tdb_off_t off, tdb_len_t len, bool convert)
421 const void *ret = NULL;
423 if (likely(!(tdb->flags & TDB_CONVERT)))
424 ret = tdb->methods->direct(tdb, off, len, false);
427 struct tdb_access_hdr *hdr;
428 hdr = _tdb_alloc_read(tdb, off, len, sizeof(*hdr));
430 hdr->next = tdb->access;
434 tdb_convert(tdb, (void *)ret, len);
437 tdb->direct_access++;
442 void *tdb_access_write(struct tdb_context *tdb,
443 tdb_off_t off, tdb_len_t len, bool convert)
447 if (tdb->read_only) {
448 tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_DEBUG_WARNING,
449 "Write to read-only database");
453 if (likely(!(tdb->flags & TDB_CONVERT)))
454 ret = tdb->methods->direct(tdb, off, len, true);
457 struct tdb_access_hdr *hdr;
458 hdr = _tdb_alloc_read(tdb, off, len, sizeof(*hdr));
460 hdr->next = tdb->access;
464 hdr->convert = convert;
467 tdb_convert(tdb, (void *)ret, len);
470 tdb->direct_access++;
475 static struct tdb_access_hdr **find_hdr(struct tdb_context *tdb, const void *p)
477 struct tdb_access_hdr **hp;
479 for (hp = &tdb->access; *hp; hp = &(*hp)->next) {
486 void tdb_access_release(struct tdb_context *tdb, const void *p)
488 struct tdb_access_hdr *hdr, **hp = find_hdr(tdb, p);
495 tdb->direct_access--;
498 int tdb_access_commit(struct tdb_context *tdb, void *p)
500 struct tdb_access_hdr *hdr, **hp = find_hdr(tdb, p);
506 ret = tdb_write_convert(tdb, hdr->off, p, hdr->len);
508 ret = tdb_write(tdb, hdr->off, p, hdr->len);
512 tdb->direct_access--;
517 static void *tdb_direct(struct tdb_context *tdb, tdb_off_t off, size_t len,
520 if (unlikely(!tdb->map_ptr))
523 if (unlikely(tdb_oob(tdb, off + len, true) == -1))
525 return (char *)tdb->map_ptr + off;
528 void add_stat_(struct tdb_context *tdb, uint64_t *s, size_t val)
530 if ((uintptr_t)s < (uintptr_t)tdb->stats + tdb->stats->size)
534 static const struct tdb_methods io_methods = {
543 initialise the default methods table
545 void tdb_io_init(struct tdb_context *tdb)
547 tdb->methods = &io_methods;