You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by wr...@apache.org on 2001/03/31 08:22:38 UTC

cvs commit: apr/file_io/unix filepath.c Makefile.in

wrowe       01/03/30 22:22:38

  Modified:    .        CHANGES
               include  apr_file_info.h
               file_io/unix Makefile.in
  Added:       file_io/unix filepath.c
  Log:
    First draft implementation of unix apr_filepath_ get, set, merge, and
    parse_root.  [William Rowe]
  
  Revision  Changes    Path
  1.77      +3 -0      apr/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apr/CHANGES,v
  retrieving revision 1.76
  retrieving revision 1.77
  diff -u -r1.76 -r1.77
  --- CHANGES	2001/03/31 05:52:41	1.76
  +++ CHANGES	2001/03/31 06:22:37	1.77
  @@ -1,5 +1,8 @@
   Changes with APR b1  
   
  +  *) First draft implementation of apr_filepath (get/set/parse_root
  +     and merge) for Unix.  [William Rowe]
  +
     *) Add apr_ipsubnet_create() and apr_ipsubnet_test() for testing
        whether or not an address is within a subnet.  [Jeff Trawick]
   
  
  
  
  1.15      +41 -4     apr/include/apr_file_info.h
  
  Index: apr_file_info.h
  ===================================================================
  RCS file: /home/cvs/apr/include/apr_file_info.h,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- apr_file_info.h	2001/03/24 04:22:36	1.14
  +++ apr_file_info.h	2001/03/31 06:22:37	1.15
  @@ -291,6 +291,25 @@
    */
   #define APR_FILEPATH_TRUENAME       0x20
   
  +/**
  + * Extract the rootpath from the given filepath
  + * @param rootpath the root file path returned with APR_SUCCESS or APR_EINCOMPLETE
  + * @param filepath the pathname to parse for it's root component
  + * @param p the pool to allocate the new path string from
  + * @deffunc apr_status_t apr_filepath_root(const char **rootpath, const char **inpath, apr_pool_t *p)
  + * @tip on return, filepath now points to the character following the root.
  + * In the simplest example, given a filepath of "/foo", returns the rootpath
  + * of "/" and filepath points at "foo".  This is far more complex on other 
  + * platforms, which even changes alternate format of rootpath to canonical
  + * form.  The function returns APR_ERELATIVE if filepath isn't rooted (an
  + * error), APR_EINCOMPLETE if the root path is ambigious (but potentially
  + * legitimate, e.g. "/" on Windows is incomplete because it doesn't specify
  + * the drive letter), or APR_EBADPATH if the root is simply invalid.
  + * APR_SUCCESS is returned if filepath is an absolute path.
  + */
  +APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath, 
  +                                            const char **filepath, 
  +                                            apr_pool_t *p);
   
   /**
    * Merge additional file path onto the previously processed rootpath
  @@ -301,10 +320,28 @@
    * @param p the pool to allocate the new path string from
    * @deffunc apr_status_t apr_filepath_merge(char **newpath, const char *rootpath, const char *addpath, apr_int32_t flags, apr_pool_t *p)
    */                        
  -APR_DECLARE(apr_status_t) 
  -                apr_filepath_merge(char **newpath, const char *rootpath,
  -                                   const char *addpath, apr_int32_t flags,
  -                                   apr_pool_t *p);
  +APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath, 
  +                                             const char *rootpath,
  +                                             const char *addpath, 
  +                                             apr_int32_t flags,
  +                                             apr_pool_t *p);
  +
  +/**
  + * Return the default file path (for relative file names)
  + * @param path the default path string returned
  + * @param p the pool to allocate the default path string from
  + * @deffunc apr_status_t apr_filepath_get(char **path, apr_pool_t *p)
  + */
  +APR_DECLARE(apr_status_t) apr_filepath_get(char **path, apr_pool_t *p);
  +
  +/**
  + * Set the default file path (for relative file names)
  + * @param path the default path returned
  + * @param p the pool to allocate any working storage
  + * @deffunc apr_status_t apr_filepath_get(char **defpath, apr_pool_t *p)
  + */
  +APR_DECLARE(apr_status_t) apr_filepath_set(const char *path, apr_pool_t *p);
  +
   
   #ifdef __cplusplus
   }
  
  
  
  1.23      +1 -0      apr/file_io/unix/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  RCS file: /home/cvs/apr/file_io/unix/Makefile.in,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- Makefile.in	2001/02/21 15:51:42	1.22
  +++ Makefile.in	2001/03/31 06:22:38	1.23
  @@ -3,6 +3,7 @@
   	dir.lo \
   	fileacc.lo \
   	filedup.lo \
  +	filepath.lo \
   	filestat.lo \
   	flock.lo \
   	fullrw.lo \
  
  
  
  1.1                  apr/file_io/unix/filepath.c
  
  Index: filepath.c
  ===================================================================
  /* ====================================================================
   * 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);
  }
  
  

Re: cvs commit: apr/file_io/unix filepath.c Makefile.in

Posted by Greg Stein <gs...@lyra.org>.
On Sat, Mar 31, 2001 at 06:22:38AM -0000, wrowe@apache.org wrote:
>...
>   +/**
>   + * Extract the rootpath from the given filepath
>   + * @param rootpath the root file path returned with APR_SUCCESS or APR_EINCOMPLETE
>   + * @param filepath the pathname to parse for it's root component
>   + * @param p the pool to allocate the new path string from
>   + * @deffunc apr_status_t apr_filepath_root(const char **rootpath, const char **inpath, apr_pool_t *p)
>   + * @tip on return, filepath now points to the character following the root.
>   + * In the simplest example, given a filepath of "/foo", returns the rootpath
>   + * of "/" and filepath points at "foo".  This is far more complex on other 
>   + * platforms, which even changes alternate format of rootpath to canonical
>   + * form.  The function returns APR_ERELATIVE if filepath isn't rooted (an
>   + * error), APR_EINCOMPLETE if the root path is ambigious (but potentially
>   + * legitimate, e.g. "/" on Windows is incomplete because it doesn't specify
>   + * the drive letter), or APR_EBADPATH if the root is simply invalid.
>   + * APR_SUCCESS is returned if filepath is an absolute path.
>   + */

I don't think it should ever return APR_EINCOMPLETE. If there is no drive
letter, then it should just return APR_ERELATIVE.

And don't say "current drive" because then you could say "current
directory." There is no effective difference between them.

>...
>   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;
>   }

Euh... I expected rootpath to be "/foo/bar/" if it was passed "/foo/bar/baz"
Is the above function just a first hack, or was the intent to only return a
single "/" ??

If it *is* just a first hack, then you MUST leave a comment in there.
Otherwise, you get people (like me) wondering wtf is going on in there.

>   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 */

"addseg" is more descriptive as "pathlen", the current path length.

>       apr_size_t endseg;  /* is the end of the current segment */

And this would be "seglen".

>       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);

memcpy(path, rootpath, rootlen);
path[rootlen] = '/0';

Might be faster. Definitely faster if you don't need to null-term.

Hmm. Looking at the code, you don't need the null-term until the very end.
You could null-term when the while-loop exits. Until then, use memcpy()
everywhere for speed.

>           /* 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))

The above test isn't strong enough. It could misfire on "/foo../". You need
to check for "whatever/../" and "../".

>               {
>                   /* 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, "../");

memcpy(path + addseg, "../", 3);

>                   addseg += 3;
>               }
>               else 
>               {
>                   /* otherwise crop the prior segment 
>                    */
>                   do {
>                       --addseg;
>                   } while (addseg && path[addseg - 1] != '/');
>                   path[addseg] = '\0';

Null-term not needed.

>               }
>   
>               /* 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);

strncpy() doesn't always null-terminate. In the above code, it definitely
does not. Therefore, you'd want to use:

memcpy(path + addseg, addpath, endseg + i);

and then after the next line:

>               addseg += endseg + i;

path[addseg] = '\0';

>           }
>   
>           /* 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);

newpath will always be != NULL, so this test is unneeded.

Cheers,
-g

-- 
Greg Stein, http://www.lyra.org/