diff options
author | William A. Rowe Jr <wrowe@apache.org> | 2001-03-31 06:22:38 +0000 |
---|---|---|
committer | William A. Rowe Jr <wrowe@apache.org> | 2001-03-31 06:22:38 +0000 |
commit | 758ce25c9b64e73f70da21c1e727016cd4f6a1aa (patch) | |
tree | a5fef39ae8dc38d53cc928eee146baa2d9548d1e /file_io/unix/filepath.c | |
parent | 6ab7815c79d1478147f25c774c656cfea1fe3f5a (diff) | |
download | apr-758ce25c9b64e73f70da21c1e727016cd4f6a1aa.tar.gz apr-758ce25c9b64e73f70da21c1e727016cd4f6a1aa.zip |
First draft implementation of unix apr_filepath_ get, set, merge, and
parse_root. [William Rowe]
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@61403 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'file_io/unix/filepath.c')
-rw-r--r-- | file_io/unix/filepath.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/file_io/unix/filepath.c b/file_io/unix/filepath.c new file mode 100644 index 000000000..66df39565 --- /dev/null +++ b/file_io/unix/filepath.c @@ -0,0 +1,317 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000-2001 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +#include "apr.h" +#include "fileio.h" +#include "apr_file_io.h" +#include "apr_strings.h" +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <direct.h> + + +/* Any OS that requires/refuses trailing slashes should be delt with here. + */ +APR_DECLARE(apr_status_t) apr_filepath_get(char **defpath, 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; +} + + +/* Any OS that requires/refuses trailing slashes should be delt with here + */ +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_parse_root(const char **rootpath, + const char **inpath, + apr_pool_t *p) +{ + if (**inpath == '/') + { + *rootpath = apr_pstrdup(p, "/"); + ++*inpath; + return APR_EABSOLUTE; + } + + 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_PATH_MAX]; + apr_size_t rootlen; /* is the original rootpath len */ + apr_size_t newseg; /* is the path offset to the added path */ + apr_size_t addseg; /* is the path offset we are appending at */ + apr_size_t endseg; /* is the end of the current segment */ + apr_status_t rv; + + /* Treat null as an empty path. + */ + if (!addpath) + addpath = ""; + + if (addpath[0] == '/') + { + /* If addpath is rooted, then rootpath is unused. + * Ths violates any APR_FILEPATH_SECUREROOTTEST and + * APR_FILEPATH_NOTABSOLUTE flags specified. + */ + if (flags & APR_FILEPATH_SECUREROOTTEST) + return APR_EABOVEROOT; + if (flags & APR_FILEPATH_NOTABSOLUTE) + return APR_EABSOLUTE; + + /* 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 (!rootpath && !(flags & APR_FILEPATH_NOTABOVEROOT)) + rootpath = ""; + } + else + { + /* If APR_FILEPATH_NOTABSOLUTE is specified, the caller + * requires a relative result. If the rootpath is + * ommitted, we do not retrieve the working path, + * if rootpath was supplied as absolute then fail. + */ + if (flags & APR_FILEPATH_NOTABSOLUTE) + { + if (!rootpath) + rootpath = ""; + else if (rootpath[0] == '/') + return APR_EABSOLUTE; + } + } + + if (!rootpath) + { + /* 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. + */ + char *getpath; + rv = apr_filepath_get(&getpath, p); + rootpath = getpath; + if (rv != APR_SUCCESS) + return errno; + + /* XXX: Any kernel subject to goofy, uncanonical results + * must run the rootpath against the user's given flags. + * Simplest would be a recursive call to apr_filepath_merge + * with an empty (not null) rootpath and addpath of the cwd. + */ + } + + rootlen = strlen(rootpath); + + if (addpath[0] == '/') + { + /* Ignore the given root path, strip off leading + * '/'s to a single leading '/' from the addpath, + * and leave addpath at the first non-'/' character. + */ + newseg = 0; + while (addpath[0] == '/') + ++addpath; + strcpy (path, "/"); + addseg = 1; + } + else + { + /* If both paths are relative, fail early + */ + if (rootpath[0] != '/' && (flags & APR_FILEPATH_NOTRELATIVE)) + return APR_ERELATIVE; + + /* Base the result path on the rootpath + */ + newseg = rootlen; + if (rootlen >= sizeof(path)) + return APR_ENAMETOOLONG; + strcpy(path, rootpath); + + /* Always '/' terminate the given root path + */ + if (newseg && path[newseg - 1] != '/') { + if (newseg + 1 >= sizeof(path)) + return APR_ENAMETOOLONG; + path[newseg++] = '/'; + path[newseg] = '\0'; + } + addseg = newseg; + } + + while (*addpath) + { + /* Parse each segment, find the closing '/' + */ + endseg = 0; + while (addpath[endseg] && addpath[endseg] != '/') + ++endseg; + + if (endseg == 0 || (endseg == 1 && addpath[0] == '.')) + { + /* noop segment (/ or ./) so skip it + */ + } + else if (endseg == 2 && addpath[0] == '.' && addpath[1] == '.') + { + /* backpath (../) */ + if (addseg == 1 && path[0] == '/') + { + /* 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. + * Flag that rootpath was entirely replaced. + */ + newseg = 0; + } + else if (addseg == 0 || (addseg >= 3 + && strcmp(path + addseg - 3, "../") == 0)) + { + /* Path is already backpathed or empty, if the + * APR_FILEPATH_SECUREROOTTEST.was given die now. + */ + if (flags & APR_FILEPATH_SECUREROOTTEST) + return APR_EABOVEROOT; + + /* Otherwise append another backpath. + */ + if (addseg + 3 >= sizeof(path)) + return APR_ENAMETOOLONG; + strcpy(path + addseg, "../"); + addseg += 3; + } + else + { + /* otherwise crop the prior segment + */ + do { + --addseg; + } while (addseg && path[addseg - 1] != '/'); + path[addseg] = '\0'; + } + + /* Now test if we are above where we started and back up + * the newseg offset to reflect the added/altered path. + */ + if (addseg < newseg) + { + if (flags & APR_FILEPATH_SECUREROOTTEST) + return APR_EABOVEROOT; + newseg = addseg; + } + } + else + { + /* An actual segment, append it to the destination path + */ + apr_size_t i = (addpath[endseg] != '\0'); + if (addseg + endseg + i >= sizeof(path)) + return APR_ENAMETOOLONG; + strncpy(path + addseg, addpath, endseg + i); + addseg += endseg + i; + } + + /* Skip over trailing slash to the next segment + */ + if (addpath[endseg]) + ++endseg; + + addpath += endseg; + } + + /* newseg will be the rootlen unless the addpath contained + * backpath elements. If so, and APR_FILEPATH_NOTABOVEROOT + * is specified (APR_FILEPATH_SECUREROOTTEST was caught above), + * compare the original root to assure the result path is + * still within given root path. + */ + if ((flags & APR_FILEPATH_NOTABOVEROOT) && newseg < rootlen) { + if (strncmp(rootpath, path, rootlen)) + return APR_EABOVEROOT; + if (rootpath[rootlen - 1] != '/' + && path[rootlen] && path[rootlen] != '/') + return APR_EABOVEROOT; + } + + *newpath = apr_pstrdup(p, path); + return (newpath ? APR_SUCCESS : APR_ENOMEM); +}
\ No newline at end of file |