Home | History | Annotate | Line # | Download | only in ksh
      1  1.14    andvar /*	$NetBSD: path.c,v 1.14 2022/10/31 21:22:05 andvar Exp $	*/
      2   1.5       agc #include <sys/cdefs.h>
      3   1.5       agc 
      4   1.5       agc #ifndef lint
      5  1.14    andvar __RCSID("$NetBSD: path.c,v 1.14 2022/10/31 21:22:05 andvar Exp $");
      6   1.5       agc #endif
      7   1.5       agc 
      8  1.13     kamil #include <sys/stat.h>
      9   1.2       tls 
     10   1.1       jtc #include "sh.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.1       jtc 
    134   1.1       jtc 	/* Before			After
    135   1.1       jtc 	 *  /foo/			/foo
    136   1.1       jtc 	 *  /foo/../../bar		/bar
    137   1.1       jtc 	 *  /foo/./blah/..		/foo
    138   1.1       jtc 	 *  .				.
    139   1.1       jtc 	 *  ..				..
    140   1.1       jtc 	 *  ./foo			foo
    141   1.1       jtc 	 *  foo/../../../bar		../../bar
    142   1.1       jtc 	 */
    143   1.4   hubertf 
    144   1.1       jtc 	for (cur = t = start = very_start; ; ) {
    145   1.1       jtc 		/* treat multiple '/'s as one '/' */
    146   1.1       jtc 		while (ISDIRSEP(*t))
    147   1.1       jtc 			t++;
    148   1.1       jtc 
    149   1.1       jtc 		if (*t == '\0') {
    150   1.7  christos 			if (cur == pathx)
    151   1.1       jtc 				/* convert empty path to dot */
    152   1.1       jtc 				*cur++ = '.';
    153   1.1       jtc 			*cur = '\0';
    154   1.1       jtc 			break;
    155   1.1       jtc 		}
    156   1.1       jtc 
    157   1.1       jtc 		if (t[0] == '.') {
    158   1.1       jtc 			if (!t[1] || ISDIRSEP(t[1])) {
    159   1.1       jtc 				t += 1;
    160   1.1       jtc 				continue;
    161   1.1       jtc 			} else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) {
    162   1.1       jtc 				if (!isrooted && cur == start) {
    163   1.1       jtc 					if (cur != very_start)
    164   1.1       jtc 						*cur++ = DIRSEP;
    165   1.1       jtc 					*cur++ = '.';
    166   1.1       jtc 					*cur++ = '.';
    167   1.1       jtc 					start = cur;
    168   1.1       jtc 				} else if (cur != start)
    169   1.1       jtc 					while (--cur > start && !ISDIRSEP(*cur))
    170   1.1       jtc 						;
    171   1.1       jtc 				t += 2;
    172   1.1       jtc 				continue;
    173   1.1       jtc 			}
    174   1.1       jtc 		}
    175   1.1       jtc 
    176   1.1       jtc 		if (cur != very_start)
    177   1.1       jtc 			*cur++ = DIRSEP;
    178   1.1       jtc 
    179   1.1       jtc 		/* find/copy next component of pathname */
    180   1.1       jtc 		while (*t && !ISDIRSEP(*t))
    181   1.1       jtc 			*cur++ = *t++;
    182   1.1       jtc 	}
    183   1.1       jtc }
    184   1.1       jtc 
    185   1.1       jtc 
    186   1.1       jtc void
    187   1.7  christos set_current_wd(pathx)
    188   1.7  christos 	char *pathx;
    189   1.1       jtc {
    190   1.1       jtc 	int len;
    191   1.7  christos 	char *p = pathx;
    192   1.1       jtc 
    193   1.1       jtc 	if (!p && !(p = ksh_get_wd((char *) 0, 0)))
    194   1.1       jtc 		p = null;
    195   1.1       jtc 
    196   1.1       jtc 	len = strlen(p) + 1;
    197   1.1       jtc 
    198   1.1       jtc 	if (len > current_wd_size)
    199   1.1       jtc 		current_wd = aresize(current_wd, current_wd_size = len, APERM);
    200   1.1       jtc 	memcpy(current_wd, p, len);
    201   1.7  christos 	if (p != pathx && p != null)
    202   1.1       jtc 		afree(p, ATEMP);
    203   1.1       jtc }
    204   1.1       jtc 
    205   1.1       jtc #ifdef S_ISLNK
    206   1.1       jtc char *
    207   1.7  christos get_phys_path(pathx)
    208   1.7  christos 	const char *pathx;
    209   1.1       jtc {
    210   1.1       jtc 	XString xs;
    211   1.1       jtc 	char *xp;
    212   1.1       jtc 
    213   1.7  christos 	Xinit(xs, xp, strlen(pathx) + 1, ATEMP);
    214   1.1       jtc 
    215   1.7  christos 	xp = do_phys_path(&xs, xp, pathx);
    216   1.1       jtc 
    217   1.1       jtc 	if (!xp)
    218   1.1       jtc 		return (char *) 0;
    219   1.1       jtc 
    220   1.1       jtc 	if (Xlength(xs, xp) == 0)
    221   1.1       jtc 		Xput(xs, xp, DIRSEP);
    222   1.1       jtc 	Xput(xs, xp, '\0');
    223   1.1       jtc 
    224   1.1       jtc 	return Xclose(xs, xp);
    225   1.1       jtc }
    226   1.1       jtc 
    227   1.1       jtc static char *
    228   1.7  christos do_phys_path(xsp, xp, pathx)
    229   1.1       jtc 	XString *xsp;
    230   1.1       jtc 	char *xp;
    231   1.7  christos 	const char *pathx;
    232   1.1       jtc {
    233   1.1       jtc 	const char *p, *q;
    234   1.1       jtc 	int len, llen;
    235   1.1       jtc 	int savepos;
    236   1.1       jtc 	char lbuf[PATH];
    237   1.1       jtc 
    238   1.1       jtc 	Xcheck(*xsp, xp);
    239   1.7  christos 	for (p = pathx; p; p = q) {
    240   1.1       jtc 		while (ISDIRSEP(*p))
    241   1.1       jtc 			p++;
    242   1.1       jtc 		if (!*p)
    243   1.1       jtc 			break;
    244   1.8     lukem 		len = (q = ksh_strchr_dirsep(p)) ? q - p : (int)strlen(p);
    245   1.1       jtc 		if (len == 1 && p[0] == '.')
    246   1.1       jtc 			continue;
    247   1.1       jtc 		if (len == 2 && p[0] == '.' && p[1] == '.') {
    248   1.1       jtc 			while (xp > Xstring(*xsp, xp)) {
    249   1.1       jtc 				xp--;
    250   1.1       jtc 				if (ISDIRSEP(*xp))
    251   1.1       jtc 					break;
    252   1.1       jtc 			}
    253   1.1       jtc 			continue;
    254   1.1       jtc 		}
    255   1.1       jtc 
    256   1.1       jtc 		savepos = Xsavepos(*xsp, xp);
    257   1.1       jtc 		Xput(*xsp, xp, DIRSEP);
    258   1.1       jtc 		XcheckN(*xsp, xp, len + 1);
    259   1.1       jtc 		memcpy(xp, p, len);
    260   1.1       jtc 		xp += len;
    261   1.1       jtc 		*xp = '\0';
    262   1.1       jtc 
    263   1.1       jtc 		llen = readlink(Xstring(*xsp, xp), lbuf, sizeof(lbuf) - 1);
    264   1.1       jtc 		if (llen < 0) {
    265   1.1       jtc 			/* EINVAL means it wasn't a symlink... */
    266   1.1       jtc 			if (errno != EINVAL)
    267   1.1       jtc 				return (char *) 0;
    268   1.1       jtc 			continue;
    269   1.1       jtc 		}
    270   1.1       jtc 		lbuf[llen] = '\0';
    271   1.1       jtc 
    272   1.1       jtc 		/* If absolute path, start from scratch.. */
    273   1.1       jtc 		xp = ISABSPATH(lbuf) ? Xstring(*xsp, xp)
    274   1.1       jtc 				     : Xrestpos(*xsp, xp, savepos);
    275   1.1       jtc 		if (!(xp = do_phys_path(xsp, xp, lbuf)))
    276   1.1       jtc 			return (char *) 0;
    277   1.1       jtc 	}
    278   1.1       jtc 	return xp;
    279   1.1       jtc }
    280   1.1       jtc #endif /* S_ISLNK */
    281   1.1       jtc 
    282   1.1       jtc #ifdef	TEST
    283   1.1       jtc 
    284   1.1       jtc main(argc, argv)
    285   1.1       jtc {
    286   1.1       jtc 	int	rv;
    287   1.1       jtc 	char	*cp, cdpath[256], pwd[256], file[256], result[256];
    288   1.1       jtc 
    289   1.1       jtc 	printf("enter CDPATH: "); gets(cdpath);
    290   1.1       jtc 	printf("enter PWD: "); gets(pwd);
    291   1.1       jtc 	while (1) {
    292   1.1       jtc 		if (printf("Enter file: "), gets(file) == 0)
    293   1.1       jtc 			return 0;
    294   1.1       jtc 		cp = cdpath;
    295   1.1       jtc 		do {
    296   1.1       jtc 			rv = make_path(pwd, file, &cp, result, sizeof(result));
    297   1.1       jtc 			printf("make_path returns (%d), \"%s\" ", rv, result);
    298   1.1       jtc 			simplify_path(result);
    299  1.14    andvar 			printf("(simplifies to \"%s\")\n", result);
    300   1.1       jtc 		} while (cp);
    301   1.1       jtc 	}
    302   1.1       jtc }
    303   1.1       jtc #endif	/* TEST */
    304