feat: complete WorkBuddy parity and Windows release workflow

This commit is contained in:
xiaohan.yuan committed 2026-10-18 12:45:21 +08:00
1 parent 143516b3a8
commit d5512df549
434 files changed
+54977 -1854

No files matched your search

+174
View File
@@ -0,0 +1,174 @@
#pragma once
#include <memory>
#include <sstream>
#include <iomanip>
#include <cwctype>
// This host-only reader never grants a workspace handle to the sandbox.
namespace workspace_read {
struct Lifetime {
Handle parent{parentProcess()}, done{CreateEventW(nullptr, TRUE, FALSE, nullptr)};
std::thread monitor;
explicit Lifetime(DWORD timeout = 4000) {
require(done.value != nullptr, "Create reader lifecycle event");
monitor = std::thread([this, timeout]() {
HANDLE events[] = {parent.value, done.value};
const DWORD state = WaitForMultipleObjects(2, events, FALSE, timeout);
if (state != WAIT_OBJECT_0 + 1) TerminateProcess(GetCurrentProcess(), 125);
});
}
~Lifetime() { SetEvent(done.value); monitor.join(); }
};
static bool component(const std::wstring& name) {
if (name.empty() || name == L"." || name == L".." || name.back() == L'.' || name.back() == L' ') return false;
for (wchar_t ch : name) if (ch < 32 || std::wstring(L"<>:\"/\\|?*").find(ch) != std::wstring::npos) return false;
auto stem = name.substr(0, name.find(L'.'));
std::transform(stem.begin(), stem.end(), stem.begin(), [](wchar_t ch) { return static_cast<wchar_t>(towupper(ch)); });
if (stem == L"CON" || stem == L"PRN" || stem == L"AUX" || stem == L"NUL") return false;
return !(stem.size() == 4 && (stem.substr(0, 3) == L"COM" || stem.substr(0, 3) == L"LPT") && stem[3] >= L'1' && stem[3] <= L'9');
}
static std::vector<std::wstring> parts(std::wstring value) {
std::replace(value.begin(), value.end(), L'/', L'\\');
std::vector<std::wstring> result;
size_t start = 0;
for (;;) {
const auto end = value.find(L'\\', start);
const auto name = value.substr(start, end == std::wstring::npos ? end : end - start);
if (!component(name)) throw std::runtime_error("Invalid workspace path component");
result.push_back(name);
if (end == std::wstring::npos) return result;
start = end + 1;
}
}
static std::wstring finalPath(HANDLE handle) {
std::vector<wchar_t> buffer(32768);
const DWORD count = GetFinalPathNameByHandleW(handle, buffer.data(), static_cast<DWORD>(buffer.size()), FILE_NAME_NORMALIZED | VOLUME_NAME_GUID);
require(count > 0 && count < buffer.size(), "Resolve workspace handle");
std::wstring path(buffer.data(), count);
while (path.size() > 1 && path.back() == L'\\') path.pop_back();
return path;
}
static BY_HANDLE_FILE_INFORMATION information(HANDLE handle) {
BY_HANDLE_FILE_INFORMATION result = {};
require(GetFileInformationByHandle(handle, &result) != FALSE, "Inspect workspace handle");
if (result.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DEVICE)) throw std::runtime_error("Workspace reparse point or device denied");
if (!(result.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && result.nNumberOfLinks != 1) throw std::runtime_error("Workspace hard link denied");
return result;
}
static std::string identity(HANDLE handle) {
FILE_ID_INFO id = {};
require(GetFileInformationByHandleEx(handle, FileIdInfo, &id, sizeof(id)) != FALSE, "Identify workspace handle");
std::ostringstream text;
text << std::hex << std::setfill('0') << std::setw(16) << id.VolumeSerialNumber << ':';
for (BYTE byte : id.FileId.Identifier) text << std::setw(2) << static_cast<unsigned int>(byte);
return text.str();
}
struct Target {
std::vector<std::unique_ptr<Handle>> held;
fs::path path;
std::wstring rootFinal;
std::string rootIdentity;
HANDLE open(bool directory) {
// Read sharing only pins names against rename/delete and excludes writable handles,
// including handles used to retarget a reparse point. All ancestors stay open.
auto handle = std::make_unique<Handle>(CreateFileW(path.c_str(), directory ? FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES : GENERIC_READ,
FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr));
require(handle->value != INVALID_HANDLE_VALUE, "Open pinned workspace target");
const auto info = information(handle->value);
if (directory && !(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) throw std::runtime_error("Workspace ancestor is not a directory");
const auto result = handle->value;
held.push_back(std::move(handle));
return result;
}
explicit Target(const std::wstring& root) {
if (root.size() < 3 || root.size() > 1024 || !iswalpha(root[0]) || root[1] != L':' || root[2] != L'\\') throw std::runtime_error("Workspace requires a local drive path");
path = root.substr(0, 3);
if (GetDriveTypeW(path.c_str()) != DRIVE_FIXED) throw std::runtime_error("Workspace requires a fixed local volume");
HANDLE last = open(true);
wchar_t filesystem[32] = {};
require(GetVolumeInformationByHandleW(last, nullptr, 0, nullptr, nullptr, nullptr, filesystem, 32) != FALSE, "Inspect workspace volume");
if (_wcsicmp(filesystem, L"NTFS") != 0) throw std::runtime_error("Workspace reader currently requires NTFS");
if (root.size() > 3) for (const auto& name : parts(root.substr(3))) { path /= name; last = open(true); }
rootFinal = finalPath(last);
rootIdentity = identity(last);
}
HANDLE resolve(const std::wstring& relative) {
if (relative == L".") return held.back()->value;
const auto names = parts(relative);
HANDLE last = nullptr;
for (size_t index = 0; index < names.size(); ++index) { path /= names[index]; last = open(index + 1 < names.size()); }
return last;
}
std::wstring relative(HANDLE handle) const {
const auto actual = finalPath(handle);
if (_wcsicmp(actual.c_str(), rootFinal.c_str()) == 0) return L".";
if (actual.size() <= rootFinal.size() || _wcsnicmp(actual.c_str(), rootFinal.c_str(), rootFinal.size()) != 0 || actual[rootFinal.size()] != L'\\') throw std::runtime_error("Workspace handle escaped root");
return actual.substr(rootFinal.size() + 1);
}
};
static std::string base64(const std::vector<BYTE>& bytes) {
static const char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string result; result.reserve((bytes.size() + 2) / 3 * 4);
for (size_t index = 0; index < bytes.size(); index += 3) {
const unsigned int value = (static_cast<unsigned int>(bytes[index]) << 16) |
(index + 1 < bytes.size() ? static_cast<unsigned int>(bytes[index + 1]) << 8 : 0) | (index + 2 < bytes.size() ? bytes[index + 2] : 0);
result += alphabet[value >> 18]; result += alphabet[(value >> 12) & 63];
result += index + 1 < bytes.size() ? alphabet[(value >> 6) & 63] : '=';
result += index + 2 < bytes.size() ? alphabet[value & 63] : '=';
}
return result;
}
static int run(const std::wstring& operation, const std::wstring& root, const std::wstring& relative, const std::string& expected, DWORD limit) {
if (inContainer(GetCurrentProcess())) throw std::runtime_error("Workspace reader is host-only");
Lifetime lifetime;
if (operation != L"identity" && operation != L"read" && operation != L"stat" && operation != L"list") throw std::runtime_error("Invalid workspace reader operation");
if (limit == 0 || limit > 8 * 1024 * 1024) throw std::runtime_error("Invalid workspace reader limit");
Target target(root);
if (operation != L"identity" && target.rootIdentity != expected) throw std::runtime_error("Workspace root identity changed");
const HANDLE handle = target.resolve(relative);
const auto before = information(handle);
const bool directory = (before.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
const auto size = (static_cast<ULONGLONG>(before.nFileSizeHigh) << 32) | before.nFileSizeLow;
std::string result = "{\"protocol\":1,\"rootIdentity\":\"" + target.rootIdentity + "\",\"identity\":\"" + identity(handle) +
"\",\"path\":\"" + jsonText(target.relative(handle)) + "\",\"kind\":\"" + (directory ? "directory" : "file") + "\",\"size\":" + std::to_string(size);
if (operation == L"read") {
if (directory) throw std::runtime_error("Workspace target is a directory");
if (size > limit) throw std::runtime_error("Workspace file exceeds read limit");
std::vector<BYTE> bytes(static_cast<size_t>(size)); DWORD read = 0;
if (!bytes.empty()) require(ReadFile(handle, bytes.data(), static_cast<DWORD>(bytes.size()), &read, nullptr) && read == bytes.size(), "Read pinned workspace file");
const auto after = information(handle);
if (after.nNumberOfLinks != 1 || after.nFileSizeLow != before.nFileSizeLow || after.nFileSizeHigh != before.nFileSizeHigh || CompareFileTime(&before.ftLastWriteTime, &after.ftLastWriteTime) != 0) throw std::runtime_error("Workspace file changed while reading");
result += ",\"data\":\"" + base64(bytes) + "\"";
} else if (operation == L"list") {
if (!directory) throw std::runtime_error("Workspace target is not a directory");
result += ",\"entries\":[";
std::vector<BYTE> buffer(65536); bool first = true; DWORD count = 0;
for (;;) {
if (!GetFileInformationByHandleEx(handle, FileIdBothDirectoryInfo, buffer.data(), static_cast<DWORD>(buffer.size()))) {
if (GetLastError() == ERROR_NO_MORE_FILES) break;
require(false, "Enumerate pinned workspace directory");
}
size_t offset = 0;
for (;;) {
const auto entry = reinterpret_cast<FILE_ID_BOTH_DIR_INFO*>(buffer.data() + offset);
if (entry->FileNameLength > buffer.size() - offset - offsetof(FILE_ID_BOTH_DIR_INFO, FileName)) throw std::runtime_error("Invalid directory record");
const std::wstring name(entry->FileName, entry->FileNameLength / sizeof(wchar_t));
if (name != L"." && name != L"..") {
if (++count > limit) throw std::runtime_error("Workspace directory exceeds entry limit");
if (!first) result += ',';
first = false;
result += "{\"name\":\"" + jsonText(name) + "\",\"kind\":\"" + ((entry->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? "link" : (entry->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? "directory" : "file") + "\"}";
}
if (entry->NextEntryOffset == 0) break;
if (entry->NextEntryOffset < sizeof(FILE_ID_BOTH_DIR_INFO) || entry->NextEntryOffset > buffer.size() - offset - sizeof(FILE_ID_BOTH_DIR_INFO)) throw std::runtime_error("Invalid next directory record");
offset += entry->NextEntryOffset;
}
}
result += ']';
}
result += "}\n";
DWORD written = 0;
require(WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), result.data(), static_cast<DWORD>(result.size()), &written, nullptr) && written == result.size(), "Write workspace reader result");
return 0;
}
}