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->log(tdb, TDB_DEBUG_WARNING, tdb->log_priv,
60 "tdb_mmap failed for size %lld (%s)\n",
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)
75 /* We can't hold pointers during this: we could unmap! */
76 assert(!tdb->direct_access
77 || (tdb->flags & TDB_NOLOCK)
78 || tdb_has_expansion_lock(tdb));
80 if (len <= tdb->map_size)
82 if (tdb->flags & TDB_INTERNAL) {
84 /* Ensure ecode is set for log fn. */
85 tdb->ecode = TDB_ERR_IO;
86 tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv,
87 "tdb_oob len %lld beyond internal"
88 " malloc size %lld\n",
90 (long long)tdb->map_size);
95 if (tdb_lock_expand(tdb, F_RDLCK) != 0)
98 ret = fstat(tdb->fd, &st);
100 tdb_unlock_expand(tdb, F_RDLCK);
103 tdb->ecode = TDB_ERR_IO;
107 if (st.st_size < (size_t)len) {
109 /* Ensure ecode is set for log fn. */
110 tdb->ecode = TDB_ERR_IO;
111 tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv,
112 "tdb_oob len %lld beyond eof at %lld\n",
113 (long long)len, (long long)st.st_size);
118 /* Unmap, update size, remap */
121 tdb->map_size = st.st_size;
126 /* Endian conversion: we only ever deal with 8 byte quantities */
127 void *tdb_convert(const struct tdb_context *tdb, void *buf, tdb_len_t size)
129 if (unlikely((tdb->flags & TDB_CONVERT)) && buf) {
130 uint64_t i, *p = (uint64_t *)buf;
131 for (i = 0; i < size / 8; i++)
132 p[i] = bswap_64(p[i]);
137 /* FIXME: Return the off? */
138 uint64_t tdb_find_nonzero_off(struct tdb_context *tdb,
139 tdb_off_t base, uint64_t start, uint64_t end)
144 /* Zero vs non-zero is the same unconverted: minor optimization. */
145 val = tdb_access_read(tdb, base + start * sizeof(tdb_off_t),
146 (end - start) * sizeof(tdb_off_t), false);
150 for (i = 0; i < (end - start); i++) {
154 tdb_access_release(tdb, val);
158 /* Return first zero offset in num offset array, or num. */
159 uint64_t tdb_find_zero_off(struct tdb_context *tdb, tdb_off_t off,
165 /* Zero vs non-zero is the same unconverted: minor optimization. */
166 val = tdb_access_read(tdb, off, num * sizeof(tdb_off_t), false);
170 for (i = 0; i < num; i++) {
174 tdb_access_release(tdb, val);
178 int zero_out(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len)
180 char buf[8192] = { 0 };
181 void *p = tdb->methods->direct(tdb, off, len);
187 unsigned todo = len < sizeof(buf) ? len : sizeof(buf);
188 if (tdb->methods->write(tdb, off, buf, todo) == -1)
196 tdb_off_t tdb_read_off(struct tdb_context *tdb, tdb_off_t off)
200 if (tdb_read_convert(tdb, off, &ret, sizeof(ret)) == -1)
205 /* Even on files, we can get partial writes due to signals. */
206 bool tdb_pwrite_all(int fd, const void *buf, size_t len, tdb_off_t off)
210 ret = pwrite(fd, buf, len, off);
217 buf = (char *)buf + ret;
224 /* Even on files, we can get partial reads due to signals. */
225 bool tdb_pread_all(int fd, void *buf, size_t len, tdb_off_t off)
229 ret = pread(fd, buf, len, off);
237 buf = (char *)buf + ret;
244 bool tdb_read_all(int fd, void *buf, size_t len)
248 ret = read(fd, buf, len);
256 buf = (char *)buf + ret;
262 /* write a lump of data at a specified offset */
263 static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
264 const void *buf, tdb_len_t len)
270 if (tdb->read_only) {
271 tdb->ecode = TDB_ERR_RDONLY;
275 if (tdb->methods->oob(tdb, off + len, 0) != 0)
279 memcpy(off + (char *)tdb->map_ptr, buf, len);
281 if (!tdb_pwrite_all(tdb->fd, buf, len, off)) {
282 tdb->ecode = TDB_ERR_IO;
283 tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv,
284 "tdb_write failed at %llu len=%llu (%s)\n",
285 (long long)off, (long long)len,
293 /* read a lump of data at a specified offset */
294 static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
297 if (tdb->methods->oob(tdb, off + len, 0) != 0) {
302 memcpy(buf, off + (char *)tdb->map_ptr, len);
304 if (!tdb_pread_all(tdb->fd, buf, len, off)) {
305 /* Ensure ecode is set for log fn. */
306 tdb->ecode = TDB_ERR_IO;
307 tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv,
308 "tdb_read failed at %lld "
309 "len=%lld (%s) map_size=%lld\n",
310 (long long)off, (long long)len,
312 (long long)tdb->map_size);
319 int tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
320 const void *rec, size_t len)
323 if (unlikely((tdb->flags & TDB_CONVERT))) {
324 void *conv = malloc(len);
326 tdb->ecode = TDB_ERR_OOM;
327 tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv,
328 "tdb_write: no memory converting %zu bytes\n",
332 memcpy(conv, rec, len);
333 ret = tdb->methods->write(tdb, off,
334 tdb_convert(tdb, conv, len), len);
337 ret = tdb->methods->write(tdb, off, rec, len);
342 int tdb_read_convert(struct tdb_context *tdb, tdb_off_t off,
343 void *rec, size_t len)
345 int ret = tdb->methods->read(tdb, off, rec, len);
346 tdb_convert(tdb, rec, len);
350 int tdb_write_off(struct tdb_context *tdb, tdb_off_t off, tdb_off_t val)
352 return tdb_write_convert(tdb, off, &val, sizeof(val));
355 static void *_tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset,
356 tdb_len_t len, unsigned int prefix)
360 /* some systems don't like zero length malloc */
361 buf = malloc(prefix + len ? prefix + len : 1);
362 if (unlikely(!buf)) {
363 tdb->ecode = TDB_ERR_OOM;
364 tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
365 "tdb_alloc_read malloc failed len=%lld\n",
366 (long long)prefix + len);
367 } else if (unlikely(tdb->methods->read(tdb, offset, buf+prefix, len))) {
374 /* read a lump of data, allocating the space for it */
375 void *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len)
377 return _tdb_alloc_read(tdb, offset, len, 0);
380 static int fill(struct tdb_context *tdb,
381 const void *buf, size_t size,
382 tdb_off_t off, tdb_len_t len)
385 size_t n = len > size ? size : len;
387 if (!tdb_pwrite_all(tdb->fd, buf, n, off)) {
388 tdb->ecode = TDB_ERR_IO;
389 tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv,
390 "fill write failed: giving up!\n");
399 /* expand a file. we prefer to use ftruncate, as that is what posix
400 says to use for mmap expansion */
401 static int tdb_expand_file(struct tdb_context *tdb, tdb_len_t addition)
405 if (tdb->read_only) {
406 tdb->ecode = TDB_ERR_RDONLY;
410 if (tdb->flags & TDB_INTERNAL) {
411 char *new = realloc(tdb->map_ptr, tdb->map_size + addition);
413 tdb->ecode = TDB_ERR_OOM;
417 tdb->map_size += addition;
419 /* Unmap before trying to write; old TDB claimed OpenBSD had
420 * problem with this otherwise. */
423 /* If this fails, we try to fill anyway. */
424 if (ftruncate(tdb->fd, tdb->map_size + addition))
427 /* now fill the file with something. This ensures that the
428 file isn't sparse, which would be very bad if we ran out of
429 disk. This must be done with write, not via mmap */
430 memset(buf, 0x43, sizeof(buf));
431 if (0 || fill(tdb, buf, sizeof(buf), tdb->map_size, addition) == -1)
433 tdb->map_size += addition;
439 /* This is only neded for tdb_access_commit, but used everywhere to simplify. */
440 struct tdb_access_hdr {
446 const void *tdb_access_read(struct tdb_context *tdb,
447 tdb_off_t off, tdb_len_t len, bool convert)
449 const void *ret = NULL;
451 if (likely(!(tdb->flags & TDB_CONVERT)))
452 ret = tdb->methods->direct(tdb, off, len);
455 struct tdb_access_hdr *hdr;
456 hdr = _tdb_alloc_read(tdb, off, len, sizeof(*hdr));
460 tdb_convert(tdb, (void *)ret, len);
463 tdb->direct_access++;
468 void *tdb_access_write(struct tdb_context *tdb,
469 tdb_off_t off, tdb_len_t len, bool convert)
473 if (likely(!(tdb->flags & TDB_CONVERT)))
474 ret = tdb->methods->direct(tdb, off, len);
477 struct tdb_access_hdr *hdr;
478 hdr = _tdb_alloc_read(tdb, off, len, sizeof(*hdr));
482 hdr->convert = convert;
485 tdb_convert(tdb, (void *)ret, len);
488 tdb->direct_access++;
493 bool is_direct(const struct tdb_context *tdb, const void *p)
496 && (char *)p >= (char *)tdb->map_ptr
497 && (char *)p < (char *)tdb->map_ptr + tdb->map_size);
500 void tdb_access_release(struct tdb_context *tdb, const void *p)
502 if (is_direct(tdb, p))
503 tdb->direct_access--;
505 free((struct tdb_access_hdr *)p - 1);
508 int tdb_access_commit(struct tdb_context *tdb, void *p)
513 || (char *)p < (char *)tdb->map_ptr
514 || (char *)p >= (char *)tdb->map_ptr + tdb->map_size) {
515 struct tdb_access_hdr *hdr;
517 hdr = (struct tdb_access_hdr *)p - 1;
519 ret = tdb_write_convert(tdb, hdr->off, p, hdr->len);
521 ret = tdb_write(tdb, hdr->off, p, hdr->len);
524 tdb->direct_access--;
529 static void *tdb_direct(struct tdb_context *tdb, tdb_off_t off, size_t len)
531 if (unlikely(!tdb->map_ptr))
534 if (unlikely(tdb_oob(tdb, off + len, true) == -1))
536 return (char *)tdb->map_ptr + off;
539 void add_stat_(struct tdb_context *tdb, uint64_t *stat, size_t val)
541 if ((uintptr_t)stat < (uintptr_t)tdb->stats + tdb->stats->size)
545 static const struct tdb_methods io_methods = {
554 initialise the default methods table
556 void tdb_io_init(struct tdb_context *tdb)
558 tdb->methods = &io_methods;