diff options
author | John Ankarström <john@ankarstrom.se> | 2021-06-07 14:12:11 +0200 |
---|---|---|
committer | John Ankarström <john@ankarstrom.se> | 2021-06-07 14:12:11 +0200 |
commit | e2294b61e15781ca784a611e8ca7dabe132ebc6d (patch) | |
tree | c2a8cc44582534f52a76b1b8e64e6f83ffa501da /path.c | |
download | ksh-e2294b61e15781ca784a611e8ca7dabe132ebc6d.tar.gz |
First commit (NetBSD 9.1)
Diffstat (limited to 'path.c')
-rw-r--r-- | path.c | 303 |
1 files changed, 303 insertions, 0 deletions
@@ -0,0 +1,303 @@ +/* $NetBSD: path.c,v 1.13 2017/06/30 03:56:12 kamil Exp $ */ +#include <sys/cdefs.h> + +#ifndef lint +__RCSID("$NetBSD: path.c,v 1.13 2017/06/30 03:56:12 kamil Exp $"); +#endif + +#include <sys/stat.h> + +#include "sh.h" + +/* + * Contains a routine to search a : separated list of + * paths (a la CDPATH) and make appropriate file names. + * Also contains a routine to simplify .'s and ..'s out of + * a path name. + * + * Larry Bouzane (larry@cs.mun.ca) + */ + +#ifdef S_ISLNK +static char *do_phys_path ARGS((XString *, char *, const char *)); +#endif /* S_ISLNK */ + +/* + * Makes a filename into result using the following algorithm. + * - make result NULL + * - if file starts with '/', append file to result & set cdpathp to NULL + * - if file starts with ./ or ../ append cwd and file to result + * and set cdpathp to NULL + * - if the first element of cdpathp doesnt start with a '/' xx or '.' xx + * then cwd is appended to result. + * - the first element of cdpathp is appended to result + * - file is appended to result + * - cdpathp is set to the start of the next element in cdpathp (or NULL + * if there are no more elements. + * The return value indicates whether a non-null element from cdpathp + * was appended to result. + */ +int +make_path(cwd, file, cdpathp, xsp, phys_pathp) + const char *cwd; + const char *file; + char **cdpathp; /* & of : separated list */ + XString *xsp; + int *phys_pathp; +{ + int rval = 0; + int use_cdpath = 1; + char *plist; + int len; + int plen = 0; + char *xp = Xstring(*xsp, xp); + + if (!file) + file = null; + + if (!ISRELPATH(file)) { + *phys_pathp = 0; + use_cdpath = 0; + } else { + if (file[0] == '.') { + char c = file[1]; + + if (c == '.') + c = file[2]; + if (ISDIRSEP(c) || c == '\0') + use_cdpath = 0; + } + + plist = *cdpathp; + if (!plist) + use_cdpath = 0; + else if (use_cdpath) { + char *pend; + + for (pend = plist; *pend && *pend != PATHSEP; pend++) + ; + plen = pend - plist; + *cdpathp = *pend ? ++pend : (char *) 0; + } + + if ((use_cdpath == 0 || !plen || ISRELPATH(plist)) + && (cwd && *cwd)) + { + len = strlen(cwd); + XcheckN(*xsp, xp, len); + memcpy(xp, cwd, len); + xp += len; + if (!ISDIRSEP(cwd[len - 1])) + Xput(*xsp, xp, DIRSEP); + } + *phys_pathp = Xlength(*xsp, xp); + if (use_cdpath && plen) { + XcheckN(*xsp, xp, plen); + memcpy(xp, plist, plen); + xp += plen; + if (!ISDIRSEP(plist[plen - 1])) + Xput(*xsp, xp, DIRSEP); + rval = 1; + } + } + + len = strlen(file) + 1; + XcheckN(*xsp, xp, len); + memcpy(xp, file, len); + + if (!use_cdpath) + *cdpathp = (char *) 0; + + return rval; +} + +/* + * Simplify pathnames containing "." and ".." entries. + * ie, simplify_path("/a/b/c/./../d/..") returns "/a/b" + */ +void +simplify_path(pathx) + char *pathx; +{ + char *cur; + char *t; + int isrooted; + char *very_start = pathx; + char *start; + + if (!*pathx) + return; + + if ((isrooted = ISROOTEDPATH(pathx))) + very_start++; + + /* Before After + * /foo/ /foo + * /foo/../../bar /bar + * /foo/./blah/.. /foo + * . . + * .. .. + * ./foo foo + * foo/../../../bar ../../bar + */ + + for (cur = t = start = very_start; ; ) { + /* treat multiple '/'s as one '/' */ + while (ISDIRSEP(*t)) + t++; + + if (*t == '\0') { + if (cur == pathx) + /* convert empty path to dot */ + *cur++ = '.'; + *cur = '\0'; + break; + } + + if (t[0] == '.') { + if (!t[1] || ISDIRSEP(t[1])) { + t += 1; + continue; + } else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) { + if (!isrooted && cur == start) { + if (cur != very_start) + *cur++ = DIRSEP; + *cur++ = '.'; + *cur++ = '.'; + start = cur; + } else if (cur != start) + while (--cur > start && !ISDIRSEP(*cur)) + ; + t += 2; + continue; + } + } + + if (cur != very_start) + *cur++ = DIRSEP; + + /* find/copy next component of pathname */ + while (*t && !ISDIRSEP(*t)) + *cur++ = *t++; + } +} + + +void +set_current_wd(pathx) + char *pathx; +{ + int len; + char *p = pathx; + + if (!p && !(p = ksh_get_wd((char *) 0, 0))) + p = null; + + len = strlen(p) + 1; + + if (len > current_wd_size) + current_wd = aresize(current_wd, current_wd_size = len, APERM); + memcpy(current_wd, p, len); + if (p != pathx && p != null) + afree(p, ATEMP); +} + +#ifdef S_ISLNK +char * +get_phys_path(pathx) + const char *pathx; +{ + XString xs; + char *xp; + + Xinit(xs, xp, strlen(pathx) + 1, ATEMP); + + xp = do_phys_path(&xs, xp, pathx); + + if (!xp) + return (char *) 0; + + if (Xlength(xs, xp) == 0) + Xput(xs, xp, DIRSEP); + Xput(xs, xp, '\0'); + + return Xclose(xs, xp); +} + +static char * +do_phys_path(xsp, xp, pathx) + XString *xsp; + char *xp; + const char *pathx; +{ + const char *p, *q; + int len, llen; + int savepos; + char lbuf[PATH]; + + Xcheck(*xsp, xp); + for (p = pathx; p; p = q) { + while (ISDIRSEP(*p)) + p++; + if (!*p) + break; + len = (q = ksh_strchr_dirsep(p)) ? q - p : (int)strlen(p); + if (len == 1 && p[0] == '.') + continue; + if (len == 2 && p[0] == '.' && p[1] == '.') { + while (xp > Xstring(*xsp, xp)) { + xp--; + if (ISDIRSEP(*xp)) + break; + } + continue; + } + + savepos = Xsavepos(*xsp, xp); + Xput(*xsp, xp, DIRSEP); + XcheckN(*xsp, xp, len + 1); + memcpy(xp, p, len); + xp += len; + *xp = '\0'; + + llen = readlink(Xstring(*xsp, xp), lbuf, sizeof(lbuf) - 1); + if (llen < 0) { + /* EINVAL means it wasn't a symlink... */ + if (errno != EINVAL) + return (char *) 0; + continue; + } + lbuf[llen] = '\0'; + + /* If absolute path, start from scratch.. */ + xp = ISABSPATH(lbuf) ? Xstring(*xsp, xp) + : Xrestpos(*xsp, xp, savepos); + if (!(xp = do_phys_path(xsp, xp, lbuf))) + return (char *) 0; + } + return xp; +} +#endif /* S_ISLNK */ + +#ifdef TEST + +main(argc, argv) +{ + int rv; + char *cp, cdpath[256], pwd[256], file[256], result[256]; + + printf("enter CDPATH: "); gets(cdpath); + printf("enter PWD: "); gets(pwd); + while (1) { + if (printf("Enter file: "), gets(file) == 0) + return 0; + cp = cdpath; + do { + rv = make_path(pwd, file, &cp, result, sizeof(result)); + printf("make_path returns (%d), \"%s\" ", rv, result); + simplify_path(result); + printf("(simpifies to \"%s\")\n", result); + } while (cp); + } +} +#endif /* TEST */ |