diff --git a/README.md b/README.md index 1b4e6dc..6c3addf 100644 --- a/README.md +++ b/README.md @@ -30,13 +30,6 @@ Use --fomod to create a new mod using the result from the FOMod * Fuse (2 or 3) * Fuse-overlayfs -## instructions and warnings about casefold: -Casefold is and options in some linux filesystem that will make a folder (not the whole filesystem) case insensitive, this is really good for proton since it gives a small file lookup performance boost and allow us to install mods without fearing having two file with the same name. - -sadly i don't think overlayfs support it, but it might still be worth a try. currently i haven't tested without casefold and mods will probably break because of that. - - - ## TODO: 1. we need a name for this. 2. allow to change mod priority. diff --git a/src/file.c b/src/file.c index 2fe36a0..b4439a7 100644 --- a/src/file.c +++ b/src/file.c @@ -2,8 +2,11 @@ #include #include #include -#include "file.h" #include +#include +#include +#include +#include "file.h" u_int32_t countSetBits(u_int32_t n) { // base case @@ -83,3 +86,36 @@ int move(const char * source, const char * destination) { return returnValue; } } + + +//rename a folder and all subfolder and files to lowercase +//TODO: error handling +void casefold(const char * folder) { + DIR * d = opendir(folder); + struct dirent *dir; + if (d) { + while ((dir = readdir(d)) != NULL) { + //removes .. & . from the list + if(strcmp(dir->d_name, "..") != 0 && strcmp(dir->d_name, ".") != 0) { + //only look at ascii and hope for the best. + gchar * file = g_build_path("/", folder, dir->d_name, NULL); + + gchar * destinationName = g_ascii_strdown(dir->d_name, -1); + gchar * destination = g_build_path("/", folder,destinationName, NULL); + + int result = move(file, destination); + if(result != EXIT_SUCCESS) { + printf("Move failed: %s => %s \n", dir->d_name, destinationName); + } + g_free(destinationName); + g_free(destination); + + if(dir->d_type == DT_DIR) { + casefold(file); + } + g_free(file); + } + } + closedir(d); + } +} diff --git a/src/file.h b/src/file.h index 02e1a65..852dea6 100644 --- a/src/file.h +++ b/src/file.h @@ -11,5 +11,6 @@ int copy(const char * path, const char * dest, u_int32_t flags); int delete(const char * path, bool recursive); int move(const char * source, const char * destination); +void casefold(const char * folder); #endif diff --git a/src/install.c b/src/install.c index c54ff6d..f212610 100644 --- a/src/install.c +++ b/src/install.c @@ -2,45 +2,100 @@ #include #include #include +#include #include #include #include "install.h" #include "main.h" +#include "file.h" -//TODO: replace ALL system call by execv / execl since it make my code into swiss cheese -// we can imagine a milicious fomod with a simple shell code inside. +int unzip(char * path, char * outdir) { + char * const args[] = { + "unzip", + "-LL", // to lowercase + "-q", + path, + "-d", + outdir, + NULL + }; -int unzip(const char * path, const char * outdir) { - int returnValue = EXIT_SUCCESS; - char * unzipCommand = g_strconcat("/bin/sh -c 'yes | unzip \"", path, "\" -d \"" , outdir, "\" > /dev/null'", NULL); - if(system(unzipCommand) != 0) { - printf("\nFailed to decompress archive\n"); - returnValue = EXIT_FAILURE; + pid_t pid = fork(); + + if(pid == 0) { + execv("/usr/bin/unzip", args); + return EXIT_FAILURE; + } else { + int returnValue; + waitpid(pid, &returnValue, 0); + + if(returnValue != 0) { + printf("\nFailed to decompress archive\n"); + returnValue = EXIT_FAILURE; + } + return EXIT_SUCCESS; } - free(unzipCommand); - return returnValue; } -int unrar(const char * path, const char * outdir) { - int returnValue = EXIT_SUCCESS; - char * unrarCommand = g_strconcat("/bin/sh -c 'unrar -y x \"", path, "\" \"", outdir, "\" > /dev/null'", NULL); - if(system(unrarCommand) != 0) { - printf("Failed to decompress archive\n"); - returnValue = EXIT_FAILURE; +int unrar(char * path, char * outdir) { + char * const args[] = { + "unrar", + "x", + "-y", //assume yes + "-cl", // to lowercase + path, + outdir, + NULL + }; + + pid_t pid = fork(); + + if(pid == 0) { + execv("/usr/bin/unrar", args); + return EXIT_FAILURE; + } else { + int returnValue; + waitpid(pid, &returnValue, 0); + + if(returnValue != 0) { + printf("\nFailed to decompress archive\n"); + returnValue = EXIT_FAILURE; + } + return EXIT_SUCCESS; } - free(unrarCommand); - return returnValue; } -int un7z(const char * path, const char * outdir) { - int returnValue = EXIT_SUCCESS; - char * un7zCommand = g_strconcat("/bin/sh -c 'yes | 7z x \"", path, "\" \"-o", outdir, "\" > /dev/null'", NULL); - if(system(un7zCommand) != 0) { - printf("Failed to decompress archive\n"); - returnValue = EXIT_FAILURE; + +int un7z(char * path, const char * outdir) { + gchar * outParameter = g_strjoin("", "-o", outdir, NULL); + + char * const args[] = { + "7z", + "-y", //assume yes + "x", + path, + outParameter, + NULL + }; + + pid_t pid = fork(); + + if(pid == 0) { + execv("/usr/bin/7z", args); + return EXIT_FAILURE; + } else { + g_free(outParameter); + int returnValue; + waitpid(pid, &returnValue, 0); + + if(returnValue != 0) { + printf("\nFailed to decompress archive\n"); + returnValue = EXIT_FAILURE; + } + //make everything lowercase since 7z don't have an argument for that. + casefold(outdir); + return EXIT_SUCCESS; } - free(un7zCommand); - return returnValue; } const char * extractLastPart(const char * filePath, const char delimeter) { @@ -66,7 +121,7 @@ const char * extractFileName(const char * filePath) { } -int addMod(const char * filePath, int appId) { +int addMod(char * filePath, int appId) { int returnValue = EXIT_SUCCESS; if (access(filePath, F_OK) != 0) { diff --git a/src/install.h b/src/install.h index abaaa4e..9fb8a57 100644 --- a/src/install.h +++ b/src/install.h @@ -1,6 +1,6 @@ #ifndef __INSTALL_H__ #define __INSTALL_H__ #define INSTALLED_FLAG_FILE "__DO_NOT_REMOVE__" -int addMod(const char * filePath, int appId); +int addMod(char * filePath, int appId); #endif diff --git a/src/main.c b/src/main.c index e1d6e23..40f5c2e 100644 --- a/src/main.c +++ b/src/main.c @@ -345,8 +345,18 @@ int setup(int argc, char ** argv) { //links don't conflict with overlayfs and avoid coping 17Gb of files. //but links require the files to be on the same filesystem - const int returnValue = copy(steamGameFolder, gameFolder, CP_RECURSIVE | CP_NO_TARGET_DIR | CP_LINK); - if(returnValue < 0) copy(steamGameFolder, gameFolder, CP_RECURSIVE | CP_NO_TARGET_DIR); + int returnValue = copy(steamGameFolder, gameFolder, CP_RECURSIVE | CP_NO_TARGET_DIR | CP_LINK); + if(returnValue < 0) { + printf("Coping game files. HINT: having the game on the same partition as you home director will make this operation use zero extra space"); + returnValue = copy(steamGameFolder, gameFolder, CP_RECURSIVE | CP_NO_TARGET_DIR); + if(returnValue < 0) { + fprintf(stderr, "Copy failed make sure you have enough space on your device."); + free(steamGameFolder); + free(gameFolder); + return EXIT_FAILURE; + } + } + casefold(gameFolder); free(steamGameFolder); free(gameFolder); @@ -382,7 +392,7 @@ int removeMod(int argc, char ** argv) { } //strtoul set EINVAL if the string is invalid - u_int32_t modId = strtoul(argv[3], NULL, 10); + unsigned long modId = strtoul(argv[3], NULL, 10); if(errno == EINVAL) { printf("Modid has to be a valid number\n"); return EXIT_FAILURE; @@ -423,7 +433,7 @@ int fomod(int argc, char ** argv) { } //strtoul set EINVAL if the string is invalid - u_int32_t modId = strtoul(argv[3], NULL, 10); + unsigned long modId = strtoul(argv[3], NULL, 10); if(errno == EINVAL) { printf("Modid has to be a valid number\n"); return -1; @@ -498,11 +508,6 @@ int main(int argc, char ** argv) { if(i < 0) { printf("Could not create configs, check access rights for this path: %s", configFolder); } - //try to enable casefold - //failure would have no impact - char * chattrcommand = g_strjoin("", "chattr +F ",configFolder, " 2> /dev/null", NULL); - system(chattrcommand); - g_free(chattrcommand); } }