📄 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_stat(&finfo, path, APR_FINFO_LINK | 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 + -