diff options
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r-- | winsup/cygwin/path.cc | 154 |
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 |