From e4b575030bb0743d48a3bf156814cf77dc397b7a Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 16 Jul 2008 20:20:45 +0000 Subject: [PATCH] Add case-sensitivity. Unconditionally handle mount points case-sensitive. Unconditionally handle virtual paths case-sensitive. Unconditionally handle registry paths case-insensitive. Otherwise, accommodate case-sensitivity of given path throughout. * cygheap.cc (cygheap_root::set): Get additional caseinsensitive parameter and store it. * cygheap.h (struct cygheap_root_mount_info): Add member caseinsensitive. * dlfcn.cc (get_full_path_of_dll): Drop PC_NOFULL parameter from call to path_conv::check. * environ.cc (pcheck_case): Remove. (check_case_init): Remove. (known): Drop "check_case" option. * exceptions.cc (open_stackdumpfile): Add comment. * fhandler.cc (fhandler_base::get_default_fmode): Call pathmatch instead of strcasematch. * fhandler_disk_file.cc: Accommodate case-sensitivity of given path throughout. (__DIR_mounts::check_mount): Unconditionally check virtual paths case-sensitive. (fhandler_disk_file::link): Drop case clash handling. (fhandler_disk_file::open): Ditto. (fhandler_disk_file::readdir_helper): Drop managed mount code. * mount.cc: Remove managed mount code and datastructures. (struct opt): Remove "managed" option. Add "posix=0" and "posix=1" options. (fillout_mntent): Remove "managed" output. Add "posix" output. * path.cc (struct symlink_info): Remove case_clash member and case_check method. (pcheck_case): Remove. (path_prefix_p): Take additional bool parameter "caseinsensitive". (pathnmatch): Ditto. (pathmatch): Ditto. (mkrelpath): Ditto. (fs_info::update): Set caseinsensitive flag according to file system name and FILE_CASE_SENSITIVE_SEARCH flag. Add comment. (tfx_chars_managed): Remove. (transform_chars): Drop "managed" parameter. Always use tfx_chars. (get_nt_native_path): Drop "managed" parameter. Make sure drive letters are always upper case. (getfileattr): Change second parameter to denote caseinsensitivity. (path_conv::check): Initialize caseinsensitive to OBJ_CASE_INSENSITIVE. Set caseinsensitive according to global obcaseinsensitive flag, file system case sensitivity and MOUNT_NOPOSIX mount flag. Drop case_clash and all the related code. (symlink_worker): Drop case clash handling. (symlink_info::set): Drop setting case_clash. (symlink_info::case_check): Remove. (cwdstuff::set): Add comment. (etc::init): Take path_conv instead of PUNICODE_STRING as parameter to allow case sensitivity. * path.h (enum pathconv_arg): Drop PC_SYM_IGNORE. (enum case_checking): Remove. (enum path_types): Drop PATH_ENC, add PATH_NOPOSIX flag. (struct fs_info): Add caseinsensitive flag and accessor methods. (class path_conv): Add caseinsensitive member and define objcaseinsensitive method. Drop case_clash member and isencoded method. (pathmatch): Change prototype according to above change. (pathnmatch): Ditto. (path_prefix_p): Ditto. (get_nt_native_path): Ditto. (class etc): Ditto. (fnunmunge): Remove prototype. * shared.cc (shared_info::init_obcaseinsensitive): Initialize obcaseinsensitive flag from obcaseinsensitive registry value. (shared_info::initialize): Call init_obcaseinsensitive here by the first process creating the shared memory. * shared_info.h (mount_item::fnmunge): Remove. (shared_info::obcaseinsensitive): Rename from obcaseinsensitivity. (shared_info::init_obcaseinsensitive): Declare. * syscalls.cc (try_to_bin): Add comment. * include/sys/mount.h (MOUNT_ENC): Remove flag. (MOUNT_NOPOSIX): Add flag. --- winsup/cygwin/ChangeLog | 77 ++++++++ winsup/cygwin/cygheap.cc | 3 +- winsup/cygwin/cygheap.h | 6 +- winsup/cygwin/dlfcn.cc | 2 +- winsup/cygwin/environ.cc | 29 --- winsup/cygwin/exceptions.cc | 2 +- winsup/cygwin/fhandler.cc | 2 +- winsup/cygwin/fhandler_disk_file.cc | 42 ++--- winsup/cygwin/fhandler_proc.cc | 10 +- winsup/cygwin/fhandler_process.cc | 8 +- winsup/cygwin/fhandler_procnet.cc | 6 +- winsup/cygwin/fhandler_registry.cc | 20 +-- winsup/cygwin/include/sys/mount.h | 4 +- winsup/cygwin/mmap.cc | 2 +- winsup/cygwin/mount.cc | 224 +++-------------------- winsup/cygwin/path.cc | 268 ++++++++++------------------ winsup/cygwin/path.h | 29 ++- winsup/cygwin/shared.cc | 21 +++ winsup/cygwin/shared_info.h | 6 +- winsup/cygwin/syscalls.cc | 13 +- winsup/cygwin/times.cc | 2 +- winsup/cygwin/uinfo.cc | 2 +- 22 files changed, 288 insertions(+), 490 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 9a71a93dd..79c592266 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,80 @@ +2008-07-16 Corinna Vinschen + + Add case-sensitivity. + Unconditionally handle mount points case-sensitive. + Unconditionally handle virtual paths case-sensitive. + Unconditionally handle registry paths case-insensitive. + Otherwise, accommodate case-sensitivity of given path throughout. + * cygheap.cc (cygheap_root::set): Get additional caseinsensitive + parameter and store it. + * cygheap.h (struct cygheap_root_mount_info): Add member + caseinsensitive. + * dlfcn.cc (get_full_path_of_dll): Drop PC_NOFULL parameter from call + to path_conv::check. + * environ.cc (pcheck_case): Remove. + (check_case_init): Remove. + (known): Drop "check_case" option. + * exceptions.cc (open_stackdumpfile): Add comment. + * fhandler.cc (fhandler_base::get_default_fmode): Call pathmatch + instead of strcasematch. + * fhandler_disk_file.cc: Accommodate case-sensitivity of given path + throughout. + (__DIR_mounts::check_mount): Unconditionally check virtual paths + case-sensitive. + (fhandler_disk_file::link): Drop case clash handling. + (fhandler_disk_file::open): Ditto. + (fhandler_disk_file::readdir_helper): Drop managed mount code. + * mount.cc: Remove managed mount code and datastructures. + (struct opt): Remove "managed" option. Add "posix=0" and "posix=1" + options. + (fillout_mntent): Remove "managed" output. Add "posix" output. + * path.cc (struct symlink_info): Remove case_clash member and + case_check method. + (pcheck_case): Remove. + (path_prefix_p): Take additional bool parameter "caseinsensitive". + (pathnmatch): Ditto. + (pathmatch): Ditto. + (mkrelpath): Ditto. + (fs_info::update): Set caseinsensitive flag according to file system + name and FILE_CASE_SENSITIVE_SEARCH flag. Add comment. + (tfx_chars_managed): Remove. + (transform_chars): Drop "managed" parameter. Always use tfx_chars. + (get_nt_native_path): Drop "managed" parameter. Make sure drive letters + are always upper case. + (getfileattr): Change second parameter to denote caseinsensitivity. + (path_conv::check): Initialize caseinsensitive to OBJ_CASE_INSENSITIVE. + Set caseinsensitive according to global obcaseinsensitive flag, file + system case sensitivity and MOUNT_NOPOSIX mount flag. + Drop case_clash and all the related code. + (symlink_worker): Drop case clash handling. + (symlink_info::set): Drop setting case_clash. + (symlink_info::case_check): Remove. + (cwdstuff::set): Add comment. + (etc::init): Take path_conv instead of PUNICODE_STRING as parameter to + allow case sensitivity. + * path.h (enum pathconv_arg): Drop PC_SYM_IGNORE. + (enum case_checking): Remove. + (enum path_types): Drop PATH_ENC, add PATH_NOPOSIX flag. + (struct fs_info): Add caseinsensitive flag and accessor methods. + (class path_conv): Add caseinsensitive member and define + objcaseinsensitive method. Drop case_clash member and isencoded method. + (pathmatch): Change prototype according to above change. + (pathnmatch): Ditto. + (path_prefix_p): Ditto. + (get_nt_native_path): Ditto. + (class etc): Ditto. + (fnunmunge): Remove prototype. + * shared.cc (shared_info::init_obcaseinsensitive): Initialize + obcaseinsensitive flag from obcaseinsensitive registry value. + (shared_info::initialize): Call init_obcaseinsensitive here by the + first process creating the shared memory. + * shared_info.h (mount_item::fnmunge): Remove. + (shared_info::obcaseinsensitive): Rename from obcaseinsensitivity. + (shared_info::init_obcaseinsensitive): Declare. + * syscalls.cc (try_to_bin): Add comment. + * include/sys/mount.h (MOUNT_ENC): Remove flag. + (MOUNT_NOPOSIX): Add flag. + 2008-07-15 Corinna Vinschen * fhandler_tape.cc (mtinfo::initialize): Remove synchronization stuff. diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc index f33ba2ea8..b3d8d6d0a 100644 --- a/winsup/cygwin/cygheap.cc +++ b/winsup/cygwin/cygheap.cc @@ -396,7 +396,7 @@ cstrdup1 (const char *s) } void -cygheap_root::set (const char *posix, const char *native) +cygheap_root::set (const char *posix, const char *native, bool caseinsensitive) { if (*posix == '/' && posix[1] == '\0') { @@ -418,6 +418,7 @@ cygheap_root::set (const char *posix, const char *native) m->native_pathlen = strlen (native); if (m->native_pathlen >= 1 && m->native_path[m->native_pathlen - 1] == '\\') m->native_path[--m->native_pathlen] = '\0'; + m->caseinsensitive = caseinsensitive; } cygheap_user::~cygheap_user () diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index 0e937ee7c..fe2333c74 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -53,6 +53,7 @@ struct cygheap_root_mount_info unsigned posix_pathlen; char native_path[CYG_MAX_PATH]; unsigned native_pathlen; + bool caseinsensitive; }; /* CGF: FIXME This doesn't belong here */ @@ -68,7 +69,8 @@ public: { if (!m) return 1; - return path_prefix_p (m->posix_path, path, m->posix_pathlen); + return path_prefix_p (m->posix_path, path, m->posix_pathlen, + m->caseinsensitive); } bool ischroot_native (const char *path) { @@ -87,7 +89,7 @@ public: return p; } bool exists () {return !!m;} - void set (const char *, const char *); + void set (const char *, const char *, bool); size_t posix_length () const { return m->posix_pathlen; } const char *posix_path () const { return m->posix_path; } size_t native_length () const { return m->native_pathlen; } diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc index bc2b39788..6319a3c11 100644 --- a/winsup/cygwin/dlfcn.cc +++ b/winsup/cygwin/dlfcn.cc @@ -63,7 +63,7 @@ get_full_path_of_dll (const char* str, char *name) if (isabspath (name) || (ret = check_path_access ("LD_LIBRARY_PATH=", name, real_filename) ?: check_path_access ("/usr/lib", name, real_filename)) == NULL) - real_filename.check (name, PC_SYM_FOLLOW | PC_NOFULL | PC_NULLEMPTY); /* Convert */ + real_filename.check (name, PC_SYM_FOLLOW | PC_NULLEMPTY); /* Convert */ if (!real_filename.error) ret = strcpy (name, real_filename.get_win32 ()); diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 2a4a73614..260d9e478 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -34,7 +34,6 @@ extern bool allow_glob; extern bool ignore_case_with_glob; extern bool allow_winsymlinks; extern bool strip_title_path; -extern int pcheck_case; bool reset_com = false; static bool envcache = true; #ifdef USE_SERVER @@ -490,33 +489,6 @@ glob_init (const char *buf) } } -static void -check_case_init (const char *buf) -{ - if (!buf || !*buf) - return; - - if (ascii_strncasematch (buf, "relax", 5)) - { - pcheck_case = PCHECK_RELAXED; - debug_printf ("File case checking set to RELAXED"); - } - else if (ascii_strcasematch (buf, "adjust")) - { - pcheck_case = PCHECK_ADJUST; - debug_printf ("File case checking set to ADJUST"); - } - else if (ascii_strcasematch (buf, "strict")) - { - pcheck_case = PCHECK_STRICT; - debug_printf ("File case checking set to STRICT"); - } - else - { - debug_printf ("Wrong case checking name: %s", buf); - } -} - void set_file_api_mode (codepage_type cp) { @@ -595,7 +567,6 @@ static struct parse_thing } known[] NO_COPY = { {"binmode", {x: &binmode}, justset, NULL, {{O_TEXT}, {O_BINARY}}}, - {"check_case", {func: &check_case_init}, isfunc, NULL, {{0}, {0}}}, {"codepage", {func: &codepage_init}, isfunc, NULL, {{0}, {0}}}, {"dosfilewarning", {&dos_file_warning}, justset, NULL, {{false}, {true}}}, {"envcache", {&envcache}, justset, NULL, {{true}, {false}}}, diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index becf3cdc0..9b7c98049 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -149,7 +149,7 @@ open_stackdumpfile () p, strlen (p)) * sizeof (WCHAR); RtlAppendUnicodeToString (&ucore, L".stackdump"); /* Create an object attribute which refers to .stackdump - in Cygwin's cwd. */ + in Cygwin's cwd. Stick to caseinsensitivity. */ InitializeObjectAttributes (&attr, &ucore, OBJ_CASE_INSENSITIVE, cygheap->cwd.get_handle (), NULL); HANDLE h; diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 07961f19f..168e4e49f 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -325,7 +325,7 @@ fhandler_base::get_default_fmode (int flags) if (pflen > nlen || (stem != get_name () && !isdirsep (stem[-1]))) continue; else if ((pf->flags & O_ACCMODE) == accflags - && strcasematch (stem, pf->name)) + && pathmatch (stem, pf->name, !!pc.objcaseinsensitive ())) { fmode = pf->flags & ~O_ACCMODE; break; diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index d0e86e481..be098ead9 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -81,20 +81,20 @@ public: UNICODE_STRING proc; RtlInitUnicodeString (&proc, L"proc"); - if (RtlEqualUnicodeString (fname, &proc, TRUE)) + if (RtlEqualUnicodeString (fname, &proc, FALSE)) { found[__DIR_PROC] = true; return 2; } if (fname->Length / sizeof (WCHAR) == mount_table->cygdrive_len - 2 - && RtlEqualUnicodeString (fname, &cygdrive, TRUE)) + && RtlEqualUnicodeString (fname, &cygdrive, FALSE)) { found[__DIR_CYGDRIVE] = true; return 2; } } for (int i = 0; i < count; ++i) - if (RtlEqualUnicodeString (fname, &mounts[i], TRUE)) + if (RtlEqualUnicodeString (fname, &mounts[i], FALSE)) { found[i] = true; return eval ? eval_ino (i) : 1; @@ -233,7 +233,7 @@ path_conv::ndisk_links (DWORD nNumberOfLinks) RtlInitCountedUnicodeString (&fname, pfdi->FileName, pfdi->FileNameLength); InitializeObjectAttributes (&attr, &fname, - OBJ_CASE_INSENSITIVE, fh, NULL); + objcaseinsensitive (), fh, NULL); if (is_volume_mountpoint (&attr)) ++count; } @@ -379,7 +379,7 @@ fhandler_base::fstat_by_name (struct __stat64 *buf) LARGE_INTEGER FileId; RtlSplitUnicodePath (pc.get_nt_native_path (), &dirname, &basename); - InitializeObjectAttributes (&attr, &dirname, OBJ_CASE_INSENSITIVE, + InitializeObjectAttributes (&attr, &dirname, pc.objcaseinsensitive (), NULL, NULL); if (!NT_SUCCESS (status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_VALID_FLAGS, @@ -1123,7 +1123,7 @@ fhandler_disk_file::link (const char *newpath) path_conv newpc (newpath, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes); if (newpc.error) { - set_errno (newpc.case_clash ? ECASECLASH : newpc.error); + set_errno (newpc.error); return -1; } @@ -1135,7 +1135,7 @@ fhandler_disk_file::link (const char *newpath) } char new_buf[strlen (newpath) + 5]; - if (!newpc.error && !newpc.case_clash) + if (!newpc.error) { if (allow_winsymlinks && pc.is_lnk_special ()) { @@ -1298,13 +1298,6 @@ fhandler_disk_file::open (int flags, mode_t mode) int fhandler_base::open_fs (int flags, mode_t mode) { - if (pc.case_clash && flags & O_CREAT) - { - debug_printf ("case clash detected"); - set_errno (ECASECLASH); - return 0; - } - /* Unfortunately NT allows to open directories for writing, but that's disallowed according to SUSv3. */ if (pc.isdir () && (flags & O_ACCMODE) != O_RDONLY) @@ -1683,7 +1676,7 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err, OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; - InitializeObjectAttributes (&attr, fname, OBJ_CASE_INSENSITIVE, + InitializeObjectAttributes (&attr, fname, pc.objcaseinsensitive (), get_handle (), NULL); if (is_volume_mountpoint (&attr) && (NT_SUCCESS (NtOpenFile (&reph, READ_CONTROL, &attr, &io, @@ -1729,18 +1722,8 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err, } } -#if 0 - if (pc.isencoded ()) - { - char tmp[NAME_MAX + 1]; - sys_wcstombs (tmp, NAME_MAX + 1, fname->Buffer, - fname->Length / sizeof (WCHAR)); - fnunmunge (de->d_name, tmp); - } - else -#endif - sys_wcstombs (de->d_name, NAME_MAX + 1, fname->Buffer, - fname->Length / sizeof (WCHAR)); + sys_wcstombs (de->d_name, NAME_MAX + 1, fname->Buffer, + fname->Length / sizeof (WCHAR)); if (dir->__d_position == 0 && !strcmp (de->d_name, ".")) dir->__flags |= dirent_saw_dot; @@ -1886,7 +1869,8 @@ go_ahead: { HANDLE hdl; - InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE, + InitializeObjectAttributes (&attr, &fname, + pc.objcaseinsensitive (), get_handle (), NULL); if (NT_SUCCESS (NtOpenFile (&hdl, READ_CONTROL, &attr, &io, FILE_SHARE_VALID_FLAGS, @@ -1964,7 +1948,7 @@ fhandler_disk_file::rewinddir (DIR *dir) HANDLE new_dir; RtlInitUnicodeString (&fname, L""); - InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE, + InitializeObjectAttributes (&attr, &fname, pc.objcaseinsensitive (), get_handle (), NULL); status = NtOpenFile (&new_dir, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_VALID_FLAGS, diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc index a30c1c246..1227720c8 100644 --- a/winsup/cygwin/fhandler_proc.cc +++ b/winsup/cygwin/fhandler_proc.cc @@ -117,7 +117,8 @@ fhandler_proc::get_proc_fhandler (const char *path) for (int i = 0; proc_listing[i]; i++) { - if (path_prefix_p (proc_listing[i], path, strlen (proc_listing[i]))) + if (path_prefix_p (proc_listing[i], path, strlen (proc_listing[i]), + false)) return proc_fhandlers[i]; } @@ -152,7 +153,7 @@ fhandler_proc::exists () if (*path == 0) return 2; for (int i = 0; proc_listing[i]; i++) - if (pathmatch (path + 1, proc_listing[i])) + if (!strcmp (path + 1, proc_listing[i])) { fileid = i; return (proc_fhandlers[i] == FH_PROC) ? (i == PROC_SELF ? -2 : -1) : 1; @@ -188,7 +189,7 @@ fhandler_proc::fstat (struct __stat64 *buf) { path++; for (int i = 0; proc_listing[i]; i++) - if (pathmatch (path, proc_listing[i])) + if (!strcmp (path, proc_listing[i])) { if (proc_fhandlers[i] != FH_PROC) buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; @@ -273,7 +274,8 @@ fhandler_proc::open (int flags, mode_t mode) proc_file_no = -1; for (int i = 0; proc_listing[i]; i++) - if (path_prefix_p (proc_listing[i], path + 1, strlen (proc_listing[i]))) + if (path_prefix_p (proc_listing[i], path + 1, strlen (proc_listing[i]), + false)) { proc_file_no = i; if (proc_fhandlers[i] != FH_PROC) diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc index b64f22175..0f0adc059 100644 --- a/winsup/cygwin/fhandler_process.cc +++ b/winsup/cygwin/fhandler_process.cc @@ -107,12 +107,12 @@ fhandler_process::exists () return 2; for (int i = 0; process_listing[i]; i++) - if (pathmatch (path + 1, process_listing[i])) + if (!strcmp (path + 1, process_listing[i])) { fileid = i; return is_symlink (i) ? -2 : (i == PROCESS_FD) ? 1 : -1; } - if (pathnmatch (strchr (path, '/') + 1, "fd/", 3)) + if (!strncmp (strchr (path, '/') + 1, "fd/", 3)) { fileid = PROCESS_FD; if (fill_filebuf ()) @@ -270,8 +270,8 @@ fhandler_process::open (int flags, mode_t mode) process_file_no = -1; for (int i = 0; process_listing[i]; i++) { - if (path_prefix_p - (process_listing[i], path + 1, strlen (process_listing[i]))) + if (path_prefix_p (process_listing[i], path + 1, + strlen (process_listing[i]), false)) process_file_no = i; } if (process_file_no == -1) diff --git a/winsup/cygwin/fhandler_procnet.cc b/winsup/cygwin/fhandler_procnet.cc index 9d01108a4..692a6dc51 100644 --- a/winsup/cygwin/fhandler_procnet.cc +++ b/winsup/cygwin/fhandler_procnet.cc @@ -65,7 +65,7 @@ fhandler_procnet::exists () return 1; for (int i = 0; process_listing[i]; i++) - if (pathmatch (path + 1, process_listing[i])) + if (!strcmp (path + 1, process_listing[i])) { if (i == PROCNET_IFINET6) { @@ -167,8 +167,8 @@ fhandler_procnet::open (int flags, mode_t mode) process_file_no = -1; for (int i = 0; process_listing[i]; i++) { - if (path_prefix_p - (process_listing[i], path + 1, strlen (process_listing[i]))) + if (path_prefix_p (process_listing[i], path + 1, + strlen (process_listing[i]), false)) process_file_no = i; } if (process_file_no == -1) diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc index dfd5a3612..dcf46de27 100644 --- a/winsup/cygwin/fhandler_registry.cc +++ b/winsup/cygwin/fhandler_registry.cc @@ -117,8 +117,8 @@ fhandler_registry::exists () if (file == path) { for (int i = 0; registry_listing[i]; i++) - if (path_prefix_p - (registry_listing[i], path, strlen (registry_listing[i]))) + if (path_prefix_p (registry_listing[i], path, + strlen (registry_listing[i]), true)) { file_type = 1; goto out; @@ -140,7 +140,7 @@ fhandler_registry::exists () NULL, NULL)) || (error == ERROR_MORE_DATA)) { - if (pathmatch (buf, file)) + if (strcasematch (buf, file)) { file_type = 1; goto out; @@ -159,8 +159,8 @@ fhandler_registry::exists () NULL, NULL)) || (error == ERROR_MORE_DATA)) { - if (pathmatch (buf, file) || (buf[0] == '\0' && - pathmatch (file, DEFAULT_VALUE_NAME))) + if (strcasematch (buf, file) + || (buf[0] == '\0' && strcasematch (file, DEFAULT_VALUE_NAME))) { file_type = -1; goto out; @@ -461,8 +461,8 @@ fhandler_registry::open (int flags, mode_t mode) if (file == path) { for (int i = 0; registry_listing[i]; i++) - if (path_prefix_p - (registry_listing[i], path, strlen (registry_listing[i]))) + if (path_prefix_p (registry_listing[i], path, + strlen (registry_listing[i]), true)) { if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { @@ -520,7 +520,7 @@ fhandler_registry::open (int flags, mode_t mode) set_io_handle (handle); - if (pathmatch (file, DEFAULT_VALUE_NAME)) + if (strcasematch (file, DEFAULT_VALUE_NAME)) value_name = cstrdup (""); else value_name = cstrdup (file); @@ -631,7 +631,7 @@ value_not_found: (error = RegEnumKeyEx (handle, index++, buf, &buf_size, NULL, NULL, NULL, NULL)) || (error == ERROR_MORE_DATA)) { - if (pathmatch (buf, value_name)) + if (strcasematch (buf, value_name)) { set_errno (EISDIR); return false; @@ -694,7 +694,7 @@ open_key (const char *name, REGSAM access, DWORD wow64, bool isValue) else { for (int i = 0; registry_listing[i]; i++) - if (pathmatch (component, registry_listing[i])) + if (strcasematch (component, registry_listing[i])) hKey = registry_keys[i]; if (hKey == (HKEY) INVALID_HANDLE_VALUE) return hKey; diff --git a/winsup/cygwin/include/sys/mount.h b/winsup/cygwin/include/sys/mount.h index ebcf8db88..45b421e7d 100644 --- a/winsup/cygwin/include/sys/mount.h +++ b/winsup/cygwin/include/sys/mount.h @@ -29,9 +29,9 @@ enum MOUNT_NOTEXEC = 0x0100, /* don't check files for executable magic */ MOUNT_DEVFS = 0x0200, /* /device "filesystem" */ MOUNT_PROC = 0x0400, /* /proc "filesystem" */ - MOUNT_ENC = 0x0800, /* encode special characters */ MOUNT_RO = 0x1000, /* read-only "filesystem" */ - MOUNT_NOACL = 0x2000 /* support reading/writing ACLs */ + MOUNT_NOACL = 0x2000, /* support reading/writing ACLs */ + MOUNT_NOPOSIX = 0x4000 /* Case insensitve path handling */ }; int mount (const char *, const char *, unsigned __flags); diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc index e09c11c8d..9b0440425 100644 --- a/winsup/cygwin/mmap.cc +++ b/winsup/cygwin/mmap.cc @@ -841,7 +841,7 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, _off64_t off) IO_STATUS_BLOCK io; RtlInitUnicodeString (&fname, L""); - InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE, + InitializeObjectAttributes (&attr, &fname, fh->pc.objcaseinsensitive (), fh->get_handle (), NULL); status = NtOpenFile (&h, fh->get_access () | GENERIC_EXECUTE | SYNCHRONIZE, diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index 2bc941ef4..283d77241 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -32,7 +32,7 @@ details. */ /* Determine if path prefix matches current cygdrive */ #define iscygdrive(path) \ - (path_prefix_p (mount_table->cygdrive, (path), mount_table->cygdrive_len)) + (path_prefix_p (mount_table->cygdrive, (path), mount_table->cygdrive_len, false)) #define iscygdrive_device(path) \ (isalpha (path[mount_table->cygdrive_len]) && \ @@ -40,7 +40,7 @@ details. */ !path[mount_table->cygdrive_len + 1])) #define isproc(path) \ - (path_prefix_p (proc, (path), proc_len)) + (path_prefix_p (proc, (path), proc_len, false)) /* is_unc_share: Return non-zero if PATH begins with //server/share or with one of the native prefixes //./ or //?/ @@ -150,161 +150,6 @@ set_flags (unsigned *flags, unsigned val) } } -static char dot_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 char *special_chars = dot_special_chars + 1; -static char special_introducers[] = - "anpcl"; - -static char -special_char (const char *s, const char *valid_chars = special_chars) -{ - if (*s != '%' || strlen (s) < 3) - return 0; - - char *p; - char hex[] = {s[1], s[2], '\0'}; - unsigned char c = strtoul (hex, &p, 16); - p = strechr (valid_chars, c); - return *p; -} - -/* Determines if name is "special". Assumes that name is empty or "absolute" */ -static int -special_name (const char *s, int inc = 1) -{ - if (!*s) - return false; - - s += inc; - - if (strcmp (s, ".") == 0 || strcmp (s, "..") == 0) - return false; - - int n; - const char *p = NULL; - if (ascii_strncasematch (s, "conin$", n = 5) - || ascii_strncasematch (s, "conout$", n = 7) - || ascii_strncasematch (s, "nul", n = 3) - || ascii_strncasematch (s, "aux", 3) - || ascii_strncasematch (s, "prn", 3) - || ascii_strncasematch (s, "con", 3)) - p = s + n; - else if (ascii_strncasematch (s, "com", 3) - || ascii_strncasematch (s, "lpt", 3)) - strtoul (s + 3, (char **) &p, 10); - if (p && (*p == '\0' || *p == '.')) - return -1; - - return (strchr (s, '\0')[-1] == '.') - || (strpbrk (s, special_chars) && !ascii_strncasematch (s, "%2f", 3)); -} - -bool -fnunmunge (char *dst, const char *src) -{ - bool converted = false; - char c; - - if ((c = special_char (src, special_introducers))) - { - __small_sprintf (dst, "%c%s", c, src + 3); - if (special_name (dst, 0)) - { - *dst++ = c; - src += 3; - } - } - - while (*src) - if (!(c = special_char (src, dot_special_chars))) - *dst++ = *src++; - else - { - converted = true; - *dst++ = c; - src += 3; - } - - *dst = *src; - return converted; -} - -static bool -copy1 (char *&d, const char *&src, int& left) -{ - left--; - if (left || !*src) - *d++ = *src++; - else - return true; - return false; -} - -static bool -copyenc (char *&d, const char *&src, int& left) -{ - char buf[16]; - int n = __small_sprintf (buf, "%%%02x", (unsigned char) *src++); - left -= n; - if (left <= 0) - return true; - strcpy (d, buf); - d += n; - return false; -} - -int -mount_item::fnmunge (char *dst, const char *src, int& left) -{ - int name_type; - if (!(name_type = special_name (src))) - { - if ((int) strlen (src) >= left) - return ENAMETOOLONG; - else - strcpy (dst, src); - } - else - { - char *d = dst; - if (copy1 (d, src, left)) - return ENAMETOOLONG; - if (name_type < 0 && copyenc (d, src, left)) - return ENAMETOOLONG; - - while (*src) - if (!strchr (special_chars, *src) || (*src == '%' && !special_char (src))) - { - if (copy1 (d, src, left)) - return ENAMETOOLONG; - } - else if (copyenc (d, src, left)) - return ENAMETOOLONG; - - char dot[] = "."; - const char *p = dot; - if (*--d != '.') - d++; - else if (copyenc (d, p, left)) - return ENAMETOOLONG; - - *d = *src; - } - - backslashify (dst, dst, 0); - return 0; -} - int mount_item::build_win32 (char *dst, const char *src, unsigned *outflags, unsigned chroot_pathlen) { @@ -328,37 +173,12 @@ mount_item::build_win32 (char *dst, const char *src, unsigned *outflags, unsigne const char *p = src + real_posix_pathlen; if (*p == '/') /* nothing */; - else if ((!(flags & MOUNT_ENC) && isdrive (dst) && !dst[2]) || *p) + else if ((isdrive (dst) && !dst[2]) || *p) dst[n++] = '\\'; - //if (!*p || !(flags & MOUNT_ENC)) - //{ - if ((n + strlen (p)) >= NT_MAX_PATH) - err = ENAMETOOLONG; - else - backslashify (p, dst + n, 0); -#if 0 - } + if ((n + strlen (p)) >= NT_MAX_PATH) + err = ENAMETOOLONG; else - { - int left = NT_MAX_PATH - n; - while (*p) - { - char slash = 0; - char *s = strchr (p + 1, '/'); - if (s) - { - slash = *s; - *s = '\0'; - } - err = fnmunge (dst += n, p, left); - if (!s || err) - break; - n = strlen (dst); - *s = slash; - p = s; - } - } -#endif + backslashify (p, dst + n, 0); return err; } @@ -493,7 +313,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, continue; } - if (path_prefix_p (path, src_path, len)) + if (path_prefix_p (path, src_path, len, mi->flags & MOUNT_NOPOSIX)) break; } @@ -693,7 +513,8 @@ mount_info::conv_to_posix_path (const char *src_path, char *posix_path, for (int i = 0; i < nmounts; ++i) { mount_item &mi = mount[native_sorted[i]]; - if (!path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen)) + if (!path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen, + mi.flags & MOUNT_NOPOSIX)) continue; if (cygheap->root.exists () && !cygheap->root.posix_ok (mi.posix_path)) @@ -726,14 +547,6 @@ 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 0 - if (mi.flags & MOUNT_ENC) - { - char *tmpbuf = tp.c_get (); - if (fnunmunge (tmpbuf, posix_path)) - strcpy (posix_path, tmpbuf); - } -#endif goto out; } @@ -782,7 +595,8 @@ mount_info::set_flags_from_win32_path (const char *p) for (int i = 0; i < nmounts; i++) { mount_item &mi = mount[native_sorted[i]]; - if (path_prefix_p (mi.native_path, p, mi.native_pathlen)) + if (path_prefix_p (mi.native_path, p, mi.native_pathlen, + mi.flags & MOUNT_NOPOSIX)) return mi.flags; } return PATH_BINARY; @@ -831,9 +645,10 @@ struct opt {"notexec", MOUNT_NOTEXEC, 0}, {"cygexec", MOUNT_CYGWIN_EXEC, 0}, {"nosuid", 0, 0}, - {"managed", MOUNT_ENC, 0}, {"acl", MOUNT_NOACL, 1}, - {"noacl", MOUNT_NOACL, 0} + {"noacl", MOUNT_NOACL, 0}, + {"posix=1", MOUNT_NOPOSIX, 1}, + {"posix=0", MOUNT_NOPOSIX, 0} }; static bool @@ -1196,7 +1011,7 @@ mount_info::add_item (const char *native, const char *posix, int i; for (i = 0; i < nmounts; i++) { - if (strcasematch (mount[i].posix_path, posixtmp)) + if (!strcmp (mount[i].posix_path, posixtmp)) { /* Don't allow to override a system mount with a user mount. */ if ((mount[i].flags & MOUNT_SYSTEM) && !(mountflags & MOUNT_SYSTEM)) @@ -1258,7 +1073,7 @@ mount_info::del_item (const char *path, unsigned flags) { int ent = native_sorted[i]; /* in the same order as getmntent() */ if (((posix_path_p) - ? strcasematch (mount[ent].posix_path, pathtmp) + ? !strcmp (mount[ent].posix_path, pathtmp) : strcasematch (mount[ent].native_path, pathtmp))) { /* Don't allow to remove a system mount. */ @@ -1315,7 +1130,7 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags) tmp_pathbuf tp; UNICODE_STRING unat; tp.u_get (&unat); - get_nt_native_path (native_path, unat, flags & MOUNT_ENC); + get_nt_native_path (native_path, unat); if (append_bs) RtlAppendUnicodeToString (&unat, L"\\"); mntinfo.update (&unat, NULL); @@ -1352,12 +1167,13 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags) strcat (_my_tls.locals.mnt_opts, (char *) ",exec"); else if (flags & MOUNT_NOTEXEC) strcat (_my_tls.locals.mnt_opts, (char *) ",noexec"); - if (flags & MOUNT_ENC) - strcat (_my_tls.locals.mnt_opts, ",managed"); if (flags & MOUNT_NOACL) strcat (_my_tls.locals.mnt_opts, (char *) ",noacl"); + if (flags & MOUNT_NOPOSIX) + strcat (_my_tls.locals.mnt_opts, (char *) ",posix=0"); + if ((flags & MOUNT_CYGDRIVE)) /* cygdrive */ strcat (_my_tls.locals.mnt_opts, (char *) ",noumount"); diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 0e671bec7..173442c8e 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -71,6 +71,7 @@ #include #include #include +#include bool dos_file_warning = true; @@ -84,7 +85,6 @@ struct symlink_info int issymlink; bool ext_tacked_on; int error; - bool case_clash; bool isdevice; _major_t major; _minor_t minor; @@ -93,7 +93,6 @@ struct symlink_info fs_info &fs); int set (char *path); bool parse_device (const char *); - bool case_check (char *path); int check_sysfile (HANDLE h); int check_shortcut (HANDLE h); int check_reparse_point (HANDLE h); @@ -104,8 +103,6 @@ struct symlink_info muto NO_COPY cwdstuff::cwd_lock; -int pcheck_case = PCHECK_RELAXED; /* Determines the case check behaviour. */ - static const GUID GUID_shortcut = { 0x00021401L, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46 }; @@ -154,7 +151,8 @@ struct win_shortcut_hdr */ int -path_prefix_p (const char *path1, const char *path2, int len1) +path_prefix_p (const char *path1, const char *path2, int len1, + bool caseinsensitive) { /* Handle case where PATH1 has trailing '/' and when it doesn't. */ if (len1 > 0 && isdirsep (path1[len1 - 1])) @@ -164,7 +162,8 @@ path_prefix_p (const char *path1, const char *path2, int len1) return isdirsep (path2[0]) && !isdirsep (path2[1]); if (isdirsep (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':') - return pathnmatch (path1, path2, len1); + return caseinsensitive ? strncasematch (path1, path2, len1) + : !strncmp (path1, path2, len1); return 0; } @@ -172,19 +171,19 @@ path_prefix_p (const char *path1, const char *path2, int len1) /* Return non-zero if paths match in first len chars. Check is dependent of the case sensitivity setting. */ int -pathnmatch (const char *path1, const char *path2, int len) +pathnmatch (const char *path1, const char *path2, int len, bool caseinsensitive) { - return pcheck_case == PCHECK_STRICT ? !strncmp (path1, path2, len) - : strncasematch (path1, path2, len); + return caseinsensitive + ? strncasematch (path1, path2, len) : !strncmp (path1, path2, len); } /* Return non-zero if paths match. Check is dependent of the case sensitivity setting. */ int -pathmatch (const char *path1, const char *path2) +pathmatch (const char *path1, const char *path2, bool caseinsensitive) { - return pcheck_case == PCHECK_STRICT ? !strcmp (path1, path2) - : strcasematch (path1, path2); + return caseinsensitive + ? strcasematch (path1, path2) : !strcmp (path1, path2); } /* TODO: This function is used in mkdir and rmdir to generate correct @@ -326,9 +325,9 @@ path_conv::add_ext_from_sym (symlink_info &sym) } } -static void __stdcall mkrelpath (char *dst) __attribute__ ((regparm (2))); +static void __stdcall mkrelpath (char *dst, bool caseinsensitive) __attribute__ ((regparm (2))); static void __stdcall -mkrelpath (char *path) +mkrelpath (char *path, bool caseinsensitive) { tmp_pathbuf tp; char *cwd_win32 = tp.c_get (); @@ -336,7 +335,7 @@ mkrelpath (char *path) return; unsigned cwdlen = strlen (cwd_win32); - if (!path_prefix_p (cwd_win32, path, cwdlen)) + if (!path_prefix_p (cwd_win32, path, cwdlen, caseinsensitive)) return; size_t n = strlen (path); @@ -394,6 +393,7 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) vol = in_vol; else { + /* Always caseinsensitive. We really just need access to the drive. */ InitializeObjectAttributes (&attr, upath, OBJ_CASE_INSENSITIVE, NULL, NULL); status = NtOpenFile (&vol, READ_CONTROL, &attr, &io, @@ -523,6 +523,12 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) in fhandler.cc (fhandler_disk_file::open). */ RtlInitUnicodeString (&testname, L"SUNWNFS"); has_buggy_open (RtlEqualUnicodeString (&fsname, &testname, FALSE)); + /* Case sensitivity is supported if FILE_CASE_SENSITIVE_SEARCH is set, + except on Samba which handles Windows clients case insensitive. + NFS doesn't set the FILE_CASE_SENSITIVE_SEARCH flag but is case + sensitive. */ + caseinsensitive ((!(flags () & FILE_CASE_SENSITIVE_SEARCH) || is_samba ()) + && !is_nfs ()); if (!in_vol) NtClose (vol); @@ -581,34 +587,14 @@ WCHAR tfx_chars[] NO_COPY = { 'x', 'y', 'z', '{', 0xf000 | '|', '}', '~', 127 }; -WCHAR tfx_chars_managed[] NO_COPY = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, '!', 0xf000 | '"', '#', '$', '%', '&', 39, - '(', ')', 0xf000 | '*', '+', ',', '-', '.', '/', - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 0xf000 | ':', ';', 0xf000 | '<', '=', 0xf000 | '>', 0xf000 | '?', - '@', 0xf000 | 'A', 0xf000 | 'B', 0xf000 | 'C', 0xf000 | 'D', 0xf000 | 'E', 0xf000 | 'F', 0xf000 | 'G', - 0xf000 | 'H', 0xf000 | 'I', 0xf000 | 'J', 0xf000 | 'K', 0xf000 | 'L', 0xf000 | 'M', 0xf000 | 'N', 0xf000 | 'O', - 0xf000 | 'P', 0xf000 | 'Q', 0xf000 | 'R', 0xf000 | 'S', 0xf000 | 'T', 0xf000 | 'U', 0xf000 | 'V', 0xf000 | 'W', - 0xf000 | 'X', 0xf000 | 'Y', 0xf000 | 'Z', '[', '\\', ']', '^', '_', - '`', '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', '{', 0xf000 | '|', '}', '~', 127 -}; - static void -transform_chars (PUNICODE_STRING upath, USHORT start_idx, bool managed) +transform_chars (PUNICODE_STRING upath, USHORT start_idx) { register PWCHAR buf = upath->Buffer; register PWCHAR end = buf + upath->Length / sizeof (WCHAR) - 1; - register PWCHAR tfx = managed ? tfx_chars_managed : tfx_chars; for (buf += start_idx; buf <= end; ++buf) if (*buf < 128) - *buf = tfx[*buf]; + *buf = tfx_chars[*buf]; #if 0 /* Win32 can't handle trailing dots and spaces. Transform the last of them to the private use area, too, to create a valid Win32 filename. */ @@ -620,7 +606,7 @@ transform_chars (PUNICODE_STRING upath, USHORT start_idx, bool managed) } PUNICODE_STRING -get_nt_native_path (const char *path, UNICODE_STRING& upath, bool managed) +get_nt_native_path (const char *path, UNICODE_STRING& upath) { upath.Length = 0; if (path[0] == '/') /* special path w/o NT path representation. */ @@ -628,9 +614,15 @@ get_nt_native_path (const char *path, UNICODE_STRING& upath, bool managed) else if (path[0] != '\\') /* X:\... or relative path. */ { if (path[1] == ':') /* X:\... */ - str2uni_cat (upath, "\\??\\"); - str2uni_cat (upath, path); - transform_chars (&upath, 7, managed); + { + str2uni_cat (upath, "\\??\\"); + str2uni_cat (upath, path); + /* The drive letter must be upper case. */ + upath.Buffer[4] = towupper (upath.Buffer[4]); + } + else + str2uni_cat (upath, path); + transform_chars (&upath, 7); } else if (path[1] != '\\') /* \Device\... */ str2uni_cat (upath, path); @@ -639,7 +631,7 @@ get_nt_native_path (const char *path, UNICODE_STRING& upath, bool managed) { str2uni_cat (upath, "\\??\\UNC\\"); str2uni_cat (upath, path + 2); - transform_chars (&upath, 8, managed); + transform_chars (&upath, 8); } else /* \\.\device or \\?\foo */ { @@ -658,7 +650,7 @@ path_conv::get_nt_native_path () uni_path.MaximumLength = (strlen (path) + 10) * sizeof (WCHAR); wide_path = (PWCHAR) cmalloc_abort (HEAP_STR, uni_path.MaximumLength); uni_path.Buffer = wide_path; - ::get_nt_native_path (path, uni_path, isencoded ()); + ::get_nt_native_path (path, uni_path); } return &uni_path; } @@ -669,7 +661,7 @@ path_conv::get_object_attr (OBJECT_ATTRIBUTES &attr, SECURITY_ATTRIBUTES &sa) if (!get_nt_native_path ()) return NULL; InitializeObjectAttributes (&attr, &uni_path, - OBJ_CASE_INSENSITIVE + objcaseinsensitive () | (sa.bInheritHandle ? OBJ_INHERIT : 0), NULL, sa.lpSecurityDescriptor); return &attr; @@ -708,7 +700,7 @@ warn_msdos (const char *src) } static DWORD -getfileattr (const char *path, bool managed) /* path has to be always absolute. */ +getfileattr (const char *path, bool caseinsensitive) /* path has to be always absolute. */ { tmp_pathbuf tp; UNICODE_STRING upath; @@ -718,8 +710,10 @@ getfileattr (const char *path, bool managed) /* path has to be always absolute. IO_STATUS_BLOCK io; tp.u_get (&upath); - InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL); - get_nt_native_path (path, upath, managed); + InitializeObjectAttributes (&attr, &upath, + caseinsensitive ? OBJ_CASE_INSENSITIVE : 0, + NULL, NULL); + get_nt_native_path (path, upath); status = NtQueryAttributesFile (&attr, &fbi); if (NT_SUCCESS (status)) @@ -736,7 +730,8 @@ getfileattr (const char *path, bool managed) /* path has to be always absolute. RtlSplitUnicodePath (&upath, &dirname, &basename); InitializeObjectAttributes (&attr, &dirname, - OBJ_CASE_INSENSITIVE, NULL, NULL); + caseinsensitive ? OBJ_CASE_INSENSITIVE : 0, + NULL, NULL); status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT @@ -825,10 +820,10 @@ path_conv::check (const char *src, unsigned opt, path_flags = 0; known_suffix = NULL; fileattr = INVALID_FILE_ATTRIBUTES; + caseinsensitive = OBJ_CASE_INSENSITIVE; if (wide_path) cfree (wide_path); wide_path = NULL; - case_clash = false; memset (&dev, 0, sizeof (dev)); fs.clear (); if (!normalized_path_size && normalized_path) @@ -918,7 +913,8 @@ path_conv::check (const char *src, unsigned opt, fileattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY; else { - fileattr = getfileattr (this->path, sym.pflags & MOUNT_ENC); + fileattr = getfileattr (this->path, + sym.pflags & MOUNT_NOPOSIX); dev.devn = FH_FS; } goto out; @@ -927,7 +923,7 @@ path_conv::check (const char *src, unsigned opt, { dev.devn = FH_FS; #if 0 - fileattr = getfileattr (this->path, sym.pflags & MOUNT_ENC); + fileattr = getfileattr (this->path, sym.pflags & MOUNT_NOPOSIX); if (!component && fileattr == INVALID_FILE_ATTRIBUTES) { fileattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY; @@ -1031,81 +1027,59 @@ is_virtual_symlink: goto out; } - if (sym.case_clash) + if (!component) { - if (pcheck_case == PCHECK_STRICT) + fileattr = sym.fileattr; + path_flags = sym.pflags; + if (cygwin_shared->obcaseinsensitive || fs.caseinsensitive ()) + path_flags |= PATH_NOPOSIX; + caseinsensitive = (path_flags & PATH_NOPOSIX) + ? OBJ_CASE_INSENSITIVE : 0; + } + + /* If symlink.check found an existing non-symlink file, then + it sets the appropriate flag. It also sets any suffix found + into `ext_here'. */ + if (!sym.issymlink && sym.fileattr != INVALID_FILE_ATTRIBUTES) + { + error = sym.error; + if (component == 0) + add_ext_from_sym (sym); + else if (!(sym.fileattr & FILE_ATTRIBUTE_DIRECTORY)) { - case_clash = true; - error = ENOENT; + error = ENOTDIR; goto out; } - /* If pcheck_case==PCHECK_ADJUST the case_clash is remembered - if the last component is concerned. This allows functions - which shall create files to avoid overriding already existing - files with another case. */ - if (!component) - case_clash = true; + goto out; // file found } - if (!(opt & PC_SYM_IGNORE)) + /* Found a symlink if symlen > 0. If component == 0, then the + src path itself was a symlink. If !follow_mode then + we're done. Otherwise we have to insert the path found + into the full path that we are building and perform all of + these operations again on the newly derived path. */ + else if (symlen > 0) { - if (!component) + saw_symlinks = 1; + if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW)) { - fileattr = sym.fileattr; - path_flags = sym.pflags; - } - - /* If symlink.check found an existing non-symlink file, then - it sets the appropriate flag. It also sets any suffix found - into `ext_here'. */ - if (!sym.issymlink && sym.fileattr != INVALID_FILE_ATTRIBUTES) - { - error = sym.error; - if (component == 0) - add_ext_from_sym (sym); - else if (!(sym.fileattr & FILE_ATTRIBUTE_DIRECTORY)) + set_symlink (symlen); // last component of path is a symlink. + if (opt & PC_SYM_CONTENTS) { - error = ENOTDIR; + strcpy (path, sym.contents); goto out; } - if (pcheck_case == PCHECK_RELAXED) - goto out; // file found - /* Avoid further symlink evaluation. Only case checks are - done now. */ - opt |= PC_SYM_IGNORE; - } - /* Found a symlink if symlen > 0. If component == 0, then the - src path itself was a symlink. If !follow_mode then - we're done. Otherwise we have to insert the path found - into the full path that we are building and perform all of - these operations again on the newly derived path. */ - else if (symlen > 0) - { - saw_symlinks = 1; - if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW)) - { - set_symlink (symlen); // last component of path is a symlink. - if (opt & PC_SYM_CONTENTS) - { - strcpy (path, sym.contents); - goto out; - } - add_ext_from_sym (sym); - if (pcheck_case == PCHECK_RELAXED) - goto out; - /* Avoid further symlink evaluation. Only case checks are - done now. */ - opt |= PC_SYM_IGNORE; - } - else - break; - } - else if (sym.error && sym.error != ENOENT && sym.error != ENOSHARE) - { - error = sym.error; + add_ext_from_sym (sym); goto out; } - /* No existing file found. */ + else + break; } + else if (sym.error && sym.error != ENOENT && sym.error != ENOSHARE) + { + error = sym.error; + goto out; + } + /* No existing file found. */ virtual_component_retry: /* Find the new "tail" of the path, e.g. in '/for/bar/baz', @@ -1246,7 +1220,7 @@ out: if (opt & PC_NOFULL) { if (is_relpath) - mkrelpath (this->path); + mkrelpath (this->path, !!caseinsensitive); if (need_directory) { size_t n = strlen (this->path); @@ -1587,7 +1561,7 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym, if (win32_newpath.error) { - set_errno (win32_newpath.case_clash ? ECASECLASH : win32_newpath.error); + set_errno (win32_newpath.error); goto done; } @@ -2334,7 +2308,8 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt, minor = 0; mode = 0; pflags &= ~(PATH_SYMLINK | PATH_LNK | PATH_REP); - case_clash = false; + ULONG ci_flag = cygwin_shared->obcaseinsensitive || (pflags & PATH_NOPOSIX) + ? OBJ_CASE_INSENSITIVE : 0; /* TODO: Temporarily do all char->UNICODE conversion here. This should already be slightly faster than using Ascii functions. */ @@ -2342,7 +2317,7 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt, UNICODE_STRING upath; OBJECT_ATTRIBUTES attr; tp.u_get (&upath); - InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL); + InitializeObjectAttributes (&attr, &upath, ci_flag, NULL, NULL); PVOID eabuf = &nfs_aol_ffei; ULONG easize = sizeof nfs_aol_ffei; @@ -2355,7 +2330,7 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt, bool no_ea = false; error = 0; - get_nt_native_path (suffix.path, upath, pflags & MOUNT_ENC); + get_nt_native_path (suffix.path, upath); if (h) { NtClose (h); @@ -2434,8 +2409,8 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt, } fdi_buf; RtlSplitUnicodePath (&upath, &dirname, &basename); - InitializeObjectAttributes (&dattr, &dirname, - OBJ_CASE_INSENSITIVE, NULL, NULL); + InitializeObjectAttributes (&dattr, &dirname, ci_flag, + NULL, NULL); status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY, &dattr, &io, FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT @@ -2475,10 +2450,6 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt, ext_tacked_on = !!*ext_here; - if (pcheck_case != PCHECK_RELAXED && !case_check (path) - || (opt & PC_SYM_IGNORE)) - goto file_not_symlink; - res = -1; /* Windows shortcuts are potentially treated as symlinks. Valid Cygwin @@ -2569,54 +2540,12 @@ symlink_info::set (char *path) error = 0; issymlink = true; isdevice = false; - ext_tacked_on = case_clash = false; + ext_tacked_on = false; ext_here = NULL; extn = major = minor = mode = 0; return strlen (path); } -/* Check the correct case of the last path component (given in DOS style). - Adjust the case in this->path if pcheck_case == PCHECK_ADJUST or return - false if pcheck_case == PCHECK_STRICT. - Dont't call if pcheck_case == PCHECK_RELAXED. -*/ - -bool -symlink_info::case_check (char *path) -{ - WIN32_FIND_DATA data; - HANDLE h; - char *c; - - /* Set a pointer to the beginning of the last component. */ - if (!(c = strrchr (path, '\\'))) - c = path; - else - ++c; - - if ((h = FindFirstFile (path, &data)) - != INVALID_HANDLE_VALUE) - { - FindClose (h); - - /* If that part of the component exists, check the case. */ - if (strncmp (c, data.cFileName, strlen (data.cFileName))) - { - case_clash = true; - - /* If check is set to STRICT, a wrong case results - in returning a ENOENT. */ - if (pcheck_case == PCHECK_STRICT) - return false; - - /* PCHECK_ADJUST adjusts the case in the incoming - path which points to the path in *this. */ - strcpy (c, data.cFileName); - } - } - return true; -} - /* readlink system call */ extern "C" ssize_t @@ -3267,6 +3196,7 @@ cwdstuff::set (PUNICODE_STRING nat_cwd, const char *posix_cwd, bool doit) phdl = &get_user_proc_parms ()->CurrentDirectoryHandle; if (!nat_cwd) /* On init, just reopen CWD with desired access flags. */ RtlInitUnicodeString (&upath, L""); + /* This is for Win32 apps only. No case sensitivity here... */ InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE | OBJ_INHERIT, nat_cwd ? NULL : *phdl, NULL); @@ -3461,7 +3391,7 @@ OBJECT_ATTRIBUTES etc::fn[MAX_ETC_FILES + 1]; LARGE_INTEGER etc::last_modified[MAX_ETC_FILES + 1]; int -etc::init (int n, PUNICODE_STRING etc_fn) +etc::init (int n, path_conv &pc) { if (n > 0) /* ok */; @@ -3470,7 +3400,7 @@ etc::init (int n, PUNICODE_STRING etc_fn) else api_fatal ("internal error"); - InitializeObjectAttributes (&fn[n], etc_fn, OBJ_CASE_INSENSITIVE, NULL, NULL); + pc.get_object_attr (fn[n], sec_none_nih); change_possible[n] = false; test_file_change (n); paranoid_printf ("fn[%d] %S, curr_ix %d", n, fn[n].ObjectName, curr_ix); diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 2db254e58..a567e1e07 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -49,7 +49,6 @@ enum pathconv_arg { PC_SYM_FOLLOW = 0x0001, PC_SYM_NOFOLLOW = 0x0002, - PC_SYM_IGNORE = 0x0004, PC_SYM_CONTENTS = 0x0008, PC_NOFULL = 0x0010, PC_NULLEMPTY = 0x0020, @@ -59,13 +58,6 @@ enum pathconv_arg PC_NO_ACCESS_CHECK = 0x00800000 }; -enum case_checking -{ - PCHECK_RELAXED = 0, - PCHECK_ADJUST = 1, - PCHECK_STRICT = 2 -}; - #define PC_NONULLEMPTY -1 #include "sys/mount.h" @@ -78,9 +70,9 @@ enum path_types PATH_EXEC = MOUNT_EXEC, PATH_NOTEXEC = MOUNT_NOTEXEC, PATH_CYGWIN_EXEC = MOUNT_CYGWIN_EXEC, - PATH_ENC = MOUNT_ENC, PATH_RO = MOUNT_RO, PATH_NOACL = MOUNT_NOACL, + PATH_NOPOSIX = MOUNT_NOPOSIX, PATH_ALL_EXEC = (PATH_CYGWIN_EXEC | PATH_EXEC), PATH_NO_ACCESS_CHECK = PC_NO_ACCESS_CHECK, PATH_LNK = 0x01000000, @@ -103,6 +95,7 @@ struct fs_info unsigned has_buggy_open : 1; unsigned has_acls : 1; unsigned hasgood_inode : 1; + unsigned caseinsensitive : 1; unsigned is_fat : 1; unsigned is_ntfs : 1; unsigned is_samba : 1; @@ -122,6 +115,7 @@ struct fs_info IMPLEMENT_STATUS_FLAG (bool, has_buggy_open) IMPLEMENT_STATUS_FLAG (bool, has_acls) IMPLEMENT_STATUS_FLAG (bool, hasgood_inode) + IMPLEMENT_STATUS_FLAG (bool, caseinsensitive) IMPLEMENT_STATUS_FLAG (bool, is_fat) IMPLEMENT_STATUS_FLAG (bool, is_ntfs) IMPLEMENT_STATUS_FLAG (bool, is_samba) @@ -136,6 +130,7 @@ struct fs_info class path_conv { DWORD fileattr; + ULONG caseinsensitive; fs_info fs; PWCHAR wide_path; UNICODE_STRING uni_path; @@ -146,15 +141,14 @@ class path_conv char *known_suffix; int error; device dev; - bool case_clash; bool isremote () const {return fs.is_remote_drive ();} + ULONG objcaseinsensitive () const {return caseinsensitive;} bool has_acls () const {return !(path_flags & PATH_NOACL) && fs.has_acls (); } bool hasgood_inode () const {return fs.hasgood_inode (); } bool isgood_inode (__ino64_t ino) const; int has_symlinks () const {return path_flags & PATH_HAS_SYMLINKS;} int has_buggy_open () const {return fs.has_buggy_open ();} - bool isencoded () const {return path_flags & PATH_ENC;} int binmode () const { if (path_flags & PATH_BINARY) @@ -333,18 +327,17 @@ has_exec_chars (const char *buf, int len) (buf[0] == 'M' && buf[1] == 'Z')); } -int pathmatch (const char *path1, const char *path2) __attribute__ ((regparm (2))); -int pathnmatch (const char *path1, const char *path2, int len) __attribute__ ((regparm (2))); +int pathmatch (const char *path1, const char *path2, bool caseinsensitive) __attribute__ ((regparm (3))); +int pathnmatch (const char *path1, const char *path2, int len, bool caseinsensitive) __attribute__ ((regparm (3))); bool has_dot_last_component (const char *dir, bool test_dot_dot) __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))); +int path_prefix_p (const char *path1, const char *path2, int len1, + bool caseinsensitive) __attribute__ ((regparm (3))); bool is_floppy (const char *); int normalize_win32_path (const char *, char *, char *&); int normalize_posix_path (const char *, char *, char *&); -PUNICODE_STRING get_nt_native_path (const char *, UNICODE_STRING&, bool); +PUNICODE_STRING get_nt_native_path (const char *, UNICODE_STRING&); /* FIXME: Move to own include file eventually */ @@ -358,7 +351,7 @@ class etc static OBJECT_ATTRIBUTES fn[MAX_ETC_FILES + 1]; static LARGE_INTEGER last_modified[MAX_ETC_FILES + 1]; static bool dir_changed (int); - static int init (int, PUNICODE_STRING); + static int init (int, path_conv &pc); static bool file_changed (int); static bool test_file_change (int); friend class pwdgrp; diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc index 047d97895..8f2537915 100644 --- a/winsup/cygwin/shared.cc +++ b/winsup/cygwin/shared.cc @@ -240,6 +240,25 @@ user_shared_initialize (bool reinit) } } +/* Initialize obcaseinsensitive. Default to case insensitive on pre-XP. */ +void +shared_info::init_obcaseinsensitive () +{ + HKEY key; + DWORD size = sizeof (DWORD); + + obcaseinsensitive = 1; + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\kernel", + 0, KEY_READ, &key) == ERROR_SUCCESS) + { + RegQueryValueEx (key, "obcaseinsensitive", NULL, NULL, + (LPBYTE) &obcaseinsensitive, &size); + RegCloseKey (key); + } + debug_printf ("obcaseinsensitive set to %d", obcaseinsensitive); +} + void shared_info::initialize () { @@ -260,8 +279,10 @@ shared_info::initialize () if (!sversion) { + tty.init (); /* Initialize tty table. */ mt.initialize (); /* Initialize shared tape information. */ + init_obcaseinsensitive ();/* Initialize obcaseinsensitive. */ cb = sizeof (*this); /* Do last, after all shared memory initialization */ } diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h index b926bdb1e..3b0036286 100644 --- a/winsup/cygwin/shared_info.h +++ b/winsup/cygwin/shared_info.h @@ -33,7 +33,6 @@ class mount_item void init (const char *dev, const char *path, unsigned flags); struct mntent *getmntent (); - int fnmunge (char *, const char *, int&); int build_win32 (char *, const char *, unsigned *, unsigned); }; @@ -120,7 +119,7 @@ public: #define SHARED_INFO_CB 31136 -#define CURR_SHARED_MAGIC 0xace17c0fU +#define CURR_SHARED_MAGIC 0x18da899eU /* NOTE: Do not make gratuitous changes to the names or organization of the below class. The layout is checksummed to determine compatibility between @@ -136,10 +135,11 @@ class shared_info DWORD sys_mount_table_counter; tty_list tty; LONG last_used_bindresvport; - DWORD obcaseinsensitivity; + DWORD obcaseinsensitive; mtinfo mt; void initialize (); + void init_obcaseinsensitive (); unsigned heap_chunk_size (); unsigned heap_slop_size (); }; diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 18c8d7498..f9d030ccc 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -197,7 +197,7 @@ try_to_bin (path_conv &win32_path, HANDLE h) RtlSplitUnicodePath (win32_path.get_nt_native_path (), &root, NULL); root.Length -= fname.Length - sizeof (WCHAR); - /* Open root directory. */ + /* Open root directory. All recycler bin ops are caseinsensitive. */ InitializeObjectAttributes (&attr, &root, OBJ_CASE_INSENSITIVE, NULL, NULL); status = NtOpenFile (&rootdir, FILE_TRAVERSE, &attr, &io, FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT); @@ -1602,13 +1602,13 @@ rename (const char *oldpath, const char *newpath) /* This test is necessary in almost every case, so just do it once here. */ equal_path = RtlEqualUnicodeString (oldpc.get_nt_native_path (), newpc.get_nt_native_path (), - TRUE); + oldpc.objcaseinsensitive ()); /* First check if oldpath and newpath only differ by case. If so, it's just a request to change the case of the filename. By simply setting the file attributes to INVALID_FILE_ATTRIBUTES (which translates to "file doesn't exist"), all later tests are skipped. */ - if (newpc.exists () && equal_path) + if (oldpc.objcaseinsensitive () && newpc.exists () && equal_path) { if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), newpc.get_nt_native_path (), @@ -1646,7 +1646,7 @@ rename (const char *oldpath, const char *newpath) newpc.check (newpath, PC_SYM_NOFOLLOW); if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), newpc.get_nt_native_path (), - TRUE)) + oldpc.objcaseinsensitive ())) { res = 0; goto out; @@ -1674,7 +1674,7 @@ rename (const char *oldpath, const char *newpath) newpc.check (newpath, PC_SYM_NOFOLLOW); if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), newpc.get_nt_native_path (), - TRUE)) + oldpc.objcaseinsensitive ())) { res = 0; goto out; @@ -2776,7 +2776,8 @@ chroot (const char *newroot) else { getwinenv("PATH="); /* Save the native PATH */ - cygheap->root.set (path.normalized_path, path.get_win32 ()); + cygheap->root.set (path.normalized_path, path.get_win32 (), + !!path.objcaseinsensitive ()); ret = 0; } diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc index ee63a2e3a..4b78cab61 100644 --- a/winsup/cygwin/times.cc +++ b/winsup/cygwin/times.cc @@ -495,7 +495,7 @@ utimens_worker (path_conv &win32, const struct timespec *tvp) if (cfd->get_access () & (FILE_WRITE_ATTRIBUTES | GENERIC_WRITE) && RtlEqualUnicodeString (cfd->pc.get_nt_native_path (), win32.get_nt_native_path (), - TRUE)) + cfd->pc.objcaseinsensitive ())) { fh = cfd; fromfd = true; diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 0ec828427..cc8beeb23 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -527,7 +527,7 @@ pwdgrp::load (const char *posix_fname) curr_lines = 0; pc.check (posix_fname); - etc_ix = etc::init (etc_ix, pc.get_nt_native_path ()); + etc_ix = etc::init (etc_ix, pc); paranoid_printf ("%s", posix_fname);