[prev in list] [next in list] [prev in thread] [next in thread] 

List:       apache-cvs
Subject:    svn commit: r1847430 - in /httpd/httpd/trunk: CHANGES include/ap_mmn.h include/http_config.h include
From:       minfrin () apache ! org
Date:       2018-11-25 21:15:21
Message-ID: 20181125211522.4D3E53A0253 () svn01-us-west ! apache ! org
[Download RAW message or body]

Author: minfrin
Date: Sun Nov 25 21:15:21 2018
New Revision: 1847430

URL: http://svn.apache.org/viewvc?rev=1847430&view=rev
Log:
core: Split out the ability to parse wildcard files and directories
from the Include/IncludeOptional directives into a generic set of
functions ap_dir_nofnmatch() and ap_dir_fnmatch().

Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/include/ap_mmn.h
    httpd/httpd/trunk/include/http_config.h
    httpd/httpd/trunk/include/httpd.h
    httpd/httpd/trunk/server/config.c
    httpd/httpd/trunk/server/util.c

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1847430&r1=1847429&r2=1847430&view=diff
 ==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Sun Nov 25 21:15:21 2018
@@ -1,6 +1,10 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.1
 
+  *) core: Split out the ability to parse wildcard files and directories
+     from the Include/IncludeOptional directives into a generic set of
+     functions ap_dir_nofnmatch() and ap_dir_fnmatch(). [Graham Leggett]
+
   *) mod_dav: Fix an unlikely time-window where some incorrect data could be \
returned  from a PROPFIND request [Ruediger Pluem]
 

Modified: httpd/httpd/trunk/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_mmn.h?rev=1847430&r1=1847429&r2=1847430&view=diff
 ==============================================================================
--- httpd/httpd/trunk/include/ap_mmn.h (original)
+++ httpd/httpd/trunk/include/ap_mmn.h Sun Nov 25 21:15:21 2018
@@ -608,6 +608,7 @@
  *                         fields by struct ap_filter_private *priv
  * 20180906.1 (2.5.1-dev)  Don't export ap_filter_recycle() anymore
  * 20180906.2 (2.5.1-dev)  Add ap_state_dir_relative()
+ * 20180906.3 (2.5.1-dev)  Add ap_dir_nofnmatch() and ap_dir_fnmatch().
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */

Modified: httpd/httpd/trunk/include/http_config.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/http_config.h?rev=1847430&r1=1847429&r2=1847430&view=diff
 ==============================================================================
--- httpd/httpd/trunk/include/http_config.h (original)
+++ httpd/httpd/trunk/include/http_config.h Sun Nov 25 21:15:21 2018
@@ -939,6 +939,21 @@ AP_DECLARE(const char *) ap_walk_config(
                                         ap_conf_vector_t *section_vector);
 
 /**
+ * Convenience function to create a ap_dir_match_t structure from a cmd_parms.
+ *
+ * @param cmd The command.
+ * @param flags Flags to indicate whether optional or recursive.
+ * @param cb Callback for each file found that matches the wildcard. Return NULL on
+ *        success, an error string on error.
+ * @param ctx Context for the callback.
+ * @return Structure ap_dir_match_t with fields populated, allocated from the
+ *         cmd->temp_pool.
+ */
+AP_DECLARE(ap_dir_match_t *)ap_dir_cfgmatch(cmd_parms *cmd, int flags,
+        const char *(*cb)(ap_dir_match_t *w, const char *fname), void *ctx)
+        __attribute__((nonnull(1,3)));
+
+/**
  * @defgroup ap_check_cmd_context Check command context
  * @{
  */

Modified: httpd/httpd/trunk/include/httpd.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/httpd.h?rev=1847430&r1=1847429&r2=1847430&view=diff
 ==============================================================================
--- httpd/httpd/trunk/include/httpd.h (original)
+++ httpd/httpd/trunk/include/httpd.h Sun Nov 25 21:15:21 2018
@@ -2559,6 +2559,92 @@ AP_DECLARE(int) ap_cstr_casecmp(const ch
  */
 AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n);
 
