fs: implement file::read_at

Reads from the given offset; does not seek; thread-safe.
This commit is contained in:
Nekotekina 2022-12-24 17:15:29 +03:00 committed by Ivan
parent 9d432187aa
commit 2f9cac8d18
5 changed files with 156 additions and 15 deletions

View File

@ -1106,10 +1106,12 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
class windows_file final : public file_base
{
const HANDLE m_handle;
atomic_t<u64> 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<open_mode> mode)
const DWORD size = static_cast<DWORD>(std::min<u64>(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<char*>(buffer); count;)
{
const DWORD size = static_cast<DWORD>(std::min<u64>(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<open_mode> mode)
count -= size;
data += size;
offset += size;
}
return nread_sum;
@ -1189,8 +1224,13 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
const DWORD size = static_cast<DWORD>(std::min<u64>(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<open_mode> 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<open_mode> 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<u64>(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<fs::file> 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<u64>(size, end - pos))
{
u8* buf_out = static_cast<u8*>(buffer);
u64 buf_max = max;
for (auto it = ends.upper_bound(pos); it != ends.end(); ++it)
{
const u64 count = std::min<u64>(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;

View File

@ -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<u64>(size, end - offset))
{
std::copy(obj.cbegin() + offset, obj.cbegin() + offset + max, static_cast<value_type*>(buffer));
update_time();
return max;
}
}
return 0;
}
u64 write(const void* buffer, u64 size) override
{
const u64 old_size = obj.size();

View File

@ -115,6 +115,11 @@ public:
return bytesRead;
}
u64 read_at(u64 offset, void* buffer, u64 size) override
{
return ReadData(offset, static_cast<u8*>(buffer), size);
}
u64 write(const void*, u64) override
{
return 0;

View File

@ -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;

View File

@ -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<void> _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());
}