Home | History | Annotate | Line # | Download | only in ksh
path.c revision 1.7.28.1
      1  1.7.28.1       jym /*	$NetBSD: path.c,v 1.7.28.1 2009/05/13 19:15:50 jym Exp $	*/
      2       1.5       agc #include <sys/cdefs.h>
      3       1.5       agc 
      4       1.5       agc #ifndef lint
      5  1.7.28.1       jym __RCSID("$NetBSD: path.c,v 1.7.28.1 2009/05/13 19:15:50 jym Exp $");
      6       1.5       agc #endif
      7       1.5       agc 
      8       1.2       tls 
      9       1.1       jtc #include "sh.h"
     10       1.1       jtc #include "ksh_stat.h"
     11       1.1       jtc 
     12       1.1       jtc /*
     13       1.4   hubertf  *	Contains a routine to search a : separated list of
     14       1.6   mycroft  *	paths (a la CDPATH) and make appropriate file names.
     15       1.1       jtc  *	Also contains a routine to simplify .'s and ..'s out of
     16       1.1       jtc  *	a path name.
     17       1.1       jtc  *
     18       1.1       jtc  *	Larry Bouzane (larry (at) cs.mun.ca)
     19       1.1       jtc  */
     20       1.1       jtc 
     21       1.1       jtc #ifdef S_ISLNK
     22       1.7  christos static char	*do_phys_path ARGS((XString *, char *, const char *));
     23       1.1       jtc #endif /* S_ISLNK */
     24       1.1       jtc 
     25       1.1       jtc /*
     26       1.1       jtc  *	Makes a filename into result using the following algorithm.
     27       1.1       jtc  *	- make result NULL
     28       1.1       jtc  *	- if file starts with '/', append file to result & set cdpathp to NULL
     29       1.1       jtc  *	- if file starts with ./ or ../ append cwd and file to result
     30       1.1       jtc  *	  and set cdpathp to NULL
     31       1.1       jtc  *	- if the first element of cdpathp doesnt start with a '/' xx or '.' xx
     32       1.1       jtc  *	  then cwd is appended to result.
     33       1.1       jtc  *	- the first element of cdpathp is appended to result
     34       1.1       jtc  *	- file is appended to result
     35       1.1       jtc  *	- cdpathp is set to the start of the next element in cdpathp (or NULL
     36       1.1       jtc  *	  if there are no more elements.
     37       1.1       jtc  *	The return value indicates whether a non-null element from cdpathp
     38       1.6   mycroft  *	was appended to result.
     39       1.1       jtc  */
     40       1.1       jtc int
     41       1.1       jtc make_path(cwd, file, cdpathp, xsp, phys_pathp)
     42       1.1       jtc 	const char *cwd;
     43       1.1       jtc 	const char *file;
     44       1.4   hubertf 	char	**cdpathp;	/* & of : separated list */
     45       1.1       jtc 	XString	*xsp;
     46       1.1       jtc 	int	*phys_pathp;
     47       1.1       jtc {
     48       1.1       jtc 	int	rval = 0;
     49       1.1       jtc 	int	use_cdpath = 1;
     50       1.1       jtc 	char	*plist;
     51       1.1       jtc 	int	len;
     52       1.1       jtc 	int	plen = 0;
     53       1.1       jtc 	char	*xp = Xstring(*xsp, xp);
     54       1.1       jtc 
     55       1.1       jtc 	if (!file)
     56       1.1       jtc 		file = null;
     57       1.1       jtc 
     58       1.1       jtc 	if (!ISRELPATH(file)) {
     59       1.1       jtc 		*phys_pathp = 0;
     60       1.1       jtc 		use_cdpath = 0;
     61       1.1       jtc 	} else {
     62       1.1       jtc 		if (file[0] == '.') {
     63       1.1       jtc 			char c = file[1];
     64       1.1       jtc 
     65       1.1       jtc 			if (c == '.')
     66       1.1       jtc 				c = file[2];
     67       1.1       jtc 			if (ISDIRSEP(c) || c == '\0')
     68       1.1       jtc 				use_cdpath = 0;
     69       1.1       jtc 		}
     70       1.1       jtc 
     71       1.1       jtc 		plist = *cdpathp;
     72       1.1       jtc 		if (!plist)
     73       1.1       jtc 			use_cdpath = 0;
     74       1.1       jtc 		else if (use_cdpath) {
     75       1.1       jtc 			char *pend;
     76       1.1       jtc 
     77       1.1       jtc 			for (pend = plist; *pend && *pend != PATHSEP; pend++)
     78       1.1       jtc 				;
     79       1.1       jtc 			plen = pend - plist;
     80       1.1       jtc 			*cdpathp = *pend ? ++pend : (char *) 0;
     81       1.1       jtc 		}
     82       1.1       jtc 
     83       1.1       jtc 		if ((use_cdpath == 0 || !plen || ISRELPATH(plist))
     84       1.1       jtc 		    && (cwd && *cwd))
     85       1.1       jtc 		{
     86       1.1       jtc 			len = strlen(cwd);
     87       1.1       jtc 			XcheckN(*xsp, xp, len);
     88       1.1       jtc 			memcpy(xp, cwd, len);
     89       1.1       jtc 			xp += len;
     90       1.1       jtc 			if (!ISDIRSEP(cwd[len - 1]))
     91       1.1       jtc 				Xput(*xsp, xp, DIRSEP);
     92       1.1       jtc 		}
     93       1.1       jtc 		*phys_pathp = Xlength(*xsp, xp);
     94       1.1       jtc 		if (use_cdpath && plen) {
     95       1.1       jtc 			XcheckN(*xsp, xp, plen);
     96       1.1       jtc 			memcpy(xp, plist, plen);
     97       1.1       jtc 			xp += plen;
     98       1.1       jtc 			if (!ISDIRSEP(plist[plen - 1]))
     99       1.1       jtc 				Xput(*xsp, xp, DIRSEP);
    100       1.1       jtc 			rval = 1;
    101       1.1       jtc 		}
    102       1.1       jtc 	}
    103       1.1       jtc 
    104       1.1       jtc 	len = strlen(file) + 1;
    105       1.1       jtc 	XcheckN(*xsp, xp, len);
    106       1.1       jtc 	memcpy(xp, file, len);
    107       1.1       jtc 
    108       1.1       jtc 	if (!use_cdpath)
    109       1.1       jtc 		*cdpathp = (char *) 0;
    110       1.1       jtc 
    111       1.1       jtc 	return rval;
    112       1.1       jtc }
    113       1.1       jtc 
    114       1.1       jtc /*
    115       1.1       jtc  * Simplify pathnames containing "." and ".." entries.
    116       1.1       jtc  * ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
    117       1.1       jtc  */
    118       1.1       jtc void
    119       1.7  christos simplify_path(pathx)
    120       1.7  christos 	char	*pathx;
    121       1.1       jtc {
    122       1.1       jtc 	char	*cur;
    123       1.1       jtc 	char	*t;
    124       1.1       jtc 	int	isrooted;
    125       1.7  christos 	char	*very_start = pathx;
    126       1.1       jtc 	char	*start;
    127       1.1       jtc 
    128       1.7  christos 	if (!*pathx)
    129       1.1       jtc 		return;
    130       1.1       jtc 
    131       1.7  christos 	if ((isrooted = ISROOTEDPATH(pathx)))
    132       1.1       jtc 		very_start++;
    133       1.4   hubertf #if defined (OS2) || defined (__CYGWIN__)
    134       1.7  christos 	if (pathx[0] && pathx[1] == ':')	/* skip a: */
    135       1.1       jtc 		very_start += 2;
    136       1.4   hubertf #endif /* OS2 || __CYGWIN__ */
    137       1.1       jtc 
    138       1.1       jtc 	/* Before			After
    139       1.1       jtc 	 *  /foo/			/foo
    140       1.1       jtc 	 *  /foo/../../bar		/bar
    141       1.1       jtc 	 *  /foo/./blah/..		/foo
    142       1.1       jtc 	 *  .				.
    143       1.1       jtc 	 *  ..				..
    144       1.1       jtc 	 *  ./foo			foo
    145       1.1       jtc 	 *  foo/../../../bar		../../bar
    146       1.4   hubertf 	 * OS2 and CYGWIN:
    147       1.1       jtc 	 *  a:/foo/../..		a:/
    148       1.1       jtc 	 *  a:.				a:
    149       1.1       jtc 	 *  a:..			a:..
    150       1.1       jtc 	 *  a:foo/../../blah		a:../blah
    151       1.1       jtc 	 */
    152       1.4   hubertf 
    153       1.4   hubertf #ifdef __CYGWIN__
    154       1.4   hubertf        /* preserve leading double-slash on pathnames (for UNC paths) */
    155       1.7  christos        if (pathx[0] && ISDIRSEP(pathx[0]) && pathx[1] && ISDIRSEP(pathx[1]))
    156       1.4   hubertf                very_start++;
    157       1.4   hubertf #endif /* __CYGWIN__ */
    158       1.1       jtc 
    159       1.1       jtc 	for (cur = t = start = very_start; ; ) {
    160       1.1       jtc 		/* treat multiple '/'s as one '/' */
    161       1.1       jtc 		while (ISDIRSEP(*t))
    162       1.1       jtc 			t++;
    163       1.1       jtc 
    164       1.1       jtc 		if (*t == '\0') {
    165       1.7  christos 			if (cur == pathx)
    166       1.1       jtc 				/* convert empty path to dot */
    167       1.1       jtc 				*cur++ = '.';
    168       1.1       jtc 			*cur = '\0';
    169       1.1       jtc 			break;
    170       1.1       jtc 		}
    171       1.1       jtc 
    172       1.1       jtc 		if (t[0] == '.') {
    173       1.1       jtc 			if (!t[1] || ISDIRSEP(t[1])) {
    174       1.1       jtc 				t += 1;
    175       1.1       jtc 				continue;
    176       1.1       jtc 			} else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) {
    177       1.1       jtc 				if (!isrooted && cur == start) {
    178       1.1       jtc 					if (cur != very_start)
    179       1.1       jtc 						*cur++ = DIRSEP;
    180       1.1       jtc 					*cur++ = '.';
    181       1.1       jtc 					*cur++ = '.';
    182       1.1       jtc 					start = cur;
    183       1.1       jtc 				} else if (cur != start)
    184       1.1       jtc 					while (--cur > start && !ISDIRSEP(*cur))
    185       1.1       jtc 						;
    186       1.1       jtc 				t += 2;
    187       1.1       jtc 				continue;
    188       1.1       jtc 			}
    189       1.1       jtc 		}
    190       1.1       jtc 
    191       1.1       jtc 		if (cur != very_start)
    192       1.1       jtc 			*cur++ = DIRSEP;
    193       1.1       jtc 
    194       1.1       jtc 		/* find/copy next component of pathname */
    195       1.1       jtc 		while (*t && !ISDIRSEP(*t))
    196       1.1       jtc 			*cur++ = *t++;
    197       1.1       jtc 	}
    198       1.1       jtc }
    199       1.1       jtc 
    200       1.1       jtc 
    201       1.1       jtc void
    202       1.7  christos set_current_wd(pathx)
    203       1.7  christos 	char *pathx;
    204       1.1       jtc {
    205       1.1       jtc 	int len;
    206       1.7  christos 	char *p = pathx;
    207       1.1       jtc 
    208       1.1       jtc 	if (!p && !(p = ksh_get_wd((char *) 0, 0)))
    209       1.1       jtc 		p = null;
    210       1.1       jtc 
    211       1.1       jtc 	len = strlen(p) + 1;
    212       1.1       jtc 
    213       1.1       jtc 	if (len > current_wd_size)
    214       1.1       jtc 		current_wd = aresize(current_wd, current_wd_size = len, APERM);
    215       1.1       jtc 	memcpy(current_wd, p, len);
    216       1.7  christos 	if (p != pathx && p != null)
    217       1.1       jtc 		afree(p, ATEMP);
    218       1.1       jtc }
    219       1.1       jtc 
    220       1.1       jtc #ifdef S_ISLNK
    221       1.1       jtc char *
    222       1.7  christos get_phys_path(pathx)
    223       1.7  christos 	const char *pathx;
    224       1.1       jtc {
    225       1.1       jtc 	XString xs;
    226       1.1       jtc 	char *xp;
    227       1.1       jtc 
    228       1.7  christos 	Xinit(xs, xp, strlen(pathx) + 1, ATEMP);
    229       1.1       jtc 
    230       1.7  christos 	xp = do_phys_path(&xs, xp, pathx);
    231       1.1       jtc 
    232       1.1       jtc 	if (!xp)
    233       1.1       jtc 		return (char *) 0;
    234       1.1       jtc 
    235       1.1       jtc 	if (Xlength(xs, xp) == 0)
    236       1.1       jtc 		Xput(xs, xp, DIRSEP);
    237       1.1       jtc 	Xput(xs, xp, '\0');
    238       1.1       jtc 
    239       1.1       jtc 	return Xclose(xs, xp);
    240       1.1       jtc }
    241       1.1       jtc 
    242       1.1       jtc static char *
    243       1.7  christos do_phys_path(xsp, xp, pathx)
    244       1.1       jtc 	XString *xsp;
    245       1.1       jtc 	char *xp;
    246       1.7  christos 	const char *pathx;
    247       1.1       jtc {
    248       1.1       jtc 	const char *p, *q;
    249       1.1       jtc 	int len, llen;
    250       1.1       jtc 	int savepos;
    251       1.1       jtc 	char lbuf[PATH];
    252       1.1       jtc 
    253       1.1       jtc 	Xcheck(*xsp, xp);
    254       1.7  christos 	for (p = pathx; p; p = q) {
    255       1.1       jtc 		while (ISDIRSEP(*p))
    256       1.1       jtc 			p++;
    257       1.1       jtc 		if (!*p)
    258       1.1       jtc 			break;
    259  1.7.28.1       jym 		len = (q = ksh_strchr_dirsep(p)) ? q - p : (int)strlen(p);
    260       1.1       jtc 		if (len == 1 && p[0] == '.')
    261       1.1       jtc 			continue;
    262       1.1       jtc 		if (len == 2 && p[0] == '.' && p[1] == '.') {
    263       1.1       jtc 			while (xp > Xstring(*xsp, xp)) {
    264       1.1       jtc 				xp--;
    265       1.1       jtc 				if (ISDIRSEP(*xp))
    266       1.1       jtc 					break;
    267       1.1       jtc 			}
    268       1.1       jtc 			continue;
    269       1.1       jtc 		}
    270       1.1       jtc 
    271       1.1       jtc 		savepos = Xsavepos(*xsp, xp);
    272       1.1       jtc 		Xput(*xsp, xp, DIRSEP);
    273       1.1       jtc 		XcheckN(*xsp, xp, len + 1);
    274       1.1       jtc 		memcpy(xp, p, len);
    275       1.1       jtc 		xp += len;
    276       1.1       jtc 		*xp = '\0';
    277       1.1       jtc 
    278       1.1       jtc 		llen = readlink(Xstring(*xsp, xp), lbuf, sizeof(lbuf) - 1);
    279       1.1       jtc 		if (llen < 0) {
    280       1.1       jtc 			/* EINVAL means it wasn't a symlink... */
    281       1.1       jtc 			if (errno != EINVAL)
    282       1.1       jtc 				return (char *) 0;
    283       1.1       jtc 			continue;
    284       1.1       jtc 		}
    285       1.1       jtc 		lbuf[llen] = '\0';
    286       1.1       jtc 
    287       1.1       jtc 		/* If absolute path, start from scratch.. */
    288       1.1       jtc 		xp = ISABSPATH(lbuf) ? Xstring(*xsp, xp)
    289       1.1       jtc 				     : Xrestpos(*xsp, xp, savepos);
    290       1.1       jtc 		if (!(xp = do_phys_path(xsp, xp, lbuf)))
    291       1.1       jtc 			return (char *) 0;
    292       1.1       jtc 	}
    293       1.1       jtc 	return xp;
    294       1.1       jtc }
    295       1.1       jtc #endif /* S_ISLNK */
    296       1.1       jtc 
    297       1.1       jtc #ifdef	TEST
    298       1.1       jtc 
    299       1.1       jtc main(argc, argv)
    300       1.1       jtc {
    301       1.1       jtc 	int	rv;
    302       1.1       jtc 	char	*cp, cdpath[256], pwd[256], file[256], result[256];
    303       1.1       jtc 
    304       1.1       jtc 	printf("enter CDPATH: "); gets(cdpath);
    305       1.1       jtc 	printf("enter PWD: "); gets(pwd);
    306       1.1       jtc 	while (1) {
    307       1.1       jtc 		if (printf("Enter file: "), gets(file) == 0)
    308       1.1       jtc 			return 0;
    309       1.1       jtc 		cp = cdpath;
    310       1.1       jtc 		do {
    311       1.1       jtc 			rv = make_path(pwd, file, &cp, result, sizeof(result));
    312       1.1       jtc 			printf("make_path returns (%d), \"%s\" ", rv, result);
    313       1.1       jtc 			simplify_path(result);
    314       1.1       jtc 			printf("(simpifies to \"%s\")\n", result);
    315       1.1       jtc 		} while (cp);
    316       1.1       jtc 	}
    317       1.1       jtc }
    318       1.1       jtc #endif	/* TEST */
    319