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