092e870d2a
This is another bunch of callbacks which provide the file contents to the clients. We jump through some extra hoops in order to have more pleasant user experience. Simple stuff goes first. The file offset (or position) is split into the low and high parts because this is the format in which the clients receive the request from the server. They can simply copy the values as is into the struct without repackaging them (which we do instead in the end to get a 64-bit off_t). Another thing is that we try to minimize the number of lseek() calls and to keep as few file descriptors open as possible. We cannot open all the files at once as there could be thousands of them and we'll run out of the allowed number of the fds. However, the server can (in theory) request the file ranges randomly so we need to be prepared for that. One way to do that would be to always open the file before reading and close it immediately afterwards. A dead simple solution with an acceptable performance, but... some file systems do not support seeking, such as FTP directories mounted over FUSE. However, they handle sequential reading just fine *and* the server requests the data sequentially most of the time so we can exploit this. Thus open the file only once, during the first range request and keep it open until the server reads all the data. In order to know how much data is left we keep an accurate account of all reads and maintain the file offset ourselves. This also allows us to avoid calling lseek() when the file offset will not be effectively changed. However, if the server requests some weird offset then we have no choice and will attempt seeking. Unfortunately, we cannot tell whether it is a genuine failure or the file system just does not support seeking, so we do not handle the error further. (One workaround would be to reopen the file and keep reading it until we're at the correct offset.) In this way we can support sequential-only file systems if the server requests the contents sequentially (and it does). Also note that we do an fstat() right after opening the file in order to have an accurate value of file size, for this exact file descriptor we will be using. We should have it filled it by now, but just in case... There is one more thing to explain. The cbRequested field specifies the maximum number of bytes the server can handle, not the required number. Usually this is some power-of-two number like 64 KB, based on the size of the files on the clipboard. This is why posix_file_read_perform() does not attempt to fill the whole buffer by repeatedly calling read() if it has read less data than requested. The server can handle underruns just fine (and this spares us from special-casing the EOF condition). |
||
---|---|---|
.. | ||
asn1 | ||
bcrypt | ||
clipboard | ||
com | ||
comm | ||
credentials | ||
credui | ||
crt | ||
crypto | ||
dsparse | ||
environment | ||
error | ||
file | ||
handle | ||
heap | ||
input | ||
interlocked | ||
io | ||
library | ||
locale | ||
memory | ||
nt | ||
path | ||
pipe | ||
pool | ||
registry | ||
rpc | ||
security | ||
shell | ||
smartcard | ||
sspi | ||
sspicli | ||
synch | ||
sysinfo | ||
thread | ||
timezone | ||
utils | ||
winhttp | ||
winsock | ||
wnd | ||
wtsapi | ||
CMakeLists.txt | ||
dummy.c | ||
log.h |