From a954d2fda18a17061b765e628d209f66173e3268 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Sat, 3 Oct 2009 17:44:41 -0400 Subject: [PATCH] Only accept \ as path separator when reading archives on Windows. This seems to offer the best trade-off of compatibility and correctness. SVN-Revision: 1480 --- tar/tree.c | 9 +++------ tar/util.c | 34 ++++++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/tar/tree.c b/tar/tree.c index 5fbd3c720..eeae00b03 100644 --- a/tar/tree.c +++ b/tar/tree.c @@ -72,9 +72,6 @@ __FBSDID("$FreeBSD: src/usr.bin/tar/tree.c,v 1.9 2008/11/27 05:49:52 kientzle Ex #endif #if defined(HAVE_WINDOWS_H) && !defined(__CYGWIN__) #include -#define DIRSEP '\\' -#else -#define DIRSEP '/' #endif #include "tree.h" @@ -255,8 +252,8 @@ tree_append(struct tree *t, const char *name, size_t name_length) p = t->buff + t->dirname_length; t->path_length = t->dirname_length + name_length; /* Add a separating '/' if it's needed. */ - if (t->dirname_length > 0 && p[-1] != '/' && p[-1] != '\\') { - *p++ = DIRSEP; + if (t->dirname_length > 0 && p[-1] != '/') { + *p++ = '/'; t->path_length ++; } #if HAVE_STRNCPY_S @@ -349,7 +346,7 @@ tree_pop(struct tree *t) t->dirname_length = te->dirname_length; if (t->buff) { t->basename = t->buff + t->dirname_length; - while (t->basename[0] == '/' || t->basename[0] == '\\') + while (t->basename[0] == '/') t->basename++; } free(te->name); diff --git a/tar/util.c b/tar/util.c index d2a3126d8..2ae448e61 100644 --- a/tar/util.c +++ b/tar/util.c @@ -298,15 +298,16 @@ do_chdir(struct bsdtar *bsdtar) } const char * -strip_components(const char *path, int elements) +strip_components(const char *p, int elements) { - const char *p = path; - + /* Skip as many elements as necessary. */ while (elements > 0) { switch (*p++) { case '/': +#if defined(_WIN32) && !defined(__CYGWIN__) + case '\\': /* Support \ path sep on Windows ONLY. */ +#endif elements--; - path = p; break; case '\0': /* Path is too short, skip it. */ @@ -314,12 +315,25 @@ strip_components(const char *path, int elements) } } - while (*path == '/') - ++path; - if (*path == '\0') - return (NULL); - - return (path); + /* Skip any / characters. This handles short paths that have + * additional / termination. This also handles the case where + * the logic above stops in the middle of a duplicate // + * sequence (which would otherwise get converted to an + * absolute path). */ + for (;;) { + switch (*p) { + case '/': +#if defined(_WIN32) && !defined(__CYGWIN__) + case '\\': /* Support \ path sep on Windows ONLY. */ +#endif + ++p; + break; + case '\0': + return (NULL); + default: + return (p); + } + } } /* -- 2.47.3