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 // write the final 0 to 0 file from the second FAT to 20 MiB
data[CDB_SIZE - 1] = 0; data[CDB_SIZE - 1] = 0;
fs->WriteFile(*fd, data.data(), static_cast<u32>(data.size())); fs->WriteFile(*fd, data.data(), static_cast<u32>(data.size()));
fs->Close(*fd);
} }
bool CBoot::BootNANDTitle(const u64 title_id) bool CBoot::BootNANDTitle(const u64 title_id)

View File

@ -4,6 +4,7 @@
#include "Core/IOS/FS/FileSystem.h" #include "Core/IOS/FS/FileSystem.h"
#include "Common/Assert.h"
#include "Core/IOS/FS/HostBackend/FS.h" #include "Core/IOS/FS/HostBackend/FS.h"
namespace IOS::HLE::FS namespace IOS::HLE::FS
@ -13,6 +14,35 @@ std::unique_ptr<FileSystem> MakeFileSystem()
return std::make_unique<HostFileSystem>(); 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() void FileSystem::Init()
{ {
if (Delete(0, 0, "/tmp") == ResultCode::Success) if (Delete(0, 0, "/tmp") == ResultCode::Success)

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
@ -96,6 +97,26 @@ struct FileStatus
u32 size; 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 class FileSystem
{ {
public: public:
@ -106,8 +127,8 @@ public:
/// Format the file system. /// Format the file system.
virtual ResultCode Format(Uid uid) = 0; virtual ResultCode Format(Uid uid) = 0;
/// Get a file descriptor for accessing a file. /// Get a file descriptor for accessing a file. The FD will be automatically closed after use.
virtual Result<Fd> OpenFile(Uid uid, Gid gid, const std::string& path, Mode mode) = 0; virtual Result<FileHandle> OpenFile(Uid uid, Gid gid, const std::string& path, Mode mode) = 0;
/// Close a file descriptor. /// Close a file descriptor.
virtual ResultCode Close(Fd fd) = 0; virtual ResultCode Close(Fd fd) = 0;
/// Read `size` bytes from the file descriptor. Returns the number of bytes read. /// 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); return GetDefaultReply(IPC_SUCCESS);
} }
const auto backend_fd = m_ios.GetFS()->OpenFile(request.uid, request.gid, request.path, auto backend_fd = m_ios.GetFS()->OpenFile(request.uid, request.gid, request.path,
static_cast<Mode>(request.flags & 3)); static_cast<Mode>(request.flags & 3));
LogResult(StringFromFormat("OpenFile(%s)", request.path.c_str()), backend_fd); LogResult(StringFromFormat("OpenFile(%s)", request.path.c_str()), backend_fd);
if (!backend_fd) if (!backend_fd)
return GetFSReply(ConvertResult(backend_fd.Error())); 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); std::strncpy(m_fd_map[request.fd].name.data(), request.path.c_str(), 64);
return GetFSReply(IPC_SUCCESS); return GetFSReply(IPC_SUCCESS);
} }

View File

@ -30,7 +30,7 @@ public:
ResultCode Format(Uid uid) override; 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; ResultCode Close(Fd fd) override;
Result<u32> ReadBytesFromFile(Fd fd, u8* ptr, u32 size) override; Result<u32> ReadBytesFromFile(Fd fd, u8* ptr, u32 size) override;
Result<u32> WriteBytesToFile(Fd fd, const 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; 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(); Handle* handle = AssignFreeHandle();
if (!handle) if (!handle)
@ -74,7 +74,7 @@ Result<Fd> HostFileSystem::OpenFile(Uid uid, Gid gid, const std::string& path, M
handle->wii_path = path; handle->wii_path = path;
handle->mode = mode; handle->mode = mode;
handle->file_offset = 0; handle->file_offset = 0;
return ConvertHandleToFd(handle); return FileHandle{this, ConvertHandleToFd(handle)};
} }
ResultCode HostFileSystem::Close(Fd fd) ResultCode HostFileSystem::Close(Fd fd)