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