From eb8844fd113d3fdae0456d56bdb0eb56e3a5f26b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eray=20or=C3=A7unus?= Date: Sun, 26 Jul 2020 20:59:58 +0300 Subject: Fix casepath chaos --- src/audio/oal/stream.cpp | 12 ++--- src/core/CdStreamPosix.cpp | 16 +++--- src/core/FileMgr.cpp | 37 +++---------- src/fakerw/fake.cpp | 62 ++++++++++------------ src/skel/crossplatform.cpp | 129 ++++++++++++++++++++++++++++----------------- src/skel/crossplatform.h | 6 ++- 6 files changed, 132 insertions(+), 130 deletions(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index 1ffe941e..9fad47a9 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -203,15 +203,11 @@ CStream::CStream(char *filename, ALuint &source, ALuint (&buffers)[NUM_STREAMBUF { // Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/) #if !defined(_WIN32) - FILE *test = fopen(filename, "r"); - if (!test) { - char *r = (char*)alloca(strlen(filename) + 4); - if (casepath(filename, r)) - { - strcpy(m_aFilename, r); - } + char *real = casepath(filename); + if (real) { + strcpy(m_aFilename, real); + free(real); } else { - fclose(test); #else { #endif diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp index 073ba909..45fd9832 100644 --- a/src/core/CdStreamPosix.cpp +++ b/src/core/CdStreamPosix.cpp @@ -189,10 +189,11 @@ GetGTA3ImgSize(void) realpath(gImgNames[0], path); if (stat(path, &statbuf) == -1) { // Try case-insensitivity - char *r = (char*)alloca(strlen(gImgNames[0]) + 4); - if (casepath(gImgNames[0], r)) + char* real = casepath(gImgNames[0], false); + if (real) { - realpath(r, path); + realpath(real, path); + free(real); if (stat(path, &statbuf) != -1) goto ok; } @@ -210,7 +211,6 @@ CdStreamShutdown(void) { // Destroying semaphores and free(gpReadInfo) will be done at threads #ifndef ONE_THREAD_PER_CHANNEL - free(gChannelRequestQ.items); gCdStreamThreadStatus = 2; sem_post(&gCdStreamSema); #endif @@ -442,6 +442,7 @@ void *CdStreamThread(void *param) sem_destroy(&gpReadInfo[i].pDoneSemaphore); } sem_destroy(&gCdStreamSema); + free(gChannelRequestQ.items); #else sem_destroy(&gpReadInfo[channel].pStartSemaphore); sem_destroy(&gpReadInfo[channel].pDoneSemaphore); @@ -460,10 +461,11 @@ CdStreamAddImage(char const *path) // Fix case sensitivity and backslashes. if (gImgFiles[gNumImages] == -1) { - char *r = (char*)alloca(strlen(path) + 4); - if (casepath(path, r)) + char* real = casepath(path, false); + if (real) { - gImgFiles[gNumImages] = open(r, _gdwCdStreamFlags); + gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags); + free(real); } } diff --git a/src/core/FileMgr.cpp b/src/core/FileMgr.cpp index 618874fa..ac51f8de 100644 --- a/src/core/FileMgr.cpp +++ b/src/core/FileMgr.cpp @@ -4,6 +4,7 @@ #include #endif #include "common.h" +#include "crossplatform.h" #include "FileMgr.h" @@ -31,19 +32,16 @@ static myFILE myfiles[NUMFILES]; #include #include #include -#include "crossplatform.h" #define _getcwd getcwd // Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen) void mychdir(char const *path) { - char *r = (char*)alloca(strlen(path) + 4); - if (casepath(path, r)) - { + char* r = casepath(path, false); + if (r) { chdir(r); - } - else - { + free(r); + } else { errno = ENOENT; } } @@ -73,30 +71,7 @@ found: *p++ = 'b'; *p = '\0'; -#if !defined(_WIN32) - char *newPath = strdup(filename); - // Normally casepath() fixes backslashes, but if the mode is sth other than r/rb it will create new file with backslashes on linux, so fix backslashes here - char *nextBs; - while(nextBs = strstr(newPath, "\\")){ - *nextBs = '/'; - } -#else - const char *newPath = filename; -#endif - - myfiles[fd].file = fopen(newPath, realmode); -// Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/) -#if !defined(_WIN32) - if (!myfiles[fd].file) { - char *r = (char*)alloca(strlen(newPath) + 4); - if (casepath(newPath, r)) - { - myfiles[fd].file = fopen(r, realmode); - } - } - - free(newPath); -#endif + myfiles[fd].file = fcaseopen(filename, realmode); if(myfiles[fd].file == nil) return 0; return fd; diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index d4417a7f..7d563d77 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -375,23 +375,19 @@ RwStream *RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, const v file = rwNewT(StreamFile, 1, 0); memcpy(file, &fakefile, sizeof(StreamFile)); #ifndef _WIN32 - // Be case-insensitive and fix backslashes (from https://github.com/OneSadCookie/fcaseopen/) - FILE* first = fopen((char*)pData, "r"); - char *r; - if (!first) { - r = (char*)alloca(strlen((char*)pData) + 4); - // Use default path(and pass error handling to librw) if we can't find any match - if (!casepath((char*)pData, r)) - r = (char*)pData; + char *r = casepath((char*)pData); + if (r) { + if (file->open((char*)r, mode)) { + free(r); + return file; + } + free(r); } else - fclose(first); - - if(file->open((char*)r, mode)) - return file; -#else - if(file->open((char*)pData, mode)) - return file; #endif + { + if (file->open((char*)pData, mode)) + return file; + } rwFree(file); return nil; } @@ -859,15 +855,14 @@ RwImage * RtBMPImageWrite(RwImage *image, const RwChar *imageName) { #ifndef _WIN32 - char *r = nil; - FILE *valid = fopen((char *)imageName, "r"); - if(!valid) { - char *r = (char *)alloca(strlen((char *)imageName) + 4); - // Use default path(and pass error handling to librw) if we can't find any match - if(!casepath((char *)imageName, r)) r = (char *)imageName; - } else - fclose(valid); - rw::writeBMP(image, r); + char *r = casepath(imageName); + if (r) { + rw::writeBMP(image, r); + free(r); + } else { + rw::writeBMP(image, imageName); + } + #else rw::writeBMP(image, imageName); #endif @@ -877,15 +872,16 @@ RwImage * RtBMPImageRead(const RwChar *imageName) { #ifndef _WIN32 - char *r = nil; - FILE *valid = fopen((char *)imageName, "r"); - if(!valid) { - r = (char *)alloca(strlen((char *)imageName) + 4); - // Use default path(and pass error handling to librw) if we can't find any match - if(!casepath((char *)imageName, r)) r = (char *)imageName; - } else - fclose(valid); - return rw::readBMP(r); + RwImage *image; + char *r = casepath(imageName); + if (r) { + image = rw::readBMP(r); + free(r); + } else { + image = rw::readBMP(imageName); + } + return image; + #else return rw::readBMP(imageName); #endif diff --git a/src/skel/crossplatform.cpp b/src/skel/crossplatform.cpp index 40f4f053..6188992d 100644 --- a/src/skel/crossplatform.cpp +++ b/src/skel/crossplatform.cpp @@ -87,7 +87,7 @@ void FileTimeToSystemTime(time_t* writeTime, SYSTEMTIME* out) { // Funcs/features from Windows that we need on other platforms #ifndef _WIN32 char *strupr(char *s) { - char* tmp = s; + char* tmp = s; for (;*tmp;++tmp) { *tmp = toupper((unsigned char) *tmp); @@ -96,7 +96,7 @@ char *strupr(char *s) { return s; } char *strlwr(char *s) { - char* tmp = s; + char* tmp = s; for (;*tmp;++tmp) { *tmp = tolower((unsigned char) *tmp); @@ -116,86 +116,117 @@ char *trim(char *s) { return s; } +FILE* _fcaseopen(char const* filename, char const* mode) +{ + FILE* result; + char* real = casepath(filename); + if (!real) + result = fopen(filename, mode); + else { + result = fopen(real, mode); + free(real); + } + return result; +} + // Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen) -// r must have strlen(path) + 2 bytes -int casepath(char const *path, char *r) +// Returned string should freed manually (if exists) +char* casepath(char const* path, bool checkPathFirst) { + if (checkPathFirst && access(path, F_OK) != -1) { + // File path is correct + return nil; + } + size_t l = strlen(path); - char *p = (char*)alloca(l + 1); + char* p = (char*)alloca(l + 1); + char* out = (char*)malloc(l + 3); // for extra ./ strcpy(p, path); - // my addon: change \'s with / - char *nextBs; - while(nextBs = strstr(p, "\\")){ - *nextBs = '/'; - } - - // my addon: linux doesn't handle filenames with spaces at the end nicely - p = trim(p); + // my addon: linux doesn't handle filenames with spaces at the end nicely + p = trim(p); size_t rl = 0; - - DIR *d; - if (p[0] == '/') + + DIR* d; + if (p[0] == '/' || p[0] == '\\') { d = opendir("/"); - p = p + 1; } else { d = opendir("."); - r[0] = '.'; - r[1] = 0; + out[0] = '.'; + out[1] = 0; rl = 1; } - - int last = 0; - char *c = strsep(&p, "/"); - while (c) + + bool cantProceed = false; // just convert slashes in what's left in string, not case sensitivity + bool mayBeTrailingSlash = false; + char* c; + while (c = strsep(&p, "/\\")) { - if (!d) + // May be trailing slash(allow), slash at the start(avoid), or multiple slashes(avoid) + if (*c == '\0') { - return 0; + mayBeTrailingSlash = true; + continue; + } else { + mayBeTrailingSlash = false; } - - if (last) + + out[rl] = '/'; + rl += 1; + out[rl] = 0; + + if (cantProceed) { - closedir(d); - return 0; + strcpy(out + rl, c); + rl += strlen(c); + continue; } - - r[rl] = '/'; - rl += 1; - r[rl] = 0; - - struct dirent *e = readdir(d); - while (e) + + struct dirent* e; + while (e = readdir(d)) { if (strcasecmp(c, e->d_name) == 0) { - strcpy(r + rl, e->d_name); - rl += strlen(e->d_name); + strcpy(out + rl, e->d_name); + int reportedLen = (int)strlen(e->d_name); + rl += reportedLen; + assert(reportedLen == strlen(c) && "casepath: This is not good at all"); closedir(d); - d = opendir(r); - + d = opendir(out); + + // Either it wasn't a folder, or permission error, I/O error etc. + if (!d) { + cantProceed = true; + } + break; } - - e = readdir(d); } - + if (!e) { - strcpy(r + rl, c); + printf("casepath couldn't find dir/file \"%s\", full path was %s\n", c, path); + // No match, add original name and continue converting further slashes. + strcpy(out + rl, c); rl += strlen(c); - last = 1; + cantProceed = true; } - - c = strsep(&p, "/"); } - + if (d) closedir(d); - return 1; + if (mayBeTrailingSlash) { + out[rl] = '/'; rl += 1; + out[rl] = '\0'; + } + + if (rl > l + 2) { + printf("\n\ncasepath: Corrected path length is longer then original+2:\n\tOriginal: %s (%d chars)\n\tCorrected: %s (%d chars)\n\n", path, l, out, rl); + } + return out; } #endif diff --git a/src/skel/crossplatform.h b/src/skel/crossplatform.h index 268eedff..69600385 100644 --- a/src/skel/crossplatform.h +++ b/src/skel/crossplatform.h @@ -23,7 +23,7 @@ enum eWinVersion #include "win.h" #endif extern DWORD _dwOperatingSystemVersion; - +#define fcaseopen fopen #else char *strupr(char *str); char *strlwr(char *str); @@ -43,7 +43,9 @@ enum { }; extern long _dwOperatingSystemVersion; -int casepath(char const *path, char *r); +char *casepath(char const *path, bool checkPathFirst = true); +FILE *_fcaseopen(char const *filename, char const *mode); +#define fcaseopen _fcaseopen #endif #ifdef RW_GL3 -- cgit v1.2.3