Case sensitive file paths on Windows
The intent is to avoid UMC authors accidentally mistyping a file name and making an addon that doesn't work correctly on GNU/Linux. Thanks to @Arcanister for suggesting the GetFinalPathNameByHandle function.
This commit is contained in:
parent
640ffe42d4
commit
37225d24ea
4 changed files with 43 additions and 0 deletions
|
@ -1,4 +1,6 @@
|
||||||
Version 1.13.11:
|
Version 1.13.11:
|
||||||
|
* WML Engine:
|
||||||
|
* File paths are now case sensitive even on Windows.
|
||||||
|
|
||||||
Version 1.13.10:
|
Version 1.13.10:
|
||||||
* Add-ons client:
|
* Add-ons client:
|
||||||
|
|
|
@ -54,6 +54,9 @@ enum file_name_option { ENTIRE_FILE_PATH, FILE_NAME_ONLY };
|
||||||
enum file_filter_option { NO_FILTER, SKIP_MEDIA_DIR, SKIP_PBL_FILES };
|
enum file_filter_option { NO_FILTER, SKIP_MEDIA_DIR, SKIP_PBL_FILES };
|
||||||
enum file_reorder_option { DONT_REORDER, DO_REORDER };
|
enum file_reorder_option { DONT_REORDER, DO_REORDER };
|
||||||
|
|
||||||
|
/** Some tasks to run on startup. */
|
||||||
|
void init();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates 'files' with all the files and
|
* Populates 'files' with all the files and
|
||||||
* 'dirs' with all the directories in dir.
|
* 'dirs' with all the directories in dir.
|
||||||
|
|
|
@ -43,6 +43,7 @@ using boost::uintmax_t;
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "game_config.hpp"
|
#include "game_config.hpp"
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
#include "serialization/unicode_cast.hpp"
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
|
|
||||||
static lg::log_domain log_filesystem("filesystem");
|
static lg::log_domain log_filesystem("filesystem");
|
||||||
|
@ -189,12 +190,42 @@ namespace {
|
||||||
};
|
};
|
||||||
|
|
||||||
static static_runner static_bfs_path_imbuer;
|
static static_runner static_bfs_path_imbuer;
|
||||||
|
|
||||||
|
typedef DWORD(WINAPI *GetFinalPathNameByHandleWPtr)(HANDLE, LPWSTR, DWORD, DWORD);
|
||||||
|
static GetFinalPathNameByHandleWPtr dyn_GetFinalPathNameByHandle;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool is_filename_case_correct(const std::string& fname, const boost::iostreams::file_descriptor_source& fd)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
if(dyn_GetFinalPathNameByHandle == nullptr) {
|
||||||
|
// Windows XP. Just assume that the case is correct.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t real_path[MAX_PATH];
|
||||||
|
dyn_GetFinalPathNameByHandle(fd.handle(), real_path, MAX_PATH - 1, VOLUME_NAME_NONE);
|
||||||
|
std::string real_name = filesystem::base_name(unicode_cast<std::string>(std::wstring(real_path)));
|
||||||
|
return real_name == filesystem::base_name(fname);
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace filesystem {
|
namespace filesystem {
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
HMODULE kernel32 = GetModuleHandle(TEXT("Kernel32.dll"));
|
||||||
|
// Note that this returns a null pointer on Windows XP!
|
||||||
|
dyn_GetFinalPathNameByHandle = reinterpret_cast<GetFinalPathNameByHandleWPtr>(
|
||||||
|
GetProcAddress(kernel32, "GetFinalPathNameByHandleW"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void push_if_exists(std::vector<std::string> *vec, const path &file, bool full) {
|
static void push_if_exists(std::vector<std::string> *vec, const path &file, bool full) {
|
||||||
if (vec != nullptr) {
|
if (vec != nullptr) {
|
||||||
if (full)
|
if (full)
|
||||||
|
@ -779,6 +810,11 @@ filesystem::scoped_istream istream_file(const std::string &fname, bool treat_fai
|
||||||
//TODO: has this still use ?
|
//TODO: has this still use ?
|
||||||
if (!fd.is_open() && treat_failure_as_error) {
|
if (!fd.is_open() && treat_failure_as_error) {
|
||||||
ERR_FS << "Could not open '" << fname << "' for reading.\n";
|
ERR_FS << "Could not open '" << fname << "' for reading.\n";
|
||||||
|
} else if (!is_filename_case_correct(fname, fd)) {
|
||||||
|
ERR_FS << "Not opening '" << fname << "' due to case mismatch.\n";
|
||||||
|
filesystem::scoped_istream s(new bfs::ifstream());
|
||||||
|
s->clear(std::ios_base::failbit);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
return filesystem::scoped_istream(new boost::iostreams::stream<boost::iostreams::file_descriptor_source>(fd, 4096, 0));
|
return filesystem::scoped_istream(new boost::iostreams::stream<boost::iostreams::file_descriptor_source>(fd, 4096, 0));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1003,6 +1003,8 @@ int main(int argc, char** argv)
|
||||||
#endif
|
#endif
|
||||||
#endif //_OPENMP
|
#endif //_OPENMP
|
||||||
|
|
||||||
|
filesystem::init();
|
||||||
|
|
||||||
if(SDL_Init(SDL_INIT_TIMER) < 0) {
|
if(SDL_Init(SDL_INIT_TIMER) < 0) {
|
||||||
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
|
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
|
||||||
return(1);
|
return(1);
|
||||||
|
|
Loading…
Add table
Reference in a new issue