From d49657aab8952e54f49d666dabddd42c885af6d9 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Fri, 8 Jul 2016 23:06:38 -0700 Subject: First steps toward native path handling. - /proc and /dev are are still available, accessed as proc:/ and dev:/ - All other paths are native, and do not "see" virtual Cygwin items; /cygdrive is just C:\cygdrive (if the current drive is C). - chdir() to a virtual directory like dev:/ or proc:/ results in errno EOPNOTSUPP. * winsup/cygwin/mount.cc (mount_info::conv_to_win32_path): Takes new bool argument, hide_cygwin_virtuals. If true all that the function does is "backslashify" the path. (mount_info::add_item): Special hack inserted here so that we can create the virtual root directory which holds dev and proc and whatnot, and is passed here as "/". We cannot let this go through normalize_posix_path any more because it will turn to C:\. * winsup/cygwin/mount.h (mount_info::conv_to_win32_path): Declaration updated. * winsup/cygwin/path.cc (is_posix_space): New static function: tests for paths in special spaces, currently "dev:/" and "proc:/". Used by normalize_posix_path. (normalize_posix_path): Any path that doesn't satisfy the is_posix_space test is treated as Win32. Since the bulk of the code is now only used for these spaces, the relative path handling is not required and a the corresponding block of code is removed. Paths satisfying is_posix_space are transformed. I.e. the underlying path resolution machine in the path_conv class still recognizes /proc and /dev. It's just that these will not occur, because normalize_posix_path will convert them to references with drive names. (path_conv::check): Pass the is_msdos flag down to mount_info::conv_to_win32_path as the new argument. Thus if normalize_posix_path indicates a native path, this function will hide the virtual spaces. Also, we add MOUNT_NOPOSIX and MOUNT_NOACL to the object's mount_flags. This is used in chdir. (normalize_win32_path): A small piece of logic works against our plan here: it checks for the leading forward slash on the path, and prevents such paths from being converted to Win32 paths with a drive reference. We eliminate this test, and treat paths unconditionally. (chdir): Here, if the path is not native, we return EOPNOTSUPP. Thus it is impossible to chdir into Cygwin virtual directories like /dev (now referenced as dev:/). They can be listed but not turned into the current directory. Eventually we want chdir to actually set the Win32 current directory of the process; that can't work for virtual dirs. * winsup/cygwin/path.h (path_conv::is_native): New inline accessor which tests for the MOUNT_NOPOSIX flag. --- winsup/cygwin/mount.cc | 20 ++++++++++++- winsup/cygwin/mount.h | 3 +- winsup/cygwin/path.cc | 80 ++++++++++++++++++++++++++++++++------------------ winsup/cygwin/path.h | 1 + 4 files changed, 73 insertions(+), 31 deletions(-) diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index e0349815d..1e424bd23 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -565,7 +565,7 @@ mount_item::build_win32 (char *dst, const char *src, unsigned *outflags, unsigne int mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, - unsigned *flags) + unsigned *flags, bool hide_cygwin_virtuals) { bool chroot_ok = !cygheap->root.exists (); @@ -592,6 +592,13 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, converting normalizex UNIX path to a DOS-style path, looking up the appropriate drive in the mount table. */ + if (hide_cygwin_virtuals) + { + dev = *fs_dev; + backslashify (src_path, dst, 0); + rc = 0; + goto out_no_chroot_check; + } /* See if this is a cygwin "device" */ if (win32_device_name (src_path, dst, dev)) { @@ -1388,6 +1395,17 @@ mount_info::add_item (const char *native, const char *posix, if (posix == NULL || !isabspath (posix) || is_unc_share (posix) || isdrive (posix)) posixerr = EINVAL; + else if (posix[0] == '/' && posix[1] == 0) + { + /* Special case hack for root, because the Cygnal + * version of normalize_posix_path + * doesn't handle this. + */ + posixtail = posixtmp; + *posixtail++ = '/'; + *posixtail = '\0'; + posixerr = 0; + } else posixerr = normalize_posix_path (posix, posixtmp, posixtail); diff --git a/winsup/cygwin/mount.h b/winsup/cygwin/mount.h index 122a679a8..dc15ff41e 100644 --- a/winsup/cygwin/mount.h +++ b/winsup/cygwin/mount.h @@ -190,7 +190,8 @@ class mount_info int del_item (const char *path, unsigned flags); int conv_to_win32_path (const char *src_path, char *dst, device&, - unsigned *flags = NULL); + unsigned *flags = NULL, + bool hide_cygwin_virtuals = false); int conv_to_posix_path (PWCHAR src_path, char *posix_path, int ccp_flags); int conv_to_posix_path (const char *src_path, char *posix_path, int ccp_flags); diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 1d6bcbe48..edc17152b 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -227,9 +227,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) @@ -239,28 +260,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; @@ -284,7 +309,6 @@ normalize_posix_path (const char *src, char *dst, char *&tail) if (*src != '.') break; - sawdot: if (src[1] != '.') { if (!src[1]) @@ -740,7 +764,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.mount_flags); + dev, &sym.mount_flags, + is_msdos); if (error) return; @@ -1463,7 +1488,7 @@ normalize_win32_path (const char *src, char *dst, char *&tail) if (!isdirsep (src[0])) *tail++ = '\\'; } - else if (*src != '/') + else { /* Make sure dst points to the rightmost backslash which must not be backtracked over during ".." evaluation. This is either @@ -3624,12 +3649,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. @@ -3640,11 +3667,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); diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 5c60ee116..c1cdc554b 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -166,6 +166,7 @@ class path_conv && fs.has_acls (); } bool hasgood_inode () const {return !(mount_flags & MOUNT_IHASH); } bool isgood_inode (ino_t ino) const; + bool is_native () const {return !!(mount_flags & MOUNT_NOPOSIX);} bool support_sparse () const { return (mount_flags & MOUNT_SPARSE) -- cgit v1.2.3