| 172 | VOID Close(FSP_FILE_SYSTEM*, PVOID /*FileContext*/) { } |
| 173 | |
| 174 | NTSTATUS Read(FSP_FILE_SYSTEM*, PVOID FileContext, PVOID Buffer, |
| 175 | UINT64 Offset, ULONG Length, PULONG PBytesTransferred) |
| 176 | { |
| 177 | Node* node = ctx_node(FileContext); |
| 178 | if (!node || !node->is_file()) return STATUS_INVALID_DEVICE_REQUEST; |
| 179 | auto t0 = GetTickCount64(); |
| 180 | try { |
| 181 | UINT64 size = node->size(); |
| 182 | if (Offset >= size) { |
| 183 | *PBytesTransferred = 0; |
| 184 | return STATUS_END_OF_FILE; |
| 185 | } |
| 186 | // Cap Length to what's actually inside the file. This is what every |
| 187 | // sane Windows file driver does; HxD-style readers issue reads that |
| 188 | // straddle EOF on sector-aligned chunks and expect the FS to return |
| 189 | // exactly (size - Offset) bytes for the tail. |
| 190 | ULONG cap = (ULONG)std::min<UINT64>(Length, size - Offset); |
| 191 | std::size_t got = node->read(Offset, Buffer, cap); |
| 192 | |
| 193 | // If the producer underdelivered (returned fewer bytes than the |
| 194 | // capped length), zero-fill the gap. Otherwise WinFsp+HxD see a |
| 195 | // partial read inside the file body and surface a "stream read |
| 196 | // error" — even though the user-visible file size says the bytes |
| 197 | // should be there. This matches sparse-file semantics: gaps in |
| 198 | // the page cache read as zeros, not as I/O failures. |
| 199 | if (got < cap) { |
| 200 | std::memset(static_cast<u8*>(Buffer) + got, 0, cap - got); |
| 201 | got = cap; |
| 202 | } |
| 203 | *PBytesTransferred = (ULONG)got; |
| 204 | auto dt = GetTickCount64() - t0; |
| 205 | if (dt > 200) { |
| 206 | log::info("[WinFsp] Read '{}' off={:#x} len={} took {}ms", |
| 207 | node->name(), Offset, Length, dt); |
| 208 | } |
| 209 | return STATUS_SUCCESS; |
| 210 | } catch (const std::exception& e) { |
| 211 | log::warn("[WinFsp] Read threw for '{}': {}", node->name(), e.what()); |
| 212 | *PBytesTransferred = 0; |
| 213 | return STATUS_IO_DEVICE_ERROR; |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | NTSTATUS GetFileInfo(FSP_FILE_SYSTEM*, PVOID FileContext, FSP_FSCTL_FILE_INFO* FileInfo) { |
| 218 | Node* node = ctx_node(FileContext); |