ntdll: Check for case-insensitive volumes.
This commit is contained in:
parent
1c25577873
commit
4e44e153c5
|
@ -5849,6 +5849,7 @@ for ac_header in \
|
||||||
strings.h \
|
strings.h \
|
||||||
stropts.h \
|
stropts.h \
|
||||||
sys/asoundlib.h \
|
sys/asoundlib.h \
|
||||||
|
sys/attr.h \
|
||||||
sys/cdio.h \
|
sys/cdio.h \
|
||||||
sys/elf32.h \
|
sys/elf32.h \
|
||||||
sys/epoll.h \
|
sys/epoll.h \
|
||||||
|
@ -12755,6 +12756,7 @@ for ac_func in \
|
||||||
ftruncate \
|
ftruncate \
|
||||||
futimes \
|
futimes \
|
||||||
futimesat \
|
futimesat \
|
||||||
|
getattrlist \
|
||||||
getdirentries \
|
getdirentries \
|
||||||
getopt_long \
|
getopt_long \
|
||||||
getpagesize \
|
getpagesize \
|
||||||
|
|
|
@ -456,6 +456,7 @@ AC_CHECK_HEADERS(\
|
||||||
strings.h \
|
strings.h \
|
||||||
stropts.h \
|
stropts.h \
|
||||||
sys/asoundlib.h \
|
sys/asoundlib.h \
|
||||||
|
sys/attr.h \
|
||||||
sys/cdio.h \
|
sys/cdio.h \
|
||||||
sys/elf32.h \
|
sys/elf32.h \
|
||||||
sys/epoll.h \
|
sys/epoll.h \
|
||||||
|
@ -1909,6 +1910,7 @@ AC_CHECK_FUNCS(\
|
||||||
ftruncate \
|
ftruncate \
|
||||||
futimes \
|
futimes \
|
||||||
futimesat \
|
futimesat \
|
||||||
|
getattrlist \
|
||||||
getdirentries \
|
getdirentries \
|
||||||
getopt_long \
|
getopt_long \
|
||||||
getpagesize \
|
getpagesize \
|
||||||
|
|
|
@ -44,6 +44,9 @@
|
||||||
#ifdef HAVE_SYS_SYSCALL_H
|
#ifdef HAVE_SYS_SYSCALL_H
|
||||||
# include <sys/syscall.h>
|
# include <sys/syscall.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_SYS_ATTR_H
|
||||||
|
#include <sys/attr.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SYS_IOCTL_H
|
#ifdef HAVE_SYS_IOCTL_H
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -59,6 +62,9 @@
|
||||||
#ifdef HAVE_SYS_MOUNT_H
|
#ifdef HAVE_SYS_MOUNT_H
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_SYS_STATFS_H
|
||||||
|
#include <sys/statfs.h>
|
||||||
|
#endif
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
|
@ -774,6 +780,243 @@ static char *get_device_mount_point( dev_t dev )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(HAVE_GETATTRLIST) && defined(ATTR_VOL_CAPABILITIES) && \
|
||||||
|
defined(VOL_CAPABILITIES_FORMAT) && defined(VOL_CAP_FMT_CASE_SENSITIVE)
|
||||||
|
|
||||||
|
struct get_fsid
|
||||||
|
{
|
||||||
|
ULONG size;
|
||||||
|
dev_t dev;
|
||||||
|
fsid_t fsid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fs_cache
|
||||||
|
{
|
||||||
|
dev_t dev;
|
||||||
|
fsid_t fsid;
|
||||||
|
BOOLEAN case_sensitive;
|
||||||
|
} fs_cache[64];
|
||||||
|
|
||||||
|
struct vol_caps
|
||||||
|
{
|
||||||
|
ULONG size;
|
||||||
|
vol_capabilities_attr_t caps;
|
||||||
|
};
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* look_up_fs_cache
|
||||||
|
*
|
||||||
|
* Checks if the specified file system is in the cache.
|
||||||
|
*/
|
||||||
|
static struct fs_cache *look_up_fs_cache( dev_t dev )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < sizeof(fs_cache)/sizeof(fs_cache[0]); i++)
|
||||||
|
if (fs_cache[i].dev == dev)
|
||||||
|
return fs_cache+i;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* add_fs_cache
|
||||||
|
*
|
||||||
|
* Adds the specified file system to the cache.
|
||||||
|
*/
|
||||||
|
static void add_fs_cache( dev_t dev, fsid_t fsid, BOOLEAN case_sensitive )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct fs_cache *entry = look_up_fs_cache( dev );
|
||||||
|
static int once = 0;
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
/* Update the cache */
|
||||||
|
entry->fsid = fsid;
|
||||||
|
entry->case_sensitive = case_sensitive;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a new entry */
|
||||||
|
for (i = 0; i < sizeof(fs_cache)/sizeof(fs_cache[0]); i++)
|
||||||
|
if (fs_cache[i].dev == 0)
|
||||||
|
{
|
||||||
|
/* This entry is empty, use it */
|
||||||
|
fs_cache[i].dev = dev;
|
||||||
|
fs_cache[i].fsid = fsid;
|
||||||
|
fs_cache[i].case_sensitive = case_sensitive;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cache is out of space, warn */
|
||||||
|
if (once++)
|
||||||
|
WARN( "FS cache is out of space, expect performance problems\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* get_dir_case_sensitivity_attr
|
||||||
|
*
|
||||||
|
* Checks if the volume containing the specified directory is case
|
||||||
|
* sensitive or not. Uses getattrlist(2).
|
||||||
|
*/
|
||||||
|
static int get_dir_case_sensitivity_attr( const char *dir )
|
||||||
|
{
|
||||||
|
char *mntpoint = NULL;
|
||||||
|
struct attrlist attr;
|
||||||
|
struct vol_caps caps;
|
||||||
|
struct get_fsid get_fsid;
|
||||||
|
struct fs_cache *entry;
|
||||||
|
|
||||||
|
/* First get the FS ID of the volume */
|
||||||
|
attr.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||||
|
attr.reserved = 0;
|
||||||
|
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 ||
|
||||||
|
get_fsid.size != sizeof(get_fsid))
|
||||||
|
return -1;
|
||||||
|
/* Try to look it up in the cache */
|
||||||
|
entry = look_up_fs_cache( get_fsid.dev );
|
||||||
|
if (entry && !memcmp( &entry->fsid, &get_fsid.fsid, sizeof(fsid_t) ))
|
||||||
|
/* Cache lookup succeeded */
|
||||||
|
return entry->case_sensitive;
|
||||||
|
/* Cache is stale at this point, we have to update it */
|
||||||
|
|
||||||
|
mntpoint = get_device_mount_point( get_fsid.dev );
|
||||||
|
/* Now look up the case-sensitivity */
|
||||||
|
attr.commonattr = 0;
|
||||||
|
attr.volattr = ATTR_VOL_INFO|ATTR_VOL_CAPABILITIES;
|
||||||
|
if (getattrlist( mntpoint, &attr, &caps, sizeof(caps), 0 ) < 0)
|
||||||
|
{
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, mntpoint );
|
||||||
|
add_fs_cache( get_fsid.dev, get_fsid.fsid, TRUE );
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, mntpoint );
|
||||||
|
if (caps.size == sizeof(caps) &&
|
||||||
|
(caps.caps.valid[VOL_CAPABILITIES_FORMAT] &
|
||||||
|
(VOL_CAP_FMT_CASE_SENSITIVE | VOL_CAP_FMT_CASE_PRESERVING)) ==
|
||||||
|
(VOL_CAP_FMT_CASE_SENSITIVE | VOL_CAP_FMT_CASE_PRESERVING))
|
||||||
|
{
|
||||||
|
BOOLEAN ret;
|
||||||
|
|
||||||
|
if ((caps.caps.capabilities[VOL_CAPABILITIES_FORMAT] &
|
||||||
|
VOL_CAP_FMT_CASE_SENSITIVE) != VOL_CAP_FMT_CASE_SENSITIVE)
|
||||||
|
ret = FALSE;
|
||||||
|
else
|
||||||
|
ret = TRUE;
|
||||||
|
/* Update the cache */
|
||||||
|
add_fs_cache( get_fsid.dev, get_fsid.fsid, ret );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* get_dir_case_sensitivity_stat
|
||||||
|
*
|
||||||
|
* Checks if the volume containing the specified directory is case
|
||||||
|
* sensitive or not. Uses statfs(2) or statvfs(2).
|
||||||
|
*/
|
||||||
|
static BOOLEAN get_dir_case_sensitivity_stat( const char *dir )
|
||||||
|
{
|
||||||
|
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
|
struct statfs stfs;
|
||||||
|
|
||||||
|
statfs( dir, &stfs );
|
||||||
|
/* 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).
|
||||||
|
*/
|
||||||
|
if (!strcmp( stfs.f_fstypename, "fusefs" ) &&
|
||||||
|
!strncmp( stfs.f_mntfromname, "ciopfs", 5 ))
|
||||||
|
return FALSE;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (!strcmp( stfs.f_fstypename, "msdos" ) ||
|
||||||
|
!strcmp( stfs.f_fstypename, "cd9660" ) ||
|
||||||
|
!strcmp( stfs.f_fstypename, "udf" ) ||
|
||||||
|
!strcmp( stfs.f_fstypename, "ntfs" ) ||
|
||||||
|
!strcmp( stfs.f_fstypename, "smbfs" ))
|
||||||
|
return FALSE;
|
||||||
|
#ifdef _DARWIN_FEATURE_64_BIT_INODE
|
||||||
|
if (!strcmp( stfs.f_fstypename, "hfs" ) && (stfs.f_fssubtype == 0 ||
|
||||||
|
stfs.f_fssubtype == 1 ||
|
||||||
|
stfs.f_fssubtype == 128))
|
||||||
|
return FALSE;
|
||||||
|
#else
|
||||||
|
/* The field says "reserved", but a quick look at the kernel source
|
||||||
|
* tells us that this "reserved" field is really the same as the
|
||||||
|
* "fssubtype" field from the inode64 structure (see munge_statfs()
|
||||||
|
* in <xnu-source>/bsd/vfs/vfs_syscalls.c).
|
||||||
|
*/
|
||||||
|
if (!strcmp( stfs.f_fstypename, "hfs" ) && (stfs.f_reserved1 == 0 ||
|
||||||
|
stfs.f_reserved1 == 1 ||
|
||||||
|
stfs.f_reserved1 == 128))
|
||||||
|
return FALSE;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
#elif defined(__NetBSD__)
|
||||||
|
struct statvfs stfs;
|
||||||
|
|
||||||
|
statvfs( dir, &stfs );
|
||||||
|
/* Only assume CIOPFS is case insensitive. */
|
||||||
|
if (strcmp( stfs.f_fstypename, "fusefs" ) ||
|
||||||
|
strncmp( stfs.f_mntfromname, "ciopfs", 5 ))
|
||||||
|
return TRUE;
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
#elif defined(__linux__)
|
||||||
|
struct statfs stfs;
|
||||||
|
struct stat st;
|
||||||
|
char *cifile;
|
||||||
|
|
||||||
|
/* Only assume CIOPFS is case insensitive. */
|
||||||
|
statfs( dir, &stfs );
|
||||||
|
if (stfs.f_type != 0x65735546 /* FUSE_SUPER_MAGIC */)
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, cifile );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, cifile );
|
||||||
|
return TRUE;
|
||||||
|
#else
|
||||||
|
return TRUE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* get_dir_case_sensitivity
|
||||||
|
*
|
||||||
|
* Checks if the volume containing the specified directory is case
|
||||||
|
* sensitive or not. Uses statfs(2) or statvfs(2).
|
||||||
|
*/
|
||||||
|
static BOOLEAN get_dir_case_sensitivity( 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 );
|
||||||
|
if (case_sensitive != -1) return case_sensitive;
|
||||||
|
#endif
|
||||||
|
return get_dir_case_sensitivity_stat( dir );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* init_options
|
* init_options
|
||||||
*
|
*
|
||||||
|
@ -1837,6 +2080,8 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
|
||||||
str.MaximumLength = str.Length;
|
str.MaximumLength = str.Length;
|
||||||
is_name_8_dot_3 = RtlIsNameLegalDOS8Dot3( &str, NULL, &spaces ) && !spaces;
|
is_name_8_dot_3 = RtlIsNameLegalDOS8Dot3( &str, NULL, &spaces ) && !spaces;
|
||||||
|
|
||||||
|
if (!is_name_8_dot_3 && !get_dir_case_sensitivity( unix_name )) goto not_found;
|
||||||
|
|
||||||
/* now look for it through the directory */
|
/* now look for it through the directory */
|
||||||
|
|
||||||
#ifdef VFAT_IOCTL_READDIR_BOTH
|
#ifdef VFAT_IOCTL_READDIR_BOTH
|
||||||
|
|
|
@ -200,6 +200,9 @@
|
||||||
/* Define to 1 if you have the `getaddrinfo' function. */
|
/* Define to 1 if you have the `getaddrinfo' function. */
|
||||||
#undef HAVE_GETADDRINFO
|
#undef HAVE_GETADDRINFO
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `getattrlist' function. */
|
||||||
|
#undef HAVE_GETATTRLIST
|
||||||
|
|
||||||
/* Define to 1 if you have the `getdirentries' function. */
|
/* Define to 1 if you have the `getdirentries' function. */
|
||||||
#undef HAVE_GETDIRENTRIES
|
#undef HAVE_GETDIRENTRIES
|
||||||
|
|
||||||
|
@ -875,6 +878,9 @@
|
||||||
/* Define to 1 if you have the <sys/asoundlib.h> header file. */
|
/* Define to 1 if you have the <sys/asoundlib.h> header file. */
|
||||||
#undef HAVE_SYS_ASOUNDLIB_H
|
#undef HAVE_SYS_ASOUNDLIB_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/attr.h> header file. */
|
||||||
|
#undef HAVE_SYS_ATTR_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/cdio.h> header file. */
|
/* Define to 1 if you have the <sys/cdio.h> header file. */
|
||||||
#undef HAVE_SYS_CDIO_H
|
#undef HAVE_SYS_CDIO_H
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue