[PATCH 2/2] ntdll: Check for case-insensitive volumes. (try 6
Charles Davis
cdavis at mymail.mines.edu
Sun Nov 14 17:12:04 CST 2010
On 11/14/10 3:01 PM, James McKenzie wrote:
> On 11/5/10 8:17 AM, Charles Davis wrote:
>> Changes since try 5:
>> o All case-sensitivity logic has been absorbed into find_file_in_dir().
>> o Eliminated one more stat(2) that I missed last time.
>> o Eliminated a statfs(2) call on Linux.
>>
>> This is a far as I think I can take it without gutting it completely. If
>> any of you have better ideas, I'd like to hear them.
>> ---
>> dlls/ntdll/directory.c | 233
>> +++++++++++++++++++++++++++++++++++++++++++++++-
>> 1 files changed, 229 insertions(+), 4 deletions(-)
>>
>> diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
>> index 865c2fa..2891792 100644
>> --- a/dlls/ntdll/directory.c
>> +++ b/dlls/ntdll/directory.c
>> @@ -41,6 +41,9 @@
>> #ifdef HAVE_SYS_STAT_H
>> # include<sys/stat.h>
>> #endif
>> +#ifdef HAVE_SYS_ATTR_H
>> +#include<sys/attr.h>
>> +#endif
>> #ifdef HAVE_SYS_IOCTL_H
>> #include<sys/ioctl.h>
>> #endif
>> @@ -56,6 +59,9 @@
>> #ifdef HAVE_SYS_MOUNT_H
>> #include<sys/mount.h>
>> #endif
>> +#ifdef HAVE_SYS_STATFS_H
>> +#include<sys/statfs.h>
>> +#endif
>> #include<time.h>
>> #ifdef HAVE_UNISTD_H
>> # include<unistd.h>
>> @@ -130,6 +136,35 @@ static inline int getdents64( int fd, char *de,
>> unsigned int size )
>>
>> #endif /* linux */
>>
>> +#if defined(HAVE_GETATTRLIST)
>> +
>> +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];
>> +
>> +#if defined(ATTR_VOL_CAPABILITIES)&&
>> defined(VOL_CAPABILITIES_FORMAT)&& \
>> + defined(VOL_CAP_FMT_CASE_SENSITIVE)
>> +
>> +struct vol_caps
>> +{
>> + ULONG size;
>> + vol_capabilities_attr_t caps;
>> +};
>> +
>> +#endif /* ATTR_VOL_CAPABILITIES */
>> +
>> +#endif /* HAVE_GETATTRLIST */
>> +
>> #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) ==
>> 't' || (ch) == 'T' || (ch) == '1')
>> #define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/')
>>
>> @@ -783,6 +818,192 @@ static char *get_device_mount_point( dev_t dev )
>> }
>>
>>
>> +
>> +#ifdef HAVE_GETATTRLIST
>> +/***********************************************************************
>> + * 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" );
>> +}
>> +#endif
>> +
>> +/***********************************************************************
>> + * get_dir_case_sensitivity
>> + *
>> + * Checks if the volume containing the specified directory is case
>> + * sensitive or not.
>> + */
>> +static BOOLEAN get_dir_case_sensitivity( const char *dir )
>> +{
>> +#if defined(__APPLE__) || defined(__FreeBSD__) ||
>> defined(__FreeBSD_kernel__)
>> + struct statfs stfs;
>> +#elif defined(__NetBSD__)
>> + struct statvfs stfs;
>> +#elif defined(__linux__)
>> + struct stat st;
>> + char *cifile;
>> +#endif
>> +
>> +#if defined(HAVE_GETATTRLIST)&& defined(ATTR_VOL_CAPABILITIES)&& \
>> + defined(VOL_CAPABILITIES_FORMAT)&&
>> defined(VOL_CAP_FMT_CASE_SENSITIVE)
>> + 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 TRUE;
>> + /* 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)
>> + {
>> + 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;
>> +
>> + RtlFreeHeap( GetProcessHeap(), 0, mntpoint );
>> + if ((caps.caps.capabilities[VOL_CAPABILITIES_FORMAT]&
>> + VOL_CAP_FMT_CASE_SENSITIVE) !=
>> VOL_CAP_FMT_CASE_SENSITIVE)
>> + ret = FALSE;
>> + ret = TRUE;
>> + /* Update the cache */
>> + add_fs_cache( get_fsid.dev, get_fsid.fsid, ret );
>> + return ret;
>> + }
>> + }
>> + RtlFreeHeap( GetProcessHeap(), 0, mntpoint );
>> + /* Fall through */
>> +#endif
>> +#if defined(__APPLE__) || defined(__FreeBSD__) ||
>> defined(__FreeBSD_kernel__)
>> + statfs( dir,&stfs );
>> + /* Assume these file systems are always case insensitive on Mac OS.
>
> Don't do this. Quake2 and quake2 turn out to be different (and I tried
> to move to a directory called Quake2 using cd
> $HOME/wine.../drive_c/quake2 and received an error this morning [Yes,
> I'm playing Quake2 on my Mac, I really, really need the stress relief,
> it is really hard to explain.})
Your FS must be a case-sensitive one. That's why I check for specific
subtypes of HFS. The ones I check for are the ones that are case
insensitive. Subtypes 0 (HFS+), 1 (HFS+ with journaling), and 128 (the
original HFS) don't check case. Subtypes 2 (HFSX) and 3 (HFSX with
journaling) do.
Last I checked, FAT, CDFS, UDF, and NTFS (but not the NTFS-3g FUSE
driver) were all case-insensitive. SMB/CIFS are also case-insensitive,
except for certain subtypes (which I don't know yet, and I need to read
the source for the SMB driver to find out).
Chip
More information about the wine-devel
mailing list