diff --git a/app/src/main/cpp/skyline/vfs/os_backing.cpp b/app/src/main/cpp/skyline/vfs/os_backing.cpp index ae9c7676..b1b3884f 100644 --- a/app/src/main/cpp/skyline/vfs/os_backing.cpp +++ b/app/src/main/cpp/skyline/vfs/os_backing.cpp @@ -21,11 +21,28 @@ namespace skyline::vfs { } size_t OsBacking::ReadImpl(span output, size_t offset) { - auto ret{pread64(fd, output.data(), output.size(), static_cast(offset))}; - if (ret < 0) - throw exception("Failed to read from fd: {}", strerror(errno)); + size_t bytesRead{}; + while (bytesRead < output.size()) { + auto ret{pread64(fd, output.data() + bytesRead, output.size() - bytesRead, static_cast(offset + bytesRead))}; + if (ret < 0) { + if (errno == EFAULT) { + // If EFAULT is returned then we're reading into a trapped region so create a temporary buffer and read into that instead + // This is required since pread doesn't trigger signal handlers itself + std::vector buffer(output.size() - bytesRead); + ret = pread64(fd, buffer.data(), buffer.size(), static_cast(offset + bytesRead)); + if (ret >= 0) { + output.subspan(bytesRead).copy_from(buffer); + bytesRead += static_cast(ret); + continue; + } + } - return static_cast(ret); + throw exception("Failed to read from fd: {}", strerror(errno)); + } else { + bytesRead += static_cast(ret); + } + } + return output.size(); } size_t OsBacking::WriteImpl(span input, size_t offset) {