From 1ef69bec74a6cda8d9f2d7a82053bebc48eb89ef Mon Sep 17 00:00:00 2001 From: gion Date: Fri, 10 Jan 2020 13:14:09 +0100 Subject: [PATCH 1/5] Add missing Linux exports. --- dll/wrap.cpp | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 dll/wrap.cpp diff --git a/dll/wrap.cpp b/dll/wrap.cpp new file mode 100644 index 0000000..76dfc30 --- /dev/null +++ b/dll/wrap.cpp @@ -0,0 +1,200 @@ +/* Copyright (C) 2019 Mr Goldberg + This file is part of the Goldberg Emulator + + The Goldberg Emulator is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + The Goldberg Emulator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the Goldberg Emulator; if not, see + . */ + +#include "dll.h" + +#ifdef STEAM_WIN32 +// Nothing to be done here +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +STEAMAPI_API FILE *__wrap_freopen(const char *pathname, const char *mode, FILE *stream) +{ + return freopen(pathname, mode, stream); +} + +STEAMAPI_API FILE *__wrap_fopen(const char *filename, const char *mode) +{ + return fopen(filename, mode); +} + +STEAMAPI_API FILE *__wrap_fopen64(const char *filename, const char *mode) +{ + return fopen64(filename, mode); +} + +STEAMAPI_API int __wrap_open(const char *pathname, int flags, mode_t mode) +{ + return open(pathname, flags, mode); +} + +STEAMAPI_API int __wrap_open64(const char *pathname, int flags, mode_t mode) +{ + return open64(pathname, flags, mode); +} + +STEAMAPI_API int __wrap_access(const char *pathname, int mode) +{ + return access(pathname, mode); +} + +STEAMAPI_API int __wrap___xstat(int ver, const char * path, struct stat * stat_buf) +{ + return __xstat(ver, path, stat_buf); +} + +STEAMAPI_API int __wrap_stat(const char * path, struct stat * stat_buf) +{ + return __wrap___xstat(3, path, stat_buf); +} + +STEAMAPI_API int __wrap___lxstat(int ver, const char * path, struct stat * stat_buf) +{ + return __lxstat(ver, path, stat_buf); +} + +STEAMAPI_API int __wrap_lstat(const char * path, struct stat * stat_buf) +{ + return __wrap___lxstat(3, path, stat_buf); +} + +STEAMAPI_API int __wrap_scandir(const char *dir, struct dirent ***namelist, int (*sel)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)) +{ + return scandir(dir, namelist, sel, compar); +} + +STEAMAPI_API int __wrap_scandir64(const char *dir, struct dirent64 ***namelist, int (*sel)(const struct dirent64 *), int (*compar)(const struct dirent64 **, const struct dirent64 **)) +{ + return scandir64(dir, namelist, sel, compar); +} + +STEAMAPI_API DIR *__wrap_opendir(const char *name) +{ + return opendir(name); +} + +STEAMAPI_API int __wrap___xstat64(int vers, const char *name, struct stat64 *buf) +{ + return __xstat64(vers, name, buf); +} + +STEAMAPI_API int __wrap___lxstat64(int vers, const char *name, struct stat64 *buf) +{ + return __lxstat64(vers, name, buf); +} + +STEAMAPI_API int __wrap_statvfs(const char *path, struct statvfs *buf) +{ + return statvfs(path, buf); +} + +STEAMAPI_API int __wrap_statvfs64(const char *path, struct statvfs64 *buf) +{ + return statvfs64(path, buf); +} + +STEAMAPI_API int __wrap_chmod(const char *pathname, mode_t mode) +{ + return chmod(pathname, mode); +} + +STEAMAPI_API int __wrap_chown(const char *path, uid_t owner, gid_t group) +{ + return chown(path, owner, group); +} + +STEAMAPI_API int __wrap_lchown(const char *path, uid_t owner, gid_t group) +{ + return lchown(path, owner, group); +} + +STEAMAPI_API int __wrap_symlink(const char *path1, const char *path2) +{ + return symlink(path1, path2); +} + +STEAMAPI_API int __wrap_link(const char *path1, const char *path2) +{ + return link(path1, path2); +} + +STEAMAPI_API int __wrap_mknod(const char *path, mode_t mode, dev_t dev) +{ + return __xmknod(1, path, mode, &dev); +} + +STEAMAPI_API int __wrap_mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data) +{ + return mount(source, target, filesystemtype, mountflags, data); +} + +STEAMAPI_API int __wrap_unlink(const char *path) +{ + return unlink(path); +} + +STEAMAPI_API int __wrap_mkfifo(const char *path, mode_t mode) +{ + return mkfifo(path, mode); +} + +STEAMAPI_API int __wrap_rename(const char *old_name, const char *new_name) +{ + return rename(old_name, new_name); +} + +STEAMAPI_API int __wrap_utime(const char *path, const struct utimbuf *times) +{ + return utime(path, times); +} + +STEAMAPI_API int __wrap_utimes(const char *path, const struct timeval times[2]) +{ + return utimes(path, times); +} + +STEAMAPI_API int __wrap_mkdir(const char *path, mode_t mode) +{ + return mkdir(path, mode); +} + +STEAMAPI_API int __wrap_rmdir(const char *path) +{ + return rmdir(path); +} + +STEAMAPI_API void * __wrap_dlopen(const char *file, int mode) +{ + return dlopen(file, mode); +} + +STEAMAPI_API void * __wrap_dlmopen(Lmid_t lmid, const char *filename, int flags) +{ + return dlmopen(lmid, filename, flags); +} + +#endif \ No newline at end of file From a0447b930f44e2bf493a1b53b9eaa08c86bf19fd Mon Sep 17 00:00:00 2001 From: gion Date: Fri, 10 Jan 2020 14:35:36 +0100 Subject: [PATCH 2/5] Fix Linux build. --- CMakeLists.txt | 1 + build_steamos.sh | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aa2c057..190dadc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,6 +230,7 @@ target_link_libraries(${BIN_LOBBY_CONNECT} $<$:ws2_32> $<$:iphlpapi> $<$:comdlg32> + ${CMAKE_DL_LIBS} -debug:none ) diff --git a/build_steamos.sh b/build_steamos.sh index ef0423e..213e7c2 100755 --- a/build_steamos.sh +++ b/build_steamos.sh @@ -8,9 +8,9 @@ cp scripts/find_interfaces.sh linux/tools/ cp scripts/steamclient_loader.sh linux/tools/ ../protobuf/prefix_x86/bin/protoc -I./dll/ --cpp_out=./dll/ ./dll/*.proto g++ -m32 -shared -fPIC -fvisibility=hidden -Wl,--exclude-libs,ALL -DGNUC -DEMU_RELEASE_BUILD -DNDEBUG -s -o linux/x86/libsteam_api.so dll/*.cpp dll/*.cc -Wno-return-type -I../protobuf/prefix_x86/include/ -L../protobuf/prefix_x86/lib/ -lprotobuf-lite -std=c++11 && echo built32 -g++ -m32 -fvisibility=hidden -Wl,--exclude-libs,ALL -DGNUC -DEMU_RELEASE_BUILD -DNDEBUG -DNO_DISK_WRITES -DLOBBY_CONNECT -s -o linux/lobby_connect/lobby_connect_x86 lobby_connect.cpp dll/*.cpp dll/*.cc -Wno-return-type -I../protobuf/prefix_x86/include/ -L../protobuf/prefix_x86/lib/ -lprotobuf-lite -lpthread -std=c++11 && echo built_lobby_connect32 +g++ -m32 -fvisibility=hidden -Wl,--exclude-libs,ALL -DGNUC -DEMU_RELEASE_BUILD -DNDEBUG -DNO_DISK_WRITES -DLOBBY_CONNECT -s -o linux/lobby_connect/lobby_connect_x86 lobby_connect.cpp dll/*.cpp dll/*.cc -Wno-return-type -I../protobuf/prefix_x86/include/ -L../protobuf/prefix_x86/lib/ -lprotobuf-lite -lpthread -ldl -std=c++11 && echo built_lobby_connect32 g++ -m32 -shared -fPIC -fvisibility=hidden -Wl,--exclude-libs,ALL -DGNUC -DEMU_RELEASE_BUILD -DSTEAMCLIENT_DLL -DNDEBUG -s -o linux/x86/steamclient.so dll/*.cpp dll/*.cc -Wno-return-type -I../protobuf/prefix_x86/include/ -L../protobuf/prefix_x86/lib/ -lprotobuf-lite -std=c++11 && echo built32_steamclient ../protobuf/prefix/bin/protoc -I./dll/ --cpp_out=./dll/ ./dll/*.proto g++ -shared -fPIC -fvisibility=hidden -Wl,--exclude-libs,ALL -DGNUC -DEMU_RELEASE_BUILD -DNDEBUG -s -o linux/x86_64/libsteam_api.so dll/*.cpp dll/*.cc -Wno-return-type -I../protobuf/prefix/include/ -L../protobuf/prefix/lib/ -lprotobuf-lite -std=c++11 && echo built64 -g++ -fvisibility=hidden -Wl,--exclude-libs,ALL -DGNUC -DEMU_RELEASE_BUILD -DNDEBUG -DNO_DISK_WRITES -DLOBBY_CONNECT -s -o linux/lobby_connect/lobby_connect_x64 lobby_connect.cpp dll/*.cpp dll/*.cc -Wno-return-type -I../protobuf/prefix/include/ -L../protobuf/prefix/lib/ -lprotobuf-lite -lpthread -std=c++11 && echo built_lobby_connect64 +g++ -fvisibility=hidden -Wl,--exclude-libs,ALL -DGNUC -DEMU_RELEASE_BUILD -DNDEBUG -DNO_DISK_WRITES -DLOBBY_CONNECT -s -o linux/lobby_connect/lobby_connect_x64 lobby_connect.cpp dll/*.cpp dll/*.cc -Wno-return-type -I../protobuf/prefix/include/ -L../protobuf/prefix/lib/ -lprotobuf-lite -lpthread -ldl -std=c++11 && echo built_lobby_connect64 g++ -shared -fPIC -fvisibility=hidden -Wl,--exclude-libs,ALL -DGNUC -DEMU_RELEASE_BUILD -DSTEAMCLIENT_DLL -DNDEBUG -s -o linux/x86_64/steamclient.so dll/*.cpp dll/*.cc -Wno-return-type -I../protobuf/prefix/include/ -L../protobuf/prefix/lib/ -lprotobuf-lite -std=c++11 && echo built64_steamclient From 86d7806f27aaa93283fc335cd5849f6d5f7ed71d Mon Sep 17 00:00:00 2001 From: gion Date: Wed, 15 Jan 2020 20:37:41 +0100 Subject: [PATCH 3/5] Implement case insensitive filesystem access. --- dll/wrap.cpp | 390 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 342 insertions(+), 48 deletions(-) diff --git a/dll/wrap.cpp b/dll/wrap.cpp index 76dfc30..e43b194 100644 --- a/dll/wrap.cpp +++ b/dll/wrap.cpp @@ -15,6 +15,7 @@ License along with the Goldberg Emulator; if not, see . */ +#include "base.h" #include "dll.h" #ifdef STEAM_WIN32 @@ -32,169 +33,462 @@ #include #include -STEAMAPI_API FILE *__wrap_freopen(const char *pathname, const char *mode, FILE *stream) +#define PATH_SEPARATOR_CHAR '/' +#define STEAM_PATH_CACHE_SIZE 4096 + +const char *STEAM_PATH; +size_t STEAM_PATH_SIZE; + +const char *get_steam_path() { - return freopen(pathname, mode, stream); + char *home_path = getenv("HOME"); + char steam_path[STEAM_PATH_CACHE_SIZE]; + char *steam_realpath = nullptr; + + // Build steam_path from home + int required_size = snprintf(steam_path, STEAM_PATH_CACHE_SIZE, "%s/.steam/steam", home_path); + + // Allocate more space for steam_path if needed (required_size does not count terminator) + if (required_size > 0 && required_size >= STEAM_PATH_CACHE_SIZE) { + char *large_steam_path = (char *)malloc(sizeof(char) * (required_size + 1)); + int check_size = snprintf(steam_path, required_size + 1, "%s/.steam/steam", home_path); + // Check that path fits this time + if (check_size == required_size) { + steam_realpath = realpath(large_steam_path, nullptr); + } + free(large_steam_path); + } else { + steam_realpath = realpath(steam_path, nullptr); + } + + // Terminate path with a file separator + if (steam_realpath && *steam_realpath) { + size_t path_size = strlen(steam_realpath); + if (steam_realpath[path_size - 1] != PATH_SEPARATOR_CHAR) { + steam_realpath = (char *)realloc(steam_realpath, path_size + 2); + steam_realpath[path_size] = PATH_SEPARATOR_CHAR; + steam_realpath[path_size + 1] = 0; + } + } else { + // Failsafe to root + steam_realpath = strdup("/"); + } + + return steam_realpath; } -STEAMAPI_API FILE *__wrap_fopen(const char *filename, const char *mode) + +bool match_path(char *path, int start, bool accept_same_case) { - return fopen(filename, mode); + if (!path[start + 1]) { + return true; + } + + // Snap to the next separator in path + int separator = start + 1; + while (path[separator] != PATH_SEPARATOR_CHAR && path[separator]) { + separator++; + } + + bool is_last_component = path[separator] != PATH_SEPARATOR_CHAR; + + char stored_char = path[separator]; + path[separator] = 0; + bool path_accessible = access(path, 0) == 0; + path[separator] = stored_char; + + if (!path_accessible || !is_last_component && !match_path(path, separator, accept_same_case)) { + DIR *current_directory = nullptr; + int component = start + 1; + + if (start) { + stored_char = path[start]; + path[start] = 0; + current_directory = opendir(path); + path[start] = stored_char; + component = start + 1; + } else { + if (*path == PATH_SEPARATOR_CHAR) { + component = start + 1; + current_directory = opendir("/"); + } else { + component = start; + current_directory = opendir("."); + } + } + + // 0123456789012345678901234567890123456789 + // path = /this/is/a/sample/path/to/file.txt + // ^^ ^ + // ab c + // a. start = 10 + // b. component = 11 + // c. separator = 17 + // current_directory = /this/is/a/ + + if (current_directory) { + dirent64 *entry = (dirent64 *)readdir64(current_directory); + while (entry) { + const char *entry_name = entry->d_name; + stored_char = path[separator]; + path[separator] = 0; + + // Fix current component if entry with similar name exists + if (!strcasecmp(&path[component], entry_name)) { + bool case_differs = strcmp(&path[component], entry_name) != 0; + path[separator] = stored_char; + if (case_differs) { + char *iterator = &path[component]; + // Replace with entry name + while (*entry_name != PATH_SEPARATOR_CHAR && *entry_name) { + *(iterator++) = *(entry_name++); + } + // Fix next component + if (is_last_component || match_path(path, separator, accept_same_case)) { + closedir(current_directory); + return true; + } + } + } else { + path[separator] = stored_char; + } + entry = (dirent64 *)readdir64(current_directory); + } + } + + if (current_directory) { + closedir(current_directory); + } + + return accept_same_case && is_last_component; + } + + return true; } -STEAMAPI_API FILE *__wrap_fopen64(const char *filename, const char *mode) +const char *lowercase_path(const char *path, bool accept_same_case, bool stop_at_separator) { - return fopen64(filename, mode); + std::locale loc; + char *path_lowercased = nullptr; + + if (path && *path) { + if (access(path, 0)) { + // Make a copy of the path on which to work on + path_lowercased = strdup(path); + if (!path_lowercased) { + return nullptr; + } + // Load steam path if not done already + if (!STEAM_PATH) { + STEAM_PATH = get_steam_path(); + STEAM_PATH_SIZE = strlen(STEAM_PATH); + } + + char *lowercase_iterator = path_lowercased; + // Lowercase whole steam path if possible + if (!strncasecmp(path_lowercased, STEAM_PATH, STEAM_PATH_SIZE)) { + memcpy(path_lowercased, STEAM_PATH, STEAM_PATH_SIZE); + lowercase_iterator = &path_lowercased[STEAM_PATH_SIZE - 1]; + } + // Lowercase rest of the path + char *iterator = lowercase_iterator; + while ((!stop_at_separator || *iterator != PATH_SEPARATOR_CHAR) && *iterator) { + *iterator = std::tolower(*iterator, loc); + iterator++; + } + + // Check if we can access the lowered-case path + int error = access(path_lowercased, 0); + if (!error) { + // The new path is valid + return path_lowercased; + } else { + if (accept_same_case) { + const char *name_iterator = &path[lowercase_iterator - path_lowercased]; + while (*lowercase_iterator) { + *(lowercase_iterator++) = *(name_iterator++); + } + } + // Retry accesing the file again and tweak the path if needed + if (match_path(path_lowercased, STEAM_PATH_SIZE - 1, accept_same_case)) { + return path_lowercased; + } + } + } + } + + return path; } -STEAMAPI_API int __wrap_open(const char *pathname, int flags, mode_t mode) +STEAMAPI_API FILE *__wrap_freopen(const char *path, const char *modes, FILE *stream) { - return open(pathname, flags, mode); + bool is_writable = strpbrk(modes, "wa+") != 0; + const char *path_lowercased = lowercase_path(path, is_writable, true); + FILE *result = freopen(path_lowercased, modes, stream); + free((void *)path_lowercased); + return result; } -STEAMAPI_API int __wrap_open64(const char *pathname, int flags, mode_t mode) +STEAMAPI_API FILE *__wrap_fopen(const char *path, const char *modes) { - return open64(pathname, flags, mode); + bool is_writable = strpbrk(modes, "wa+") != 0; + const char *path_lowercased = lowercase_path(path, is_writable, true); + FILE *result = fopen(path_lowercased, modes); + free((void *)path_lowercased); + return result; } -STEAMAPI_API int __wrap_access(const char *pathname, int mode) +STEAMAPI_API FILE *__wrap_fopen64(const char *path, const char *modes) { - return access(pathname, mode); + bool is_writable = strpbrk(modes, "wa+") != 0; + const char *path_lowercased = lowercase_path(path, is_writable, true); + FILE *result = fopen64(path_lowercased, modes); + free((void *)path_lowercased); + return result; +} + +STEAMAPI_API int __wrap_open(const char *path, int flags, mode_t mode) +{ + bool is_writable = flags & 3; + const char *path_lowercased = lowercase_path(path, is_writable, true); + int result = open(path_lowercased, flags, mode); + free((void *)path_lowercased); + return result; +} + +STEAMAPI_API int __wrap_open64(const char *path, int flags, mode_t mode) +{ + bool is_writable = flags & 3; + const char *path_lowercased = lowercase_path(path, is_writable, true); + int result = open64(path_lowercased, flags, mode); + free((void *)path_lowercased); + return result; +} + +STEAMAPI_API int __wrap_access(const char *path, int mode) +{ + const char *path_lowercased = lowercase_path(path, false, false); + int result = access(path_lowercased, mode); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap___xstat(int ver, const char * path, struct stat * stat_buf) { - return __xstat(ver, path, stat_buf); + const char *path_lowercased = lowercase_path(path, false, false); + int result = __xstat(ver, path_lowercased, stat_buf); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_stat(const char * path, struct stat * stat_buf) { - return __wrap___xstat(3, path, stat_buf); + return __wrap___xstat(3, path, stat_buf); } STEAMAPI_API int __wrap___lxstat(int ver, const char * path, struct stat * stat_buf) { - return __lxstat(ver, path, stat_buf); + const char *path_lowercased = lowercase_path(path, false, false); + int result = __lxstat(ver, path_lowercased, stat_buf); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_lstat(const char * path, struct stat * stat_buf) { - return __wrap___lxstat(3, path, stat_buf); + return __wrap___lxstat(3, path, stat_buf); } -STEAMAPI_API int __wrap_scandir(const char *dir, struct dirent ***namelist, int (*sel)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)) +STEAMAPI_API int __wrap_scandir(const char *path, struct dirent ***namelist, int (*sel)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)) { - return scandir(dir, namelist, sel, compar); + const char *path_lowercased = lowercase_path(path, false, false); + int result = scandir(path_lowercased, namelist, sel, compar); + free((void *)path_lowercased); + return result; } -STEAMAPI_API int __wrap_scandir64(const char *dir, struct dirent64 ***namelist, int (*sel)(const struct dirent64 *), int (*compar)(const struct dirent64 **, const struct dirent64 **)) +STEAMAPI_API int __wrap_scandir64(const char *path, struct dirent64 ***namelist, int (*sel)(const struct dirent64 *), int (*compar)(const struct dirent64 **, const struct dirent64 **)) { - return scandir64(dir, namelist, sel, compar); + const char *path_lowercased = lowercase_path(path, false, false); + int result = scandir64(path_lowercased, namelist, sel, compar); + free((void *)path_lowercased); + return result; } -STEAMAPI_API DIR *__wrap_opendir(const char *name) +STEAMAPI_API DIR *__wrap_opendir(const char *path) { - return opendir(name); + const char *path_lowercased = lowercase_path(path, false, false); + DIR *result = opendir(path_lowercased); + free((void *)path_lowercased); + return result; } -STEAMAPI_API int __wrap___xstat64(int vers, const char *name, struct stat64 *buf) +STEAMAPI_API int __wrap___xstat64(int ver, const char *path, struct stat64 *stat_buf) { - return __xstat64(vers, name, buf); + const char *path_lowercased = lowercase_path(path, false, false); + int result = __xstat64(ver, path_lowercased, stat_buf); + free((void *)path_lowercased); + return result; } -STEAMAPI_API int __wrap___lxstat64(int vers, const char *name, struct stat64 *buf) +STEAMAPI_API int __wrap___lxstat64(int ver, const char *path, struct stat64 *stat_buf) { - return __lxstat64(vers, name, buf); + const char *path_lowercased = lowercase_path(path, false, false); + int result = __lxstat64(ver, path_lowercased, stat_buf); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_statvfs(const char *path, struct statvfs *buf) { - return statvfs(path, buf); + const char *path_lowercased = lowercase_path(path, false, false); + int result = statvfs(path_lowercased, buf); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_statvfs64(const char *path, struct statvfs64 *buf) { - return statvfs64(path, buf); + const char *path_lowercased = lowercase_path(path, false, false); + int result = statvfs64(path_lowercased, buf); + free((void *)path_lowercased); + return result; } -STEAMAPI_API int __wrap_chmod(const char *pathname, mode_t mode) +STEAMAPI_API int __wrap_chmod(const char *path, mode_t mode) { - return chmod(pathname, mode); + const char *path_lowercased = lowercase_path(path, false, false); + int result = chmod(path_lowercased, mode); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_chown(const char *path, uid_t owner, gid_t group) { - return chown(path, owner, group); + const char *path_lowercased = lowercase_path(path, false, false); + int result = chown(path_lowercased, owner, group); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_lchown(const char *path, uid_t owner, gid_t group) { - return lchown(path, owner, group); + const char *path_lowercased = lowercase_path(path, false, false); + int result = lchown(path_lowercased, owner, group); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_symlink(const char *path1, const char *path2) { - return symlink(path1, path2); + const char *path_lowercased1 = lowercase_path(path1, true, true); + const char *path_lowercased2 = lowercase_path(path2, false, false); + int result = symlink(path_lowercased1, path_lowercased2); + free((void *)path_lowercased1); + free((void *)path_lowercased2); + return result; } STEAMAPI_API int __wrap_link(const char *path1, const char *path2) { - return link(path1, path2); + const char *path_lowercased1 = lowercase_path(path1, true, true); + const char *path_lowercased2 = lowercase_path(path2, false, false); + int result = link(path_lowercased1, path_lowercased2); + free((void *)path_lowercased1); + free((void *)path_lowercased2); + return result; } STEAMAPI_API int __wrap_mknod(const char *path, mode_t mode, dev_t dev) { - return __xmknod(1, path, mode, &dev); + const char *path_lowercased = lowercase_path(path, true, true); + int result = __xmknod(1, path_lowercased, mode, &dev); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data) { - return mount(source, target, filesystemtype, mountflags, data); + const char *source_lowercased = lowercase_path(source, false, false); + const char *target_lowercased = lowercase_path(target, false, false); + int result = mount(source_lowercased, target_lowercased, filesystemtype, mountflags, data); + free((void *)source_lowercased); + free((void *)target_lowercased); + return result; } STEAMAPI_API int __wrap_unlink(const char *path) { - return unlink(path); + const char *path_lowercased = lowercase_path(path, false, false); + int result = unlink(path); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_mkfifo(const char *path, mode_t mode) { - return mkfifo(path, mode); + const char *path_lowercased = lowercase_path(path, true, true); + int result = mkfifo(path, mode); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_rename(const char *old_name, const char *new_name) { - return rename(old_name, new_name); + const char *old_name_lowercased = lowercase_path(old_name, true, true); + const char *new_name_lowercased = lowercase_path(new_name, false, false); + int result = rename(old_name_lowercased, new_name_lowercased); + free((void *)old_name_lowercased); + free((void *)new_name_lowercased); + return result; } STEAMAPI_API int __wrap_utime(const char *path, const struct utimbuf *times) { - return utime(path, times); + const char *path_lowercased = lowercase_path(path, false, false); + int result = utime(path_lowercased, times); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_utimes(const char *path, const struct timeval times[2]) { - return utimes(path, times); + const char *path_lowercased = lowercase_path(path, false, false); + int result = utimes(path_lowercased, times); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_mkdir(const char *path, mode_t mode) { - return mkdir(path, mode); + const char *path_lowercased = lowercase_path(path, true, true); + int result = mkdir(path_lowercased, mode); + free((void *)path_lowercased); + return result; } STEAMAPI_API int __wrap_rmdir(const char *path) { - return rmdir(path); + const char *path_lowercased = lowercase_path(path, false, false); + int result = rmdir(path_lowercased); + free((void *)path_lowercased); + return result; } -STEAMAPI_API void * __wrap_dlopen(const char *file, int mode) +STEAMAPI_API void *__wrap_dlopen(const char *path, int mode) { - return dlopen(file, mode); + const char *path_lowercased = lowercase_path(path, false, false); + void * result = dlopen(path_lowercased, mode); + free((void *)path_lowercased); + return result; } -STEAMAPI_API void * __wrap_dlmopen(Lmid_t lmid, const char *filename, int flags) +STEAMAPI_API void *__wrap_dlmopen(Lmid_t lmid, const char *path, int flags) { - return dlmopen(lmid, filename, flags); + const char *path_lowercased = lowercase_path(path, false, false); + void * result = dlmopen(lmid, path_lowercased, flags); + free((void *)path_lowercased); + return result; } -#endif \ No newline at end of file +#endif From d1b901a49129967a4a16d5a18b8f32b0748e5daa Mon Sep 17 00:00:00 2001 From: gion Date: Thu, 16 Jan 2020 00:55:38 +0100 Subject: [PATCH 4/5] Ops, too many frees. --- dll/wrap.cpp | 142 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 106 insertions(+), 36 deletions(-) diff --git a/dll/wrap.cpp b/dll/wrap.cpp index e43b194..e192d98 100644 --- a/dll/wrap.cpp +++ b/dll/wrap.cpp @@ -97,7 +97,7 @@ bool match_path(char *path, int start, bool accept_same_case) bool path_accessible = access(path, 0) == 0; path[separator] = stored_char; - if (!path_accessible || !is_last_component && !match_path(path, separator, accept_same_case)) { + if (!path_accessible || (!is_last_component && !match_path(path, separator, accept_same_case))) { DIR *current_directory = nullptr; int component = start + 1; @@ -225,7 +225,9 @@ STEAMAPI_API FILE *__wrap_freopen(const char *path, const char *modes, FILE *str bool is_writable = strpbrk(modes, "wa+") != 0; const char *path_lowercased = lowercase_path(path, is_writable, true); FILE *result = freopen(path_lowercased, modes, stream); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -234,7 +236,9 @@ STEAMAPI_API FILE *__wrap_fopen(const char *path, const char *modes) bool is_writable = strpbrk(modes, "wa+") != 0; const char *path_lowercased = lowercase_path(path, is_writable, true); FILE *result = fopen(path_lowercased, modes); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -243,7 +247,9 @@ STEAMAPI_API FILE *__wrap_fopen64(const char *path, const char *modes) bool is_writable = strpbrk(modes, "wa+") != 0; const char *path_lowercased = lowercase_path(path, is_writable, true); FILE *result = fopen64(path_lowercased, modes); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -252,7 +258,9 @@ STEAMAPI_API int __wrap_open(const char *path, int flags, mode_t mode) bool is_writable = flags & 3; const char *path_lowercased = lowercase_path(path, is_writable, true); int result = open(path_lowercased, flags, mode); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -261,7 +269,9 @@ STEAMAPI_API int __wrap_open64(const char *path, int flags, mode_t mode) bool is_writable = flags & 3; const char *path_lowercased = lowercase_path(path, is_writable, true); int result = open64(path_lowercased, flags, mode); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -269,7 +279,9 @@ STEAMAPI_API int __wrap_access(const char *path, int mode) { const char *path_lowercased = lowercase_path(path, false, false); int result = access(path_lowercased, mode); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -277,7 +289,9 @@ STEAMAPI_API int __wrap___xstat(int ver, const char * path, struct stat * stat_b { const char *path_lowercased = lowercase_path(path, false, false); int result = __xstat(ver, path_lowercased, stat_buf); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -290,7 +304,9 @@ STEAMAPI_API int __wrap___lxstat(int ver, const char * path, struct stat * stat_ { const char *path_lowercased = lowercase_path(path, false, false); int result = __lxstat(ver, path_lowercased, stat_buf); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -303,7 +319,9 @@ STEAMAPI_API int __wrap_scandir(const char *path, struct dirent ***namelist, int { const char *path_lowercased = lowercase_path(path, false, false); int result = scandir(path_lowercased, namelist, sel, compar); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -311,7 +329,9 @@ STEAMAPI_API int __wrap_scandir64(const char *path, struct dirent64 ***namelist, { const char *path_lowercased = lowercase_path(path, false, false); int result = scandir64(path_lowercased, namelist, sel, compar); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -319,7 +339,9 @@ STEAMAPI_API DIR *__wrap_opendir(const char *path) { const char *path_lowercased = lowercase_path(path, false, false); DIR *result = opendir(path_lowercased); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -327,7 +349,9 @@ STEAMAPI_API int __wrap___xstat64(int ver, const char *path, struct stat64 *stat { const char *path_lowercased = lowercase_path(path, false, false); int result = __xstat64(ver, path_lowercased, stat_buf); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -335,7 +359,9 @@ STEAMAPI_API int __wrap___lxstat64(int ver, const char *path, struct stat64 *sta { const char *path_lowercased = lowercase_path(path, false, false); int result = __lxstat64(ver, path_lowercased, stat_buf); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -343,7 +369,9 @@ STEAMAPI_API int __wrap_statvfs(const char *path, struct statvfs *buf) { const char *path_lowercased = lowercase_path(path, false, false); int result = statvfs(path_lowercased, buf); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -351,7 +379,9 @@ STEAMAPI_API int __wrap_statvfs64(const char *path, struct statvfs64 *buf) { const char *path_lowercased = lowercase_path(path, false, false); int result = statvfs64(path_lowercased, buf); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -359,7 +389,9 @@ STEAMAPI_API int __wrap_chmod(const char *path, mode_t mode) { const char *path_lowercased = lowercase_path(path, false, false); int result = chmod(path_lowercased, mode); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -367,7 +399,9 @@ STEAMAPI_API int __wrap_chown(const char *path, uid_t owner, gid_t group) { const char *path_lowercased = lowercase_path(path, false, false); int result = chown(path_lowercased, owner, group); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -375,7 +409,9 @@ STEAMAPI_API int __wrap_lchown(const char *path, uid_t owner, gid_t group) { const char *path_lowercased = lowercase_path(path, false, false); int result = lchown(path_lowercased, owner, group); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -384,8 +420,12 @@ STEAMAPI_API int __wrap_symlink(const char *path1, const char *path2) const char *path_lowercased1 = lowercase_path(path1, true, true); const char *path_lowercased2 = lowercase_path(path2, false, false); int result = symlink(path_lowercased1, path_lowercased2); - free((void *)path_lowercased1); - free((void *)path_lowercased2); + if (path_lowercased1 != path1) { + free((void *)path_lowercased1); + } + if (path_lowercased2 != path2) { + free((void *)path_lowercased2); + } return result; } @@ -394,8 +434,12 @@ STEAMAPI_API int __wrap_link(const char *path1, const char *path2) const char *path_lowercased1 = lowercase_path(path1, true, true); const char *path_lowercased2 = lowercase_path(path2, false, false); int result = link(path_lowercased1, path_lowercased2); - free((void *)path_lowercased1); - free((void *)path_lowercased2); + if (path_lowercased1 != path1) { + free((void *)path_lowercased1); + } + if (path_lowercased2 != path2) { + free((void *)path_lowercased2); + } return result; } @@ -403,7 +447,9 @@ STEAMAPI_API int __wrap_mknod(const char *path, mode_t mode, dev_t dev) { const char *path_lowercased = lowercase_path(path, true, true); int result = __xmknod(1, path_lowercased, mode, &dev); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -412,8 +458,12 @@ STEAMAPI_API int __wrap_mount(const char *source, const char *target, const char const char *source_lowercased = lowercase_path(source, false, false); const char *target_lowercased = lowercase_path(target, false, false); int result = mount(source_lowercased, target_lowercased, filesystemtype, mountflags, data); - free((void *)source_lowercased); - free((void *)target_lowercased); + if (source_lowercased != source) { + free((void *)source_lowercased); + } + if (target_lowercased != target) { + free((void *)target_lowercased); + } return result; } @@ -421,7 +471,9 @@ STEAMAPI_API int __wrap_unlink(const char *path) { const char *path_lowercased = lowercase_path(path, false, false); int result = unlink(path); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -429,7 +481,9 @@ STEAMAPI_API int __wrap_mkfifo(const char *path, mode_t mode) { const char *path_lowercased = lowercase_path(path, true, true); int result = mkfifo(path, mode); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -438,8 +492,12 @@ STEAMAPI_API int __wrap_rename(const char *old_name, const char *new_name) const char *old_name_lowercased = lowercase_path(old_name, true, true); const char *new_name_lowercased = lowercase_path(new_name, false, false); int result = rename(old_name_lowercased, new_name_lowercased); - free((void *)old_name_lowercased); - free((void *)new_name_lowercased); + if (old_name_lowercased != old_name) { + free((void *)old_name_lowercased); + } + if (new_name_lowercased != new_name) { + free((void *)new_name_lowercased); + } return result; } @@ -447,7 +505,9 @@ STEAMAPI_API int __wrap_utime(const char *path, const struct utimbuf *times) { const char *path_lowercased = lowercase_path(path, false, false); int result = utime(path_lowercased, times); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -455,7 +515,9 @@ STEAMAPI_API int __wrap_utimes(const char *path, const struct timeval times[2]) { const char *path_lowercased = lowercase_path(path, false, false); int result = utimes(path_lowercased, times); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -463,7 +525,9 @@ STEAMAPI_API int __wrap_mkdir(const char *path, mode_t mode) { const char *path_lowercased = lowercase_path(path, true, true); int result = mkdir(path_lowercased, mode); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -471,7 +535,9 @@ STEAMAPI_API int __wrap_rmdir(const char *path) { const char *path_lowercased = lowercase_path(path, false, false); int result = rmdir(path_lowercased); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -479,7 +545,9 @@ STEAMAPI_API void *__wrap_dlopen(const char *path, int mode) { const char *path_lowercased = lowercase_path(path, false, false); void * result = dlopen(path_lowercased, mode); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } @@ -487,7 +555,9 @@ STEAMAPI_API void *__wrap_dlmopen(Lmid_t lmid, const char *path, int flags) { const char *path_lowercased = lowercase_path(path, false, false); void * result = dlmopen(lmid, path_lowercased, flags); - free((void *)path_lowercased); + if (path_lowercased != path) { + free((void *)path_lowercased); + } return result; } From 12e9b31b3052d6d70ec6d5b9089357a4e43a29e4 Mon Sep 17 00:00:00 2001 From: gion Date: Sat, 29 Feb 2020 16:33:30 +0100 Subject: [PATCH 5/5] Bug fixes. --- dll/wrap.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/dll/wrap.cpp b/dll/wrap.cpp index a3e9687..6e262c6 100644 --- a/dll/wrap.cpp +++ b/dll/wrap.cpp @@ -40,6 +40,8 @@ const char *STEAM_PATH; size_t STEAM_PATH_SIZE; +// Returns a '/' terminated absolute path to the steam folder in user's home, +// root is returned if env home is not set const char *get_steam_path() { char *home_path = getenv("HOME"); @@ -52,7 +54,7 @@ const char *get_steam_path() // Allocate more space for steam_path if needed (required_size does not count terminator) if (required_size > 0 && required_size >= STEAM_PATH_CACHE_SIZE) { char *large_steam_path = (char *)malloc(sizeof(char) * (required_size + 1)); - int check_size = snprintf(steam_path, required_size + 1, "%s/.steam/steam", home_path); + int check_size = snprintf(large_steam_path, required_size + 1, "%s/.steam/steam", home_path); // Check that path fits this time if (check_size == required_size) { steam_realpath = realpath(large_steam_path, nullptr); @@ -78,7 +80,8 @@ const char *get_steam_path() return steam_realpath; } - +// Fixes given path by navigating filesystem and lowering case to match +// existing entries on disk bool match_path(char *path, int start, bool accept_same_case) { if (!path[start + 1]) { @@ -95,7 +98,7 @@ bool match_path(char *path, int start, bool accept_same_case) char stored_char = path[separator]; path[separator] = 0; - bool path_accessible = access(path, 0) == 0; + bool path_accessible = access(path, F_OK) == 0; path[separator] = stored_char; if (!path_accessible || (!is_last_component && !match_path(path, separator, accept_same_case))) { @@ -167,13 +170,15 @@ bool match_path(char *path, int start, bool accept_same_case) return true; } +// Tries to convert the given path to the preferred lower-cased version const char *lowercase_path(const char *path, bool accept_same_case, bool stop_at_separator) { std::locale loc; char *path_lowercased = nullptr; if (path && *path) { - if (access(path, 0)) { + // If file does not exist + if (access(path, F_OK)) { // Make a copy of the path on which to work on path_lowercased = strdup(path); if (!path_lowercased) { @@ -187,9 +192,11 @@ const char *lowercase_path(const char *path, bool accept_same_case, bool stop_at char *lowercase_iterator = path_lowercased; // Lowercase whole steam path if possible + bool has_steam_root = false; if (!strncasecmp(path_lowercased, STEAM_PATH, STEAM_PATH_SIZE)) { memcpy(path_lowercased, STEAM_PATH, STEAM_PATH_SIZE); lowercase_iterator = &path_lowercased[STEAM_PATH_SIZE - 1]; + has_steam_root = true; } // Lowercase rest of the path char *iterator = lowercase_iterator; @@ -199,7 +206,7 @@ const char *lowercase_path(const char *path, bool accept_same_case, bool stop_at } // Check if we can access the lowered-case path - int error = access(path_lowercased, 0); + int error = access(path_lowercased, F_OK); if (!error) { // The new path is valid return path_lowercased; @@ -211,7 +218,7 @@ const char *lowercase_path(const char *path, bool accept_same_case, bool stop_at } } // Retry accesing the file again and tweak the path if needed - if (match_path(path_lowercased, STEAM_PATH_SIZE - 1, accept_same_case)) { + if (match_path(path_lowercased, has_steam_root? STEAM_PATH_SIZE - 1 : 0, accept_same_case)) { return path_lowercased; } } @@ -256,7 +263,7 @@ STEAMAPI_API FILE *__wrap_fopen64(const char *path, const char *modes) STEAMAPI_API int __wrap_open(const char *path, int flags, mode_t mode) { - bool is_writable = flags & 3; + bool is_writable = flags & (X_OK | W_OK); const char *path_lowercased = lowercase_path(path, is_writable, true); int result = open(path_lowercased, flags, mode); if (path_lowercased != path) { @@ -267,7 +274,7 @@ STEAMAPI_API int __wrap_open(const char *path, int flags, mode_t mode) STEAMAPI_API int __wrap_open64(const char *path, int flags, mode_t mode) { - bool is_writable = flags & 3; + bool is_writable = flags & (X_OK | W_OK); const char *path_lowercased = lowercase_path(path, is_writable, true); int result = open64(path_lowercased, flags, mode); if (path_lowercased != path) {