Improved safety and reliability of the --add option

This commit is contained in:
Marc
2022-10-02 19:11:37 +02:00
parent 511a4ae352
commit bdb2f52d07
6 changed files with 135 additions and 45 deletions
-7
View File
@@ -30,13 +30,6 @@ Use --fomod <APPID> <MODID> to create a new mod using the result from the FOMod
* Fuse (2 or 3) * Fuse (2 or 3)
* Fuse-overlayfs * 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: ## TODO:
1. we need a name for this. 1. we need a name for this.
2. allow to change mod priority. 2. allow to change mod priority.
+37 -1
View File
@@ -2,8 +2,11 @@
#include <string.h> #include <string.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include "file.h"
#include <stdio.h> #include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <glib.h>
#include "file.h"
u_int32_t countSetBits(u_int32_t n) { u_int32_t countSetBits(u_int32_t n) {
// base case // base case
@@ -83,3 +86,36 @@ int move(const char * source, const char * destination) {
return returnValue; 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);
}
}
+1
View File
@@ -11,5 +11,6 @@
int copy(const char * path, const char * dest, u_int32_t flags); int copy(const char * path, const char * dest, u_int32_t flags);
int delete(const char * path, bool recursive); int delete(const char * path, bool recursive);
int move(const char * source, const char * destination); int move(const char * source, const char * destination);
void casefold(const char * folder);
#endif #endif
+78 -23
View File
@@ -2,45 +2,100 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <glib.h> #include <glib.h>
#include "install.h" #include "install.h"
#include "main.h" #include "main.h"
#include "file.h"
//TODO: replace ALL system call by execv / execl since it make my code into swiss cheese int unzip(char * path, char * outdir) {
// we can imagine a milicious fomod with a simple shell code inside. char * const args[] = {
"unzip",
"-LL", // to lowercase
"-q",
path,
"-d",
outdir,
NULL
};
int unzip(const char * path, const char * outdir) { pid_t pid = fork();
int returnValue = EXIT_SUCCESS;
char * unzipCommand = g_strconcat("/bin/sh -c 'yes | unzip \"", path, "\" -d \"" , outdir, "\" > /dev/null'", NULL); if(pid == 0) {
if(system(unzipCommand) != 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"); printf("\nFailed to decompress archive\n");
returnValue = EXIT_FAILURE; returnValue = EXIT_FAILURE;
} }
free(unzipCommand); return EXIT_SUCCESS;
return returnValue; }
} }
int unrar(const char * path, const char * outdir) { int unrar(char * path, char * outdir) {
int returnValue = EXIT_SUCCESS; char * const args[] = {
char * unrarCommand = g_strconcat("/bin/sh -c 'unrar -y x \"", path, "\" \"", outdir, "\" > /dev/null'", NULL); "unrar",
if(system(unrarCommand) != 0) { "x",
printf("Failed to decompress archive\n"); "-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; returnValue = EXIT_FAILURE;
} }
free(unrarCommand); return EXIT_SUCCESS;
return returnValue; }
} }
int un7z(const char * path, const char * outdir) {
int returnValue = EXIT_SUCCESS; int un7z(char * path, const char * outdir) {
char * un7zCommand = g_strconcat("/bin/sh -c 'yes | 7z x \"", path, "\" \"-o", outdir, "\" > /dev/null'", NULL); gchar * outParameter = g_strjoin("", "-o", outdir, NULL);
if(system(un7zCommand) != 0) {
printf("Failed to decompress archive\n"); 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; returnValue = EXIT_FAILURE;
} }
free(un7zCommand); //make everything lowercase since 7z don't have an argument for that.
return returnValue; casefold(outdir);
return EXIT_SUCCESS;
}
} }
const char * extractLastPart(const char * filePath, const char delimeter) { 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; int returnValue = EXIT_SUCCESS;
if (access(filePath, F_OK) != 0) { if (access(filePath, F_OK) != 0) {
+1 -1
View File
@@ -1,6 +1,6 @@
#ifndef __INSTALL_H__ #ifndef __INSTALL_H__
#define __INSTALL_H__ #define __INSTALL_H__
#define INSTALLED_FLAG_FILE "__DO_NOT_REMOVE__" #define INSTALLED_FLAG_FILE "__DO_NOT_REMOVE__"
int addMod(const char * filePath, int appId); int addMod(char * filePath, int appId);
#endif #endif
+14 -9
View File
@@ -345,8 +345,18 @@ int setup(int argc, char ** argv) {
//links don't conflict with overlayfs and avoid coping 17Gb of files. //links don't conflict with overlayfs and avoid coping 17Gb of files.
//but links require the files to be on the same filesystem //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); 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); 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(steamGameFolder);
free(gameFolder); free(gameFolder);
@@ -382,7 +392,7 @@ int removeMod(int argc, char ** argv) {
} }
//strtoul set EINVAL if the string is invalid //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) { if(errno == EINVAL) {
printf("Modid has to be a valid number\n"); printf("Modid has to be a valid number\n");
return EXIT_FAILURE; return EXIT_FAILURE;
@@ -423,7 +433,7 @@ int fomod(int argc, char ** argv) {
} }
//strtoul set EINVAL if the string is invalid //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) { if(errno == EINVAL) {
printf("Modid has to be a valid number\n"); printf("Modid has to be a valid number\n");
return -1; return -1;
@@ -498,11 +508,6 @@ int main(int argc, char ** argv) {
if(i < 0) { if(i < 0) {
printf("Could not create configs, check access rights for this path: %s", configFolder); 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);
} }
} }