summaryrefslogtreecommitdiff
path: root/winsup/cygwin/path.cc
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r--winsup/cygwin/path.cc154
1 files changed, 124 insertions, 30 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 60856f2e110..8947be723f1 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -53,7 +53,6 @@ details. */
#include <sys/mount.h>
#include <mntent.h>
#include <unistd.h>
-#include <errno.h>
#include <ctype.h>
#include <winioctl.h>
#include <wingdi.h>
@@ -208,7 +207,7 @@ normalize_posix_path (const char *src, char *dst)
syscall_printf ("src %s", src);
- if (isdrive (src) || strpbrk (src, "\\:"))
+ if (isdrive (src))
{
int err = normalize_win32_path (src, dst);
if (!err && isdrive (dst))
@@ -513,7 +512,7 @@ path_conv::check (const char *src, unsigned opt,
/* Scan path_copy from right to left looking either for a symlink
or an actual existing file. If an existing file is found, just
- return. If a symlink is found exit the for loop.
+ return. If a symlink is found, exit the for loop.
Also: be careful to preserve the errno returned from
symlink.check as the caller may need it. */
/* FIXME: Do we have to worry about multiple \'s here? */
@@ -1151,10 +1150,99 @@ set_flags (unsigned *flags, unsigned val)
}
}
+char special_chars[] =
+ "\001" "\002" "\003" "\004" "\005" "\006" "\007" "\010"
+ "\011" "\012" "\013" "\014" "\015" "\016" "\017" "\020"
+ "\021" "\022" "\023" "\024" "\025" "\026" "\027" "\030"
+ "\031" "\032" "\033" "\034" "\035" "\036" "\037"
+ ":" "\\" "*" "?" "%"
+ "A" "B" "C" "D" "E" "F" "G" "H"
+ "I" "J" "K" "L" "M" "N" "O" "P"
+ "Q" "R" "S" "T" "U" "V" "W" "X"
+ "Y" "Z";
+
+static inline char
+special_char (const char *s)
+{
+ char *p = strechr (special_chars, *s);
+ if (*p == '%' && strlen (p) >= 3)
+ {
+ char hex[] = {s[1], s[2], '\0'};
+ unsigned char c = strtoul (hex, &p, 16);
+ p = strechr (special_chars, c);
+ }
+ return *p;
+}
+
+bool
+fnunmunge (char *dst, const char *src)
+{
+ bool converted = false;
+ char c;
+
+ while (*src)
+ if (*src != '%' || !(c = special_char (src)))
+ *dst++ = *src++;
+ else
+ {
+ converted = true;
+ *dst++ = c;
+ src += 3;
+ }
+
+ *dst = *src;
+ return converted;
+}
+
+/* Determines if name is "special". Assumes that name is empty or "absolute" */
+static int
+special_name (const char *s)
+{
+ if (!*s)
+ return false;
+
+ if (strpbrk (++s, special_chars))
+ return !strncasematch (s, "%2f", 3);
+
+ if (strcasematch (s, "nul")
+ || strcasematch (s, "aux")
+ || strcasematch (s, "prn"))
+ return -1;
+ if (!strncasematch (s, "com", 3)
+ && !strncasematch (s, "lpt", 3))
+ return false;
+ char *p;
+ (void) strtol (s, &p, 10);
+ return -(*p == '\0');
+}
+
void
mount_item::fnmunge (char *dst, const char *src)
{
- strcpy (dst, src);
+ int name_type;
+ if (!(flags & MOUNT_ENC) || !(name_type = special_name (src)))
+ strcpy (dst, src);
+ else
+ {
+ char *d = dst;
+ *d++ = *src++;
+ if (name_type < 0)
+ {
+ __small_sprintf (d, "%%%02x", (unsigned char) *src++);
+ d += 3;
+ }
+
+ while (*src)
+ if (!special_char (src))
+ *d++ = *src++;
+ else
+ {
+ __small_sprintf (d, "%%%02x", (unsigned char) *src++);
+ d += 3;
+ }
+ *d = *src;
+ }
+
backslashify (dst, dst, 0);
}
@@ -1181,7 +1269,7 @@ mount_item::build_win32 (char *dst, const char *src, unsigned *outflags, unsigne
const char *p = src + real_posix_pathlen;
if (*p == '/')
/* nothing */;
- else if ((isdrive (dst) && !dst[2]) || *p)
+ else if ((!(flags & MOUNT_ENC) && isdrive (dst) && !dst[2]) || *p)
dst[n++] = '\\';
fnmunge (dst + n, p);
}
@@ -1234,22 +1322,6 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev,
if (dst == NULL)
goto out; /* Sanity check. */
- /* An MS-DOS spec has either a : or a \. If this is found, short
- circuit most of the rest of this function. */
- if (strpbrk (src_path, ":\\") != NULL || slash_unc_prefix_p (src_path))
- {
- debug_printf ("%s already win32", src_path);
- rc = normalize_win32_path (src_path, dst);
- if (rc)
- {
- debug_printf ("normalize_win32_path failed, rc %d", rc);
- return rc;
- }
-
- set_flags (flags, (unsigned) set_flags_from_win32_path (dst));
- goto out;
- }
-
/* Normalize the path, taking out ../../ stuff, we need to do this
so that we can move from one mounted directory to another with relative
stuff.
@@ -1349,16 +1421,21 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev,
break;
}
- if (i >= nmounts)
+ if (i < nmounts)
{
- backslashify (pathbuf, dst, 0); /* just convert */
- set_flags (flags, PATH_BINARY);
- chroot_ok = !cygheap->root.exists ();
+ mi->build_win32 (dst, pathbuf, flags, chroot_pathlen);
+ chroot_ok = true;
}
else
{
- mi->build_win32 (dst, pathbuf, flags, chroot_pathlen);
- chroot_ok = true;
+ if (strpbrk (src_path, ":\\") != NULL || slash_unc_prefix_p (src_path))
+ rc = normalize_win32_path (src_path, dst);
+ else
+ {
+ backslashify (pathbuf, dst, 0); /* just convert */
+ set_flags (flags, PATH_BINARY);
+ }
+ chroot_ok = !cygheap->root.exists ();
}
if (!isvirtual_dev (dev.devn))
@@ -1522,6 +1599,12 @@ mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
const char *p = cygheap->root.unchroot (posix_path);
memmove (posix_path, p, strlen (p) + 1);
}
+ if (mi.flags & MOUNT_ENC)
+ {
+ char tmpbuf[MAX_PATH + 1];
+ if (fnunmunge (tmpbuf, posix_path))
+ strcpy (posix_path, tmpbuf);
+ }
goto out;
}
@@ -1656,10 +1739,16 @@ mount_info::from_registry ()
/* FIXME: Need a mutex to avoid collisions with other tasks. */
int
-mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags)
+mount_info::add_reg_mount (const char *native_path, const char *posix_path, unsigned mountflags)
{
int res = 0;
+ if (strchr (posix_path, '\\'))
+ {
+ set_errno (EINVAL);
+ goto err1;
+ }
+
/* Add the mount to the right registry location, depending on
whether MOUNT_SYSTEM is set in the mount flags. */
if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */
@@ -1710,6 +1799,7 @@ mount_info::add_reg_mount (const char * native_path, const char * posix_path, un
return 0; /* Success */
err:
__seterrno_from_win_error (res);
+ err1:
return -1;
}
@@ -2175,6 +2265,8 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags)
strcat (_reent_winsup ()->mnt_opts, (char *) ",exec");
else if (flags & MOUNT_NOTEXEC)
strcat (_reent_winsup ()->mnt_opts, (char *) ",noexec");
+ if (flags & MOUNT_ENC)
+ strcat (_reent_winsup ()->mnt_opts, ",managed");
if ((flags & MOUNT_CYGDRIVE)) /* cygdrive */
strcat (_reent_winsup ()->mnt_opts, (char *) ",noumount");
@@ -2259,7 +2351,9 @@ mount (const char *win32_path, const char *posix_path, unsigned flags)
{
int res = -1;
- if (flags & MOUNT_CYGDRIVE) /* normal mount */
+ if (strpbrk (posix_path, "\\:"))
+ set_errno (EINVAL);
+ else if (flags & MOUNT_CYGDRIVE) /* normal mount */
{
/* When flags include MOUNT_CYGDRIVE, take this to mean that
we actually want to change the cygdrive prefix and flags
@@ -3162,7 +3256,7 @@ chdir (const char *in_dir)
return -1;
}
- const char *native_dir = path.get_win32 ();
+ const char *native_dir = path;
/* Check to see if path translates to something like C:.
If it does, append a \ to the native directory specification to