diff --git a/src/common/byte_stream.cpp b/src/common/byte_stream.cpp index 1ae2d82b7..4de50028a 100644 --- a/src/common/byte_stream.cpp +++ b/src/common/byte_stream.cpp @@ -262,9 +262,9 @@ protected: class AtomicUpdatedFileByteStream : public FileByteStream { public: - AtomicUpdatedFileByteStream(FILE* pFile, const char* originalFileName, const char* temporaryFileName) - : FileByteStream(pFile), m_committed(false), m_discarded(false), m_originalFileName(originalFileName), - m_temporaryFileName(temporaryFileName) + AtomicUpdatedFileByteStream(FILE* pFile, std::string originalFileName, std::string temporaryFileName) + : FileByteStream(pFile), m_committed(false), m_discarded(false), m_originalFileName(std::move(originalFileName)), + m_temporaryFileName(std::move(temporaryFileName)) { } @@ -272,7 +272,7 @@ public: { if (m_discarded) { -#if _WIN32 +#if defined(_WIN32) && !defined(_UWP) // delete the temporary file if (!DeleteFileW(StringUtil::UTF8StringToWideString(m_temporaryFileName).c_str())) { @@ -280,6 +280,14 @@ public: "AtomicUpdatedFileByteStream::~AtomicUpdatedFileByteStream(): Failed to delete temporary file '%s'", m_temporaryFileName.c_str()); } +#elif defined(_UWP) + // delete the temporary file + if (!DeleteFileFromAppW(StringUtil::UTF8StringToWideString(m_temporaryFileName).c_str())) + { + Log_WarningPrintf( + "AtomicUpdatedFileByteStream::~AtomicUpdatedFileByteStream(): Failed to delete temporary file '%s'", + m_temporaryFileName.c_str()); + } #else // delete the temporary file if (remove(m_temporaryFileName.c_str()) < 0) @@ -315,7 +323,7 @@ public: fflush(m_pFile); -#ifdef _WIN32 +#if defined(_WIN32) && !defined(_UWP) // move the atomic file name to the original file name if (!MoveFileExW(StringUtil::UTF8StringToWideString(m_temporaryFileName).c_str(), StringUtil::UTF8StringToWideString(m_originalFileName).c_str(), MOVEFILE_REPLACE_EXISTING)) @@ -328,6 +336,17 @@ public: { m_committed = true; } +#elif defined(_UWP) + if (!FileSystem::RenamePath(m_temporaryFileName.c_str(), m_originalFileName.c_str())) + { + Log_WarningPrintf("AtomicUpdatedFileByteStream::Commit(): Failed to rename temporary file '%s' to '%s'", + m_temporaryFileName.c_str(), m_originalFileName.c_str()); + m_discarded = true; + } + else + { + m_committed = true; + } #else // move the atomic file name to the original file name if (rename(m_temporaryFileName.c_str(), m_originalFileName.c_str()) < 0) @@ -1000,6 +1019,7 @@ std::unique_ptr ByteStream_OpenFileStream(const char* fileName, u32 { DebugAssert(openMode & (BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_WRITE)); +#ifndef _UWP // generate the temporary file name u32 fileNameLength = static_cast(std::strlen(fileName)); char* temporaryFileName = (char*)alloca(fileNameLength + 8); @@ -1008,6 +1028,22 @@ std::unique_ptr ByteStream_OpenFileStream(const char* fileName, u32 // fill in random characters _mktemp_s(temporaryFileName, fileNameLength + 8); const std::wstring wideTemporaryFileName(StringUtil::UTF8StringToWideString(temporaryFileName)); +#else + // On UWP, preserve the extension, as it affects permissions. + std::string temporaryFileName; + const char* extension = std::strrchr(fileName, '.'); + if (extension) + temporaryFileName.append(fileName, extension - fileName); + else + temporaryFileName.append(fileName); + + temporaryFileName.append("_XXXXXX"); + _mktemp_s(temporaryFileName.data(), temporaryFileName.size() + 1); + if (extension) + temporaryFileName.append(extension); + + const std::wstring wideTemporaryFileName(StringUtil::UTF8StringToWideString(temporaryFileName)); +#endif // massive hack here DWORD desiredAccess = GENERIC_WRITE; diff --git a/src/common/file_system.cpp b/src/common/file_system.cpp index 799558a1b..bb64d9ffb 100644 --- a/src/common/file_system.cpp +++ b/src/common/file_system.cpp @@ -1794,7 +1794,17 @@ bool FileSystem::RenamePath(const char* OldPath, const char* NewPath) return false; } #else - if (!ReplaceFileFromAppW(old_wpath.c_str(), new_wpath.c_str(), nullptr, 0, nullptr, nullptr)) + // try moving if it doesn't exist, since ReplaceFile fails on non-existing destinations + if (WrapGetFileAttributes(new_wpath.c_str()) != INVALID_FILE_ATTRIBUTES) + { + if (!DeleteFileFromAppW(new_wpath.c_str())) + { + Log_ErrorPrintf("DeleteFileFromAppW('%s') failed: %08X", new_wpath.c_str(), GetLastError()); + return false; + } + } + + if (!MoveFileFromAppW(old_wpath.c_str(), new_wpath.c_str())) { Log_ErrorPrintf("MoveFileFromAppW('%s', '%s') failed: %08X", OldPath, NewPath, GetLastError()); return false;