2017-03-12  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* compat/dbmopen.c (ndbm_open_dir_file0) [O_BINARY]:  For DOS/DJGPP
	systems use PAG_FILE_IS_HARD_LINK_TO_DIR_FILE instead of st_ino
	together with st_dev.

	* compat/ndbm.h:  Add structure tag to data structure.  This inhibits
	warning about anonymous struct using if g++ 2.95.2 is used.

	* doc/gdbm.3:  Add additional library linking info.

	* gdbm.texi:  Add additional library linking info.
	Add info about DJGPP specific resource filenames depending on if the
	used file system offers LFN support or not.

	* doc/gdbmtool.1:  Add info about DJGPP specific resource filenames
	depending on if the used file system offers LFN support or not.

	* src/gdbm.h.in:  Add structure tag to data structures.  This inhibits
	warning about anonymous struct using if g++ 2.95.2 is used.

	* src/gdbmdefs.h:  Add structure tag to data and gdbm structures.
	This inhibits warning about anonymous struct using if g++ 2.95.2
	is used.

	* src/gdbmexp.c [HAVE_ARPA_INET_H]:  Do not include arpa/inet.h.

	* src/gdbmimp.c [HAVE_ARPA_INET_H]:  Do not include arpa/inet.h.

	* src/gdbmtool.h:  Use _GDBMTOOLRC macro defined in systems.h instead
	of hard coded file name.

	* src/lock.c [EWOULDBLOCK]:  If EWOULDBLOCK not defined define it as
	EAGAIN.
	[EDEADLK]:  If EDEADLK not defined define it as 9.  Taken from errno.h.

	* src/progname.c (set_progname):  Use STRIP_FULL_PATH_AND_EXTENSION and
	CANONICALIZE_PATH.

	* src/systems.h [O_BINARY, __DJGPP__]:  New macros HAS_LFN_SUPPORT and
	GDBMTOOLRC.  These macros select either .gdbmtoolrc or _gdbmtoolrc as
	file name depending on LFN/SFN capability of the file system used.
	They provide default values for anything else than DJGPP.
	[O_BINARY]:  PAG_FILE_IS_HARD_LINK_TO_DIR_FILE macro tries to check if
	data base file .pag is a hard link to data base file .dir.
	[O_BINARY, __DJGPP__]:  STATBLKSIZE must be set to a multiple of 512
	or the initalization of the hash table directory for a new file will
	fail.
	[O_BINARY]:  New macro open. Open file in binary mode.
	[O_BINARY]:  New macro IS_DIR_SEPARATOR. Check for DOS-style directory
	separators.
	[O_BINARY, __DJGPP__]:  DJGPP does neither provide htonl() nor ntohl().
	Those functions implemented as NO-OP macros.
	New macros STRIP_FULL_PATH_AND_EXTENSION and CANONICALIZE_PATH.  These
	are NO-OPs for anything else than DJGPP.

	* src/var.c (set_progname):  Rename bool with gdbm_bool in union value.
	(s2b, b2b, i2b, variable_get, variable_print_all):  bool replaved with
	gdbm_bool.

	* tests/gtopt.c [_SC_PAGESIZE]:  If _SC_PAGESIZE not defined define it
	as 65536






diff -aprNU5 gdbm-1.13.orig/compat/dbmopen.c gdbm-1.13/compat/dbmopen.c
--- gdbm-1.13.orig/compat/dbmopen.c	2017-01-02 11:51:44 +0000
+++ gdbm-1.13/compat/dbmopen.c	2017-03-12 17:13:48 +0000
@@ -76,13 +76,17 @@ ndbm_open_dir_file0 (const char *file_na
     } 
       
   /* Previous versions of GDBM linked pag to dir. Try to detect this: */
   if (stat (file_name, &st) == 0)
     {
+#if defined(__DJGPP__)
+      if (PAG_FILE_IS_HARD_LINK_TO_DIR_FILE(file_name))
+#else
       if (st.st_nlink >= 2)
 	{
 	  if (st.st_dev == pagst.st_dev && st.st_ino == pagst.st_ino)
+#endif
 	    {
 	      if (unlink (file_name))
 		{
 		  if ((mode & GDBM_OPENMASK) == GDBM_READER)
 		    /* Ok, try to cope with it. */
@@ -92,16 +96,18 @@ ndbm_open_dir_file0 (const char *file_na
 		      gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, TRUE); 
 		      return -1;
 		    } 
 		}
 	    }
+#if !defined(__DJGPP__)
 	  else
 	    {
 	      gdbm_set_errno (NULL, GDBM_FILE_OPEN_ERROR, FALSE);
 	      return -1;
 	    }
 	}
