Skip to content

Commit

Permalink
Experimental file renaming without closing handle.
Browse files Browse the repository at this point in the history
  • Loading branch information
AdmiralCurtiss committed Aug 24, 2020
1 parent c36ae84 commit 8b01027
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 8 deletions.
2 changes: 2 additions & 0 deletions Source/Core/Common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ add_library(common
Event.h
File.cpp
File.h
FileByHandle.cpp
FileByHandle.h
FileSearch.cpp
FileSearch.h
FileUtil.cpp
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Common/Common.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
<ClInclude Include="ENetUtil.h" />
<ClInclude Include="Event.h" />
<ClInclude Include="File.h" />
<ClInclude Include="FileByHandle.h" />
<ClInclude Include="FileSearch.h" />
<ClInclude Include="FileUtil.h" />
<ClInclude Include="FixedSizeQueue.h" />
Expand Down Expand Up @@ -196,6 +197,7 @@
<ClCompile Include="DynamicLibrary.cpp" />
<ClCompile Include="ENetUtil.cpp" />
<ClCompile Include="File.cpp" />
<ClCompile Include="FileByHandle.cpp" />
<ClCompile Include="FileSearch.cpp" />
<ClCompile Include="FileUtil.cpp" />
<ClCompile Include="FloatUtils.cpp" />
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Common/Common.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@
<Filter>GL\GLExtensions</Filter>
</ClInclude>
<ClInclude Include="File.h" />
<ClInclude Include="FileByHandle.h" />
<ClInclude Include="Lazy.h" />
<ClInclude Include="LdrWatcher.h" />
<ClInclude Include="GL\GLExtensions\ARB_texture_compression_bptc.h">
Expand Down Expand Up @@ -355,6 +356,7 @@
<ClCompile Include="Analytics.cpp" />
<ClCompile Include="MD5.cpp" />
<ClCompile Include="File.cpp" />
<ClCompile Include="FileByHandle.cpp" />
<ClCompile Include="LdrWatcher.cpp" />
<ClCompile Include="CompatPatches.cpp" />
<ClCompile Include="Config\ConfigInfo.cpp" />
Expand Down
72 changes: 72 additions & 0 deletions Source/Core/Common/FileByHandle.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "FileByHandle.h"

#include <memory>

#include <Windows.h>

#include "StringUtil.h"

namespace File
{
struct IOFileByHandle::Impl
{
HANDLE m_handle;
};

IOFileByHandle::IOFileByHandle(const std::string& filename) : m_data(std::make_unique<Impl>())
{
auto wide_filename = UTF8ToTStr(filename);
m_data->m_handle = CreateFile(wide_filename.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0,
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, nullptr);
if (m_data->m_handle == INVALID_HANDLE_VALUE)
return;
}

IOFileByHandle::~IOFileByHandle()
{
if (m_data->m_handle == INVALID_HANDLE_VALUE)
return;

CloseHandle(m_data->m_handle);
}

bool IOFileByHandle::Write(const u8* data, size_t length)
{
if (m_data->m_handle == INVALID_HANDLE_VALUE)
return false;

DWORD bytes_written;
if (WriteFile(m_data->m_handle, data, static_cast<DWORD>(length), &bytes_written, nullptr))
return bytes_written == length;

return false;
}

bool IOFileByHandle::Rename(const std::string& filename)
{
if (m_data->m_handle == INVALID_HANDLE_VALUE)
return false;

auto wide_filename = UTF8ToWString(filename);
size_t rename_info_length = sizeof(FILE_RENAME_INFO) + wide_filename.length() * sizeof(wchar_t);
auto rename_info_buffer = std::make_unique<u8[]>(rename_info_length);

FILE_RENAME_INFO* rename_info = reinterpret_cast<FILE_RENAME_INFO*>(rename_info_buffer.get());
rename_info->ReplaceIfExists = TRUE;
rename_info->FileNameLength = static_cast<DWORD>(wide_filename.length());
std::memcpy(rename_info->FileName, wide_filename.c_str(),
wide_filename.length() * sizeof(wchar_t));

if (SetFileInformationByHandle(m_data->m_handle, FileRenameInfo, rename_info_buffer.get(),
static_cast<DWORD>(rename_info_length)))
{
return true;
}

return false;
}
} // namespace File
38 changes: 38 additions & 0 deletions Source/Core/Common/FileByHandle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <memory>
#include <string>

#include "Common/CommonTypes.h"

namespace File
{
class IOFileByHandle
{
public:
IOFileByHandle(const std::string& filename);
~IOFileByHandle();

IOFileByHandle(const IOFileByHandle&) = delete;
IOFileByHandle& operator=(const IOFileByHandle&) = delete;

bool Write(const u8* data, size_t length);

bool Rename(const std::string& filename);

template <typename T>
bool WriteArray(const T* elements, size_t count)
{
return Write(reinterpret_cast<const u8*>(elements), count * sizeof(T));
}

private:
struct Impl;
std::unique_ptr<Impl> m_data;
};

} // namespace File
16 changes: 8 additions & 8 deletions Source/Core/Core/IOS/FS/HostBackend/FS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "Common/Assert.h"
#include "Common/ChunkFile.h"
#include "Common/FileByHandle.h"
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Common/NandPaths.h"
Expand Down Expand Up @@ -177,16 +178,15 @@ void HostFileSystem::SaveFst()

const std::string dest_path = GetFstFilePath();
const std::string temp_path = File::GetTempFilenameForAtomicWrite(dest_path);

File::IOFileByHandle file(temp_path);
if (!file.WriteArray(to_write.data(), to_write.size()))
{
// This temporary file must be closed before it can be renamed.
File::IOFile file{temp_path, "wb"};
if (!file.WriteArray(to_write.data(), to_write.size()))
{
PanicAlert("IOS_FS: Failed to write new FST");
return;
}
PanicAlert("IOS_FS: Failed to write new FST");
return;
}
if (!File::Rename(temp_path, dest_path))

if (!file.Rename(dest_path))
PanicAlert("IOS_FS: Failed to rename temporary FST file");
}

Expand Down

0 comments on commit 8b01027

Please sign in to comment.