From 68c701fb4a2b9502fa0e38f2665c12c4a46dc485 Mon Sep 17 00:00:00 2001 From: helixhorned Date: Fri, 25 May 2012 15:23:55 +0000 Subject: [PATCH] On Windows, check for case-mismatched file names on successful kopen4load(). When a file from the local file system is opened, its real file name is gotten with SHGetFileInfo() and compared against the one that was passed. In the case they're not identical, a warning is issued. This is one step towards eliminating mismatched file names in DEFs etc., which cause trouble on systems that look them up case-sensitively. However, it's not perfect because the issue is trickier than it appears on first sight. For one thing, this will only check the last (i.e. file) part in the path, falsely accepting mismatched directory names. However for these, it reports them ruthlessly, even for those names where the try-other-case hack (try all uppercase, all lowercase) would find the correctly-cased file. git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/build/src/cache1d.c | 80 ++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/polymer/eduke32/build/src/cache1d.c b/polymer/eduke32/build/src/cache1d.c index fc7a8c926..273ab60a3 100644 --- a/polymer/eduke32/build/src/cache1d.c +++ b/polymer/eduke32/build/src/cache1d.c @@ -6,6 +6,10 @@ // by Jonathon Fowler (jf@jonof.id.au) #include "compat.h" +#ifdef _WIN32 +// for FILENAME_CASE_CHECK +# include +#endif #include "cache1d.h" #include "pragmas.h" #include "baselayer.h" @@ -443,6 +447,16 @@ int32_t findfrompath(const char *fn, char **where) return -1; } +#ifdef _WIN32 +# define FILENAME_CASE_CHECK +#endif + +#ifdef FILENAME_CASE_CHECK +// don't free pfn if !=0 AND we Bopen()'ed the file successfully +static int32_t dont_free_pfn; +static char *lastpfn; +#endif + int32_t openfrompath(const char *fn, int32_t flags, int32_t mode) { char *pfn; @@ -450,7 +464,12 @@ int32_t openfrompath(const char *fn, int32_t flags, int32_t mode) if (findfrompath(fn, &pfn) < 0) return -1; h = Bopen(pfn, flags, mode); - Bfree(pfn); +#ifdef FILENAME_CASE_CHECK + if (h>=0 && dont_free_pfn) + lastpfn = pfn; + else +#endif + Bfree(pfn); return h; } @@ -666,6 +685,24 @@ void uninitgroupfile(void) } } +#ifdef FILENAME_CASE_CHECK +// See +// http://stackoverflow.com/questions/74451/getting-actual-file-name-with-proper-casing-on-windows +// for relevant discussion. + +static SHFILEINFO shinf; + +// -1: failure, 0: match, 1: mismatch +static int32_t check_filename_mismatch(const char *filename, int32_t ofs) +{ + // we assume that UNICODE is not #defined, winlayer.c errors out else + if (!SHGetFileInfo(filename, -1, &shinf, sizeof(shinf), SHGFI_DISPLAYNAME)) + return -1; + + return !!Bstrcmp(shinf.szDisplayName, filename+ofs); +} +#endif + int32_t kopen4load(const char *filename, char searchfirst) { int32_t j, k, fil, newhandle = MAXOPENFILES-1; @@ -685,14 +722,55 @@ int32_t kopen4load(const char *filename, char searchfirst) } } +#ifdef FILENAME_CASE_CHECK + dont_free_pfn = 1; +#endif + if (searchfirst == 0 && (fil = openfrompath(filename,BO_BINARY|BO_RDONLY,S_IREAD)) >= 0) { +#ifdef FILENAME_CASE_CHECK + int32_t status; + char *cp, *lastslash; + + // convert all slashes to backslashes because SHGetFileInfo() + // complains else! + lastslash = lastpfn; + for (cp=lastpfn; *cp; cp++) + if (*cp=='/') + { + *cp = '\\'; + lastslash = cp; + } + if (lastslash != lastpfn) + lastslash++; + + status = check_filename_mismatch(lastpfn, lastslash-lastpfn); + + dont_free_pfn = 0; + + if (status == -1) + { + initprintf("SHGetFileInfo failed with error code %lu\n", GetLastError()); + } + else if (status == 1) + { + initprintf("warning: case mismatch: passed \"%s\", real \"%s\"\n", + lastslash, shinf.szDisplayName); + } + + Bfree(lastpfn); + lastpfn=NULL; +#endif filegrp[newhandle] = 255; filehan[newhandle] = fil; filepos[newhandle] = 0; return(newhandle); } +#ifdef FILENAME_CASE_CHECK + dont_free_pfn = 0; +#endif + for (; toupperlookup[*filename] == '/'; filename++); #ifdef WITHKPLIB