]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Added a isc_glob() function that wraps glob() calls for POSIX systems include-multiple-files-windows
authorDiego Fronza <diego@isc.org>
Wed, 23 Oct 2019 19:25:06 +0000 (16:25 -0300)
committerDiego Fronza <diego@isc.org>
Thu, 24 Oct 2019 17:12:48 +0000 (14:12 -0300)
and implement a custom glob() function on Windows systems.

configure.ac
lib/isc/Makefile.in
lib/isc/glob.c [new file with mode: 0644]
lib/isc/include/isc/glob.h [new file with mode: 0644]
lib/isc/win32/libisc.def.in
lib/isc/win32/libisc.vcxproj.in
lib/isccfg/parser.c
util/copyrights

index 17b09511b72e5a06bd4224e7a32e157ed13447a8..6b277a80abdacd5ab4d2fe5e62ba78b934e0d2ea 100644 (file)
@@ -2566,6 +2566,8 @@ AC_SUBST(DLZ_DRIVER_MYSQL_INCLUDES)
 AC_SUBST(DLZ_DRIVER_MYSQL_LIBS)
 AC_SUBST_FILE(DLZ_DRIVER_RULES)
 
+AC_CHECK_HEADERS([glob.h])
+
 if test "yes" = "$cross_compiling"; then
        if test -z "$BUILD_CC"; then
                AC_MSG_ERROR([BUILD_CC not set])
index ae7ca482bf4926ad638ad8374b967c38ed69d913..9ca56e5fdc1031c82829d3ba8b651678eb3f006f 100644 (file)
@@ -50,7 +50,7 @@ OBJS =                pk11.@O@ pk11_result.@O@ \
                backtrace.@O@ base32.@O@ base64.@O@ \
                bind9.@O@ buffer.@O@ bufferlist.@O@ \
                commandline.@O@ counter.@O@ crc64.@O@ error.@O@ entropy.@O@ \
-               event.@O@ hash.@O@ ht.@O@ heap.@O@ hex.@O@ hmac.@O@ \
+               event.@O@ glob.@O@ hash.@O@ ht.@O@ heap.@O@ hex.@O@ hmac.@O@ \
                httpd.@O@ iterated_hash.@O@ \
                lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
                md.@O@ mem.@O@ mutexblock.@O@ \
@@ -69,8 +69,8 @@ SRCS =                pk11.c pk11_result.c \
                aes.c app.c assertions.c \
                backtrace.c base32.c base64.c bind9.c \
                buffer.c bufferlist.c commandline.c counter.c crc64.c \
-               entropy.c error.c event.c hash.c ht.c heap.c hex.c hmac.c \
-               httpd.c iterated_hash.c \
+               entropy.c error.c event.c glob.c hash.c ht.c heap.c hex.c \
+               hmac.c httpd.c iterated_hash.c \
                lex.c lfsr.c lib.c log.c \
                md.c mem.c mutexblock.c \
                netaddr.c netscope.c nonce.c openssl_shim.c pool.c \
