summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2016-07-08 23:06:38 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-07-26 21:52:24 -0700
commitd49657aab8952e54f49d666dabddd42c885af6d9 (patch)
tree1daa3079f1f5cc7c5bcd340db276bab969bb4d5f
parent3388801d6d3a5d93b5d8709370518f804ecee39f (diff)
downloadcygnal-d49657aab8952e54f49d666dabddd42c885af6d9.tar.gz
cygnal-d49657aab8952e54f49d666dabddd42c885af6d9.tar.bz2
cygnal-d49657aab8952e54f49d666dabddd42c885af6d9.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 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.
-rw-r--r--winsup/cygwin/mount.cc20
-rw-r--r--winsup/cygwin/mount.h3
-rw-r--r--winsup/cygwin/path.cc80
-rw-r--r--winsup/cygwin/path.h1
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)