This adds support for checking the case-insensitive attribute on ext4 with newer kernels so that Wine can rely on it for performance.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/ntdll/directory.c | 53 ++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 22 deletions(-)
diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index bbdbbe9..b18f56b 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,6 +132,12 @@ 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 @@ -1113,7 +1121,7 @@ static int get_dir_case_sensitivity_attr( const char *dir ) * 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), statvfs(2), fstatat(2), or ioctl(2). */ static BOOLEAN get_dir_case_sensitivity_stat( const char *dir ) { @@ -1165,32 +1173,33 @@ static BOOLEAN get_dir_case_sensitivity_stat( const char *dir ) return FALSE;
#elif defined(__linux__) + BOOLEAN sens = TRUE; struct statfs stfs; struct stat st; - char *cifile; + int fd, flags;
- /* Only assume CIOPFS is case insensitive. */ - if (statfs( dir, &stfs ) == -1) return FALSE; - if (stfs.f_type != 0x65735546 /* FUSE_SUPER_MAGIC */) + if ((fd = open( dir, O_RDONLY | O_NONBLOCK | O_LARGEFILE )) == -1) return TRUE; - /* Normally, we'd have to parse the mtab to find out exactly what - * kind of FUSE FS this is. But, someone on wine-devel suggested - * a shortcut. We'll stat a special file in the directory. If it's - * there, we'll assume it's a CIOPFS, else not. - * This will break if somebody puts a file named ".ciopfs" in a non- - * CIOPFS directory. - */ - cifile = RtlAllocateHeap( GetProcessHeap(), 0, strlen( dir )+sizeof("/.ciopfs") ); - if (!cifile) return TRUE; - strcpy( cifile, dir ); - strcat( cifile, "/.ciopfs" ); - if (stat( cifile, &st ) == 0) + + if (ioctl( fd, EXT2_IOC_GETFLAGS, &flags ) != -1 && (flags & EXT4_CASEFOLD_FL)) { - RtlFreeHeap( GetProcessHeap(), 0, cifile ); - return FALSE; + sens = FALSE; } - RtlFreeHeap( GetProcessHeap(), 0, cifile ); - return TRUE; + else + { + /* Assume CIOPFS is case insensitive. Normally, we'd have to parse + * the mtab to find out exactly what kind of FUSE FS this is. But, + * someone on wine-devel suggested a shortcut. We'll stat a special + * file in the directory. If it's there, we'll assume it's a CIOPFS, + * else not. This will break if somebody puts a file named ".ciopfs" + * in a non-CIOPFS directory. + */ + if (fstatfs( fd, &stfs ) != -1 && stfs.f_type == 0x65735546 /* FUSE_SUPER_MAGIC */ && + fstatat( fd, ".ciopfs", &st, AT_NO_AUTOMOUNT ) == 0) + sens = FALSE; + } + close( fd ); + return sens; #else return TRUE; #endif @@ -1201,7 +1210,7 @@ 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 ) {
On Thu, Jun 13, 2019 at 06:53:59PM +0300, Gabriel Ivăncescu wrote:
- if ((fd = open( dir, O_RDONLY | O_NONBLOCK | O_LARGEFILE )) == -1) return TRUE;
- /* Normally, we'd have to parse the mtab to find out exactly what
* kind of FUSE FS this is. But, someone on wine-devel suggested
* a shortcut. We'll stat a special file in the directory. If it's
* there, we'll assume it's a CIOPFS, else not.
* This will break if somebody puts a file named ".ciopfs" in a non-
* CIOPFS directory.
*/
- cifile = RtlAllocateHeap( GetProcessHeap(), 0, strlen( dir )+sizeof("/.ciopfs") );
- if (!cifile) return TRUE;
- strcpy( cifile, dir );
- strcat( cifile, "/.ciopfs" );
- if (stat( cifile, &st ) == 0)
- if (ioctl( fd, EXT2_IOC_GETFLAGS, &flags ) != -1 && (flags & EXT4_CASEFOLD_FL)) {
RtlFreeHeap( GetProcessHeap(), 0, cifile );
return FALSE;
}sens = FALSE;
- RtlFreeHeap( GetProcessHeap(), 0, cifile );
- return TRUE;
- else
- {
/* Assume CIOPFS is case insensitive. Normally, we'd have to parse
* the mtab to find out exactly what kind of FUSE FS this is. But,
* someone on wine-devel suggested a shortcut. We'll stat a special
* file in the directory. If it's there, we'll assume it's a CIOPFS,
* else not. This will break if somebody puts a file named ".ciopfs"
* in a non-CIOPFS directory.
*/
if (fstatfs( fd, &stfs ) != -1 && stfs.f_type == 0x65735546 /* FUSE_SUPER_MAGIC */ &&
fstatat( fd, ".ciopfs", &st, AT_NO_AUTOMOUNT ) == 0)
sens = FALSE;
- }
- close( fd );
- return sens;
#else return TRUE; #endif
I've sent in a new version with a few changes. Most notably I've trimmed the CIOPFS comment right down. I've also inverted the return value check of fstatfs() to match that of fstatat().
Huw.