OSSP CVS Repository

ossp - ossp-pkg/path/path_resolve.c
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/path/path_resolve.c
/*
**  OSSP path - Filesystem Path Manipulation
**  Copyright (c) 2002-2003 Ralf S. Engelschall <rse@engelschall.com>
**  Copyright (c) 2002-2003 The OSSP Project <http://www.ossp.org/>
**  Copyright (c) 2002-2003 Cable & Wireless Deutschland <http://www.cw.com/de/>
**
**  This file is part of OSSP path, a filesystem path manipulation library
**  which can be found at http://www.ossp.org/pkg/lib/path/.
**
**  Permission to use, copy, modify, and distribute this software for
**  any purpose with or without fee is hereby granted, provided that
**  the above copyright notice and this permission notice appear in all
**  copies.
**
**  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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR
**  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.
**
**  path_resolve.c: pathname resolving
*/

/*
 * Copyright (c) 1994
 *  The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Jan-Simon Pendry.
 *
 * 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. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *       This product includes software developed by the University of
 *       California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS 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 REGENTS OR 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.
 */

#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/stat.h>

#include "path.h"

char *
path_resolve(
    char *outbuf,
    size_t outsize,
    const char *path)
{
    struct stat sb;
    int fd, n, rootd, serrno;
    char *p, *q, wbuf[MAXPATHLEN];
    char resolved[MAXPATHLEN];
    int symlinks = 0;

    /* save the starting point */
    if ((fd = open(".", O_RDONLY)) < 0) {
        strcpy(resolved, ".");
        return NULL;
    }

    /*
     * Find the dirname and basename from the path to be resolved.
     * Change directory to the dirname component.
     * lstat() the basename part.
     *     if it is a symlink, read in the value and loop.
     *     if it is a directory, then change to that directory.
     * get the current directory name and append the basename.
     */
    strncpy(resolved, path, MAXPATHLEN - 1);
    resolved[MAXPATHLEN-1] = '\0';
loop:
    if ((q = strrchr(resolved, '/')) != NULL) {
        p = q + 1;
        if (q == resolved)
            q = "/";
        else {
            do {
                --q;
            } while (q > resolved && *q == '/');
            q[1] = '\0';
            q = resolved;
        }
        if (chdir(q) < 0)
            goto err1;
    } else
        p = resolved;

    /* Deal with the last component. */
    if (*p != '\0' && lstat(p, &sb) == 0) {
        if (S_ISLNK(sb.st_mode)) {
            if (++symlinks > MAXSYMLINKS) {
                errno = ELOOP;
                goto err1;
            }
            n = readlink(p, resolved, MAXPATHLEN - 1);
            if (n < 0)
                goto err1;
            resolved[n] = '\0';
            goto loop;
        }
        if (S_ISDIR(sb.st_mode)) {
            if (chdir(p) < 0)
                goto err1;
            p = "";
        }
    }

    /*
     * Save the last component name and get the full pathname of
     * the current directory.
     */
    strcpy(wbuf, p);
    if (getcwd(resolved, MAXPATHLEN) == 0)
        goto err1;

    /*
     * Join the two strings together, ensuring that the right thing
     * happens if the last component is empty, or the dirname is root.
     */
    if (resolved[0] == '/' && resolved[1] == '\0')
        rootd = 1;
    else
        rootd = 0;

    if (*wbuf) {
        if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {
            errno = ENAMETOOLONG;
            goto err1;
        }
        if (rootd == 0)
            strcat(resolved, "/");
        strcat(resolved, wbuf);
    }

    /* Go back to where we came from. */
    if (fchdir(fd) < 0) {
        serrno = errno;
        goto err2;
    }

    /* It's okay if the close fails, what's an fd more or less? */
    close(fd);
    strncpy(outbuf, resolved, outsize);
    outbuf[outsize-1] = '\0';
    return outbuf;

err1:
    serrno = errno;
    fchdir(fd);
err2:
    close(fd);
    errno = serrno;
    return NULL;
}


CVSTrac 2.0.1