IOS/FS: Make it harder to forget closing FDs

Return a FileHandle which will automatically close the FD when
the handle goes out of scope. For the rare cases where this behaviour
is undesirable, the FD can be released from the handle.
This commit is contained in:
Léo Lam 2018-03-08 18:32:49 +01:00
parent de15e09a4f
commit 2d8be6a77d
6 changed files with 59 additions and 9 deletions

View File

@ -49,7 +49,6 @@ static void CreateVirtualFATFilesystem(std::shared_ptr<IOS::HLE::FS::FileSystem>
// write the final 0 to 0 file from the second FAT to 20 MiB
data[CDB_SIZE - 1] = 0;
fs->WriteFile(*fd, data.data(), static_cast<u32>(data.size()));
fs->Close(*fd);
}
bool CBoot::BootNANDTitle(const u64 title_id)

View File

@ -4,6 +4,7 @@
#include "Core/IOS/FS/FileSystem.h"
#include "Common/Assert.h"
#include "Core/IOS/FS/HostBackend/FS.h"
namespace IOS::HLE::FS
@ -13,6 +14,35 @@ std::unique_ptr<FileSystem> MakeFileSystem()
return std::make_unique<HostFileSystem>();
}
FileHandle::FileHandle(FileSystem* fs, Fd fd) : m_fs{fs}, m_fd{fd}
{
}
FileHandle::FileHandle(FileHandle&& other) : m_fs{other.m_fs}, m_fd{other.m_fd}
{
other.m_fd.reset();
}
FileHandle& FileHandle::operator=(FileHandle&& other)
{
if (*this != other)
*this = std::move(other);
return *this;
}
FileHandle::~FileHandle()
{
if (m_fd && m_fs)
ASSERT(m_fs->Close(*m_fd) == FS::ResultCode::Success);
}
Fd FileHandle::Release()
{
const Fd fd = m_fd.value();
m_fd.reset();
return fd;
}
void FileSystem::Init()
{
if (Delete(0, 0, "/tmp") == ResultCode::Success)

View File

@ -5,6 +5,7 @@
#pragma once
#include <memory>
#include <optional>
#include <string>
#include <vector>
@ -96,6 +97,26 @@ struct FileStatus
u32 size;
};
class FileSystem;
class FileHandle final
{
public:
FileHandle(FileSystem* fs, Fd fd);
FileHandle(FileHandle&&);
~FileHandle();
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
FileHandle& operator=(FileHandle&&);
operator Fd() const { return m_fd.value(); }
/// Release the FD so that it is not automatically closed.
Fd Release();
private:
FileSystem* m_fs;
std::optional<Fd> m_fd;
};
class FileSystem
{
public:
@ -106,8 +127,8 @@ public:
/// Format the file system.
virtual ResultCode Format(Uid uid) = 0;
/// Get a file descriptor for accessing a file.
virtual Result<Fd> OpenFile(Uid uid, Gid gid, const std::string& path, Mode mode) = 0;
/// Get a file descriptor for accessing a file. The FD will be automatically closed after use.
virtual Result<FileHandle> OpenFile(Uid uid, Gid gid, const std::string& path, Mode mode) = 0;
/// Close a file descriptor.
virtual ResultCode Close(Fd fd) = 0;
/// Read `size` bytes from the file descriptor. Returns the number of bytes read.

View File

@ -70,13 +70,13 @@ IPCCommandResult FS::Open(const OpenRequest& request)
return GetDefaultReply(IPC_SUCCESS);
}
const auto backend_fd = m_ios.GetFS()->OpenFile(request.uid, request.gid, request.path,
static_cast<Mode>(request.flags & 3));
auto backend_fd = m_ios.GetFS()->OpenFile(request.uid, request.gid, request.path,
static_cast<Mode>(request.flags & 3));
LogResult(StringFromFormat("OpenFile(%s)", request.path.c_str()), backend_fd);
if (!backend_fd)
return GetFSReply(ConvertResult(backend_fd.Error()));
m_fd_map[request.fd] = {request.gid, request.uid, *backend_fd};
m_fd_map[request.fd] = {request.gid, request.uid, backend_fd->Release()};
std::strncpy(m_fd_map[request.fd].name.data(), request.path.c_str(), 64);
return GetFSReply(IPC_SUCCESS);
}

View File

@ -30,7 +30,7 @@ public:
ResultCode Format(Uid uid) override;
Result<Fd> OpenFile(Uid uid, Gid gid, const std::string& path, Mode mode) override;
Result<FileHandle> OpenFile(Uid uid, Gid gid, const std::string& path, Mode mode) override;
ResultCode Close(Fd fd) override;
Result<u32> ReadBytesFromFile(Fd fd, u8* ptr, u32 size) override;
Result<u32> WriteBytesToFile(Fd fd, const u8* ptr, u32 size) override;

View File

@ -57,7 +57,7 @@ std::shared_ptr<File::IOFile> HostFileSystem::OpenHostFile(const std::string& ho
return file;
}
Result<Fd> HostFileSystem::OpenFile(Uid uid, Gid gid, const std::string& path, Mode mode)
Result<FileHandle> HostFileSystem::OpenFile(Uid, Gid, const std::string& path, Mode mode)
{
Handle* handle = AssignFreeHandle();
if (!handle)
@ -74,7 +74,7 @@ Result<Fd> HostFileSystem::OpenFile(Uid uid, Gid gid, const std::string& path, M
handle->wii_path = path;
handle->mode = mode;
handle->file_offset = 0;
return ConvertHandleToFd(handle);
return FileHandle{this, ConvertHandleToFd(handle)};
}
ResultCode HostFileSystem::Close(Fd fd)