📄 request.c
字号:
if ((res = apr_stat(&fi, d, lfi->valid & ~(APR_FINFO_NAME | APR_FINFO_LINK), p)) != APR_SUCCESS) { return HTTP_FORBIDDEN; } /* Give back the target */ memcpy(lfi, &fi, sizeof(fi)); if (savename) { lfi->name = savename; lfi->valid |= APR_FINFO_NAME; } return OK; } /* OPT_SYM_OWNER only works if we can get the owner of * both the file and symlink. First fill in a missing * owner of the symlink, then get the info of the target. */ if (!(lfi->valid & APR_FINFO_OWNER)) { if ((res = apr_lstat(&fi, d, lfi->valid | APR_FINFO_OWNER, p)) != APR_SUCCESS) { return HTTP_FORBIDDEN; } } if ((res = apr_stat(&fi, d, lfi->valid & ~(APR_FINFO_NAME), p)) != APR_SUCCESS) { return HTTP_FORBIDDEN; } if (apr_compare_users(fi.user, lfi->user) != APR_SUCCESS) { return HTTP_FORBIDDEN; } /* Give back the target */ memcpy(lfi, &fi, sizeof(fi)); if (savename) { lfi->name = savename; lfi->valid |= APR_FINFO_NAME; } return OK;}/* * As we walk the directory configuration, the merged config won't * be 'rooted' to a specific vhost until the very end of the merge. * * We need a very fast mini-merge to a real, vhost-rooted merge * of core.opts and core.override, the only options tested within * directory_walk itself. * * See core.c::merge_core_dir_configs() for explanation. */typedef struct core_opts_t { allow_options_t opts; allow_options_t add; allow_options_t remove; overrides_t override;} core_opts_t;static void core_opts_merge(const ap_conf_vector_t *sec, core_opts_t *opts){ core_dir_config *this_dir = ap_get_module_config(sec, &core_module); if (!this_dir) { return; } if (this_dir->opts & OPT_UNSET) { opts->add = (opts->add & ~this_dir->opts_remove) | this_dir->opts_add; opts->remove = (opts->remove & ~this_dir->opts_add) | this_dir->opts_remove; opts->opts = (opts->opts & ~opts->remove) | opts->add; } else { opts->opts = this_dir->opts; opts->add = this_dir->opts_add; opts->remove = this_dir->opts_remove; } if (!(this_dir->override & OR_UNSET)) { opts->override = this_dir->override; }}/***************************************************************** * * Getting and checking directory configuration. Also checks the * FollowSymlinks and FollowSymOwner stuff, since this is really the * only place that can happen (barring a new mid_dir_walk callout). * * We can't do it as an access_checker module function which gets * called with the final per_dir_config, since we could have a directory * with FollowSymLinks disabled, which contains a symlink to another * with a .htaccess file which turns FollowSymLinks back on --- and * access in such a case must be denied. So, whatever it is that * checks FollowSymLinks needs to know the state of the options as * they change, all the way down. */AP_DECLARE(int) ap_directory_walk(request_rec *r){ ap_conf_vector_t *now_merged = NULL; core_server_config *sconf = ap_get_module_config(r->server->module_config, &core_module); ap_conf_vector_t **sec_ent = (ap_conf_vector_t **) sconf->sec_dir->elts; int num_sec = sconf->sec_dir->nelts; walk_cache_t *cache; char *entry_dir; apr_status_t rv; /* XXX: Better (faster) tests needed!!! * * "OK" as a response to a real problem is not _OK_, but to allow broken * modules to proceed, we will permit the not-a-path filename to pass the * following two tests. This behavior may be revoked in future versions * of Apache. We still must catch it later if it's heading for the core * handler. Leave INFO notes here for module debugging. */ if (r->filename == NULL) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Module bug? Request filename is missing for URI %s", r->uri); return OK; } /* Canonicalize the file path without resolving filename case or aliases * so we can begin by checking the cache for a recent directory walk. * This call will ensure we have an absolute path in the same pass. */ if ((rv = apr_filepath_merge(&entry_dir, NULL, r->filename, APR_FILEPATH_NOTRELATIVE, r->pool)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Module bug? Request filename path %s is invalid or " "or not absolute for uri %s", r->filename, r->uri); return OK; } /* XXX Notice that this forces path_info to be canonical. That might * not be desired by all apps. However, some of those same apps likely * have significant security holes. */ r->filename = entry_dir; cache = prep_walk_cache(AP_NOTE_DIRECTORY_WALK, r); /* If this is not a dirent subrequest with a preconstructed * r->finfo value, then we can simply stat the filename to * save burning mega-cycles with unneeded stats - if this is * an exact file match. We don't care about failure... we * will stat by component failing this meager attempt. * * It would be nice to distinguish APR_ENOENT from other * types of failure, such as APR_ENOTDIR. We can do something * with APR_ENOENT, knowing that the path is good. */ if (!r->finfo.filetype || r->finfo.filetype == APR_LNK) { rv = apr_stat(&r->finfo, r->filename, APR_FINFO_MIN, r->pool); /* some OSs will return APR_SUCCESS/APR_REG if we stat * a regular file but we have '/' at the end of the name; * * other OSs will return APR_ENOTDIR for that situation; * * handle it the same everywhere by simulating a failure * if it looks like a directory but really isn't * * Also reset if the stat failed, just for safety. */ if ((rv != APR_SUCCESS) || (r->finfo.filetype && (r->finfo.filetype != APR_DIR) && (r->filename[strlen(r->filename) - 1] == '/'))) { r->finfo.filetype = 0; /* forget what we learned */ } } if (r->finfo.filetype == APR_REG) { entry_dir = ap_make_dirstr_parent(r->pool, entry_dir); } else if (r->filename[strlen(r->filename) - 1] != '/') { entry_dir = apr_pstrcat(r->pool, r->filename, "/", NULL); } /* If we have a file already matches the path of r->filename, * and the vhost's list of directory sections hasn't changed, * we can skip rewalking the directory_walk entries. */ if (cache->cached && ((r->finfo.filetype == APR_REG) || ((r->finfo.filetype == APR_DIR) && (!r->path_info || !*r->path_info))) && (cache->dir_conf_tested == sec_ent) && (strcmp(entry_dir, cache->cached) == 0)) { /* Well this looks really familiar! If our end-result (per_dir_result) * didn't change, we have absolutely nothing to do :) * Otherwise (as is the case with most dir_merged/file_merged requests) * we must merge our dir_conf_merged onto this new r->per_dir_config. */ if (r->per_dir_config == cache->per_dir_result) { return OK; } if (r->per_dir_config == cache->dir_conf_merged) { r->per_dir_config = cache->per_dir_result; return OK; } if (cache->walked->nelts) { now_merged = ((walk_walked_t*)cache->walked->elts) [cache->walked->nelts - 1].merged; } } else { /* We start now_merged from NULL since we want to build * a locations list that can be merged to any vhost. */ int sec_idx; int matches = cache->walked->nelts; walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts; core_dir_config *this_dir; core_opts_t opts; apr_finfo_t thisinfo; char *save_path_info; apr_size_t buflen; char *buf; unsigned int seg, startseg; /* Invariant: from the first time filename_len is set until * it goes out of scope, filename_len==strlen(r->filename) */ apr_size_t filename_len;#ifdef CASE_BLIND_FILESYSTEM apr_size_t canonical_len;#endif /* * We must play our own mini-merge game here, for the few * running dir_config values we care about within dir_walk. * We didn't start the merge from r->per_dir_config, so we * accumulate opts and override as we merge, from the globals. */ this_dir = ap_get_module_config(r->per_dir_config, &core_module); opts.opts = this_dir->opts; opts.add = this_dir->opts_add; opts.remove = this_dir->opts_remove; opts.override = this_dir->override; /* Set aside path_info to merge back onto path_info later. * If r->filename is a directory, we must remerge the path_info, * before we continue! [Directories cannot, by defintion, have * path info. Either the next segment is not-found, or a file.] * * r->path_info tracks the unconsumed source path. * r->filename tracks the path as we process it */ if ((r->finfo.filetype == APR_DIR) && r->path_info && *r->path_info) { if ((rv = apr_filepath_merge(&r->path_info, r->filename, r->path_info, APR_FILEPATH_NOTABOVEROOT, r->pool)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "dir_walk error, path_info %s is not relative " "to the filename path %s for uri %s", r->path_info, r->filename, r->uri); return HTTP_INTERNAL_SERVER_ERROR; } save_path_info = NULL; } else { save_path_info = r->path_info; r->path_info = r->filename; }#ifdef CASE_BLIND_FILESYSTEM canonical_len = 0; while (r->canonical_filename && r->canonical_filename[canonical_len] && (r->canonical_filename[canonical_len] == r->path_info[canonical_len])) { ++canonical_len; } while (canonical_len && ((r->canonical_filename[canonical_len - 1] != '/' && r->canonical_filename[canonical_len - 1]) || (r->path_info[canonical_len - 1] != '/' && r->path_info[canonical_len - 1]))) { --canonical_len; } /* * Now build r->filename component by component, starting * with the root (on Unix, simply "/"). We will make a huge * assumption here for efficiency, that any canonical path * already given included a canonical root. */ rv = apr_filepath_root((const char **)&r->filename, (const char **)&r->path_info, canonical_len ? 0 : APR_FILEPATH_TRUENAME, r->pool); filename_len = strlen(r->filename); /* * Bad assumption above? If the root's length is longer * than the canonical length, then it cannot be trusted as * a truename. So try again, this time more seriously. */ if ((rv == APR_SUCCESS) && canonical_len && (filename_len > canonical_len)) { rv = apr_filepath_root((const char **)&r->filename, (const char **)&r->path_info, APR_FILEPATH_TRUENAME, r->pool); filename_len = strlen(r->filename); canonical_len = 0; }#else /* ndef CASE_BLIND_FILESYSTEM, really this simple for Unix today; */ rv = apr_filepath_root((const char **)&r->filename, (const char **)&r->path_info, 0, r->pool); filename_len = strlen(r->filename);#endif if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "dir_walk error, could not determine the root " "path of filename %s%s for uri %s", r->filename, r->path_info, r->uri); return HTTP_INTERNAL_SERVER_ERROR; } /* Working space for terminating null and an extra / is required. */ buflen = filename_len + strlen(r->path_info) + 2; buf = apr_palloc(r->pool, buflen); memcpy(buf, r->filename, filename_len + 1); r->filename = buf; thisinfo.valid = APR_FINFO_TYPE; thisinfo.filetype = APR_DIR; /* It's the root, of course it's a dir */ /* * seg keeps track of which segment we've copied. * sec_idx keeps track of which section we're on, since sections are
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -