[bug] Windows-to-Linux remote mount overlapped I/O is not detecting EOF for read operations #48
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit

This commit is contained in:
Scott E. Graves 2025-04-17 08:24:34 -05:00
parent 45080aa32f
commit ece42df528
9 changed files with 35 additions and 29 deletions

View File

@ -14,6 +14,7 @@
* \#45 [bug] Windows-to-Linux remote mount is not handling attempts to remove a non-empty directory properly * \#45 [bug] Windows-to-Linux remote mount is not handling attempts to remove a non-empty directory properly
* \#46 [bug] Changes to maximum cache size should be updated live * \#46 [bug] Changes to maximum cache size should be updated live
* \#47 [bug] Windows-to-Linux remote mount is allowing directory rename when directory is not empty * \#47 [bug] Windows-to-Linux remote mount is allowing directory rename when directory is not empty
* \#48 [bug] Windows-to-Linux remote mount overlapped I/O is not detecting EOF for read operations
### Changes from v2.0.5-rc ### Changes from v2.0.5-rc

View File

@ -346,15 +346,16 @@ public:
DECODE_OR_RETURN(request, length); DECODE_OR_RETURN(request, length);
data_buffer buffer(length); data_buffer buffer(length);
UINT32 bytes_transferred{0}; UINT32 bytes_transferred{0U};
ret = this->winfsp_read(file_desc, buffer.data(), offset, length, ret = this->winfsp_read(file_desc, buffer.data(), offset, length,
&bytes_transferred); &bytes_transferred);
if (ret == STATUS_SUCCESS) { response.encode(bytes_transferred);
response.encode(bytes_transferred); buffer.resize(bytes_transferred);
if (bytes_transferred != 0U) {
response.encode(buffer.data(), bytes_transferred); if ((ret == STATUS_SUCCESS) && (bytes_transferred != 0U)) {
} response.encode(buffer.data(), bytes_transferred);
} }
return ret; return ret;
}}); }});
handler_lookup_.insert( handler_lookup_.insert(

View File

@ -28,7 +28,6 @@
#include "drives/directory_iterator.hpp" #include "drives/directory_iterator.hpp"
#include "drives/remote/remote_open_file_table.hpp" #include "drives/remote/remote_open_file_table.hpp"
#include "events/event_system.hpp" #include "events/event_system.hpp"
#include "events/types/debug_log.hpp"
#include "events/types/remote_server_event.hpp" #include "events/types/remote_server_event.hpp"
#include "platform/platform.hpp" #include "platform/platform.hpp"
#include "types/remote.hpp" #include "types/remote.hpp"
@ -1379,18 +1378,12 @@ auto remote_server::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
if (ret == STATUS_SUCCESS) { if (ret == STATUS_SUCCESS) {
auto res = pread64(static_cast<native_handle>(handle), buffer, length, auto res = pread64(static_cast<native_handle>(handle), buffer, length,
static_cast<off_t>(offset)); static_cast<off_t>(offset));
event_system::instance().raise<debug_log>(
function_name,
fmt::format("read|offset|{}|len|{}|res|{}", offset, length, res));
if (res >= 0) { if (res >= 0) {
*bytes_transferred = static_cast<UINT32>(res); *bytes_transferred = static_cast<UINT32>(res);
} else { } else {
ret = ret =
static_cast<packet::error_type>(utils::unix_error_to_windows(errno)); static_cast<packet::error_type>(utils::unix_error_to_windows(errno));
} }
event_system::instance().raise<debug_log>(
function_name,
fmt::format("read|offset|{}|len|{}|res|{}", offset, length, res));
} }
RAISE_REMOTE_FUSE_SERVER_EVENT( RAISE_REMOTE_FUSE_SERVER_EVENT(

View File

@ -198,11 +198,6 @@ auto remote_client::winfsp_create(PWSTR file_name, UINT32 create_options,
utils::string::to_utf8(file_name), utils::string::to_utf8(file_name),
}); });
} }
#if defined(_WIN32)
else {
ret = STATUS_OBJECT_NAME_COLLISION;
}
#endif // defined(_WIN32)
} }
return ret; return ret;
@ -232,7 +227,8 @@ auto remote_client::winfsp_get_dir_buffer([[maybe_unused]] PVOID file_desc,
if (get_directory_buffer(reinterpret_cast<native_handle>(file_desc), ptr)) { if (get_directory_buffer(reinterpret_cast<native_handle>(file_desc), ptr)) {
return static_cast<packet::error_type>(STATUS_SUCCESS); return static_cast<packet::error_type>(STATUS_SUCCESS);
} }
#endif #endif // defined(_WIN32)
return static_cast<packet::error_type>(STATUS_INVALID_HANDLE); return static_cast<packet::error_type>(STATUS_INVALID_HANDLE);
} }
@ -392,6 +388,8 @@ auto remote_client::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
-> packet::error_type { -> packet::error_type {
REPERTORY_USES_FUNCTION_NAME(); REPERTORY_USES_FUNCTION_NAME();
*bytes_transferred = 0U;
packet request; packet request;
request.encode(file_desc); request.encode(file_desc);
request.encode(offset); request.encode(offset);
@ -403,14 +401,8 @@ auto remote_client::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
packet_client_.send(function_name, request, response, service_flags), packet_client_.send(function_name, request, response, service_flags),
}; };
DECODE_OR_IGNORE(&response, *bytes_transferred); DECODE_OR_IGNORE(&response, *bytes_transferred);
if (ret == STATUS_SUCCESS) { if ((ret == STATUS_SUCCESS) && (*bytes_transferred != 0U)) {
ret = response.decode(buffer, *bytes_transferred); ret = response.decode(buffer, *bytes_transferred);
#if defined(_WIN32)
if ((ret == STATUS_SUCCESS) &&
((*bytes_transferred == 0U) || (*bytes_transferred != length))) {
::SetLastError(ERROR_HANDLE_EOF);
}
#endif
} }
return ret; return ret;
@ -529,6 +521,8 @@ auto remote_client::winfsp_write(PVOID file_desc, PVOID buffer, UINT64 offset,
-> packet::error_type { -> packet::error_type {
REPERTORY_USES_FUNCTION_NAME(); REPERTORY_USES_FUNCTION_NAME();
*bytes_transferred = 0U;
packet request; packet request;
request.encode(file_desc); request.encode(file_desc);
request.encode(length); request.encode(length);

View File

@ -1221,6 +1221,7 @@ auto remote_server::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
? STATUS_SUCCESS ? STATUS_SUCCESS
: FspNtStatusFromWin32(::GetLastError()); : FspNtStatusFromWin32(::GetLastError());
} }
if (ret != STATUS_SUCCESS) { if (ret != STATUS_SUCCESS) {
RAISE_REMOTE_WINFSP_SERVER_EVENT(function_name, RAISE_REMOTE_WINFSP_SERVER_EVENT(function_name,
get_open_file_path(file_desc), ret); get_open_file_path(file_desc), ret);

View File

@ -143,6 +143,9 @@ auto remote_winfsp_drive::Create(PWSTR file_name, UINT32 create_options,
wcsncpy(ofi->NormalizedName, file_path.data(), wcslen(file_path.c_str())); wcsncpy(ofi->NormalizedName, file_path.data(), wcslen(file_path.c_str()));
ofi->NormalizedNameSize = ofi->NormalizedNameSize =
static_cast<UINT16>(wcslen(file_path.c_str()) * sizeof(WCHAR)); static_cast<UINT16>(wcslen(file_path.c_str()) * sizeof(WCHAR));
if (exists != 0U) {
ret = STATUS_OBJECT_NAME_COLLISION;
}
} }
return ret; return ret;
@ -346,9 +349,15 @@ void remote_winfsp_drive::populate_file_info(const json &item,
auto remote_winfsp_drive::Read(PVOID /*file_node*/, PVOID file_desc, auto remote_winfsp_drive::Read(PVOID /*file_node*/, PVOID file_desc,
PVOID buffer, UINT64 offset, ULONG length, PVOID buffer, UINT64 offset, ULONG length,
PULONG bytes_transferred) -> NTSTATUS { PULONG bytes_transferred) -> NTSTATUS {
return remote_instance_->winfsp_read( auto ret = remote_instance_->winfsp_read(
file_desc, buffer, offset, length, file_desc, buffer, offset, length,
reinterpret_cast<PUINT32>(bytes_transferred)); reinterpret_cast<PUINT32>(bytes_transferred));
fmt::println("read|len|{}|ret|{}|bytes|{}", length, ret, *bytes_transferred);
if ((ret == STATUS_SUCCESS) && (*bytes_transferred != length)) {
::SetLastError(ERROR_HANDLE_EOF);
}
return ret;
} }
auto remote_winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc, auto remote_winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc,

View File

@ -122,8 +122,8 @@ open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
open_file::~open_file() { close(); } open_file::~open_file() { close(); }
auto open_file::adjust_cache_size(std::uint64_t file_size, auto open_file::adjust_cache_size(std::uint64_t file_size, bool shrink)
bool shrink) -> api_error { -> api_error {
REPERTORY_USES_FUNCTION_NAME(); REPERTORY_USES_FUNCTION_NAME();
if (file_size == get_file_size()) { if (file_size == get_file_size()) {
@ -554,6 +554,7 @@ auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
read_size = read_size =
utils::calculate_read_size(get_file_size(), read_size, read_offset); utils::calculate_read_size(get_file_size(), read_size, read_offset);
if (read_size == 0U) { if (read_size == 0U) {
data.resize(0U);
return api_error::success; return api_error::success;
} }

View File

@ -207,6 +207,7 @@ auto ring_buffer_base::read(std::size_t read_size, std::uint64_t read_offset,
read_size = read_size =
utils::calculate_read_size(get_file_size(), read_size, read_offset); utils::calculate_read_size(get_file_size(), read_size, read_offset);
if (read_size == 0U) { if (read_size == 0U) {
data.resize(0U);
return api_error::success; return api_error::success;
} }

View File

@ -334,9 +334,14 @@ static void test_overlapped_file(auto &&mount_location, auto &&file_path,
EXPECT_EQ(0, EXPECT_EQ(0,
std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read)); std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read));
LARGE_INTEGER size{};
::GetFileSizeEx(handle, &size);
read_buffer.clear(); read_buffer.clear();
read_buffer.resize(buffer_size); read_buffer.resize(buffer_size);
overlapped.Offset = 3U * bytes_per_sector; overlapped.Offset = 3U * bytes_per_sector;
fmt::println("size|{}|offset|{}|buf_size|{}", size.QuadPart,
overlapped.Offset, buffer_size);
ret = ::ReadFile(handle, read_buffer.data(), bytes_per_sector, &bytes_read, ret = ::ReadFile(handle, read_buffer.data(), bytes_per_sector, &bytes_read,
&overlapped); &overlapped);
EXPECT_TRUE(ret || ERROR_IO_PENDING == ::GetLastError() || EXPECT_TRUE(ret || ERROR_IO_PENDING == ::GetLastError() ||