]> git.sur5r.net Git - openldap/commitdiff
Factor filename handling out to mdb_fname_*()
authorHallvard Furuseth <hallvard@openldap.org>
Sat, 17 Sep 2016 19:31:04 +0000 (21:31 +0200)
committerHallvard Furuseth <hallvard@openldap.org>
Sun, 25 Sep 2016 13:40:08 +0000 (15:40 +0200)
No change in functionality, except needs less mallocing.

libraries/liblmdb/mdb.c

index b0da3856f9fdaa5415c68bbb0b2463fee273785c..763972bdf8db32640c9a8e2cb111f69e8d40b0f9 100644 (file)
@@ -41,6 +41,7 @@
 #ifdef _WIN32
 #include <malloc.h>
 #include <windows.h>
+#include <wchar.h>                             /* get wcscpy() */
 
 /* We use native NT APIs to setup the memory map, so that we can
  * let the DB file grow incrementally instead of always preallocating
@@ -1554,7 +1555,8 @@ static SECURITY_DESCRIPTOR mdb_null_sd;
 static SECURITY_ATTRIBUTES mdb_all_sa;
 static int mdb_sec_inited;
 
-static int utf8_to_utf16(const char *src, int srcsize, wchar_t **dst, int *dstsize);
+struct MDB_name;
+static int utf8_to_utf16(const char *src, struct MDB_name *dst, int xtra);
 #endif
 
 /** Return the library version info. */
@@ -4386,6 +4388,79 @@ mdb_fsize(HANDLE fd, mdb_size_t *size)
        return MDB_SUCCESS;
 }
 
+
+#ifdef _WIN32
+typedef wchar_t        mdb_nchar_t;
+# define MDB_NAME(str) L##str
+# define mdb_name_cpy  wcscpy
+#else
+/** Character type for file names: char on Unix, wchar_t on Windows */
+typedef char   mdb_nchar_t;
+# define MDB_NAME(str) str             /**< #mdb_nchar_t[] string literal */
+# define mdb_name_cpy  strcpy  /**< Copy name (#mdb_nchar_t string) */
+#endif
+
+/** Filename - string of #mdb_nchar_t[] */
+typedef struct MDB_name {
+       int mn_len;                                     /**< Length  */
+       int mn_alloced;                         /**< True if #mn_val was malloced */
+       mdb_nchar_t     *mn_val;                /**< Contents */
+} MDB_name;
+
+/** Filename suffixes [datafile,lockfile][without,with MDB_NOSUBDIR] */
+static const mdb_nchar_t *const mdb_suffixes[2][2] = {
+       { MDB_NAME("/data.mdb"), MDB_NAME("")      },
+       { MDB_NAME("/lock.mdb"), MDB_NAME("-lock") }
+};
+
+#define MDB_SUFFLEN 9  /**< Max string length in #mdb_suffixes[] */
+
+/** Set up filename + scratch area for filename suffix, for opening files.
+ * It should be freed with #mdb_fname_destroy().
+ * On Windows, paths are converted from char *UTF-8 to wchar_t *UTF-16.
+ *
+ * @param[in] path Pathname for #mdb_env_open().
+ * @param[in] envflags Whether a subdir and/or lockfile will be used.
+ * @param[out] fname Resulting filename, with room for a suffix if necessary.
+ */
+static int ESECT
+mdb_fname_init(const char *path, unsigned envflags, MDB_name *fname)
+{
+       int no_suffix = F_ISSET(envflags, MDB_NOSUBDIR|MDB_NOLOCK);
+       fname->mn_alloced = 0;
+#ifdef _WIN32
+       return utf8_to_utf16(path, fname, no_suffix ? 0 : MDB_SUFFLEN);
+#else
+       fname->mn_len = strlen(path);
+       if (no_suffix)
+               fname->mn_val = (char *) path;
+       else if ((fname->mn_val = malloc(fname->mn_len + MDB_SUFFLEN+1)) != NULL) {
+               fname->mn_alloced = 1;
+               strcpy(fname->mn_val, path);
+       }
+       else
+               return ENOMEM;
+       return MDB_SUCCESS;
+#endif
+}
+
+/** Destroy \b fname from #mdb_fname_init() */
+#define mdb_fname_destroy(fname) \
+       do { if ((fname).mn_alloced) free((fname).mn_val); } while (0)
+
+enum mdb_fopen_type {
+       MDB_O_DATA, MDB_O_LOCKS
+};
+
+static void ESECT
+mdb_fname_suffix_set(MDB_env *env, MDB_name *fname, enum mdb_fopen_type which)
+{
+       if (fname->mn_alloced)          /* modifiable copy */
+               mdb_name_cpy(fname->mn_val + fname->mn_len,
+                       mdb_suffixes[which==MDB_O_LOCKS][F_ISSET(env->me_flags, MDB_NOSUBDIR)]);
+}
+
+
 #ifdef BROKEN_FDATASYNC
 #include <sys/utsname.h>
 #include <sys/vfs.h>