+#endif
       else if (st.st_size == 0)
 	/* ok */;
       else if (st.st_size != DEF_DIR_SIZE)
 	{
 	  gdbm_set_errno (NULL, GDBM_BAD_MAGIC_NUMBER, FALSE);
diff -aprNU5 gdbm-1.13.orig/compat/ndbm.h gdbm-1.13/compat/ndbm.h
--- gdbm-1.13.orig/compat/ndbm.h	2017-01-02 11:51:44 +0000
+++ gdbm-1.13/compat/ndbm.h	2017-03-12 14:58:38 +0000
@@ -30,11 +30,11 @@
 /* Parameters to dbm_store for simple insertion or replacement. */
 #define DBM_INSERT  GDBM_INSERT
 #define DBM_REPLACE GDBM_REPLACE
 
 /* The file information header.  */
-typedef struct
+typedef struct __tag_dbm
 {
   GDBM_FILE file;         /* Actual gdbm file (held in the .pag file */
   int dirfd;              /* Descriptor of the .dir file */
   datum _dbm_memory;      /* Keeps the last returned key */
   char *_dbm_fetch_val;   /* Keeps the dptr of the last fetched datum */
diff -aprNU5 gdbm-1.13.orig/doc/gdbm.3 gdbm-1.13/doc/gdbm.3
--- gdbm-1.13.orig/doc/gdbm.3	2017-01-02 11:51:44 +0000
+++ gdbm-1.13/doc/gdbm.3	2017-03-12 15:01:18 +0000
@@ -417,11 +417,16 @@ gcc \-o prog prog.c \-lgdbm
 If you wish to use the \fBdbm\fR or \fBndbm\fR compatibility routines,
 you must link in the \fIgdbm_compat\fR library as well.  For example:
 .sp
 .nf
 .in +5
-gcc \-o prog proc.c \-lgdbm \-lgdbm_compat
+gcc \-o prog proc.c \-lgdbm_compat \-lgdbm
+
+Please note that the compatibility library contains references to
+gdbm routines so the order in which the libraries are linked is essential.
+This means that the library linking order given in the above example must
+be respected.
 .in
 .fi
 .\" .SH BUGS
 
 .SH "BUG REPORTS"
diff -aprNU5 gdbm-1.13.orig/doc/gdbm.texi gdbm-1.13/doc/gdbm.texi
--- gdbm-1.13.orig/doc/gdbm.texi	2017-01-02 11:51:44 +0000
+++ gdbm-1.13/doc/gdbm.texi	2017-03-12 16:42:32 +0000
@@ -235,11 +235,12 @@ int gdbm_count (GDBM_FILE dbf, gdbm_coun
 int gdbm_version_cmp (int const a[], int const b[]);
 @end example
 
 The @code{gdbm.h} include file is often in the @file{/usr/include}
 directory. (The actual location of @code{gdbm.h} depends on your local
-installation of @code{gdbm}.)
+installation of @code{gdbm}.  In case of the @acronym{DJGPP} port, the @code{gdbm.h}
+include file is in the @file{/dev/env/DJDIR/usr/include} directory.)
 
 @node Open
 @chapter Opening the database.
 
 @cindex opening the database
@@ -1669,18 +1670,23 @@ The compatibility layer consists of two
 and @file{dbm.h} and the @file{libgdbm_compat} library.
 
 Older programs using @code{ndbm} or @code{dbm} interfaces can
 use @file{libgdbm_compat} without any changes.  To link a program with
 the compatibility library, add the following two options to the
-@command{cc} invocation: @option{-lgdbm -lgdbm_compat}.  The @option{-L}
+@command{cc} invocation: @option{-lgdbm_compat -lgdbm}.  The @option{-L}
 option may also be required, depending on where @code{gdbm} is
 installed, e.g.:
 
 @example
-cc ... -lgdbm -lgdbm_compat
+cc ... -lgdbm_compat -lgdbm
 @end example
 
+Please note that the compatibility library contains references to
+gdbm routines so the order in which the libraries are linked is essential.
+This means that the library linking order given in the above example must
+be respected.
+
 @cindex @samp{dir} file
 @cindex @samp{pag} file
 Databases created and manipulated by the compatibility interfaces
 consist of two different files: @file{@var{file}.dir} and
 @file{@var{file}.pag}.  This is required by the @acronym{POSIX}
@@ -2609,10 +2615,16 @@ hash value = 13089969.
 @flindex .gdbmtoolrc
 Upon startup @command{gdbmtool} looks for a file named
 @samp{.gdbmtoolrc} first in the current working directory and, if not
 found, in the home directory of the user who started the command.
 
+The port compiled with @acronym{DJGPP} will look either for a file named
+@samp{.gdbmtoolrc} or @samp{_gdbmtoolrc}, in that order, depending on if
+the underlying file system used offers long filename support (aka @acronym{LFN}
+support) or not.  If not, like on plain @acronym{DOS}, then only for
+@samp{_gdbmtoolrc} will be looked.
+
 If found, this file is read and interpreted as a list of
 @command{gdbmtool} commands.  This allows you to customize the
 program behavior.
 
 Following is an example startup file which disables the welcome
diff -aprNU5 gdbm-1.13.orig/doc/gdbmtool.1 gdbm-1.13/doc/gdbmtool.1
--- gdbm-1.13.orig/doc/gdbmtool.1	2017-01-02 11:51:44 +0000
+++ gdbm-1.13/doc/gdbmtool.1	2017-03-12 15:09:46 +0000
@@ -48,10 +48,25 @@ first in the current working directory,
 the home directory of the user who started the program.  If found,
 this file is read and interpreted as a list of
 .B gdbmtool
 commands.
 .PP
+The port compiled with
+.B DJGPP
+will look either for a file named
+.B .gdbmtoolrc
+or
+.B _gdbmtoolrc
+, in that order, depending on if the underlying file system used offers
+long filename support (aka
+.B LFN
+support) or not.  If not, like on plain
+.B DOS
+, then only for
+.B _gdbmtoolrc
+will be looked.
+.PP
 Then
 .B gdbmtool
 starts a loop, in which it reads
 commands from the standard input, executes them and prints the results on the
 standard output.  If the standard input is attached to a console,
diff -aprNU5 gdbm-1.13.orig/src/gdbm.h.in gdbm-1.13/src/gdbm.h.in
--- gdbm-1.13.orig/src/gdbm.h.in	2017-01-02 11:51:44 +0000
+++ gdbm-1.13/src/gdbm.h.in	2017-03-12 16:46:38 +0000
@@ -86,11 +86,11 @@ extern "C" {
 # define GDBM_GETBLOCKSIZE    16 /* Return block size */
 
 typedef @GDBM_COUNT_T@ gdbm_count_t;
   
 /* The data and key structure. */
-typedef struct
+typedef struct __tag_datum
 {
   char *dptr;
   int   dsize;
 } datum;
 
diff -aprNU5 gdbm-1.13.orig/src/gdbmdefs.h gdbm-1.13/src/gdbmdefs.h
--- gdbm-1.13.orig/src/gdbmdefs.h	2017-01-02 11:51:44 +0000
+++ gdbm-1.13/src/gdbmdefs.h	2017-03-12 16:49:24 +0000
@@ -33,30 +33,30 @@
    one filles up, it is split in half and half is pushed on an "avail
    stack."  When the active avail table is empty and the "avail stack" is
    not empty, the top of the stack is popped into the active avail table. */
 
 /* The following structure is the element of the avaliable table.  */
-typedef struct
+typedef struct __tag_avail_elem
 {
   int   av_size;                /* The size of the available block. */
   off_t  av_adr;                /* The file address of the available block. */
 } avail_elem;
 
 /* This is the actual table. The in-memory images of the avail blocks are
    allocated by malloc using a calculated size.  */
-typedef struct
+typedef struct __tag_avail_block
 {
   int   size;             /* The number of avail elements in the table.*/
   int   count;            /* The number of entries in the table. */
   off_t next_block;       /* The file address of the next avail block. */
   avail_elem av_table[1]; /* The table.  Make it look like an array.  */
 } avail_block;
 
 /* The dbm file header keeps track of the current location of the hash
    directory and the free space in the file.  */
 
-typedef struct
+typedef struct __tag_gdbm_file_header
 {
   int   header_magic;  /* Version of file. */
   int   block_size;    /* The optimal i/o blocksize from stat. */
   off_t dir;           /* File address of hash directory table. */
   int   dir_size;      /* Size in bytes of the table.  */
@@ -74,11 +74,11 @@ typedef struct
    "pointer" to the key and data (stored together) with their sizes.  It also
    has a small part of the actual key value.  It is used to verify the first
    part of the key has the correct value without having to read the actual
    key. */
 
-typedef struct
+typedef struct __tag_bucket_element
 {
   int   hash_value;       /* The complete 31 bit value. */
   char  key_start[SMALL]; /* Up to the first SMALL bytes of the key.  */
   off_t data_pointer;     /* The file address of the key record. The
 			     data record directly follows the key.  */
@@ -97,11 +97,11 @@ typedef struct
    value modulo the size of the bucket.  The in-memory images of the
    buckets are allocated by malloc using a calculated size depending of
    the file system buffer size.  To speed up write, each bucket will have
    BUCKET_AVAIL avail elements with the bucket. */
 
-typedef struct
+typedef struct __tag_hash_bucket
 {
   int   av_count;            /* The number of bucket_avail entries. */
   avail_elem bucket_avail[BUCKET_AVAIL];  /* Distributed avail. */
   int   bucket_bits;         /* The number of bits used to get here. */
   int   count;               /* The number of element buckets full. */
@@ -117,20 +117,20 @@ typedef struct
    must exactly match the key from the file.  To reduce overhead, the
    data will be read at the same time.  Both key and data will be stored
    in a data cache.  Each bucket cached will have a one element data
    cache.  */
 
-typedef struct
+typedef struct __tag_data_cache_elem
 {
   int   hash_val;
   int   data_size;
   int   key_size;
   char *dptr;
   int   elem_loc;
 } data_cache_elem;
 
-typedef struct
+typedef struct __tag_cache_elem
 {
   hash_bucket *   ca_bucket;
   off_t           ca_adr;
   char            ca_changed;   /* Data in the bucket changed. */
   data_cache_elem ca_data;
diff -aprNU5 gdbm-1.13.orig/src/gdbmexp.c gdbm-1.13/src/gdbmexp.c
--- gdbm-1.13.orig/src/gdbmexp.c	2017-01-02 11:51:44 +0000
+++ gdbm-1.13/src/gdbmexp.c	2017-03-12 16:55:46 +0000
@@ -17,11 +17,13 @@
    You should have received a copy of the GNU General Public License
    along with GDBM. If not, see <http://www.gnu.org/licenses/>.   */
 
 /* Include system configuration before all else. */
 # include "autoconf.h"
-# include <arpa/inet.h>
+# if HAVE_ARPA_INET_H
+#  include <arpa/inet.h>
+# endif
 
 # include "gdbmdefs.h"
 # include "gdbm.h"
 
 int
diff -aprNU5 gdbm-1.13.orig/src/gdbmimp.c gdbm-1.13/src/gdbmimp.c
--- gdbm-1.13.orig/src/gdbmimp.c	2017-01-02 11:51:44 +0000
+++ gdbm-1.13/src/gdbmimp.c	2017-03-12 16:55:42 +0000
@@ -16,11 +16,13 @@
 
    You should have received a copy of the GNU General Public License
    along with GDBM. If not, see <http://www.gnu.org/licenses/>.   */
 
 # include "autoconf.h"
-# include <arpa/inet.h>
+# if HAVE_ARPA_INET_H
+#  include <arpa/inet.h>
+# endif
 # include <limits.h>
 
 # include "gdbmdefs.h"
 # include "gdbm.h"
 
diff -aprNU5 gdbm-1.13.orig/src/gdbmtool.h gdbm-1.13/src/gdbmtool.h
--- gdbm-1.13.orig/src/gdbmtool.h	2017-01-02 11:51:44 +0000
+++ gdbm-1.13/src/gdbmtool.h	2017-03-12 17:03:18 +0000
@@ -111,11 +111,11 @@ int setsource (const char *filename, int
 
 extern char *file_name;
 extern int interactive;
 extern int open_mode;
 
-#define GDBMTOOLRC ".gdbmtoolrc"
+#define GDBMTOOLRC _GDBMTOOLRC
 #define GDBMTOOL_DEFFILE "junk.gdbm"
 
 ssize_t input_read (FILE *fp, char *buf, size_t size);
 void input_init (void);
 void input_done (void);
diff -aprNU5 gdbm-1.13.orig/src/lock.c gdbm-1.13/src/lock.c
--- gdbm-1.13.orig/src/lock.c	2017-01-02 11:51:46 +0000
+++ gdbm-1.13/src/lock.c	2017-03-12 17:04:24 +0000
@@ -45,10 +45,20 @@
 # define HAVE_FCNTL_LOCK 1
 #else
 # define HAVE_FCNTL_LOCK 0
 #endif
 
+#ifndef EWOULDBLOCK
+# define EWOULDBLOCK  EAGAIN
+#endif
+
+#ifndef EDEADLK
+# if __DJGPP__
+#  define EDEADLK  9  /* From errno.h.  */
+# endif
+#endif
+
 #if 0
 int
 gdbm_locked (GDBM_FILE dbf)
 {
   return (dbf->lock_type != LOCKING_NONE);
diff -aprNU5 gdbm-1.13.orig/src/progname.c gdbm-1.13/src/progname.c
--- gdbm-1.13.orig/src/progname.c	2017-01-02 11:51:46 +0000
+++ gdbm-1.13/src/progname.c	2017-03-12 17:05:44 +0000
@@ -17,16 +17,20 @@
 # include "autoconf.h"
 # include "gdbm.h"
 # include "gdbmapp.h"
 # include <string.h>
 
+# ifndef STRIP_FULL_PATH_AND_EXTENSION
+#  include "systems.h"
+# endif
+
 const char *progname;
 
 void
 set_progname (const char *arg)
 {
-  const char *p = strrchr (arg, '/');
+  const char *p = STRIP_FULL_PATH_AND_EXTENSION(arg);
   if (p)
     ++p;
   else
     p = arg;
   if (strncmp (p, "lt-", 3) == 0)
diff -aprNU5 gdbm-1.13.orig/src/systems.h gdbm-1.13/src/systems.h
--- gdbm-1.13.orig/src/systems.h	2017-01-02 11:51:46 +0000
+++ gdbm-1.13/src/systems.h	2017-03-12 17:25:04 +0000
@@ -33,25 +33,27 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 
 #ifndef SEEK_SET
-# define SEEK_SET        0
+# define SEEK_SET   0
 #endif
 
 #ifndef O_CLOEXEC
-# define O_CLOEXEC 0
+# define O_CLOEXEC  0
 #endif
 
 /* Default block size.  Some systems do not have blocksize in their
    stat record. This code uses the BSD blocksize from stat. */
 
+#ifndef __DJGPP__
 #if HAVE_STRUCT_STAT_ST_BLKSIZE
 # define STATBLKSIZE(st) (st).st_blksize
 #else
 # define STATBLKSIZE(st) 1024
 #endif
+#endif
 
 /* Do we have ftruncate? */
 #if HAVE_FTRUNCATE
 # define TRUNCATE(dbf) ftruncate (dbf->desc, 0)
 #else
@@ -77,5 +79,173 @@
 # else
 #  define __fsync(_dbf)			{ sync(); sync(); }
 # endif
 #endif
 
+/* For systems that distinguish between text and binary I/O.
+   O_BINARY is usually declared in fcntl.h  */
+#if !defined O_BINARY && defined _O_BINARY
+  /* For MSC-compatible compilers.  */
+# define O_BINARY _O_BINARY
+#endif
+#if O_BINARY
+  /* Files must be opened in BINARY mode. */
+# undef  open
+# define open(file, mode, ...)  open((file), (mode) | O_BINARY, ##__VA_ARGS__)
+# define IS_SLASH(c)            ((c) == '/' || (c) == '\\')
+# define IS_DIR_SEPARATOR(c)    (IS_SLASH(c) || (c) == ':')
+
+# if __DJGPP__
+
+   /* DJGPP does not support neither hton[ls] nor ntoh[ls].  */
+#  undef  htonl
+#  define htonl(hostlong)  (hostlong)  /*  No op.  */
+#  undef  ntohl
+#  define ntohl(netlong)   (netlong)   /*  No op.  */
+
+   /*
+       A newly created data base file gets an initial hash table directory
+       that has a size of 8 * sizeof (off_t).  This is only possible if
+       STATBLKSIZE (file system block size) is a multiple of 512.
+       Unfortunately DJGPP's fstat does not always return a st_blksize value
+       that is a multiple of 512.
+   */
+#  undef  STATBLKSIZE
+#  define STATBLKSIZE(st)  512
+
+
+#  if defined (__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))
+#   define __gnuc_extension__  __extension__
+#  else
+#   define __gnuc_extension__
+#  endif
+
+#  include <libc/unconst.h>
+#  define STRIP_FULL_PATH_AND_EXTENSION(file_name)                                                                        \
+   (__gnuc_extension__                                                                                                    \
+     ({                                                                                                                   \
+        char *_dst, *_src;                                                                                                \
+        _dst = _src = unconst((file_name), char *);                                                                       \
+        while (*_src++)                                                                                                   \
+          ;                                                                                                               \
+        while ((_src - _dst) && (*--_src != '.'))                                                                         \
+          ;                                                                                                               \
+        for (*_src = '\0'; (_src - _dst); _src--)                                                                         \
+          if (IS_DIR_SEPARATOR(*_src))                                                                                    \
+            break;                                                                                                        \
+        if (_src - _dst)                                                                                                  \
+          while ((*_dst++ = *++_src))                                                                                     \
+            ;                                                                                                             \
+        (file_name);                                                                                                      \
+     })                                                                                                                   \
+   )
+
+#  define CANONICALIZE_PATH(path)                                                                                         \
+   (__gnuc_extension__                                                                                                    \
+     ({                                                                                                                   \
+        if ((path))                                                                                                       \
+        {                                                                                                                 \
+          char *_p = unconst((path), char *);                                                                             \
+          for (; *_p; _p++)                                                                                               \
+            if (*_p == '\\')                                                                                              \
+              *_p = '/';                                                                                                  \
+        }                                                                                                                 \
+        (path);                                                                                                           \
+     })                                                                                                                   \
+   )
+
+   /*
+       It is not possible to use st_ino to determinated
+       if .pag file is an hard link to .dir file.
+   */
+#  include <stdbool.h>
+#  define PAG_FILE_IS_HARD_LINK_TO_DIR_FILE(file_name)                                                                    \
+   (__gnuc_extension__                                                                                                    \
+     ({                                                                                                                   \
+        bool _is_link = false;                                                                                            \
+        char *_dir_file, *_pag_file;                                                                                      \
+        size_t length = (size_t)strlen(file_name);                                                                        \
+                                                                                                                          \
+        _dir_file = unconst((file_name), char *);                                                                         \
+        _pag_file = malloc(length + 1);                                                                                   \
+        strcpy(_pag_file, _dir_file);                                                                                     \
+        _pag_file[--length] = 'g';                                                                                        \
+        _pag_file[--length] = 'a';                                                                                        \
+        _pag_file[--length] = 'p';                                                                                        \
+                                                                                                                          \
+        if (!access(_dir_file, F_OK) && !access(_pag_file, F_OK))                                                         \
+        {                                                                                                                 \
+          struct stat _sb_dir, _sb_pag;                                                                                   \
+          if (!stat(_dir_file, &_sb_dir) && !stat(_pag_file, &_sb_pag))                                                   \
+          {                                                                                                               \
+            if ((_sb_dir.st_dev == _sb_pag.st_dev) && (_sb_dir.st_size == _sb_pag.st_size))                               \
+            {                                                                                                             \
+              int _fd_dir = open(_dir_file, O_RDONLY | O_BINARY);                                                         \
+              int _fd_pag = open(_pag_file, O_RDONLY | O_BINARY);                                                         \
+              if ((_fd_dir > -1) && (_fd_pag > -1))                                                                       \
+              {                                                                                                           \
+                char _buffer_dir[512], _buffer_pag[512];                                                                  \
+                ssize_t _bytes_read_dir, _bytes_read_pag;                                                                 \
+                                                                                                                          \
+                _bytes_read_dir = read(_fd_dir, _buffer_dir, 512);                                                        \
+                _bytes_read_pag = read(_fd_pag, _buffer_pag, 512);                                                        \
+                if ((_bytes_read_dir > -1) && (_bytes_read_pag > -1) && (_bytes_read_dir == _bytes_read_pag))             \
+                {                                                                                                         \
+                  ssize_t _i;                                                                                             \
+                  for (_i = 0; _i < _bytes_read_dir && _buffer_dir[_i] == _buffer_pag[_i]; _i++)                          \
+                    ;                                                                                                     \
+                  if (_i != _bytes_read_dir)                                                                              \
+                    goto _finished;                                                                                       \
+                                                                                                                          \
+                  off_t _pos_dir = lseek(_fd_dir, -512, SEEK_END);                                                        \
+                  off_t _pos_pag = lseek(_fd_pag, -512, SEEK_END);                                                        \
+                  if ((_pos_dir > -1) && (_pos_pag > -1) && (_pos_dir == _pos_pag))                                       \
+                  {                                                                                                       \
+                    _bytes_read_dir = read(_fd_dir, _buffer_dir, 512);                                                    \
+                    _bytes_read_pag = read(_fd_pag, _buffer_pag, 512);                                                    \
+                    if ((_bytes_read_dir > -1) && (_bytes_read_pag > -1) && (_bytes_read_dir == _bytes_read_pag))         \
+                    {                                                                                                     \
+                      for (_i = 0; _i < _bytes_read_dir && _buffer_dir[_i] == _buffer_pag[_i]; _i++)                      \
+                        ;                                                                                                 \
+                      if (_i != _bytes_read_dir)                                                                          \
+                        goto _finished;                                                                                   \
+                      _is_link = true;                                                                                    \
+                    }                                                                                                     \
+                  }                                                                                                       \
+                }                                                                                                         \
+                                                                                                                          \
+_finished:                                                                                                                \
+                close(_fd_dir);                                                                                           \
+                close(_fd_pag);                                                                                           \
+              }                                                                                                           \
+            }                                                                                                             \
+          }                                                                                                               \
+        }                                                                                                                 \
+        (_is_link);                                                                                                       \
+     })                                                                                                                   \
+   )
+
+#  define HAS_LFN_SUPPORT(name)  (pathconf((name), _PC_NAME_MAX) > 12)
+#  define FILE_EXISTS(name)      (access((name), R_OK) == 0)
+
+#  define _GDBMTOOLRC                                                                                                     \
+   (__gnuc_extension__                                                                                                    \
+     ({                                                                                                                   \
+        char *gdbmtoolrc = HAS_LFN_SUPPORT(".gdbmtoolrc") && FILE_EXISTS(".gdbmtoolrc") ? ".gdbmtoolrc" : "_gdbmtoolrc";  \
+        gdbmtoolrc;                                                                                                       \
+     })                                                                                                                   \
+   )
+
+# else /* !__DJGPP__  */
+#  define STRIP_FULL_PATH_AND_EXTENSION(file_name)  (strrchr ((file_name), '/'))
+#  define CANONICALIZE_PATH(path)                   (path)
+#  define HAS_LFN_SUPPORT(name)                     (0)
+#  define _GDBMTOOLRC                               "_gdbmtoolrc"
+# endif /* !__DJGPP__  */
+#else /* not O_BINARY */
+# define O_BINARY
+# define IS_DIR_SEPARATOR(c)                        ((c) == '/')
+# define STRIP_FULL_PATH_AND_EXTENSION(file_name)   (strrchr ((file_name), '/'))
+# define CANONICALIZE_PATH(path)                    (path)
+# define HAS_LFN_SUPPORT(name)                      (1)
+# define _GDBMTOOLRC                                ".gdbmtoolrc"
+#endif /* not O_BINARY */
diff -aprNU5 gdbm-1.13.orig/src/var.c gdbm-1.13/src/var.c
--- gdbm-1.13.orig/src/var.c	2017-01-02 11:51:46 +0000
+++ gdbm-1.13/src/var.c	2017-03-12 17:10:48 +0000
@@ -26,11 +26,11 @@
 #define VAR_IS_SET(v) ((v)->flags & (VARF_SET|VARF_INIT))
 
 union value
 {
   char *string;
-  int bool;
+  int gdbm_bool;
   int num;
 };
 
 struct variable
 {
@@ -50,17 +50,17 @@ static struct variable vartab[] = {
   { "ps2", VART_STRING, VARF_INIT, { .string = "%_>%_" } },
   /* This delimits array members */
   { "delim1", VART_STRING, VARF_INIT|VARF_PROT, { .string = "," } },
   /* This delimits structure members */
   { "delim2", VART_STRING, VARF_INIT|VARF_PROT, { .string = "," } },
-  { "confirm", VART_BOOL, VARF_INIT, { .bool = 1 } },
+  { "confirm", VART_BOOL, VARF_INIT, { .gdbm_bool = 1 } },
   { "cachesize", VART_INT, VARF_DFL },
   { "blocksize", VART_INT, VARF_DFL },
   { "open", VART_STRING, VARF_DFL, { NULL }, open_hook },
-  { "lock", VART_BOOL, VARF_INIT, { .bool = 1 } },
-  { "mmap", VART_BOOL, VARF_INIT, { .bool = 1 } },
-  { "sync", VART_BOOL, VARF_INIT, { .bool = 0 } },
+  { "lock", VART_BOOL, VARF_INIT, { .gdbm_bool = 1 } },
+  { "mmap", VART_BOOL, VARF_INIT, { .gdbm_bool = 1 } },
+  { "sync", VART_BOOL, VARF_INIT, { .gdbm_bool = 0 } },
   { "filemode", VART_INT, VARF_INIT|VARF_OCTAL|VARF_PROT, { .num = 0644 } },
   { "pager", VART_STRING, VARF_DFL },
   { "quiet", VART_BOOL, VARF_DFL },
   { NULL }
 };
@@ -141,25 +141,25 @@ s2b (union value *vp, void *val, int fla
   char *p;
   
   for (i = 0; trueval[i]; i++)
     if (strcasecmp (trueval[i], val) == 0)
       {
-	vp->bool = 1;
+	vp->gdbm_bool = 1;
 	return VAR_OK;
       }
   
   for (i = 0; falseval[i]; i++)
     if (strcasecmp (falseval[i], val) == 0)
       {
-	vp->bool = 0;
+	vp->gdbm_bool = 0;
 	return VAR_OK;
       }
   
   n = strtoul (val, &p, 0);
   if (*p)
     return VAR_ERR_BADTYPE;
-  vp->bool = !!n;
+  vp->gdbm_bool = !!n;
   return VAR_OK;
 }
   
 static int
 s2i (union value *vp, void *val, int flags)
@@ -175,11 +175,11 @@ s2i (union value *vp, void *val, int fla
 }
 
 static int
 b2b (union value *vp, void *val, int flags)
 {
-  vp->bool = !!*(int*)val;
+  vp->gdbm_bool = !!*(int*)val;
   return VAR_OK;
 }
 
 static int
 b2i (union value *vp, void *val, int flags)
@@ -196,11 +196,11 @@ i2i (union value *vp, void *val, int fla
 }
 
 static int
 i2b (union value *vp, void *val, int flags)
 {
-  vp->bool = *(int*)val;
+  vp->gdbm_bool = *(int*)val;
   return VAR_OK;
 }
 
 static setvar_t setvar[3][3] = {
             /*    s     b    i */
@@ -292,11 +292,11 @@ variable_get (const char *name, int type
     case VART_STRING:
       *val = vp->v.string;
       break;
 
     case VART_BOOL:
-      *(int*)val = vp->v.bool;
+      *(int*)val = vp->v.gdbm_bool;
       break;
       
     case VART_INT:
       *(int*)val = vp->v.num;
       break;
@@ -340,11 +340,11 @@ variable_print_all (FILE *fp)
 	      fprintf (fp, (vp->flags & VARF_OCTAL) ? "%s=%03o" : "%s=%d",
 		       vp->name, vp->v.num);
 	      break;
 	      
 	    case VART_BOOL:
-	      fprintf (fp, "%s%s", vp->v.bool ? "" : "no", vp->name);
+	      fprintf (fp, "%s%s", vp->v.gdbm_bool ? "" : "no", vp->name);
 	      break;
 	      
 	    case VART_STRING:
 	      fprintf (fp, "%s=\"", vp->name);
 	      for (s = vp->v.string; *s; s++)
diff -aprNU5 gdbm-1.13.orig/tests/gtopt.c gdbm-1.13/tests/gtopt.c
--- gdbm-1.13.orig/tests/gtopt.c	2017-01-02 11:51:46 +0000
+++ gdbm-1.13/tests/gtopt.c	2017-03-12 15:15:16 +0000
@@ -29,10 +29,14 @@ int flags = 0;                  /* gdbm_
 int mode = GDBM_WRCREAT;        /* gdbm_open mode */
 int block_size = 0;             /* block size for the db. 0 means default */
 size_t mapped_size_max = 32768; /* size of the memory mapped region */
 size_t cache_size = 32;         /* cache size */
 
+#ifndef _SC_PAGESIZE
+# define _SC_PAGESIZE  65536
+#endif
+
 static size_t
 get_max_mmap_size (const char *arg)
 {
   char *p;
   size_t size;










2017-05-03  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* export/export.c (main):  Use STRIP_FULL_PATH_AND_EXTENSION.


2017-05-02  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* export/export.c:  Because it is linked with gdbm-1.8.3 library,
	gdbm_set_errno and all required variables that would have been provided
	by gdbm-1.13 lib must be explicitly added.






diff -aprNU5 gdbm-1.13.orig/export/export.c gdbm-1.13/export/export.c
--- gdbm-1.13.orig/export/export.c	2017-01-02 11:51:44 +0100
+++ gdbm-1.13/export/export.c	2017-05-06 00:29:28 +0200
@@ -24,10 +24,47 @@
 #include <gdbm.h>
 
 /* Pull in gdbm_export() */
 #include "gdbmexp.c"
 
+/* These are from gdbmerrno.c and must be added explicitly
+   because the file is linked with gdbm-1.8.3 and do not
+   provide this gdbm-1.13 specific functionality.  */
+
+int const gdbm_syserr[_GDBM_MAX_ERRNO+1] = {
+  [GDBM_FILE_OPEN_ERROR]        = 1,
+  [GDBM_FILE_WRITE_ERROR]       = 1,
+  [GDBM_FILE_SEEK_ERROR]        = 1,
+  [GDBM_FILE_READ_ERROR]        = 1,
+  [GDBM_FILE_STAT_ERROR]        = 1,
+  [GDBM_BACKUP_FAILED]          = 1
+};
+
+/* The dbm error number is placed in the variable GDBM_ERRNO. */
+gdbm_error gdbm_errno = GDBM_NO_ERROR;
+
+/* Store error code EC in the database structure DBF and in the
+   global variable gdbm_error. 
+*/
+void
+gdbm_set_errno (GDBM_FILE dbf, gdbm_error ec, int fatal)
+{
+  if (dbf)
+    {
+      free (dbf->last_errstr);
+      dbf->last_errstr = NULL;
+      
+      dbf->last_error = ec;
+      if (gdbm_syserr[ec])
+	dbf->last_syserror = errno;
+      else
+	dbf->last_syserror = 0;
+      dbf->need_recovery = fatal;
+    }
+  gdbm_errno = ec;
+}
+
 void
 usage (char *s)
 {
   printf ("Usage: %s database outfile\n", s);
   printf ("   or: %s [-hv]\n", s);
@@ -54,10 +91,12 @@ main(int argc, char *argv[])
 {
   int c;
   GDBM_FILE dbf;
   int flags = 0;
 
+  STRIP_FULL_PATH_AND_EXTENSION(argv[0]);
+
   while ((c = getopt (argc, argv, "hlv")) != -1)
     switch (c)
       {
       case 'h':
 	usage (argv[0]);






2017-05-06  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* src/datconv.c:  Extra semicolon outside DEFNSCAN function removed.






diff -aprNU5 gdbm-1.13.orig/src/datconv.c gdbm-1.13/src/datconv.c
--- gdbm-1.13.orig/src/datconv.c	2017-01-02 12:51:48 +0100
+++ gdbm-1.13/src/datconv.c	2017-05-06 02:34:56 +0200
@@ -100,12 +100,12 @@ name (struct xdatum *xd, char *str)
     return 1;                                   \
   xd_store (xd, &n, sizeof (n));                \
   return 0;                                     \
 }
 
-DEFNSCAN(s_short, short, long, strtol);
-DEFNSCAN(s_ushort, unsigned short, unsigned long, strtoul);
+DEFNSCAN(s_short, short, long, strtol)
+DEFNSCAN(s_ushort, unsigned short, unsigned long, strtoul)
 DEFNSCAN(s_int, int, long, strtol)
 DEFNSCAN(s_uint, unsigned, unsigned long, strtol)
 DEFNSCAN(s_long, long, long, strtoul)
 DEFNSCAN(s_ulong, unsigned long, unsigned long, strtoul)
 DEFNSCAN(s_llong, long long, long long, strtoll)




2017-05-12  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* src/recover.c (backup_name):  If no LFN support is avaliable use
	consume the extension to create the backup name.


2017-05-11  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* src/recover.c (gdbm_recover):  If no LFN support is avaliable use
	"gbXXXXXX" pattern as temporary name.





diff -aprNU5 gdbm-1.13.orig/src/recover.c gdbm-1.13/src/recover.c
--- gdbm-1.13.orig/src/recover.c	2017-01-02 11:51:46 +0000
+++ gdbm-1.13/src/recover.c	2017-05-13 21:42:24 +0000
@@ -50,36 +50,92 @@ backup_name (char const *name)
   size_t suf_pos;
   size_t suf_len;
   
 #define INITIAL_SUFFIX ".~1~"
   
-  len = strlen (name + sizeof (INITIAL_SUFFIX));
+  len = strlen (name) + sizeof (INITIAL_SUFFIX);
   buf = malloc (len);
   if (!buf)
     return NULL;
   strcpy (buf, name);
   suf_pos = strlen (buf) + 2; 
   suf_len = 1;
   strcat (buf, INITIAL_SUFFIX);
 
+  if (!HAS_LFN_SUPPORT(buf))
+    {
+      char *dot = buf + len - sizeof (INITIAL_SUFFIX);
+      char *ext = dot;
+      while (--dot > buf && *dot != '.')
+        ;
+
+      if (dot > buf)
+        {
+          const int ext_len = ext - dot;
+          if (ext_len == 1)
+            suf_pos -= 1;
+          else
+            {
+              ext[sizeof(INITIAL_SUFFIX) - 2] = '\0';
+              dot = ext;
+              if (ext_len == 2)
+                {
+                  ext++;
+                  suf_pos -= 1;
+                }
+              else if (ext_len == 3)
+                {
+                  ext += 2;
+                  suf_pos -= 2;
+                }
+              else if (ext_len == 4)
+                {
+                  dot = ext - 1;
+                  ext += 2;
+                  suf_pos -= 3;
+                }
+            }
+          while ((*dot++ = *ext++))
+            ;
+        }
+    }
+
   while (access (buf, F_OK) == 0)
     {
       size_t i = suf_len;
       while (buf[suf_pos + i - 1] == '9')
 	{
 	  buf[suf_pos + i - 1] = '0';
 	  i--;
 	  if (i == 0)
 	    {
-	      char *p = realloc (buf, ++len);
-	      if (!p)
-		{
-		  SAVE_ERRNO (free (buf));
-		  return NULL;
-		}
-	      memmove (p + suf_pos + 1, p + suf_pos, suf_len + 2);
-	      buf = p;
+              if (!HAS_LFN_SUPPORT(buf))
+                {
+                  suf_pos--;
+                  if (buf[suf_pos] == '.')
+		    {
+                      SAVE_ERRNO (free (buf));
+                      return NULL;
+		    }
+                  else if (buf[suf_pos] == '~' && buf[suf_pos + 2] == '~')
+		    {
+                      suf_pos += 2;
+                      suf_len = 0;
+		    }
+                  buf[suf_pos] = '0';
+                }
+              else
+                {
+	          char *p = realloc (buf, ++len);
+	          if (!p)
+		    {
+		      SAVE_ERRNO (free (buf));
+		      return NULL;
+		    }
+	          memmove (p + suf_pos + 1, p + suf_pos, suf_len + 2);
+	          buf = p;
+                }
 	      suf_len++;
 	      i++;
 	    }
 	}
       ++buf[suf_pos + i - 1];
@@ -368,10 +424,18 @@ gdbm_recover (GDBM_FILE dbf, gdbm_recove
 	  GDBM_SET_ERRNO (NULL, GDBM_MALLOC_ERROR, FALSE);
 	  return -1;
 	}
       strcat (strcpy (new_name, dbf->name), TMPSUF);
   
+      if (!HAS_LFN_SUPPORT(new_name))
+        {
+          new_name[0] = 'g';
+          new_name[1] = 'b';
+          new_name[2] = '\0';
+          strcat(new_name + 2, TMPSUF + 1);
+        }
+
       fd = mkstemp (new_name);
       if (fd == -1)
 	{
 	  GDBM_SET_ERRNO (NULL, GDBM_FILE_OPEN_ERROR, FALSE);
 	  free (new_name);




2017-05-26  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* src/recover.c (_gdbm_finish_transfer) [O_BINARY]:  Close both old
	and new database files before renaming them.  Call backup_and_rename
	to create a backup file according to DOS rules.
	[O_BINARY]:  New function backup_and_rename that creates a backup from
	the database file closing it before renaming it and reopening it later.






diff -aprNU5 gdbm-1.13.orig/src/recover.c gdbm-1.13/src/recover.c
--- gdbm-1.13.orig/src/recover.c	2017-05-26 20:55:26 +0000
+++ gdbm-1.13/src/recover.c	2017-05-28 01:41:10 +0000
@@ -40,10 +40,59 @@ gdbm_copy_meta (GDBM_FILE dst, GDBM_FILE
       return -1;
     }
   return 0;
 }
 
+#if O_BINARY
+static int
+backup_and_rename (GDBM_FILE *orig_dbf, char const *backup_name)
+{
+  GDBM_FILE dbf = *orig_dbf;
+  char *dbf_name = malloc (strlen (dbf->name + 1));
+  int dbf_block_size = dbf->header->block_size;
+  int dbf_flags = GDBM_WRITER;
+  void (*dbf_fatal) ();
+  int status;
+  struct stat fileinfo;
+
+  if (!dbf_name)
+    {
+      GDBM_SET_ERRNO (NULL, GDBM_MALLOC_ERROR, FALSE);
+      return -1;
+    }
+  strcpy (dbf_name, dbf->name);
+
+  if (!(dbf->file_locking)) dbf_flags |= GDBM_NOLOCK;
+  if (!(dbf->fast_write))   dbf_flags |= GDBM_SYNC;
+  dbf_fatal = dbf->fatal_err;
+
+  /* Get the mode for the old file */
+  if (fstat (dbf->desc, &fileinfo))
+    {
+      GDBM_SET_ERRNO (NULL, GDBM_FILE_STAT_ERROR, FALSE);
+      return -1;
+    }
+
+  gdbm_close (dbf);
+
+  status = link (dbf_name, backup_name);
+
+  /* Reorganized database will be opened with old file name. */
+  dbf = gdbm_open (dbf_name, dbf_block_size, dbf_flags,
+                   fileinfo.st_mode, dbf_fatal);
+  free (dbf_name);
+  if (dbf == NULL)
+    /* Database file cannot be reopened.
+       Note that gdbm_errno != GDBM_REORGANIZE_FAILED now,
+       and hence the `dbf' is corrupt. */
+    status = -1;
+  **orig_dbf = *dbf;
+
+  return status;  /* If status == 0 then renaming *and* reopening worked. */
+}
+#endif
+
 static char *
 backup_name (char const *name)
 {
   char *buf;
   size_t len;
@@ -145,12 +194,10 @@ backup_name (char const *name)
 
 static int
 _gdbm_finish_transfer (GDBM_FILE dbf, GDBM_FILE new_dbf,
 		       gdbm_recovery *rcvr, int flags)
 {
-  int i;
-  
   /* Write everything. */
   if (_gdbm_end_update (new_dbf))
     {
       gdbm_close (new_dbf);
       return -1;
@@ -174,21 +221,92 @@ _gdbm_finish_transfer (GDBM_FILE dbf, GD
 	{
 	  SAVE_ERRNO (gdbm_close (new_dbf));
 	  GDBM_SET_ERRNO (NULL, GDBM_BACKUP_FAILED, FALSE);
 	  return -1;
 	}
+#if O_BINARY
+      if (backup_and_rename (&dbf, bkname) != 0)
+#else
       if (rename (dbf->name, bkname) != 0)
+#endif
 	{
 	  SAVE_ERRNO (gdbm_close (new_dbf); free (bkname));
 	  GDBM_SET_ERRNO (NULL, GDBM_BACKUP_FAILED, FALSE);
 	  return -1;
 	}
       rcvr->backup_name = bkname;
     }
   
   /* Move the new file to old name. */
 
+#if O_BINARY
+
+  /* DOS cannot rename an open file.
+     Both source and destination must be closed. */
+  {
+     char *dbf_name = malloc (strlen (dbf->name + 1));
+     char *new_name = malloc (strlen (new_dbf->name + 1));
+     int dbf_block_size = dbf->header->block_size;
+     int dbf_flags = GDBM_WRITER;
+     void (*dbf_fatal) ();
+     int status;
+     struct stat fileinfo;
+
+     if (!new_name)
+       {
+         GDBM_SET_ERRNO (NULL, GDBM_MALLOC_ERROR, FALSE);
+         return -1;
+       }
+     strcpy (new_name, new_dbf->name);
+
+     if (!dbf_name)
+       {
+         GDBM_SET_ERRNO (NULL, GDBM_MALLOC_ERROR, FALSE);
+         free (new_name);
+         return -1;
+       }
+     strcpy (dbf_name, dbf->name);
+
+     if (!(dbf->file_locking)) dbf_flags |= GDBM_NOLOCK;
+     if (!(dbf->fast_write))   dbf_flags |= GDBM_SYNC;
+     dbf_fatal = dbf->fatal_err;
+
+     /* Get the mode for the old file */
+     if (fstat (dbf->desc, &fileinfo))
+       {
+         GDBM_SET_ERRNO (NULL, GDBM_FILE_STAT_ERROR, FALSE);
+         return -1;
+       }
+
+     gdbm_close (new_dbf);
+
+     gdbm_close (dbf);
+
+     status = rename (new_name, dbf_name);
+
+     /* Reorganized database will be opened with old file name. */
+     new_dbf = gdbm_open (dbf_name, dbf_block_size, dbf_flags,
+                          fileinfo.st_mode, dbf_fatal);
+     free (dbf_name);
+     if (new_dbf == NULL)
+       /* Database file cannot be reopened.
+          Note that gdbm_errno != GDBM_REORGANIZE_FAILED now,
+          and hence the `dbf' is corrupt. */
+       status = -1;
+     else
+       {
+          /* if errno == GDBM_REORGANIZE_FAILED,
+             the caller still has a valid `dbf'. */
+          if (status != 0) GDBM_SET_ERRNO (NULL, GDBM_REORGANIZE_FAILED, FALSE);
+          *dbf = *new_dbf;
+       }
+
+     return status;  /* If status == 0 then renaming *and* reopening worked. */
+  }
+
+#else  /* not O_BINARY */
+
   if (rename (new_dbf->name, dbf->name) != 0)
     {
       GDBM_SET_ERRNO (NULL, GDBM_REORGANIZE_FAILED, FALSE);
       gdbm_close (new_dbf);
       return -1;
@@ -201,10 +319,12 @@ _gdbm_finish_transfer (GDBM_FILE dbf, GD
   free (dbf->header);
   free (dbf->dir);
 
   if (dbf->bucket_cache != NULL)
     {
+      int i;
+
       for (i = 0; i < dbf->cache_size; i++)
 	 {
 	   free (dbf->bucket_cache[i].ca_bucket);
 	   free (dbf->bucket_cache[i].ca_data.dptr);
 	 }
@@ -236,10 +356,12 @@ _gdbm_finish_transfer (GDBM_FILE dbf, GD
    __fsync (dbf);
 
    /* Force the right stuff for a correct bucket cache. */
    dbf->cache_entry    = &dbf->bucket_cache[0];
    return _gdbm_get_bucket (dbf, 0);
+
+#endif /* not O_BINARY */
  }
 
 int
 _gdbm_next_bucket_dir (GDBM_FILE dbf, int bucket_dir)
 {




2017-07-24  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* src/recover.c (backup_and_rename):  Return address of dbf.
	(_gdbm_finish_transfer):  Duplicate dbf before using it.  Pass
	duplicated dbf as argument to backup_and_rename.  Use duplicated
	dbf to close and reopen data base file.

	* src/systems.h [O_BINARY, __DJGPP__]:  New macro DUPLICATE_DBF.
	Allocates a new GDBM_FILE and copies the original one.  No-op for all
	other compiler systems.





diff -aprNU5 gdbm-1.13.orig/src/recover.c gdbm-1.13/src/recover.c
--- gdbm-1.13.orig/src/recover.c	2017-07-24 23:49:58 +0000
+++ gdbm-1.13/src/recover.c	2017-07-24 23:25:50 +0000
@@ -83,11 +83,11 @@ backup_and_rename (GDBM_FILE *orig_dbf,
   if (dbf == NULL)
     /* Database file cannot be reopened.
        Note that gdbm_errno != GDBM_REORGANIZE_FAILED now,
        and hence the `dbf' is corrupt. */
     status = -1;
-  **orig_dbf = *dbf;
+  *orig_dbf = dbf;
 
   return status;  /* If status == 0 then renaming *and* reopening worked. */
 }
 #endif
 
@@ -194,10 +194,19 @@ backup_name (char const *name)
 
 static int
 _gdbm_finish_transfer (GDBM_FILE dbf, GDBM_FILE new_dbf,
 		       gdbm_recovery *rcvr, int flags)
 {
+#if O_BINARY
+  GDBM_FILE work_dbf = DUPLICATE_DBF(dbf);
+  if (!work_dbf)
+    {
+      GDBM_SET_ERRNO (NULL, GDBM_MALLOC_ERROR, FALSE);
+      return -1;
+    }
+#endif
+
   /* Write everything. */
   if (_gdbm_end_update (new_dbf))
     {
       gdbm_close (new_dbf);
       return -1;
@@ -222,11 +231,11 @@ _gdbm_finish_transfer (GDBM_FILE dbf, GD
 	  SAVE_ERRNO (gdbm_close (new_dbf));
 	  GDBM_SET_ERRNO (NULL, GDBM_BACKUP_FAILED, FALSE);
 	  return -1;
 	}
 #if O_BINARY
-      if (backup_and_rename (&dbf, bkname) != 0)
+      if (backup_and_rename (&work_dbf, bkname) != 0)
 #else
       if (rename (dbf->name, bkname) != 0)
 #endif
 	{
 	  SAVE_ERRNO (gdbm_close (new_dbf); free (bkname));
@@ -277,29 +286,29 @@ _gdbm_finish_transfer (GDBM_FILE dbf, GD
          return -1;
        }
 
      gdbm_close (new_dbf);
 
-     gdbm_close (dbf);
+     gdbm_close (work_dbf);
 
      status = rename (new_name, dbf_name);
 
      /* Reorganized database will be opened with old file name. */
-     new_dbf = gdbm_open (dbf_name, dbf_block_size, dbf_flags,
-                          fileinfo.st_mode, dbf_fatal);
+     work_dbf = gdbm_open (dbf_name, dbf_block_size, dbf_flags,
+                           fileinfo.st_mode, dbf_fatal);
      free (dbf_name);
-     if (new_dbf == NULL)
+     if (work_dbf == NULL)
        /* Database file cannot be reopened.
           Note that gdbm_errno != GDBM_REORGANIZE_FAILED now,
           and hence the `dbf' is corrupt. */
        status = -1;
      else
        {
           /* if errno == GDBM_REORGANIZE_FAILED,
              the caller still has a valid `dbf'. */
           if (status != 0) GDBM_SET_ERRNO (NULL, GDBM_REORGANIZE_FAILED, FALSE);
-          *dbf = *new_dbf;
+          *dbf = *work_dbf;
        }
 
      return status;  /* If status == 0 then renaming *and* reopening worked. */
   }
 
diff -aprNU5 gdbm-1.13.orig/src/systems.h gdbm-1.13/src/systems.h
--- gdbm-1.13.orig/src/systems.h	2017-07-24 23:49:58 +0000
+++ gdbm-1.13/src/systems.h	2017-07-24 23:38:40 +0000
@@ -233,15 +233,29 @@ _finished:
         char *gdbmtoolrc = HAS_LFN_SUPPORT(".gdbmtoolrc") && FILE_EXISTS(".gdbmtoolrc") ? ".gdbmtoolrc" : "_gdbmtoolrc";  \
         gdbmtoolrc;                                                                                                       \
      })                                                                                                                   \
    )
 
+#  define DUPLICATE_DBF(ORIGINAL)                                                                                         \
+   (__gnuc_extension__                                                                                                    \
+     ({                                                                                                                   \
+        GDBM_FILE duplicate = (GDBM_FILE)malloc(sizeof(*(ORIGINAL)));                                                     \
+        if (!duplicate)                                                                                                   \
+          GDBM_SET_ERRNO(NULL, GDBM_MALLOC_ERROR, FALSE);                                                                 \
+        else                                                                                                              \
+          *duplicate = *(ORIGINAL);                                                                                       \
+                                                                                                                          \
+        (duplicate);                                                                                                      \
+     })                                                                                                                   \
+   )
+
 # else /* !__DJGPP__  */
 #  define STRIP_FULL_PATH_AND_EXTENSION(file_name)  (strrchr ((file_name), '/'))
 #  define CANONICALIZE_PATH(path)                   (path)
 #  define HAS_LFN_SUPPORT(name)                     (0)
 #  define _GDBMTOOLRC                               "_gdbmtoolrc"
+#  define DUPLICATE_DBF(ORIGINAL)                   NULL
 # endif /* !__DJGPP__  */
 #else /* not O_BINARY */
 # define O_BINARY
 # define IS_DIR_SEPARATOR(c)                        ((c) == '/')
 # define STRIP_FULL_PATH_AND_EXTENSION(file_name)   (strrchr ((file_name), '/'))




2017-07-26  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* src/gdbmsetopt.c (gdbm_setopt):  In case that HAVE_MMAP is undefine
	exclude all optflag between GDBM_SETMAXMAPSIZE and GDBM_GETMMAP.





diff -aprNU5 gdbm-1.13.orig/src/gdbmsetopt.c gdbm-1.13/src/gdbmsetopt.c
--- gdbm-1.13.orig/src/gdbmsetopt.c	2017-01-02 11:51:48 +0000
+++ gdbm-1.13/src/gdbmsetopt.c	2017-07-26 21:25:44 +0000
@@ -316,11 +316,11 @@ static setopt_handler setopt_handler_tab
   [GDBM_GETSYNCMODE]  = setopt_gdbm_getsyncmode,
   [GDBM_SETCENTFREE]  = setopt_gdbm_setcentfree,
   [GDBM_GETCENTFREE]  = setopt_gdbm_getcentfree,
   [GDBM_SETCOALESCEBLKS] = setopt_gdbm_setcoalesceblks,
   [GDBM_GETCOALESCEBLKS] = setopt_gdbm_getcoalesceblks,
-#if HAVE_MMAP  
+#if HAVE_MMAP
   [GDBM_SETMMAP]         = setopt_gdbm_setmmap,
   [GDBM_GETMMAP]         = setopt_gdbm_getmmap,
   [GDBM_SETMAXMAPSIZE]   = setopt_gdbm_setmaxmapsize,
   [GDBM_GETMAXMAPSIZE]   = setopt_gdbm_getmaxmapsize,
   [GDBM_GETFLAGS]        = setopt_gdbm_getflags,
@@ -334,10 +334,13 @@ gdbm_setopt (GDBM_FILE dbf, int optflag,
 {
   /* Return immediately if the database needs recovery */	
   GDBM_ASSERT_CONSISTENCY (dbf, -1);
 
   if (optflag >= 0
+#ifndef HAVE_MMAP
+  && (optflag > GDBM_GETMMAP || optflag < GDBM_SETMAXMAPSIZE)
+#endif
   && optflag < sizeof (setopt_handler_tab) / sizeof (setopt_handler_tab[0]))
     return setopt_handler_tab[optflag] (dbf, optval, optlen);
   
   GDBM_SET_ERRNO (dbf, GDBM_OPT_ILLEGAL, FALSE);
   return -1;
