Edit

IABSD.fr/xenocara/app/xedit/realpath.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2006-11-25 20:07:29
    Hash : 616b6f15
    Message : Importing from X.Org 7.2RC2

  • app/xedit/realpath.c
  • /*
     * 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.
     */
    /* $XFree86: xc/programs/xedit/realpath.c,v 1.4 2000/02/12 20:45:45 dawes Exp $ */
    
    #if defined(LIBC_SCCS) && !defined(lint)
    static char sccsid[] = "@(#)realpath.c	8.1 (Berkeley) 2/16/94";
    #endif /* LIBC_SCCS and not lint */
    
    #include <sys/param.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #include <errno.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #ifndef LISP
    #include "xedit.h"
    #endif
    
    #if defined(__Lynx__)
    #define NO_FCHDIR
    #endif
    
    #if defined(ISC)
    #ifndef MAXPATHLEN
    #define MAXPATHLEN	1024
    #endif
    #endif
    #ifndef MAXSYMLINKS
    #define MAXSYMLINKS	256
    #endif
    
    /*
     * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
     *
     * Find the real name of path, by removing all ".", ".." and symlink
     * components.  Returns (resolved) on success, or (NULL) on failure,
     * in which case the path which caused trouble is left in (resolved).
     */
    char *
    realpath(path, resolved)
    	const char *path;
    	char *resolved;
    {
    	struct stat sb;
    #ifdef NO_FCHDIR
    	char start[MAXPATHLEN];
    #else
    	int fd;
    #endif
    	int n, rootd, serrno;
    	char *p, *q, wbuf[MAXPATHLEN];
    	int symlinks = 0;
    
    	/* Save the starting point. */
    #ifdef NO_FCHDIR
    	if (getcwd(start, MAXPATHLEN) == NULL) {
    		(void)strcpy(resolved, ".");
    		return (NULL);
    	}
    #else
    	if ((fd = open(".", O_RDONLY)) < 0) {
    		(void)strcpy(resolved, ".");
    		return (NULL);
    	}
    #endif
    
    	/*
    	 * 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.
    	 */
    	(void)strncpy(resolved, path, MAXPATHLEN - 1);
    	resolved[MAXPATHLEN - 1] = '\0';
    loop:
    	q = strrchr(resolved, '/');
    	if (q != 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);
    			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.
    	 */
    	(void)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)
    			(void)strcat(resolved, "/");
    		(void)strcat(resolved, wbuf);
    	}
    
    	/* Go back to where we came from. */
    #ifdef NO_FCHDIR
    	if (chdir(start) < 0)
    #else
    	if (fchdir(fd) < 0)
    #endif
    	{
    		serrno = errno;
    		goto err2;
    	}
    
    	/* It's okay if the close fails, what's an fd more or less? */
    #ifndef NO_FCHDIR
    	(void)close(fd);
    #endif
    	return (resolved);
    
    err1:	serrno = errno;
    #ifdef NO_FCHDIR
    	(void)chdir(start);
    #else
    	(void)fchdir(fd);
    #endif
    err2:
    #ifndef NO_FCHDIR
    	(void)close(fd);
    #endif
    	errno = serrno;
    	return (NULL);
    }