📄 filepath.c
字号:
return APR_EBADPATH;
#ifndef NETWARE
/* This isn't legal unless the unc path is completed
*/
if (fixunc)
return APR_EBADPATH;
#endif
/* backpath (../) when an absolute path is given */
if (rootlen && (pathlen <= rootlen))
{
/* Attempt to move above root. Always die if the
* APR_FILEPATH_SECUREROOTTEST flag is specified.
*/
if (flags & APR_FILEPATH_SECUREROOTTEST)
return APR_EABOVEROOT;
/* Otherwise this is simply a noop, above root is root.
*/
}
else if (pathlen == 0
|| (pathlen >= 3
&& (pathlen == 3
|| path[pathlen - 4] == ':'
|| path[pathlen - 4] == '/'
|| path[pathlen - 4] == '\\')
&& path[pathlen - 3] == '.'
&& path[pathlen - 2] == '.'
&& (path[pathlen - 1] == '/'
|| path[pathlen - 1] == '\\')))
{
/* Verified path is empty, exactly "..[/\]", or ends
* in "[:/\]..[/\]" - these patterns we will not back
* over since they aren't 'prior segements'.
*
* If APR_FILEPATH_SECUREROOTTEST.was given, die now.
*/
if (flags & APR_FILEPATH_SECUREROOTTEST)
return APR_EABOVEROOT;
/* Otherwise append another backpath.
*/
if (pathlen + 3 >= sizeof(path))
return APR_ENAMETOOLONG;
path[pathlen++] = '.';
path[pathlen++] = '.';
if (addpath[segend]) {
path[pathlen++] = ((flags & APR_FILEPATH_NATIVE)
? '\\' : ((flags & APR_FILEPATH_TRUENAME)
? '/' : addpath[segend]));
}
/* The 'root' part of this path now includes the ../ path,
* because that backpath will not be parsed by the truename
* code below.
*/
keptlen = pathlen;
}
else
{
/* otherwise crop the prior segment
*/
do {
--pathlen;
} while (pathlen && path[pathlen - 1] != '/'
&& path[pathlen - 1] != '\\');
/* Now test if we are above where we started and back up
* the keptlen offset to reflect the added/altered path.
*/
if (pathlen < keptlen)
{
if (flags & APR_FILEPATH_SECUREROOTTEST)
return APR_EABOVEROOT;
keptlen = pathlen;
}
}
}
else /* not empty or dots */
{
#ifndef NETWARE
if (fixunc) {
const char *testpath = path;
const char *testroot;
apr_status_t testtype;
apr_size_t i = (addpath[segend] != '\0');
/* This isn't legal unless the unc path is complete!
*/
if (seglen < segend)
return APR_EBADPATH;
if (pathlen + seglen + 1 >= sizeof(path))
return APR_ENAMETOOLONG;
memcpy(path + pathlen, addpath, seglen + i);
/* Always add the trailing slash to a UNC segment
*/
path[pathlen + seglen] = ((flags & APR_FILEPATH_NATIVE)
? '\\' : '/');
pathlen += seglen + 1;
/* Recanonicalize the UNC root with the new UNC segment,
* and if we succeed, reset this test and the rootlen,
* and replace our path with the canonical UNC root path
*/
path[pathlen] = '\0';
/* This call _should_ test the path
*/
testtype = apr_filepath_root(&testroot, &testpath,
APR_FILEPATH_TRUENAME
| (flags & APR_FILEPATH_NATIVE),
p);
if (testtype == APR_SUCCESS) {
rootlen = pathlen = (testpath - path);
memcpy(path, testroot, pathlen);
fixunc = 0;
}
else if (testtype != APR_EINCOMPLETE) {
/* apr_filepath_root was very unexpected so fail already
*/
return testtype;
}
}
else
#endif
{
/* An actual segment, append it to the destination path
*/
apr_size_t i = (addpath[segend] != '\0');
if (pathlen + seglen + i >= sizeof(path))
return APR_ENAMETOOLONG;
memcpy(path + pathlen, addpath, seglen + i);
if (i)
path[pathlen + seglen] = ((flags & APR_FILEPATH_NATIVE)
? '\\' : '/');
pathlen += seglen + i;
}
}
/* Skip over trailing slash to the next segment
*/
if (addpath[segend])
++segend;
addpath += segend;
}
/* keptlen will be the baselen unless the addpath contained
* backpath elements. If so, and APR_FILEPATH_NOTABOVEROOT
* is specified (APR_FILEPATH_SECUREROOTTEST was caught above),
* compare the string beyond the root to assure the result path
* is still within given basepath. Note that the root path
* segment is thoroughly tested prior to path parsing.
*/
if ((flags & APR_FILEPATH_NOTABOVEROOT) && baselen) {
if (memcmp(basepath, path + rootlen, baselen) != 0)
return APR_EABOVEROOT;
/* Ahem... if we have a basepath without a trailing slash,
* we better be sure that /foo wasn't replaced with /foobar!
*/
if (basepath[baselen - 1] != '/' && basepath[baselen - 1] != '\\'
&& path[rootlen + baselen] && path[rootlen + baselen] != '/'
&& path[rootlen + baselen] != '\\')
return APR_EABOVEROOT;
}
if (addpath && (flags & APR_FILEPATH_TRUENAME)) {
/* We can always skip the root, it's already true-named. */
if (rootlen > keptlen)
keptlen = rootlen;
if ((path[keptlen] == '/') || (path[keptlen] == '\\')) {
/* By rights, keptlen may grown longer than pathlen.
* we wont' use it again (in that case) so we don't care.
*/
++keptlen;
}
/* Go through all the new segments */
while (keptlen < pathlen) {
apr_finfo_t finfo;
char saveslash = 0;
seglen = 0;
/* find any slash and set it aside for a minute. */
for (seglen = 0; keptlen + seglen < pathlen; ++seglen) {
if ((path[keptlen + seglen] == '/') ||
(path[keptlen + seglen] == '\\')) {
saveslash = path[keptlen + seglen];
break;
}
}
/* Null term for stat! */
path[keptlen + seglen] = '\0';
if ((rv = apr_lstat(&finfo, path,
APR_FINFO_TYPE | APR_FINFO_NAME, p))
== APR_SUCCESS) {
apr_size_t namelen = strlen(finfo.name);
#if defined(OS2) /* only has case folding, never aliases that change the length */
if (memcmp(finfo.name, path + keptlen, seglen) != 0) {
memcpy(path + keptlen, finfo.name, namelen);
}
#else /* WIN32 || NETWARE; here there be aliases that gire and gimble and change length */
if ((namelen != seglen) ||
(memcmp(finfo.name, path + keptlen, seglen) != 0))
{
if (namelen <= seglen) {
memcpy(path + keptlen, finfo.name, namelen);
if ((namelen < seglen) && saveslash) {
memmove(path + keptlen + namelen + 1,
path + keptlen + seglen + 1,
pathlen - keptlen - seglen);
pathlen += namelen - seglen;
seglen = namelen;
}
}
else { /* namelen > seglen */
if (pathlen + namelen - seglen >= sizeof(path))
return APR_ENAMETOOLONG;
if (saveslash) {
memmove(path + keptlen + namelen + 1,
path + keptlen + seglen + 1,
pathlen - keptlen - seglen);
}
memcpy(path + keptlen, finfo.name, namelen);
pathlen += namelen - seglen;
seglen = namelen;
}
}
#endif /* !OS2 (Whatever that alias was we're over it) */
/* That's it, the rest is path info.
* I don't know how we aught to handle this. Should
* we define a new error to indicate 'more info'?
* Should we split out the rest of the path?
*/
if ((finfo.filetype != APR_DIR) &&
(finfo.filetype != APR_LNK) && saveslash)
rv = APR_ENOTDIR;
#ifdef XXX_FIGURE_THIS_OUT
{
/* the example inserts a null between the end of
* the filename and the next segment, and increments
* the path length so we would return both segments.
*/
if (saveslash) {
keptlen += seglen;
path[keptlen] = saveslash;
if (pathlen + 1 >= sizeof(path))
return APR_ENAMETOOLONG;
memmove(path + keptlen + 1,
path + keptlen,
pathlen - keptlen);
path[keptlen] = '\0';
++pathlen;
break;
}
}
#endif
}
/* put back the '/' */
if (saveslash) {
path[keptlen + seglen] = saveslash;
++seglen;
}
keptlen += seglen;
if (rv != APR_SUCCESS) {
if (APR_STATUS_IS_ENOENT(rv))
break;
if (APR_STATUS_IS_EPATHWILD(rv))
/* This path included wildcards. The path elements
* that did not contain wildcards are canonicalized,
* so we will return the path, although later elements
* don't necessarily exist, and aren't canonical.
*/
break;
else if (APR_STATUS_IS_ENOTDIR(rv))
/* This is a little more serious, we just added a name
* onto a filename (think http's PATH_INFO)
* If the caller is foolish enough to do this, we expect
* the've already canonicalized the root) that they knew
* what they are doing :(
*/
break;
else
return rv;
}
}
}
*newpath = apr_pmemdup(p, path, pathlen + 1);
(*newpath)[pathlen] = '\0';
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_filepath_list_split(apr_array_header_t **pathelts,
const char *liststr,
apr_pool_t *p)
{
return apr_filepath_list_split_impl(pathelts, liststr, ';', p);
}
APR_DECLARE(apr_status_t) apr_filepath_list_merge(char **liststr,
apr_array_header_t *pathelts,
apr_pool_t *p)
{
return apr_filepath_list_merge_impl(liststr, pathelts, ';', p);
}
APR_DECLARE(apr_status_t) apr_filepath_encoding(int *style, apr_pool_t *p)
{
#if APR_HAS_UNICODE_FS
IF_WIN_OS_IS_UNICODE
{
*style = APR_FILEPATH_ENCODING_UTF8;
return APR_SUCCESS;
}
#endif
*style = APR_FILEPATH_ENCODING_LOCALE;
return APR_SUCCESS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -