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
10
** NOTE! The following LGPL license applies to the tdb
11
** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
29
#include "tdb_private.h"
31
/* check for an out of bounds access - if it is out of bounds then
32
see if the database has been expanded by someone else and expand
34
note that "len" is the minimum length needed for the db
36
static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
39
if (len <= tdb->map_size)
41
if (tdb->flags & TDB_INTERNAL) {
43
/* Ensure ecode is set for log fn. */
44
tdb->ecode = TDB_ERR_IO;
45
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond internal malloc size %d\n",
46
(int)len, (int)tdb->map_size));
48
return TDB_ERRCODE(TDB_ERR_IO, -1);
51
if (fstat(tdb->fd, &st) == -1) {
52
return TDB_ERRCODE(TDB_ERR_IO, -1);
55
if (st.st_size < (size_t)len) {
57
/* Ensure ecode is set for log fn. */
58
tdb->ecode = TDB_ERR_IO;
59
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond eof at %d\n",
60
(int)len, (int)st.st_size));
62
return TDB_ERRCODE(TDB_ERR_IO, -1);
65
/* Unmap, update size, remap */
66
if (tdb_munmap(tdb) == -1)
67
return TDB_ERRCODE(TDB_ERR_IO, -1);
68
tdb->map_size = st.st_size;
73
/* write a lump of data at a specified offset */
74
static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
75
const void *buf, tdb_len_t len)
81
if (tdb->read_only || tdb->traverse_read) {
82
tdb->ecode = TDB_ERR_RDONLY;
86
if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0)
90
memcpy(off + (char *)tdb->map_ptr, buf, len);
92
ssize_t written = pwrite(tdb->fd, buf, len, off);
93
if ((written != (ssize_t)len) && (written != -1)) {
95
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: wrote only "
96
"%d of %d bytes at %d, trying once more\n",
97
(int)written, len, off));
99
written = pwrite(tdb->fd, (const void *)((const char *)buf+written),
104
/* Ensure ecode is set for log fn. */
105
tdb->ecode = TDB_ERR_IO;
106
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %d "
107
"len=%d (%s)\n", off, len, strerror(errno)));
108
return TDB_ERRCODE(TDB_ERR_IO, -1);
109
} else if (written != (ssize_t)len) {
110
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: failed to "
111
"write %d bytes at %d in two attempts\n",
114
return TDB_ERRCODE(TDB_ERR_IO, -1);
120
/* Endian conversion: we only ever deal with 4 byte quantities */
121
void *tdb_convert(void *buf, uint32_t size)
123
uint32_t i, *p = (uint32_t *)buf;
124
for (i = 0; i < size / 4; i++)
125
p[i] = TDB_BYTEREV(p[i]);
130
/* read a lump of data at a specified offset, maybe convert */
131
static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
132
tdb_len_t len, int cv)
134
if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0) {
139
memcpy(buf, off + (char *)tdb->map_ptr, len);
141
ssize_t ret = pread(tdb->fd, buf, len, off);
142
if (ret != (ssize_t)len) {
143
/* Ensure ecode is set for log fn. */
144
tdb->ecode = TDB_ERR_IO;
145
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %d "
146
"len=%d ret=%d (%s) map_size=%d\n",
147
(int)off, (int)len, (int)ret, strerror(errno),
148
(int)tdb->map_size));
149
return TDB_ERRCODE(TDB_ERR_IO, -1);
153
tdb_convert(buf, len);
161
do an unlocked scan of the hash table heads to find the next non-zero head. The value
162
will then be confirmed with the lock held
164
static void tdb_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
168
for (;h < tdb->header.hash_size;h++) {
169
if (0 != *(uint32_t *)(TDB_HASH_TOP(h) + (unsigned char *)tdb->map_ptr)) {
175
for (;h < tdb->header.hash_size;h++) {
176
if (tdb_ofs_read(tdb, TDB_HASH_TOP(h), &off) != 0 || off != 0) {
185
int tdb_munmap(struct tdb_context *tdb)
187
if (tdb->flags & TDB_INTERNAL)
194
ret = munmap(tdb->map_ptr, tdb->map_size);
203
void tdb_mmap(struct tdb_context *tdb)
205
if (tdb->flags & TDB_INTERNAL)
209
if (!(tdb->flags & TDB_NOMMAP)) {
210
tdb->map_ptr = mmap(NULL, tdb->map_size,
211
PROT_READ|(tdb->read_only? 0:PROT_WRITE),
212
MAP_SHARED|MAP_FILE, tdb->fd, 0);
215
* NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
218
if (tdb->map_ptr == MAP_FAILED) {
220
TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n",
221
tdb->map_size, strerror(errno)));
231
/* expand a file. we prefer to use ftruncate, as that is what posix
232
says to use for mmap expansion */
233
static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t addition)
237
if (tdb->read_only || tdb->traverse_read) {
238
tdb->ecode = TDB_ERR_RDONLY;
242
if (ftruncate(tdb->fd, size+addition) == -1) {
244
ssize_t written = pwrite(tdb->fd, &b, 1, (size+addition) - 1);
246
/* try once more, potentially revealing errno */
247
written = pwrite(tdb->fd, &b, 1, (size+addition) - 1);
250
/* again - give up, guessing errno */
254
TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n",
255
size+addition, strerror(errno)));
260
/* now fill the file with something. This ensures that the
261
file isn't sparse, which would be very bad if we ran out of
262
disk. This must be done with write, not via mmap */
263
memset(buf, TDB_PAD_BYTE, sizeof(buf));
265
size_t n = addition>sizeof(buf)?sizeof(buf):addition;
266
ssize_t written = pwrite(tdb->fd, buf, n, size);
268
/* prevent infinite loops: try _once_ more */
269
written = pwrite(tdb->fd, buf, n, size);
272
/* give up, trying to provide a useful errno */
273
TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
274
"returned 0 twice: giving up!\n"));
277
} else if (written == -1) {
278
TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
279
"%d bytes failed (%s)\n", (int)n,
282
} else if (written != n) {
283
TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
284
"only %d of %d bytes - retrying\n", (int)written,
294
/* expand the database at least size bytes by expanding the underlying
295
file and doing the mmap again if necessary */
296
int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
298
struct list_struct rec;
299
tdb_off_t offset, new_size;
301
if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
302
TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n"));
306
/* must know about any previous expansions by another process */
307
tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
309
/* always make room for at least 100 more records, and at
310
least 25% more space. Round the database up to a multiple
312
new_size = MAX(tdb->map_size + size*100, tdb->map_size * 1.25);
313
size = TDB_ALIGN(new_size, tdb->page_size) - tdb->map_size;
315
if (!(tdb->flags & TDB_INTERNAL))
319
* We must ensure the file is unmapped before doing this
320
* to ensure consistency with systems like OpenBSD where
321
* writes and mmaps are not consistent.
324
/* expand the file itself */
325
if (!(tdb->flags & TDB_INTERNAL)) {
326
if (tdb->methods->tdb_expand_file(tdb, tdb->map_size, size) != 0)
330
tdb->map_size += size;
332
if (tdb->flags & TDB_INTERNAL) {
333
char *new_map_ptr = (char *)realloc(tdb->map_ptr,
336
tdb->map_size -= size;
339
tdb->map_ptr = new_map_ptr;
342
* We must ensure the file is remapped before adding the space
343
* to ensure consistency with systems like OpenBSD where
344
* writes and mmaps are not consistent.
347
/* We're ok if the mmap fails as we'll fallback to read/write */
351
/* form a new freelist record */
352
memset(&rec,'\0',sizeof(rec));
353
rec.rec_len = size - sizeof(rec);
355
/* link it into the free list */
356
offset = tdb->map_size - size;
357
if (tdb_free(tdb, offset, &rec) == -1)
360
tdb_unlock(tdb, -1, F_WRLCK);
363
tdb_unlock(tdb, -1, F_WRLCK);
367
/* read/write a tdb_off_t */
368
int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
370
return tdb->methods->tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV());
373
int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
376
return tdb->methods->tdb_write(tdb, offset, CONVERT(off), sizeof(*d));
380
/* read a lump of data, allocating the space for it */
381
unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len)
385
/* some systems don't like zero length malloc */
390
if (!(buf = (unsigned char *)malloc(len))) {
391
/* Ensure ecode is set for log fn. */
392
tdb->ecode = TDB_ERR_OOM;
393
TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%d (%s)\n",
394
len, strerror(errno)));
395
return TDB_ERRCODE(TDB_ERR_OOM, buf);
397
if (tdb->methods->tdb_read(tdb, offset, buf, len, 0) == -1) {
404
/* Give a piece of tdb data to a parser */
406
int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
407
tdb_off_t offset, tdb_len_t len,
408
int (*parser)(TDB_DATA key, TDB_DATA data,
417
if ((tdb->transaction == NULL) && (tdb->map_ptr != NULL)) {
419
* Optimize by avoiding the malloc/memcpy/free, point the
420
* parser directly at the mmap area.
422
if (tdb->methods->tdb_oob(tdb, offset+len, 0) != 0) {
425
data.dptr = offset + (unsigned char *)tdb->map_ptr;
426
return parser(key, data, private_data);
429
if (!(data.dptr = tdb_alloc_read(tdb, offset, len))) {
433
result = parser(key, data, private_data);
438
/* read/write a record */
439
int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec)
441
if (tdb->methods->tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1)
443
if (TDB_BAD_MAGIC(rec)) {
444
/* Ensure ecode is set for log fn. */
445
tdb->ecode = TDB_ERR_CORRUPT;
446
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset));
447
return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
449
return tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0);
452
int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec)
454
struct list_struct r = *rec;
455
return tdb->methods->tdb_write(tdb, offset, CONVERT(r), sizeof(r));
458
static const struct tdb_methods io_methods = {
468
initialise the default methods table
470
void tdb_io_init(struct tdb_context *tdb)
472
tdb->methods = &io_methods;