From 74313585bf5fd3453ea4a3ce1b9ed2b567637fac Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sun, 20 Jan 2019 21:28:17 -0500 Subject: [PATCH 1/7] [string] Remove reuse of va_list in AppendVarargs va_list are not guarenteed to maintain their values after being used. With clang on Linux, args is undefined after fetching length and will print "(null)". Copy args into another va_list before getting length to prevent this. Add tests. --- src/xenia/base/string_buffer.cc | 14 ++++++----- src/xenia/base/testing/string_test.cc | 34 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 src/xenia/base/testing/string_test.cc diff --git a/src/xenia/base/string_buffer.cc b/src/xenia/base/string_buffer.cc index 050ddf9d8d2..2966b865e90 100644 --- a/src/xenia/base/string_buffer.cc +++ b/src/xenia/base/string_buffer.cc @@ -68,13 +68,15 @@ void StringBuffer::Append(const std::string_view value) { } void StringBuffer::AppendVarargs(const char* format, va_list args) { - int result = vsnprintf(nullptr, 0, format, args); - if (result <= 0) { - return; - } - auto length = static_cast(result); + va_list size_args; + va_copy(size_args, args); // arg is indeterminate after the return so copy it + int length = vsnprintf(nullptr, 0, format, size_args); + assert_true(length >= 0); + va_end(size_args); Grow(length + 1); - vsnprintf(buffer_ + buffer_offset_, buffer_capacity_, format, args); + int result = vsnprintf(buffer_ + buffer_offset_, + buffer_capacity_ - buffer_offset_, format, args); + assert_true(result == length); buffer_offset_ += length; buffer_[buffer_offset_] = 0; } diff --git a/src/xenia/base/testing/string_test.cc b/src/xenia/base/testing/string_test.cc new file mode 100644 index 00000000000..654f7d440a7 --- /dev/null +++ b/src/xenia/base/testing/string_test.cc @@ -0,0 +1,34 @@ +/** +****************************************************************************** +* Xenia : Xbox 360 Emulator Research Project * +****************************************************************************** +* Copyright 2019 Ben Vanik. All rights reserved. * +* Released under the BSD license - see LICENSE in the root for more details. * +****************************************************************************** +*/ + +#include "xenia/base/string.h" +#include "xenia/base/string_buffer.h" + +#include "third_party/catch/include/catch.hpp" + +namespace xe { +namespace base { +namespace test { + +TEST_CASE("StringBuffer") { + StringBuffer sb; + uint32_t module_flags = 0x1000000; + + std::string path_(R"(\Device\Cdrom0\default.xex)"); + sb.AppendFormat("Module {}:\n", path_.c_str()); + REQUIRE(sb.to_string() == "Module \\Device\\Cdrom0\\default.xex:\n"); + sb.AppendFormat(" Module Flags: {:08X}\n", module_flags); + REQUIRE( + sb.to_string() == + "Module \\Device\\Cdrom0\\default.xex:\n Module Flags: 01000000\n"); +} + +} // namespace test +} // namespace base +} // namespace xe From 2478a58a46fd67e446a54b78b9529ba8b43e2c3d Mon Sep 17 00:00:00 2001 From: Doug Johnson Date: Sat, 15 Jul 2017 17:44:37 -0600 Subject: [PATCH 2/7] main_posix: Print build version and date Print build version and date in the same way as the windows main --- src/xenia/base/main_posix.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xenia/base/main_posix.cc b/src/xenia/base/main_posix.cc index 673ff0ac45b..06bbb013b97 100644 --- a/src/xenia/base/main_posix.cc +++ b/src/xenia/base/main_posix.cc @@ -7,6 +7,7 @@ ****************************************************************************** */ +#include "build/version.h" #include "xenia/base/cvar.h" #include "xenia/base/main.h" @@ -34,6 +35,10 @@ extern "C" int main(int argc, char** argv) { // Initialize logging. Needs parsed FLAGS. xe::InitializeLogging(entry_info.name); + // Print version info. + XELOGI("Build: {} / {} on {}", XE_BUILD_BRANCH, XE_BUILD_COMMIT, + XE_BUILD_DATE); + // Call app-provided entry point. int result = entry_info.entry_point(args); From dcc1f52474317aa6181c57e993da4b9071e4b9d7 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sun, 3 Feb 2019 09:58:57 -0500 Subject: [PATCH 3/7] [fs linux] Fix ListFiles Skip recursive "." and ".." paths. Join paths instead of concatenating them. Assert stat return code. --- src/xenia/base/filesystem_posix.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/xenia/base/filesystem_posix.cc b/src/xenia/base/filesystem_posix.cc index 497c98bd3c3..e3960580dae 100644 --- a/src/xenia/base/filesystem_posix.cc +++ b/src/xenia/base/filesystem_posix.cc @@ -19,10 +19,11 @@ #include #include #include -#include #include #include #include +#include +#include #include namespace xe { @@ -217,11 +218,17 @@ std::vector ListFiles(const std::filesystem::path& path) { } while (auto ent = readdir(dir)) { + if (std::strcmp(ent->d_name, ".") == 0 || + std::strcmp(ent->d_name, "..") == 0) { + continue; + } + FileInfo info; info.name = ent->d_name; struct stat st; - stat((path / info.name).c_str(), &st); + auto ret = stat((path / info.name).c_str(), &st); + assert_zero(ret); info.create_timestamp = convertUnixtimeToWinFiletime(st.st_ctime); info.access_timestamp = convertUnixtimeToWinFiletime(st.st_atime); info.write_timestamp = convertUnixtimeToWinFiletime(st.st_mtime); @@ -230,7 +237,7 @@ std::vector ListFiles(const std::filesystem::path& path) { info.total_size = 0; } else { info.type = FileInfo::Type::kFile; - info.total_size = st.st_size; + info.total_size = static_cast(st.st_size); } result.push_back(info); } From 35d8d5329c1b54ecf4925518b908acf028948cb7 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Mon, 15 Jul 2019 18:39:29 -0400 Subject: [PATCH 4/7] [kernel] Add demangling of type_id for linux --- src/xenia/base/demangle.h | 19 +++++++++++++++++++ src/xenia/base/demangle_posix.cc | 26 ++++++++++++++++++++++++++ src/xenia/base/demangle_win.cc | 16 ++++++++++++++++ src/xenia/kernel/util/object_table.cc | 7 +++++-- 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 src/xenia/base/demangle.h create mode 100644 src/xenia/base/demangle_posix.cc create mode 100644 src/xenia/base/demangle_win.cc diff --git a/src/xenia/base/demangle.h b/src/xenia/base/demangle.h new file mode 100644 index 00000000000..6fbdab9a9ed --- /dev/null +++ b/src/xenia/base/demangle.h @@ -0,0 +1,19 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_BASE_DEMANGLE_H_ +#define XENIA_BASE_DEMANGLE_H_ + +#include + +namespace xe { +std::string Demangle(const std::string& mangled_name); +} + +#endif // XENIA_BASE_DEMANGLE_H_ diff --git a/src/xenia/base/demangle_posix.cc b/src/xenia/base/demangle_posix.cc new file mode 100644 index 00000000000..4e50e3dbb7e --- /dev/null +++ b/src/xenia/base/demangle_posix.cc @@ -0,0 +1,26 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/base/demangle.h" + +#include +#include + +namespace xe { + +std::string Demangle(const std::string& mangled_name) { + std::size_t len = 0; + int status = 0; + std::unique_ptr ptr( + __cxxabiv1::__cxa_demangle(mangled_name.c_str(), nullptr, &len, &status), + &std::free); + return ptr ? std::string("class ") + ptr.get() : ""; +} + +} // namespace xe diff --git a/src/xenia/base/demangle_win.cc b/src/xenia/base/demangle_win.cc new file mode 100644 index 00000000000..84a46a437e5 --- /dev/null +++ b/src/xenia/base/demangle_win.cc @@ -0,0 +1,16 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/base/demangle.h" + +namespace xe { + +std::string Demangle(const std::string& name) { return name; } + +} // namespace xe diff --git a/src/xenia/kernel/util/object_table.cc b/src/xenia/kernel/util/object_table.cc index df881e3a1b4..1d1c0d9663b 100644 --- a/src/xenia/kernel/util/object_table.cc +++ b/src/xenia/kernel/util/object_table.cc @@ -13,6 +13,7 @@ #include #include "xenia/base/byte_stream.h" +#include "xenia/base/demangle.h" #include "xenia/base/logging.h" #include "xenia/kernel/xobject.h" #include "xenia/kernel/xthread.h" @@ -118,7 +119,8 @@ X_STATUS ObjectTable::AddHandle(XObject* object, X_HANDLE* out_handle) { // Retain so long as the object is in the table. object->Retain(); - XELOGI("Added handle:{:08X} for {}", handle, typeid(*object).name()); + XELOGI("Added handle:{:08X} for {}", handle, + Demangle(typeid(*object).name())); } } @@ -203,7 +205,8 @@ X_STATUS ObjectTable::RemoveHandle(X_HANDLE handle) { object->handles().erase(handle_entry); } - XELOGI("Removed handle:{:08X} for {}", handle, typeid(*object).name()); + XELOGI("Removed handle:{:08X} for {}", handle, + Demangle(typeid(*object).name()).c_str()); // Release now that the object has been removed from the table. object->Release(); From 2ce67e389bb6e03dfc3f74a13e36673ff88cb887 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Fri, 23 Aug 2019 08:16:08 +0200 Subject: [PATCH 5/7] [fs linux] Cleanup headers Remove unused platform_linux reference. Replace C-style header uses. Replace C-style NULL with nullptr. Replace stdlib assert with xenia assert. Fix spelling --- src/xenia/base/exception_handler_linux.cc | 1 - src/xenia/base/filesystem_posix.cc | 7 +++---- src/xenia/base/system_linux.cc | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/xenia/base/exception_handler_linux.cc b/src/xenia/base/exception_handler_linux.cc index bc656a15d85..040e23dd795 100644 --- a/src/xenia/base/exception_handler_linux.cc +++ b/src/xenia/base/exception_handler_linux.cc @@ -11,7 +11,6 @@ #include "xenia/base/assert.h" #include "xenia/base/math.h" -#include "xenia/base/platform_linux.h" namespace xe { diff --git a/src/xenia/base/filesystem_posix.cc b/src/xenia/base/filesystem_posix.cc index e3960580dae..f4ccfce90a8 100644 --- a/src/xenia/base/filesystem_posix.cc +++ b/src/xenia/base/filesystem_posix.cc @@ -12,7 +12,6 @@ #include "xenia/base/logging.h" #include "xenia/base/string.h" -#include #include #include #include @@ -66,12 +65,12 @@ std::filesystem::path GetUserFolder() { home = std::getenv("HOME"); // if HOME not set, fall back to this - if (home == NULL) { + if (home == nullptr) { struct passwd pw1; struct passwd* pw; - char buf[4096]; // could potentionally lower this + char buf[4096]; // could potentially lower this getpwuid_r(getuid(), &pw1, buf, sizeof(buf), &pw); - assert(&pw1 == pw); // sanity check + assert_true(&pw1 == pw); // sanity check home = pw->pw_dir; } diff --git a/src/xenia/base/system_linux.cc b/src/xenia/base/system_linux.cc index 80773618a9c..89e1042e9f9 100644 --- a/src/xenia/base/system_linux.cc +++ b/src/xenia/base/system_linux.cc @@ -7,7 +7,7 @@ ****************************************************************************** */ -#include +#include #include From 513059c800c48126c0d984f89c7034bf4083538a Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sat, 24 Aug 2019 19:13:53 +0200 Subject: [PATCH 6/7] [fs linux]: Add more info to GetInfo Fill in name, path and total_size. Correct convertUnixtimeToWinFiletime which was using deprecated stat function without nanoseconds. It now includes nanoseconds. Add unit test for file and folder info. --- src/xenia/base/filesystem_posix.cc | 33 +++++++------ src/xenia/base/testing/filesystem_test.cc | 58 +++++++++++++++++++++++ src/xenia/base/testing/premake5.lua | 7 +++ src/xenia/base/testing/res/test_file | 1 + 4 files changed, 84 insertions(+), 15 deletions(-) create mode 100644 src/xenia/base/testing/filesystem_test.cc create mode 100644 src/xenia/base/testing/res/test_file diff --git a/src/xenia/base/filesystem_posix.cc b/src/xenia/base/filesystem_posix.cc index f4ccfce90a8..e88f661f65e 100644 --- a/src/xenia/base/filesystem_posix.cc +++ b/src/xenia/base/filesystem_posix.cc @@ -9,21 +9,18 @@ #include "xenia/base/assert.h" #include "xenia/base/filesystem.h" -#include "xenia/base/logging.h" #include "xenia/base/string.h" #include #include #include -#include #include -#include #include #include #include +#include #include #include -#include namespace xe { @@ -112,13 +109,14 @@ static int removeCallback(const char* fpath, const struct stat* sb, return rv; } -static uint64_t convertUnixtimeToWinFiletime(time_t unixtime) { - // Linux uses number of seconds since 1/1/1970, and Windows uses +static uint64_t convertUnixtimeToWinFiletime(const timespec& unixtime) { + // Linux uses number of nanoseconds since 1/1/1970, and Windows uses // number of nanoseconds since 1/1/1601 - // so we convert linux time to nanoseconds and then add the number of - // nanoseconds from 1601 to 1970 + // so we add the number of nanoseconds from 1601 to 1970 + // and return in the format of 10ns intervals // see https://msdn.microsoft.com/en-us/library/ms724228 - uint64_t filetime = filetime = (unixtime * 10000000) + 116444736000000000; + uint64_t filetime = (unixtime.tv_sec * 10000000) + unixtime.tv_nsec / 100 + + 116444736000000000; return filetime; } @@ -197,12 +195,17 @@ bool GetInfo(const std::filesystem::path& path, FileInfo* out_info) { if (stat(path.c_str(), &st) == 0) { if (S_ISDIR(st.st_mode)) { out_info->type = FileInfo::Type::kDirectory; + // On Linux st.st_size can have non-zero size (generally 4096) so make 0 + out_info->total_size = 0; } else { out_info->type = FileInfo::Type::kFile; + out_info->total_size = st.st_size; } - out_info->create_timestamp = convertUnixtimeToWinFiletime(st.st_ctime); - out_info->access_timestamp = convertUnixtimeToWinFiletime(st.st_atime); - out_info->write_timestamp = convertUnixtimeToWinFiletime(st.st_mtime); + out_info->path = path.parent_path(); + out_info->name = path.filename(); + out_info->create_timestamp = convertUnixtimeToWinFiletime(st.st_ctim); + out_info->access_timestamp = convertUnixtimeToWinFiletime(st.st_atim); + out_info->write_timestamp = convertUnixtimeToWinFiletime(st.st_mtim); return true; } return false; @@ -228,9 +231,9 @@ std::vector ListFiles(const std::filesystem::path& path) { struct stat st; auto ret = stat((path / info.name).c_str(), &st); assert_zero(ret); - info.create_timestamp = convertUnixtimeToWinFiletime(st.st_ctime); - info.access_timestamp = convertUnixtimeToWinFiletime(st.st_atime); - info.write_timestamp = convertUnixtimeToWinFiletime(st.st_mtime); + info.create_timestamp = convertUnixtimeToWinFiletime(st.st_ctim); + info.access_timestamp = convertUnixtimeToWinFiletime(st.st_atim); + info.write_timestamp = convertUnixtimeToWinFiletime(st.st_mtim); if (ent->d_type == DT_DIR) { info.type = FileInfo::Type::kDirectory; info.total_size = 0; diff --git a/src/xenia/base/testing/filesystem_test.cc b/src/xenia/base/testing/filesystem_test.cc new file mode 100644 index 00000000000..2829e6b9d58 --- /dev/null +++ b/src/xenia/base/testing/filesystem_test.cc @@ -0,0 +1,58 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2019 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/base/filesystem.h" + +#include + +#include "third_party/catch/include/catch.hpp" + +namespace xe { +namespace base { +namespace test { + +TEST_CASE("file_get_info", "Get Info") { + auto test_file_name = std::filesystem::path("test_file"); + auto test_file_dir = std::filesystem::path("src/xenia/base/testing/res"); + auto test_file_path = test_file_dir / test_file_name; + + filesystem::FileInfo info = {}; + + REQUIRE(filesystem::GetInfo(test_file_path, &info)); + + CHECK(info.type == filesystem::FileInfo::Type::kFile); + CHECK(info.name == test_file_name); + CHECK(info.path == test_file_dir); + CHECK(info.total_size == 81); + CHECK(info.create_timestamp > 132111406279379842); + CHECK(info.access_timestamp > 132111406279379842); + CHECK(info.write_timestamp > 132111406279379842); +} + +TEST_CASE("folder_get_info", "Get Info") { + auto test_folder_name = std::filesystem::path("res"); + auto test_folder_dir = std::filesystem::path("src/xenia/base/testing"); + auto test_folder_path = test_folder_dir / test_folder_name; + + filesystem::FileInfo info = {}; + + REQUIRE(filesystem::GetInfo(test_folder_path, &info)); + + CHECK(info.type == filesystem::FileInfo::Type::kDirectory); + CHECK(info.name == test_folder_name); + CHECK(info.path == test_folder_dir); + CHECK(info.total_size == 0); + CHECK(info.create_timestamp > 132111406279379842); + CHECK(info.access_timestamp > 132111406279379842); + CHECK(info.write_timestamp > 132111406279379842); +} + +} // namespace test +} // namespace base +} // namespace xe diff --git a/src/xenia/base/testing/premake5.lua b/src/xenia/base/testing/premake5.lua index 74d39aa651c..61194c98a8b 100644 --- a/src/xenia/base/testing/premake5.lua +++ b/src/xenia/base/testing/premake5.lua @@ -7,3 +7,10 @@ test_suite("xenia-base-tests", project_root, ".", { "xenia-base", }, }) + files({ + "res/*", + }) + filter("files:res/*") + flags({"ExcludeFromBuild"}) + filter("platforms:Windows") + debugdir(project_root) \ No newline at end of file diff --git a/src/xenia/base/testing/res/test_file b/src/xenia/base/testing/res/test_file new file mode 100644 index 00000000000..c94444439f2 --- /dev/null +++ b/src/xenia/base/testing/res/test_file @@ -0,0 +1 @@ +Test file to test the xe::filesystem::GetInfo function on both Windows and Linux From 75849c82d6d9b116f161cc7276d2cf2e36d1a995 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sat, 24 Aug 2019 22:33:30 +0200 Subject: [PATCH 7/7] [fs linux]: Simplify terniary expressions to bool --- src/xenia/base/filesystem_posix.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xenia/base/filesystem_posix.cc b/src/xenia/base/filesystem_posix.cc index e88f661f65e..a74efab9174 100644 --- a/src/xenia/base/filesystem_posix.cc +++ b/src/xenia/base/filesystem_posix.cc @@ -141,16 +141,16 @@ class PosixFileHandle : public FileHandle { size_t* out_bytes_read) override { ssize_t out = pread(handle_, buffer, buffer_length, file_offset); *out_bytes_read = out; - return out >= 0 ? true : false; + return out >= 0; } bool Write(size_t file_offset, const void* buffer, size_t buffer_length, size_t* out_bytes_written) override { ssize_t out = pwrite(handle_, buffer, buffer_length, file_offset); *out_bytes_written = out; - return out >= 0 ? true : false; + return out >= 0; } bool SetLength(size_t length) override { - return ftruncate(handle_, length) >= 0 ? true : false; + return ftruncate(handle_, length) >= 0; } void Flush() override { fsync(handle_); }