+/**
+ * Default flags for apr_dir_*().
+ */
+#define AP_DIR_FLAG_NONE      0
+
+/**
+ * If set, wildcards that match no files or directories will be ignored, otherwise
+ * an error is triggered.
+ */
+#define AP_DIR_FLAG_OPTIONAL  1
+
+/**
+ * If set, and the wildcard resolves to a directory, recursively find all files
+ * below that directory, otherwise return the directory.
+ */
+#define AP_DIR_FLAG_RECURSIVE 2
+
+/**
+ * Structure to provide the state of a directory match.
+ */
+typedef struct ap_dir_match_t ap_dir_match_t;
+
+/**
+ * Concrete structure to provide the state of a directory match.
+ */
+struct ap_dir_match_t {
+    /** Pool to use for allocating the result */
+    apr_pool_t *p;
+    /** Temporary pool used for directory traversal */
+    apr_pool_t *ptemp;
+    /** Prefix for log messages */
+    const char *prefix;
+    /** Callback for each file found that matches the wildcard. Return NULL on \
success, an error string on error. */ +    const char *(*cb)(ap_dir_match_t *w, const \
char *fname); +    /** Context for the callback */
+    void *ctx;
+    /** Flags to indicate whether optional or recursive */
+    int flags;
+    /** Recursion depth safety check */
+    unsigned int depth;
+};
+
+/**
+ * Search for files given a non wildcard filename with non native separators.
+ *
+ * If the provided filename points at a file, the callback within ap_dir_match_t is
+ * triggered for that file, and this function returns the result of the callback.
+ *
+ * If the provided filename points at a directory, and recursive within \
ap_dir_match_t + * is true, the callback will be triggered for every file found \
recursively beneath + * that directory, otherwise the callback is triggered once for \
the directory itself. + * This function returns the result of the callback.
+ *
+ * If the provided path points to neither a file nor a directory, and optional \
within + * ap_dir_match_t is true, this function returns NULL. If optional within \
ap_dir_match_t + * is false, this function will return an error string indicating \
that the path does not + * exist.
+ *
+ * @param w Directory match structure containing callback and context.
+ * @param fname The name of the file or directory, with non native separators.
+ * @return NULL on success, or a string describing the error.
+ */
+AP_DECLARE(const char *)ap_dir_nofnmatch(ap_dir_match_t *w, const char *fname)
+        __attribute__((nonnull(1,2)));
+
+/**
+ * Search for files given a wildcard filename with non native separators.
+ *
+ * If the filename contains a wildcard, all files and directories that match the \
wildcard + * will be returned.
+ *
+ * ap_dir_nofnmatch() is called for each directory and file found, and the callback
+ * within ap_dir_match_t triggered as described above.
+ *
+ * Wildcards may appear in both directory and file components in the path, and
+ * wildcards may appear more than once.
+ *
+ * @param w Directory match structure containing callback and context.
+ * @param path Path prefix for search, with non native separators and no wildcards.
+ * @param fname The name of the file or directory, with non native separators and
+ * optional wildcards.
+ * @return NULL on success, or a string describing the error.
+ */
+AP_DECLARE(const char *)ap_dir_fnmatch(ap_dir_match_t *w, const char *path,
+        const char *fname) __attribute__((nonnull(1,3)));
+
 #ifdef __cplusplus
 }
 #endif

Modified: httpd/httpd/trunk/server/config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/config.c?rev=1847430&r1=1847429&r2=1847430&view=diff
 ==============================================================================
--- httpd/httpd/trunk/server/config.c (original)
+++ httpd/httpd/trunk/server/config.c Sun Nov 25 21:15:21 2018
@@ -1795,18 +1795,6 @@ static const char *process_command_confi
     return NULL;
 }
 
-typedef struct {
-    const char *fname;
-} fnames;
-
-static int fname_alphasort(const void *fn1, const void *fn2)
-{
-    const fnames *f1 = fn1;
-    const fnames *f2 = fn2;
-
-    return strcmp(f1->fname,f2->fname);
-}
-
 /**
  * Used by -D DUMP_INCLUDES to output the config file "tree".
  */
@@ -1902,200 +1890,15 @@ AP_DECLARE(const char *) ap_process_reso
     return NULL;
 }
 
