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.})
> + * For FreeBSD, only assume CIOPFS is case insensitive (AFAIK, Mac OS
> + * is the only UNIX that supports case-insensitive lookup).
> + */