Re: Bug in canonicalize_path() - Mailing list pgsql-patches

From Tom Lane
Subject Re: Bug in canonicalize_path()
Date
Msg-id 23841.1123881289@sss.pgh.pa.us
Whole thread Raw
In response to Re: Bug in canonicalize_path()  (Bruce Momjian <pgman@candle.pha.pa.us>)
List pgsql-patches
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> In my first attempt, I counted the number of ".." groups, then went up
> to remove each "..", and them remove a regular directory for each "..".
> And then you have this case:

>     /usr/local/../bin/../..

> Here you hit the first ".." as you are going up.  It just seemed like a
> lost cause.

BTW, you were right: this is a *lot* harder than it looks at first
glance.  Here's what I ended up with:

    /*
     * Remove any trailing uses of "." and process ".." ourselves
     *
     * Note that "/../.." should reduce to just "/", while "../.." has to
     * be kept as-is.  In the latter case we put back mistakenly trimmed
     * ".." components below.  Also note that we want a Windows drive spec
     * to be visible to trim_directory(), but it's not part of the logic
     * that's looking at the name components; hence distinction between
     * path and spath.
     */
    spath = skip_drive(path);
    pending_strips = 0;
    for (;;)
    {
        int         len = strlen(spath);

        if (len >= 2 && strcmp(spath + len - 2, "/.") == 0)
            trim_directory(path);
        else if (strcmp(spath, ".") == 0)
        {
            /* Want to leave "." alone, but "./.." has to become ".." */
            if (pending_strips > 0)
                *spath = '\0';
            break;
        }
        else if ((len >= 3 && strcmp(spath + len - 3, "/..") == 0) ||
                 strcmp(spath, "..") == 0)
        {
            trim_directory(path);
            pending_strips++;
        }
        else if (pending_strips > 0 && *spath != '\0')
        {
            /* trim a regular directory name cancelled by ".." */
            trim_directory(path);
            pending_strips--;
            /* foo/.. should become ".", not empty */
            if (*spath == '\0')
                strcpy(spath, ".");
        }
        else
            break;
    }

    if (pending_strips > 0)
    {
        /*
         * We could only get here if path is now totally empty (other than
         * a possible drive specifier on Windows).
         * We have to put back one or more ".."'s that we took off.
         */
        while (--pending_strips > 0)
            strcat(path, "../");
        strcat(path, "..");
    }
}

            regards, tom lane

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: More to Bad link Makefile patch
Next
From: Bruce Momjian
Date:
Subject: Re: Bitmap index AM