ODX copy error with misaligned file size
Noticed while testing something on Win2016:
When doing a copy/paste within a share on Win2016,
the client will use ODX_READ/ODX_WRITE. That all
appears to work OK, but on the last ODX write in the
sequence, NS returns STATUS_INVALID_PARAMETER.
It looks like this may have to do with the previous
ODX write returning a transfer size that's limited to
the size of the file, which happens to be not an even
multiple of the block size.
Steps to Reproduce:
Map an NS share on a Win2016 client.
Copy a file into the share, making sure to choose one
with length that's not an even multiple of 512.
Start a network capture
Use explorer to copy/paste within the same share.
Examine the network capture, looking at the last ODX write.
The status invalid parameter is not expected.
The file copy appears to be successful,
but the protocol error is not expected.
See status invaild paramter, i.e.
frame 102 in the attached odx1.snoop
Updated by Gordon Ross about 1 year ago
When a Windows client uses ODX to copy a file where the length is not an even multiple of the ODX block size, it will use a transfer length that's rounded-up to a block boundary. I guess this makes sense for Windows, where the ODX copy is reportedly doing the copy "below" the file system, so in their case they would be actually copying those underlying file system blocks, including the unused space in the last block beyond the end of file.
With such a request, we currently return a "transferred" size on the last request that reflects the actual file size. In response, the client appears to come back with another ODX write request covering the range from EOF to the rounded up size. (i.e. frame 101 in the attached odx1.snoop)
The starting offset of the follow-on request is not block aligned (probably because our previous "transferred" return was not block aligned) so this new request gets an "invalid parameter" error due to alignment rules for ODX requests.
To avoid this error when copying such files (non-aligned length) we should return a "transferred" size that includes that "rounded up" size, not the actual EOF. That's relatively simple to do, though in the back-end copying functions, we want the copy to terminate at the actual EOF, not the rounded up size.
Added odx3.snoop showing how it looks after the fix.
See frames 115, 117