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