diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 6ea3e8b74a..046b252a33 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -1106,10 +1106,12 @@ fs::file::file(const std::string& path, bs_t mode) class windows_file final : public file_base { const HANDLE m_handle; + atomic_t m_pos; public: windows_file(HANDLE handle) : m_handle(handle) + , m_pos(0) { } @@ -1165,7 +1167,39 @@ fs::file::file(const std::string& path, bs_t mode) const DWORD size = static_cast(std::min(count, DWORD{umax} & -4096)); DWORD nread = 0; - ensure(ReadFile(m_handle, data, size, &nread, nullptr)); // "file::read" + OVERLAPPED ovl{}; + const u64 pos = m_pos; + ovl.Offset = DWORD(pos); + ovl.OffsetHigh = DWORD(pos >> 32); + ensure(ReadFile(m_handle, data, size, &nread, &ovl) || GetLastError() == ERROR_HANDLE_EOF); // "file::read" + nread_sum += nread; + m_pos += nread; + + if (nread < size) + { + break; + } + + count -= size; + data += size; + } + + return nread_sum; + } + + u64 read_at(u64 offset, void* buffer, u64 count) override + { + u64 nread_sum = 0; + + for (char* data = static_cast(buffer); count;) + { + const DWORD size = static_cast(std::min(count, DWORD{umax} & -4096)); + + DWORD nread = 0; + OVERLAPPED ovl{}; + ovl.Offset = DWORD(offset); + ovl.OffsetHigh = DWORD(offset >> 32); + ensure(ReadFile(m_handle, data, size, &nread, &ovl) || GetLastError() == ERROR_HANDLE_EOF); // "file::read" nread_sum += nread; if (nread < size) @@ -1175,6 +1209,7 @@ fs::file::file(const std::string& path, bs_t mode) count -= size; data += size; + offset += size; } return nread_sum; @@ -1189,8 +1224,13 @@ fs::file::file(const std::string& path, bs_t mode) const DWORD size = static_cast(std::min(count, DWORD{umax} & -4096)); DWORD nwritten = 0; - ensure(WriteFile(m_handle, data, size, &nwritten, nullptr)); // "file::write" + OVERLAPPED ovl{}; + const u64 pos = m_pos; + ovl.Offset = DWORD(pos); + ovl.OffsetHigh = DWORD(pos >> 32); + ensure(WriteFile(m_handle, data, size, &nwritten, &ovl)); // "file::write" nwritten_sum += nwritten; + m_pos += nwritten; if (nwritten < size) { @@ -1211,20 +1251,19 @@ fs::file::file(const std::string& path, bs_t mode) fmt::throw_exception("Invalid whence (0x%x)", whence); } - LARGE_INTEGER pos; - pos.QuadPart = offset; + const s64 new_pos = + whence == fs::seek_set ? offset : + whence == fs::seek_cur ? offset + m_pos : + whence == fs::seek_end ? offset + size() : -1; - const DWORD mode = - whence == seek_set ? FILE_BEGIN : - whence == seek_cur ? FILE_CURRENT : FILE_END; - - if (!SetFilePointerEx(m_handle, pos, &pos, mode)) + if (new_pos < 0) { - g_tls_error = to_error(GetLastError()); + fs::g_tls_error = fs::error::inval; return -1; } - return pos.QuadPart; + m_pos = new_pos; + return m_pos; } u64 size() override @@ -1349,6 +1388,14 @@ fs::file::file(const std::string& path, bs_t mode) return result; } + u64 read_at(u64 offset, void* buffer, u64 count) override + { + const auto result = ::pread(m_fd, buffer, count, offset); + ensure(result != -1); + + return result; + } + u64 write(const void* buffer, u64 count) override { const auto result = ::write(m_fd, buffer, count); @@ -1466,6 +1513,21 @@ fs::file::file(const void* ptr, usz size) return 0; } + u64 read_at(u64 offset, void* buffer, u64 count) override + { + if (offset < m_size) + { + // Get readable size + if (const u64 result = std::min(count, m_size - offset)) + { + std::memcpy(buffer, m_ptr + offset, result); + return result; + } + } + + return 0; + } + u64 write(const void*, u64) override { return 0; @@ -1951,6 +2013,40 @@ fs::file fs::make_gather(std::vector files) return 0; } + u64 read_at(u64 start, void* buffer, u64 size) override + { + if (start < end) + { + u64 pos = start; + + // Get readable size + if (const u64 max = std::min(size, end - pos)) + { + u8* buf_out = static_cast(buffer); + u64 buf_max = max; + + for (auto it = ends.upper_bound(pos); it != ends.end(); ++it) + { + const u64 count = std::min(it->first - pos, buf_max); + const u64 read = files[it->second].read_at(files[it->second].size() + pos - it->first, buf_out, count); + + buf_out += count; + buf_max -= count; + pos += read; + + if (read < count || buf_max == 0) + { + break; + } + } + + return pos - start; + } + } + + return 0; + } + u64 write(const void*, u64) override { return 0; diff --git a/Utilities/File.h b/Utilities/File.h index 008c1a2bc2..7a6b4d5fd5 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -93,6 +93,7 @@ namespace fs virtual void sync(); virtual bool trunc(u64 length) = 0; virtual u64 read(void* buffer, u64 size) = 0; + virtual u64 read_at(u64 offset, void* buffer, u64 size) = 0; virtual u64 write(const void* buffer, u64 size) = 0; virtual u64 seek(s64 offset, seek_mode whence) = 0; virtual u64 size() = 0; @@ -301,6 +302,17 @@ namespace fs return m_file->read(buffer, count); } + // Read the data from the file at specified offset in thread-safe manner + u64 read_at(u64 offset, void* buffer, u64 count, + u32 line = __builtin_LINE(), + u32 col = __builtin_COLUMN(), + const char* file = __builtin_FILE(), + const char* func = __builtin_FUNCTION()) const + { + if (!m_file) xnull({line, col, file, func}); + return m_file->read_at(offset, buffer, count); + } + // Write the data to the file and return the amount of data actually written u64 write(const void* buffer, u64 count, u32 line = __builtin_LINE(), @@ -724,6 +736,24 @@ namespace fs return 0; } + u64 read_at(u64 offset, void* buffer, u64 size) override + { + const u64 end = obj.size(); + + if (offset < end) + { + // Get readable size + if (const u64 max = std::min(size, end - offset)) + { + std::copy(obj.cbegin() + offset, obj.cbegin() + offset + max, static_cast(buffer)); + update_time(); + return max; + } + } + + return 0; + } + u64 write(const void* buffer, u64 size) override { const u64 old_size = obj.size(); diff --git a/rpcs3/Crypto/unedat.h b/rpcs3/Crypto/unedat.h index 80e6f12837..d4ff4578db 100644 --- a/rpcs3/Crypto/unedat.h +++ b/rpcs3/Crypto/unedat.h @@ -115,6 +115,11 @@ public: return bytesRead; } + u64 read_at(u64 offset, void* buffer, u64 size) override + { + return ReadData(offset, static_cast(buffer), size); + } + u64 write(const void*, u64) override { return 0; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 812efcecd6..09ceafdd52 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -617,7 +617,7 @@ struct ppu_far_jumps_t bool with_toc; std::string module_name; ppu_intrp_func_t func; - + u32 get_target(u32 pc, ppu_thread* ppu = nullptr) const { u32 direct_target = this->target; @@ -706,7 +706,7 @@ struct ppu_far_jumps_t { return targets; } - + for (auto end = vals.lower_bound(pc + size); it != end; it++) { all_info_t& all_info = it->second; @@ -1994,7 +1994,7 @@ void ppu_thread::fast_call(u32 addr, u64 rtoc) if (auto name = get_prx_name_by_cia(cia)) { - return fmt::format("PPU[0x%x] Thread (%s) [%s: 0x%08x]", _this->id, *name_cache.get(), name, cia); + return fmt::format("PPU[0x%x] Thread (%s) [%s: 0x%08x]", _this->id, *name_cache.get(), name, cia); } return fmt::format("PPU[0x%x] Thread (%s) [0x%08x]", _this->id, *name_cache.get(), cia); @@ -2806,6 +2806,11 @@ namespace return result; } + u64 read_at(u64 offset, void* buffer, u64 size) override + { + return m_file.read_at(offset + m_off, buffer, size); + } + u64 write(const void*, u64) override { return 0; diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 071477958f..0c4c0113d2 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -579,6 +579,11 @@ struct lv2_file::file_view : fs::file_base return result; } + u64 read_at(u64 offset, void* buffer, u64 size) override + { + return m_file->file.read_at(offset, buffer, size); + } + u64 write(const void*, u64) override { return 0; @@ -2380,7 +2385,7 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 strcpy_trunc(entry.entry_name.d_name, info->name); } - // Apparently all this function does to additional buffer elements is to zeroize them + // Apparently all this function does to additional buffer elements is to zeroize them std::memset(arg_ptr.get_ptr() + read_count, 0, (max - read_count) * arg->ptr.size()); }