Browse Source

Fix activity SDK publication under Wine

Rhodderz 4 days ago
parent
commit
ab268de462

+ 20 - 9
Sunrise/src/client/content/activity/activity_sdk_live_publication.cpp

@@ -69,33 +69,44 @@ struct Marker final {
     }
 }
 
-/** Requires every existing drive-path directory component to be ordinary, never a reparse point. */
-[[nodiscard]] bool ordinary_ancestry(const std::wstring& directory) noexcept {
+/** Names the first drive-path component which is not an ordinary directory. */
+[[nodiscard]] const char* ordinary_ancestry_reason(const std::wstring& directory) noexcept {
     if (directory.size() < 3U || directory[1] != L':' || directory[2] != L'\\') {
-        return false;
-    }
-    if (!ordinary_directory(directory.substr(0, 3U).c_str())) {
-        return false;
+        return "path_shape";
     }
+    const bool rootOrdinary = ordinary_directory(directory.substr(0, 3U).c_str());
     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 false;
+            return "ancestor";
         }
         if (separator == std::wstring::npos) {
             break;
         }
         cursor = separator + 1U;
     }
-    return true;
+    return rootOrdinary ? "ready" : "drive_root";
+}
+
+/** Wine maps its synthetic drive root as a reparse point; real path components remain checked. */
+[[nodiscard]] bool ordinary_ancestry_allowed(const char* reason) noexcept {
+    if (std::string_view(reason) == "ready") {
+        return true;
+    }
+    if (std::string_view(reason) != "drive_root") {
+        return false;
+    }
+    const HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
+    return ntdll != nullptr && GetProcAddress(ntdll, "wine_get_version") != nullptr;
 }
 
 /** 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(output);
+    return full_path(input, output)
+           && ordinary_ancestry_allowed(ordinary_ancestry_reason(output));
 }
 
 /** Compares two complete Windows path components without locale-sensitive folding. */