-static const char *process_resource_config_nofnmatch(server_rec *s,
-                                                     const char *fname,
-                                                     ap_directive_t **conftree,
-                                                     apr_pool_t *p,
-                                                     apr_pool_t *ptemp,
-                                                     unsigned depth,
-                                                     int optional)
-{
-    const char *error;
-    apr_status_t rv;
-
-    if (ap_is_directory(ptemp, fname)) {
-        apr_dir_t *dirp;
-        apr_finfo_t dirent;
-        int current;
-        apr_array_header_t *candidates = NULL;
-        fnames *fnew;
-        char *path = apr_pstrdup(ptemp, fname);
-
-        if (++depth > AP_MAX_INCLUDE_DIR_DEPTH) {
-            return apr_psprintf(p, "Directory %s exceeds the maximum include "
-                                "directory nesting level of %u. You have "
-                                "probably a recursion somewhere.", path,
-                                AP_MAX_INCLUDE_DIR_DEPTH);
-        }
-
-        /*
-         * first course of business is to grok all the directory
-         * entries here and store 'em away. Recall we need full pathnames
-         * for this.
-         */
-        rv = apr_dir_open(&dirp, path, ptemp);
-        if (rv != APR_SUCCESS) {
-            return apr_psprintf(p, "Could not open config directory %s: %pm",
-                                path, &rv);
-        }
-
-        candidates = apr_array_make(ptemp, 1, sizeof(fnames));
-        while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) {
-            /* strip out '.' and '..' */
-            if (strcmp(dirent.name, ".")
-                && strcmp(dirent.name, "..")) {
-                fnew = (fnames *) apr_array_push(candidates);
-                fnew->fname = ap_make_full_path(ptemp, path, dirent.name);
-            }
-        }
-
-        apr_dir_close(dirp);
-        if (candidates->nelts != 0) {
-            qsort((void *) candidates->elts, candidates->nelts,
-                  sizeof(fnames), fname_alphasort);
-
-            /*
-             * Now recurse these... we handle errors and subdirectories
-             * via the recursion, which is nice
-             */
-            for (current = 0; current < candidates->nelts; ++current) {
-                fnew = &((fnames *) candidates->elts)[current];
-                error = process_resource_config_nofnmatch(s, fnew->fname,
-                                                          conftree, p, ptemp,
-                                                          depth, optional);
-                if (error) {
-                    return error;
-                }
-            }
-        }
-
-        return NULL;
-    }
-    else if (optional) {
-        /* If the optinal flag is set (like for IncludeOptional) we can
-         * tolerate that no file or directory is present and bail out.
-         */
-        apr_finfo_t finfo;
-        if (apr_stat(&finfo, fname, APR_FINFO_TYPE, ptemp) != APR_SUCCESS
-            || finfo.filetype == APR_NOFILE)
-            return NULL;
-    }
-
-    return ap_process_resource_config(s, fname, conftree, p, ptemp);
-}
+typedef struct {
+    server_rec *s;
+    ap_directive_t **conftree;
+} configs;
 
