From 1d3c799e6faa6c0c24a2a60245d51491f5695918 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Fri, 7 Jun 2019 10:53:43 +1000 Subject: [PATCH] Added ntdll-ext4-case-folder patchset --- ...Add-support-for-EXT4-case-folding-pe.patch | 189 ++++++++++++++++++ ...k-drive_c-as-case-insensitive-when-c.patch | 94 +++++++++ patches/ntdll-ext4-case-folder/definition | 1 + patches/patchinstall.sh | 21 ++ 4 files changed, 305 insertions(+) create mode 100644 patches/ntdll-ext4-case-folder/0001-ntdll-directory-Add-support-for-EXT4-case-folding-pe.patch create mode 100644 patches/ntdll-ext4-case-folder/0002-ntdll-server-Mark-drive_c-as-case-insensitive-when-c.patch create mode 100644 patches/ntdll-ext4-case-folder/definition diff --git a/patches/ntdll-ext4-case-folder/0001-ntdll-directory-Add-support-for-EXT4-case-folding-pe.patch b/patches/ntdll-ext4-case-folder/0001-ntdll-directory-Add-support-for-EXT4-case-folding-pe.patch new file mode 100644 index 00000000..1d5b14ce --- /dev/null +++ b/patches/ntdll-ext4-case-folder/0001-ntdll-directory-Add-support-for-EXT4-case-folding-pe.patch @@ -0,0 +1,189 @@ +From ca8e866f9653e4c045a9c59759a0d2400d4dfc2c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= +Date: Fri, 24 May 2019 15:09:34 +0300 +Subject: [PATCH 1/2] ntdll/directory: Add support for EXT4 case folding per + directory +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This adds support for checking the case-insensitive attribute on ext4 with +newer kernels so that Wine can rely on it for performance. + +It has some conditional processing for perf reasons. Checking for the +EXT4_CASEFOLD_FL attribute involves an ioctl, which operates on file +descriptors, while all the former checks operated directly on the dir pathname +(e.g. statfs). + +Obviously, it's best to avoid looking up the directory multiple times (also +for correctness, so it refers to the same dir). So in the case that we *do* +have a file descriptor, then use it everywhere, with e.g. fstatfs. + +However, to avoid a perf regression or downgrade on systems that don't +support the EXT2_IOC_GETFLAGS ioctl (e.g. MacOS, FreeBSD), we continue +using statfs and the like directly, this shaves off two syscalls (open/close). + +But in the case the EXT4_CASEFOLD_FL is not supported on Linux (i.e. on +current kernels) or the directory doesn't have it, this will unfortunately +involve a bit more syscalls now, because it has to open() and close() the fd, +but it shouldn't be too much of a problem. (the fstatfs and fstatat make it +less impactful somewhat, so they won't have to lookup the directory again, +hopefully mitigating some of it) + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47099 +Signed-off-by: Gabriel Ivăncescu +--- + dlls/ntdll/directory.c | 73 +++++++++++++++++++++++++++++++++++++----- + 1 file changed, 65 insertions(+), 8 deletions(-) + +diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c +index bbdbbe9781..354c00f7eb 100644 +--- a/dlls/ntdll/directory.c ++++ b/dlls/ntdll/directory.c +@@ -115,6 +115,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(file); + + /* just in case... */ + #undef VFAT_IOCTL_READDIR_BOTH ++#undef EXT2_IOC_GETFLAGS ++#undef EXT4_CASEFOLD_FL + + #ifdef linux + +@@ -130,12 +132,25 @@ typedef struct + /* Define the VFAT ioctl to get both short and long file names */ + #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, KERNEL_DIRENT [2] ) + ++/* Define the ext2 ioctl for handling extra attributes */ ++#define EXT2_IOC_GETFLAGS _IOR('f', 1, long) ++ ++/* Case-insensitivity attribute */ ++#define EXT4_CASEFOLD_FL 0x40000000 ++ + #ifndef O_DIRECTORY + # define O_DIRECTORY 0200000 /* must be directory */ + #endif + + #endif /* linux */ + ++/* Use a file descriptor for the case-sensitivity check if we have to */ ++#if defined(EXT2_IOC_GETFLAGS) && defined(EXT4_CASEFOLD_FL) ++#define GET_DIR_CASE_SENSITIVITY_USE_FD 1 ++#else ++#define GET_DIR_CASE_SENSITIVITY_USE_FD 0 ++#endif ++ + #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1') + #define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/') + +@@ -1109,18 +1124,35 @@ static int get_dir_case_sensitivity_attr( const char *dir ) + } + #endif + ++/*********************************************************************** ++ * get_dir_case_sensitivity_ioctl ++ * ++ * Checks if the specified directory is case sensitive or not. Uses ioctl(2). ++ */ ++static int get_dir_case_sensitivity_ioctl(int fd) ++{ ++#if defined(EXT2_IOC_GETFLAGS) && defined(EXT4_CASEFOLD_FL) ++ int flags; ++ if (ioctl(fd, EXT2_IOC_GETFLAGS, &flags) != -1 && (flags & EXT4_CASEFOLD_FL)) ++ return FALSE; ++#endif ++ return -1; ++} ++ + /*********************************************************************** + * get_dir_case_sensitivity_stat + * + * Checks if the volume containing the specified directory is case +- * sensitive or not. Uses statfs(2) or statvfs(2). ++ * sensitive or not. Uses (f)statfs(2), (f)statvfs(2), or fstatat(2). + */ +-static BOOLEAN get_dir_case_sensitivity_stat( const char *dir ) ++static BOOLEAN get_dir_case_sensitivity_stat( const char *dir, int fd ) + { + #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + struct statfs stfs; + +- if (statfs( dir, &stfs ) == -1) return FALSE; ++ if (fd != -1 && fstatfs( fd, &stfs ) == -1) return FALSE; ++ if (fd == -1 && statfs( dir, &stfs ) == -1) return FALSE; ++ + /* Assume these file systems are always case insensitive on Mac OS. + * For FreeBSD, only assume CIOPFS is case insensitive (AFAIK, Mac OS + * is the only UNIX that supports case-insensitive lookup). +@@ -1157,7 +1189,9 @@ static BOOLEAN get_dir_case_sensitivity_stat( const char *dir ) + #elif defined(__NetBSD__) + struct statvfs stfs; + +- if (statvfs( dir, &stfs ) == -1) return FALSE; ++ if (fd != -1 && fstatvfs( fd, &stfs ) == -1) return FALSE; ++ if (fd == -1 && statvfs( dir, &stfs ) == -1) return FALSE; ++ + /* Only assume CIOPFS is case insensitive. */ + if (strcmp( stfs.f_fstypename, "fusefs" ) || + strncmp( stfs.f_mntfromname, "ciopfs", 5 )) +@@ -1170,7 +1204,9 @@ static BOOLEAN get_dir_case_sensitivity_stat( const char *dir ) + char *cifile; + + /* Only assume CIOPFS is case insensitive. */ +- if (statfs( dir, &stfs ) == -1) return FALSE; ++ if (fd != -1 && fstatfs( fd, &stfs ) == -1) return FALSE; ++ if (fd == -1 && statfs( dir, &stfs ) == -1) return FALSE; ++ + if (stfs.f_type != 0x65735546 /* FUSE_SUPER_MAGIC */) + return TRUE; + /* Normally, we'd have to parse the mtab to find out exactly what +@@ -1180,6 +1216,13 @@ static BOOLEAN get_dir_case_sensitivity_stat( const char *dir ) + * This will break if somebody puts a file named ".ciopfs" in a non- + * CIOPFS directory. + */ ++ if (fd != -1) ++ { ++ if (fstatat( fd, ".ciopfs", &st, AT_NO_AUTOMOUNT ) == 0) ++ return FALSE; ++ return TRUE; ++ } ++ + cifile = RtlAllocateHeap( GetProcessHeap(), 0, strlen( dir )+sizeof("/.ciopfs") ); + if (!cifile) return TRUE; + strcpy( cifile, dir ); +@@ -1201,16 +1244,30 @@ static BOOLEAN get_dir_case_sensitivity_stat( const char *dir ) + * get_dir_case_sensitivity + * + * Checks if the volume containing the specified directory is case +- * sensitive or not. Uses statfs(2) or statvfs(2). ++ * sensitive or not. Uses multiple methods, depending on platform. + */ + static BOOLEAN get_dir_case_sensitivity( const char *dir ) + { ++ int case_sensitive, fd = -1; ++ + #if defined(HAVE_GETATTRLIST) && defined(ATTR_VOL_CAPABILITIES) && \ + defined(VOL_CAPABILITIES_FORMAT) && defined(VOL_CAP_FMT_CASE_SENSITIVE) +- int case_sensitive = get_dir_case_sensitivity_attr( dir ); ++ case_sensitive = get_dir_case_sensitivity_attr( dir ); + if (case_sensitive != -1) return case_sensitive; + #endif +- return get_dir_case_sensitivity_stat( dir ); ++ ++ if (GET_DIR_CASE_SENSITIVITY_USE_FD) ++ { ++ if ((fd = open(dir, O_RDONLY | O_NONBLOCK | O_LARGEFILE)) == -1) ++ return TRUE; ++ if ((case_sensitive = get_dir_case_sensitivity_ioctl(fd)) != -1) ++ goto end; ++ } ++ case_sensitive = get_dir_case_sensitivity_stat(dir, fd); ++ ++end: ++ if (fd != -1) close(fd); ++ return case_sensitive; + } + + +-- +2.17.1 + diff --git a/patches/ntdll-ext4-case-folder/0002-ntdll-server-Mark-drive_c-as-case-insensitive-when-c.patch b/patches/ntdll-ext4-case-folder/0002-ntdll-server-Mark-drive_c-as-case-insensitive-when-c.patch new file mode 100644 index 00000000..b553fed8 --- /dev/null +++ b/patches/ntdll-ext4-case-folder/0002-ntdll-server-Mark-drive_c-as-case-insensitive-when-c.patch @@ -0,0 +1,94 @@ +From f794872f3ba2bd78afea1df2f353846a7f5e5788 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= +Date: Fri, 24 May 2019 15:09:35 +0300 +Subject: [PATCH] ntdll/server: Mark drive_c as case-insensitive when created +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47099 +Signed-off-by: Gabriel Ivăncescu +--- + dlls/ntdll/server.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c +index dcb355a6534..aca93509639 100644 +--- a/dlls/ntdll/server.c ++++ b/dlls/ntdll/server.c +@@ -51,6 +51,12 @@ + #ifdef HAVE_SYS_MMAN_H + #include + #endif ++#ifdef HAVE_SYS_IOCTL_H ++#include ++#endif ++#ifdef HAVE_LINUX_IOCTL_H ++#include ++#endif + #ifdef HAVE_SYS_PRCTL_H + # include + #endif +@@ -86,6 +92,22 @@ + WINE_DEFAULT_DEBUG_CHANNEL(server); + WINE_DECLARE_DEBUG_CHANNEL(winediag); + ++/* just in case... */ ++#undef EXT2_IOC_GETFLAGS ++#undef EXT2_IOC_SETFLAGS ++#undef EXT4_CASEFOLD_FL ++ ++#ifdef __linux__ ++ ++/* Define the ext2 ioctls for handling extra attributes */ ++#define EXT2_IOC_GETFLAGS _IOR('f', 1, long) ++#define EXT2_IOC_SETFLAGS _IOW('f', 2, long) ++ ++/* Case-insensitivity attribute */ ++#define EXT4_CASEFOLD_FL 0x40000000 ++ ++#endif ++ + /* Some versions of glibc don't define this */ + #ifndef SCM_RIGHTS + #define SCM_RIGHTS 1 +@@ -1248,6 +1270,28 @@ static void start_server(void) + } + + ++/*********************************************************************** ++ * set_case_insensitive ++ * ++ * Make the supplied directory case insensitive, if available. ++ */ ++static void set_case_insensitive(const char *dir) ++{ ++#if defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && defined(EXT4_CASEFOLD_FL) ++ int flags, fd; ++ ++ if ((fd = open(dir, O_RDONLY | O_NONBLOCK | O_LARGEFILE)) == -1) ++ return; ++ if (ioctl(fd, EXT2_IOC_GETFLAGS, &flags) != -1 && !(flags & EXT4_CASEFOLD_FL)) ++ { ++ flags |= EXT4_CASEFOLD_FL; ++ ioctl(fd, EXT2_IOC_SETFLAGS, &flags); ++ } ++ close(fd); ++#endif ++} ++ ++ + /*********************************************************************** + * setup_config_dir + * +@@ -1291,6 +1335,7 @@ static int setup_config_dir(void) + /* create the drive symlinks */ + + mkdir( "drive_c", 0777 ); ++ set_case_insensitive( "drive_c" ); + symlink( "../drive_c", "dosdevices/c:" ); + symlink( "/", "dosdevices/z:" ); + +-- +2.17.1 + diff --git a/patches/ntdll-ext4-case-folder/definition b/patches/ntdll-ext4-case-folder/definition new file mode 100644 index 00000000..39ed8863 --- /dev/null +++ b/patches/ntdll-ext4-case-folder/definition @@ -0,0 +1 @@ +Fixes: [47099] Support for EXT4 case folding per directory. diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 060e7b4d..ecf52521 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -221,6 +221,7 @@ patch_enable_all () enable_ntdll_Wait_User_APC="$1" enable_ntdll_Zero_mod_name="$1" enable_ntdll_aarch_TEB="$1" + enable_ntdll_ext4_case_folder="$1" enable_ntdll_set_full_cpu_context="$1" enable_ntoskrnl_Stubs="$1" enable_nvapi_Stub_DLL="$1" @@ -788,6 +789,9 @@ patch_enable () ntdll-aarch-TEB) enable_ntdll_aarch_TEB="$2" ;; + ntdll-ext4-case-folder) + enable_ntdll_ext4_case_folder="$2" + ;; ntdll-set_full_cpu_context) enable_ntdll_set_full_cpu_context="$2" ;; @@ -4967,6 +4971,23 @@ if test "$enable_ntdll_aarch_TEB" -eq 1; then ) >> "$patchlist" fi +# Patchset ntdll-ext4-case-folder +# | +# | This patchset fixes the following Wine bugs: +# | * [#47099] Support for EXT4 case folding per directory. +# | +# | Modified files: +# | * dlls/ntdll/directory.c, dlls/ntdll/server.c +# | +if test "$enable_ntdll_ext4_case_folder" -eq 1; then + patch_apply ntdll-ext4-case-folder/0001-ntdll-directory-Add-support-for-EXT4-case-folding-pe.patch + patch_apply ntdll-ext4-case-folder/0002-ntdll-server-Mark-drive_c-as-case-insensitive-when-c.patch + ( + printf '%s\n' '+ { "Gabriel Ivăncescu", "ntdll/directory: Add support for EXT4 case folding per directory.", 1 },'; + printf '%s\n' '+ { "Gabriel Ivăncescu", "ntdll/server: Mark drive_c as case-insensitive when created.", 1 },'; + ) >> "$patchlist" +fi + # Patchset ntdll-set_full_cpu_context # | # | Modified files: