diff --git a/FEXCore/Source/Utils/FileLoading.cpp b/FEXCore/Source/Utils/FileLoading.cpp index 14aec693b..71e6c8317 100644 --- a/FEXCore/Source/Utils/FileLoading.cpp +++ b/FEXCore/Source/Utils/FileLoading.cpp @@ -24,24 +24,48 @@ static bool LoadFileImpl(T &Data, const fextl::string &Filepath, size_t FixedSiz size_t FileSize{}; if (FixedSize == 0) { struct stat buf; - if (fstat(FD, &buf) != 0) { - close(FD); - return false; + if (fstat(FD, &buf) == 0) { + FileSize = buf.st_size; } - - FileSize = buf.st_size; } else { FileSize = FixedSize; } ssize_t Read = -1; - if (FileSize > 0) { + bool LoadedFile{}; + if (FileSize) { + // File size is known upfront Data.resize(FileSize); Read = pread(FD, &Data.at(0), FileSize, 0); + + LoadedFile = Read == FileSize; + } + else { + // The file is either empty or its size is unknown (e.g. procfs data). + // Try reading in chunks instead + ssize_t CurrentOffset = 0; + constexpr size_t READ_SIZE = 4096; + Data.resize(READ_SIZE); + + while ((Read = pread(FD, &Data.at(CurrentOffset), READ_SIZE, CurrentOffset)) == READ_SIZE) { + CurrentOffset += Read; + Data.resize(CurrentOffset + Read); + } + + if (Read == -1) { + Data.clear(); + close(FD); + return false; + } + + // Final resize to ensure there is no garbage data past the end. + Data.resize(CurrentOffset + Read); + + LoadedFile = true; } close(FD); - return Read == FileSize; + return LoadedFile; } ssize_t LoadFileToBuffer(const fextl::string &Filepath, std::span Buffer) { diff --git a/FEXCore/unittests/APITests/FileLoading.cpp b/FEXCore/unittests/APITests/FileLoading.cpp new file mode 100644 index 000000000..ebebfd144 --- /dev/null +++ b/FEXCore/unittests/APITests/FileLoading.cpp @@ -0,0 +1,22 @@ +#include +#include + +TEST_CASE("LoadFile-Doesn'tExist") { + fextl::string MapsFile; + auto Read = FEXCore::FileLoading::LoadFile(MapsFile, "/tmp/a/b/c/d/e/z"); + REQUIRE(MapsFile.size() == 0); + REQUIRE(Read == false); +} + +TEST_CASE("LoadFile-procfs") { + fextl::string MapsFile; + FEXCore::FileLoading::LoadFile(MapsFile, "/proc/self/maps"); + REQUIRE(MapsFile.size() != 0); +} + +TEST_CASE("LoadFile-Buffer") { + fextl::string MapsFile; + MapsFile.resize(16); + auto Read = FEXCore::FileLoading::LoadFileToBuffer("/proc/self/maps", MapsFile); + REQUIRE(MapsFile.size() == Read); +}