-static const char *process_resource_config_fnmatch(server_rec *s,
-                                                   const char *path,
-                                                   const char *fname,
-                                                   ap_directive_t **conftree,
-                                                   apr_pool_t *p,
-                                                   apr_pool_t *ptemp,
-                                                   unsigned depth,
-                                                   int optional)
+static const char *process_resource_config_cb(ap_dir_match_t *w, const char *fname)
 {
-    const char *rest;
-    apr_status_t rv;
-    apr_dir_t *dirp;
-    apr_finfo_t dirent;
-    apr_array_header_t *candidates = NULL;
-    fnames *fnew;
-    int current;
-
-    /* find the first part of the filename */
-    rest = ap_strchr_c(fname, '/');
-    if (rest) {
-        fname = apr_pstrmemdup(ptemp, fname, rest - fname);
-        rest++;
-    }
-
-    /* optimisation - if the filename isn't a wildcard, process it directly */
-    if (!apr_fnmatch_test(fname)) {
-        path = ap_make_full_path(ptemp, path, fname);
-        if (!rest) {
-            return process_resource_config_nofnmatch(s, path,
-                                                     conftree, p,
-                                                     ptemp, 0, optional);
-        }
-        else {
-            return process_resource_config_fnmatch(s, path, rest,
-                                                   conftree, p,
-                                                   ptemp, 0, optional);
-        }
-    }
-
-    /*
-     * first course of business is to grok all the directory
-     * entries here and store 'em away. Recall we need full pathnames
-     * for this.
-     */
-    rv = apr_dir_open(&dirp, path, ptemp);
-    if (rv != APR_SUCCESS) {
-        /* If the directory doesn't exist and the optional flag is set
-         * there is no need to return an error.
-         */
-        if (rv == APR_ENOENT && optional) {
-            return NULL;
-        }
-        return apr_psprintf(p, "Could not open config directory %s: %pm",
-                            path, &rv);
-    }
-
-    candidates = apr_array_make(ptemp, 1, sizeof(fnames));
-    while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp) == \
                APR_SUCCESS) {
-        /* strip out '.' and '..' */
-        if (strcmp(dirent.name, ".")
-            && strcmp(dirent.name, "..")
-            && (apr_fnmatch(fname, dirent.name,
-                            APR_FNM_PERIOD) == APR_SUCCESS)) {
-            const char *full_path = ap_make_full_path(ptemp, path, dirent.name);
-            /* If matching internal to path, and we happen to match something
-             * other than a directory, skip it
-             */
-            if (rest && (dirent.filetype != APR_DIR)) {
-                continue;
-            }
-            fnew = (fnames *) apr_array_push(candidates);
-            fnew->fname = full_path;
-        }
-    }
-
-    apr_dir_close(dirp);
-    if (candidates->nelts != 0) {
-        const char *error;
-
-        qsort((void *) candidates->elts, candidates->nelts,
-              sizeof(fnames), fname_alphasort);
-
-        /*
-         * Now recurse these... we handle errors and subdirectories
-         * via the recursion, which is nice
-         */
-        for (current = 0; current < candidates->nelts; ++current) {
-            fnew = &((fnames *) candidates->elts)[current];
-            if (!rest) {
-                error = process_resource_config_nofnmatch(s, fnew->fname,
-                                                          conftree, p,
-                                                          ptemp, 0, optional);
-            }
-            else {
-                error = process_resource_config_fnmatch(s, fnew->fname, rest,
-                                                        conftree, p,
-                                                        ptemp, 0, optional);
-            }
-            if (error) {
-                return error;
-            }
-        }
-    }
-    else {
-
-        if (!optional) {
-            return apr_psprintf(p, "No matches for the wildcard '%s' in '%s', \
                failing "
-                                   "(use IncludeOptional if required)", fname, \
                path);
-        }
-    }
-
-    return NULL;
+    configs *cfgs = w->ctx;
+    return ap_process_resource_config(cfgs->s, fname, cfgs->conftree, w->p, \
w->ptemp);  }
 
 AP_DECLARE(const char *) ap_process_fnmatch_configs(server_rec *s,
@@ -2105,8 +1908,18 @@ AP_DECLARE(const char *) ap_process_fnma
                                                     apr_pool_t *ptemp,
                                                     int optional)
 {
-    /* XXX: lstat() won't work on the wildcard pattern...
-     */
+    configs cfgs;
+    ap_dir_match_t w;
+
+    cfgs.s = s;
+    cfgs.conftree = conftree;
+
+    w.prefix = "Include/IncludeOptional: ";
+    w.p = p;
+    w.ptemp = ptemp;
+    w.flags = (optional ? AP_DIR_FLAG_OPTIONAL : AP_DIR_FLAG_NONE) | \
AP_DIR_FLAG_RECURSIVE; +    w.cb = process_resource_config_cb;
+    w.ctx = &cfgs;
 
     /* don't require conf/httpd.conf if we have a -C or -c switch */
     if ((ap_server_pre_read_config->nelts
@@ -2119,7 +1932,7 @@ AP_DECLARE(const char *) ap_process_fnma
     }
 
     if (!apr_fnmatch_test(fname)) {
-        return process_resource_config_nofnmatch(s, fname, conftree, p, ptemp, 0, \
optional); +        return ap_dir_nofnmatch(&w, fname);
     }
     else {
         apr_status_t status;
@@ -2137,8 +1950,7 @@ AP_DECLARE(const char *) ap_process_fnma
         }
 
         /* walk the filepath */
-        return process_resource_config_fnmatch(s, rootpath, filepath, conftree, p, \
                ptemp,
-                                               0, optional);
+        return ap_dir_fnmatch(&w, rootpath, filepath);
     }
 }
 