diff --git a/lib/isc/glob.c b/lib/isc/glob.c
new file mode 100644 (file)
index 0000000..7bf9214
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <isc/errno.h>
+#include <isc/glob.h>
+#include <isc/result.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#if HAVE_GLOB_H
+#include <glob.h>
+#elif defined(_WIN32) || defined(_WIN64)
+#include <stdlib.h>
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#include <isc/list.h>
+#define GLOB_WIN_IMPL 1
+#define GLOB_ERR     0x0004  /* Return on error. */
+#define GLOB_NOSPACE (-1)
+#define GLOB_NOMATCH (-3)
+
+/* custom glob implementation for windows */
+static int
+glob(const char *pattern, int flags, void *unused, glob_t *pglob);
+
+static void
+globfree(glob_t *pglob);
+
+#else
+#error "Required header missing: glob.h"
+#endif
+
+isc_result_t
+isc_glob(const char *pattern, glob_t *pglob) {
+       REQUIRE(pattern != NULL);
+       REQUIRE(*pattern != '\0');
+       REQUIRE(pglob != NULL);
+
+       int rc = glob(pattern, GLOB_ERR, NULL, pglob);
+
+       switch (rc) {
+               case 0:
+                       return (ISC_R_SUCCESS);
+               case GLOB_NOMATCH:
+                       /* if a magic char (*?[]) was in pattern
+                        * and no path matched we report error early,
+                        * otherwise proceed as normal */
+                       return (strpbrk(pattern, "[]*?")) ?
+                                       (ISC_R_FILENOTFOUND) : (ISC_R_SUCCESS);
+
+               case GLOB_NOSPACE:
+                       return (ISC_R_NOMEMORY);
+               default:
+                       return (errno != 0 ? isc_errno_toresult(errno) : ISC_R_IOERROR);
+       }
+
+}
+
+void
+isc_globfree(glob_t *pglob) {
+       REQUIRE(pglob != NULL);
+       globfree(pglob);
+}
+
+#ifdef GLOB_WIN_IMPL
+
+typedef struct file_path file_path_t;
+
+struct file_path {
+       char *path;
+       ISC_LINK(file_path_t) link;
+};
+
+typedef ISC_LIST(file_path_t) file_list_t;
+
+/* map a winapi error to a convenient errno code */
+static int
+map_error(DWORD win_err_code) {
+       switch (win_err_code) {
+       case ERROR_FILE_NOT_FOUND:
+       case ERROR_PATH_NOT_FOUND:
+               return (GLOB_NOMATCH);
+       case ERROR_ACCESS_DENIED:
+               return (EACCES);
+       case ERROR_NOT_ENOUGH_MEMORY:
+               return (GLOB_NOSPACE);
+       default:
+               return (EIO);
+       }
+}
+
+/* add file in directory dir, that matches glob expression
+ * provided in function glob(), to the linked list fl */
+static int
+append_file(isc_mem_t *mctx,
+           file_list_t *fl,
+           const char *dir,
+           const char *file,
+           size_t full_path_len)
+{
+       file_path_t *fp = isc_mem_get(mctx, sizeof(file_path_t));
+       fp->path = isc_mem_get(mctx, full_path_len + 1);
+       _snprintf(fp->path, full_path_len + 1, "%s%s", dir, file);
+
+       ISC_LINK_INIT(fp, link);
+       ISC_LIST_PREPEND(*fl, fp, link);
+}
+
+/* sort files alphabetically case insensitive on windows */
+static int
+path_cmp(const void *path1, const void *path2) {
+       return _stricmp((const char *)path1, (const char *)path2);
+}
+
+static int
+glob(const char *pattern, int flags, void *unused, glob_t *pglob) {
+       char path[MAX_PATH];
+       WIN32_FIND_DATAA find_data;;
+       HANDLE hnd;
+
+       REQUIRE(pattern != NULL);
+       REQUIRE(pglob != NULL);
+
+       UNUSED(flags);
+       UNUSED(unused);
+
+       pglob->mctx = NULL;
+       pglob->gl_pathc = 0;
+       pglob->gl_pathv = NULL;
+
+       hnd = FindFirstFileA(pattern, &find_data);
+       if (hnd == INVALID_HANDLE_VALUE) {
+               return (map_error(GetLastError()));
+       }
+
+       path[MAX_PATH - 1] = 0;
+       strncpy(path, pattern, MAX_PATH);
+       if (path[MAX_PATH - 1] != 0) {
+               errno = ENAMETOOLONG;
+               goto fail;
+       }
+
+       // strip filename from path.
+       size_t dir_len = strlen(path);
+       while (dir_len > 0 && path[dir_len - 1] != '/' && path[dir_len - 1] != '\\') {
+               dir_len--;
+       }
+
+       path[dir_len] = '\0';
+
+       isc_mem_create(&pglob->mctx);
+       pglob->reserved = isc_mem_get(pglob->mctx, sizeof(file_list_t));
+
+       size_t entries = 0;
+
+       do {
+               size_t file_len = strlen(find_data.cFileName);
+               size_t full_path_len = dir_len + file_len;
+
+               if (full_path_len > MAX_PATH) {
+                       errno = ENAMETOOLONG;
+                       goto fail;
+               }
+
+               append_file(pglob->mctx,
+                           (file_list_t *)pglob->reserved,
+                           path,
+                           find_data.cFileName,
+                           full_path_len);
+
+               entries++;
+       } while (FindNextFileA(hnd, &find_data));
+
+       FindClose(hnd);
+
+       pglob->gl_pathv = isc_mem_get(pglob->mctx, (entries + 1) * sizeof(char*));
+       pglob->gl_pathv[entries] = NULL;
+       pglob->gl_pathc = entries;
+
+       file_list_t *fl = (file_list_t *)pglob->reserved;
+
+       size_t e = 0;
+       file_path_t *fp;
+       for (fp = ISC_LIST_HEAD(*fl); fp != NULL; fp = ISC_LIST_NEXT(fp, link)) {
+               pglob->gl_pathv[e++] = fp->path;
+       }
+
+       qsort(pglob->gl_pathv, pglob->gl_pathc, sizeof(char*), path_cmp);
+
+       return (0);
+
+fail:
+       int ec = errno;
+
+       FindClose(hnd);
+
+       if (pglob->mctx) {
+               globfree(pglob);
+       }
+
+       return ec;
+}
+
+void
+globfree(glob_t* pglob) {
+{
+       REQUIRE(pglob != NULL);
+       REQUIRE(pglob->mctx != NULL);
+
+       /* first free memory used by char ** gl_pathv */
+       if (pglob->gl_pathv) {
+               isc_mem_put(pglob->mctx,
+                           pglob->gl_pathv,
+                           (pglob->gl_pathc + 1) * sizeof(char *));
+               pglob->gl_pathv = NULL;
+       }
+
+       file_list_t *fl = (file_list_t *)pglob->reserved;
+       file_path_t *p, *next;
+
+       /* next free each individual file path string + nodes in list */
+       for (p = ISC_LIST_HEAD(*fl); p != NULL; p = next) {
+               next = ISC_LIST_NEXT(p, link);
+               isc_mem_put(pglob->mctx, p->path, strlen(p->path) + 1);
+               isc_mem_put(pglob->mctx, p, sizeof(file_path_t));
+       }
+
+       /* free linked list of files */
+       isc_mem_put(pglob->mctx, pglob->reserved, sizeof(file_list_t));
+       pglob->reserved = NULL;
+       pglob->gl_pathc = 0;
+       pglob->gl_pathv = NULL;
+
+       isc_mem_destroy(&pglob->mctx);
+       pglob->mctx = NULL;
+}
+
+#endif /* GLOB_WIN_IMPL */
diff --git a/lib/isc/include/isc/glob.h b/lib/isc/include/isc/glob.h
new file mode 100644 (file)
index 0000000..314dd5a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_GLOB_H
+#define ISC_GLOB_H
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+#if HAVE_GLOB_H
+#include <glob.h>
+#else
+#include <stddef.h>
+#include <isc/mem.h>
+
+typedef struct {
+    size_t      gl_pathc;
+    char      **gl_pathv;
+    isc_mem_t  *mctx;
+    void       *reserved;
+} glob_t;
+
+#endif
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_glob(const char *pattern, glob_t *pglob);
+
+void
+isc_globfree(glob_t *pglob);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_GLOB_H */
index 96097ff1bcb5ab520ad25584cc4dfa08fe6da94b..01dbf24c874f343e751cda2efacfa10c8884a589 100644 (file)
@@ -228,6 +228,8 @@ isc_fsaccess_add
 isc_fsaccess_changeowner
 isc_fsaccess_remove
 isc_fsaccess_set
+isc_glob
+isc_globfree
 isc_hash_function
 isc_hash_get_initializer
 isc_hash_set_initializer
index 885d83c64e88bee14781c0afa4f8a50f07c328cd..070cbf0f5257be3e628f027e3f258b115ba803f1 100644 (file)
@@ -307,6 +307,7 @@ copy InstallFiles ..\Build\Release\
     <ClInclude Include="..\include\isc\file.h" />
     <ClInclude Include="..\include\isc\formatcheck.h" />
     <ClInclude Include="..\include\isc\fsaccess.h" />
+    <ClInclude Include="..\include\isc\glob.h" />
     <ClInclude Include="..\include\isc\hash.h" />
     <ClInclude Include="..\include\isc\heap.h" />
     <ClInclude Include="..\include\isc\hex.h" />
@@ -417,6 +418,7 @@ copy InstallFiles ..\Build\Release\
     <ClCompile Include="..\entropy.c" />
     <ClCompile Include="..\error.c" />
     <ClCompile Include="..\event.c" />
+    <ClCompile Include="..\glob.c" />
     <ClCompile Include="..\hash.c" />
     <ClCompile Include="..\heap.c" />
     <ClCompile Include="..\hex.c" />
index 586689a673e59583ef0da722d975a2fdfa94d3f6..869f46b8024e719e93e2fd16b8699e362ff0cb3f 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <glob.h>
 
 #include <isc/buffer.h>
 #include <isc/dir.h>
 #include <isc/errno.h>
 #include <isc/formatcheck.h>
+#include <isc/glob.h>
 #include <isc/lex.h>
 #include <isc/log.h>
 #include <isc/mem.h>
@@ -104,9 +104,6 @@ static void
 parser_complain(cfg_parser_t *pctx, bool is_warning,
                unsigned int flags, const char *format, va_list args);
 
-static isc_result_t
-glob_include(const char * restrict pattern, glob_t * restrict pglob);
-
 #if defined(HAVE_GEOIP2)
 static isc_result_t
 parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
@@ -1971,13 +1968,15 @@ cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
                        /* Allow include to specify a pattern that follows
                         * the same rules as the shell e.g "/path/zone*.conf" */
                        glob_t glob_obj;
-                       CHECK(glob_include(includename->value.string.base, &glob_obj));
+                       CHECK(isc_glob(includename->value.string.base, &glob_obj));
                        cfg_obj_destroy(pctx, &includename);
 
                        for (size_t i = 0; i < glob_obj.gl_pathc; ++i) {
                                CHECK(parser_openfile(pctx, glob_obj.gl_pathv[i]));
                        }
 
+                       isc_globfree(&glob_obj);
+
                        goto redo;
                }
 
