Fix casepath chaos

This commit is contained in:
eray orçunus
2020-07-26 20:59:58 +03:00
parent ef7afe5f2f
commit c87b639a84
6 changed files with 150 additions and 119 deletions

View File

@ -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;
}
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
// r must have strlen(path) + 2 bytes
int casepath(char const *path, char *r)
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)
// 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)
{
closedir(d);
return 0;
}
r[rl] = '/';
out[rl] = '/';
rl += 1;
r[rl] = 0;
struct dirent *e = readdir(d);
while (e)
out[rl] = 0;
if (cantProceed)
{
strcpy(out + rl, c);
rl += strlen(c);
continue;
}
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

View File

@ -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