Skip to content

Commit 933aedc

Browse files
authored
Correctly set FileOffsets in WriteHandle (#14562)
* Correctly set FileOffsets in WriteHandle * Apply PR suggestions
1 parent e7c520e commit 933aedc

3 files changed

Lines changed: 72 additions & 1 deletion

File tree

src/windows/common/relay.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1443,7 +1443,7 @@ void HTTPChunkBasedReadHandle::OnRead(const gsl::span<char>& Input)
14431443
}
14441444

14451445
WriteHandle::WriteHandle(HandleWrapper&& MovedHandle, const std::vector<char>& Buffer) :
1446-
Handle(std::move(MovedHandle)), Buffer(Buffer)
1446+
Handle(std::move(MovedHandle)), Buffer(Buffer), Offset(InitializeFileOffset(Handle.Get()))
14471447
{
14481448
Overlapped.hEvent = Event.get();
14491449
}
@@ -1475,10 +1475,15 @@ void WriteHandle::Schedule()
14751475

14761476
Event.ResetEvent();
14771477

1478+
Overlapped.Offset = Offset.LowPart;
1479+
Overlapped.OffsetHigh = Offset.HighPart;
1480+
14781481
// Schedule the write.
14791482
DWORD bytesWritten{};
14801483
if (WriteFile(Handle.Get(), Buffer.data(), static_cast<DWORD>(Buffer.size()), &bytesWritten, &Overlapped))
14811484
{
1485+
Offset.QuadPart += bytesWritten;
1486+
14821487
Buffer.erase(Buffer.begin(), Buffer.begin() + bytesWritten);
14831488
if (Buffer.empty())
14841489
{
@@ -1505,6 +1510,7 @@ void WriteHandle::Collect()
15051510
// Complete the write.
15061511
DWORD bytesWritten{};
15071512
THROW_IF_WIN32_BOOL_FALSE(GetOverlappedResult(Handle.Get(), &Overlapped, &bytesWritten, false));
1513+
Offset.QuadPart += bytesWritten;
15081514

15091515
Buffer.erase(Buffer.begin(), Buffer.begin() + bytesWritten);
15101516
if (Buffer.empty())

src/windows/common/relay.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ class WriteHandle : public OverlappedIOHandle
361361
wil::unique_event Event{wil::EventOptions::ManualReset};
362362
OVERLAPPED Overlapped{};
363363
std::vector<char> Buffer;
364+
LARGE_INTEGER Offset{};
364365
};
365366

366367
template <typename TRead = ReadHandle>

test/windows/WSLCTests.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4688,6 +4688,70 @@ class WSLCTests
46884688
runTest({"3\r\nfoo\r\n3\r\nbar\r\n0", "\r\n\r\n"}, {"foo", "bar"});
46894689
}
46904690

4691+
TEST_METHOD(WriteHandleContent)
4692+
{
4693+
WSL2_TEST_ONLY();
4694+
4695+
// Validate that writing to a pipe works as expected.
4696+
{
4697+
const std::string expectedData = "Pipe-test";
4698+
std::vector<char> writeBuffer{expectedData.begin(), expectedData.end()};
4699+
4700+
auto [readPipe, writePipe] = wsl::windows::common::wslutil::OpenAnonymousPipe(16 * 1024, true, false);
4701+
4702+
std::string readData;
4703+
wsl::windows::common::relay::MultiHandleWait io;
4704+
4705+
io.AddHandle(std::make_unique<wsl::windows::common::relay::ReadHandle>(std::move(readPipe), [&](const gsl::span<char>& buffer) {
4706+
if (!buffer.empty())
4707+
{
4708+
readData.append(buffer.data(), buffer.size());
4709+
}
4710+
}));
4711+
4712+
io.AddHandle(std::make_unique<WriteHandle>(std::move(writePipe), writeBuffer));
4713+
4714+
io.Run({});
4715+
4716+
VERIFY_ARE_EQUAL(expectedData, readData);
4717+
}
4718+
4719+
// Validate that writing to files work as expected.
4720+
// Use a large buffer to make sure that overlapped writes correctly handle offsets.
4721+
{
4722+
constexpr size_t fileSize = 50 * 1024 * 1024;
4723+
4724+
std::vector<char> writeBuffer(fileSize);
4725+
for (size_t i = 0; i < fileSize; i++)
4726+
{
4727+
writeBuffer[i] = static_cast<char>(i % 251);
4728+
}
4729+
4730+
auto outputFile = wil::open_or_create_file(L"write-handle-test", GENERIC_WRITE | GENERIC_READ, 0, nullptr);
4731+
4732+
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
4733+
outputFile.reset();
4734+
std::filesystem::remove("write-handle-test");
4735+
});
4736+
4737+
wsl::windows::common::relay::MultiHandleWait io;
4738+
io.AddHandle(std::make_unique<WriteHandle>(outputFile.get(), writeBuffer));
4739+
io.Run({});
4740+
4741+
VERIFY_ARE_NOT_EQUAL(SetFilePointer(outputFile.get(), 0, nullptr, FILE_BEGIN), INVALID_SET_FILE_POINTER);
4742+
4743+
LARGE_INTEGER size{};
4744+
VERIFY_WIN32_BOOL_SUCCEEDED(GetFileSizeEx(outputFile.get(), &size));
4745+
VERIFY_ARE_EQUAL(static_cast<long long>(fileSize), size.QuadPart);
4746+
4747+
std::vector<char> readBuffer(fileSize);
4748+
DWORD bytesRead = 0;
4749+
VERIFY_IS_TRUE(ReadFile(outputFile.get(), readBuffer.data(), static_cast<DWORD>(fileSize), &bytesRead, nullptr));
4750+
VERIFY_ARE_EQUAL(static_cast<DWORD>(fileSize), bytesRead);
4751+
VERIFY_IS_TRUE(readBuffer == writeBuffer);
4752+
}
4753+
}
4754+
46914755
TEST_METHOD(DockerIORelay)
46924756
{
46934757
using namespace wsl::windows::common::relay;

0 commit comments

Comments
 (0)