aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS12
-rw-r--r--doc/gdbm.texi21
-rw-r--r--src/gdbm.h.in3
-rw-r--r--src/gdbmconst.h3
-rw-r--r--src/gdbmimp.c8
-rw-r--r--src/gdbmopen.c89
6 files changed, 91 insertions, 45 deletions
diff --git a/NEWS b/NEWS
index 0c0525d..99d4963 100644
--- a/NEWS
+++ b/NEWS
@@ -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;

Return to:

Send suggestions and report system problems to the System administrator.