static Char * dgoto(Char *cp) { Char *dp, *ret; if (!ABSOLUTEP(cp)) { Char *p, *q; size_t cwdlen; cwdlen = Strlen(dcwd->di_name); if (cwdlen == 1) /* root */ cwdlen = 0; dp = xmalloc((cwdlen + Strlen(cp) + 2) * sizeof(Char)); for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';) continue; if (cwdlen) p[-1] = '/'; else p--; /* don't add a / after root */ Strcpy(p, cp); xfree(cp); cp = dp; dp += cwdlen; } else dp = cp; #if defined(WINNT_NATIVE) return agetcwd(); #elif defined(__CYGWIN__) if (ABSOLUTEP(cp) && cp[1] == ':') { /* Only DOS paths are treated that way */ return agetcwd(); } else { cleanup_push(cp, xfree); ret = dcanon(cp, dp); cleanup_ignore(cp); cleanup_until(cp); } #else /* !WINNT_NATIVE */ cleanup_push(cp, xfree); ret = dcanon(cp, dp); cleanup_ignore(cp); cleanup_until(cp); #endif /* WINNT_NATIVE */ return ret; }
int nt_try_fast_exec(struct command *t) { register Char **pv, **av; register Char *dp,*sav; register char **tt; register char *f; register struct varent *v; register int hashval,i; register int slash; int rc = 0, gflag; Char *vp; Char *blk[2]; vp = varval(STRNTslowexec); if (vp != STRNULL) return 1; blk[0] = t->t_dcom[0]; blk[1] = 0; // don't do backtick if(Strchr(t->t_dcom[0],'`') ) return 1; gflag = tglob(blk); if (gflag) { pv = globall(blk, gflag); if (pv == 0) { return 1; } } else pv = saveblk(blk); trim(pv); epath = Strsave(pv[0]); v = adrof(STRpath); if (v == 0 && epath[0] != '/' && epath[0] != '.') { blkfree(pv); return 1; } slash = any(short2str(epath),'/'); /* * Glob the argument list, if necessary. Otherwise trim off the quote bits. */ av = &t->t_dcom[1]; gflag = tglob(av); if (gflag) { av = globall(av, gflag);/*FIXRESET*/ if (av == 0) { blkfree(pv); return 1; } } else av = saveblk(av); blkfree(t->t_dcom); t->t_dcom = blkspl(pv, av); xfree((ptr_t) pv); xfree((ptr_t) av); av = t->t_dcom; //trim(av); if (*av == NULL || **av == '\0') return 1; xechoit(av);/*FIXRESET*/ /* Echo command if -x */ if (v == 0 || v->vec[0] == 0 || slash) pv = abspath; else pv = v->vec; sav = Strspl(STRslash,*av); hashval = hashval_extern(*av); i = 0; do { #pragma warning(disable:4310) if (!slash && ABSOLUTEP(pv[0]) && havhash) { #pragma warning(default:4310) if (!bit_extern(hashval,i)){ pv++;i++; continue; } } if (pv[0][0] == 0 || eq(pv[0],STRdot)) { tt = short2blk(av); f = short2str(*av); rc = nt_texec(f, tt); blkfree((Char**)tt); if (!rc) break; } else { dp = Strspl(*pv,sav); tt = short2blk(av); f = short2str(dp); rc = nt_texec(f, tt); blkfree((Char**)tt); xfree((ptr_t)dp); if (!rc) break; } pv++; i++; }while(*pv); return rc; }
/* * dcanon - canonicalize the pathname, removing excess ./ and ../ etc. * we are of course assuming that the file system is standardly * constructed (always have ..'s, directories have links) */ Char * dcanon(Char *cp, Char *p) { Char *sp; Char *p1, *p2; /* general purpose */ int slash; #ifdef HAVE_SLASHSLASH int slashslash; #endif /* HAVE_SLASHSLASH */ size_t clen; #ifdef S_IFLNK /* if we have symlinks */ Char *mlink, *newcp; char *tlink; size_t cc; #endif /* S_IFLNK */ clen = Strlen(cp); /* * christos: if the path given does not start with a slash prepend cwd. If * cwd does not start with a slash or the result would be too long try to * correct it. */ if (!ABSOLUTEP(cp)) { Char *tmpdir; size_t len; p1 = varval(STRcwd); if (p1 == STRNULL || !ABSOLUTEP(p1)) { Char *new_cwd = agetcwd(); if (new_cwd == NULL) { xprintf("%s: %s\n", progname, strerror(errno)); setcopy(STRcwd, str2short("/"), VAR_READWRITE|VAR_NOGLOB); } else setv(STRcwd, new_cwd, VAR_READWRITE|VAR_NOGLOB); p1 = varval(STRcwd); } len = Strlen(p1); tmpdir = xmalloc((len + clen + 2) * sizeof (*tmpdir)); (void) Strcpy(tmpdir, p1); (void) Strcat(tmpdir, STRslash); (void) Strcat(tmpdir, cp); xfree(cp); cp = p = tmpdir; } #ifdef HAVE_SLASHSLASH slashslash = (cp[0] == '/' && cp[1] == '/'); #endif /* HAVE_SLASHSLASH */ while (*p) { /* for each component */ sp = p; /* save slash address */ while (*++p == '/') /* flush extra slashes */ continue; if (p != ++sp) for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';) continue; p = sp; /* save start of component */ slash = 0; if (*p) while (*++p) /* find next slash or end of path */ if (*p == '/') { slash = 1; *p = 0; break; } #ifdef HAVE_SLASHSLASH if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0') slashslash = 1; #endif /* HAVE_SLASHSLASH */ if (*sp == '\0') { /* if component is null */ if (--sp == cp) /* if path is one char (i.e. /) */ break; else *sp = '\0'; } else if (sp[0] == '.' && sp[1] == 0) { if (slash) { for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';) continue; p = --sp; } else if (--sp != cp) *sp = '\0'; else sp[1] = '\0'; } else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) { /* * We have something like "yyy/xxx/..", where "yyy" can be null or * a path starting at /, and "xxx" is a single component. Before * compressing "xxx/..", we want to expand "yyy/xxx", if it is a * symbolic link. */ *--sp = 0; /* form the pathname for readlink */ #ifdef S_IFLNK /* if we have symlinks */ if (sp != cp && /* symlinks != SYM_IGNORE && */ (tlink = areadlink(short2str(cp))) != NULL) { mlink = str2short(tlink); xfree(tlink); if (slash) *p = '/'; /* * Point p to the '/' in "/..", and restore the '/'. */ *(p = sp) = '/'; if (*mlink != '/') { /* * Relative path, expand it between the "yyy/" and the * "/..". First, back sp up to the character past "yyy/". */ while (*--sp != '/') continue; sp++; *sp = 0; /* * New length is "yyy/" + mlink + "/.." and rest */ p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) + Strlen(p) + 1) * sizeof(Char)); /* * Copy new path into newcp */ for (p2 = cp; (*p1++ = *p2++) != '\0';) continue; for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';) continue; for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) continue; /* * Restart canonicalization at expanded "/xxx". */ p = sp - cp - 1 + newcp; } else { newcp = Strspl(mlink, p); /* * Restart canonicalization at beginning */ p = newcp; } xfree(cp); cp = newcp; #ifdef HAVE_SLASHSLASH slashslash = (cp[0] == '/' && cp[1] == '/'); #endif /* HAVE_SLASHSLASH */ continue; /* canonicalize the link */ } #endif /* S_IFLNK */ *sp = '/'; if (sp != cp) while (*--sp != '/') continue; if (slash) { for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';) continue; p = sp; } else if (cp == sp) *++sp = '\0'; else *sp = '\0'; } else { /* normal dir name (not . or .. or nothing) */ #ifdef S_IFLNK /* if we have symlinks */ if (sp != cp && symlinks == SYM_CHASE && (tlink = areadlink(short2str(cp))) != NULL) { mlink = str2short(tlink); xfree(tlink); /* * restore the '/'. */ if (slash) *p = '/'; /* * point sp to p (rather than backing up). */ sp = p; if (*mlink != '/') { /* * Relative path, expand it between the "yyy/" and the * remainder. First, back sp up to the character past * "yyy/". */ while (*--sp != '/') continue; sp++; *sp = 0; /* * New length is "yyy/" + mlink + "/.." and rest */ p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) + Strlen(p) + 1) * sizeof(Char)); /* * Copy new path into newcp */ for (p2 = cp; (*p1++ = *p2++) != '\0';) continue; for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';) continue; for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) continue; /* * Restart canonicalization at expanded "/xxx". */ p = sp - cp - 1 + newcp; } else { newcp = Strspl(mlink, p); /* * Restart canonicalization at beginning */ p = newcp; } xfree(cp); cp = newcp; #ifdef HAVE_SLASHSLASH slashslash = (cp[0] == '/' && cp[1] == '/'); #endif /* HAVE_SLASHSLASH */ continue; /* canonicalize the mlink */ } #endif /* S_IFLNK */ if (slash) *p = '/'; } } /* * fix home... */ #ifdef S_IFLNK p1 = varval(STRhome); cc = Strlen(p1); /* * See if we're not in a subdir of STRhome */ if (p1 && *p1 == '/' && (Strncmp(p1, cp, cc) != 0 || (cp[cc] != '/' && cp[cc] != '\0'))) { static ino_t home_ino = (ino_t) -1; static dev_t home_dev = (dev_t) -1; static Char *home_ptr = NULL; struct stat statbuf; int found; Char *copy; /* * Get dev and ino of STRhome */ if (home_ptr != p1 && stat(short2str(p1), &statbuf) != -1) { home_dev = statbuf.st_dev; home_ino = statbuf.st_ino; home_ptr = p1; } /* * Start comparing dev & ino backwards */ p2 = copy = Strsave(cp); found = 0; while (*p2 && stat(short2str(p2), &statbuf) != -1) { if (DEV_DEV_COMPARE(statbuf.st_dev, home_dev) && statbuf.st_ino == home_ino) { found = 1; break; } if ((sp = Strrchr(p2, '/')) != NULL) *sp = '\0'; } /* * See if we found it */ if (*p2 && found) { /* * Use STRhome to make '~' work */ newcp = Strspl(p1, cp + Strlen(p2)); xfree(cp); cp = newcp; } xfree(copy); } #endif /* S_IFLNK */ #ifdef HAVE_SLASHSLASH if (slashslash) { if (cp[1] != '/') { p = xmalloc((Strlen(cp) + 2) * sizeof(Char)); *p = '/'; (void) Strcpy(&p[1], cp); xfree(cp); cp = p; } } if (cp[1] == '/' && cp[2] == '/') { for (p1 = &cp[1], p2 = &cp[2]; (*p1++ = *p2++) != '\0';) continue; } #endif /* HAVE_SLASHSLASH */ return cp; }
/* dnormalize(): * The path will be normalized if it * 1) is "..", * 2) or starts with "../", * 3) or ends with "/..", * 4) or contains the string "/../", * then it will be normalized, unless those strings are quoted. * Otherwise, a copy is made and sent back. */ Char * dnormalize(const Char *cp, int expnd) { /* return true if dp is of the form "../xxx" or "/../xxx" */ #define IS_DOTDOT(sp, p) (ISDOTDOT(p) && ((p) == (sp) || *((p) - 1) == '/')) #define IS_DOT(sp, p) (ISDOT(p) && ((p) == (sp) || *((p) - 1) == '/')) #ifdef S_IFLNK if (expnd) { struct Strbuf buf = Strbuf_INIT; int dotdot = 0; Char *dp, *cwd; const Char *start = cp; # ifdef HAVE_SLASHSLASH int slashslash; # endif /* HAVE_SLASHSLASH */ /* * count the number of "../xxx" or "xxx/../xxx" in the path */ for ( ; *cp && *(cp + 1); cp++) if (IS_DOTDOT(start, cp)) dotdot++; /* * if none, we are done. */ if (dotdot == 0) return (Strsave(start)); # ifdef notdef struct stat sb; /* * We disable this test because: * cd /tmp; mkdir dir1 dir2; cd dir2; ln -s /tmp/dir1; cd dir1; * echo ../../dir1 does not expand. We had enabled this before * because it was bothering people with expansions in compilation * lines like -I../../foo. Maybe we need some kind of finer grain * control? * * If the path doesn't exist, we are done too. */ if (lstat(short2str(start), &sb) != 0 && errno == ENOENT) return (Strsave(start)); # endif cwd = xmalloc((Strlen(dcwd->di_name) + 3) * sizeof(Char)); (void) Strcpy(cwd, dcwd->di_name); /* * If the path starts with a slash, we are not relative to * the current working directory. */ if (ABSOLUTEP(start)) *cwd = '\0'; # ifdef HAVE_SLASHSLASH slashslash = cwd[0] == '/' && cwd[1] == '/'; # endif /* HAVE_SLASHSLASH */ /* * Ignore . and count ..'s */ cp = start; do { dotdot = 0; buf.len = 0; while (*cp) if (IS_DOT(start, cp)) { if (*++cp) cp++; } else if (IS_DOTDOT(start, cp)) { if (buf.len != 0) break; /* finish analyzing .././../xxx/[..] */ dotdot++; cp += 2; if (*cp) cp++; } else Strbuf_append1(&buf, *cp++); Strbuf_terminate(&buf); while (dotdot > 0) if ((dp = Strrchr(cwd, '/')) != NULL) { # ifdef HAVE_SLASHSLASH if (dp == &cwd[1]) slashslash = 1; # endif /* HAVE_SLASHSLASH */ *dp = '\0'; dotdot--; } else break; if (!*cwd) { /* too many ..'s, starts with "/" */ cwd[0] = '/'; # ifdef HAVE_SLASHSLASH /* * Only append another slash, if already the former cwd * was in a double-slash path. */ cwd[1] = slashslash ? '/' : '\0'; cwd[2] = '\0'; # else /* !HAVE_SLASHSLASH */ cwd[1] = '\0'; # endif /* HAVE_SLASHSLASH */ } # ifdef HAVE_SLASHSLASH else if (slashslash && cwd[1] == '\0') { cwd[1] = '/'; cwd[2] = '\0'; } # endif /* HAVE_SLASHSLASH */ if (buf.len != 0) { size_t i; i = Strlen(cwd); if (TRM(cwd[i - 1]) != '/') { cwd[i++] = '/'; cwd[i] = '\0'; } dp = Strspl(cwd, TRM(buf.s[0]) == '/' ? &buf.s[1] : buf.s); xfree(cwd); cwd = dp; i = Strlen(cwd) - 1; if (TRM(cwd[i]) == '/') cwd[i] = '\0'; } /* Reduction of ".." following the stuff we collected in buf * only makes sense if the directory item in buf really exists. * Avoid reduction of "-I../.." (typical compiler call) to "" * or "/usr/nonexistant/../bin" to "/usr/bin": */ if (cwd[0]) { struct stat exists; if (0 != stat(short2str(cwd), &exists)) { xfree(buf.s); xfree(cwd); return Strsave(start); } } } while (*cp != '\0'); xfree(buf.s); return cwd; } #endif /* S_IFLNK */ return Strsave(cp); }