@@ -4803,13 +4878,13 @@ mdb_hash_enc(MDB_val *val, char *encbuf)
 
 /** Open and/or initialize the lock region for the environment.
  * @param[in] env The LMDB environment.
- * @param[in] lpath The pathname of the file used for the lock region.
+ * @param[in] fname Filename + scratch area, from #mdb_fname_init().
  * @param[in] mode The Unix permissions for the file, if we create it.
  * @param[in,out] excl In -1, out lock type: -1 none, 0 shared, 1 exclusive
  * @return 0 on success, non-zero on failure.
  */
 static int ESECT
-mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
+mdb_env_setup_locks(MDB_env *env, MDB_name *fname, int mode, int *excl)
 {
 #ifdef _WIN32
 #      define MDB_ERRCODE_ROFS ERROR_WRITE_PROTECT
@@ -4829,17 +4904,13 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
        int rc;
        off_t size, rsize;
 
+       mdb_fname_suffix_set(env, fname, MDB_O_LOCKS);
 #ifdef _WIN32
-       wchar_t *wlpath;
-       rc = utf8_to_utf16(lpath, -1, &wlpath, NULL);
-       if (rc)
-               return rc;
-       env->me_lfd = CreateFileW(wlpath, GENERIC_READ|GENERIC_WRITE,
+       env->me_lfd = CreateFileW(fname->mn_val, GENERIC_READ|GENERIC_WRITE,
                FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
                FILE_ATTRIBUTE_NORMAL, NULL);
-       free(wlpath);
 #else
-       env->me_lfd = open(lpath, O_RDWR|O_CREAT|MDB_CLOEXEC, mode);
+       env->me_lfd = open(fname->mn_val, O_RDWR|O_CREAT|MDB_CLOEXEC, mode);
 #endif
        if (env->me_lfd == INVALID_HANDLE_VALUE) {
                rc = ErrCode();
@@ -4979,7 +5050,7 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
                if (env->me_wmutex == SEM_FAILED) goto fail_errno;
 #elif defined(MDB_USE_SYSV_SEM)
                unsigned short vals[2] = {1, 1};
-               key_t key = ftok(lpath, 'M');
+               key_t key = ftok(fname->mn_val, 'M'); /* fname is lockfile path now */
                if (key == -1)
                        goto fail_errno;
                semid = semget(key, 2, (mode & 0777) | IPC_CREAT);
@@ -5083,12 +5154,6 @@ fail:
        return rc;
 }
 
-       /** The name of the lock file in the DB environment */
-#define LOCKNAME       "/lock.mdb"
-       /** The name of the data file in the DB environment */
-#define DATANAME       "/data.mdb"
-       /** The suffix of the lock file when no subdir is used */
-#define LOCKSUFF       "-lock"
        /** Only a subset of the @ref mdb_env flags can be changed
         *      at runtime. Changing other flags requires closing the
         *      environment and re-opening it with the new flags.
@@ -5105,10 +5170,7 @@ int ESECT
 mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode)
 {
        int             oflags, rc, len, excl = -1;
-       char *lpath, *dpath;
-#ifdef _WIN32
-       wchar_t *wpath;
-#endif
+       MDB_name fname;
 
        if (env->me_fd!=INVALID_HANDLE_VALUE || (flags & ~(CHANGEABLE|CHANGELESS)))
                return EINVAL;
@@ -5123,28 +5185,12 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
                return EINVAL;
        }
 #endif
+       flags |= env->me_flags;
 
-       len = strlen(path);
-       if (flags & MDB_NOSUBDIR) {
-               rc = len + sizeof(LOCKSUFF) + len + 1;
-       } else {
-               rc = len + sizeof(LOCKNAME) + len + sizeof(DATANAME);
-       }
-       lpath = malloc(rc);
-       if (!lpath)
-               return ENOMEM;
-       if (flags & MDB_NOSUBDIR) {
-               dpath = lpath + len + sizeof(LOCKSUFF);
-               sprintf(lpath, "%s" LOCKSUFF, path);
-               strcpy(dpath, path);
-       } else {
-               dpath = lpath + len + sizeof(LOCKNAME);
-               sprintf(lpath, "%s" LOCKNAME, path);
-               sprintf(dpath, "%s" DATANAME, path);
-       }
+       rc = mdb_fname_init(path, flags, &fname);
+       if (rc)
+               return rc;
 
-       rc = MDB_SUCCESS;
-       flags |= env->me_flags;
        if (flags & MDB_RDONLY) {
                /* silently ignore WRITEMAP when we're only getting read access */
                flags &= ~MDB_WRITEMAP;
@@ -5180,11 +5226,12 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
 
        /* For RDONLY, get lockfile after we know datafile exists */
        if (!(flags & (MDB_RDONLY|MDB_NOLOCK))) {
-               rc = mdb_env_setup_locks(env, lpath, mode, &excl);
+               rc = mdb_env_setup_locks(env, &fname, mode, &excl);
                if (rc)
                        goto leave;
        }
 
+       mdb_fname_suffix_set(env, &fname, MDB_O_DATA);
 #ifdef _WIN32
        if (F_ISSET(flags, MDB_RDONLY)) {
                oflags = GENERIC_READ;
@@ -5194,19 +5241,15 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
                len = OPEN_ALWAYS;
        }
        mode = FILE_ATTRIBUTE_NORMAL;
-       rc = utf8_to_utf16(dpath, -1, &wpath, NULL);
-       if (rc)
-               goto leave;
-       env->me_fd = CreateFileW(wpath, oflags, FILE_SHARE_READ|FILE_SHARE_WRITE,
+       env->me_fd = CreateFileW(fname.mn_val, oflags, FILE_SHARE_READ|FILE_SHARE_WRITE,
                NULL, len, mode, NULL);
-       free(wpath);
 #else
        if (F_ISSET(flags, MDB_RDONLY))
                oflags = O_RDONLY;
        else
                oflags = O_RDWR | O_CREAT;
 
-       env->me_fd = open(dpath, oflags, mode);
+       env->me_fd = open(fname.mn_val, oflags, mode);
 #endif
        if (env->me_fd == INVALID_HANDLE_VALUE) {
                rc = ErrCode();
@@ -5214,7 +5257,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
        }
 
        if ((flags & (MDB_RDONLY|MDB_NOLOCK)) == MDB_RDONLY) {
-               rc = mdb_env_setup_locks(env, lpath, mode, &excl);
+               rc = mdb_env_setup_locks(env, &fname, mode, &excl);
                if (rc)
                        goto leave;
        }
@@ -5226,18 +5269,15 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
                        /* Synchronous fd for meta writes. Needed even with
                         * MDB_NOSYNC/MDB_NOMETASYNC, in case these get reset.
                         */
+                       mdb_fname_suffix_set(env, &fname, MDB_O_DATA);
 #ifdef _WIN32
                        len = OPEN_EXISTING;
-                       rc = utf8_to_utf16(dpath, -1, &wpath, NULL);
-                       if (rc)
-                               goto leave;
-                       env->me_mfd = CreateFileW(wpath, oflags,
+                       env->me_mfd = CreateFileW(fname.mn_val, oflags,
                                FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, len,
                                mode | FILE_FLAG_WRITE_THROUGH, NULL);
-                       free(wpath);
 #else
                        oflags &= ~O_CREAT;
-                       env->me_mfd = open(dpath, oflags | MDB_DSYNC, mode);
+                       env->me_mfd = open(fname.mn_val, oflags | MDB_DSYNC, mode);
 #endif
                        if (env->me_mfd == INVALID_HANDLE_VALUE) {
                                rc = ErrCode();
@@ -5285,7 +5325,7 @@ leave:
        if (rc) {
                mdb_env_close0(env, excl);
        }
-       free(lpath);
+       mdb_fname_destroy(fname);
        return rc;
 }
 
@@ -10131,37 +10171,24 @@ mdb_env_copyfd(MDB_env *env, HANDLE fd)
 int ESECT
 mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags)
 {
-       int rc, len;
-       char *lpath;
+       int rc;
+       MDB_name fname;
        HANDLE newfd = INVALID_HANDLE_VALUE;
-#ifdef _WIN32
-       wchar_t *wpath;
-#endif
 
-       if (env->me_flags & MDB_NOSUBDIR) {
-               lpath = (char *)path;
-       } else {
-               len = strlen(path);
-               len += sizeof(DATANAME);
-               lpath = malloc(len);
-               if (!lpath)
-                       return ENOMEM;
-               sprintf(lpath, "%s" DATANAME, path);
-       }
+       rc = mdb_fname_init(path, env->me_flags | MDB_NOLOCK, &fname);
+       if (rc)
+               return rc;
+       mdb_fname_suffix_set(env, &fname, MDB_O_DATA);
 
        /* The destination path must exist, but the destination file must not.
         * We don't want the OS to cache the writes, since the source data is
         * already in the OS cache.
         */
 #ifdef _WIN32
-       rc = utf8_to_utf16(lpath, -1, &wpath, NULL);
-       if (rc)
-               goto leave;
-       newfd = CreateFileW(wpath, GENERIC_WRITE, 0, NULL, CREATE_NEW,
+       newfd = CreateFileW(fname.mn_val, GENERIC_WRITE, 0, NULL, CREATE_NEW,
                                FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL);
-       free(wpath);
 #else
-       newfd = open(lpath, O_WRONLY|O_CREAT|O_EXCL, 0666);
+       newfd = open(fname.mn_val, O_WRONLY|O_CREAT|O_EXCL, 0666);
 #endif
        if (newfd == INVALID_HANDLE_VALUE) {
                rc = ErrCode();
@@ -10181,8 +10208,7 @@ mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags)
        rc = mdb_env_copyfd2(env, newfd, flags);
 
 leave:
-       if (!(env->me_flags & MDB_NOSUBDIR))
-               free(lpath);
+       mdb_fname_destroy(fname);
        if (newfd != INVALID_HANDLE_VALUE)
                if (close(newfd) < 0 && rc == MDB_SUCCESS)
                        rc = ErrCode();
@@ -10888,27 +10914,28 @@ mdb_mutex_failed(MDB_env *env, mdb_mutexref_t mutex, int rc)
 #endif /* MDB_ROBUST_SUPPORTED */
 
 #if defined(_WIN32)
+/** Convert \b src to new wchar_t[] string with room for \b xtra extra chars */
 static int ESECT
-utf8_to_utf16(const char *src, int srcsize, wchar_t **dst, int *dstsize)
+utf8_to_utf16(const char *src, MDB_name *dst, int xtra)
 {
        int rc, need = 0;
        wchar_t *result = NULL;
        for (;;) {                                      /* malloc result, then fill it in */
-               need = MultiByteToWideChar(CP_UTF8, 0, src, srcsize, result, need);
+               need = MultiByteToWideChar(CP_UTF8, 0, src, -1, result, need);
                if (!need) {
                        rc = ErrCode();
                        free(result);
                        return rc;
                }
                if (!result) {
-                       result = malloc(sizeof(wchar_t) * need);
+                       result = malloc(sizeof(wchar_t) * (need + xtra));
                        if (!result)
                                return ENOMEM;
                        continue;
                }
-               if (dstsize)
-                       *dstsize = need;
-               *dst = result;
+               dst->mn_alloced = 1;
+               dst->mn_len = need - 1;
+               dst->mn_val = result;
                return MDB_SUCCESS;
        }
 }