From 6b6c3f9525e99adc8354b608ef63c637db30de8b Mon Sep 17 00:00:00 2001 From: cgf Date: Fri, 4 Jul 2003 03:07:01 +0000 Subject: [PATCH] * fhandler.h (FH_ENC): New enum. (fhandler_base::get_encoded): New function. (fhandler_base::set_encoded): Ditto. * fhandler_disk_file.cc (fhandler_disk_file::opendir): Set encoded flag in fhandler, as appropriate. (fhandler_disk_file::readdir): Unmunge filename as appropriate based on new encoding flag. * path.cc (normalize_posix_path): Don't punt on files with colons. (special_char): New function. (mount_item::fnmunge): Ditto. (fnunmunge): Ditto. (special_name): Ditto. (mount_item::build_win32): Avoid drive considerations when file is encoded. (mount_info::conv_to_win32_path): Handle encoded filenames. (mount_info::conv_to_posix_path): Ditto. (fillout_mntent): Add posix string when directory is encoded. * path.h (fnunmunge): Declare. (path_conv::is_encoded): Declare. --- winsup/cygwin/ChangeLog | 22 ++++++ winsup/cygwin/fhandler.h | 6 +- winsup/cygwin/fhandler_disk_file.cc | 11 +-- winsup/cygwin/path.cc | 140 +++++++++++++++++++++++++++++------- winsup/cygwin/path.h | 4 ++ 5 files changed, 150 insertions(+), 33 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index a65c92d4fc..82045de21d 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,25 @@ +2003-07-02 Christopher Faylor + + * fhandler.h (FH_ENC): New enum. + (fhandler_base::get_encoded): New function. + (fhandler_base::set_encoded): Ditto. + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Set encoded flag + in fhandler, as appropriate. + (fhandler_disk_file::readdir): Unmunge filename as appropriate based on + new encoding flag. + * path.cc (normalize_posix_path): Don't punt on files with colons. + (special_char): New function. + (mount_item::fnmunge): Ditto. + (fnunmunge): Ditto. + (special_name): Ditto. + (mount_item::build_win32): Avoid drive considerations when file is + encoded. + (mount_info::conv_to_win32_path): Handle encoded filenames. + (mount_info::conv_to_posix_path): Ditto. + (fillout_mntent): Add posix string when directory is encoded. + * path.h (fnunmunge): Declare. + (path_conv::is_encoded): Declare. + 2003-07-03 Christopher Faylor * fhandler_tty.cc (fhandler_tty_slave::open): Conditionalize a little diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index ae3becc32d..9d037d6d7d 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -23,8 +23,7 @@ enum FH_WBINSET = 0x00010000, /* binary write mode has been explicitly set */ FH_APPEND = 0x00020000, /* always append */ FH_ASYNC = 0x00040000, /* async I/O */ - FH_SIGCLOSE = 0x00080000, /* signal handler should close fd on interrupt */ - + FH_ENC = 0x00080000, /* native path is encoded */ FH_SYMLINK = 0x00100000, /* is a symlink */ FH_EXECABL = 0x00200000, /* file looked like it would run: * ends in .exe or .bat or begins with #! */ @@ -242,6 +241,9 @@ class fhandler_base bool get_need_fork_fixup () { return FHISSETF (FFIXUP); } void set_need_fork_fixup () { FHSETF (FFIXUP); } + bool get_encoded () { return FHISSETF (ENC);} + void set_encoded () { FHSETF (ENC);} + virtual void set_close_on_exec (int val); virtual void fixup_before_fork_exec (DWORD) {} diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 48778f4fc2..29206bb0c4 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -607,6 +607,8 @@ fhandler_disk_file::opendir (path_conv& real_name) res = dir; } + if (real_name.isencoded ()) + set_encoded (); } syscall_printf ("%p = opendir (%s)", res, get_name ()); @@ -633,9 +635,7 @@ fhandler_disk_file::readdir (DIR *dir) } } else if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE) - { - return res; - } + return res; else if (!FindNextFileA (dir->__d_u.__d_data.__handle, &buf)) { DWORD lasterr = GetLastError (); @@ -650,7 +650,10 @@ fhandler_disk_file::readdir (DIR *dir) } /* We get here if `buf' contains valid data. */ - strcpy (dir->__d_dirent->d_name, buf.cFileName); + if (get_encoded ()) + (void) fnunmunge (dir->__d_dirent->d_name, buf.cFileName); + else + strcpy (dir->__d_dirent->d_name, buf.cFileName); /* Check for Windows shortcut. If it's a Cygwin or U/WIN symlink, drop the .lnk suffix. */ diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index d0648192d7..ab3e51f300 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -203,7 +203,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)) @@ -499,7 +499,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? */ @@ -1390,10 +1390,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); } @@ -1420,7 +1509,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); } @@ -1475,22 +1564,6 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, 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. @@ -1587,16 +1660,21 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, 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 (devn)) @@ -1760,6 +1838,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; } @@ -2420,6 +2504,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, ",posix"); if ((flags & MOUNT_CYGDRIVE)) /* cygdrive */ strcat (_reent_winsup ()->mnt_opts, (char *) ",noumount"); @@ -3344,7 +3430,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 diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index bd5b4a286a..f92e2d3dc9 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -46,6 +46,7 @@ enum path_types PATH_EXEC = MOUNT_EXEC, PATH_NOTEXEC = MOUNT_NOTEXEC, PATH_CYGWIN_EXEC = MOUNT_CYGWIN_EXEC, + PATH_ENC = MOUNT_ENC, PATH_ALL_EXEC = (PATH_CYGWIN_EXEC | PATH_EXEC), PATH_LNK = 0x01000000, PATH_TEXT = 0x02000000, @@ -89,6 +90,7 @@ class path_conv int has_symlinks () const {return path_flags & PATH_HAS_SYMLINKS;} int hasgood_inode () const {return path_flags & PATH_HASACLS;} // Not strictly correct int has_buggy_open () const {return path_flags & PATH_HASBUGGYOPEN;} + bool isencoded () {return path_flags & PATH_ENC;} int binmode () const { if (path_flags & PATH_BINARY) @@ -210,6 +212,8 @@ has_exec_chars (const char *buf, int len) int pathmatch (const char *path1, const char *path2) __attribute__ ((regparm (2))); int pathnmatch (const char *path1, const char *path2, int len) __attribute__ ((regparm (2))); +bool fnunmunge (char *, const char *) __attribute__ ((regparm (2))); + int path_prefix_p (const char *path1, const char *path2, int len1) __attribute__ ((regparm (3))); /* FIXME: Move to own include file eventually */ -- 2.11.0