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