sunshine-sdk/src/platform/windows/nvprefs/undo_file.cpp
ns6089 f245f777f7 Modify and restore NVIDIA control panel settings
Namely:
- Power profile for sunshine.exe
- Global OpenGL/Vulkan DXGI swapchain
2023-07-19 01:14:08 -05:00

155 lines
4.5 KiB
C++

#include "nvprefs_common.h"
#include "undo_file.h"
namespace {
using namespace nvprefs;
DWORD
relax_permissions(HANDLE file_handle) {
PACL old_dacl = nullptr;
safe_hlocal<PSECURITY_DESCRIPTOR> sd;
DWORD status = GetSecurityInfo(file_handle, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nullptr, nullptr, &old_dacl, nullptr, &sd);
if (status != ERROR_SUCCESS) return status;
safe_sid users_sid;
SID_IDENTIFIER_AUTHORITY nt_authorithy = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(&nt_authorithy, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &users_sid)) {
return GetLastError();
}
EXPLICIT_ACCESS ea = {};
ea.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE | DELETE;
ea.grfAccessMode = GRANT_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.ptstrName = (LPTSTR) users_sid.get();
safe_hlocal<PACL> new_dacl;
status = SetEntriesInAcl(1, &ea, old_dacl, &new_dacl);
if (status != ERROR_SUCCESS) return status;
status = SetSecurityInfo(file_handle, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nullptr, nullptr, new_dacl.get(), nullptr);
if (status != ERROR_SUCCESS) return status;
return 0;
}
} // namespace
namespace nvprefs {
std::optional<undo_file_t>
undo_file_t::open_existing_file(std::filesystem::path file_path, bool &access_denied) {
undo_file_t file;
file.file_handle.reset(CreateFileW(file_path.c_str(), GENERIC_READ | DELETE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
if (file.file_handle) {
access_denied = false;
return file;
}
else {
auto last_error = GetLastError();
access_denied = (last_error != ERROR_FILE_NOT_FOUND && last_error != ERROR_PATH_NOT_FOUND);
return std::nullopt;
}
}
std::optional<undo_file_t>
undo_file_t::create_new_file(std::filesystem::path file_path) {
undo_file_t file;
file.file_handle.reset(CreateFileW(file_path.c_str(), GENERIC_WRITE | STANDARD_RIGHTS_ALL, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL));
if (file.file_handle) {
// give GENERIC_READ, GENERIC_WRITE and DELETE permissions to Users group
if (relax_permissions(file.file_handle.get()) != 0) {
error_message("Failed to relax permissions on undo file");
}
return file;
}
else {
return std::nullopt;
}
}
bool
undo_file_t::delete_file() {
if (!file_handle) return false;
FILE_DISPOSITION_INFO delete_file_info = { TRUE };
if (SetFileInformationByHandle(file_handle.get(), FileDispositionInfo, &delete_file_info, sizeof(delete_file_info))) {
file_handle.reset();
return true;
}
else {
return false;
}
}
bool
undo_file_t::write_undo_data(const undo_data_t &undo_data) {
if (!file_handle) return false;
std::string buffer;
try {
buffer = undo_data.write();
}
catch (...) {
error_message("Couldn't serialize undo data");
return false;
}
if (!SetFilePointerEx(file_handle.get(), {}, nullptr, FILE_BEGIN) || !SetEndOfFile(file_handle.get())) {
error_message("Couldn't clear undo file");
return false;
}
DWORD bytes_written = 0;
if (!WriteFile(file_handle.get(), buffer.data(), buffer.size(), &bytes_written, nullptr) || bytes_written != buffer.size()) {
error_message("Couldn't write undo file");
return false;
}
if (!FlushFileBuffers(file_handle.get())) {
error_message("Failed to flush undo file");
}
return true;
}
std::optional<undo_data_t>
undo_file_t::read_undo_data() {
if (!file_handle) return std::nullopt;
LARGE_INTEGER file_size;
if (!GetFileSizeEx(file_handle.get(), &file_size)) {
error_message("Couldn't get undo file size");
return std::nullopt;
}
if ((size_t) file_size.QuadPart > 1024) {
error_message("Undo file size is unexpectedly large, aborting");
return std::nullopt;
}
std::vector<char> buffer(file_size.QuadPart);
DWORD bytes_read = 0;
if (!ReadFile(file_handle.get(), buffer.data(), buffer.size(), &bytes_read, nullptr) || bytes_read != buffer.size()) {
error_message("Couldn't read undo file");
return std::nullopt;
}
undo_data_t undo_data;
try {
undo_data.read(buffer);
}
catch (...) {
error_message("Couldn't parse undo file");
return std::nullopt;
}
return undo_data;
}
} // namespace nvprefs