summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2016-07-08 23:06:38 -0700
committerKaz Kylheku <kaz@kylheku.com>2016-07-08 23:06:38 -0700
commita73b5a8f6beb37685888977171cea10af94e77c9 (patch)
tree2536518d59ba59ac26abf7a0640f5c149e108138
parenteec582cdb351530131d2ae30376eca2771f78e49 (diff)
downloadcygnal-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.cc20
-rw-r--r--winsup/cygwin/mount.h3
-rw-r--r--winsup/cygwin/path.cc84
-rw-r--r--winsup/cygwin/path.h1
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)