#include "apr.h"
#include "apr_private.h"
#include "apr_arch_file_io.h"
#include "apr_file_io.h"
#include "apr_strings.h"
#define APR_WANT_STRFUNC
#include "apr_want.h"
#if APR_HAVE_UNISTD_H
#include <unistd.h>
#endif
#if APR_HAVE_DIRENT_H
#include <dirent.h>
#endif
APR_DECLARE(apr_status_t) apr_filepath_get(char **defpath, apr_int32_t flags,
apr_pool_t *p)
{
char path[APR_PATH_MAX];
if (!getcwd(path, sizeof(path))) {
if (errno == ERANGE)
return APR_ENAMETOOLONG;
else
return errno;
}
*defpath = apr_pstrdup(p, path);
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_filepath_set(const char *path, apr_pool_t *p)
{
if (chdir(path) != 0)
return errno;
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath,
const char **inpath,
apr_int32_t flags,
apr_pool_t *p)
{
if (**inpath == '/') {
*rootpath = apr_pstrdup(p, "/");
do {
++(*inpath);
} while (**inpath == '/');
return APR_SUCCESS;
}
return APR_ERELATIVE;
}
APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath,
const char *rootpath,
const char *addpath,
apr_int32_t flags,
apr_pool_t *p)
{
char *path;
apr_size_t rootlen;
apr_size_t maxlen;
apr_size_t keptlen;
apr_size_t pathlen;
apr_size_t seglen;
apr_status_t rv;
if (!addpath)
addpath = "";
if (addpath[0] == '/') {
if (flags & APR_FILEPATH_SECUREROOTTEST)
return APR_EABOVEROOT;
if (flags & APR_FILEPATH_NOTABSOLUTE)
return APR_EABSOLUTE;
if (!rootpath && !(flags & APR_FILEPATH_NOTABOVEROOT))
rootpath = "";
}
else {
if (flags & APR_FILEPATH_NOTABSOLUTE) {
if (!rootpath)
rootpath = "";
else if (rootpath[0] == '/')
return APR_EABSOLUTE;
}
}
if (!rootpath) {
char *getpath;
rv = apr_filepath_get(&getpath, flags, p);
rootpath = getpath;
if (rv != APR_SUCCESS)
return errno;
}
rootlen = strlen(rootpath);
maxlen = rootlen + strlen(addpath) + 4;
if (maxlen > APR_PATH_MAX) {
return APR_ENAMETOOLONG;
}
path = (char *)apr_palloc(p, maxlen);
if (addpath[0] == '/') {
keptlen = 0;
while (addpath[0] == '/')
++addpath;
path[0] = '/';
pathlen = 1;
}
else {
if (rootpath[0] != '/' && (flags & APR_FILEPATH_NOTRELATIVE))
return APR_ERELATIVE;
keptlen = rootlen;
memcpy(path, rootpath, rootlen);
if (keptlen && path[keptlen - 1] != '/') {
path[keptlen++] = '/';
}
pathlen = keptlen;
}
while (*addpath) {
const char *next = addpath;
while (*next && (*next != '/')) {
++next;
}
seglen = next - addpath;
if (seglen == 0 || (seglen == 1 && addpath[0] == '.')) {
}
else if (seglen == 2 && addpath[0] == '.' && addpath[1] == '.') {
if (pathlen == 1 && path[0] == '/') {
if (flags & APR_FILEPATH_SECUREROOTTEST) {
return APR_EABOVEROOT;
}
keptlen = 0;
}
else if (pathlen == 0
|| (pathlen == 3
&& !memcmp(path + pathlen - 3, "../", 3))
|| (pathlen > 3
&& !memcmp(path + pathlen - 4, "/../", 4))) {
if (flags & APR_FILEPATH_SECUREROOTTEST) {
return APR_EABOVEROOT;
}
memcpy(path + pathlen, "../", *next ? 3 : 2);
pathlen += *next ? 3 : 2;
}
else {
do {
--pathlen;
} while (pathlen && path[pathlen - 1] != '/');
}
if (pathlen < keptlen) {
if (flags & APR_FILEPATH_SECUREROOTTEST) {
return APR_EABOVEROOT;
}
keptlen = pathlen;
}
}
else {
if (*next) {
seglen++;
}
memcpy(path + pathlen, addpath, seglen);
pathlen += seglen;
}
if (*next) {
++next;
}
addpath = next;
}
path[pathlen] = '\0';
if ((flags & APR_FILEPATH_NOTABOVEROOT) && keptlen < rootlen) {
if (strncmp(rootpath, path, rootlen)) {
return APR_EABOVEROOT;
}
if (rootpath[rootlen - 1] != '/'
&& path[rootlen] && path[rootlen] != '/') {
return APR_EABOVEROOT;
}
}
*newpath = path;
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 defined(DARWIN)
*style = APR_FILEPATH_ENCODING_UTF8;
#else
*style = APR_FILEPATH_ENCODING_LOCALE;
#endif
return APR_SUCCESS;
}