mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
Implement fs::file::get_id()
File descripor ID with 2 provided ways to compare between them: 1. is_mirror_of(): Test if identical: For example: when LHS writes one byte to a file at X offset, RHS file be able to read that exact byte at X offset) 2. is_coherent_with(): Test if both files point to the same file: For example: if a file descriptor pointing to the complete file exists and is being truncated to 0 bytes from non- -zero size state: this has to affect both RHS and LHS files.
This commit is contained in:
parent
e27e6c0b2d
commit
eecadab387
@ -244,6 +244,11 @@ namespace fs
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file_id file_base::get_id()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
u64 file_base::write_gather(const iovec_clone* buffers, u64 buf_count)
|
u64 file_base::write_gather(const iovec_clone* buffers, u64 buf_count)
|
||||||
{
|
{
|
||||||
u64 total = 0;
|
u64 total = 0;
|
||||||
@ -272,6 +277,66 @@ namespace fs
|
|||||||
return this->write(buf.get(), total);
|
return this->write(buf.get(), total);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file_id::operator bool() const
|
||||||
|
{
|
||||||
|
return !type.empty() && !data.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if identical
|
||||||
|
// For example: when LHS writes one byte to a file at X offset, RHS file be able to read that exact byte at X offset)
|
||||||
|
bool file_id::is_mirror_of(const file_id& rhs) const
|
||||||
|
{
|
||||||
|
// If either is an invalid ID we cannot compare safely, return false
|
||||||
|
return rhs && type == rhs.type && data == rhs.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if both files point to the same file
|
||||||
|
// For example: if a file descriptor pointing to the complete file exists and is being truncated to 0 bytes from non-
|
||||||
|
// -zero size state: this has to affect both RHS and LHS files.
|
||||||
|
bool file_id::is_coherent_with(const file_id& rhs) const
|
||||||
|
{
|
||||||
|
struct id_view
|
||||||
|
{
|
||||||
|
std::string_view type_view;
|
||||||
|
std::basic_string_view<u8> data_view;
|
||||||
|
};
|
||||||
|
|
||||||
|
id_view _rhs{rhs.type, {rhs.data.data(), rhs.data.size()}};
|
||||||
|
id_view _lhs{type, {data.data(), data.size()}};
|
||||||
|
|
||||||
|
// Peek through fs::file wrappers
|
||||||
|
auto peek_wrapppers = [](id_view& id)
|
||||||
|
{
|
||||||
|
u64 offset_count = 0;
|
||||||
|
constexpr auto lv2_view = "lv2_file::file_view: "sv;
|
||||||
|
|
||||||
|
for (usz pos = 0; (pos = id.type_view.find(lv2_view, pos)) != umax; pos += lv2_view.size())
|
||||||
|
{
|
||||||
|
offset_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove offsets data
|
||||||
|
id.data_view.remove_suffix(sizeof(u64) * offset_count);
|
||||||
|
|
||||||
|
// Get last category identifier
|
||||||
|
if (usz sep = id.type_view.rfind(": "); sep != umax)
|
||||||
|
{
|
||||||
|
id.type_view.remove_prefix(sep + 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
peek_wrapppers(_rhs);
|
||||||
|
peek_wrapppers(_lhs);
|
||||||
|
|
||||||
|
// If either is an invalid ID we cannot compare safely, return false
|
||||||
|
if (_rhs.type_view.empty() || _rhs.data_view.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _rhs.type_view == _lhs.type_view && _rhs.data_view == _lhs.data_view;
|
||||||
|
}
|
||||||
|
|
||||||
dir_base::~dir_base()
|
dir_base::~dir_base()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -1289,6 +1354,28 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
|||||||
{
|
{
|
||||||
return m_handle;
|
return m_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file_id get_id() override
|
||||||
|
{
|
||||||
|
file_id id{"windows_file"};
|
||||||
|
id.data.resize(sizeof(FILE_ID_INFO));
|
||||||
|
|
||||||
|
FILE_ID_INFO info;
|
||||||
|
|
||||||
|
if (!GetFileInformationByHandleEx(m_handle, FileIdInfo, &info, sizeof(info)))
|
||||||
|
{
|
||||||
|
// Try GetFileInformationByHandle as a fallback
|
||||||
|
BY_HANDLE_FILE_INFORMATION info2;
|
||||||
|
ensure(GetFileInformationByHandle(m_handle, &info2));
|
||||||
|
|
||||||
|
info = {};
|
||||||
|
info.VolumeSerialNumber = info2.dwVolumeSerialNumber;
|
||||||
|
std::memcpy(&info.FileId, &info2.nFileIndexHigh, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(id.data.data(), &info, sizeof(info));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
m_file = std::make_unique<windows_file>(handle);
|
m_file = std::make_unique<windows_file>(handle);
|
||||||
@ -1481,6 +1568,19 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
|||||||
return m_fd;
|
return m_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file_id get_id() override
|
||||||
|
{
|
||||||
|
struct ::stat file_info;
|
||||||
|
ensure(::fstat(m_fd, &file_info) == 0); // "file::get_id"
|
||||||
|
|
||||||
|
file_id id{"unix_file"};
|
||||||
|
id.data.resize(sizeof(file_info.st_dev) + sizeof(file_info.st_ino));
|
||||||
|
|
||||||
|
std::memcpy(id.data.data(), &file_info.st_dev, sizeof(file_info.st_dev));
|
||||||
|
std::memcpy(id.data.data() + sizeof(file_info.st_dev), &file_info.st_ino, sizeof(file_info.st_ino));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
u64 write_gather(const iovec_clone* buffers, u64 buf_count) override
|
u64 write_gather(const iovec_clone* buffers, u64 buf_count) override
|
||||||
{
|
{
|
||||||
static_assert(sizeof(iovec) == sizeof(iovec_clone), "Weird iovec size");
|
static_assert(sizeof(iovec) == sizeof(iovec_clone), "Weird iovec size");
|
||||||
@ -1615,6 +1715,16 @@ fs::native_handle fs::file::get_handle() const
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs::file_id fs::file::get_id() const
|
||||||
|
{
|
||||||
|
if (m_file)
|
||||||
|
{
|
||||||
|
return m_file->get_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool fs::dir::open(const std::string& path)
|
bool fs::dir::open(const std::string& path)
|
||||||
{
|
{
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
@ -2256,3 +2366,12 @@ void fmt_class_string<fs::error>::format(std::string& out, u64 arg)
|
|||||||
return unknown;
|
return unknown;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void fmt_class_string<fs::file_id>::format(std::string& out, u64 arg)
|
||||||
|
{
|
||||||
|
const fs::file_id& id = get_object(arg);
|
||||||
|
|
||||||
|
// TODO: Format data
|
||||||
|
fmt::append(out, "{type='%s'}", id.type);
|
||||||
|
}
|
||||||
|
@ -84,6 +84,16 @@ namespace fs
|
|||||||
usz iov_len;
|
usz iov_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct file_id
|
||||||
|
{
|
||||||
|
std::string type;
|
||||||
|
std::vector<u8> data;
|
||||||
|
|
||||||
|
explicit operator bool() const;
|
||||||
|
bool is_mirror_of(const file_id&) const;
|
||||||
|
bool is_coherent_with(const file_id&) const;
|
||||||
|
};
|
||||||
|
|
||||||
// File handle base
|
// File handle base
|
||||||
struct file_base
|
struct file_base
|
||||||
{
|
{
|
||||||
@ -98,6 +108,7 @@ namespace fs
|
|||||||
virtual u64 seek(s64 offset, seek_mode whence) = 0;
|
virtual u64 seek(s64 offset, seek_mode whence) = 0;
|
||||||
virtual u64 size() = 0;
|
virtual u64 size() = 0;
|
||||||
virtual native_handle get_handle();
|
virtual native_handle get_handle();
|
||||||
|
virtual file_id get_id();
|
||||||
virtual u64 write_gather(const iovec_clone* buffers, u64 buf_count);
|
virtual u64 write_gather(const iovec_clone* buffers, u64 buf_count);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -505,6 +516,9 @@ namespace fs
|
|||||||
// Get native handle if available
|
// Get native handle if available
|
||||||
native_handle get_handle() const;
|
native_handle get_handle() const;
|
||||||
|
|
||||||
|
// Get file ID information (custom ID)
|
||||||
|
file_id get_id() const;
|
||||||
|
|
||||||
// Gathered write
|
// Gathered write
|
||||||
u64 write_gather(const iovec_clone* buffers, u64 buf_count,
|
u64 write_gather(const iovec_clone* buffers, u64 buf_count,
|
||||||
u32 line = __builtin_LINE(),
|
u32 line = __builtin_LINE(),
|
||||||
|
@ -143,4 +143,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
u64 size() override { return file_size; }
|
u64 size() override { return file_size; }
|
||||||
|
|
||||||
|
fs::file_id get_id() override
|
||||||
|
{
|
||||||
|
fs::file_id id = edata_file.get_id();
|
||||||
|
id.type.insert(0, "EDATADecrypter: "sv);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -641,6 +641,18 @@ struct lv2_file::file_view : fs::file_base
|
|||||||
{
|
{
|
||||||
return m_file->file.size();
|
return m_file->file.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs::file_id get_id() override
|
||||||
|
{
|
||||||
|
fs::file_id id = m_file->file.get_id();
|
||||||
|
|
||||||
|
be_t<u64> off = m_off;
|
||||||
|
const auto ptr = reinterpret_cast<u8*>(&off);
|
||||||
|
|
||||||
|
id.data.insert(id.data.end(), ptr, ptr + sizeof(off));
|
||||||
|
id.type.insert(0, "lv2_file::file_view: "sv);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fs::file lv2_file::make_view(const std::shared_ptr<lv2_file>& _file, u64 offset)
|
fs::file lv2_file::make_view(const std::shared_ptr<lv2_file>& _file, u64 offset)
|
||||||
|
Loading…
Reference in New Issue
Block a user