📄 filepath.c
字号:
APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath,
const char *basepath,
const char *addpath,
apr_int32_t flags,
apr_pool_t *p)
{
char path[APR_PATH_MAX]; /* isn't null term */
const char *baseroot = NULL;
const char *addroot;
apr_size_t rootlen; /* the length of the root portion of path, d:/ is 3 */
apr_size_t baselen; /* the length of basepath (excluding baseroot) */
apr_size_t keptlen; /* the length of the retained basepath (incl root) */
apr_size_t pathlen; /* the length of the result path */
apr_size_t segend; /* the end of the current segment */
apr_size_t seglen; /* the length of the segment (excl trailing chars) */
apr_status_t basetype = 0; /* from parsing the basepath's baseroot */
apr_status_t addtype; /* from parsing the addpath's addroot */
apr_status_t rv;
#ifndef NETWARE
int fixunc = 0; /* flag to complete an incomplete UNC basepath */
#endif
/* Treat null as an empty path, otherwise split addroot from the addpath
*/
if (!addpath) {
addpath = addroot = "";
addtype = APR_ERELATIVE;
}
else {
/* This call _should_ test the path
*/
addtype = apr_filepath_root(&addroot, &addpath,
APR_FILEPATH_TRUENAME
| (flags & APR_FILEPATH_NATIVE),
p);
if (addtype == APR_SUCCESS) {
addtype = APR_EABSOLUTE;
}
else if (addtype == APR_ERELATIVE) {
addroot = "";
}
else if (addtype != APR_EINCOMPLETE) {
/* apr_filepath_root was incomprehensible so fail already
*/
return addtype;
}
}
/* If addpath is (even partially) rooted, then basepath is
* unused. Ths violates any APR_FILEPATH_SECUREROOTTEST
* and APR_FILEPATH_NOTABSOLUTE flags specified.
*/
if (addtype == APR_EABSOLUTE || addtype == APR_EINCOMPLETE)
{
if (flags & APR_FILEPATH_SECUREROOTTEST)
return APR_EABOVEROOT;
if (flags & APR_FILEPATH_NOTABSOLUTE)
return addtype;
}
/* Optimized tests before we query the current working path
*/
if (!basepath) {
/* If APR_FILEPATH_NOTABOVEROOT wasn't specified,
* we won't test the root again, it's ignored.
* Waste no CPU retrieving the working path.
*/
if (addtype == APR_EABSOLUTE && !(flags & APR_FILEPATH_NOTABOVEROOT)) {
basepath = baseroot = "";
basetype = APR_ERELATIVE;
}
/* If APR_FILEPATH_NOTABSOLUTE is specified, the caller
* requires an absolutely relative result, So do not retrieve
* the working path.
*/
if (addtype == APR_ERELATIVE && (flags & APR_FILEPATH_NOTABSOLUTE)) {
basepath = baseroot = "";
basetype = APR_ERELATIVE;
}
}
if (!basepath)
{
/* Start with the current working path. This is bass akwards,
* but required since the compiler (at least vc) doesn't like
* passing the address of a char const* for a char** arg.
* We must grab the current path of the designated drive
* if addroot is given in drive-relative form (e.g. d:foo)
*/
char *getpath;
#ifndef NETWARE
if (addtype == APR_EINCOMPLETE && addroot[1] == ':')
rv = filepath_drive_get(&getpath, addroot[0], flags, p);
else
#endif
rv = apr_filepath_get(&getpath, flags, p);
if (rv != APR_SUCCESS)
return rv;
basepath = getpath;
}
if (!baseroot) {
/* This call should _not_ test the path
*/
basetype = apr_filepath_root(&baseroot, &basepath,
(flags & APR_FILEPATH_NATIVE), p);
if (basetype == APR_SUCCESS) {
basetype = APR_EABSOLUTE;
}
else if (basetype == APR_ERELATIVE) {
baseroot = "";
}
else if (basetype != APR_EINCOMPLETE) {
/* apr_filepath_root was incomprehensible so fail already
*/
return basetype;
}
}
baselen = strlen(basepath);
/* If APR_FILEPATH_NOTABSOLUTE is specified, the caller
* requires an absolutely relative result. If the given
* basepath is not relative then fail.
*/
if ((flags & APR_FILEPATH_NOTABSOLUTE) && basetype != APR_ERELATIVE)
return basetype;
/* The Win32 nightmare on unc street... start combining for
* many possible root combinations.
*/
if (addtype == APR_EABSOLUTE)
{
/* Ignore the given root path, and start with the addroot
*/
if ((flags & APR_FILEPATH_NOTABOVEROOT)
&& strncmp(baseroot, addroot, strlen(baseroot)))
return APR_EABOVEROOT;
keptlen = 0;
rootlen = pathlen = strlen(addroot);
memcpy(path, addroot, pathlen);
}
else if (addtype == APR_EINCOMPLETE)
{
/* There are several types of incomplete paths,
* incomplete UNC paths (//foo/ or //),
* drives without rooted paths (d: as in d:foo),
* and simple roots (/ as in /foo).
* Deal with these in significantly different manners...
*/
#ifndef NETWARE
if ((addroot[0] == '/' || addroot[0] == '\\') &&
(addroot[1] == '/' || addroot[1] == '\\'))
{
/* Ignore the given root path if the incomplete addpath is UNC,
* (note that the final result will be incomplete).
*/
if (flags & APR_FILEPATH_NOTRELATIVE)
return addtype;
if ((flags & APR_FILEPATH_NOTABOVEROOT)
&& strncmp(baseroot, addroot, strlen(baseroot)))
return APR_EABOVEROOT;
fixunc = 1;
keptlen = 0;
rootlen = pathlen = strlen(addroot);
memcpy(path, addroot, pathlen);
}
else
#endif
if ((addroot[0] == '/' || addroot[0] == '\\') && !addroot[1])
{
/* Bring together the drive or UNC root from the baseroot
* if the addpath is a simple root and basepath is rooted,
* otherwise disregard the basepath entirely.
*/
if (basetype != APR_EABSOLUTE && (flags & APR_FILEPATH_NOTRELATIVE))
return basetype;
if (basetype != APR_ERELATIVE) {
#ifndef NETWARE
if (basetype == APR_INCOMPLETE
&& (baseroot[0] == '/' || baseroot[0] == '\\')
&& (baseroot[1] == '/' || baseroot[1] == '\\'))
fixunc = 1;
#endif
keptlen = rootlen = pathlen = strlen(baseroot);
memcpy(path, baseroot, pathlen);
}
else {
if (flags & APR_FILEPATH_NOTABOVEROOT)
return APR_EABOVEROOT;
keptlen = 0;
rootlen = pathlen = strlen(addroot);
memcpy(path, addroot, pathlen);
}
}
#ifdef NETWARE
else if (filepath_has_drive(addroot, DRIVE_ONLY, p))
{
/* If the addroot is a drive (without a volume root)
* use the basepath _if_ it matches this drive letter!
* Otherwise we must discard the basepath.
*/
if (!filepath_compare_drive(addroot, baseroot, p) &&
filepath_has_drive(baseroot, 0, p)) {
#else
else if (addroot[0] && addroot[1] == ':' && !addroot[2])
{
/* If the addroot is a drive (without a volume root)
* use the basepath _if_ it matches this drive letter!
* Otherwise we must discard the basepath.
*/
if (addroot[0] == baseroot[0] && baseroot[1] == ':') {
#endif
/* Base the result path on the basepath
*/
if (basetype != APR_EABSOLUTE && (flags & APR_FILEPATH_NOTRELATIVE))
return basetype;
rootlen = strlen(baseroot);
keptlen = pathlen = rootlen + baselen;
if (keptlen >= sizeof(path))
return APR_ENAMETOOLONG;
memcpy(path, baseroot, rootlen);
memcpy(path + rootlen, basepath, baselen);
}
else {
if (flags & APR_FILEPATH_NOTRELATIVE)
return addtype;
if (flags & APR_FILEPATH_NOTABOVEROOT)
return APR_EABOVEROOT;
keptlen = 0;
rootlen = pathlen = strlen(addroot);
memcpy(path, addroot, pathlen);
}
}
else {
/* Now this is unexpected, we aren't aware of any other
* incomplete path forms! Fail now.
*/
return APR_EBADPATH;
}
}
else { /* addtype == APR_ERELATIVE */
/* If both paths are relative, fail early
*/
if (basetype != APR_EABSOLUTE && (flags & APR_FILEPATH_NOTRELATIVE))
return basetype;
#ifndef NETWARE
/* An incomplete UNC path must be completed
*/
if (basetype == APR_INCOMPLETE
&& (baseroot[0] == '/' || baseroot[0] == '\\')
&& (baseroot[1] == '/' || baseroot[1] == '\\'))
fixunc = 1;
#endif
/* Base the result path on the basepath
*/
rootlen = strlen(baseroot);
keptlen = pathlen = rootlen + baselen;
if (keptlen >= sizeof(path))
return APR_ENAMETOOLONG;
memcpy(path, baseroot, rootlen);
memcpy(path + rootlen, basepath, baselen);
}
/* '/' terminate the given root path unless it's already terminated
* or is an incomplete drive root. Correct the trailing slash unless
* we have an incomplete UNC path still to fix.
*/
if (pathlen && path[pathlen - 1] != ':') {
if (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\') {
if (pathlen + 1 >= sizeof(path))
return APR_ENAMETOOLONG;
path[pathlen++] = ((flags & APR_FILEPATH_NATIVE) ? '\\' : '/');
}
/* XXX: wrong, but gotta figure out what I intended;
* else if (!fixunc)
* path[pathlen++] = ((flags & APR_FILEPATH_NATIVE) ? '\\' : '/');
*/
}
while (*addpath)
{
/* Parse each segment, find the closing '/'
*/
seglen = 0;
while (addpath[seglen] && addpath[seglen] != '/'
&& addpath[seglen] != '\\')
++seglen;
/* Truncate all trailing spaces and all but the first two dots */
segend = seglen;
while (seglen && (addpath[seglen - 1] == ' '
|| addpath[seglen - 1] == '.')) {
if (seglen > 2 || addpath[seglen - 1] != '.' || addpath[0] != '.')
--seglen;
else
break;
}
if (seglen == 0 || (seglen == 1 && addpath[0] == '.'))
{
/* NOTE: win32 _hates_ '/ /' and '/. /' (yes, with spaces in there)
* so eliminate all preconceptions that it is valid.
*/
if (seglen < segend)
return APR_EBADPATH;
#ifndef NETWARE
/* This isn't legal unless the unc path is completed
*/
if (fixunc)
return APR_EBADPATH;
#endif
/* Otherwise, this is a noop segment (/ or ./) so ignore it
*/
}
else if (seglen == 2 && addpath[0] == '.' && addpath[1] == '.')
{
/* NOTE: win32 _hates_ '/.. /' (yes, with a space in there)
* and '/..../', some functions treat it as ".", and some
* fail! Eliminate all preconceptions that they are valid.
*/
if (seglen < segend && (seglen != 3 || addpath[2] != '.'))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -