You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by David Reid <dr...@jetnet.co.uk> on 2001/03/03 16:55:29 UTC

apr_realpath

Did we ever get a point of agreeing if we wanted to add apr_realpath?  I
seem to have deleted the emails concerning it but ISTR that there was a
patch?

david


Re: apr_realpath

Posted by Kevin Pilch-Bisson <ke...@pilch-bisson.net>.
On Wed, Mar 14, 2001 at 12:34:39PM -0600, cmpilato@collab.net wrote:
> Kevin Pilch-Bisson <ke...@pilch-bisson.net> writes:
> 
> > Sorry, I think it has to do with the way mutt handles pgp signing
> > messages.  I'm not going to sign this one, so hopefully it won't do so.
> > 
> > Offhand, which pathetic win32 client.
> 
> X-Mailer: Microsoft Outlook Express 5.50.4133.2400
> 
> Just a guess. :-)
> 
Doh! I have ignores set up for most standard mail headers.

Don't I feel silly.
> 

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kevin Pilch-Bisson                    http://www.pilch-bisson.net
     "Historically speaking, the presences of wheels in Unix
     has never precluded their reinvention." - Larry Wall
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Re: apr_realpath

Posted by cm...@collab.net.
Kevin Pilch-Bisson <ke...@pilch-bisson.net> writes:

> Sorry, I think it has to do with the way mutt handles pgp signing
> messages.  I'm not going to sign this one, so hopefully it won't do so.
> 
> Offhand, which pathetic win32 client.

X-Mailer: Microsoft Outlook Express 5.50.4133.2400

Just a guess. :-)



Re: apr_realpath

Posted by Kevin Pilch-Bisson <ke...@pilch-bisson.net>.
On Wed, Mar 14, 2001 at 03:29:49PM -0600, William A. Rowe, Jr. wrote:
> From: "Kevin Pilch-Bisson" <ke...@pilch-bisson.net>
> Sent: Wednesday, March 14, 2001 3:08 PM
> 
> 
> > > > Would there be a way to convert an incomplete path to a complete path?
> > > > (change drive to c:, getpwd, append foo, in the above example)
> > > 
> > > That is what apr_filepath_merge does for you.  You can pass a partial root [/ or d:]
> > > apr_filepath_root over to apr_filepath_merge as the addpath (with a null root).  That
> > > will return a true root.  apr_filepath_root is as much to help apr_filepath_merge
> > > (and any other app) break apart the root from a name, since the root is very platform
> > > specific (moreso than any other part of this debate.)  Look at netware machine/sys:/
> > > versus win32/os2, toss in unc names and unix remote volumes and ugh, what a mess.
> > > 
> > I believe you, I am just a little confused as to the process.  Say I do
> > the following:
> > 
> > C:\mywork\subversion\ > svn commit C:foo
> > 
> > which eventually reaches the following code.
> > 
> > char added_path[][] = { "C:foo", NULL };
> > (or should this be { "C:", "foo", NULL }; ?)
> > char *newpath;
> > apr_filepath_merge(&newpath, NULL, added_path, APR_FILEPATH_TRUEPATH, p);
> > 
> > What do I get back from apr_filepath_merge?  Or more to the point, how
> > can I get C:\mywork\subversion\foo as newpath?
> 
> Simply, rootpath == NULL uses CWD, therefore c:\mywork\subversion.
> 
> 
> char *newpath = "foo"
> char **addpath = &newpath
> char **newpath;
> 
> apr_filepath_merge(&newpath, NULL, addpath, APR_FILEPATH_TRUEPATH, p);
> 
> If foo exists, newpath == "c:\mywork\subversion\foo", and addpath += 4
> (points to the trailing NULL of the string you passed).
> 
> If foo is not found, newpath == "c:\mywork\subversion\" and addpath didn't
> change (the path wasn't found.
> 
> If you pass "foo/bar" as addpath, and foo exists, then ".../foo/" is retured
> for newpath, and addpath += 4 (pointing at "bar") if bar was not found.
> 
> Of course, without APR_FILEPATH_TRUEPATH, the whole thing just returns, and
> doesn't care if the path names are real.  With APR_FILEPATH_TRUECASE, those
> parts that exist are returned with the correct case followed by the remaining
> given path, since it also doesn't care if the files exist, only that the
> names that exist are the proper case.  Both of these would set point addpath
> to it's own trailing NULL.
> 
> The Q. remains, do we want char** addpath, or simply a char* with no feedback
> of existing v.s. nonexisting path components?
> 
> Bill
> 
> 
Right.  Now say the target was D:foo, but my current drive was C:, as in
D:\mywork\subversion> C:
C:\Program Files\Subversion> svn commit D:foo

How do I find out that D:foo is really D:\mywork\subversion\foo?

On another note, I thought of another root case to be handled under
UNIX.  Cygwin with windows drives.  I.e. / is %SYSDRIVE%:\, but //c/ is
C:\ and //d/ is D:\.  The double slashes are important to cygwin.

What a PITA.  Sometimes I don't know whether I am glad for cygwin
because it makes having to use 'Doze at work less annoying, or pissed of
because of the hassle it makes for real unix development!
-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kevin Pilch-Bisson                    http://www.pilch-bisson.net
     "Historically speaking, the presences of wheels in Unix
     has never precluded their reinvention." - Larry Wall
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Re: apr_realpath

Posted by "William A. Rowe, Jr." <wr...@rowe-clan.net>.
From: "Kevin Pilch-Bisson" <ke...@pilch-bisson.net>
Sent: Wednesday, March 14, 2001 3:08 PM


> > > Would there be a way to convert an incomplete path to a complete path?
> > > (change drive to c:, getpwd, append foo, in the above example)
> > 
> > That is what apr_filepath_merge does for you.  You can pass a partial root [/ or d:]
> > apr_filepath_root over to apr_filepath_merge as the addpath (with a null root).  That
> > will return a true root.  apr_filepath_root is as much to help apr_filepath_merge
> > (and any other app) break apart the root from a name, since the root is very platform
> > specific (moreso than any other part of this debate.)  Look at netware machine/sys:/
> > versus win32/os2, toss in unc names and unix remote volumes and ugh, what a mess.
> > 
> I believe you, I am just a little confused as to the process.  Say I do
> the following:
> 
> C:\mywork\subversion\ > svn commit C:foo
> 
> which eventually reaches the following code.
> 
> char added_path[][] = { "C:foo", NULL };
> (or should this be { "C:", "foo", NULL }; ?)
> char *newpath;
> apr_filepath_merge(&newpath, NULL, added_path, APR_FILEPATH_TRUEPATH, p);
> 
> What do I get back from apr_filepath_merge?  Or more to the point, how
> can I get C:\mywork\subversion\foo as newpath?

Simply, rootpath == NULL uses CWD, therefore c:\mywork\subversion.


char *newpath = "foo"
char **addpath = &newpath
char **newpath;

apr_filepath_merge(&newpath, NULL, addpath, APR_FILEPATH_TRUEPATH, p);

If foo exists, newpath == "c:\mywork\subversion\foo", and addpath += 4
(points to the trailing NULL of the string you passed).

If foo is not found, newpath == "c:\mywork\subversion\" and addpath didn't
change (the path wasn't found.

If you pass "foo/bar" as addpath, and foo exists, then ".../foo/" is retured
for newpath, and addpath += 4 (pointing at "bar") if bar was not found.

Of course, without APR_FILEPATH_TRUEPATH, the whole thing just returns, and
doesn't care if the path names are real.  With APR_FILEPATH_TRUECASE, those
parts that exist are returned with the correct case followed by the remaining
given path, since it also doesn't care if the files exist, only that the
names that exist are the proper case.  Both of these would set point addpath
to it's own trailing NULL.

The Q. remains, do we want char** addpath, or simply a char* with no feedback
of existing v.s. nonexisting path components?

Bill


Re: apr_realpath

Posted by Kevin Pilch-Bisson <ke...@pilch-bisson.net>.
On Wed, Mar 14, 2001 at 09:38:21AM -0600, William A. Rowe, Jr. wrote:
> From: "Kevin Pilch-Bisson" <ke...@pilch-bisson.net>
> Sent: Wednesday, March 14, 2001 7:48 AM
> 
> >> Attachment
> 
> Huge favor, if you would, look into why all your posts are going in as text file
> attachments?  At least they appear so on my pathetic Win32 email client.

Sorry, I think it has to do with the way mutt handles pgp signing
messages.  I'm not going to sign this one, so hopefully it won't do so.

Offhand, which pathetic win32 client.

> 
> To answer your questions:
> 
> apr_filepath_merge(char **newpath, char *rootpath, char **addedpath, APR_FILEPATH_TRUEPATH, p)
> 
> would allow us to take rootpath of '/usr/local/bin' and addedpath of 'apache/secure/conf',
> merge them into '/usr/local/bin/apache/' [an existing path] and leave addedpath pointing
> to 'secure/conf' [the non-existant portion of addedpath.]  The user can do whatever they like
> to make them work.

[snip explanation]

OOhhh, now I understand.  I like!

> 
> My only other 'simple' solution, if that flag is passed, is to append a second string following
> the null of the root string.  If they pass that flag, the user is guarenteed a second null 
> (even if the entire given path was existed, so the non-existant result is empty.)
> 
> Since that is alien to everything we have done in APR, I'm hesistant to try it.

No, no, no.  I don't like that at all.
> 
> 
> I didn't miss your question on comparing paths, we need to add these other functions:

Actually, for now I think I can do what I need with just
apr_filepath_merge, with NULL, rootpath arguments.  (We have existing
svn functions to do the rest, although in time they would probably be
re-worked to use the below).

> 
> apr_status_t apr_filepath_root(char** pathroot, char** name, apr_pool_t *p)
>     Which returns the canonical form of the pathroot and returns the first non-root
>     part of name (e.g. '/foo' is '/' 'foo' on unix, 'c:\foo' is 'c:\' 'foo' and
>     '//machine/share/foo' is '//machine/share/' 'foo' on win32)
>     Handles incomplete roots ('c:foo' on win32 is 'c:', 'foo', but returns a status
>     of APR_EINCOMPLETE).

Would there be a way to convert an incomplete path to a complete path?
(change drive to c:, getpwd, append foo, in the above example)
> 
> apr_status_t apr_filepath_elements_count(int *n, char *path)
>     counts the elements given in the file path.  
>     [counts the root as one element]
> 
> apr_status_t apr_filepath_elements_get(char **segments, char *path, int first, int last, apr_pool_t *p)
>     returns the requested elements of the file path.
>     All even numbered elements are delimiters, so 0 is the delimited root,
>     1 is the first name, 2 is the delimiter, 3 is the second name.    
>     While more complex, this presupposes some platform could have a multi-byte
>     delimiter (unlikely, but consider a utf-8 path delimiter char that is more
>     than a single byte, not true of '/' or '\', but it's easier to code for it
>     now than change it later.)
> 
> The even/odd theory falls apart for relative paths like foo/bar unless we return an
> empty string for foo, so this needs more thought.

Will keep thinking about this.

> 
> apr_status_t apr_filepath_common(char** result, char* a, char* b, apr_pool_t *p)
>     returns the segments that match, comparing from the beginning.
>     The user must canonicalize the paths first with apr_filepath_merge.
>     /foo/bar compared to /foo/barstool  returns  /foo/
>     compare does not distinguish between '/' and '\' on win32/os2 - they compare equal.
>     If a and b were char**, we could point at the first uncommon element, but a strlen
>     of result provides the same answer, no?  [This isn't true of the above example that
>     is changing the case, eliminating trailing '.'s and ' 's from win32 names, and 
>     converting short aliases to true names).
> 
> Canonicalizing first to the truename is required before apr_filepath_common can be
> trusted on Win32 or OS2, since c:/thislongname/ is also c:/THISLO~1/

Canonicalizing is done by apr_filepath_merge, with NULL rootpath, right?
> 
> Bill

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kevin Pilch-Bisson                    http://www.pilch-bisson.net
     "Historically speaking, the presences of wheels in Unix
     has never precluded their reinvention." - Larry Wall
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Re: apr_realpath

Posted by Brian Havard <br...@kheldar.apana.org.au>.
On Wed, 14 Mar 2001 21:08:01 -0600, William A. Rowe, Jr. wrote:

>From: "Brian Havard" <br...@kheldar.apana.org.au>
>Sent: Wednesday, March 14, 2001 7:39 PM

>> Actually OS/2 does NOT have the long/short name crap that windows does.
>
>Good point.  Quick question ... it does have case insensitivty and drive/path (with
>current paths of each drive, correct?)  And it does or doesn't have unc notation 
>(sorry, I know you have answered that before, I get lost :-?)

Yes, all that's the same as Win32 along with trailing . and space
truncation.

-- 
 ______________________________________________________________________________
 |  Brian Havard                 |  "He is not the messiah!                   |
 |  brianh@kheldar.apana.org.au  |  He's a very naughty boy!" - Life of Brian |
 ------------------------------------------------------------------------------


Re: apr_realpath

Posted by "William A. Rowe, Jr." <ad...@rowe-clan.net>.
From: "Brian Havard" <br...@kheldar.apana.org.au>
Sent: Wednesday, March 14, 2001 7:39 PM


> On Wed, 14 Mar 2001 09:38:21 -0600, William A. Rowe, Jr. wrote:
> 
> [...]
> 
> >Canonicalizing first to the truename is required before apr_filepath_common can be
> >trusted on Win32 or OS2, since c:/thislongname/ is also c:/THISLO~1/
> 
> Actually OS/2 does NOT have the long/short name crap that windows does.

Good point.  Quick question ... it does have case insensitivty and drive/path (with
current paths of each drive, correct?)  And it does or doesn't have unc notation 
(sorry, I know you have answered that before, I get lost :-?)

Bill




Re: apr_realpath

Posted by Brian Havard <br...@kheldar.apana.org.au>.
On Wed, 14 Mar 2001 09:38:21 -0600, William A. Rowe, Jr. wrote:

[...]

>Canonicalizing first to the truename is required before apr_filepath_common can be
>trusted on Win32 or OS2, since c:/thislongname/ is also c:/THISLO~1/

Actually OS/2 does NOT have the long/short name crap that windows does.

-- 
 ______________________________________________________________________________
 |  Brian Havard                 |  "He is not the messiah!                   |
 |  brianh@kheldar.apana.org.au  |  He's a very naughty boy!" - Life of Brian |
 ------------------------------------------------------------------------------


Re: apr_realpath

Posted by "William A. Rowe, Jr." <wr...@rowe-clan.net>.
From: "Kevin Pilch-Bisson" <ke...@pilch-bisson.net>
Sent: Wednesday, March 14, 2001 7:48 AM

>> Attachment

Huge favor, if you would, look into why all your posts are going in as text file
attachments?  At least they appear so on my pathetic Win32 email client.

To answer your questions:

apr_filepath_merge(char **newpath, char *rootpath, char **addedpath, APR_FILEPATH_TRUEPATH, p)

would allow us to take rootpath of '/usr/local/bin' and addedpath of 'apache/secure/conf',
merge them into '/usr/local/bin/apache/' [an existing path] and leave addedpath pointing
to 'secure/conf' [the non-existant portion of addedpath.]  The user can do whatever they like
to make them work.

I'm insisting that rootpath has always been 'preaccepted' by whatever mechanism you are
using (processed with APR_FILEPATH_TRUEPATH flag set) and is never optimized, tested or
canonicalized.  Any Truepath/Truecase operation will be very expensive, and we never want
to repeat it once we have processed that path the first time.

Now the programmer can split the remaining addedpath by segments (a new apr function as well)
so they append 'secure' and call apr_dir_make.  Then append conf and (since there are no more
segments) call apr_dir_make or apr_file_open and do their damage.

An http server can take that remainder and chug it through whatever parsing they like.

My point is that we have the possibility of knowing the 'remainder' even if we are asking for
the existant elements by passing that flag.  

My only other 'simple' solution, if that flag is passed, is to append a second string following
the null of the root string.  If they pass that flag, the user is guarenteed a second null 
(even if the entire given path was existed, so the non-existant result is empty.)

Since that is alien to everything we have done in APR, I'm hesistant to try it.


I didn't miss your question on comparing paths, we need to add these other functions:

apr_status_t apr_filepath_root(char** pathroot, char** name, apr_pool_t *p)
    Which returns the canonical form of the pathroot and returns the first non-root
    part of name (e.g. '/foo' is '/' 'foo' on unix, 'c:\foo' is 'c:\' 'foo' and
    '//machine/share/foo' is '//machine/share/' 'foo' on win32)
    Handles incomplete roots ('c:foo' on win32 is 'c:', 'foo', but returns a status
    of APR_EINCOMPLETE).

apr_status_t apr_filepath_elements_count(int *n, char *path)
    counts the elements given in the file path.  
    [counts the root as one element]

apr_status_t apr_filepath_elements_get(char **segments, char *path, int first, int last, apr_pool_t *p)
    returns the requested elements of the file path.
    All even numbered elements are delimiters, so 0 is the delimited root,
    1 is the first name, 2 is the delimiter, 3 is the second name.    
    While more complex, this presupposes some platform could have a multi-byte
    delimiter (unlikely, but consider a utf-8 path delimiter char that is more
    than a single byte, not true of '/' or '\', but it's easier to code for it
    now than change it later.)

The even/odd theory falls apart for relative paths like foo/bar unless we return an
empty string for foo, so this needs more thought.

apr_status_t apr_filepath_common(char** result, char* a, char* b, apr_pool_t *p)
    returns the segments that match, comparing from the beginning.
    The user must canonicalize the paths first with apr_filepath_merge.
    /foo/bar compared to /foo/barstool  returns  /foo/
    compare does not distinguish between '/' and '\' on win32/os2 - they compare equal.
    If a and b were char**, we could point at the first uncommon element, but a strlen
    of result provides the same answer, no?  [This isn't true of the above example that
    is changing the case, eliminating trailing '.'s and ' 's from win32 names, and 
    converting short aliases to true names).

Canonicalizing first to the truename is required before apr_filepath_common can be
trusted on Win32 or OS2, since c:/thislongname/ is also c:/THISLO~1/

Bill





Re: apr_realpath

Posted by Kevin Pilch-Bisson <ke...@pilch-bisson.net>.
Here are some things I got from this.

On Tue, Mar 13, 2001 at 01:40:02AM -0600, William A. Rowe, Jr. wrote:
> Here is what I've worked up thus far for Unix... n'er mind the _more_ complicated
> Win32 beast [all I could do to get the _root_ parsing finished tonight!]
> 
> So feel free to look at the server root parse function, and the unix implementation
> of apr_filepath_merge(), and let me know if I've gone off in the wrong direction.
> 
> Survey; is there any reason -not- to canonicalize a name, ever (/./ elimination, etc)?

Not that I can think of.
> 
> Is there a decent semantic to append a missing trailing slash for a directory vs. a file?

Not sure exactly what you are asking.
> 
> Should we have a char** input argument for addpath (who cares about realpath) so that
> we can actually return the user the existing path, while incrementing the pointer to the
> start of the non-existinant path (a slow operation, by request only)?

Why?
> 
> Should we persist in forcing Win32 to use slashes, or should we return backslashes?

Subversion uses native path separators. I don't know what the rest of
APR/Apache do.
> 
> Last comment (not a q)... I will round out the Win32 code and add apr_pathname_segment()
> fn to pull apart a path, which is what I got out of kevin's request, and what I need
> for the Apache core.

Actually, I am looking for a function to portably, always get an absolut
path from a given string.  I'll try to give you a use case for it.  In
subversion, we have the idea of commits, where you can give a list of
targets on the command line.

kevin@pilchie:/home/kevin/repos$ svn commit file1 dir/file2 /home/kevin/repos/dir2/file3

From that command, we would like to be able to take the three file
arguments, and find out what is the deepest directory which is common to
all three targets, since that is where we have to start making changes
to our repository.  In the above example that would be
/home/kevin/repos.  We already have a function which takes a list of
(absolute) targets, finds the common part of the path, and converts the
other targets to relative paths from that base.  Now we need a portable
way to convert the targets given above into absolute paths.  The
problem we ran into is that while realpath exists on unix, and _fullpath
exists on win32, there is nothing (that we knew about anyway, on BeOS).
Also, realpath is known to be broken on some older versions of Solaris,
in that it merely canonicalizes a path if it is below the cwd.  For now,
we are just using realpath and _fullpath (and not putting our heads in
the sand with respect to Solaris and BeOS.

> 
> Bill
> 
> Index: file_io/unix/filepath.c
> ===================================================================
> RCS file: filepath.c
> diff -N filepath.c
> --- /dev/null Mon Mar 12 23:32:12 2001
> +++ filepath.c Mon Mar 12 23:32:23 2001
> @@ -0,0 +1,233 @@
> +/* ====================================================================
> + * 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>
> +
> +
> +APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath,
> +                                            const char **inpath, apr_pool_t *p)
> +{
> +    if (**inpath == '/') {
> +        *rootpath = apr_pstrdup(p, "/");
> +        ++*inpath;
> +        return APR_EABSOLUTE;
> +    }
> +
> +    *rootpath = apr_pstrdup(p, "");
> +    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 newseg, addseg, endseg, rootlen;
> +
> +    if (!rootpath) {
> +        /* Start with the current working path
> +         * XXX: Any kernel subject to goofy, uncanonical results
> +         * must test the cwd 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.
> +         */
> +        if (!(rootpath = getcwd(path, sizeof(path)))) {

Um, rootpath is const char *, should we be assigning values to it?

> +            if (errno == ERANGE)
> +                return APR_ENAMETOOLONG;
> +            else
> +                return errno;
> +        }
> +        newseg = strlen(rootpath);
> +    }
> +    else {
> +        /* Accept the given rootpath as pre-tested and simply append to it */
> +        newseg = strlen(rootpath);
> +        if (newseg >= sizeof(path))
> +            return APR_ENAMETOOLONG;
> +        strcpy(path, rootpath);
> +    }
> +
> +    rootlen = newseg;
> +
> +    /* tack on a trailing '/' if we have anything to append */
> +    if (newseg && addpath[0] && path[newseg - 1] != '/') {

what if addpath is NULL?

> +        path[newseg++] = '/';
> +        path[newseg] = '\0';
> +    }
> +
> +    addseg = newseg;
> +
> +    /* strip down leading '/'s to a single leading '/',
> +     * entirely replacing the root path.
> +     */

Why not test this before bothering to get the rootpath in the first
place?

> +    if (addpath[0] == '/') {
> +        if (flags & APR_FILEPATH_SECUREROOTTEST)
> +            return APR_EABOVEROOT;
> +        newseg = 0;
> +        strcpy (path, "/");
> +        addseg = 1;
> +        while (addpath[0])
> +            ++addpath;
> +    } else if (path[0] != '/') {
> +        if (flags & APR_FILEPATH_NOTRELATIVE)
> +            return APR_ERELATIVE;
> +    }
> +
> +    if (path[0] == '/' && (flags & APR_FILEPATH_NOTABSOLUTE))
> +        return APR_EABSOLUTE;
> +
> +    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] == '/') {
> +                /* above root?  die if we are fixated on security */
> +                if (flags & APR_FILEPATH_SECUREROOTTEST)
> +                    return APR_EABOVEROOT;
> +                /* otherwise a noop, above root is ... root */
> +                newseg = 0;
> +            }
> +            else if (addseg == 0 || (addseg >= 3
> +                                  && strcmp(path + addseg - 3, "../") == 0)) {
> +                /* already backpathed or empty, append a backpath unless
> +                 * the user insisten never to continue above the root.
> +                 */
> +                if (flags & APR_FILEPATH_SECUREROOTTEST)
> +                    return APR_EABOVEROOT;
> +                if (addseg + 3 >= sizeof(path))
> +                    return APR_ENAMETOOLONG;
> +                strcpy(path + addseg, "../");
> +                addseg += 3;
> +            }
> +            else {
> +                /* otherwise crop prior segment */
> +                do {
> +                    --addseg;
> +                } while (addseg && path[addseg - 1] != '/');
> +                path[addseg] = '\0';
> +            }
> +
> +            /* Now test if we are above where we started */
> +            if (addseg < newseg) {
> +                if (flags & APR_FILEPATH_SECUREROOTTEST)
> +                    return APR_EABOVEROOT;
> +                newseg = addseg;
> +            }
> +        }
> +        else {
> +            /* actual segment, append */
> +            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 */
> +        if (addpath[endseg])
> +            ++endseg;
> +
> +        addpath += endseg;
> +    }
> +
> +    if ((flags & APR_FILEPATH_NOTABOVEROOT) && newseg < rootlen) {
> +        /* If newseg moved back, the end result string must be tested
> +         * that it is still within the root.  Only the _SECUREROOT
> +         * option prohibits the user from 'testing' the absolute
> +         * location of a file by backing over and readding it.
> +         */
> +        if (strncmp(rootpath, path, rootlen))
> +            return APR_EABOVEROOT;
> +        if (rootpath[rootlen - 1] != '/'
> +                && path[rootlen] && path[rootlen] != '/')
> +            return APR_EABOVEROOT;
> +    }
> +
> +#if 0
> +    /* Just an idea - don't know where it's headed yet */
> +    if (addpath && addpath[endseg - 1] != '/'
> +                && (flags & APR_FILEPATH_TRUECASE)) {
> +        apr_finfo_t finfo;
> +        if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) == APR_SUCCESS) {
> +            if (addpath[endseg - 1] != finfo.filetype == APR_DIR) {
> +                if (endseg + 1 >= sizeof(path))
> +                    return APR_ENAMETOOLONG;
> +                path[endseg++] = '/';
> +                path[endseg] = '\0';
> +            }
> +        }
> +    }
> +#endif
> +
> +    /* Whew... */
> +    *newpath = apr_pstrdup(p, path);
> +    return (newpath ? APR_SUCCESS : APR_ENOMEM);
> +}
> Index: file_io/win32/filepath.c
> ===================================================================
> RCS file: filepath.c
> diff -N filepath.c
> --- /dev/null Mon Mar 12 23:32:12 2001
> +++ filepath.c Mon Mar 12 23:32:25 2001
> @@ -0,0 +1,357 @@
> +/* ====================================================================
> + * 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"
> +
> +
> +/* Win32 Exceptions:
> + *
> + * Note that trailing spaces and trailing periods are never recorded
> + * in the file system, except by a very obscure bug where any file
> + * that is created with a trailing space or period, followed by the
> + * ':' stream designator on an NTFS volume can never be accessed again.
> + * In other words, don't ever accept them if designating a stream!
> + *
> + * An interesting side effect is that two or three periods are both
> + * treated as the parent directory, although the fourth and on are
> + * not [strongly suggest all trailing periods are trimmed off, or
> + * down to two if there are no other characters.]
> + *
> + * Leading spaces and periods are accepted, however.
> + */
> +static int is_fnchar(char ch)
> +{
> +    /* No control code between 0 and 31 is allowed
> +     * The * < > ? codes all have wildcard effects
> +     * The " / \ : are exlusively separator tokens
> +     * The system doesn't accept | for any purpose.
> +     * Oddly, \x7f is acceptable.
> +     */
> +    if (ch >= 0 || ch < 32
> +        return 0;
> +
> +    if (ch == '\"' || ch ==  '*' || ch == '/'
> +     || ch ==  ':' || ch ==  '<' || ch == '>'
> +     || ch ==  '?' || ch == '\\' || ch == '|')
> +        return 0;
> +
> +    return 1;
> +}
> +
> +
> +APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath,
> +                                            const char **inpath, apr_pool_t *p)
> +{
> +    if (*inpath[0] == '/' || *inpath[0] == '\\') {
> +        if (*inpath[1] == '/' || *inpath[1] == '\\') {

What if you get /\blah, or \/blah?


All in all, I don't want to review this, since I don't know enough about
win32 path semantics.

[snip rest of win32 code]
> Index: include/apr_errno.h
> ===================================================================
> RCS file: /home/cvs/apr/include/apr_errno.h,v
> retrieving revision 1.54
> diff -u -r1.54 apr_errno.h
> --- include/apr_errno.h 2001/02/16 04:15:42 1.54
> +++ include/apr_errno.h 2001/03/13 07:32:36
> @@ -205,6 +205,10 @@
>   *                    platform, either because nobody has gotten to it yet,
>   *                    or the function is impossible on this platform.
>   * APR_EMISMATCH      Two passwords do not match.
> + * APR_EABSOLUTE      The given path was absolute.
> + * APR_ERELATIVE      The given path was relative.
> + * APR_EINCOMPLETE    The given path was neither relative nor absolute.
> + * APR_EABOVEROOT     The given path was above the root path.
>   * </PRE>
>   *
>   * @param status The APR_status code to check.
> @@ -236,6 +240,10 @@
>  /* empty slot: +17 */
>  /* empty slot: +18 */
>  #define APR_EDSOOPEN       (APR_OS_START_ERROR + 19)
> +#define APR_EABSOLUTE      (APR_OS_START_ERROR + 20)
> +#define APR_ERELATIVE      (APR_OS_START_ERROR + 21)
> +#define APR_EINCOMPLETE    (APR_OS_START_ERROR + 22)
> +#define APR_EABOVEROOT     (APR_OS_START_ERROR + 23)
> 
> 
>  /* APR ERROR VALUE TESTS */
> @@ -258,6 +266,10 @@
>  /* empty slot: +17 */
>  /* empty slot: +18 */
>  #define APR_STATUS_IS_EDSOOPEN(s)       ((s) == APR_EDSOOPEN)
> +#define APR_STATUS_IS_EABSOLUTE(s)      ((s) == APR_EABSOLUTE)
> +#define APR_STATUS_IS_ERELATIVE(s)      ((s) == APR_ERELATIVE)
> +#define APR_STATUS_IS_EINCOMPLETE(s)    ((s) == APR_EINCOMPLETE)
> +#define APR_STATUS_IS_EABOVEROOT(s)     ((s) == APR_EABOVEROOT)
> 
> 
>  /* APR STATUS VALUES */
> Index: include/apr_file_info.h
> ===================================================================
> RCS file: /home/cvs/apr/include/apr_file_info.h,v
> retrieving revision 1.13
> diff -u -r1.13 apr_file_info.h
> --- include/apr_file_info.h 2001/02/16 04:15:43 1.13
> +++ include/apr_file_info.h 2001/03/13 07:32:36
> @@ -246,7 +246,9 @@
> 
>  /**
>   * Read the next entry from the specified directory.
> - * @param thedir the directory descriptor to read from, and fill out.
> + * @param finfo the file info structure and filled in by apr_dir_read
> + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values
> + * @param thedir the directory descriptor returned from apr_dir_open
>   * @tip All systems return . and .. as the first two files.
>   * @deffunc apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, apr_dir_t *thedir)
>   */
> @@ -260,6 +262,49 @@
>   */
>  APR_DECLARE(apr_status_t) apr_dir_rewind(apr_dir_t *thedir);
> 
> +/* apr_filepath flags
> + */
> +
> +/* Cause apr_filepath_merge to fail if addpath is above rootpath */
> +#define APR_FILEPATH_NOTABOVEROOT   0x01
> +
> +/* internal: Only meaningful with APR_FILEPATH_NOTABOVEROOT */
> +#define APR_FILEPATH_SECUREROOTTEST 0x02
> +
> +/* Cause apr_filepath_merge to fail if addpath is above rootpath,
> + * even given a rootpath /foo/bar and an addpath ../bar/bash
> + */
> +#define APR_FILEPATH_SECUREROOT     0x03
> +
> +/* Fail apr_filepath_merge if the merged path is relative */
> +#define APR_FILEPATH_NOTRELATIVE    0x04
> +
> +/* Fail apr_filepath_merge if the merged path is absolute */
> +#define APR_FILEPATH_NOTABSOLUTE    0x08
> +
> +/* Cleans all ambigious /./  or // segments
> + * if the target is a directory */
> +#define APR_FILEPATH_CANONICAL      0x10
> +
> +/* Resolve the true case of existing directories and file elements
> + * of addpath, and append a proper trailing slash if a directory
> + */
> +#define APR_FILEPATH_TRUECASE       0x20
> +
> +
> +/**
> + * Merge additional file path onto the previously processed rootpath
> + * @param newpath the merged paths returned
> + * @param rootpath the root file path (NULL uses the current working path)
> + * @param addpath the path to add to the root path
> + * @param flags the desired APR_FILEPATH_ rules to apply when merging
> + * @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);
> 
>  #ifdef __cplusplus
>  }
> 
> 
> 
> 
> 

Have fun with this :)

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kevin Pilch-Bisson                    http://www.pilch-bisson.net
     "Historically speaking, the presences of wheels in Unix
     has never precluded their reinvention." - Larry Wall
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Re: apr_realpath

Posted by "William A. Rowe, Jr." <ad...@rowe-clan.net>.
Here is what I've worked up thus far for Unix... n'er mind the _more_ complicated
Win32 beast [all I could do to get the _root_ parsing finished tonight!]

So feel free to look at the server root parse function, and the unix implementation
of apr_filepath_merge(), and let me know if I've gone off in the wrong direction.

Survey; is there any reason -not- to canonicalize a name, ever (/./ elimination, etc)?

Is there a decent semantic to append a missing trailing slash for a directory vs. a file?

Should we have a char** input argument for addpath (who cares about realpath) so that
we can actually return the user the existing path, while incrementing the pointer to the
start of the non-existinant path (a slow operation, by request only)?

Should we persist in forcing Win32 to use slashes, or should we return backslashes?

Last comment (not a q)... I will round out the Win32 code and add apr_pathname_segment()
fn to pull apart a path, which is what I got out of kevin's request, and what I need
for the Apache core.

Bill

Index: file_io/unix/filepath.c
===================================================================
RCS file: filepath.c
diff -N filepath.c
--- /dev/null Mon Mar 12 23:32:12 2001
+++ filepath.c Mon Mar 12 23:32:23 2001
@@ -0,0 +1,233 @@
+/* ====================================================================
+ * 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>
+
+
+APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath,
+                                            const char **inpath, apr_pool_t *p)
+{
+    if (**inpath == '/') {
+        *rootpath = apr_pstrdup(p, "/");
+        ++*inpath;
+        return APR_EABSOLUTE;
+    }
+
+    *rootpath = apr_pstrdup(p, "");
+    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 newseg, addseg, endseg, rootlen;
+
+    if (!rootpath) {
+        /* Start with the current working path
+         * XXX: Any kernel subject to goofy, uncanonical results
+         * must test the cwd 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.
+         */
+        if (!(rootpath = getcwd(path, sizeof(path)))) {
+            if (errno == ERANGE)
+                return APR_ENAMETOOLONG;
+            else
+                return errno;
+        }
+        newseg = strlen(rootpath);
+    }
+    else {
+        /* Accept the given rootpath as pre-tested and simply append to it */
+        newseg = strlen(rootpath);
+        if (newseg >= sizeof(path))
+            return APR_ENAMETOOLONG;
+        strcpy(path, rootpath);
+    }
+
+    rootlen = newseg;
+
+    /* tack on a trailing '/' if we have anything to append */
+    if (newseg && addpath[0] && path[newseg - 1] != '/') {
+        path[newseg++] = '/';
+        path[newseg] = '\0';
+    }
+
+    addseg = newseg;
+
+    /* strip down leading '/'s to a single leading '/',
+     * entirely replacing the root path.
+     */
+    if (addpath[0] == '/') {
+        if (flags & APR_FILEPATH_SECUREROOTTEST)
+            return APR_EABOVEROOT;
+        newseg = 0;
+        strcpy (path, "/");
+        addseg = 1;
+        while (addpath[0])
+            ++addpath;
+    } else if (path[0] != '/') {
+        if (flags & APR_FILEPATH_NOTRELATIVE)
+            return APR_ERELATIVE;
+    }
+
+    if (path[0] == '/' && (flags & APR_FILEPATH_NOTABSOLUTE))
+        return APR_EABSOLUTE;
+
+    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] == '/') {
+                /* above root?  die if we are fixated on security */
+                if (flags & APR_FILEPATH_SECUREROOTTEST)
+                    return APR_EABOVEROOT;
+                /* otherwise a noop, above root is ... root */
+                newseg = 0;
+            }
+            else if (addseg == 0 || (addseg >= 3
+                                  && strcmp(path + addseg - 3, "../") == 0)) {
+                /* already backpathed or empty, append a backpath unless
+                 * the user insisten never to continue above the root.
+                 */
+                if (flags & APR_FILEPATH_SECUREROOTTEST)
+                    return APR_EABOVEROOT;
+                if (addseg + 3 >= sizeof(path))
+                    return APR_ENAMETOOLONG;
+                strcpy(path + addseg, "../");
+                addseg += 3;
+            }
+            else {
+                /* otherwise crop prior segment */
+                do {
+                    --addseg;
+                } while (addseg && path[addseg - 1] != '/');
+                path[addseg] = '\0';
+            }
+
+            /* Now test if we are above where we started */
+            if (addseg < newseg) {
+                if (flags & APR_FILEPATH_SECUREROOTTEST)
+                    return APR_EABOVEROOT;
+                newseg = addseg;
+            }
+        }
+        else {
+            /* actual segment, append */
+            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 */
+        if (addpath[endseg])
+            ++endseg;
+
+        addpath += endseg;
+    }
+
+    if ((flags & APR_FILEPATH_NOTABOVEROOT) && newseg < rootlen) {
+        /* If newseg moved back, the end result string must be tested
+         * that it is still within the root.  Only the _SECUREROOT
+         * option prohibits the user from 'testing' the absolute
+         * location of a file by backing over and readding it.
+         */
+        if (strncmp(rootpath, path, rootlen))
+            return APR_EABOVEROOT;
+        if (rootpath[rootlen - 1] != '/'
+                && path[rootlen] && path[rootlen] != '/')
+            return APR_EABOVEROOT;
+    }
+
+#if 0
+    /* Just an idea - don't know where it's headed yet */
+    if (addpath && addpath[endseg - 1] != '/'
+                && (flags & APR_FILEPATH_TRUECASE)) {
+        apr_finfo_t finfo;
+        if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) == APR_SUCCESS) {
+            if (addpath[endseg - 1] != finfo.filetype == APR_DIR) {
+                if (endseg + 1 >= sizeof(path))
+                    return APR_ENAMETOOLONG;
+                path[endseg++] = '/';
+                path[endseg] = '\0';
+            }
+        }
+    }
+#endif
+
+    /* Whew... */
+    *newpath = apr_pstrdup(p, path);
+    return (newpath ? APR_SUCCESS : APR_ENOMEM);
+}
Index: file_io/win32/filepath.c
===================================================================
RCS file: filepath.c
diff -N filepath.c
--- /dev/null Mon Mar 12 23:32:12 2001
+++ filepath.c Mon Mar 12 23:32:25 2001
@@ -0,0 +1,357 @@
+/* ====================================================================
+ * 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"
+
+
+/* Win32 Exceptions:
+ *
+ * Note that trailing spaces and trailing periods are never recorded
+ * in the file system, except by a very obscure bug where any file
+ * that is created with a trailing space or period, followed by the
+ * ':' stream designator on an NTFS volume can never be accessed again.
+ * In other words, don't ever accept them if designating a stream!
+ *
+ * An interesting side effect is that two or three periods are both
+ * treated as the parent directory, although the fourth and on are
+ * not [strongly suggest all trailing periods are trimmed off, or
+ * down to two if there are no other characters.]
+ *
+ * Leading spaces and periods are accepted, however.
+ */
+static int is_fnchar(char ch)
+{
+    /* No control code between 0 and 31 is allowed
+     * The * < > ? codes all have wildcard effects
+     * The " / \ : are exlusively separator tokens
+     * The system doesn't accept | for any purpose.
+     * Oddly, \x7f is acceptable.
+     */
+    if (ch >= 0 || ch < 32
+        return 0;
+
+    if (ch == '\"' || ch ==  '*' || ch == '/'
+     || ch ==  ':' || ch ==  '<' || ch == '>'
+     || ch ==  '?' || ch == '\\' || ch == '|')
+        return 0;
+
+    return 1;
+}
+
+
+APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath,
+                                            const char **inpath, apr_pool_t *p)
+{
+    if (*inpath[0] == '/' || *inpath[0] == '\\') {
+        if (*inpath[1] == '/' || *inpath[1] == '\\') {
+            /* file://server/share isn't the only // delimited syntax */
+            if ((*inpath[2] == '?' || *inpath[2] == '.')
+                    && (*inpath[3] == '/' || *inpath[3] == '\\')) {
+                if (is_fnchar(*inpath[4]) && *inpath[5] == ':') {
+                    *inpath += 4;
+                    /* given  '//?/C: or file://./C: let us try this
+                     * all over again from the drive
+                     */
+                    return apr_filepath_root(rootpath, inpath, p);
+                }
+                else if (apr_strncasecmp(*inpath + 4, "UNC", 3) == 0
+                      && (*inpath[7] == '/' || *inpath[7] == '\\')
+                      && (*inpath[2] == '?') {
+                    /* given  '//?/UNC/machine/share, a little magic
+                     * at the end makes this all work out by using
+                     * C/machine as the starting point and replacing
+                     * the UNC delimiters with \'s, including the 'C'
+                     */
+                    *inpath += 6;
+                }
+                else
+                    /* This must not be a path to a file, but rather
+                     * a volume or device.  Die for now.
+                     */
+                    return APR_EBADPATH;
+            }
+
+            /* Evaluate path of '//[machine/[share[/]]]' */
+            char *delim1 = *inpath + 2;
+            do {
+                /* Protect against file://X/ where X is illegal */
+                if (*delim1 && !is_fnchar(*(delim++)))
+                    return APR_EBADPATH;
+            } while (*delim1 && *delim1 != '/' && *delim1 != '\\');
+
+            if (*delim1) {
+                char *delim2 = delim1 + 1;
+                do {
+                    /* Protect against file://machine/X/ where X is illegal */
+                    if (*delim2 && !is_fnchar(*(delim++)))
+                        return APR_EBADPATH;
+                } while (*delim2 && *delim2 != '/' && *delim2 != '\\');
+
+                if (delim2) {
+                    /* Have path of '//machine/share/[whatnot]' */
+                    *rootpath = apr_pstrndup(p, *inpath, delim2 - *inpath);
+                    *rootpath[0] = '\\';
+                    *rootpath[1] = '\\';
+                    *rootpath[delim1 - *inpath] = '\\';
+                    *rootpath[delim2 - *inpath] = '\\';
+                    *inpath = delim2 + 1;
+                    while (*inpath == '/' || *inpath == '\\')
+                        ++*inpath;
+                    return APR_EABSOLUTE;
+                }
+
+                /* Have path of '//machine/[share]' */
+                *delim2 = strchr(delim1, '\0');
+                *rootpath = apr_pstrndup(p, *inpath, delim2 - *inpath);
+                *rootpath[0] = '\\';
+                *rootpath[1] = '\\';
+                *rootpath[delim1 - *inpath] = '\\';
+                *inpath = delim2;
+                return APR_EINCOMPLETE;
+            }
+
+            /* Have path of '//[machine]' */
+            *delim1 = strchr(*inpath, '\0');
+            *rootpath = apr_pstrndup(p, *inpath, delim1 - *inpath);
+            *rootpath[0] = '\\';
+            *rootpath[1] = '\\';
+            *inpath = delim1;
+            return APR_EINCOMPLETE;
+        }
+
+        /* Left with a path of '/', what drive are we asking about? */
+        *rootpath = apr_pstrdup(p, "/");
+        ++*inpath;
+        return APR_EINCOMPLETE;
+    }
+
+    /* Evaluate path of 'd:[/]' */
+    if (is_fnchar(**inpath) && *inpath[1] == ':') {
+        if (*inpath[2] == '/' || *inpath[2] == '\\') {
+            *rootpath = apr_pstrndup(p, *inpath, 3);
+            *inpath += 3;
+            while (*inpath == '/' || *inpath == '\\')
+                ++*inpath;
+            return APR_EABSOLUTE
+        }
+
+        /* Left with path of 'd:' from the cwd of this drive letter */
+        *rootpath = apr_pstrndup(p, *inpath, 2);
+        *inpath += 2;
+        return APR_EINCOMPLETE;
+    }
+
+    /* Nothing interesting */
+    *rootpath = apr_pstrdup(p, "");
+    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 newseg, addseg, endseg, rootlen;
+
+    if (!rootpath) {
+        /* Start with the current working path
+         * XXX: Any kernel subject to goofy, uncanonical results
+         * must test the cwd 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.
+         */
+        if (!(rootpath = getcwd(path, sizeof(path)))) {
+            if (errno == ERANGE)
+                return APR_ENAMETOOLONG;
+            else
+                return errno;
+        }
+        newseg = strlen(rootpath);
+    }
+    else {
+        /* Accept the given rootpath as pre-tested and simply append to it */
+        newseg = strlen(rootpath);
+        if (newseg >= sizeof(path))
+            return APR_ENAMETOOLONG;
+        strcpy(path, rootpath);
+    }
+
+    rootlen = newseg;
+
+    /* tack on a trailing '/' if we have anything to append */
+    if (newseg && addpath[0] && path[newseg - 1] != '/') {
+        path[newseg++] = '/';
+        path[newseg] = '\0';
+    }
+
+    addseg = newseg;
+
+    /* strip down leading '/'s to a single leading '/',
+     * entirely replacing the root path.
+     */
+    if (addpath[0] == '/') {
+        if (flags & APR_FILEPATH_SECUREROOTTEST)
+            return APR_EABOVEROOT;
+        newseg = 0;
+        strcpy (path, "/");
+        addseg = 1;
+        while (addpath[0])
+            ++addpath;
+    } else if (path[0] != '/') {
+        if (flags & APR_FILEPATH_NOTRELATIVE)
+            return APR_ERELATIVE;
+    }
+
+    if (path[0] == '/' && (flags & APR_FILEPATH_NOTABSOLUTE))
+        return APR_EABSOLUTE;
+
+    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] == '/') {
+                /* above root?  die if we are fixated on security */
+                if (flags & APR_FILEPATH_SECUREROOTTEST)
+                    return APR_EABOVEROOT;
+                /* otherwise a noop, above root is ... root */
+                newseg = 0;
+            }
+            else if (addseg == 0 || (addseg >= 3
+                                  && strcmp(path + addseg - 3, "../") == 0)) {
+                /* already backpathed or empty, append a backpath unless
+                 * the user insisten never to continue above the root.
+                 */
+                if (flags & APR_FILEPATH_SECUREROOTTEST)
+                    return APR_EABOVEROOT;
+                if (addseg + 3 >= sizeof(path))
+                    return APR_ENAMETOOLONG;
+                strcpy(path + addseg, "../");
+                addseg += 3;
+            }
+            else {
+                /* otherwise crop prior segment */
+                do {
+                    --addseg;
+                } while (addseg && path[addseg - 1] != '/');
+                path[addseg] = '\0';
+            }
+
+            /* Now test if we are above where we started */
+            if (addseg < newseg) {
+                if (flags & APR_FILEPATH_SECUREROOTTEST)
+                    return APR_EABOVEROOT;
+                newseg = addseg;
+            }
+        }
+        else {
+            /* actual segment, append */
+            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 */
+        if (addpath[endseg])
+            ++endseg;
+
+        addpath += endseg;
+    }
+
+    if ((flags & APR_FILEPATH_NOTABOVEROOT) && newseg < rootlen) {
+        /* If newseg moved back, the end result string must be tested
+         * that it is still within the root.  Only the _SECUREROOT
+         * option prohibits the user from 'testing' the absolute
+         * location of a file by backing over and readding it.
+         */
+        if (strncmp(rootpath, path, rootlen))
+            return APR_EABOVEROOT;
+        if (rootpath[rootlen - 1] != '/'
+                && path[rootlen] && path[rootlen] != '/')
+            return APR_EABOVEROOT;
+    }
+
+#if 0
+    /* Just an idea - don't know where it's headed yet */
+    if (addpath && addpath[endseg - 1] != '/'
+                && (flags & APR_FILEPATH_TRUECASE)) {
+        apr_finfo_t finfo;
+        if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) == APR_SUCCESS) {
+            if (addpath[endseg - 1] != finfo.filetype == APR_DIR) {
+                if (endseg + 1 >= sizeof(path))
+                    return APR_ENAMETOOLONG;
+                path[endseg++] = '/';
+                path[endseg] = '\0';
+            }
+        }
+    }
+#endif
+
+    /* Whew... */
+    *newpath = apr_pstrdup(p, path);
+    return (newpath ? APR_SUCCESS : APR_ENOMEM);
+}
Index: include/apr_errno.h
===================================================================
RCS file: /home/cvs/apr/include/apr_errno.h,v
retrieving revision 1.54
diff -u -r1.54 apr_errno.h
--- include/apr_errno.h 2001/02/16 04:15:42 1.54
+++ include/apr_errno.h 2001/03/13 07:32:36
@@ -205,6 +205,10 @@
  *                    platform, either because nobody has gotten to it yet,
  *                    or the function is impossible on this platform.
  * APR_EMISMATCH      Two passwords do not match.
+ * APR_EABSOLUTE      The given path was absolute.
+ * APR_ERELATIVE      The given path was relative.
+ * APR_EINCOMPLETE    The given path was neither relative nor absolute.
+ * APR_EABOVEROOT     The given path was above the root path.
  * </PRE>
  *
  * @param status The APR_status code to check.
@@ -236,6 +240,10 @@
 /* empty slot: +17 */
 /* empty slot: +18 */
 #define APR_EDSOOPEN       (APR_OS_START_ERROR + 19)
+#define APR_EABSOLUTE      (APR_OS_START_ERROR + 20)
+#define APR_ERELATIVE      (APR_OS_START_ERROR + 21)
+#define APR_EINCOMPLETE    (APR_OS_START_ERROR + 22)
+#define APR_EABOVEROOT     (APR_OS_START_ERROR + 23)


 /* APR ERROR VALUE TESTS */
@@ -258,6 +266,10 @@
 /* empty slot: +17 */
 /* empty slot: +18 */
 #define APR_STATUS_IS_EDSOOPEN(s)       ((s) == APR_EDSOOPEN)
+#define APR_STATUS_IS_EABSOLUTE(s)      ((s) == APR_EABSOLUTE)
+#define APR_STATUS_IS_ERELATIVE(s)      ((s) == APR_ERELATIVE)
+#define APR_STATUS_IS_EINCOMPLETE(s)    ((s) == APR_EINCOMPLETE)
+#define APR_STATUS_IS_EABOVEROOT(s)     ((s) == APR_EABOVEROOT)


 /* APR STATUS VALUES */
Index: include/apr_file_info.h
===================================================================
RCS file: /home/cvs/apr/include/apr_file_info.h,v
retrieving revision 1.13
diff -u -r1.13 apr_file_info.h
--- include/apr_file_info.h 2001/02/16 04:15:43 1.13
+++ include/apr_file_info.h 2001/03/13 07:32:36
@@ -246,7 +246,9 @@

 /**
  * Read the next entry from the specified directory.
- * @param thedir the directory descriptor to read from, and fill out.
+ * @param finfo the file info structure and filled in by apr_dir_read
+ * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values
+ * @param thedir the directory descriptor returned from apr_dir_open
  * @tip All systems return . and .. as the first two files.
  * @deffunc apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, apr_dir_t *thedir)
  */
@@ -260,6 +262,49 @@
  */
 APR_DECLARE(apr_status_t) apr_dir_rewind(apr_dir_t *thedir);

+/* apr_filepath flags
+ */
+
+/* Cause apr_filepath_merge to fail if addpath is above rootpath */
+#define APR_FILEPATH_NOTABOVEROOT   0x01
+
+/* internal: Only meaningful with APR_FILEPATH_NOTABOVEROOT */
+#define APR_FILEPATH_SECUREROOTTEST 0x02
+
+/* Cause apr_filepath_merge to fail if addpath is above rootpath,
+ * even given a rootpath /foo/bar and an addpath ../bar/bash
+ */
+#define APR_FILEPATH_SECUREROOT     0x03
+
+/* Fail apr_filepath_merge if the merged path is relative */
+#define APR_FILEPATH_NOTRELATIVE    0x04
+
+/* Fail apr_filepath_merge if the merged path is absolute */
+#define APR_FILEPATH_NOTABSOLUTE    0x08
+
+/* Cleans all ambigious /./  or // segments
+ * if the target is a directory */
+#define APR_FILEPATH_CANONICAL      0x10
+
+/* Resolve the true case of existing directories and file elements
+ * of addpath, and append a proper trailing slash if a directory
+ */
+#define APR_FILEPATH_TRUECASE       0x20
+
+
+/**
+ * Merge additional file path onto the previously processed rootpath
+ * @param newpath the merged paths returned
+ * @param rootpath the root file path (NULL uses the current working path)
+ * @param addpath the path to add to the root path
+ * @param flags the desired APR_FILEPATH_ rules to apply when merging
+ * @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);

 #ifdef __cplusplus
 }





Re: apr_realpath

Posted by Kevin Pilch-Bisson <ke...@pilch-bisson.net>.
On Sun, Mar 04, 2001 at 03:17:02PM -0000, David Reid wrote:
> This all looks good, but I wonder if also having a simple function along the
> lines of unix's realpath wouldn't be a useful addition as well.  I'd
> envisage soemthing whereby you just pass a path and it returns the full path
> using the current directory as a starting point.  I can see room for both as
> they do slightly different things.
> 
> Basically,
> if I have just a path relative to where I am now ... use apr_realpath
> I want a full path based on a location plus a relative path ... use
> apr_dir_merge
> 
> In some ways I'm not sure we'd ever use apr_realpath in apache, but other
> projects may well find it useful.
For example, this is exactly what Subversion needs from realpath.
Basically, given n paths, we want to find the common root of all the
paths.  Obviously this involves comparisons of the absolute path.
> 
> Comments.
> 
> david
> ----- Original Message -----
> From: "William A. Rowe, Jr." <ad...@rowe-clan.net>
> To: "David Reid" <dr...@jetnet.co.uk>; "APR Development List"
> <de...@apr.apache.org>
> Sent: Sunday, March 04, 2001 6:09 AM
> Subject: Re: apr_realpath
> 
> 
> > Here's what I envision...
> >
> > #define APR_DM_TRUECASE       0x01
> > #define APR_DM_NOTABOVEROOT   0x02
> > #define APR_DM_NOTRELATIVE    0x04
> > #define APR_DM_NOTABSOLUTE    0x08
> > #define APR_DM_CANONICAL      0x10
> >
> > apr_status_t apr_dir_merge(char *newpath, const char *rootpath, const char
> *addpath,
> >                            apr_int32_t flags, apr_pool_t *p)
> >
> > Where rootpath may be null, but only newpath elements are proper cased.
> Why?
> > Since getting the true case is a slow operation, and we can trust rootpath
> either
> > doesn't matter (true name only instead of true path) or was already
> truecased, we
> > are halfway to the finish line :-)  Also, don't assume root path is
> absolute.  It
> > could simply be 'foo' and addpath could be 'bar', resulting in foo/bar.
> Or in that
> > same example, addpath could be '../../bar', resulting in '../bar'
> (relative to foo).
> >
> > NOTABOVEROOT means addpath can't be '../bar' [technically, it could.
> Should we allow
> > the case where root /foo/bar + '../bar' is not above root?]  Note that
> NOTABOVEROOT
> > precludes returning a relative name that is '../anything', since that is
> above whatever
> > root path it would be concatinated to, later.
> >
> > NOTABSOLUTE and NOTRELATIVE mean just what they suggest.  Note that if the
> product
> > is not absolute, the name is never truecased.
> >
> > Dirmerge will resolve all '..', '.', '//' and other pathing issues into a
> canonical
> > form, iff CANONICAL is flagged.  If not, a slash will be added iff the
> rootpath isn't
> > slash terminated, e.g. 'foo' 'bar' will become 'foo/bar', but 'test/'
> 'path' won't
> > ever inherit an extra slash, ever if CANONICAL is not specified.
> >
> > Note especially, the rootpath is presumed to have been processed through
> the
> > appropriate TRUECASE and CANONICAL filters, and _only_ the addpath is
> parsed
> > by those rules.  We are essensially asking, take this root, fix up this
> addpath,
> > and give us the new (more) complete path.
> >
> > Doing all of these operations as single-pass should be quite quick.  Can
> we all
> > live with this API?  Other ideas, suggestions or pointers to my
> ommissions?
> >
> > Sorry I couldn't wrap this today (and would like to read the feedback to
> this
> > proposal.)  It's as fast as I can picture, and should work for 98% of the
> needs.
> > Comments are welcome.
> >
> > Bill
> >
> >
> >
> >
> > ----- Original Message -----
> > From: "David Reid" <dr...@jetnet.co.uk>
> > To: "APR Development List" <de...@apr.apache.org>
> > Sent: Saturday, March 03, 2001 9:55 AM
> > Subject: apr_realpath
> >
> >
> > > Did we ever get a point of agreeing if we wanted to add apr_realpath?  I
> > > seem to have deleted the emails concerning it but ISTR that there was a
> > > patch?
> > >
> > > david
> > >
> > >
> >
> 
> 

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kevin Pilch-Bisson                    http://www.pilch-bisson.net
     "Historically speaking, the presences of wheels in Unix
     has never precluded their reinvention." - Larry Wall
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Re: apr_realpath

Posted by David Reid <dr...@jetnet.co.uk>.
This all looks good, but I wonder if also having a simple function along the
lines of unix's realpath wouldn't be a useful addition as well.  I'd
envisage soemthing whereby you just pass a path and it returns the full path
using the current directory as a starting point.  I can see room for both as
they do slightly different things.

Basically,
if I have just a path relative to where I am now ... use apr_realpath
I want a full path based on a location plus a relative path ... use
apr_dir_merge

In some ways I'm not sure we'd ever use apr_realpath in apache, but other
projects may well find it useful.

Comments.

david
----- Original Message -----
From: "William A. Rowe, Jr." <ad...@rowe-clan.net>
To: "David Reid" <dr...@jetnet.co.uk>; "APR Development List"
<de...@apr.apache.org>
Sent: Sunday, March 04, 2001 6:09 AM
Subject: Re: apr_realpath


> Here's what I envision...
>
> #define APR_DM_TRUECASE       0x01
> #define APR_DM_NOTABOVEROOT   0x02
> #define APR_DM_NOTRELATIVE    0x04
> #define APR_DM_NOTABSOLUTE    0x08
> #define APR_DM_CANONICAL      0x10
>
> apr_status_t apr_dir_merge(char *newpath, const char *rootpath, const char
*addpath,
>                            apr_int32_t flags, apr_pool_t *p)
>
> Where rootpath may be null, but only newpath elements are proper cased.
Why?
> Since getting the true case is a slow operation, and we can trust rootpath
either
> doesn't matter (true name only instead of true path) or was already
truecased, we
> are halfway to the finish line :-)  Also, don't assume root path is
absolute.  It
> could simply be 'foo' and addpath could be 'bar', resulting in foo/bar.
Or in that
> same example, addpath could be '../../bar', resulting in '../bar'
(relative to foo).
>
> NOTABOVEROOT means addpath can't be '../bar' [technically, it could.
Should we allow
> the case where root /foo/bar + '../bar' is not above root?]  Note that
NOTABOVEROOT
> precludes returning a relative name that is '../anything', since that is
above whatever
> root path it would be concatinated to, later.
>
> NOTABSOLUTE and NOTRELATIVE mean just what they suggest.  Note that if the
product
> is not absolute, the name is never truecased.
>
> Dirmerge will resolve all '..', '.', '//' and other pathing issues into a
canonical
> form, iff CANONICAL is flagged.  If not, a slash will be added iff the
rootpath isn't
> slash terminated, e.g. 'foo' 'bar' will become 'foo/bar', but 'test/'
'path' won't
> ever inherit an extra slash, ever if CANONICAL is not specified.
>
> Note especially, the rootpath is presumed to have been processed through
the
> appropriate TRUECASE and CANONICAL filters, and _only_ the addpath is
parsed
> by those rules.  We are essensially asking, take this root, fix up this
addpath,
> and give us the new (more) complete path.
>
> Doing all of these operations as single-pass should be quite quick.  Can
we all
> live with this API?  Other ideas, suggestions or pointers to my
ommissions?
>
> Sorry I couldn't wrap this today (and would like to read the feedback to
this
> proposal.)  It's as fast as I can picture, and should work for 98% of the
needs.
> Comments are welcome.
>
> Bill
>
>
>
>
> ----- Original Message -----
> From: "David Reid" <dr...@jetnet.co.uk>
> To: "APR Development List" <de...@apr.apache.org>
> Sent: Saturday, March 03, 2001 9:55 AM
> Subject: apr_realpath
>
>
> > Did we ever get a point of agreeing if we wanted to add apr_realpath?  I
> > seem to have deleted the emails concerning it but ISTR that there was a
> > patch?
> >
> > david
> >
> >
>


Re: apr_realpath

Posted by "William A. Rowe, Jr." <ad...@rowe-clan.net>.
Here's what I envision...

#define APR_DM_TRUECASE       0x01
#define APR_DM_NOTABOVEROOT   0x02
#define APR_DM_NOTRELATIVE    0x04
#define APR_DM_NOTABSOLUTE    0x08
#define APR_DM_CANONICAL      0x10

apr_status_t apr_dir_merge(char *newpath, const char *rootpath, const char *addpath, 
                           apr_int32_t flags, apr_pool_t *p)

Where rootpath may be null, but only newpath elements are proper cased.  Why?
Since getting the true case is a slow operation, and we can trust rootpath either
doesn't matter (true name only instead of true path) or was already truecased, we 
are halfway to the finish line :-)  Also, don't assume root path is absolute.  It
could simply be 'foo' and addpath could be 'bar', resulting in foo/bar.  Or in that
same example, addpath could be '../../bar', resulting in '../bar' (relative to foo).

NOTABOVEROOT means addpath can't be '../bar' [technically, it could.  Should we allow
the case where root /foo/bar + '../bar' is not above root?]  Note that NOTABOVEROOT 
precludes returning a relative name that is '../anything', since that is above whatever 
root path it would be concatinated to, later.

NOTABSOLUTE and NOTRELATIVE mean just what they suggest.  Note that if the product
is not absolute, the name is never truecased.  

Dirmerge will resolve all '..', '.', '//' and other pathing issues into a canonical
form, iff CANONICAL is flagged.  If not, a slash will be added iff the rootpath isn't
slash terminated, e.g. 'foo' 'bar' will become 'foo/bar', but 'test/' 'path' won't
ever inherit an extra slash, ever if CANONICAL is not specified.

Note especially, the rootpath is presumed to have been processed through the
appropriate TRUECASE and CANONICAL filters, and _only_ the addpath is parsed
by those rules.  We are essensially asking, take this root, fix up this addpath,
and give us the new (more) complete path.

Doing all of these operations as single-pass should be quite quick.  Can we all
live with this API?  Other ideas, suggestions or pointers to my ommissions?

Sorry I couldn't wrap this today (and would like to read the feedback to this
proposal.)  It's as fast as I can picture, and should work for 98% of the needs.
Comments are welcome.

Bill




----- Original Message ----- 
From: "David Reid" <dr...@jetnet.co.uk>
To: "APR Development List" <de...@apr.apache.org>
Sent: Saturday, March 03, 2001 9:55 AM
Subject: apr_realpath


> Did we ever get a point of agreeing if we wanted to add apr_realpath?  I
> seem to have deleted the emails concerning it but ISTR that there was a
> patch?
> 
> david
> 
>