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 | |
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')
-rw-r--r-- | src/gdbmload.c | 13 | ||||
-rw-r--r-- | src/gdbmopen.c | 20 | ||||
-rw-r--r-- | src/mmap.c | 55 |
3 files changed, 69 insertions, 19 deletions
diff --git a/src/gdbmload.c b/src/gdbmload.c index f634987..b243d08 100644 --- a/src/gdbmload.c +++ b/src/gdbmload.c @@ -295,7 +295,6 @@ _set_gdbm_meta_info (GDBM_FILE dbf, char *param, int meta_mask) int meta_flags = 0; const char *p; char *end; - int rc = 0; if (!(meta_mask & GDBM_META_MASK_OWNER)) { @@ -366,7 +365,11 @@ _set_gdbm_meta_info (GDBM_FILE dbf, char *param, int meta_mask) if ((meta_flags & (META_UID|META_GID)) != (META_UID|META_GID)) { struct stat st; - fstat (fd, &st); + if (fstat (fd, &st)) + { + GDBM_SET_ERRNO (dbf, GDBM_FILE_STAT_ERROR, FALSE); + return 1; + } if (!(meta_flags & META_UID)) owner_uid = st.st_uid; if (!(meta_flags & META_GID)) @@ -375,16 +378,16 @@ _set_gdbm_meta_info (GDBM_FILE dbf, char *param, int meta_mask) if (fchown (fd, owner_uid, owner_gid)) { GDBM_SET_ERRNO (dbf, GDBM_ERR_FILE_OWNER, FALSE); - rc = 1; + return 1; } } if ((meta_flags & META_MODE) && fchmod (fd, mode)) { GDBM_SET_ERRNO (dbf, GDBM_ERR_FILE_OWNER, FALSE); - rc = 1; + return 1; } } - return rc; + return 0; } int diff --git a/src/gdbmopen.c b/src/gdbmopen.c index 80474a6..cb73669 100644 --- a/src/gdbmopen.c +++ b/src/gdbmopen.c @@ -71,7 +71,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, } /* Allocate new info structure. */ - dbf = (GDBM_FILE) malloc (sizeof (*dbf)); + dbf = calloc (1, sizeof (*dbf)); if (dbf == NULL) { if (flags & GDBM_CLOERROR) @@ -171,7 +171,15 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, if ((flags & GDBM_OPENMASK) == GDBM_NEWDB && file_stat.st_size != 0) { TRUNCATE (dbf); - fstat (dbf->desc, &file_stat); + if (fstat (dbf->desc, &file_stat)) + { + if (flags & GDBM_CLOERROR) + close (dbf->desc); + free (dbf->name); + free (dbf); + GDBM_SET_ERRNO2 (NULL, GDBM_FILE_STAT_ERROR, FALSE, GDBM_DEBUG_OPEN); + return NULL; + } } /* Decide if this is a new file or an old file. */ @@ -208,7 +216,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, /* Get space for the file header. It will be written to disk, so make sure there's no garbage in it. */ - dbf->header = (gdbm_file_header *) calloc (1, block_size); + dbf->header = calloc (1, block_size); if (dbf->header == NULL) { if (!(flags & GDBM_CLOERROR)) @@ -241,7 +249,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, (dbf->header->block_size - sizeof (hash_bucket)) / sizeof (bucket_element) + 1; dbf->header->bucket_size = dbf->header->block_size; - dbf->bucket = (hash_bucket *) malloc (dbf->header->bucket_size); + dbf->bucket = calloc (1, dbf->header->bucket_size); if (dbf->bucket == NULL) { if (!(flags & GDBM_CLOERROR)) @@ -356,7 +364,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, } /* It is a good database, read the entire header. */ - dbf->header = (gdbm_file_header *) malloc (partial_header.block_size); + dbf->header = malloc (partial_header.block_size); if (dbf->header == NULL) { if (!(flags & GDBM_CLOERROR)) @@ -379,7 +387,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, } /* Allocate space for the hash table directory. */ - dbf->dir = (off_t *) malloc (dbf->header->dir_size); + dbf->dir = malloc (dbf->header->dir_size); if (dbf->dir == NULL) { if (!(flags & GDBM_CLOERROR)) @@ -54,7 +54,10 @@ _gdbm_file_size (GDBM_FILE dbf, off_t *psize) { struct stat sb; if (fstat (dbf->desc, &sb)) + { + 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; - } needle = file_size - offset; break; } |