about summary refs log tree commit diff stats
path: root/src/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools')
-rwxr-xr-xsrc/tools/fileutils.c129
-rwxr-xr-xsrc/tools/pathcoll.c182
-rwxr-xr-xsrc/tools/wine_tools.c107
3 files changed, 418 insertions, 0 deletions
diff --git a/src/tools/fileutils.c b/src/tools/fileutils.c
new file mode 100755
index 00000000..6a964553
--- /dev/null
+++ b/src/tools/fileutils.c
@@ -0,0 +1,129 @@
+#define _FILE_OFFSET_BITS 64
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h> 
+#include <sys/stat.h> 
+#include <unistd.h>
+#include <limits.h>
+#include <stdint.h>
+
+#ifndef MAX_PATH
+#define MAX_PATH 4096
+#endif
+
+#include "debug.h"
+#include "fileutils.h"
+
+static const char* x64sign = "\x7f" "ELF" "\x02" "\x01" "\x01" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x02" "\x00" "\x3e" "\x00";
+
+int FileExist(const char* filename, int flags)
+{
+    struct stat sb;
+    if (stat(filename, &sb) == -1)
+        return 0;
+    if(flags==-1)
+        return 1;
+    // check type of file? should be executable, or folder
+    if(flags&IS_FILE) {
+        if(!S_ISREG(sb.st_mode))
+            return 0;
+    } else if(!S_ISDIR(sb.st_mode))
+            return 0;
+    
+    if(flags&IS_EXECUTABLE) {
+        if((sb.st_mode&S_IXUSR)!=S_IXUSR)
+            return 0;   // nope
+    }
+    return 1;
+}
+
+char* ResolveFile(const char* filename, path_collection_t* paths)
+{
+    char p[MAX_PATH];
+    if(filename[0]=='/')
+        return strdup(filename);
+    for (int i=0; i<paths->size; ++i) {
+        if(paths->paths[i][0]!='/') {
+            // not an absolute path...
+            getcwd(p, sizeof(p));
+            if(p[strlen(p)-1]!='/')
+                strcat(p, "/");
+            strcat(p, paths->paths[i]);
+        } else
+            strcpy(p, paths->paths[i]);
+        strcat(p, filename);
+        if(FileExist(p, IS_FILE))
+            return realpath(p, NULL);
+    }
+
+    return NULL;
+}
+
+int FileIsX64ELF(const char* filename)
+{
+    FILE *f = fopen(filename, "rb");
+    if(!f)
+        return 0;
+    char head[sizeof(*x64sign)] = {0};
+    int sz = fread(head, sizeof(*x64sign), 1, f);
+    if(sz!=1) {
+        fclose(f);
+        return 0;
+    }
+    fclose(f);
+    if(memcmp(head, x64sign, sizeof(*x64sign))==0)
+        return 1;
+    return 0;
+}
+
+#if defined(RPI) || defined(RK3399)
+void sanitize_mojosetup_gtk_background()
+{
+    // get GTK2_RC_FILES folder
+    const char* gtk2_rc = getenv("GTK2_RC_FILES");
+    // check if $GTK2_RC_FILES/pixmaps/background.png exist
+    char background[1000] = {0};
+    strcpy(background, gtk2_rc);
+    char* p = strrchr(background, '/'); // remove "/gtkrc"
+    // every error will just silently abort
+    if(!p)
+        return;
+    *p = 0;
+    strcat(background, "/pixmaps/background.png");
+    if(!FileExist(background, IS_FILE))
+        return;
+    // now open are read the header of the PNG to grab the width and height
+    //very crude reading here!
+    FILE* f = fopen(background, "rb");
+    if(!f)
+        return;
+    char sign[8];
+    if(fread(sign, 8, 1, f)!=1) {
+        fclose(f); return;
+    }
+    const char ref[8] = {'\211', 'P', 'N', 'G', '\r', '\n', '\032', '\n' };
+    if (memcmp(sign, ref, 8)) {
+        fclose(f); return;
+    }
+    int32_t width, height;
+    fseek(f, 16, SEEK_SET);
+    if(fread(&width, sizeof(width), 1, f)!=1) {
+        fclose(f); return;
+    }
+    if(fread(&height, sizeof(height), 1, f)!=1) {
+        fclose(f); return;
+    }
+    fclose(f);
+    // need to swap bitness!
+    width = __builtin_bswap32(width);
+    height = __builtin_bswap32(height);
+    printf_log(LOG_INFO, "Mojosetup detected, size of background picture is %dx%d\n", width, height);
+    if(width!=5000 || height!=3000)
+        return; // not a background that will cause any issue
+    // delete the file!
+    f = fopen(background, "r+b");
+    remove(background);
+    printf_log(LOG_INFO, "background deleted!\n");
+}
+#endif
diff --git a/src/tools/pathcoll.c b/src/tools/pathcoll.c
new file mode 100755
index 00000000..d7e423bb
--- /dev/null
+++ b/src/tools/pathcoll.c
@@ -0,0 +1,182 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+
+#ifndef MAX_PATH
+#define MAX_PATH 4096
+#endif
+
+#include "debug.h"
+#include "pathcoll.h"
+
+void FreeCollection(path_collection_t* collection)
+{
+    if(!collection)
+        return;
+    if(collection->cap) {
+        for(int i=0; i<collection->size; ++i)
+            free(collection->paths[i]);
+        free(collection->paths);
+    }
+    collection->paths = NULL;
+    collection->size = 0;
+    collection->cap = 0;
+    return;
+}
+
+void ParseList(const char* List, path_collection_t* collection, int folder)
+{
+    if(collection->cap)
+        FreeCollection(collection);
+    // count the stings (basically count(':') + 1) to define cap
+    int cnt = 1;
+    {
+        const char* p = List;
+        while(p) {
+            p = strchr(p, ':');
+            ++cnt;
+            if(p) ++p;
+        }
+    }
+    // alloc empty strings
+    collection->cap = cnt;
+    collection->paths = (char**)calloc(cnt, sizeof(char*));
+    // and now split the paths...
+    char tmp[MAX_PATH];
+    const char *p = List;
+    int idx = 0;
+    while(p) {
+        const char *p2 = strchr(p, ':');
+        if(!p2) {
+            strncpy(tmp, p, MAX_PATH - 1);
+            p=NULL;
+        } else {
+            int l = (uintptr_t)p2 - (uintptr_t)p;
+            strncpy(tmp, p, l);
+            tmp[l]='\0';
+            p=p2+1;
+        }
+        // check if there is terminal '/', add it if not
+        int l = strlen(tmp);
+        // skip empty strings
+        if(l) {
+            if(folder && tmp[l-1]!='/')
+                strcat(tmp, "/");
+            collection->paths[idx]  =strdup(tmp);
+            collection->size=++idx;
+        }
+    }
+}
+
+void CopyCollection(path_collection_t* to, path_collection_t* from)
+{
+    to->cap = from->cap;
+    to->paths = (char**)calloc(to->cap, sizeof(char*));
+    to->size = from->size;
+    for (int i=0; i<to->size; ++i)
+        to->paths[i] = strdup(from->paths[i]);
+}
+
+void AddPath(const char* path, path_collection_t* collection, int folder)
+{
+    char tmp[MAX_PATH];
+    strcpy(tmp, path);
+    int l = strlen(tmp);
+    // skip empty strings
+    if(l) {
+        if(folder && tmp[l-1]!='/')
+            strcat(tmp, "/");
+        if(collection->size==collection->cap) {
+            collection->cap += 4;
+            collection->paths = (char**)realloc(collection->paths, collection->cap*sizeof(char*));
+        }
+        collection->paths[collection->size++]=strdup(tmp);
+    }
+}
+void PrependPath(const char* path, path_collection_t* collection, int folder)
+{
+    char tmp[MAX_PATH];
+    strcpy(tmp, path);
+    int l = strlen(tmp);
+    // skip empty strings
+    if(l) {
+        if(folder && tmp[l-1]!='/')
+            strcat(tmp, "/");
+        if(collection->size==collection->cap) {
+            collection->cap += 4;
+            collection->paths = (char**)realloc(collection->paths, collection->cap*sizeof(char*));
+        }
+        memmove(collection->paths+1, collection->paths, sizeof(char*)*collection->size);
+        collection->paths[0]=strdup(tmp);
+        ++collection->size;
+    }
+}
+
+void AppendList(path_collection_t* collection, const char* List, int folder)
+{
+    if(!List)
+        return;
+        // and now split the paths...
+    char tmp[MAX_PATH];
+    const char *p = List;
+    while(p) {
+        const char *p2 = strchr(p, ':');
+        if(!p2) {
+            strncpy(tmp, p, MAX_PATH - 1);
+            p=NULL;
+        } else {
+            int l = (uintptr_t)p2 - (uintptr_t)p;
+            strncpy(tmp, p, l);
+            tmp[l]='\0';
+            p=p2+1;
+        }
+        // check if there is terminal '/', add it if not
+        int l = strlen(tmp);
+        // skip empty strings
+        if(l) {
+            if(folder && tmp[l-1]!='/')
+                strcat(tmp, "/");
+            AddPath(tmp, collection, folder);
+        }
+    }
+
+}
+void PrependList(path_collection_t* collection, const char* List, int folder)
+{
+    if(!List)
+        return;
+        // and now split the paths...
+    char tmp[MAX_PATH];
+    char *p = strdup(List);
+    while(p) {
+        char *p2 = strrchr(p, ':');
+        if(!p2) {
+            strncpy(tmp, p, MAX_PATH - 1);
+            free(p);
+            p=NULL;
+        } else {
+            strncpy(tmp, p2+1, MAX_PATH - 1);
+            tmp[MAX_PATH - 1]='\0';
+            *p2 = '\0';
+        }
+        // check if there is terminal '/', add it if not
+        int l = strlen(tmp);
+        // skip empty strings
+        if(l) {
+            if(folder && tmp[l-1]!='/')
+                strcat(tmp, "/");
+            PrependPath(tmp, collection, folder);
+        }
+    }
+
+}
+
+int FindInCollection(const char* path, path_collection_t* collection)
+{
+    for (int i=0; i<collection->size; ++i)
+        if(strcmp(path, collection->paths[i])==0)
+            return 1;
+    return 0;
+}
diff --git a/src/tools/wine_tools.c b/src/tools/wine_tools.c
new file mode 100755
index 00000000..6fa7a47d
--- /dev/null
+++ b/src/tools/wine_tools.c
@@ -0,0 +1,107 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include "wine_tools.h"
+#include "debug.h"
+#include "box64context.h"
+
+typedef struct wine_prereserve_s
+{
+    void*   addr;
+    size_t  size;
+} wine_prereserve_t;
+
+// only the prereseve argument is reserved, not the other zone that wine-preloader reserve
+static wine_prereserve_t my_wine_reserve[] = {{(void*)0x00010000, 0x00008000}, {(void*)0x00110000, 0x30000000}, {(void*)0x7f000000, 0x03000000}, {0, 0}, {0, 0}};
+
+int wine_preloaded = 0;
+
+static int get_prereserve(const char* reserve, void** addr, size_t* size)
+{
+    if(!reserve)
+        return 0;
+    uintptr_t r = 0;
+    int first = 1;
+    while(*reserve) {
+        // numbers reading
+        if(*reserve>='0' && *reserve<='9')  r=r*16+(*reserve)-'0';
+        else if(*reserve>='A' && *reserve<='F')  r=r*16+(*reserve)-'A'+10;
+        else if(*reserve>='a' && *reserve<='f')  r=r*16+(*reserve)-'a'+10;
+        else if(*reserve=='-') {if(first) {*addr=(void*)(r&~(box64_pagesize-1)); r=0; first=0;} else {printf_log(LOG_NONE, "Warning, Wine prereserve badly formated\n"); return 0;}}
+        else {printf_log(LOG_NONE, "Warning, Wine prereserve badly formated\n"); return 0;}
+        ++reserve;
+    }
+    *size = r;
+    return 1;
+}
+
+static void add_no_overlap(void* addr, size_t size)
+{
+    int idx = 0;
+    while(my_wine_reserve[idx].addr && my_wine_reserve[idx].size) {
+        if(addr>=my_wine_reserve[idx].addr && addr<my_wine_reserve[idx].addr+my_wine_reserve[idx].size) {
+            // overlap
+            if (addr+size > my_wine_reserve[idx].addr+my_wine_reserve[idx].size)
+                // need adjust size
+                my_wine_reserve[idx].size = (intptr_t)addr-(intptr_t)my_wine_reserve[idx].addr+size;
+            return;
+        }
+        ++idx;
+    }
+    my_wine_reserve[idx].addr = addr;
+    my_wine_reserve[idx].size = size;
+}
+
+void wine_prereserve(const char* reserve)
+{
+    void* addr = NULL;
+    size_t size = 0;
+
+    if(get_prereserve(reserve, &addr, &size)) {
+        add_no_overlap(addr, size);
+    }
+
+    int idx = 0;
+    while(my_wine_reserve[idx].addr && my_wine_reserve[idx].size) {
+        void* p = mmap(my_wine_reserve[idx].addr, my_wine_reserve[idx].size, 
+                    PROT_NONE, /*MAP_FIXED |*/ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0);
+        if(p==(void*)-1 || p!=my_wine_reserve[idx].addr) {
+            printf_log(LOG_NONE, "Warning, prereserve of %p:0x%x failed (%s)\n", my_wine_reserve[idx].addr, my_wine_reserve[idx].size, strerror(errno));
+            if(p!=(void*)-1)
+                munmap(p, my_wine_reserve[idx].size);
+            my_wine_reserve[idx].addr = NULL;
+            my_wine_reserve[idx].size = 0;
+        } else {
+            printf_log(LOG_DEBUG, "WINE prereserve of %p:0x%x done\n", my_wine_reserve[idx].addr, my_wine_reserve[idx].size);
+            ++idx;
+        }
+    }
+
+    wine_preloaded = 1;
+}
+
+void* get_wine_prereserve()
+{
+    if(!wine_preloaded)
+        wine_prereserve(NULL);
+    return (void*)my_wine_reserve;
+}
+
+#ifdef DYNAREC
+void dynarec_wine_prereserve()
+{
+    #if 0
+    // disable for now, as it break some installer
+    if(!wine_preloaded)
+        wine_prereserve(NULL);
+    // don't reserve the initial arbritrary block as "with linker", it's not true
+    for(int i=1; i<sizeof(my_wine_reserve)/sizeof(my_wine_reserve[0]); ++i)
+        if(my_wine_reserve[i].addr && my_wine_reserve[i].size)
+            addDBFromAddressRange(my_context, (uintptr_t)my_wine_reserve[i].addr, my_wine_reserve[i].size, 0);  // prepare the prereserved area for exec, with linker
+    #endif
+}
+#endif