retry gdbm_open() upon block size error
authorZefram <zefram@fysh.org>
Sat, 16 Dec 2017 02:17:08 +0000 (02:17 +0000)
committerZefram <zefram@fysh.org>
Sat, 16 Dec 2017 02:19:26 +0000 (02:19 +0000)
It is reported that gdbm_open() with default block size can fail on
filesystems with a non-power-of-two block size.  In that event, retry
opening, forcing a power-of-two block size.  Fixes [perl #119623].

ext/GDBM_File/GDBM_File.xs
pod/perldelta.pod

index 33e08e2..7f91049 100644 (file)
@@ -23,8 +23,6 @@ typedef datum datum_key ;
 typedef datum datum_value ;
 typedef datum datum_key_copy;
 
-#define GDBM_BLOCKSIZE 0 /* gdbm defaults to stat blocksize */
-
 #if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) \
     && GDBM_VERSION_MAJOR > 1 || \
     (GDBM_VERSION_MAJOR == 1 && GDBM_VERSION_MINOR >= 9)
@@ -81,17 +79,28 @@ gdbm_TIEHASH(dbtype, name, read_write, mode)
        char *          name
        int             read_write
        int             mode
+       PREINIT:
+       GDBM_FILE dbp;
        CODE:
-       {
-           GDBM_FILE   dbp ;
-
-           RETVAL = NULL ;
-           if ((dbp =  gdbm_open(name, GDBM_BLOCKSIZE, read_write, mode,
-                                 (FATALFUNC) croak_string))) {
-               RETVAL = (GDBM_File)safecalloc(1, sizeof(GDBM_File_type)) ;
-               RETVAL->dbp = dbp ;
-           }
-           
+       dbp = gdbm_open(name, 0, read_write, mode, (FATALFUNC)croak_string);
+       if (!dbp && gdbm_errno == GDBM_BLOCK_SIZE_ERROR) {
+           /*
+            * By specifying a block size of 0 above, we asked gdbm to
+            * default to the filesystem's block size.  That's usually the
+            * right size to choose.  But some versions of gdbm require
+            * a power-of-two block size, and some unusual filesystems
+            * or devices have a non-power-of-two size that cause this
+            * defaulting to fail.  In that case, force an acceptable
+            * block size.
+            */
+           dbp = gdbm_open(name, 4096, read_write, mode,
+                   (FATALFUNC)croak_string);
+       }
+       if (dbp) {
+           RETVAL = (GDBM_File)safecalloc(1, sizeof(GDBM_File_type));
+           RETVAL->dbp = dbp;
+       } else {
+           RETVAL = NULL;
        }
        OUTPUT:
          RETVAL
index 0dab15e..99c823b 100644 (file)
@@ -187,6 +187,8 @@ core of its job.  [perl #110520]
 L<GDBM_File> has been upgraded from version 1.16 to 1.17.
 Its documentation now explains that C<each> and C<delete> don't mix in
 hashes tied to this module [perl #117449].
+It will now retry opening with an acceptable block size if asking gdbm
+to default the block size failed [perl #119623].
 
 =back