Skip Unnecessary SDK Copying

This commit is contained in:
TheBrokenRail 2024-12-21 04:46:31 -05:00
parent bf24ace78e
commit a80b5fb5c2
9 changed files with 220 additions and 113 deletions

View File

@ -40,7 +40,7 @@ include(cmake/options/paths.cmake)
# Required Compile Flags # Required Compile Flags
string(CONCAT COMPILE_FLAGS_SETUP string(CONCAT COMPILE_FLAGS_SETUP
# Optimizations # Optimizations
"if(CMAKE_BUILD_TYPE STREQUAL \"Release\")\n" "if(CMAKE_BUILD_TYPE MATCHES Release)\n"
" add_compile_options(-O3)\n" " add_compile_options(-O3)\n"
" add_link_options(-s)\n" " add_link_options(-s)\n"
"else()\n" "else()\n"
@ -169,27 +169,34 @@ if(BUILD_NATIVE_COMPONENTS)
list(APPEND ARM_OPTIONS "-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>") list(APPEND ARM_OPTIONS "-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>")
if(NOT MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN) if(NOT MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
if(DEFINED CMAKE_TOOLCHAIN_FILE) if(DEFINED CMAKE_TOOLCHAIN_FILE)
list(APPEND ARM_OPTIONS "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}") set(ARM_TOOLCHAIN "${CMAKE_TOOLCHAIN_FILE}")
endif() endif()
else() 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() endif()
list(APPEND ARM_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}") list(APPEND ARM_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}")
# Build # Build
ExternalProject_Add(arm-components ExternalProject_Add(arm-components
# Source Directory
DOWNLOAD_COMMAND "" DOWNLOAD_COMMAND ""
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
# Pass Arguments To CMake
CMAKE_CACHE_ARGS ${ARM_OPTIONS} CMAKE_CACHE_ARGS ${ARM_OPTIONS}
# Install
INSTALL_COMMAND INSTALL_COMMAND
"${CMAKE_COMMAND}" "-E" "${CMAKE_COMMAND}" "-E"
"rm" "-rf" "<INSTALL_DIR>/${MCPI_INSTALL_DIR}" "rm" "-rf" "<INSTALL_DIR>/${MCPI_INSTALL_DIR}"
COMMAND COMMAND
"${CMAKE_COMMAND}" "-E" "env" "${CMAKE_COMMAND}" "-E" "env" "DESTDIR="
"DESTDIR="
"${CMAKE_COMMAND}" "--install" "<BINARY_DIR>" "${CMAKE_COMMAND}" "--install" "<BINARY_DIR>"
# Use Terminal
USES_TERMINAL_CONFIGURE TRUE USES_TERMINAL_CONFIGURE TRUE
USES_TERMINAL_BUILD TRUE USES_TERMINAL_BUILD TRUE
USES_TERMINAL_INSTALL TRUE USES_TERMINAL_INSTALL TRUE
# Always Build
BUILD_ALWAYS TRUE BUILD_ALWAYS TRUE
) )
# Install # Install

View File

@ -30,7 +30,7 @@ void bootstrap(const options_t &options) {
// Copy SDK // Copy SDK
if (!reborn_is_server()) { if (!reborn_is_server()) {
copy_sdk(binary_directory, true); copy_sdk(binary_directory, false);
} }
// Resolve Binary Path // Resolve Binary Path

View File

@ -42,36 +42,15 @@ static void load(std::vector<std::string> &ld_preload, const std::string &folder
if (recursion_limit <= 0) { if (recursion_limit <= 0) {
ERR("Reached Recursion Limit While Loading Mods"); ERR("Reached Recursion Limit While Loading Mods");
} }
// Open Folder // Make Directory
ensure_directory(folder.c_str()); ensure_directory(folder.c_str());
DIR *dp = opendir(folder.c_str()); // Read
if (dp == nullptr) { read_directory(folder, [&folder, &ld_preload, &recursion_limit](const dirent *entry) {
// 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 // Get Full Name
std::string name = folder + entry->d_name; const std::string name = folder + entry->d_name;
// Handle // Handle
handle_file(ld_preload, name, recursion_limit); 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);
} }
// Bootstrap Mods // Bootstrap Mods

View File

@ -41,7 +41,7 @@ static void setup_environment(const options_t &options) {
static void handle_non_launch_commands(const options_t &options) { static void handle_non_launch_commands(const options_t &options) {
if (options.copy_sdk) { if (options.copy_sdk) {
const std::string binary_directory = get_binary_directory(); const std::string binary_directory = get_binary_directory();
copy_sdk(binary_directory, false); copy_sdk(binary_directory, true);
fflush(stdout); fflush(stdout);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }

View File

@ -1,61 +1,166 @@
#include <optional>
#include <fstream>
#include <sstream>
#include <sys/stat.h>
#include <dirent.h>
#include <cstring>
#include <libreborn/log.h> #include <libreborn/log.h>
#include <libreborn/util/util.h> #include <libreborn/util/util.h>
#include <libreborn/util/io.h> #include <libreborn/util/io.h>
#include <libreborn/config.h> #include <libreborn/config.h>
#include "../bootstrap/bootstrap.h"
#include "util.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<std::string> 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<std::string> home_hash = get_sdk_hash(get_sdk_path_home());
if (!home_hash.has_value()) {
return true;
}
const std::optional<std::string> 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 // Log
#define LOG(is_debug, ...) \ #define LOG(is_debug, ...) \
{ \ ({ \
if (is_debug) { \ if ((is_debug)) { \
DEBUG(__VA_ARGS__); \ DEBUG(__VA_ARGS__); \
} else { \ } else { \
INFO(__VA_ARGS__); \ INFO(__VA_ARGS__); \
} \ } \
} })
// Copy SDK Into ~/.minecraft-pi // Copy SDK Into ~/.minecraft-pi
#define HOME_SUBDIRECTORY_FOR_SDK "/sdk" static void do_copy_sdk(const std::string &binary_directory, const bool force) {
void copy_sdk(const std::string &binary_directory, const bool log_with_debug) { // Check If Copy Is Needed
// Ensure SDK Directory bool should_copy = force;
std::string sdk_path; if (!should_copy) {
{ should_copy = should_copy_sdk(binary_directory);
sdk_path = home_get() + HOME_SUBDIRECTORY_FOR_SDK; }
const char *const command[] = {"mkdir", "-p", sdk_path.c_str(), nullptr}; if (!should_copy) {
run_simple_command(command, "Unable To Create SDK Directory"); return;
} }
// Lock File // Get Paths
const std::string lock_file_path = sdk_path + "/.lock"; const std::string src_sdk = get_sdk_path_bundled(binary_directory);
const int lock_file_fd = lock_file(lock_file_path.c_str()); const std::string dst_sdk = get_sdk_path_home();
// Output Directory // Create Output Directory
const std::string output = sdk_path + "/" MCPI_SDK_DIR; delete_recursively(dst_sdk, true);
// Source Directory make_directory(dst_sdk);
const std::string source = binary_directory + "/sdk/.";
// Clean // Copy Directory
{ copy_directory(src_sdk, dst_sdk);
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");
}
// Log // 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
unlock_file(lock_file_path.c_str(), lock_file_fd); unlock_file(lock_file_path.c_str(), lock_file_fd);

View File

@ -1,18 +1,11 @@
#include <dirent.h>
#include <cstring>
#include <libreborn/log.h> #include <libreborn/log.h>
#include <libreborn/util/exec.h> #include <libreborn/util/exec.h>
#include "util.h" #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<unsigned char> *output = run_command(command, &status);
delete output;
if (!is_exit_status_success(status)) {
ERR("%s", error);
}
}
// Chop Off Last Component // Chop Off Last Component
void chop_last_component(std::string &str) { void chop_last_component(std::string &str) {
const std::string::size_type pos = str.find_last_of('/'); const std::string::size_type pos = str.find_last_of('/');
@ -40,3 +33,28 @@ std::string get_binary_directory() {
// Return // Return
return exe; return exe;
} }
// Read Directory
bool read_directory(const std::string &path, const std::function<void(const dirent *)> &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;
}

View File

@ -1,14 +1,15 @@
#pragma once #pragma once
#include <string> #include <string>
#include <functional>
void run_simple_command(const char *const command[], const char *error);
void chop_last_component(std::string &str); void chop_last_component(std::string &str);
std::string safe_realpath(const std::string &path); std::string safe_realpath(const std::string &path);
std::string get_binary_directory(); 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_path();
void setup_home(); void setup_home();
bool read_directory(const std::string &path, const std::function<void(const struct dirent *)> &callback, bool allow_nonexistent_dir = false);

View File

@ -86,11 +86,14 @@ const char *get_home_subdirectory_for_game_data() {
// Make Sure Directory Exists // Make Sure Directory Exists
void ensure_directory(const char *path) { void ensure_directory(const char *path) {
if (path[0] == '\0') {
return;
}
int ret = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); int ret = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (ret != 0 && errno != EEXIST) { 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 = {}; struct stat obj = {};
ret = stat(path, &obj); ret = stat(path, &obj);
if (ret == 0) { if (ret == 0) {

View File

@ -105,8 +105,10 @@ static bool is_whitelist() {
} }
// Get Path Of Blacklist (Or Whitelist) File // Get Path Of Blacklist (Or Whitelist) File
static std::string get_blacklist_file() { static std::string get_blacklist_file() {
std::string file(home_get()); std::string file = home_get();
file.append(is_whitelist() ? "/whitelist.txt" : "/blacklist.txt"); file += '/';
file += is_whitelist() ? "whitelist" : "blacklist";
file += ".txt";
return file; return file;
} }
@ -418,9 +420,8 @@ static bool is_ip_in_blacklist(const char *ip) {
ips.clear(); ips.clear();
// Check banned-ips.txt // Check banned-ips.txt
const std::string blacklist_file_path = get_blacklist_file(); 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) {
if (blacklist_file.good()) {
std::string line; std::string line;
while (std::getline(blacklist_file, line)) { while (std::getline(blacklist_file, line)) {
// Check Line // Check Line
@ -428,10 +429,7 @@ static bool is_ip_in_blacklist(const char *ip) {
ips.push_back(line); ips.push_back(line);
} }
} }
}
if (blacklist_file.is_open()) {
blacklist_file.close(); blacklist_file.close();
}
} else { } else {
ERR("Unable To Read Blacklist/Whitelist"); ERR("Unable To Read Blacklist/Whitelist");
} }
@ -523,10 +521,10 @@ static void server_init() {
// Open Properties File // Open Properties File
std::string file(home_get()); std::string file(home_get());
file.append("/server.properties"); file.append("/server.properties");
std::ifstream properties_file(file); std::ifstream properties_file(file, std::ios::binary);
// Check Properties File // Check Properties File
if (!properties_file.good()) { if (!properties_file) {
// Write Defaults // Write Defaults
std::ofstream properties_file_output(file); std::ofstream properties_file_output(file);
get_property_types(); get_property_types();
@ -536,12 +534,12 @@ static void server_init() {
} }
properties_file_output.close(); properties_file_output.close();
// Re-Open File // Re-Open File
properties_file = std::ifstream(file); properties_file = std::ifstream(file, std::ios::binary);
} }
// Check Properties File // Check Properties File
if (!properties_file.is_open()) { if (!properties_file) {
ERR("Unable To Open %s", file.c_str()); ERR("Unable To Read Server Properties");
} }
// Load Properties // Load Properties
get_server_properties().load(properties_file); get_server_properties().load(properties_file);
@ -550,16 +548,12 @@ static void server_init() {
// Create Empty Blacklist/Whitelist File // Create Empty Blacklist/Whitelist File
std::string blacklist_file_path = get_blacklist_file(); std::string blacklist_file_path = get_blacklist_file();
std::ifstream blacklist_file(blacklist_file_path); if (access(blacklist_file_path.c_str(), F_OK) != 0) {
if (!blacklist_file.good()) {
// Write Default // Write Default
std::ofstream blacklist_output(blacklist_file_path); std::ofstream blacklist_output(blacklist_file_path);
blacklist_output << "# Blacklist/Whitelist; Each Line Is One IP Address\n"; blacklist_output << "# Blacklist/Whitelist; Each Line Is One IP Address\n";
blacklist_output.close(); blacklist_output.close();
} }
if (blacklist_file.is_open()) {
blacklist_file.close();
}
// Load Blacklist/Whitelist // Load Blacklist/Whitelist
is_ip_in_blacklist(nullptr); is_ip_in_blacklist(nullptr);