@@ -3650,27 +3649,3 @@ cfg_pluginlist_foreach(const cfg_obj_t *config, const cfg_obj_t *list,
 
        return (result);
 }
-
-
-static isc_result_t
-glob_include(const char * restrict pattern, glob_t * restrict pglob)
-{
-       int rc = glob(pattern, GLOB_ERR, NULL, pglob);
-
-       switch (rc) {
-               case 0:
-                       return (ISC_R_SUCCESS);
-               case GLOB_NOMATCH:
-                       /* if a magic char (*?[]) was in pattern
-                        * and no path matched we report error early,
-                        * otherwise proceed as normal */
-                       return (strpbrk(pattern, "[]*?")) ?
-                                       (ISC_R_FILENOTFOUND) : (ISC_R_SUCCESS);
-
-               case GLOB_NOSPACE:
-                       return (ISC_R_NOMEMORY);
-               default:
-                       return (errno != 0 ? isc_errno_toresult(errno) : ISC_R_IOERROR);
-       }
-
-}
index 2a37ee3792de52829e1e3258ab8cc3108372050e..e480827769aacc0c3e678440876fbca3c2970236 100644 (file)
 ./lib/isc/error.c                              C       1998,1999,2000,2001,2004,2005,2007,2015,2016,2018,2019
 ./lib/isc/event.c                              C       1998,1999,2000,2001,2004,2005,2007,2014,2016,2017,2018,2019
 ./lib/isc/fsaccess.c                           C       2000,2001,2004,2005,2007,2016,2017,2018,2019
