diff --git a/CMakeLists.txt b/CMakeLists.txt index 16a6dac43..c1f64af91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ include(cmake/options/paths.cmake) # Required Compile Flags string(CONCAT COMPILE_FLAGS_SETUP # Optimizations - "if(CMAKE_BUILD_TYPE STREQUAL \"Release\")\n" + "if(CMAKE_BUILD_TYPE MATCHES Release)\n" " add_compile_options(-O3)\n" " add_link_options(-s)\n" "else()\n" @@ -169,27 +169,34 @@ if(BUILD_NATIVE_COMPONENTS) list(APPEND ARM_OPTIONS "-DCMAKE_INSTALL_PREFIX:PATH=") if(NOT MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN) if(DEFINED CMAKE_TOOLCHAIN_FILE) - list(APPEND ARM_OPTIONS "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}") + set(ARM_TOOLCHAIN "${CMAKE_TOOLCHAIN_FILE}") endif() else() - list(APPEND ARM_OPTIONS "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${MCPI_CMAKE_TOOLCHAIN_FILE}") + set(ARM_TOOLCHAIN "${MCPI_CMAKE_TOOLCHAIN_FILE}") + endif() + if(DEFINED ARM_TOOLCHAIN) + list(APPEND ARM_OPTIONS "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${ARM_TOOLCHAIN}") endif() list(APPEND ARM_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}") # Build ExternalProject_Add(arm-components + # Source Directory DOWNLOAD_COMMAND "" SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" + # Pass Arguments To CMake CMAKE_CACHE_ARGS ${ARM_OPTIONS} + # Install INSTALL_COMMAND "${CMAKE_COMMAND}" "-E" "rm" "-rf" "/${MCPI_INSTALL_DIR}" COMMAND - "${CMAKE_COMMAND}" "-E" "env" - "DESTDIR=" + "${CMAKE_COMMAND}" "-E" "env" "DESTDIR=" "${CMAKE_COMMAND}" "--install" "" + # Use Terminal USES_TERMINAL_CONFIGURE TRUE USES_TERMINAL_BUILD TRUE USES_TERMINAL_INSTALL TRUE + # Always Build BUILD_ALWAYS TRUE ) # Install diff --git a/launcher/src/bootstrap/bootstrap.cpp b/launcher/src/bootstrap/bootstrap.cpp index 069de05f0..a62c6751c 100644 --- a/launcher/src/bootstrap/bootstrap.cpp +++ b/launcher/src/bootstrap/bootstrap.cpp @@ -30,7 +30,7 @@ void bootstrap(const options_t &options) { // Copy SDK if (!reborn_is_server()) { - copy_sdk(binary_directory, true); + copy_sdk(binary_directory, false); } // Resolve Binary Path diff --git a/launcher/src/bootstrap/mods.cpp b/launcher/src/bootstrap/mods.cpp index 86d6bb15b..813027d2a 100644 --- a/launcher/src/bootstrap/mods.cpp +++ b/launcher/src/bootstrap/mods.cpp @@ -42,36 +42,15 @@ static void load(std::vector &ld_preload, const std::string &folder if (recursion_limit <= 0) { ERR("Reached Recursion Limit While Loading Mods"); } - // Open Folder + // Make Directory ensure_directory(folder.c_str()); - DIR *dp = opendir(folder.c_str()); - if (dp == nullptr) { - // Unable To Open Folder - ERR("Error Opening Directory: %s: %s", folder.c_str(), strerror(errno)); - } - // Loop Through Folder - while (true) { - errno = 0; - const dirent *entry = readdir(dp); - if (entry != nullptr) { - // Block Pseudo-Directories - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { - continue; - } - // Get Full Name - std::string name = folder + entry->d_name; - // Handle - handle_file(ld_preload, name, recursion_limit); - } else if (errno != 0) { - // Error Reading Contents Of Folder - ERR("Error Reading Directory: %s: %s", folder.c_str(), strerror(errno)); - } else { - // Done! - break; - } - } - // Close Folder - closedir(dp); + // Read + read_directory(folder, [&folder, &ld_preload, &recursion_limit](const dirent *entry) { + // Get Full Name + const std::string name = folder + entry->d_name; + // Handle + handle_file(ld_preload, name, recursion_limit); + }); } // Bootstrap Mods diff --git a/launcher/src/main.cpp b/launcher/src/main.cpp index 46cde35ee..467ffa7eb 100644 --- a/launcher/src/main.cpp +++ b/launcher/src/main.cpp @@ -41,7 +41,7 @@ static void setup_environment(const options_t &options) { static void handle_non_launch_commands(const options_t &options) { if (options.copy_sdk) { const std::string binary_directory = get_binary_directory(); - copy_sdk(binary_directory, false); + copy_sdk(binary_directory, true); fflush(stdout); exit(EXIT_SUCCESS); } diff --git a/launcher/src/util/sdk.cpp b/launcher/src/util/sdk.cpp index 858d6ec8c..bb493daed 100644 --- a/launcher/src/util/sdk.cpp +++ b/launcher/src/util/sdk.cpp @@ -1,62 +1,167 @@ +#include +#include +#include +#include +#include +#include + #include #include #include #include -#include "../bootstrap/bootstrap.h" #include "util.h" +// Utility Functions +static constexpr char path_separator = '/'; +static void make_directory(std::string path /* Must Be Absolute */) { + path += path_separator; + std::stringstream stream(path); + path = ""; + std::string path_segment; + while (std::getline(stream, path_segment, path_separator)) { + path += path_segment; + ensure_directory(path.c_str()); + path += path_separator; + } +} +static void delete_recursively(const std::string &path, const bool allow_nonexistent_dir) { + // Loop Through Children + const bool success = read_directory(path, [&path](const dirent *entry) { + // Handle + const std::string child = path + path_separator + entry->d_name; + if (entry->d_type == DT_DIR) { + delete_recursively(child, false); + } else if (unlink(child.c_str()) != 0) { + ERR("Unable To Delete File: %s: %s", child.c_str(), strerror(errno)); + } + }, allow_nonexistent_dir); + // Delete + if (success && rmdir(path.c_str()) != 0) { + ERR("Unable To Delete Directory: %s: %s", path.c_str(), strerror(errno)); + } +} +static void copy_file(const std::string &src, const std::string &dst) { + std::ifstream in(src, std::ios::binary); + if (!in) { + ERR("Unable To Open Source File: %s", src.c_str()); + } + std::ofstream out(dst, std::ios::binary); + if (!out) { + ERR("Unable To Create Destination File: %s", dst.c_str()); + } + out << in.rdbuf(); + out.close(); + in.close(); +} +static void copy_directory(const std::string &src, const std::string &dst) { + read_directory(src, [&src, &dst](const dirent *entry) { + const std::string name = path_separator + std::string(entry->d_name); + const std::string in = src + name; + const std::string out = dst + name; + if (entry->d_type == DT_DIR) { + ensure_directory(out.c_str()); + copy_directory(in, out); + } else { + copy_file(in, out); + } + }); +} + +// Path +static std::string get_sdk_root(const std::string &home) { + return home + path_separator + "sdk"; +} +static std::string get_sdk_path_home() { + return get_sdk_root(home_get()) + path_separator + MCPI_SDK_DIR; +} +static std::string get_sdk_path_bundled(const std::string &binary_directory) { + return get_sdk_root(binary_directory); +} + +// Test Whether SDK Should Be Copied +static std::optional get_sdk_hash(const std::string &sdk) { + const std::string path = sdk + path_separator + ".hash"; + // Open File + std::ifstream stream(path, std::ios::binary | std::ios::ate); + if (stream) { + std::string hash; + // Read File + const std::streamoff size = stream.tellg(); + stream.seekg(0, std::ifstream::beg); + hash.resize(size); + stream.read(hash.data(), size); + // Close File + stream.close(); + // Return + return hash; + } else { + // Unable To Read + return std::nullopt; + } +} +static bool should_copy_sdk(const std::string &binary_directory) { + // Read Hashes + const std::optional home_hash = get_sdk_hash(get_sdk_path_home()); + if (!home_hash.has_value()) { + return true; + } + const std::optional bundled_hash = get_sdk_hash(get_sdk_path_bundled(binary_directory)); + if (!home_hash.has_value()) { + IMPOSSIBLE(); + } + const bool should_copy = home_hash.value() != bundled_hash.value(); + if (!should_copy) { + DEBUG("Skipped Unnecessary SDK Copy"); + } + return should_copy; +} + // Log #define LOG(is_debug, ...) \ - { \ - if (is_debug) { \ + ({ \ + if ((is_debug)) { \ DEBUG(__VA_ARGS__); \ } else { \ INFO(__VA_ARGS__); \ } \ - } + }) // Copy SDK Into ~/.minecraft-pi -#define HOME_SUBDIRECTORY_FOR_SDK "/sdk" -void copy_sdk(const std::string &binary_directory, const bool log_with_debug) { - // Ensure SDK Directory - std::string sdk_path; - { - sdk_path = home_get() + HOME_SUBDIRECTORY_FOR_SDK; - const char *const command[] = {"mkdir", "-p", sdk_path.c_str(), nullptr}; - run_simple_command(command, "Unable To Create SDK Directory"); +static void do_copy_sdk(const std::string &binary_directory, const bool force) { + // Check If Copy Is Needed + bool should_copy = force; + if (!should_copy) { + should_copy = should_copy_sdk(binary_directory); + } + if (!should_copy) { + return; } - // Lock File - const std::string lock_file_path = sdk_path + "/.lock"; - const int lock_file_fd = lock_file(lock_file_path.c_str()); + // Get Paths + const std::string src_sdk = get_sdk_path_bundled(binary_directory); + const std::string dst_sdk = get_sdk_path_home(); - // Output Directory - const std::string output = sdk_path + "/" MCPI_SDK_DIR; - // Source Directory - const std::string source = binary_directory + "/sdk/."; + // Create Output Directory + delete_recursively(dst_sdk, true); + make_directory(dst_sdk); - // Clean - { - const char *const command[] = {"rm", "-rf", output.c_str(), nullptr}; - run_simple_command(command, "Unable To Clean SDK Output Directory"); - } - - // Make Directory - { - const char *const command[] = {"mkdir", "-p", output.c_str(), nullptr}; - run_simple_command(command, "Unable To Create SDK Output Directory"); - } - - // Copy - { - const char *const command[] = {"cp", "-ar", source.c_str(), output.c_str(), nullptr}; - run_simple_command(command, "Unable To Copy SDK"); - } + // Copy Directory + copy_directory(src_sdk, dst_sdk); // Log - LOG(log_with_debug, "Copied SDK To: %s", output.c_str()); + LOG(!force, "Copied SDK To: %s", dst_sdk.c_str()); +} +void copy_sdk(const std::string &binary_directory, const bool force) { + // Lock File + const std::string root = get_sdk_root(home_get()); + ensure_directory(root.c_str()); + const std::string lock_file_path = root + path_separator + ".lock"; + const int lock_file_fd = lock_file(lock_file_path.c_str()); + + // Do + do_copy_sdk(binary_directory, force); // Unlock File unlock_file(lock_file_path.c_str(), lock_file_fd); -} +} \ No newline at end of file diff --git a/launcher/src/util/util.cpp b/launcher/src/util/util.cpp index ca17c8add..04938b395 100644 --- a/launcher/src/util/util.cpp +++ b/launcher/src/util/util.cpp @@ -1,18 +1,11 @@ +#include +#include + #include #include #include "util.h" -// Simpler Version Of run_command() -void run_simple_command(const char *const command[], const char *error) { - int status = 0; - const std::vector *output = run_command(command, &status); - delete output; - if (!is_exit_status_success(status)) { - ERR("%s", error); - } -} - // Chop Off Last Component void chop_last_component(std::string &str) { const std::string::size_type pos = str.find_last_of('/'); @@ -40,3 +33,28 @@ std::string get_binary_directory() { // Return return exe; } + +// Read Directory +bool read_directory(const std::string &path, const std::function &callback, const bool allow_nonexistent_dir) { + // Open Directory + DIR *dp = opendir(path.c_str()); + if (dp == nullptr) { + if (allow_nonexistent_dir) { + return false; + } + ERR("Unable To Open Directory: %s: %s", path.c_str(), strerror(errno)); + } + // Read + const dirent *entry; + while ((entry = readdir(dp)) != nullptr) { + // Block Pseudo-Directories + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } + // Run + callback(entry); + } + // Close + closedir(dp); + return true; +} \ No newline at end of file diff --git a/launcher/src/util/util.h b/launcher/src/util/util.h index 27b26621d..e5eeb2c3d 100644 --- a/launcher/src/util/util.h +++ b/launcher/src/util/util.h @@ -1,14 +1,15 @@ #pragma once #include - -void run_simple_command(const char *const command[], const char *error); +#include void chop_last_component(std::string &str); std::string safe_realpath(const std::string &path); std::string get_binary_directory(); -void copy_sdk(const std::string &binary_directory, bool log_with_debug); +void copy_sdk(const std::string &binary_directory, bool force); void setup_path(); -void setup_home(); \ No newline at end of file +void setup_home(); + +bool read_directory(const std::string &path, const std::function &callback, bool allow_nonexistent_dir = false); \ No newline at end of file diff --git a/libreborn/src/util/util.cpp b/libreborn/src/util/util.cpp index 94701780b..aacc59eaf 100644 --- a/libreborn/src/util/util.cpp +++ b/libreborn/src/util/util.cpp @@ -86,11 +86,14 @@ const char *get_home_subdirectory_for_game_data() { // Make Sure Directory Exists void ensure_directory(const char *path) { + if (path[0] == '\0') { + return; + } int ret = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); if (ret != 0 && errno != EEXIST) { - ERR("Unable To Create Directory: %s", strerror(errno)); + ERR("Unable To Create Directory: %s: %s", path, strerror(errno)); } - int is_dir = 0; + bool is_dir = false; struct stat obj = {}; ret = stat(path, &obj); if (ret == 0) { diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index aab5ce051..2e2f8b173 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -105,8 +105,10 @@ static bool is_whitelist() { } // Get Path Of Blacklist (Or Whitelist) File static std::string get_blacklist_file() { - std::string file(home_get()); - file.append(is_whitelist() ? "/whitelist.txt" : "/blacklist.txt"); + std::string file = home_get(); + file += '/'; + file += is_whitelist() ? "whitelist" : "blacklist"; + file += ".txt"; return file; } @@ -418,20 +420,16 @@ static bool is_ip_in_blacklist(const char *ip) { ips.clear(); // Check banned-ips.txt const std::string blacklist_file_path = get_blacklist_file(); - std::ifstream blacklist_file(blacklist_file_path); + std::ifstream blacklist_file(blacklist_file_path, std::ios::binary); if (blacklist_file) { - if (blacklist_file.good()) { - std::string line; - while (std::getline(blacklist_file, line)) { - // Check Line - if (line.length() > 0 && line[0] != '#') { - ips.push_back(line); - } + std::string line; + while (std::getline(blacklist_file, line)) { + // Check Line + if (line.length() > 0 && line[0] != '#') { + ips.push_back(line); } } - if (blacklist_file.is_open()) { - blacklist_file.close(); - } + blacklist_file.close(); } else { ERR("Unable To Read Blacklist/Whitelist"); } @@ -523,10 +521,10 @@ static void server_init() { // Open Properties File std::string file(home_get()); file.append("/server.properties"); - std::ifstream properties_file(file); + std::ifstream properties_file(file, std::ios::binary); // Check Properties File - if (!properties_file.good()) { + if (!properties_file) { // Write Defaults std::ofstream properties_file_output(file); get_property_types(); @@ -536,12 +534,12 @@ static void server_init() { } properties_file_output.close(); // Re-Open File - properties_file = std::ifstream(file); + properties_file = std::ifstream(file, std::ios::binary); } // Check Properties File - if (!properties_file.is_open()) { - ERR("Unable To Open %s", file.c_str()); + if (!properties_file) { + ERR("Unable To Read Server Properties"); } // Load Properties get_server_properties().load(properties_file); @@ -550,16 +548,12 @@ static void server_init() { // Create Empty Blacklist/Whitelist File std::string blacklist_file_path = get_blacklist_file(); - std::ifstream blacklist_file(blacklist_file_path); - if (!blacklist_file.good()) { + if (access(blacklist_file_path.c_str(), F_OK) != 0) { // Write Default std::ofstream blacklist_output(blacklist_file_path); blacklist_output << "# Blacklist/Whitelist; Each Line Is One IP Address\n"; blacklist_output.close(); } - if (blacklist_file.is_open()) { - blacklist_file.close(); - } // Load Blacklist/Whitelist is_ip_in_blacklist(nullptr);