diff options
Diffstat (limited to 'zenserver')
| -rw-r--r-- | zenserver/experimental/usnjournal.cpp | 351 | ||||
| -rw-r--r-- | zenserver/experimental/usnjournal.h | 69 | ||||
| -rw-r--r-- | zenserver/experimental/vfs.cpp | 3 | ||||
| -rw-r--r-- | zenserver/experimental/vfs.h | 5 | ||||
| -rw-r--r-- | zenserver/testing/launch.cpp | 565 | ||||
| -rw-r--r-- | zenserver/testing/launch.h | 48 | ||||
| -rw-r--r-- | zenserver/xmake.lua | 2 | ||||
| -rw-r--r-- | zenserver/zenserver.cpp | 31 | ||||
| -rw-r--r-- | zenserver/zenserver.rc | 24 |
9 files changed, 25 insertions, 1073 deletions
diff --git a/zenserver/experimental/usnjournal.cpp b/zenserver/experimental/usnjournal.cpp deleted file mode 100644 index 580d71e45..000000000 --- a/zenserver/experimental/usnjournal.cpp +++ /dev/null @@ -1,351 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include <zencore/zencore.h> - -#if ZEN_PLATFORM_WINDOWS - -# include "usnjournal.h" - -# include <zencore/except.h> -# include <zencore/logging.h> -# include <zencore/timer.h> - -ZEN_THIRD_PARTY_INCLUDES_START -# include <atlfile.h> -ZEN_THIRD_PARTY_INCLUDES_END - -# include <filesystem> - -namespace zen { - -UsnJournalReader::UsnJournalReader() -{ -} - -UsnJournalReader::~UsnJournalReader() -{ - delete[] m_JournalReadBuffer; -} - -bool -UsnJournalReader::Initialize(std::filesystem::path VolumePath) -{ - TCHAR VolumeName[MAX_PATH]; - TCHAR VolumePathName[MAX_PATH]; - - { - auto NativePath = VolumePath.native(); - BOOL Success = GetVolumePathName(NativePath.c_str(), VolumePathName, ZEN_ARRAY_COUNT(VolumePathName)); - - if (!Success) - { - zen::ThrowLastError("GetVolumePathName failed"); - } - - Success = GetVolumeNameForVolumeMountPoint(VolumePathName, VolumeName, ZEN_ARRAY_COUNT(VolumeName)); - - if (!Success) - { - zen::ThrowLastError("GetVolumeNameForVolumeMountPoint failed"); - } - - // Chop off trailing slash since we want to open a volume handle, not a handle to the volume root directory - - const size_t VolumeNameLength = wcslen(VolumeName); - - if (VolumeNameLength) - { - VolumeName[VolumeNameLength - 1] = '\0'; - } - } - - m_VolumeHandle = CreateFile(VolumeName, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - nullptr, /* no custom security */ - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - nullptr); /* template */ - - if (m_VolumeHandle == INVALID_HANDLE_VALUE) - { - ThrowLastError("Volume handle open failed"); - } - - // Figure out which file system is in use for volume - - { - WCHAR InfoVolumeName[MAX_PATH + 1]{}; - WCHAR FileSystemName[MAX_PATH + 1]{}; - DWORD MaximumComponentLength = 0; - DWORD FileSystemFlags = 0; - - BOOL Success = GetVolumeInformationByHandleW(m_VolumeHandle, - InfoVolumeName, - MAX_PATH + 1, - NULL, - &MaximumComponentLength, - &FileSystemFlags, - FileSystemName, - ZEN_ARRAY_COUNT(FileSystemName)); - - if (!Success) - { - ThrowLastError("Failed to get volume information"); - } - - ZEN_DEBUG("File system type is {}", WideToUtf8(FileSystemName)); - - if (wcscmp(L"ReFS", FileSystemName) == 0) - { - m_FileSystemType = FileSystemType::ReFS; - } - else if (wcscmp(L"NTFS", FileSystemName) == 0) - { - m_FileSystemType = FileSystemType::NTFS; - } - else - { - // Unknown file system type! - } - } - - // Determine if volume is on fast storage, where seeks aren't so expensive - - { - STORAGE_PROPERTY_QUERY StorageQuery{}; - StorageQuery.PropertyId = StorageDeviceSeekPenaltyProperty; - StorageQuery.QueryType = PropertyStandardQuery; - DWORD BytesWritten; - DEVICE_SEEK_PENALTY_DESCRIPTOR Result{}; - - if (DeviceIoControl(m_VolumeHandle, - IOCTL_STORAGE_QUERY_PROPERTY, - &StorageQuery, - sizeof(StorageQuery), - &Result, - sizeof(Result), - &BytesWritten, - nullptr)) - { - m_IncursSeekPenalty = !!Result.IncursSeekPenalty; - } - } - - // Query Journal - - USN_JOURNAL_DATA_V2 UsnData{}; - - { - DWORD BytesWritten = 0; - - const BOOL Success = - DeviceIoControl(m_VolumeHandle, FSCTL_QUERY_USN_JOURNAL, nullptr, 0, &UsnData, sizeof UsnData, &BytesWritten, nullptr); - - if (!Success) - { - switch (DWORD Error = GetLastError()) - { - case ERROR_JOURNAL_NOT_ACTIVE: - ZEN_INFO("No USN journal active on drive"); - - // TODO: optionally activate USN journal on drive? - - ThrowSystemException(HRESULT_FROM_WIN32(Error), "No USN journal active on drive"); - break; - - default: - ThrowSystemException(HRESULT_FROM_WIN32(Error), "FSCTL_QUERY_USN_JOURNAL failed"); - } - } - } - - m_JournalReadBuffer = new uint8_t[m_ReadBufferSize]; - - // Catch up to USN start - - CAtlFile VolumeRootDir; - HRESULT hRes = - VolumeRootDir.Create(VolumePathName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS); - - if (FAILED(hRes)) - { - ThrowSystemException(hRes, "Failed to open handle to volume root"); - } - - FILE_ID_INFO FileInformation{}; - BOOL Success = GetFileInformationByHandleEx(VolumeRootDir, FileIdInfo, &FileInformation, sizeof FileInformation); - - if (!Success) - { - ThrowLastError("GetFileInformationByHandleEx failed"); - } - - const Frn VolumeRootFrn = FileInformation.FileId; - - // Enumerate MFT (but not for ReFS) - - if (m_FileSystemType == FileSystemType::NTFS) - { - ZEN_INFO("Enumerating MFT for {}", WideToUtf8(VolumePathName)); - - zen::Stopwatch Timer; - uint64_t MftBytesProcessed = 0; - - MFT_ENUM_DATA_V1 MftEnumData{.StartFileReferenceNumber = 0, .LowUsn = 0, .HighUsn = 0, .MinMajorVersion = 2, .MaxMajorVersion = 3}; - - BYTE MftBuffer[64 * 1024 + sizeof(DWORDLONG)]; - DWORD BytesWritten = 0; - - for (;;) - { - Success = DeviceIoControl(m_VolumeHandle, - FSCTL_ENUM_USN_DATA, - &MftEnumData, - sizeof MftEnumData, - MftBuffer, - sizeof MftBuffer, - &BytesWritten, - nullptr); - - if (!Success) - { - DWORD Error = GetLastError(); - - if (Error == ERROR_HANDLE_EOF) - { - break; - } - - ThrowSystemException(HRESULT_FROM_WIN32(Error), "FSCTL_ENUM_USN_DATA failed"); - } - - void* BufferEnd = (void*)&MftBuffer[BytesWritten]; - - // The enumeration call returns the next FRN ahead of the other data in the buffer - MftEnumData.StartFileReferenceNumber = ((DWORDLONG*)MftBuffer)[0]; - - PUSN_RECORD_UNION CommonRecord = PUSN_RECORD_UNION(&((DWORDLONG*)MftBuffer)[1]); - - while (CommonRecord < BufferEnd) - { - switch (CommonRecord->Header.MajorVersion) - { - case 2: - { - USN_RECORD_V2& Record = CommonRecord->V2; - - const Frn FileReference = Record.FileReferenceNumber; - const Frn ParentReference = Record.ParentFileReferenceNumber; - std::wstring_view FileName{Record.FileName, Record.FileNameLength}; - } - break; - case 3: - { - USN_RECORD_V3& Record = CommonRecord->V3; - - const Frn FileReference = Record.FileReferenceNumber; - const Frn ParentReference = Record.ParentFileReferenceNumber; - std::wstring_view FileName{Record.FileName, Record.FileNameLength}; - } - break; - case 4: - { - // This captures file modification ranges. We do not yet support this however - USN_RECORD_V4& Record = CommonRecord->V4; - ZEN_UNUSED(Record); - } - break; - } - - const DWORD RecordLength = CommonRecord->Header.RecordLength; - CommonRecord = PUSN_RECORD_UNION(((uint8_t*)CommonRecord) + RecordLength); - MftBytesProcessed += RecordLength; - } - } - - const auto ElapsedMs = Timer.GetElapsedTimeMs(); - - ZEN_INFO("MFT enumeration of {} completed after {} ({})", - zen::NiceBytes(MftBytesProcessed), - zen::NiceTimeSpanMs(ElapsedMs), - zen::NiceByteRate(MftBytesProcessed, ElapsedMs)); - } - - // Populate by traversal - if (m_FileSystemType == FileSystemType::ReFS) - { - uint64_t FileInfoBuffer[8 * 1024]; - - FILE_INFO_BY_HANDLE_CLASS FibClass = FileIdBothDirectoryRestartInfo; - bool Continue = true; - - while (Continue) - { - Success = GetFileInformationByHandleEx(VolumeRootDir, FibClass, FileInfoBuffer, sizeof FileInfoBuffer); - FibClass = FileIdBothDirectoryInfo; // Set up for next iteration - - uint64_t EntryOffset = 0; - - if (!Success) - { - // Report failure? - - break; - } - - do - { - const FILE_ID_BOTH_DIR_INFO* DirInfo = - reinterpret_cast<const FILE_ID_BOTH_DIR_INFO*>(reinterpret_cast<const uint8_t*>(FileInfoBuffer) + EntryOffset); - - const uint64_t NextOffset = DirInfo->NextEntryOffset; - - if (NextOffset == 0) - { - if (EntryOffset == 0) - { - // First and last - end of iteration - Continue = false; - } - break; - } - - if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - // TODO Directory - } - else if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DEVICE) - { - // TODO Device - } - else - { - // TODO File - } - - EntryOffset += DirInfo->NextEntryOffset; - } while (EntryOffset); - } - } - - // Initialize journal reading - - m_ReadUsnJournalData = {.StartUsn = UsnData.FirstUsn, - .ReasonMask = USN_REASON_BASIC_INFO_CHANGE | USN_REASON_CLOSE | USN_REASON_DATA_EXTEND | - USN_REASON_DATA_OVERWRITE | USN_REASON_DATA_TRUNCATION | USN_REASON_FILE_CREATE | - USN_REASON_FILE_DELETE | USN_REASON_HARD_LINK_CHANGE | USN_REASON_RENAME_NEW_NAME | - USN_REASON_RENAME_OLD_NAME | USN_REASON_REPARSE_POINT_CHANGE, - .ReturnOnlyOnClose = true, - .Timeout = 0, - .BytesToWaitFor = 0, - .UsnJournalID = UsnData.UsnJournalID, - .MinMajorVersion = 0, - .MaxMajorVersion = 0}; - - return false; -} - -} // namespace zen - -#endif // ZEN_PLATFORM_WINDOWS diff --git a/zenserver/experimental/usnjournal.h b/zenserver/experimental/usnjournal.h deleted file mode 100644 index 910eb7d06..000000000 --- a/zenserver/experimental/usnjournal.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#if ZEN_PLATFORM_WINDOWS - -# include <zencore/windows.h> -# include <zencore/zencore.h> - -ZEN_THIRD_PARTY_INCLUDES_START -# include <winioctl.h> -ZEN_THIRD_PARTY_INCLUDES_END - -# include <filesystem> - -namespace zen { - -class UsnJournalReader -{ -public: - UsnJournalReader(); - ~UsnJournalReader(); - - bool Initialize(std::filesystem::path VolumePath); - -private: - void* m_VolumeHandle; - READ_USN_JOURNAL_DATA_V1 m_ReadUsnJournalData; - bool m_IncursSeekPenalty = true; - - uint8_t* m_JournalReadBuffer = nullptr; - uint64_t m_ReadBufferSize = 64 * 1024; - - struct Frn - { - uint8_t IdBytes[16]; - - Frn() = default; - - Frn(const FILE_ID_128& Rhs) { memcpy(IdBytes, Rhs.Identifier, sizeof IdBytes); } - Frn& operator=(const FILE_ID_128& Rhs) { memcpy(IdBytes, Rhs.Identifier, sizeof IdBytes); } - - Frn(const uint64_t& Rhs) - { - memcpy(IdBytes, &Rhs, sizeof Rhs); - memset(&IdBytes[8], 0, 8); - } - - Frn& operator=(const uint64_t& Rhs) - { - memcpy(IdBytes, &Rhs, sizeof Rhs); - memset(&IdBytes[8], 0, 8); - } - - std::strong_ordering operator<=>(const Frn&) const = default; - }; - - enum class FileSystemType - { - ReFS, - NTFS - }; - - FileSystemType m_FileSystemType = FileSystemType::NTFS; -}; - -} // namespace zen - -#endif // ZEN_PLATFORM_WINDOWS diff --git a/zenserver/experimental/vfs.cpp b/zenserver/experimental/vfs.cpp deleted file mode 100644 index 1af9d70a7..000000000 --- a/zenserver/experimental/vfs.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "vfs.h" diff --git a/zenserver/experimental/vfs.h b/zenserver/experimental/vfs.h deleted file mode 100644 index 1aeefe481..000000000 --- a/zenserver/experimental/vfs.h +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include <zencore/zencore.h> diff --git a/zenserver/testing/launch.cpp b/zenserver/testing/launch.cpp deleted file mode 100644 index b26f9e437..000000000 --- a/zenserver/testing/launch.cpp +++ /dev/null @@ -1,565 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "launch.h" - -#if ZEN_WITH_EXEC_SERVICES - -# include <zencore/compactbinary.h> -# include <zencore/compactbinarybuilder.h> -# include <zencore/compress.h> -# include <zencore/filesystem.h> -# include <zencore/fmtutils.h> -# include <zencore/iobuffer.h> -# include <zencore/iohash.h> -# include <zencore/logging.h> -# include <zencore/windows.h> -# include <zenstore/cidstore.h> - -ZEN_THIRD_PARTY_INCLUDES_START -# include <AccCtrl.h> -# include <AclAPI.h> -# include <UserEnv.h> -# include <atlbase.h> -# include <sddl.h> -ZEN_THIRD_PARTY_INCLUDES_END -# pragma comment(lib, "UserEnv.lib") - -# include <filesystem> -# include <span> - -using namespace std::literals; - -namespace zen { - -struct BasicJob -{ -public: - BasicJob() = default; - ~BasicJob(); - - void SetWorkingDirectory(const std::filesystem::path& WorkingDirectory) { m_WorkingDirectory = WorkingDirectory; } - bool SpawnJob(std::filesystem::path ExePath, std::wstring CommandLine); - bool Wait(uint32_t TimeoutMs = ~0); - int ExitCode(); - -private: - std::filesystem::path m_WorkingDirectory; - int m_ProcessId = 0; - CHandle m_ProcessHandle; -}; - -BasicJob::~BasicJob() -{ - Wait(); -} - -bool -BasicJob::SpawnJob(std::filesystem::path ExePath, std::wstring CommandLine) -{ - STARTUPINFOEX StartupInfo = {sizeof(STARTUPINFOEX)}; - PROCESS_INFORMATION ProcessInfo{}; - - std::wstring ExePathNative = ExePath.native(); - std::wstring WorkingDirNative = m_WorkingDirectory.native(); - - BOOL Created = ::CreateProcess(ExePathNative.data() /* ApplicationName */, - CommandLine.data() /* Command Line */, - nullptr /* Process Attributes */, - nullptr /* Security Attributes */, - FALSE /* InheritHandles */, - 0 /* Flags */, - nullptr /* Environment */, - WorkingDirNative.data() /* Current Directory */, - (LPSTARTUPINFO)&StartupInfo, - &ProcessInfo); - - if (!Created) - { - throw std::system_error(::GetLastError(), std::system_category(), fmt::format("Failed to create process '{}'", ExePath).c_str()); - } - - m_ProcessId = ProcessInfo.dwProcessId; - m_ProcessHandle.Attach(ProcessInfo.hProcess); - ::CloseHandle(ProcessInfo.hThread); - - ZEN_INFO("Created process {}", m_ProcessId); - - return true; -} - -bool -BasicJob::Wait(uint32_t TimeoutMs) -{ - if (!m_ProcessHandle) - { - return true; - } - - DWORD WaitResult = WaitForSingleObject(m_ProcessHandle, TimeoutMs); - - if (WaitResult == WAIT_TIMEOUT) - { - return false; - } - - if (WaitResult == WAIT_OBJECT_0) - { - return true; - } - - throw std::runtime_error("Failed wait on process handle"); -} - -int -BasicJob::ExitCode() -{ - DWORD Ec = 0; - BOOL Success = GetExitCodeProcess(m_ProcessHandle, &Ec); - - if (!Success) - { - ZEN_WARN("failed getting exit code"); - } - - if (Ec == STILL_ACTIVE) - { - ZEN_WARN("getting exit code but process is STILL_ACTIVE"); - } - - return gsl::narrow_cast<int>(Ec); -} - -//////////////////////////////////////////////////////////////////////////////// - -struct SandboxedJob -{ - SandboxedJob() = default; - ~SandboxedJob() = default; - - void SetWorkingDirectory(const std::filesystem::path& WorkingDirectory) { m_WorkingDirectory = WorkingDirectory; } - void Initialize(std::string_view AppContainerId); - bool SpawnJob(std::filesystem::path ExePath); - void AddWhitelistFile(const std::filesystem::path& FilePath) { m_WhitelistFiles.push_back(FilePath); } - -private: - bool GrantNamedObjectAccess(PWSTR Name, SE_OBJECT_TYPE Type, ACCESS_MASK AccessMask, bool Recursive); - - std::filesystem::path m_WorkingDirectory; - std::vector<std::filesystem::path> m_WhitelistFiles; - std::vector<std::wstring> m_WhitelistRegistryKeys; - PSID m_AppContainerSid = nullptr; - bool m_IsInitialized = false; -}; - -bool -SandboxedJob::GrantNamedObjectAccess(PWSTR ObjectName, SE_OBJECT_TYPE ObjectType, ACCESS_MASK AccessMask, bool Recursive) -{ - DWORD Status; - PACL NewAcl = nullptr; - - DWORD grfInhericance = 0; - - if (Recursive) - { - grfInhericance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; - } - - EXPLICIT_ACCESS Access{.grfAccessPermissions = AccessMask, - .grfAccessMode = GRANT_ACCESS, - .grfInheritance = grfInhericance, - .Trustee = {.pMultipleTrustee = nullptr, - .MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE, - .TrusteeForm = TRUSTEE_IS_SID, - .TrusteeType = TRUSTEE_IS_GROUP, - .ptstrName = (PWSTR)m_AppContainerSid}}; - - PACL OldAcl = nullptr; - - Status = GetNamedSecurityInfo(ObjectName /* ObjectName */, - ObjectType /* ObjectType */, - DACL_SECURITY_INFORMATION /* SecurityInfo */, - nullptr /* ppsidOwner */, - nullptr /* ppsidGroup */, - &OldAcl /* ppDacl */, - nullptr /* ppSacl */, - nullptr /* ppSecurityDescriptor */); - if (Status != ERROR_SUCCESS) - return false; - - Status = SetEntriesInAcl(1 /* CountOfExplicitEntries */, &Access /* pListOfExplicitEntries */, OldAcl, &NewAcl); - if (Status != ERROR_SUCCESS) - return false; - - Status = SetNamedSecurityInfo(ObjectName /* ObjectName */, - ObjectType /* ObjectType */, - DACL_SECURITY_INFORMATION /*SecurityInfo */, - nullptr /* psidOwner */, - nullptr /* psidGroup */, - NewAcl /* pDacl */, - nullptr /* pSacl */); - if (NewAcl) - ::LocalFree(NewAcl); - - return Status == ERROR_SUCCESS; -} - -void -SandboxedJob::Initialize(std::string_view AppContainerId) -{ - if (m_IsInitialized) - { - return; - } - - std::wstring ContainerName = zen::Utf8ToWide(AppContainerId); - - HRESULT hRes = ::CreateAppContainerProfile(ContainerName.c_str(), - ContainerName.c_str() /* Display Name */, - ContainerName.c_str() /* Description */, - nullptr /* Capabilities */, - 0 /* Capability Count */, - &m_AppContainerSid); - - if (FAILED(hRes)) - { - hRes = ::DeriveAppContainerSidFromAppContainerName(ContainerName.c_str(), &m_AppContainerSid); - - if (FAILED(hRes)) - { - ZEN_ERROR("Failed creating app container SID"); - } - } - - // Debugging context - - PWSTR Str = nullptr; - ::ConvertSidToStringSid(m_AppContainerSid, &Str); - - ZEN_INFO("AppContainer SID : '{}'", WideToUtf8(Str)); - - PWSTR Path = nullptr; - if (SUCCEEDED(::GetAppContainerFolderPath(Str, &Path))) - { - ZEN_INFO("AppContainer folder: '{}'", WideToUtf8(Path)); - - ::CoTaskMemFree(Path); - } - ::LocalFree(Str); - - m_IsInitialized = true; -} - -bool -SandboxedJob::SpawnJob(std::filesystem::path ExePath) -{ - // Build process attributes - - SECURITY_CAPABILITIES Sc = {0}; - Sc.AppContainerSid = m_AppContainerSid; - - STARTUPINFOEX StartupInfo = {sizeof(STARTUPINFOEX)}; - PROCESS_INFORMATION ProcessInfo{}; - SIZE_T Size = 0; - - ::InitializeProcThreadAttributeList(nullptr, 1, 0, &Size); - - auto AttrBuffer = std::make_unique<uint8_t[]>(Size); - StartupInfo.lpAttributeList = reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(AttrBuffer.get()); - - if (!::InitializeProcThreadAttributeList(StartupInfo.lpAttributeList, 1, 0, &Size)) - { - return false; - } - - if (!::UpdateProcThreadAttribute(StartupInfo.lpAttributeList, - 0, - PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, - &Sc, - sizeof Sc, - nullptr, - nullptr)) - { - return false; - } - - // Set up security for files/folders/registry - - for (const std::filesystem::path& File : m_WhitelistFiles) - { - std::wstring NativeFileName = File.native(); - GrantNamedObjectAccess(NativeFileName.data(), SE_FILE_OBJECT, FILE_ALL_ACCESS, true); - } - - for (std::wstring& RegKey : m_WhitelistRegistryKeys) - { - GrantNamedObjectAccess(RegKey.data(), SE_REGISTRY_WOW64_32KEY, KEY_ALL_ACCESS, true); - } - - std::wstring ExePathNative = ExePath.native(); - std::wstring WorkingDirNative = m_WorkingDirectory.native(); - - BOOL Created = ::CreateProcess(nullptr /* ApplicationName */, - ExePathNative.data() /* Command line */, - nullptr /* Process Attributes */, - nullptr /* Security Attributes */, - FALSE /* InheritHandles */, - EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE /* Flags */, - nullptr /* Environment */, - WorkingDirNative.data() /* Current Directory */, - (LPSTARTUPINFO)&StartupInfo, - &ProcessInfo); - - DeleteProcThreadAttributeList(StartupInfo.lpAttributeList); - - if (!Created) - { - return false; - } - - ZEN_INFO("Created process {}", ProcessInfo.dwProcessId); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// - -HttpLaunchService::HttpLaunchService(CidStore& Store, const std::filesystem::path& SandboxBaseDir) -: m_Log(logging::Get("exec")) -, m_CidStore(Store) -, m_SandboxPath(SandboxBaseDir) -{ - m_Router.AddPattern("job", "([[:digit:]]+)"); - - m_Router.RegisterRoute( - "jobs/{job}", - [this](HttpRouterRequest& Req) { - HttpServerRequest& HttpReq = Req.ServerRequest(); - - switch (HttpReq.RequestVerb()) - { - case HttpVerb::kGet: - break; - - case HttpVerb::kPost: - break; - - default: - break; - } - }, - HttpVerb::kGet | HttpVerb::kPost); - - // Experimental - -# if 0 - m_Router.RegisterRoute( - "jobs/sandbox", - [this](HttpRouterRequest& Req) { - HttpServerRequest& HttpReq = Req.ServerRequest(); - - switch (HttpReq.RequestVerb()) - { - case HttpVerb::kGet: - break; - - case HttpVerb::kPost: - { - SandboxedJob Job; - Job.Initialize("zen_test"); - Job.SetWorkingDirectory("c:\\temp\\sandbox1"); - Job.AddWhitelistFile("c:\\temp\\sandbox1"); - Job.SpawnJob("c:\\windows\\system32\\cmd.exe"); - } - break; - - default: - break; - } - }, - HttpVerb::kGet | HttpVerb::kPost); -# endif - - m_Router.RegisterRoute( - "jobs/prep", - [this](HttpRouterRequest& Req) { - HttpServerRequest& HttpReq = Req.ServerRequest(); - - switch (HttpReq.RequestVerb()) - { - case HttpVerb::kPost: - { - // This operation takes the proposed job spec and identifies which - // chunks are not present on this server. This list is then returned in - // the "need" list in the response - - IoBuffer Payload = HttpReq.ReadPayload(); - CbObject RequestObject = LoadCompactBinaryObject(Payload); - - std::vector<IoHash> NeedList; - - for (auto Entry : RequestObject["files"sv]) - { - CbObjectView Ob = Entry.AsObjectView(); - - const IoHash FileHash = Ob["hash"sv].AsHash(); - - if (!m_CidStore.FindChunkByCid(FileHash)) - { - ZEN_DEBUG("NEED: {} {} {}", FileHash, Ob["file"sv].AsString(), Ob["size"sv].AsUInt64()); - - NeedList.push_back(FileHash); - } - } - - CbObjectWriter Cbo; - Cbo.BeginArray("need"); - - for (const IoHash& Hash : NeedList) - { - Cbo << Hash; - } - - Cbo.EndArray(); - CbObject Response = Cbo.Save(); - - return HttpReq.WriteResponse(HttpResponseCode::OK, Response); - } - break; - - default: - break; - } - }, - HttpVerb::kPost); - - m_Router.RegisterRoute( - "jobs", - [this](HttpRouterRequest& Req) { - HttpServerRequest& HttpReq = Req.ServerRequest(); - - switch (HttpReq.RequestVerb()) - { - case HttpVerb::kGet: - break; - - case HttpVerb::kPost: - { - IoBuffer Payload = HttpReq.ReadPayload(); - CbObject RequestObject = LoadCompactBinaryObject(Payload); - - bool AllOk = true; - - std::vector<IoHash> NeedList; - - std::filesystem::path SandboxDir{CreateNewSandbox()}; - - ZEN_DEBUG("setting up job in sandbox '{}'", SandboxDir); - - zen::DeleteDirectories(SandboxDir); - zen::CreateDirectories(SandboxDir); - - for (auto Entry : RequestObject["files"sv]) - { - CbObjectView Ob = Entry.AsObjectView(); - - std::string_view FileName = Ob["file"sv].AsString(); - const IoHash FileHash = Ob["hash"sv].AsHash(); - uint64_t FileSize = Ob["size"sv].AsUInt64(); - - if (IoBuffer Chunk = m_CidStore.FindChunkByCid(FileHash); !Chunk) - { - ZEN_DEBUG("MISSING: {} {} {}", FileHash, FileName, FileSize); - AllOk = false; - - NeedList.push_back(FileHash); - } - else - { - std::filesystem::path FullPath = SandboxDir / FileName; - - IoHash RawHash; - uint64_t RawSize; - CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Chunk), RawHash, RawSize); - ZEN_ASSERT(Compressed); - ZEN_ASSERT(FileHash == RawHash); - CompositeBuffer CompositeBuffer = Compressed.DecompressToComposite(); - std::span<const SharedBuffer> Segments = CompositeBuffer.GetSegments(); - std::vector<IoBuffer> Chunks(Segments.size()); - std::vector<IoBuffer*> ChunkPtrs(Segments.size()); - for (size_t Index = 0; Index < Segments.size(); ++Index) - { - Chunks[Index] = std::move(Segments[Index].AsIoBuffer()); - ChunkPtrs[Index] = &Chunks[Index]; - } - - zen::WriteFile(FullPath, ChunkPtrs.data(), ChunkPtrs.size()); - } - } - - if (!AllOk) - { - // TODO: Could report all the missing pieces in the response here - return HttpReq.WriteResponse(HttpResponseCode::NotFound); - } - - std::string Executable8{RequestObject["cmd"].AsString()}; - std::string Args8{RequestObject["args"].AsString()}; - - std::wstring Executable = Utf8ToWide(Executable8); - std::wstring Args = Utf8ToWide(Args8); - - ZEN_DEBUG("spawning job in sandbox '{}': '{}' '{}'", SandboxDir, Executable8, Args8); - - std::filesystem::path ExeName = SandboxDir / Executable; - - BasicJob Job; - Job.SetWorkingDirectory(SandboxDir); - Job.SpawnJob(ExeName, Args); - Job.Wait(); - - CbObjectWriter Response; - - Response << "exitcode" << Job.ExitCode(); - - return HttpReq.WriteResponse(HttpResponseCode::OK, Response.Save()); - } - break; - - default: - break; - } - }, - HttpVerb::kGet | HttpVerb::kPost); -} - -HttpLaunchService::~HttpLaunchService() -{ -} - -const char* -HttpLaunchService::BaseUri() const -{ - return "/exec/"; -} - -void -HttpLaunchService::HandleRequest(HttpServerRequest& Request) -{ - if (m_Router.HandleRequest(Request) == false) - { - ZEN_WARN("No route found for {0}", Request.RelativeUri()); - } -} - -std::filesystem::path -HttpLaunchService::CreateNewSandbox() -{ - std::string UniqueId = std::to_string(++m_SandboxCount); - std::filesystem::path Path = m_SandboxPath / UniqueId; - zen::CreateDirectories(Path); - return Path; -} - -} // namespace zen - -#endif // ZEN_WITH_EXEC_SERVICES diff --git a/zenserver/testing/launch.h b/zenserver/testing/launch.h deleted file mode 100644 index f44618bfb..000000000 --- a/zenserver/testing/launch.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include <zencore/zencore.h> - -#if !defined(ZEN_WITH_EXEC_SERVICES) -# define ZEN_WITH_EXEC_SERVICES ZEN_PLATFORM_WINDOWS -#endif - -#if ZEN_WITH_EXEC_SERVICES - -# include <zencore/logging.h> -# include <zenhttp/httpserver.h> - -# include <filesystem> - -namespace zen { - -class CidStore; - -/** - * Process launcher for test executables - */ -class HttpLaunchService : public HttpService -{ -public: - HttpLaunchService(CidStore& Store, const std::filesystem::path& SandboxBaseDir); - ~HttpLaunchService(); - - virtual const char* BaseUri() const override; - virtual void HandleRequest(HttpServerRequest& Request) override; - -private: - inline spdlog::logger& Log() { return m_Log; } - - spdlog::logger& m_Log; - HttpRequestRouter m_Router; - CidStore& m_CidStore; - std::filesystem::path m_SandboxPath; - std::atomic<int> m_SandboxCount{0}; - - std::filesystem::path CreateNewSandbox(); -}; - -} // namespace zen - -#endif // ZEN_WITH_EXEC_SERVICES diff --git a/zenserver/xmake.lua b/zenserver/xmake.lua index 2174ad679..8b18bf9f9 100644 --- a/zenserver/xmake.lua +++ b/zenserver/xmake.lua @@ -16,6 +16,7 @@ target("zenserver") add_ldflags("/subsystem:console,5.02") add_ldflags("/MANIFEST:EMBED") add_ldflags("/LTCG") + add_files("zenserver.rc") else remove_files("windows/**") end @@ -30,7 +31,6 @@ target("zenserver") add_syslinks("bsm") end - add_options("vfs") add_options("compute") add_options("exec") diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp index c1e82f404..526e27152 100644 --- a/zenserver/zenserver.cpp +++ b/zenserver/zenserver.cpp @@ -105,13 +105,11 @@ ZEN_THIRD_PARTY_INCLUDES_END #include "cidstore.h" #include "compute/function.h" #include "diag/diagsvcs.h" -#include "experimental/usnjournal.h" #include "frontend/frontend.h" #include "monitoring/httpstats.h" #include "monitoring/httpstatus.h" #include "projectstore.h" #include "testing/httptest.h" -#include "testing/launch.h" #include "upstream/upstream.h" #include "zenstore/gc.h" @@ -266,23 +264,6 @@ public: m_ProjectStore = new zen::ProjectStore(*m_CidStore, m_DataRoot / "projects", m_GcManager); m_HttpProjectService.reset(new zen::HttpProjectService{*m_CidStore, m_ProjectStore}); -#if ZEN_WITH_EXEC_SERVICES - - if (ServerOptions.ExecServiceEnabled) - { - ZEN_INFO("instantiating exec service"); - - std::filesystem::path SandboxDir = m_DataRoot / "exec" / "sandbox"; - zen::CreateDirectories(SandboxDir); - m_HttpLaunchService = std::make_unique<zen::HttpLaunchService>(*m_CidStore, SandboxDir); - } - else - { - ZEN_INFO("NOT instantiating exec services"); - } - -#endif // ZEN_WITH_EXEC_SERVICES - #if ZEN_WITH_COMPUTE_SERVICES if (ServerOptions.ComputeServiceEnabled) { @@ -319,15 +300,6 @@ public: m_Http->RegisterService(*m_CidService); -#if ZEN_WITH_EXEC_SERVICES - if (ServerOptions.ExecServiceEnabled) - { - if (m_HttpLaunchService != nullptr) - { - m_Http->RegisterService(*m_HttpLaunchService); - } - } -#endif // ZEN_WITH_EXEC_SERVICES #if ZEN_WITH_COMPUTE_SERVICES if (ServerOptions.ComputeServiceEnabled) { @@ -592,9 +564,6 @@ private: std::unique_ptr<zen::HttpStructuredCacheService> m_StructuredCacheService; zen::HttpAdminService m_AdminService{m_GcScheduler}; zen::HttpHealthService m_HealthService; -#if ZEN_WITH_EXEC_SERVICES - std::unique_ptr<zen::HttpLaunchService> m_HttpLaunchService; -#endif // ZEN_WITH_EXEC_SERVICES #if ZEN_WITH_COMPUTE_SERVICES std::unique_ptr<zen::HttpFunctionService> m_HttpFunctionService; #endif // ZEN_WITH_COMPUTE_SERVICES diff --git a/zenserver/zenserver.rc b/zenserver/zenserver.rc index c063436ef..6d31e2c6e 100644 --- a/zenserver/zenserver.rc +++ b/zenserver/zenserver.rc @@ -2,6 +2,8 @@ // #include "resource.h" +#include "zencore/config.h" + #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // @@ -79,3 +81,25 @@ END ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED +VS_VERSION_INFO VERSIONINFO +FILEVERSION ZEN_CFG_VERSION_MAJOR,ZEN_CFG_VERSION_MINOR,ZEN_CFG_VERSION_ALTER,0 +PRODUCTVERSION ZEN_CFG_VERSION_MAJOR,ZEN_CFG_VERSION_MINOR,ZEN_CFG_VERSION_ALTER,0 +{ + BLOCK "StringFileInfo" + { + BLOCK "040904b0" + { + VALUE "CompanyName", "Epic Games Inc\0" + VALUE "FileDescription", "Local Storage Service for Unreal Engine\0" + VALUE "FileVersion", ZEN_CFG_VERSION "\0" + VALUE "LegalCopyright", "Copyright Epic Games Inc. All Rights Reserved\0" + VALUE "OriginalFilename", "zenserver.exe\0" + VALUE "ProductName", "Zen Storage Server\0" + VALUE "ProductVersion", ZEN_CFG_VERSION_BUILD_STRING_FULL "\0" + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x409, 1200 + } +} |