| 3679 | } |
| 3680 | |
| 3681 | AP_DECLARE(const char *)ap_dir_fnmatch(ap_dir_match_t *w, const char *path, |
| 3682 | const char *fname) |
| 3683 | { |
| 3684 | const char *rest; |
| 3685 | apr_status_t rv; |
| 3686 | apr_dir_t *dirp; |
| 3687 | apr_finfo_t dirent; |
| 3688 | apr_array_header_t *candidates = NULL; |
| 3689 | fnames *fnew; |
| 3690 | int current; |
| 3691 | |
| 3692 | /* find the first part of the filename */ |
| 3693 | rest = ap_strchr_c(fname, '/'); |
| 3694 | if (rest) { |
| 3695 | fname = apr_pstrmemdup(w->ptemp, fname, rest - fname); |
| 3696 | rest++; |
| 3697 | } |
| 3698 | |
| 3699 | /* optimisation - if the filename isn't a wildcard, process it directly */ |
| 3700 | if (!apr_fnmatch_test(fname)) { |
| 3701 | path = path ? ap_make_full_path(w->ptemp, path, fname) : fname; |
| 3702 | if (!rest) { |
| 3703 | return ap_dir_nofnmatch(w, path); |
| 3704 | } |
| 3705 | else { |
| 3706 | return ap_dir_fnmatch(w, path, rest); |
| 3707 | } |
| 3708 | } |
| 3709 | |
| 3710 | /* |
| 3711 | * first course of business is to grok all the directory |
| 3712 | * entries here and store 'em away. Recall we need full pathnames |
| 3713 | * for this. |
| 3714 | */ |
| 3715 | rv = apr_dir_open(&dirp, path, w->ptemp); |
| 3716 | if (rv != APR_SUCCESS) { |
| 3717 | /* If the directory doesn't exist and the optional flag is set |
| 3718 | * there is no need to return an error. |
| 3719 | */ |
| 3720 | if (rv == APR_ENOENT && (w->flags & AP_DIR_FLAG_OPTIONAL)) { |
| 3721 | return NULL; |
| 3722 | } |
| 3723 | return apr_psprintf(w->p, "%sCould not open directory %s: %pm", |
| 3724 | w->prefix ? w->prefix : "", path, &rv); |
| 3725 | } |
| 3726 | |
| 3727 | candidates = apr_array_make(w->ptemp, 1, sizeof(fnames)); |
| 3728 | while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp) == APR_SUCCESS) { |
| 3729 | /* strip out '.' and '..' */ |
| 3730 | if (strcmp(dirent.name, ".") |
| 3731 | && strcmp(dirent.name, "..") |
| 3732 | && (apr_fnmatch(fname, dirent.name, |
| 3733 | APR_FNM_PERIOD) == APR_SUCCESS)) { |
| 3734 | const char *full_path = ap_make_full_path(w->ptemp, path, dirent.name); |
| 3735 | /* If matching internal to path, and we happen to match something |
| 3736 | * other than a directory, skip it |
| 3737 | */ |
| 3738 | if (rest && (dirent.filetype != APR_DIR)) { |
no test coverage detected