diff options
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r-- | winsup/cygwin/path.cc | 84 |
1 files changed, 54 insertions, 30 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 7533e007e..05717b839 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -231,9 +231,30 @@ has_dot_last_component (const char *dir, bool test_dot_dot) return last_comp == dir || last_comp[-1] == '/'; } +static int +is_posix_space(const char *path) +{ + const int nprefixes = 2; + static const char *prefix[] = { "dev:/", "proc:/" }; + static int length[] = { 5, 6 }; + int i; + + for (i = 0; i < nprefixes; i++) + { + int len = length[i]; + if (strncmp(path, prefix[i], len) == 0) + return len - 2; + } + + return 0; +} + /* Normalize a POSIX path. All duplicate /'s, except for 2 leading /'s, are deleted. - The result is 0 for success, or an errno error value. */ + The result is: + 0 == success; + -1 == success: Win32 path; + > 0 == errno error value; */ int normalize_posix_path (const char *src, char *dst, char *&tail) @@ -243,28 +264,32 @@ normalize_posix_path (const char *src, char *dst, char *&tail) bool check_parent = false; syscall_printf ("src %s", src); - if ((isdrive (src) && isdirsep (src[2])) || *src == '\\') + /* + * Under Cygnal, only a few special paths beginning with a prefix + * are in a "POSIX space" and are transformed into Cygwin paths + * according to this pattern: + * + * dev:/path/to -> /dev/path/to + * + * Only certain words are recognized. + */ + + int len = is_posix_space(src); + + if (!len) goto win32_path; tail = dst; - if (!isslash (src[0])) - { - if (!cygheap->cwd.get (dst)) - return get_errno (); - tail = strchr (tail, '\0'); - if (isslash (dst[0]) && isslash (dst[1])) - ++dst_start; - if (*src == '.') - { - if (tail == dst_start + 1 && *dst_start == '/') - tail--; - goto sawdot; - } - if (tail > dst && !isslash (tail[-1])) - *tail++ = '/'; - } + + *tail++ = '/'; + + strncpy(tail, src, len); + + src += len + 1; /* src now points at slash after colon */ + tail += len; /* dst holds "/word" with no colon */ + /* Two leading /'s? If so, preserve them. */ - else if (isslash (src[1]) && !isslash (src[2])) + if (isslash (src[1]) && !isslash (src[2])) { *tail++ = *src++; ++dst_start; @@ -288,7 +313,6 @@ normalize_posix_path (const char *src, char *dst, char *&tail) if (*src != '.') break; - sawdot: if (src[1] != '.') { if (!src[1]) @@ -766,7 +790,8 @@ path_conv::check (const char *src, unsigned opt, /* Convert to native path spec sans symbolic link info. */ error = mount_table->conv_to_win32_path (path_copy, full_path, - dev, &sym.pflags); + dev, &sym.pflags, + is_msdos); if (error) return; @@ -926,8 +951,10 @@ path_conv::check (const char *src, unsigned opt, it as caseinsensitive,noacl path. This must be set before calling sym.check, otherwise the path is potentially treated casesensitive. */ - if (is_msdos) + if (is_msdos) { sym.pflags |= PATH_NOPOSIX | PATH_NOACL; + path_flags |= PATH_NOPOSIX | PATH_NOACL; + } is_fs_via_procsys: @@ -1358,7 +1385,7 @@ normalize_win32_path (const char *src, char *dst, char *&tail) if (isdrive (src)) /* Always convert drive letter to uppercase for case sensitivity. */ *tail++ = cyg_toupper (*src++); - else if (*src != '/') + else { if (beg_src_slash) tail += cygheap->cwd.get_drive (dst); @@ -3224,12 +3251,14 @@ chdir (const char *in_dir) } const char *posix_cwd = NULL; - dev_t devn = path.get_device (); + if (!path.exists ()) set_errno (ENOENT); else if (!path.isdir ()) set_errno (ENOTDIR); - else if (!isvirtual_dev (devn)) + else if (!path.is_native ()) + set_errno (EOPNOTSUPP); + else { /* The sequence chdir("xx"); chdir(".."); must be a noop if xx is not a symlink. This is exploited by find.exe. @@ -3240,11 +3269,6 @@ chdir (const char *in_dir) posix_cwd = path.get_posix (); res = 0; } - else - { - posix_cwd = path.get_posix (); - res = 0; - } if (!res) res = cygheap->cwd.set (&path, posix_cwd); |