mirror of
https://github.com/thinkonmay/sunshine-sdk.git
synced 2026-01-08 12:38:20 +00:00
155 lines
4.5 KiB
C++
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
|