+./lib/isc/glob.c                               C       2019
 ./lib/isc/hash.c                               C       2003,2004,2005,2006,2007,2009,2013,2014,2015,2016,2017,2018,2019
 ./lib/isc/heap.c                               C       1997,1998,1999,2000,2001,2004,2005,2006,2007,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019
 ./lib/isc/hex.c                                        C       2000,2001,2002,2003,2004,2005,2007,2008,2013,2014,2015,2016,2018,2019
 ./lib/isc/include/isc/formatcheck.h            C       2000,2001,2004,2005,2006,2007,2016,2018,2019
 ./lib/isc/include/isc/fsaccess.h               C       2000,2001,2004,2005,2006,2007,2009,2016,2018,2019
 ./lib/isc/include/isc/fuzz.h                   C       2017,2018,2019
+./lib/isc/include/isc/glob.h                   C       2019
 ./lib/isc/include/isc/hash.h                   C       2003,2004,2005,2006,2007,2009,2013,2014,2015,2016,2017,2018,2019
 ./lib/isc/include/isc/heap.h                   C       1997,1998,1999,2000,2001,2004,2005,2006,2007,2009,2012,2016,2018,2019
 ./lib/isc/include/isc/hex.h                    C       2000,2001,2004,2005,2006,2007,2008,2016,2018,2019