mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-05-12 04:03:53 +00:00
146 lines
2.9 KiB
C++
146 lines
2.9 KiB
C++
|
|
#include "stdafx.h"
|
||
|
|
|
||
|
|
#include "FileUtils.h"
|
||
|
|
|
||
|
|
#include "StringUtils.h"
|
||
|
|
|
||
|
|
#include <io.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
|
||
|
|
namespace ServerRuntime
|
||
|
|
{
|
||
|
|
namespace FileUtils
|
||
|
|
{
|
||
|
|
namespace
|
||
|
|
{
|
||
|
|
static std::wstring ToWidePath(const std::string &filePath)
|
||
|
|
{
|
||
|
|
return StringUtils::Utf8ToWide(filePath);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
unsigned long long GetCurrentUtcFileTime()
|
||
|
|
{
|
||
|
|
FILETIME now = {};
|
||
|
|
GetSystemTimeAsFileTime(&now);
|
||
|
|
|
||
|
|
ULARGE_INTEGER value = {};
|
||
|
|
value.LowPart = now.dwLowDateTime;
|
||
|
|
value.HighPart = now.dwHighDateTime;
|
||
|
|
return value.QuadPart;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ReadTextFile(const std::string &filePath, std::string *outText)
|
||
|
|
{
|
||
|
|
if (outText == nullptr)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
outText->clear();
|
||
|
|
|
||
|
|
const std::wstring widePath = ToWidePath(filePath);
|
||
|
|
if (widePath.empty())
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
FILE *inFile = nullptr;
|
||
|
|
if (_wfopen_s(&inFile, widePath.c_str(), L"rb") != 0 || inFile == nullptr)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (fseek(inFile, 0, SEEK_END) != 0)
|
||
|
|
{
|
||
|
|
fclose(inFile);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
long fileSize = ftell(inFile);
|
||
|
|
if (fileSize < 0)
|
||
|
|
{
|
||
|
|
fclose(inFile);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (fseek(inFile, 0, SEEK_SET) != 0)
|
||
|
|
{
|
||
|
|
fclose(inFile);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (fileSize == 0)
|
||
|
|
{
|
||
|
|
fclose(inFile);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
outText->resize((size_t)fileSize);
|
||
|
|
size_t bytesRead = fread(&(*outText)[0], 1, (size_t)fileSize, inFile);
|
||
|
|
fclose(inFile);
|
||
|
|
|
||
|
|
if (bytesRead != (size_t)fileSize)
|
||
|
|
{
|
||
|
|
outText->clear();
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool WriteTextFileAtomic(const std::string &filePath, const std::string &text)
|
||
|
|
{
|
||
|
|
const std::wstring widePath = ToWidePath(filePath);
|
||
|
|
if (widePath.empty())
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
const std::wstring tmpPath = widePath + L".tmp";
|
||
|
|
|
||
|
|
FILE *outFile = nullptr;
|
||
|
|
if (_wfopen_s(&outFile, tmpPath.c_str(), L"wb") != 0 || outFile == nullptr)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!text.empty())
|
||
|
|
{
|
||
|
|
size_t bytesWritten = fwrite(text.data(), 1, text.size(), outFile);
|
||
|
|
if (bytesWritten != text.size())
|
||
|
|
{
|
||
|
|
fclose(outFile);
|
||
|
|
DeleteFileW(tmpPath.c_str());
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (fflush(outFile) != 0 || _commit(_fileno(outFile)) != 0)
|
||
|
|
{
|
||
|
|
fclose(outFile);
|
||
|
|
DeleteFileW(tmpPath.c_str());
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
fclose(outFile);
|
||
|
|
|
||
|
|
DWORD attrs = GetFileAttributesW(widePath.c_str());
|
||
|
|
if (attrs != INVALID_FILE_ATTRIBUTES && ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0))
|
||
|
|
{
|
||
|
|
// Replace the destination without deleting the last known-good file first.
|
||
|
|
if (ReplaceFileW(widePath.c_str(), tmpPath.c_str(), nullptr, REPLACEFILE_IGNORE_MERGE_ERRORS, nullptr, nullptr))
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (MoveFileExW(tmpPath.c_str(), widePath.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH))
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Keep the temp file on failure so the original file remains recoverable and the caller can inspect the write result.
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|