Modified: httpd/httpd/trunk/server/util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util.c?rev=1847430&r1=1847429&r2=1847430&view=diff
 ==============================================================================
--- httpd/httpd/trunk/server/util.c (original)
+++ httpd/httpd/trunk/server/util.c Sun Nov 25 21:15:21 2018
@@ -48,6 +48,7 @@
 
 #include "ap_config.h"
 #include "apr_base64.h"
+#include "apr_fnmatch.h"
 #include "httpd.h"
 #include "http_main.h"
 #include "http_log.h"
@@ -97,6 +98,11 @@
 #undef APLOG_MODULE_INDEX
 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
 
+/* maximum nesting level for config directories */
+#ifndef AP_MAX_FNMATCH_DIR_DEPTH
+#define AP_MAX_FNMATCH_DIR_DEPTH (128)
+#endif
+
 /*
  * Examine a field value (such as a media-/content-type) string and return
  * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
@@ -3444,3 +3450,206 @@ AP_DECLARE(int) ap_cstr_casecmpn(const c
     return 0;
 }
 
+typedef struct {
+    const char *fname;
+} fnames;
+
+static int fname_alphasort(const void *fn1, const void *fn2)
+{
+    const fnames *f1 = fn1;
+    const fnames *f2 = fn2;
+
+    return strcmp(f1->fname,f2->fname);
+}
+
+AP_DECLARE(ap_dir_match_t *)ap_dir_cfgmatch(cmd_parms *cmd, int flags,
+        const char *(*cb)(ap_dir_match_t *w, const char *fname), void *ctx)
+{
+    ap_dir_match_t *w = apr_palloc(cmd->temp_pool, sizeof(cmd_parms));
+
+    w->prefix = apr_pstrcat(cmd->pool, cmd->cmd->name, ": ", NULL);
+    w->p = cmd->pool;
+    w->ptemp = cmd->temp_pool;
+    w->flags = flags;
+    w->cb = cb;
+    w->ctx = ctx;
+    w->depth = 0;
+
+    return w;
+}
+
+AP_DECLARE(const char *)ap_dir_nofnmatch(ap_dir_match_t *w, const char *fname)
+{
+    const char *error;
+    apr_status_t rv;
+
+    if ((w->flags & AP_DIR_FLAG_RECURSIVE) && ap_is_directory(w->ptemp, fname)) {
+        apr_dir_t *dirp;
+        apr_finfo_t dirent;
+        int current;
+        apr_array_header_t *candidates = NULL;
+        fnames *fnew;
+        char *path = apr_pstrdup(w->ptemp, fname);
+
+        if (++w->depth > AP_MAX_FNMATCH_DIR_DEPTH) {
+            return apr_psprintf(w->p, "%sDirectory '%s' exceeds the maximum include \
" +                    "directory nesting level of %u. You have "
+                    "probably a recursion somewhere.", w->prefix ? w->prefix : "", \
path, +                    AP_MAX_FNMATCH_DIR_DEPTH);
+        }
+
+        /*
+         * first course of business is to grok all the directory
+         * entries here and store 'em away. Recall we need full pathnames
+         * for this.
+         */
+        rv = apr_dir_open(&dirp, path, w->ptemp);
+        if (rv != APR_SUCCESS) {
+            return apr_psprintf(w->p, "%sCould not open directory %s: %pm",
+                    w->prefix ? w->prefix : "", path, &rv);
+        }
+
+        candidates = apr_array_make(w->ptemp, 1, sizeof(fnames));
+        while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) {
+            /* strip out '.' and '..' */
+            if (strcmp(dirent.name, ".")
+                && strcmp(dirent.name, "..")) {
+                fnew = (fnames *) apr_array_push(candidates);
+                fnew->fname = ap_make_full_path(w->ptemp, path, dirent.name);
+            }
+        }
+
+        apr_dir_close(dirp);
+        if (candidates->nelts != 0) {
+            qsort((void *) candidates->elts, candidates->nelts,
+                  sizeof(fnames), fname_alphasort);
+
+            /*
+             * Now recurse these... we handle errors and subdirectories
+             * via the recursion, which is nice
+             */
+            for (current = 0; current < candidates->nelts; ++current) {
+                fnew = &((fnames *) candidates->elts)[current];
+                error = ap_dir_nofnmatch(w, fnew->fname);
+                if (error) {
+                    return error;
+                }
+            }
+        }
+
+        w->depth--;
+
+        return NULL;
+    }
+    else if (w->flags & AP_DIR_FLAG_OPTIONAL) {
+        /* If the optional flag is set (like for IncludeOptional) we can
+         * tolerate that no file or directory is present and bail out.
+         */
+        apr_finfo_t finfo;
+        if (apr_stat(&finfo, fname, APR_FINFO_TYPE, w->ptemp) != APR_SUCCESS
+            || finfo.filetype == APR_NOFILE)
+            return NULL;
+    }
+
+    return w->cb(w, fname);
+}
+
+AP_DECLARE(const char *)ap_dir_fnmatch(ap_dir_match_t *w, const char *path,
+        const char *fname)
+{
+    const char *rest;
+    apr_status_t rv;
+    apr_dir_t *dirp;
+    apr_finfo_t dirent;
+    apr_array_header_t *candidates = NULL;
+    fnames *fnew;
+    int current;
+
+    /* find the first part of the filename */
+    rest = ap_strchr_c(fname, '/');
+    if (rest) {
+        fname = apr_pstrmemdup(w->ptemp, fname, rest - fname);
+        rest++;
+    }
+
+    /* optimisation - if the filename isn't a wildcard, process it directly */
+    if (!apr_fnmatch_test(fname)) {
+        path = path ? ap_make_full_path(w->ptemp, path, fname) : fname;
+        if (!rest) {
+            return ap_dir_nofnmatch(w, path);
+        }
+        else {
+            return ap_dir_fnmatch(w, path, rest);
+        }
+    }
+
+    /*
+     * first course of business is to grok all the directory
+     * entries here and store 'em away. Recall we need full pathnames
+     * for this.
+     */
+    rv = apr_dir_open(&dirp, path, w->ptemp);
+    if (rv != APR_SUCCESS) {
+        /* If the directory doesn't exist and the optional flag is set
+         * there is no need to return an error.
+         */
+        if (rv == APR_ENOENT && (w->flags & AP_DIR_FLAG_OPTIONAL)) {
+            return NULL;
+        }
+        return apr_psprintf(w->p, "%sCould not open directory %s: %pm",
+                w->prefix ? w->prefix : "", path, &rv);
+    }
+
+    candidates = apr_array_make(w->ptemp, 1, sizeof(fnames));
+    while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp) == \
APR_SUCCESS) { +        /* strip out '.' and '..' */
+        if (strcmp(dirent.name, ".")
+            && strcmp(dirent.name, "..")
+            && (apr_fnmatch(fname, dirent.name,
+                            APR_FNM_PERIOD) == APR_SUCCESS)) {
+            const char *full_path = ap_make_full_path(w->ptemp, path, dirent.name);
+            /* If matching internal to path, and we happen to match something
+             * other than a directory, skip it
+             */
+            if (rest && (dirent.filetype != APR_DIR)) {
+                continue;
+            }
+            fnew = (fnames *) apr_array_push(candidates);
+            fnew->fname = full_path;
+        }
+    }
+
+    apr_dir_close(dirp);
+    if (candidates->nelts != 0) {
+        const char *error;
+
+        qsort((void *) candidates->elts, candidates->nelts,
+              sizeof(fnames), fname_alphasort);
+
+        /*
+         * Now recurse these... we handle errors and subdirectories
+         * via the recursion, which is nice
+         */
+        for (current = 0; current < candidates->nelts; ++current) {
+            fnew = &((fnames *) candidates->elts)[current];
+            if (!rest) {
+                error = ap_dir_nofnmatch(w, fnew->fname);
+            }
+            else {
+                error = ap_dir_fnmatch(w, fnew->fname, rest);
+            }
+            if (error) {
+                return error;
+            }
+        }
+    }
+    else {
+
+        if (!(w->flags & AP_DIR_FLAG_OPTIONAL)) {
+            return apr_psprintf(w->p, "%sNo matches for the wildcard '%s' in '%s', \
failing", +                    w->prefix ? w->prefix : "", fname, path);
+        }
+    }
+
+    return NULL;
+}


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic