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:
parent
de15e09a4f
commit
2d8be6a77d
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue