From: Brendan Shanks bshanks@codeweavers.com
--- dlls/ntdll/unix/file.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 07b65dc23e8..f3c8039be2b 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1170,9 +1170,9 @@ static void add_fs_cache( dev_t dev, fsid_t fsid, BOOLEAN case_sensitive ) * get_dir_case_sensitivity_attr * * Checks if the volume containing the specified directory is case - * sensitive or not. Uses getattrlist(2). + * sensitive or not. Uses getattrlist(2)/getattrlistat(2). */ -static int get_dir_case_sensitivity_attr( const char *dir ) +static int get_dir_case_sensitivity_attr( int root_fd, const char *dir ) { BOOLEAN ret = FALSE; char *mntpoint; @@ -1187,7 +1187,7 @@ static int get_dir_case_sensitivity_attr( const char *dir ) attr.commonattr = ATTR_CMN_DEVID|ATTR_CMN_FSID; attr.volattr = attr.dirattr = attr.fileattr = attr.forkattr = 0; get_fsid.size = 0; - if (getattrlist( dir, &attr, &get_fsid, sizeof(get_fsid), 0 ) != 0 || + if (getattrlistat( root_fd, dir, &attr, &get_fsid, sizeof(get_fsid), 0 ) != 0 || get_fsid.size != sizeof(get_fsid)) return -1;
@@ -1241,12 +1241,19 @@ done: * Checks if the volume containing the specified directory is case * sensitive or not. Uses (f)statfs(2), statvfs(2), fstatat(2), or ioctl(2). */ -static BOOLEAN get_dir_case_sensitivity_stat( const char *dir ) +static BOOLEAN get_dir_case_sensitivity_stat( int root_fd, const char *dir ) { #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) struct statfs stfs; + int fd;
- if (statfs( dir, &stfs ) == -1) return TRUE; + if ((fd = openat( root_fd, dir, O_RDONLY )) == -1) return TRUE; + if (fstatfs( fd, &stfs ) == -1) + { + close( fd ); + return TRUE; + } + close( fd ); /* Assume these file systems are always case insensitive.*/ if (!strcmp( stfs.f_fstypename, "fusefs" ) && !strncmp( stfs.f_mntfromname, "ciopfs", 5 )) @@ -1287,8 +1294,15 @@ static BOOLEAN get_dir_case_sensitivity_stat( const char *dir )
#elif defined(__NetBSD__) struct statvfs stfs; + int fd;
- if (statvfs( dir, &stfs ) == -1) return TRUE; + if ((fd = openat( root_fd, dir, O_RDONLY )) == -1) return TRUE; + if (fstatvfs( fd, &stfs ) == -1) + { + close( fd ); + return TRUE; + } + close( fd ); /* Only assume CIOPFS is case insensitive. */ if (strcmp( stfs.f_fstypename, "fusefs" ) || strncmp( stfs.f_mntfromname, "ciopfs", 5 )) @@ -1301,7 +1315,7 @@ static BOOLEAN get_dir_case_sensitivity_stat( const char *dir ) struct stat st; int fd, flags;
- if ((fd = open( dir, O_RDONLY | O_NONBLOCK )) == -1) + if ((fd = openat( root_fd, dir, O_RDONLY | O_NONBLOCK )) == -1) return TRUE;
if (ioctl( fd, EXT2_IOC_GETFLAGS, &flags ) != -1 && (flags & EXT4_CASEFOLD_FL)) @@ -1329,14 +1343,14 @@ static BOOLEAN get_dir_case_sensitivity_stat( const char *dir ) * Checks if the volume containing the specified directory is case * sensitive or not. Uses multiple methods, depending on platform. */ -static BOOLEAN get_dir_case_sensitivity( const char *dir ) +static BOOLEAN get_dir_case_sensitivity( int root_fd, const char *dir ) { #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 ); + int case_sensitive = get_dir_case_sensitivity_attr( root_fd, dir ); if (case_sensitive != -1) return case_sensitive; #endif - return get_dir_case_sensitivity_stat( dir ); + return get_dir_case_sensitivity_stat( root_fd, dir ); }
@@ -2539,7 +2553,7 @@ static NTSTATUS read_directory_data_stat( struct dir_data *data, const char *uni struct stat st;
/* if the file system is not case sensitive we can't find the actual name through stat() */ - if (!get_dir_case_sensitivity(".")) return STATUS_NO_SUCH_FILE; + if (!get_dir_case_sensitivity( AT_FDCWD, "." )) return STATUS_NO_SUCH_FILE; if (stat( unix_name, &st ) == -1) return STATUS_NO_SUCH_FILE;
TRACE( "found %s\n", debugstr_a(unix_name) ); @@ -2894,7 +2908,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i is_name_8_dot_3 = is_name_8_dot_3 && length >= 8 && name[4] == '~'; #endif
- if (!is_name_8_dot_3 && !get_dir_case_sensitivity( unix_name )) goto not_found; + if (!is_name_8_dot_3 && !get_dir_case_sensitivity( AT_FDCWD, unix_name )) goto not_found;
/* now look for it through the directory */