vfs: update status of SMB_VFS_LISTXATTR
[samba.git] / lib / tdb / common / io.c
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 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
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
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
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
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
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 */
139 static int tdb_notrans_oob(
140         struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, 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         /*
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         if (off + len <= tdb->map_size)
159                 return 0;
160         if (tdb->flags & TDB_INTERNAL) {
161                 if (!probe) {
162                         /* Ensure ecode is set for log fn. */
163                         tdb->ecode = TDB_ERR_IO;
164                         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                 return -1;
168         }
169
170         if (tdb_fstat(tdb, &st) == -1) {
171                 tdb->ecode = TDB_ERR_IO;
172                 return -1;
173         }
174
175         /* Beware >4G files! */
176         if ((tdb_off_t)st.st_size != st.st_size) {
177                 /* Ensure ecode is set for log fn. */
178                 tdb->ecode = TDB_ERR_IO;
179                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_oob len %llu too large!\n",
180                          (long long)st.st_size));
181                 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         if (tdb_munmap(tdb) == -1) {
191                 tdb->ecode = TDB_ERR_IO;
192                 return -1;
193         }
194         tdb->map_size = st.st_size;
195         if (tdb_mmap(tdb) != 0) {
196                 return -1;
197         }
198
199         if (st.st_size < (size_t)off + len) {
200                 if (!probe) {
201                         /* Ensure ecode is set for log fn. */
202                         tdb->ecode = TDB_ERR_IO;
203                         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                 return -1;
207         }
208         return 0;
209 }
210
211 /* write a lump of data at a specified offset */
212 static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
213                      const void *buf, tdb_len_t len)
214 {
215         if (len == 0) {
216                 return 0;
217         }
218
219         if (tdb->read_only || tdb->traverse_read) {
220                 tdb->ecode = TDB_ERR_RDONLY;
221                 return -1;
222         }
223
224         if (tdb_oob(tdb, off, len, 0) != 0)
225                 return -1;
226
227         if (tdb->map_ptr) {
228                 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                 ssize_t written;
235
236                 written = tdb_pwrite(tdb, buf, len, off);
237
238                 if ((written != (ssize_t)len) && (written != -1)) {
239                         /* try once more */
240                         tdb->ecode = TDB_ERR_IO;
241                         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                         written = tdb_pwrite(tdb, (const char *)buf+written,
245                                              len-written, off+written);
246                 }
247                 if (written == -1) {
248                         /* Ensure ecode is set for log fn. */
249                         tdb->ecode = TDB_ERR_IO;
250                         TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %u "
251                                  "len=%u (%s)\n", off, len, strerror(errno)));
252                         return -1;
253                 } else if (written != (ssize_t)len) {
254                         tdb->ecode = TDB_ERR_IO;
255                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: failed to "
256                                  "write %u bytes at %u in two attempts\n",
257                                  len, off));
258                         return -1;
259                 }
260 #endif
261         }
262         return 0;
263 }
264
265 /* Endian conversion: we only ever deal with 4 byte quantities */
266 void *tdb_convert(void *buf, uint32_t size)
267 {
268         uint32_t i, *p = (uint32_t *)buf;
269         for (i = 0; i < size / 4; i++)
270                 p[i] = TDB_BYTEREV(p[i]);
271         return buf;
272 }
273
274
275 /* read a lump of data at a specified offset, maybe convert */
276 static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
277                     tdb_len_t len, int cv)
278 {
279         if (tdb_oob(tdb, off, len, 0) != 0) {
280                 return -1;
281         }
282
283         if (tdb->map_ptr) {
284                 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                 ssize_t ret;
291
292                 ret = tdb_pread(tdb, buf, len, off);
293                 if (ret != (ssize_t)len) {
294                         /* Ensure ecode is set for log fn. */
295                         tdb->ecode = TDB_ERR_IO;
296                         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                         return -1;
301                 }
302 #endif
303         }
304         if (cv) {
305                 tdb_convert(buf, len);
306         }
307         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 static void tdb_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
317 {
318         uint32_t h = *chain;
319         if (tdb->map_ptr) {
320                 for (;h < tdb->hash_size;h++) {
321                         if (0 != *(uint32_t *)(TDB_HASH_TOP(h) + (unsigned char *)tdb->map_ptr)) {
322                                 break;
323                         }
324                 }
325         } else {
326                 uint32_t off=0;
327                 for (;h < tdb->hash_size;h++) {
328                         if (tdb_ofs_read(tdb, TDB_HASH_TOP(h), &off) != 0 || off != 0) {
329                                 break;
330                         }
331                 }
332         }
333         (*chain) = h;
334 }
335
336
337 int tdb_munmap(struct tdb_context *tdb)
338 {
339         if (tdb->flags & TDB_INTERNAL)
340                 return 0;
341
342 #ifdef HAVE_MMAP
343         if (tdb->map_ptr) {
344                 int ret;
345
346                 ret = munmap(tdb->map_ptr, tdb->map_size);
347                 if (ret != 0)
348                         return ret;
349         }
350 #endif
351         tdb->map_ptr = NULL;
352         return 0;
353 }
354
355 /* If mmap isn't coherent, *everyone* must always mmap. */
356 static bool should_mmap(const struct tdb_context *tdb)
357 {
358 #ifdef HAVE_INCOHERENT_MMAP
359         return true;
360 #else
361         return !(tdb->flags & TDB_NOMMAP);
362 #endif
363 }
364
365 int tdb_mmap(struct tdb_context *tdb)
366 {
367         if (tdb->flags & TDB_INTERNAL)
368                 return 0;
369
370 #ifdef HAVE_MMAP
371         if (should_mmap(tdb)) {
372                 tdb->map_ptr = mmap(NULL, tdb->map_size,
373                                     PROT_READ|(tdb->read_only? 0:PROT_WRITE),
374                                     MAP_SHARED|MAP_FILE, tdb->fd,
375                                     tdb->hdr_ofs);
376
377                 /*
378                  * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
379                  */
380
381                 if (tdb->map_ptr == MAP_FAILED) {
382                         tdb->map_ptr = NULL;
383                         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                 tdb->map_ptr = NULL;
392         }
393 #else
394         tdb->map_ptr = NULL;
395 #endif
396         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 static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t addition)
402 {
403         char buf[8192];
404         tdb_off_t new_size;
405         int ret;
406
407         if (tdb->read_only || tdb->traverse_read) {
408                 tdb->ecode = TDB_ERR_RDONLY;
409                 return -1;
410         }
411
412         if (!tdb_add_off_t(size, addition, &new_size)) {
413                 tdb->ecode = TDB_ERR_OOM;
414                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
415                         "overflow detected current size[%u] addition[%u]!\n",
416                         (unsigned)size, (unsigned)addition));
417                 errno = ENOSPC;
418                 return -1;
419         }
420
421 #ifdef HAVE_POSIX_FALLOCATE
422         ret = tdb_posix_fallocate(tdb, size, addition);
423         if (ret == 0) {
424                 return 0;
425         }
426         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                 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         ret = tdb_ftruncate(tdb, new_size);
450         if (ret == -1) {
451                 char b = 0;
452                 ssize_t written = tdb_pwrite(tdb, &b, 1, new_size - 1);
453                 if (written == 0) {
454                         /* try once more, potentially revealing errno */
455                         written = tdb_pwrite(tdb, &b, 1, new_size - 1);
456                 }
457                 if (written == 0) {
458                         /* again - give up, guessing errno */
459                         errno = ENOSPC;
460                 }
461                 if (written != 1) {
462                         tdb->ecode = TDB_ERR_OOM;
463                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %u failed (%s)\n",
464                                  (unsigned)new_size, strerror(errno)));
465                         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         memset(buf, TDB_PAD_BYTE, sizeof(buf));
473         while (addition) {
474                 size_t n = addition>sizeof(buf)?sizeof(buf):addition;
475                 ssize_t written = tdb_pwrite(tdb, buf, n, size);
476                 if (written == 0) {
477                         /* prevent infinite loops: try _once_ more */
478                         written = tdb_pwrite(tdb, buf, n, size);
479                 }
480                 if (written == 0) {
481                         /* give up, trying to provide a useful errno */
482                         tdb->ecode = TDB_ERR_OOM;
483                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
484                                 "returned 0 twice: giving up!\n"));
485                         errno = ENOSPC;
486                         goto fail;
487                 }
488                 if (written == -1) {
489                         tdb->ecode = TDB_ERR_OOM;
490                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
491                                  "%u bytes failed (%s)\n", (int)n,
492                                  strerror(errno)));
493                         goto fail;
494                 }
495                 if (written != n) {
496                         TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
497                                  "only %zu of %zi bytes - retrying\n", written,
498                                  n));
499                 }
500                 addition -= written;
501                 size += written;
502         }
503         return 0;
504
505 fail:
506         {
507                 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                 ret = tdb_ftruncate(tdb, size);
517                 if (ret == -1) {
518                         TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: "
519                                  "retruncate to %ju failed\n",
520                                  (uintmax_t)size));
521                 }
522                 errno = err;
523         }
524
525         return -1;
526 }
527
528
529 /* You need 'size', this tells you how much you should expand by. */
530 tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size)
531 {
532         tdb_off_t new_size, top_size, increment;
533         tdb_off_t max_size = UINT32_MAX - map_size;
534
535         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                 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         if (size > 100 * 1024) {
548                 increment = size * 2;
549         } else {
550                 increment = size * 100;
551         }
552         if (increment < size) {
553                 goto overflow;
554         }
555
556         if (!tdb_add_off_t(map_size, increment, &top_size)) {
557                 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         if (map_size > 100 * 1024 * 1024) {
564                 new_size = map_size * 1.10;
565         } else {
566                 new_size = map_size * 1.25;
567         }
568         if (new_size < map_size) {
569                 goto overflow;
570         }
571
572         /* Round the database up to a multiple of the page size */
573         new_size = MAX(top_size, new_size);
574
575         if (new_size + page_size < new_size) {
576                 /* There's a "+" in TDB_ALIGN that might overflow... */
577                 goto overflow;
578         }
579
580         return TDB_ALIGN(new_size, page_size) - map_size;
581
582 overflow:
583         /*
584          * Somewhere in between we went over 4GB. Make one big jump to
585          * exactly 4GB database size.
586          */
587         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 int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
593 {
594         struct tdb_record rec;
595         tdb_off_t offset;
596         tdb_off_t new_size;
597
598         if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
599                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n"));
600                 return -1;
601         }
602
603         /* must know about any previous expansions by another process */
604         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         size = tdb_expand_adjust(tdb->map_size, size, tdb->page_size);
615
616         if (!tdb_add_off_t(tdb->map_size, size, &new_size)) {
617                 tdb->ecode = TDB_ERR_OOM;
618                 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                 goto fail;
622         }
623
624         /* form a new freelist record */
625         offset = tdb->map_size;
626         memset(&rec,'\0',sizeof(rec));
627         rec.rec_len = size - sizeof(rec);
628
629         if (tdb->flags & TDB_INTERNAL) {
630                 char *new_map_ptr;
631
632                 new_map_ptr = (char *)realloc(tdb->map_ptr, new_size);
633                 if (!new_map_ptr) {
634                         tdb->ecode = TDB_ERR_OOM;
635                         goto fail;
636                 }
637                 tdb->map_ptr = new_map_ptr;
638                 tdb->map_size = new_size;
639         } else {
640                 int ret;
641
642                 /*
643                  * expand the file itself
644                  */
645                 ret = tdb->methods->tdb_expand_file(tdb, tdb->map_size, size);
646                 if (ret != 0) {
647                         goto fail;
648                 }
649
650                 /* Explicitly remap: if we're in a transaction, this won't
651                  * happen automatically! */
652                 tdb_munmap(tdb);
653                 tdb->map_size = new_size;
654                 if (tdb_mmap(tdb) != 0) {
655                         goto fail;
656                 }
657         }
658
659         /* link it into the free list */
660         if (tdb_free(tdb, offset, &rec) == -1)
661                 goto fail;
662
663         tdb_unlock(tdb, -1, F_WRLCK);
664         return 0;
665  fail:
666         tdb_unlock(tdb, -1, F_WRLCK);
667         return -1;
668 }
669
670 int _tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe)
671 {
672         int ret = tdb->methods->tdb_oob(tdb, off, len, probe);
673         return ret;
674 }
675
676 /* read/write a tdb_off_t */
677 int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
678 {
679         return tdb->methods->tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV());
680 }
681
682 int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
683 {
684         tdb_off_t off = *d;
685         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 unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len)
691 {
692         unsigned char *buf;
693
694         /* some systems don't like zero length malloc */
695
696         if (!(buf = (unsigned char *)malloc(len ? len : 1))) {
697                 /* Ensure ecode is set for log fn. */
698                 tdb->ecode = TDB_ERR_OOM;
699                 TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%u (%s)\n",
700                            len, strerror(errno)));
701                 return NULL;
702         }
703         if (tdb->methods->tdb_read(tdb, offset, buf, len, 0) == -1) {
704                 SAFE_FREE(buf);
705                 return NULL;
706         }
707         return buf;
708 }
709
710 /* Give a piece of tdb data to a parser */
711
712 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         TDB_DATA data;
719         int result;
720
721         data.dsize = len;
722
723         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                 if (tdb_oob(tdb, offset, len, 0) != 0) {
729                         return -1;
730                 }
731                 data.dptr = offset + (unsigned char *)tdb->map_ptr;
732                 return parser(key, data, private_data);
733         }
734
735         if (!(data.dptr = tdb_alloc_read(tdb, offset, len))) {
736                 return -1;
737         }
738
739         result = parser(key, data, private_data);
740         free(data.dptr);
741         return result;
742 }
743
744 /* read/write a record */
745 int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
746 {
747         int ret;
748         tdb_len_t overall_len;
749
750         if (tdb->methods->tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1)
751                 return -1;
752         if (TDB_BAD_MAGIC(rec)) {
753                 /* Ensure ecode is set for log fn. */
754                 tdb->ecode = TDB_ERR_CORRUPT;
755                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%u\n", rec->magic, offset));
756                 return -1;
757         }
758
759         overall_len = rec->key_len + rec->data_len;
760         if (overall_len < rec->data_len) {
761                 /* overflow */
762                 return -1;
763         }
764
765         if (overall_len > rec->rec_len) {
766                 /* invalid record */
767                 return -1;
768         }
769
770         ret = tdb_oob(tdb, offset, rec->key_len, 1);
771         if (ret == -1) {
772                 return -1;
773         }
774         ret = tdb_oob(tdb, offset, rec->data_len, 1);
775         if (ret == -1) {
776                 return -1;
777         }
778         ret = tdb_oob(tdb, offset, rec->rec_len, 1);
779         if (ret == -1) {
780                 return -1;
781         }
782
783         return tdb_oob(tdb, rec->next, sizeof(*rec), 0);
784 }
785
786 int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
787 {
788         struct tdb_record r = *rec;
789         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 void tdb_io_init(struct tdb_context *tdb)
804 {
805         tdb->methods = &io_methods;
806 }