mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-07 05:00:16 +02:00
It is not an error that pread returns /less/ than what was requested. In fact it's very common for the Linux kernel to return less than the data requested from procfs. procfs keeps coming back to bite this function, previously it was fstat returning size of 0 which it hit. Now it only feeds data as much as it wants per loop. In particular /proc/self/maps would only read ~3k bytes on my system, but not be complete. To fully fix the issue, always make sure to keep reading until there is either an error OR zero is reached!
115 lines
2.7 KiB
C++
115 lines
2.7 KiB
C++
// SPDX-License-Identifier: MIT
|
|
#include <FEXCore/fextl/string.h>
|
|
#include <FEXCore/fextl/vector.h>
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <span>
|
|
#include <unistd.h>
|
|
#ifdef _WIN32
|
|
#include <fstream>
|
|
#endif
|
|
|
|
namespace FEXCore::FileLoading {
|
|
|
|
#ifndef _WIN32
|
|
template<typename T>
|
|
static bool LoadFileImpl(T& Data, const fextl::string& Filepath, size_t FixedSize) {
|
|
int FD = open(Filepath.c_str(), O_RDONLY);
|
|
|
|
if (FD == -1) {
|
|
return false;
|
|
}
|
|
|
|
size_t FileSize {};
|
|
if (FixedSize == 0) {
|
|
struct stat buf;
|
|
if (fstat(FD, &buf) == 0) {
|
|
FileSize = buf.st_size;
|
|
}
|
|
} else {
|
|
FileSize = FixedSize;
|
|
}
|
|
|
|
ssize_t CurrentOffset = 0;
|
|
ssize_t Read = -1;
|
|
bool LoadedFile {};
|
|
if (FileSize) {
|
|
// File size is known upfront
|
|
Data.resize(FileSize);
|
|
while (CurrentOffset != FileSize && (Read = pread(FD, &Data.at(CurrentOffset), FileSize, 0)) > 0) {
|
|
CurrentOffset += Read;
|
|
}
|
|
|
|
LoadedFile = CurrentOffset == FileSize && Read != -1;
|
|
} else {
|
|
// The file is either empty or its size is unknown (e.g. procfs data).
|
|
// Try reading in chunks instead
|
|
constexpr size_t READ_SIZE = 4096;
|
|
Data.resize(READ_SIZE);
|
|
|
|
while ((Read = pread(FD, &Data.at(CurrentOffset), READ_SIZE, CurrentOffset)) > 0) {
|
|
CurrentOffset += Read;
|
|
if ((CurrentOffset + READ_SIZE) > Data.size()) {
|
|
Data.resize(CurrentOffset + READ_SIZE);
|
|
}
|
|
}
|
|
|
|
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 LoadedFile;
|
|
}
|
|
|
|
ssize_t LoadFileToBuffer(const fextl::string& Filepath, std::span<char> Buffer) {
|
|
int FD = open(Filepath.c_str(), O_RDONLY);
|
|
|
|
if (FD == -1) {
|
|
return -1;
|
|
}
|
|
|
|
ssize_t Read = pread(FD, Buffer.data(), Buffer.size(), 0);
|
|
close(FD);
|
|
return Read;
|
|
}
|
|
|
|
#else
|
|
template<typename T>
|
|
static bool LoadFileImpl(T& Data, const fextl::string& Filepath, size_t FixedSize) {
|
|
std::ifstream f(Filepath.c_str(), std::ios::binary | std::ios::ate);
|
|
if (f.fail()) {
|
|
return false;
|
|
}
|
|
auto Size = f.tellg();
|
|
f.seekg(0, std::ios::beg);
|
|
Data.resize(Size);
|
|
f.read(Data.data(), Size);
|
|
return !f.fail();
|
|
}
|
|
|
|
ssize_t LoadFileToBuffer(const fextl::string& Filepath, std::span<char> Buffer) {
|
|
std::ifstream f(Filepath.c_str(), std::ios::binary | std::ios::ate);
|
|
return f.readsome(Buffer.data(), Buffer.size());
|
|
}
|
|
|
|
#endif
|
|
|
|
bool LoadFile(fextl::vector<char>& Data, const fextl::string& Filepath, size_t FixedSize) {
|
|
return LoadFileImpl(Data, Filepath, FixedSize);
|
|
}
|
|
|
|
bool LoadFile(fextl::string& Data, const fextl::string& Filepath, size_t FixedSize) {
|
|
return LoadFileImpl(Data, Filepath, FixedSize);
|
|
}
|
|
|
|
} // namespace FEXCore::FileLoading
|