diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2016-07-08 23:06:38 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2016-07-08 23:06:38 -0700 |
commit | a73b5a8f6beb37685888977171cea10af94e77c9 (patch) | |
tree | 2536518d59ba59ac26abf7a0640f5c149e108138 | |
parent | eec582cdb351530131d2ae30376eca2771f78e49 (diff) | |
download | cygnal-a73b5a8f6beb37685888977171cea10af94e77c9.tar.gz cygnal-a73b5a8f6beb37685888977171cea10af94e77c9.tar.bz2 cygnal-a73b5a8f6beb37685888977171cea10af94e77c9.zip |
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 PATH_NOPOSIX and
PATH_NOACL to the object's path_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 PATH_NOPOSIX flag.
-rw-r--r-- | winsup/cygwin/mount.cc | 20 | ||||
-rw-r--r-- | winsup/cygwin/mount.h | 3 | ||||
-rw-r--r-- | winsup/cygwin/path.cc | 84 | ||||
-rw-r--r-- | winsup/cygwin/path.h | 1 |
4 files changed, 76 insertions, 32 deletions
diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index 262168076..8954a9908 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -590,7 +590,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 (); @@ -617,6 +617,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)) { @@ -1428,6 +1435,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 d37b673e6..ee2339581 100644 --- a/winsup/cygwin/mount.h +++ b/winsup/cygwin/mount.h @@ -193,7 +193,8 @@ class mount_info unsigned set_flags_from_win32_path (const char *path); 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 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); diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 1e2af6550..c6f43c183 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -161,6 +161,7 @@ class path_conv bool has_acls () const {return !(path_flags & PATH_NOACL) && fs.has_acls (); } bool hasgood_inode () const {return !(path_flags & PATH_IHASH); } bool isgood_inode (ino_t ino) const; + bool is_native () const {return !!(path_flags & PATH_NOPOSIX);} bool support_sparse () const { return (path_flags & PATH_SPARSE) |