Fix casepath chaos

This commit is contained in:
eray orçunus 2020-07-26 20:59:58 +03:00
parent 98ec7bdaf9
commit eb8844fd11
6 changed files with 134 additions and 132 deletions

View File

@ -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/) // Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/)
#if !defined(_WIN32) #if !defined(_WIN32)
FILE *test = fopen(filename, "r"); char *real = casepath(filename);
if (!test) { if (real) {
char *r = (char*)alloca(strlen(filename) + 4); strcpy(m_aFilename, real);
if (casepath(filename, r)) free(real);
{
strcpy(m_aFilename, r);
}
} else { } else {
fclose(test);
#else #else
{ {
#endif #endif

View File

@ -189,10 +189,11 @@ GetGTA3ImgSize(void)
realpath(gImgNames[0], path); realpath(gImgNames[0], path);
if (stat(path, &statbuf) == -1) { if (stat(path, &statbuf) == -1) {
// Try case-insensitivity // Try case-insensitivity
char *r = (char*)alloca(strlen(gImgNames[0]) + 4); char* real = casepath(gImgNames[0], false);
if (casepath(gImgNames[0], r)) if (real)
{ {
realpath(r, path); realpath(real, path);
free(real);
if (stat(path, &statbuf) != -1) if (stat(path, &statbuf) != -1)
goto ok; goto ok;
} }
@ -210,7 +211,6 @@ CdStreamShutdown(void)
{ {
// Destroying semaphores and free(gpReadInfo) will be done at threads // Destroying semaphores and free(gpReadInfo) will be done at threads
#ifndef ONE_THREAD_PER_CHANNEL #ifndef ONE_THREAD_PER_CHANNEL
free(gChannelRequestQ.items);
gCdStreamThreadStatus = 2; gCdStreamThreadStatus = 2;
sem_post(&gCdStreamSema); sem_post(&gCdStreamSema);
#endif #endif
@ -442,6 +442,7 @@ void *CdStreamThread(void *param)
sem_destroy(&gpReadInfo[i].pDoneSemaphore); sem_destroy(&gpReadInfo[i].pDoneSemaphore);
} }
sem_destroy(&gCdStreamSema); sem_destroy(&gCdStreamSema);
free(gChannelRequestQ.items);
#else #else
sem_destroy(&gpReadInfo[channel].pStartSemaphore); sem_destroy(&gpReadInfo[channel].pStartSemaphore);
sem_destroy(&gpReadInfo[channel].pDoneSemaphore); sem_destroy(&gpReadInfo[channel].pDoneSemaphore);
@ -460,10 +461,11 @@ CdStreamAddImage(char const *path)
// Fix case sensitivity and backslashes. // Fix case sensitivity and backslashes.
if (gImgFiles[gNumImages] == -1) { if (gImgFiles[gNumImages] == -1) {
char *r = (char*)alloca(strlen(path) + 4); char* real = casepath(path, false);
if (casepath(path, r)) if (real)
{ {
gImgFiles[gNumImages] = open(r, _gdwCdStreamFlags); gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags);
free(real);
} }
} }

View File

@ -4,6 +4,7 @@
#include <direct.h> #include <direct.h>
#endif #endif
#include "common.h" #include "common.h"
#include "crossplatform.h"
#include "FileMgr.h" #include "FileMgr.h"
@ -31,19 +32,16 @@ static myFILE myfiles[NUMFILES];
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include "crossplatform.h"
#define _getcwd getcwd #define _getcwd getcwd
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen) // Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
void mychdir(char const *path) void mychdir(char const *path)
{ {
char *r = (char*)alloca(strlen(path) + 4); char* r = casepath(path, false);
if (casepath(path, r)) if (r) {
{
chdir(r); chdir(r);
} free(r);
else } else {
{
errno = ENOENT; errno = ENOENT;
} }
} }
@ -73,30 +71,7 @@ found:
*p++ = 'b'; *p++ = 'b';
*p = '\0'; *p = '\0';
#if !defined(_WIN32) myfiles[fd].file = fcaseopen(filename, realmode);
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
if(myfiles[fd].file == nil) if(myfiles[fd].file == nil)
return 0; return 0;
return fd; return fd;

View File

@ -375,23 +375,19 @@ RwStream *RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, const v
file = rwNewT(StreamFile, 1, 0); file = rwNewT(StreamFile, 1, 0);
memcpy(file, &fakefile, sizeof(StreamFile)); memcpy(file, &fakefile, sizeof(StreamFile));
#ifndef _WIN32 #ifndef _WIN32
// Be case-insensitive and fix backslashes (from https://github.com/OneSadCookie/fcaseopen/) char *r = casepath((char*)pData);
FILE* first = fopen((char*)pData, "r"); if (r) {
char *r; if (file->open((char*)r, mode)) {
if (!first) { free(r);
r = (char*)alloca(strlen((char*)pData) + 4); return file;
// Use default path(and pass error handling to librw) if we can't find any match }
if (!casepath((char*)pData, r)) free(r);
r = (char*)pData;
} else } else
fclose(first);
if(file->open((char*)r, mode))
return file;
#else
if(file->open((char*)pData, mode))
return file;
#endif #endif
{
if (file->open((char*)pData, mode))
return file;
}
rwFree(file); rwFree(file);
return nil; return nil;
} }
@ -859,15 +855,14 @@ RwImage *
RtBMPImageWrite(RwImage *image, const RwChar *imageName) RtBMPImageWrite(RwImage *image, const RwChar *imageName)
{ {
#ifndef _WIN32 #ifndef _WIN32
char *r = nil; char *r = casepath(imageName);
FILE *valid = fopen((char *)imageName, "r"); if (r) {
if(!valid) { rw::writeBMP(image, r);
char *r = (char *)alloca(strlen((char *)imageName) + 4); free(r);
// Use default path(and pass error handling to librw) if we can't find any match } else {
if(!casepath((char *)imageName, r)) r = (char *)imageName; rw::writeBMP(image, imageName);
} else }
fclose(valid);
rw::writeBMP(image, r);
#else #else
rw::writeBMP(image, imageName); rw::writeBMP(image, imageName);
#endif #endif
@ -877,15 +872,16 @@ RwImage *
RtBMPImageRead(const RwChar *imageName) RtBMPImageRead(const RwChar *imageName)
{ {
#ifndef _WIN32 #ifndef _WIN32
char *r = nil; RwImage *image;
FILE *valid = fopen((char *)imageName, "r"); char *r = casepath(imageName);
if(!valid) { if (r) {
r = (char *)alloca(strlen((char *)imageName) + 4); image = rw::readBMP(r);
// Use default path(and pass error handling to librw) if we can't find any match free(r);
if(!casepath((char *)imageName, r)) r = (char *)imageName; } else {
} else image = rw::readBMP(imageName);
fclose(valid); }
return rw::readBMP(r); return image;
#else #else
return rw::readBMP(imageName); return rw::readBMP(imageName);
#endif #endif

View File

@ -87,7 +87,7 @@ void FileTimeToSystemTime(time_t* writeTime, SYSTEMTIME* out) {
// Funcs/features from Windows that we need on other platforms // Funcs/features from Windows that we need on other platforms
#ifndef _WIN32 #ifndef _WIN32
char *strupr(char *s) { char *strupr(char *s) {
char* tmp = s; char* tmp = s;
for (;*tmp;++tmp) { for (;*tmp;++tmp) {
*tmp = toupper((unsigned char) *tmp); *tmp = toupper((unsigned char) *tmp);
@ -96,7 +96,7 @@ char *strupr(char *s) {
return s; return s;
} }
char *strlwr(char *s) { char *strlwr(char *s) {
char* tmp = s; char* tmp = s;
for (;*tmp;++tmp) { for (;*tmp;++tmp) {
*tmp = tolower((unsigned char) *tmp); *tmp = tolower((unsigned char) *tmp);
@ -116,86 +116,117 @@ char *trim(char *s) {
return s; return s;
} }
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen) FILE* _fcaseopen(char const* filename, char const* mode)
// r must have strlen(path) + 2 bytes
int casepath(char const *path, char *r)
{ {
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)
// 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); 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); strcpy(p, path);
// my addon: change \'s with / // my addon: linux doesn't handle filenames with spaces at the end nicely
char *nextBs; p = trim(p);
while(nextBs = strstr(p, "\\")){
*nextBs = '/';
}
// my addon: linux doesn't handle filenames with spaces at the end nicely
p = trim(p);
size_t rl = 0; size_t rl = 0;
DIR *d; DIR* d;
if (p[0] == '/') if (p[0] == '/' || p[0] == '\\')
{ {
d = opendir("/"); d = opendir("/");
p = p + 1;
} }
else else
{ {
d = opendir("."); d = opendir(".");
r[0] = '.'; out[0] = '.';
r[1] = 0; out[1] = 0;
rl = 1; rl = 1;
} }
int last = 0; bool cantProceed = false; // just convert slashes in what's left in string, not case sensitivity
char *c = strsep(&p, "/"); bool mayBeTrailingSlash = false;
while (c) 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] = '/';
{
closedir(d);
return 0;
}
r[rl] = '/';
rl += 1; rl += 1;
r[rl] = 0; out[rl] = 0;
struct dirent *e = readdir(d); if (cantProceed)
while (e) {
strcpy(out + rl, c);
rl += strlen(c);
continue;
}
struct dirent* e;
while (e = readdir(d))
{ {
if (strcasecmp(c, e->d_name) == 0) if (strcasecmp(c, e->d_name) == 0)
{ {
strcpy(r + rl, e->d_name); strcpy(out + rl, e->d_name);
rl += strlen(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); 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; break;
} }
e = readdir(d);
} }
if (!e) 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); rl += strlen(c);
last = 1; cantProceed = true;
} }
c = strsep(&p, "/");
} }
if (d) closedir(d); 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 #endif

View File

@ -23,7 +23,7 @@ enum eWinVersion
#include "win.h" #include "win.h"
#endif #endif
extern DWORD _dwOperatingSystemVersion; extern DWORD _dwOperatingSystemVersion;
#define fcaseopen fopen
#else #else
char *strupr(char *str); char *strupr(char *str);
char *strlwr(char *str); char *strlwr(char *str);
@ -43,7 +43,9 @@ enum {
}; };
extern long _dwOperatingSystemVersion; 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 #endif
#ifdef RW_GL3 #ifdef RW_GL3