diff options
-rw-r--r-- | NEWS | 12 | ||||
-rw-r--r-- | doc/gdbm.texi | 21 | ||||
-rw-r--r-- | src/gdbm.h.in | 3 | ||||
-rw-r--r-- | src/gdbmconst.h | 3 | ||||
-rw-r--r-- | src/gdbmimp.c | 8 | ||||
-rw-r--r-- | src/gdbmopen.c | 89 |
6 files changed, 91 insertions, 45 deletions
@@ -1,2 +1,2 @@ -GNU dbm NEWS -- history of user-visible changes. 2016-07-13 +GNU dbm NEWS -- history of user-visible changes. 2016-07-15 Copyright (C) 1990-2016 Free Software Foundation, Inc. @@ -25,2 +25,12 @@ Instead it sets gdbm_errno to GDBM_MALLOC_ERROR and returns NULL datum. +* New gdbm_open flag: GDBM_BSEXACT + +When creating a new database, the gdbm_open function will adjust the +requested block size so that the block can hold integer number of +directory entries. Thus, the resulting block size can be bigger than +the requested one. If the GDBM_BSEXACT flag is set, this behavior is +suppressed and gdbm_open will try to force exactly the requested block +size. If unable to do so, it will set the gdbm_errno variable to +GDBM_BLOCK_SIZE_ERROR and return NULL. + * New functions diff --git a/doc/gdbm.texi b/doc/gdbm.texi index d172ad7..8096215 100644 --- a/doc/gdbm.texi +++ b/doc/gdbm.texi @@ -260,5 +260,10 @@ constructs. It is the size of a single transfer from disk to memory. This parameter is ignored if the file has been previously -initialized. The minimum size is 512. If the value is less than 512, -the file system block size is used, otherwise the value of -@var{block_size} is used. +initialized. If the value is less than 512, the file system block +size is used instead. The size is adjusted so that the block can hold +exact number of directory entries, so that the effective block size +can be slightly greater than requested. However, if the +@samp{GDBM_BSEXACT} flag is set and the size needs to be adjusted, the +function will return with error status, setting the @samp{gdbm_errno} +variable to @samp{GDBM_BLOCK_SIZE_ERROR}. + @item flags @@ -289,2 +294,8 @@ now obsolete, since @code{gdbm} defaults to no-sync mode. +@kwindex GDBM_BSEXACT +If this flag is set and the requested @var{block_size} cannot be used +without adjustment, @code{gdbm_open} will refuse to create the +databases. In this case it will set the @samp{gdbm_errno} +variable to @samp{GDBM_BLOCK_SIZE_ERROR} and return @samp{NULL}. + @kwindex GDBM_CLOEXEC @@ -1235,5 +1246,7 @@ Memory allocation failed. Not enough memory. @kwindex GDBM_BLOCK_SIZE_ERROR +@kwindex GDBM_BSEXACT @item GDBM_BLOCK_SIZE_ERROR This error is set by the @code{gdbm_open} function (@pxref{Open}), if -the value of its @var{block_size} argument is incorrect. +the value of its @var{block_size} argument is incorrect and the +@samp{GDBM_BSEXACT} flag is set. diff --git a/src/gdbm.h.in b/src/gdbm.h.in index a3d0461..07d3d1f 100644 --- a/src/gdbm.h.in +++ b/src/gdbm.h.in @@ -51,2 +51,5 @@ extern "C" { # define GDBM_CLOEXEC 0x100 /* Close the underlying fd on exec(3) */ +# define GDBM_BSEXACT 0x200 /* Don't adjust block_size. Bail out with + GDBM_BLOCK_SIZE_ERROR error if unable to + set it. */ diff --git a/src/gdbmconst.h b/src/gdbmconst.h index 56820db..66b0fb2 100644 --- a/src/gdbmconst.h +++ b/src/gdbmconst.h @@ -40,2 +40,5 @@ +/* Minimal acceptable block size */ +#define GDBM_MIN_BLOCK_SIZE 512 + /* In freeing blocks, we will ignore any blocks smaller (and equal) to diff --git a/src/gdbmimp.c b/src/gdbmimp.c index 57d1933..fc2710d 100644 --- a/src/gdbmimp.c +++ b/src/gdbmimp.c @@ -67,3 +67,3 @@ gdbm_import_from_file (GDBM_FILE dbf, FILE *fp, int flag) /* Allocate buffers. */ - kbufsize = 512; + kbufsize = GDBM_MIN_BLOCK_SIZE; kbuffer = malloc (kbufsize); @@ -74,3 +74,3 @@ gdbm_import_from_file (GDBM_FILE dbf, FILE *fp, int flag) } - dbufsize = 512; + dbufsize = GDBM_MIN_BLOCK_SIZE; dbuffer = malloc (dbufsize); @@ -97,3 +97,3 @@ gdbm_import_from_file (GDBM_FILE dbf, FILE *fp, int flag) { - kbufsize = (size + 512); + kbufsize = (size + GDBM_MIN_BLOCK_SIZE); kbuffer = realloc (kbuffer, kbufsize); @@ -129,3 +129,3 @@ gdbm_import_from_file (GDBM_FILE dbf, FILE *fp, int flag) { - dbufsize = (size + 512); + dbufsize = (size + GDBM_MIN_BLOCK_SIZE); dbuffer = realloc (dbuffer, dbufsize); diff --git a/src/gdbmopen.c b/src/gdbmopen.c index 52814df..5210001 100644 --- a/src/gdbmopen.c +++ b/src/gdbmopen.c @@ -33,2 +33,21 @@ +static void +compute_directory_size (GDBM_FILE dbf, blksize_t block_size, + int *ret_dir_size, int *ret_dir_bits) +{ + /* Create the initial hash table directory. */ + int dir_size = 8 * sizeof (off_t); + int dir_bits = 3; + + while (dir_size < block_size && dir_bits < GDBM_HASH_BITS - 3) + { + dir_size <<= 1; + dir_bits++; + } + + *ret_dir_size = dir_size; + *ret_dir_bits = dir_bits; +} + + /* Initialize dbm system. FILE is a pointer to the file name. If the file @@ -37,11 +56,11 @@ initialization to determine the size of various constructs. If the value - is less than 512, the file system blocksize is used, otherwise the value - of BLOCK_SIZE is used. BLOCK_SIZE is ignored if the file has previously - initialized. If FLAGS is set to GDBM_READ the user wants to just - read the database and any call to dbm_store or dbm_delete will fail. Many - readers can access the database at the same time. If FLAGS is set to - GDBM_WRITE, the user wants both read and write access to the database and - requires exclusive access. If FLAGS is GDBM_WRCREAT, the user wants - both read and write access to the database and if the database does not - exist, create a new one. If FLAGS is GDBM_NEWDB, the user want a + is less than GDBM_MIN_BLOCK_SIZE, the file system blocksize is used, + otherwise the value of BLOCK_SIZE is used. BLOCK_SIZE is ignored if the + file has previously initialized. If FLAGS is set to GDBM_READ the user + wants to just read the database and any call to dbm_store or dbm_delete + will fail. Many readers can access the database at the same time. If FLAGS + is set to GDBM_WRITE, the user wants both read and write access to the + database and requires exclusive access. If FLAGS is GDBM_WRCREAT, the user + wants both read and write access to the database and if the database does + not exist, create a new one. If FLAGS is GDBM_NEWDB, the user want a new database created, regardless of whether one existed, and wants read @@ -61,3 +80,2 @@ gdbm_open (const char *file, int block_size, int flags, int mode, off_t file_pos; /* Used with seeks. */ - int file_block_size; /* Block size to use for a new file. */ int index; /* Used as a loop index. */ @@ -213,14 +231,28 @@ gdbm_open (const char *file, int block_size, int flags, int mode, { - /* This is a new file. Create an empty database. */ - + int dir_size, dir_bits; + /* Start with the blocksize. */ - if (block_size < 512) - file_block_size = STATBLKSIZE(file_stat); - else - file_block_size = block_size; - + if (block_size < GDBM_MIN_BLOCK_SIZE) + { + block_size = STATBLKSIZE (file_stat); + flags &= ~GDBM_BSEXACT; + } + compute_directory_size (dbf, block_size, &dir_size, &dir_bits); + /* Check for correct block_size. */ + if (dir_size != block_size) + { + if (flags & GDBM_BSEXACT) + { + gdbm_close (dbf); + gdbm_set_errno (NULL, GDBM_BLOCK_SIZE_ERROR, FALSE); + return NULL; + } + else + block_size = dir_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, file_block_size); + dbf->header = (gdbm_file_header *) calloc (1, block_size); if (dbf->header == NULL) @@ -234,20 +266,5 @@ gdbm_open (const char *file, int block_size, int flags, int mode, dbf->header->header_magic = GDBM_MAGIC; - dbf->header->block_size = file_block_size; - - /* Create the initial hash table directory. */ - dbf->header->dir_size = 8 * sizeof (off_t); - dbf->header->dir_bits = 3; - while (dbf->header->dir_size < dbf->header->block_size) - { - dbf->header->dir_size <<= 1; - dbf->header->dir_bits += 1; - } - - /* Check for correct block_size. */ - if (dbf->header->dir_size != dbf->header->block_size) - { - gdbm_close (dbf); - gdbm_set_errno (NULL, GDBM_BLOCK_SIZE_ERROR, FALSE); - return NULL; - } + dbf->header->block_size = block_size; + dbf->header->dir_size = dir_size; + dbf->header->dir_bits = dir_bits; |