diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2017-12-21 09:19:41 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2017-12-21 09:26:54 +0200 |
commit | 2e8a5e0be7b2db179018c10248a6cc64f9db3314 (patch) | |
tree | 6c36d26a1b6c6e668628683978baa2acea3ad3ba /src/mmap.c | |
parent | c175231e2781abd17eabf412cfb597654a076c7b (diff) | |
download | gdbm-2e8a5e0be7b2db179018c10248a6cc64f9db3314.tar.gz gdbm-2e8a5e0be7b2db179018c10248a6cc64f9db3314.tar.bz2 |
Improve database reproducibility
* src/gdbmopen.c (gdbm_fd_open): Fill allocated memory with 0's
where necessary.
Check return value from fstat.
* src/mmap.c (_gdbm_file_size): Set errno here, instead of delegating
that to the caller.
(_gdbm_file_extend): New function.
(_gdbm_mapped_remap): Call _gdbm_file_extend instead of leaving the
newly allocated space filled with garbage.
* src/gdbmload.c (_set_gdbm_meta_info): Additional error checking.
* NEWS: Update.
Diffstat (limited to 'src/mmap.c')
-rw-r--r-- | src/mmap.c | 59 |
1 files changed, 49 insertions, 10 deletions
@@ -54,7 +54,10 @@ _gdbm_file_size (GDBM_FILE dbf, off_t *psize) { struct stat sb; if (fstat (dbf->desc, &sb)) - return -1; + { + GDBM_SET_ERRNO (dbf, GDBM_FILE_STAT_ERROR, FALSE); + return -1; + } *psize = sb.st_size; return 0; } @@ -112,6 +115,48 @@ _gdbm_internal_remap (GDBM_FILE dbf, size_t size) return 0; } +/* Grow the disk file of DBF to the SIZE bytes in length. Fill the + newly allocated space with zeros. */ +static int +_gdbm_file_extend (GDBM_FILE dbf, off_t size) +{ + size_t page_size = sysconf (_SC_PAGESIZE); + char *buf; + off_t file_end; + + file_end = lseek (dbf->desc, 0, SEEK_END); + if (!file_end) + { + GDBM_SET_ERRNO (dbf, GDBM_FILE_SEEK_ERROR, FALSE); + return -1; + } + size -= file_end; + + if (size < page_size) + page_size = size; + buf = calloc (1, page_size); + if (!buf) + { + GDBM_SET_ERRNO (dbf, GDBM_MALLOC_ERROR, FALSE); + return -1; + } + + while (size) + { + ssize_t n = write (dbf->desc, buf, size < page_size ? size : page_size); + if (n <= 0) + { + GDBM_SET_ERRNO (dbf, GDBM_FILE_WRITE_ERROR, FALSE); + break; + } + size -= n; + } + free (buf); + if (size) + return -1; + return 0; +} + # define _REMAP_DEFAULT 0 # define _REMAP_EXTEND 1 # define _REMAP_END 2 @@ -140,7 +185,6 @@ _gdbm_mapped_remap (GDBM_FILE dbf, off_t size, int flag) if (_gdbm_file_size (dbf, &file_size)) { SAVE_ERRNO (_gdbm_mapped_unmap (dbf)); - GDBM_SET_ERRNO (dbf, GDBM_FILE_STAT_ERROR, FALSE); return -1; } @@ -153,12 +197,10 @@ _gdbm_mapped_remap (GDBM_FILE dbf, off_t size, int flag) { if (flag != _REMAP_DEFAULT) { - char c = 0; - if (size < dbf->header->next_block) size = dbf->header->next_block; - lseek (dbf->desc, size - 1, SEEK_SET); - write (dbf->desc, &c, 1); + if (_gdbm_file_extend (dbf, size)) + return -1; file_size = size; } else @@ -334,10 +376,7 @@ _gdbm_mapped_lseek (GDBM_FILE dbf, off_t offset, int whence) { off_t file_size; if (_gdbm_file_size (dbf, &file_size)) - { - GDBM_SET_ERRNO (dbf, GDBM_FILE_STAT_ERROR, FALSE); - return -1; - } + return -1; needle = file_size - offset; break; } |