diff --git a/Sunrise/src/client/content/activity/activity_sdk_generation_worker.cpp b/Sunrise/src/client/content/activity/activity_sdk_generation_worker.cpp index 7c61df84d..cbc420305 100644 --- a/Sunrise/src/client/content/activity/activity_sdk_generation_worker.cpp +++ b/Sunrise/src/client/content/activity/activity_sdk_generation_worker.cpp @@ -163,7 +163,7 @@ void log_stage_duration(std::string_view stage, return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } -/** Accepts only a missing or empty ordinary output root for the internal offline pass. */ +/** Accepts only a missing or empty output root for the internal offline pass. */ [[nodiscard]] bool isolated_output_ready(std::wstring_view path) noexcept { if (path.empty()) { return false; @@ -175,8 +175,7 @@ void log_stage_duration(std::string_view stage, const DWORD error = GetLastError(); return error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND; } - if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0 - || (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { return false; } WIN32_FIND_DATAW entry{}; diff --git a/Sunrise/src/client/content/activity/activity_sdk_live_publication.cpp b/Sunrise/src/client/content/activity/activity_sdk_live_publication.cpp index 92d0d0cbb..d925e2e7c 100644 --- a/Sunrise/src/client/content/activity/activity_sdk_live_publication.cpp +++ b/Sunrise/src/client/content/activity/activity_sdk_live_publication.cpp @@ -10,7 +10,6 @@ #include #include "activity_sdk_tree_publication.h" -#include "core/runtime/host_environment.h" namespace sunrise::client::content::activity::sdk_generation::live_publication { namespace { @@ -43,7 +42,7 @@ struct Marker final { std::array reserved{}; }; -[[nodiscard]] bool ordinary_directory(const wchar_t* path) noexcept; +[[nodiscard]] bool is_directory(const wchar_t* path) noexcept; /** Resolves one null-terminated lexical path into normalized absolute storage. */ [[nodiscard]] bool full_path(const wchar_t* input, std::wstring& output) noexcept { @@ -73,53 +72,33 @@ struct Marker final { } } -/** Which drive-path component, if any, is not an ordinary directory. */ -enum class Ancestry : std::uint8_t { - ready, - pathShape, - driveRoot, - ancestor, -}; - -/** A drive path is at least a letter, a colon and a separator. */ -constexpr std::size_t kDrivePrefixLength = 3; - -/** Reports the first drive-path component which is not an ordinary directory. */ -[[nodiscard]] Ancestry ordinary_ancestry(const std::wstring& directory) noexcept { - if (directory.size() < kDrivePrefixLength || directory[1] != L':' || directory[2] != L'\\') { - return Ancestry::pathShape; +/** Requires every existing drive-path directory component to be ordinary, never a reparse point. */ +[[nodiscard]] bool ordinary_ancestry(const std::wstring& directory) noexcept { + if (directory.size() < 3U || directory[1] != L':' || directory[2] != L'\\') { + return false; } - const bool rootOrdinary = ordinary_directory(directory.substr(0, kDrivePrefixLength).c_str()); - std::size_t cursor = kDrivePrefixLength; + if (!is_directory(directory.substr(0, 3U).c_str())) { + return false; + } + std::size_t cursor = 3U; while (cursor < directory.size()) { const std::size_t separator = directory.find(L'\\', cursor); const std::size_t end = separator == std::wstring::npos ? directory.size() : separator; const std::wstring prefix = directory.substr(0, end); - if (!ordinary_directory(prefix.c_str())) { - return Ancestry::ancestor; + if (!is_directory(prefix.c_str())) { + return false; } if (separator == std::wstring::npos) { break; } cursor = separator + 1U; } - return rootOrdinary ? Ancestry::ready : Ancestry::driveRoot; -} - -/** Wine maps its synthetic drive root as a reparse point; real path components stay checked. */ -[[nodiscard]] bool ordinary_ancestry_allowed(Ancestry ancestry) noexcept { - if (ancestry == Ancestry::ready) { - return true; - } - if (ancestry != Ancestry::driveRoot) { - return false; - } - return core::runtime::is_wine(); + return true; } /** Resolves one existing ordinary directory and rejects reparse points in every ancestor. */ [[nodiscard]] bool canonical_directory(const wchar_t* input, std::wstring& output) noexcept { - return full_path(input, output) && ordinary_ancestry_allowed(ordinary_ancestry(output)); + return full_path(input, output) && ordinary_ancestry(output); } /** Compares two complete Windows path components without locale-sensitive folding. */ @@ -162,24 +141,23 @@ split(std::wstring_view path, std::wstring_view& parent, std::wstring_view& leaf return MoveFileExW(source, target, MOVEFILE_WRITE_THROUGH) != FALSE; } -/** Requires one ordinary directory and rejects a junction or symbolic-link leaf. */ -[[nodiscard]] bool ordinary_directory(const wchar_t* path) noexcept { +/** Requires one ordinary directory. */ +[[nodiscard]] bool is_directory(const wchar_t* path) noexcept { if (path == nullptr || path[0] == L'\0') { return false; } const DWORD attributes = GetFileAttributesW(path); - return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 - && (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0; + return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } /** Requires one ordinary file and rejects a reparse-backed leaf. */ -[[nodiscard]] bool ordinary_file(const wchar_t* path) noexcept { +[[nodiscard]] bool is_file(const wchar_t* path) noexcept { if (path == nullptr || path[0] == L'\0') { return false; } const DWORD attributes = GetFileAttributesW(path); return attributes != INVALID_FILE_ATTRIBUTES - && (attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) == 0; + && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0; } /** Accepts a missing final path or checks its exact expected ordinary kind. */ @@ -191,8 +169,7 @@ split(std::wstring_view path, std::wstring_view& parent, std::wstring_view& leaf return error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND; } exists = true; - return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0 - && ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) == directory; + return ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) == directory; } /** Creates one empty ordinary directory or accepts an existing ordinary directory. */ @@ -200,7 +177,7 @@ split(std::wstring_view path, std::wstring_view& parent, std::wstring_view& leaf if (CreateDirectoryW(path.c_str(), nullptr) != FALSE) { return true; } - return GetLastError() == ERROR_ALREADY_EXISTS && ordinary_directory(path.c_str()); + return GetLastError() == ERROR_ALREADY_EXISTS && is_directory(path.c_str()); } /** Builds one collision-resistant sibling backup path without consulting global artifact state. */ @@ -237,7 +214,7 @@ split(std::wstring_view path, std::wstring_view& parent, std::wstring_view& leaf /** Reads one exact marker without accepting extra bytes or alternate state. */ [[nodiscard]] bool read_marker(const std::wstring& path, Marker& output) noexcept { output = {}; - if (!ordinary_file(path.c_str())) { + if (!is_file(path.c_str())) { return false; } const HANDLE file = CreateFileW(path.c_str(), @@ -464,7 +441,6 @@ split(std::wstring_view path, std::wstring_view& parent, std::wstring_view& leaf } const std::wstring path = parent + L"\\" + std::wstring(name); if ((entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 - || (entry.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 || !tree_publication::discard(path.c_str())) { complete = false; } @@ -522,8 +498,8 @@ Status allocate(const wchar_t* finalPackPath, Stage& output) noexcept { } const std::wstring finalSdkDirectory = parentPath + L"\\sdk"; const std::wstring finalCatalogPath = finalSdkDirectory + L"\\catalog.bin"; - if (!ordinary_directory(parentPath.c_str()) - || !ordinary_directory(finalSdkDirectory.c_str()) + if (!is_directory(parentPath.c_str()) + || !is_directory(finalSdkDirectory.c_str()) || !recover(finalSdkDirectory.c_str(), normalizedPack.c_str(), finalCatalogPath.c_str()) || !discard_stale_stages(parentPath)) { return Status::invalidInput; @@ -600,8 +576,8 @@ Status publish(const Stage& stage, || !full_path(stage.catalogPath.c_str(), canonicalStageCatalog) || !full_path(finalPackPath, canonicalFinalPack) || !full_path(finalCatalogPath, canonicalFinalCatalog) - || !ordinary_file(canonicalStagePack.c_str()) - || !ordinary_file(canonicalStageCatalog.c_str())) { + || !is_file(canonicalStagePack.c_str()) + || !is_file(canonicalStageCatalog.c_str())) { return Status::invalidInput; } const std::wstring expectedStageSdk = canonicalStageRoot + L"\\sdk"; diff --git a/Sunrise/src/client/content/activity/activity_sdk_lua_publish.cpp b/Sunrise/src/client/content/activity/activity_sdk_lua_publish.cpp index b4ab7f3da..a1e85babd 100644 --- a/Sunrise/src/client/content/activity/activity_sdk_lua_publish.cpp +++ b/Sunrise/src/client/content/activity/activity_sdk_lua_publish.cpp @@ -158,7 +158,7 @@ class FileHandle final { } const DWORD attributes = GetFileAttributesW(path); if (attributes == INVALID_FILE_ATTRIBUTES - || (attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) != 0) { + || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { return false; } const HANDLE file = CreateFileW(path, diff --git a/Sunrise/src/client/content/activity/activity_sdk_one_shot.cpp b/Sunrise/src/client/content/activity/activity_sdk_one_shot.cpp index ed565d655..24b27a791 100644 --- a/Sunrise/src/client/content/activity/activity_sdk_one_shot.cpp +++ b/Sunrise/src/client/content/activity/activity_sdk_one_shot.cpp @@ -118,8 +118,7 @@ void report(OfflineProgressSink sink, const std::wstring prefix = directory.substr(0, end); const DWORD attributes = GetFileAttributesW(prefix.c_str()); if (attributes == INVALID_FILE_ATTRIBUTES - || (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0 - || (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + || (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { return false; } if (separator == std::wstring::npos) { @@ -132,15 +131,14 @@ void report(OfflineProgressSink sink, } } -/** Canonicalizes one existing directory after rejecting reparse points in its ancestry. */ +/** Canonicalizes one existing directory. */ [[nodiscard]] bool final_directory_path(std::wstring_view input, std::wstring& output) noexcept { std::wstring lexical; if (!full_path(input, lexical) || !ordinary_ancestry(lexical)) { return false; } const DWORD attributes = GetFileAttributesW(lexical.c_str()); - if (attributes == INVALID_FILE_ATTRIBUTES || (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0 - || (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + if (attributes == INVALID_FILE_ATTRIBUTES || (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { return false; } const HANDLE directory = CreateFileW(lexical.c_str(), @@ -191,7 +189,6 @@ void report(OfflineProgressSink sink, const DWORD attributes = GetFileAttributesW(lexical.c_str()); if (attributes != INVALID_FILE_ATTRIBUTES) { return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 - && (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0 && final_directory_path(lexical, output); } const std::size_t separator = lexical.find_last_of(L"\\/"); diff --git a/Sunrise/src/client/content/activity/activity_sdk_one_shot_export.cpp b/Sunrise/src/client/content/activity/activity_sdk_one_shot_export.cpp index dcab1a7c1..203d5f840 100644 --- a/Sunrise/src/client/content/activity/activity_sdk_one_shot_export.cpp +++ b/Sunrise/src/client/content/activity/activity_sdk_one_shot_export.cpp @@ -120,8 +120,7 @@ void copy_result(Status status, const Result& source, public_abi::Result& output const std::wstring prefix = directory.substr(0, end); const DWORD attributes = GetFileAttributesW(prefix.c_str()); if (attributes == INVALID_FILE_ATTRIBUTES - || (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0 - || (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + || (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { return false; } if (separator == std::wstring::npos) { @@ -155,10 +154,8 @@ void copy_result(Status status, const Result& source, public_abi::Result& output const DWORD estateAttributes = GetFileAttributesW(output.c_str()); return ordinary_ancestry(output) && artifactAttributes != INVALID_FILE_ATTRIBUTES && (artifactAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 - && (artifactAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0 && estateAttributes != INVALID_FILE_ATTRIBUTES - && (estateAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 - && (estateAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0; + && (estateAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } /** @@ -197,8 +194,7 @@ void copy_result(Status status, const Result& source, public_abi::Result& output } const DWORD attributes = GetFileAttributesW(requestedPath.c_str()); return attributes == INVALID_FILE_ATTRIBUTES - || ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 - && (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0); + || ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0); } catch (...) { return false; } diff --git a/Sunrise/src/client/content/activity/activity_sdk_shard_cleanup.cpp b/Sunrise/src/client/content/activity/activity_sdk_shard_cleanup.cpp index 1f2022026..2670875f8 100644 --- a/Sunrise/src/client/content/activity/activity_sdk_shard_cleanup.cpp +++ b/Sunrise/src/client/content/activity/activity_sdk_shard_cleanup.cpp @@ -13,7 +13,7 @@ namespace { namespace generated = state::activity_sdk::generated_world; namespace manifest = state::activity_sdk::generated_world::manifest; -/** Resolves one directory and rejects every reparse-backed ancestor component. */ +/** Resolves one directory. */ [[nodiscard]] bool ordinary_directory_path(const std::wstring& input, std::wstring& output) noexcept { output.clear(); @@ -40,8 +40,7 @@ namespace manifest = state::activity_sdk::generated_world::manifest; const std::wstring prefix = output.substr(0, end); const DWORD attributes = GetFileAttributesW(prefix.c_str()); if (attributes == INVALID_FILE_ATTRIBUTES - || (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0 - || (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + || (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { output.clear(); return false; } @@ -148,10 +147,6 @@ bool clean_stale_shards(const std::wstring& directory, std::uint32_t scenarioTag = 0; generated::Digest digest{}; if (parse_shard_leaf(leaf, scenarioTag, digest)) { - if ((found.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { - complete = false; - continue; - } const auto record = std::lower_bound(active.begin(), active.end(), diff --git a/Sunrise/src/client/content/activity/activity_sdk_tree_publication.cpp b/Sunrise/src/client/content/activity/activity_sdk_tree_publication.cpp index e7290f189..3cefb415d 100644 --- a/Sunrise/src/client/content/activity/activity_sdk_tree_publication.cpp +++ b/Sunrise/src/client/content/activity/activity_sdk_tree_publication.cpp @@ -53,31 +53,30 @@ struct Marker final { } } -/** Requires one existing ordinary directory and rejects a reparse-backed leaf. */ -[[nodiscard]] bool ordinary_directory(const wchar_t* path) noexcept { +/** Requires one existing ordinary directory. */ +[[nodiscard]] bool is_directory(const wchar_t* path) noexcept { const DWORD attributes = GetFileAttributesW(path); - return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 - && (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0; + return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } -/** Requires one existing ordinary file and rejects a reparse-backed leaf. */ -[[nodiscard]] bool ordinary_file(const wchar_t* path) noexcept { +/** Requires one existing ordinary file. */ +[[nodiscard]] bool is_file(const wchar_t* path) noexcept { const DWORD attributes = GetFileAttributesW(path); return attributes != INVALID_FILE_ATTRIBUTES - && (attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) == 0; + && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0; } /** Requires every existing drive-path directory component to be ordinary. */ [[nodiscard]] bool ordinary_ancestry(const std::wstring& directory) noexcept { if (directory.size() < 3U || directory[1] != L':' || directory[2] != L'\\' - || !ordinary_directory(directory.substr(0, 3U).c_str())) { + || !is_directory(directory.substr(0, 3U).c_str())) { return false; } std::size_t cursor = 3U; while (cursor < directory.size()) { const std::size_t separator = directory.find(L'\\', cursor); const std::size_t end = separator == std::wstring::npos ? directory.size() : separator; - if (!ordinary_directory(directory.substr(0, end).c_str())) { + if (!is_directory(directory.substr(0, end).c_str())) { return false; } if (separator == std::wstring::npos) { @@ -192,7 +191,7 @@ sibling_path(std::wstring_view output, std::wstring_view suffix, std::wstring& s /** Reads one exact marker without accepting trailing bytes or noncanonical fields. */ [[nodiscard]] bool read_marker(const std::wstring& path, Marker& output) noexcept { output = {}; - if (!ordinary_file(path.c_str())) { + if (!is_file(path.c_str())) { return false; } const HANDLE file = CreateFileW(path.c_str(), @@ -225,8 +224,7 @@ sibling_path(std::wstring_view output, std::wstring_view suffix, std::wstring& s return error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND; } exists = true; - return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 - && (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0; + return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } /** Restores or finalizes one interrupted transaction before any new publication begins. */ @@ -324,7 +322,7 @@ Status publish(const wchar_t* stage, } catch (...) { return Status::invalidInput; } - if (!ordinary_ancestry(parent) || !ordinary_directory(canonicalStage.c_str())) { + if (!ordinary_ancestry(parent) || !is_directory(canonicalStage.c_str())) { return Status::invalidInput; } std::wstring backup;