summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/path.cc
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r--winsup/cygwin/path.cc17
1 files changed, 17 insertions, 0 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 16571b12e..e0fa37670 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -240,6 +240,7 @@ normalize_posix_path (const char *src, char *dst, char *&tail)
{
const char *in_src = src;
char *dst_start = dst;
+ bool check_parent = false;
syscall_printf ("src %s", src);
if ((isdrive (src) && isdirsep (src[2])) || *src == '\\')
@@ -278,6 +279,7 @@ normalize_posix_path (const char *src, char *dst, char *&tail)
*tail++ = *src++;
else
{
+ check_parent = true;
while (*++src)
{
if (isslash (*src))
@@ -301,6 +303,21 @@ normalize_posix_path (const char *src, char *dst, char *&tail)
break;
else
{
+ /* According to POSIX semantics all elements of path must
+ exist. To follow it, we must validate our path before
+ removing the trailing component. Check_parent is needed
+ for performance optimization, in order not to verify paths
+ which are already verified. For example this prevents
+ double check in case of foo/bar/../.. */
+ if (check_parent)
+ {
+ *tail = 0;
+ debug_printf ("checking %s before '..'", dst_start);
+ path_conv head (dst_start);
+ if (!head.isdir())
+ return ENOENT;
+ check_parent = false;
+ }
while (tail > dst_start && !isslash (*--tail))
continue;
src++;