File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / compat / getcwd.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 10:46:11 2013 UTC (11 years ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_8p0, v1_8_8, v1_8_7p0, v1_8_7, v1_8_10p3_0, v1_8_10p3, HEAD
1.8.7

    1: /*
    2:  * Copyright (c) 1989, 1991, 1993
    3:  *	The Regents of the University of California.  All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  * 3. Neither the name of the University nor the names of its contributors
   14:  *    may be used to endorse or promote products derived from this software
   15:  *    without specific prior written permission.
   16:  *
   17:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27:  * SUCH DAMAGE.
   28:  */
   29: 
   30: #include <config.h>
   31: 
   32: #ifndef HAVE_GETCWD
   33: 
   34: #include <sys/types.h>
   35: #include <sys/stat.h>
   36: 
   37: #include <errno.h>
   38: #include <stdio.h>
   39: #ifdef STDC_HEADERS
   40: # include <stdlib.h>
   41: # include <stddef.h>
   42: #else
   43: # ifdef HAVE_STDLIB_H
   44: #  include <stdlib.h>
   45: # endif
   46: #endif /* STDC_HEADERS */
   47: #ifdef HAVE_STRING_H
   48: # include <string.h>
   49: #endif /* HAVE_STRING_H */
   50: #ifdef HAVE_STRINGS_H
   51: # include <strings.h>
   52: #endif /* HAVE_STRINGS_H */
   53: #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
   54: # include <malloc.h>
   55: #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
   56: #ifdef HAVE_UNISTD_H
   57: # include <unistd.h>
   58: #endif /* HAVE_UNISTD_H */
   59: #ifdef HAVE_DIRENT_H
   60: # include <dirent.h>
   61: # define NAMLEN(dirent) strlen((dirent)->d_name)
   62: #else
   63: # define dirent direct
   64: # define NAMLEN(dirent) (dirent)->d_namlen
   65: # ifdef HAVE_SYS_NDIR_H
   66: #  include <sys/ndir.h>
   67: # endif
   68: # ifdef HAVE_SYS_DIR_H
   69: #  include <sys/dir.h>
   70: # endif
   71: # ifdef HAVE_NDIR_H
   72: #  include <ndir.h>
   73: # endif
   74: #endif
   75: 
   76: #include "missing.h"
   77: 
   78: #define	ISDOT(dp) \
   79: 	(dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
   80: 	    (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
   81: 
   82: char *
   83: getcwd(char *pt, size_t size)
   84: {
   85: 	struct dirent *dp;
   86: 	DIR *dir = NULL;
   87: 	dev_t dev;
   88: 	ino_t ino;
   89: 	int first;
   90: 	char *bpt, *bup;
   91: 	struct stat s;
   92: 	dev_t root_dev;
   93: 	ino_t root_ino;
   94: 	size_t ptsize, upsize;
   95: 	int save_errno;
   96: 	char *ept, *eup, *up;
   97: 
   98: 	/*
   99: 	 * If no buffer specified by the user, allocate one as necessary.
  100: 	 * If a buffer is specified, the size has to be non-zero.  The path
  101: 	 * is built from the end of the buffer backwards.
  102: 	 */
  103: 	if (pt) {
  104: 		ptsize = 0;
  105: 		if (!size) {
  106: 			errno = EINVAL;
  107: 			return NULL;
  108: 		}
  109: 		ept = pt + size;
  110: 	} else {
  111: 		if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
  112: 			return NULL;
  113: 		ept = pt + ptsize;
  114: 	}
  115: 	bpt = ept - 1;
  116: 	*bpt = '\0';
  117: 
  118: 	/*
  119: 	 * Allocate bytes (1024 - malloc space) for the string of "../"'s.
  120: 	 * Should always be enough (it's 340 levels).  If it's not, allocate
  121: 	 * as necessary.  Special * case the first stat, it's ".", not "..".
  122: 	 */
  123: 	if ((up = malloc(upsize = 1024 - 4)) == NULL)
  124: 		goto err;
  125: 	eup = up + PATH_MAX;
  126: 	bup = up;
  127: 	up[0] = '.';
  128: 	up[1] = '\0';
  129: 
  130: 	/* Save root values, so know when to stop. */
  131: 	if (stat("/", &s))
  132: 		goto err;
  133: 	root_dev = s.st_dev;
  134: 	root_ino = s.st_ino;
  135: 
  136: 	errno = 0;			/* XXX readdir has no error return. */
  137: 
  138: 	for (first = 1;; first = 0) {
  139: 		/* Stat the current level. */
  140: 		if (lstat(up, &s))
  141: 			goto err;
  142: 
  143: 		/* Save current node values. */
  144: 		ino = s.st_ino;
  145: 		dev = s.st_dev;
  146: 
  147: 		/* Check for reaching root. */
  148: 		if (root_dev == dev && root_ino == ino) {
  149: 			*--bpt = '/';
  150: 			/*
  151: 			 * It's unclear that it's a requirement to copy the
  152: 			 * path to the beginning of the buffer, but it's always
  153: 			 * been that way and stuff would probably break.
  154: 			 */
  155: 			bcopy(bpt, pt, ept - bpt);
  156: 			free(up);
  157: 			return pt;
  158: 		}
  159: 
  160: 		/*
  161: 		 * Build pointer to the parent directory, allocating memory
  162: 		 * as necessary.  Max length is 3 for "../", the largest
  163: 		 * possible component name, plus a trailing NULL.
  164: 		 */
  165: 		if (bup + 3  + MAXNAMLEN + 1 >= eup) {
  166: 			char *nup;
  167: 
  168: 			if ((nup = realloc(up, upsize *= 2)) == NULL)
  169: 				goto err;
  170: 			up = nup;
  171: 			bup = up;
  172: 			eup = up + upsize;
  173: 		}
  174: 		*bup++ = '.';
  175: 		*bup++ = '.';
  176: 		*bup = '\0';
  177: 
  178: 		/* Open and stat parent directory. */
  179: 		if (!(dir = opendir(up)) || fstat(dirfd(dir), &s))
  180: 			goto err;
  181: 
  182: 		/* Add trailing slash for next directory. */
  183: 		*bup++ = '/';
  184: 
  185: 		/*
  186: 		 * If it's a mount point, have to stat each element because
  187: 		 * the inode number in the directory is for the entry in the
  188: 		 * parent directory, not the inode number of the mounted file.
  189: 		 */
  190: 		save_errno = 0;
  191: 		if (s.st_dev == dev) {
  192: 			for (;;) {
  193: 				if (!(dp = readdir(dir)))
  194: 					goto notfound;
  195: 				if (dp->d_fileno == ino)
  196: 					break;
  197: 			}
  198: 		} else
  199: 			for (;;) {
  200: 				if (!(dp = readdir(dir)))
  201: 					goto notfound;
  202: 				if (ISDOT(dp))
  203: 					continue;
  204: 				bcopy(dp->d_name, bup, NAMLEN(dp) + 1);
  205: 
  206: 				/* Save the first error for later. */
  207: 				if (lstat(up, &s)) {
  208: 					if (!save_errno)
  209: 						save_errno = errno;
  210: 					errno = 0;
  211: 					continue;
  212: 				}
  213: 				if (s.st_dev == dev && s.st_ino == ino)
  214: 					break;
  215: 			}
  216: 
  217: 		/*
  218: 		 * Check for length of the current name, preceding slash,
  219: 		 * leading slash.
  220: 		 */
  221: 		if (bpt - pt <= NAMLEN(dp) + (first ? 1 : 2)) {
  222: 			size_t len, off;
  223: 			char *npt;
  224: 
  225: 			if (!ptsize) {
  226: 				errno = ERANGE;
  227: 				goto err;
  228: 			}
  229: 			off = bpt - pt;
  230: 			len = ept - bpt;
  231: 			if ((npt = realloc(pt, ptsize *= 2)) == NULL)
  232: 				goto err;
  233: 			pt = npt;
  234: 			bpt = pt + off;
  235: 			ept = pt + ptsize;
  236: 			bcopy(bpt, ept - len, len);
  237: 			bpt = ept - len;
  238: 		}
  239: 		if (!first)
  240: 			*--bpt = '/';
  241: 		bpt -= NAMLEN(dp);
  242: 		bcopy(dp->d_name, bpt, NAMLEN(dp));
  243: 		(void)closedir(dir);
  244: 
  245: 		/* Truncate any file name. */
  246: 		*bup = '\0';
  247: 	}
  248: 
  249: notfound:
  250: 	/*
  251: 	 * If readdir set errno, use it, not any saved error; otherwise,
  252: 	 * didn't find the current directory in its parent directory, set
  253: 	 * errno to ENOENT.
  254: 	 */
  255: 	if (!errno)
  256: 		errno = save_errno ? save_errno : ENOENT;
  257: 	/* FALLTHROUGH */
  258: err:
  259: 	if (ptsize)
  260: 		free(pt);
  261: 	if (up)
  262: 		free(up);
  263: 	if (dir)
  264: 		(void)closedir(dir);
  265: 	return NULL;
  266: }
  267: #endif /* HAVE_GETCWD */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>