IOS/FS: Add a scoped FD class to make it harder to leak FDs

This changes FileSystemProxy::Open to return a file descriptor wrapper
that will ensure the FD is closed when it goes out of scope.

By using such a wrapper we make it more difficult to forget to close
file descriptors.

This fixes a leak in ReadBootContent. I should have added such a class
from the beginning... In practice, I don't think this would have caused
any obvious issue because ReadBootContent is only called after an IOS
relaunch -- which clears all FDs -- and most titles do not get close
to the FD limit.
This commit is contained in:
Léo Lam committed 2021-04-01 21:34:58 +02:00
1 parent 06439a2d40
commit 391644dbb5
7 files changed
+68 -41

No files matched your search

+3 -4
View File
@@ -403,9 +403,9 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
// To keep track of the PPC title launch, a temporary launch file (LAUNCH_FILE_PATH) is used
// to store the title ID of the title to launch and its TMD.
// The launch file not existing means an IOS reload is required.
const auto launch_file_fd = m_ios.GetFSDevice()->Open(PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH,
FS::Mode::Read, {}, &ticks);
if (launch_file_fd < 0)
if (const auto launch_file_fd = m_ios.GetFSDevice()->Open(
PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH, FS::Mode::Read, {}, &ticks);
launch_file_fd.Get() < 0)
{
if (WriteLaunchFile(tmd, &ticks) != IPC_SUCCESS)
{
@@ -423,7 +423,6 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
// Otherwise, assume that the PPC title can now be launched directly.
// Unlike IOS, we won't bother checking the title ID in the launch file. (It's not useful.)
m_ios.GetFSDevice()->Close(launch_file_fd, &ticks);
m_ios.GetFSDevice()->DeleteFile(PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH, &ticks);
WriteSystemFile(SPACE_FILE_PATH, std::vector<u8>(SPACE_FILE_SIZE), &ticks);
+8 -8
View File
@@ -528,15 +528,15 @@ SharedContentMap::SharedContentMap(std::shared_ptr<HLE::FSDevice> fs)
static_assert(sizeof(Entry) == 28, "SharedContentMap::Entry has the wrong size");
Entry entry;
s64 fd = fs->Open(PID_KERNEL, PID_KERNEL, CONTENT_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
if (fd < 0)
const auto fd =
fs->Open(PID_KERNEL, PID_KERNEL, CONTENT_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
if (fd.Get() < 0)
return;
while (fs->Read(fd, &entry, 1, &m_ticks) == sizeof(entry))
while (fs->Read(fd.Get(), &entry, 1, &m_ticks) == sizeof(entry))
{
m_entries.push_back(entry);
m_last_id++;
}
fs->Close(fd, &m_ticks);
}
SharedContentMap::~SharedContentMap() = default;
@@ -621,18 +621,18 @@ static std::pair<u32, u64> ReadUidSysEntry(HLE::FSDevice& fs, u64 fd, u64* ticks
constexpr char UID_MAP_PATH[] = "/sys/uid.sys";
UIDSys::UIDSys(std::shared_ptr<HLE::FSDevice> fs) : m_fs_device{fs}, m_fs{fs->GetFS()}
{
s64 fd = fs->Open(PID_KERNEL, PID_KERNEL, UID_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
if (fd >= 0)
if (const auto fd =
fs->Open(PID_KERNEL, PID_KERNEL, UID_MAP_PATH, HLE::FS::Mode::Read, {}, &m_ticks);
fd.Get() >= 0)
{
while (true)
{
std::pair<u32, u64> entry = ReadUidSysEntry(*fs, fd, &m_ticks);
std::pair<u32, u64> entry = ReadUidSysEntry(*fs, fd.Get(), &m_ticks);
if (!entry.first && !entry.second)
break;
m_entries.insert(std::move(entry));
}
fs->Close(fd, &m_ticks);
}
if (m_entries.empty())
+10 -11
View File
@@ -27,13 +27,12 @@ namespace IOS::HLE
{
static ES::TMDReader FindTMD(FSDevice& fs, const std::string& tmd_path, Ticks ticks)
{
const s64 fd = fs.Open(PID_KERNEL, PID_KERNEL, tmd_path, FS::Mode::Read, {}, ticks);
if (fd < 0)
const auto fd = fs.Open(PID_KERNEL, PID_KERNEL, tmd_path, FS::Mode::Read, {}, ticks);
if (fd.Get() < 0)
return {};
Common::ScopeGuard guard{[&] { fs.Close(fd, ticks); }};
std::vector<u8> tmd_bytes(fs.GetFileStatus(fd, ticks)->size);
if (!fs.Read(fd, tmd_bytes.data(), tmd_bytes.size(), ticks))
std::vector<u8> tmd_bytes(fs.GetFileStatus(fd.Get(), ticks)->size);
if (!fs.Read(fd.Get(), tmd_bytes.data(), tmd_bytes.size(), ticks))
return {};
return ES::TMDReader{std::move(tmd_bytes)};
@@ -407,20 +406,20 @@ s32 ESDevice::WriteSystemFile(const std::string& path, const std::vector<u8>& da
return FS::ConvertResult(result);
}
const auto fd = fs.Open(PID_KERNEL, PID_KERNEL, tmp_path, FS::Mode::ReadWrite, {}, ticks);
if (fd < 0)
auto fd = fs.Open(PID_KERNEL, PID_KERNEL, tmp_path, FS::Mode::ReadWrite, {}, ticks);
if (fd.Get() < 0)
{
ERROR_LOG_FMT(IOS_ES, "Failed to open temporary file {}: {}", tmp_path, fd);
return fd;
ERROR_LOG_FMT(IOS_ES, "Failed to open temporary file {}: {}", tmp_path, fd.Get());
return fd.Get();
}
if (fs.Write(fd, data.data(), u32(data.size()), {}, ticks) != s32(data.size()))
if (fs.Write(fd.Get(), data.data(), u32(data.size()), {}, ticks) != s32(data.size()))
{
ERROR_LOG_FMT(IOS_ES, "Failed to write to temporary file {}", tmp_path);
return ES_EIO;
}
if (const auto ret = fs.Close(fd, ticks); ret != IPC_SUCCESS)
if (const auto ret = fs.Close(fd.Release(), ticks); ret != IPC_SUCCESS)
{
ERROR_LOG_FMT(IOS_ES, "Failed to close temporary file {}", tmp_path);
return ret;
+4 -4
View File
@@ -29,12 +29,12 @@ s32 ESDevice::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid,
continue;
const std::string path = GetContentPath(title_id, content, ticks);
s64 fd = m_ios.GetFSDevice()->Open(PID_KERNEL, PID_KERNEL, path, FS::Mode::Read, {}, ticks);
if (fd < 0)
return fd;
auto fd = m_ios.GetFSDevice()->Open(PID_KERNEL, PID_KERNEL, path, FS::Mode::Read, {}, ticks);
if (fd.Get() < 0)
return fd.Get();
entry.m_opened = true;
entry.m_fd = fd;
entry.m_fd = fd.Release();
entry.m_content = content;
entry.m_title_id = title_id;
entry.m_uid = uid;