librsync
2.3.1
|
Manage librsync streams of IO. More...
Go to the source code of this file.
Functions | |
int | rs_buffers_copy (rs_buffers_t *stream, int max_len) |
Copy up to max_len bytes from input of stream to its output. More... | |
void | rs_buffers_check_exit (rs_buffers_t const *stream) |
Assert input is empty or output is full. More... | |
Manage librsync streams of IO.
See
OK, so I'll admit IO here is a little complex. The most important player here is the stream, which is an object for managing filter operations. It has both input and output sides, both of which is just a (pointer,len) pair into a buffer provided by the client. The code controlling the stream handles however much data it wants, and the client provides or accepts however much is convenient.
At the same time as being friendly to the client, we also try to be very friendly to the internal code. It wants to be able to ask for arbitrary amounts of input or output and get it without having to keep track of partial completion. So there are functions which either complete, or queue whatever was not sent and return RS_BLOCKED.
The output buffer is a little more clever than simply a data buffer. Instead it knows that we can send either literal data, or data copied through from the input of the stream.
In buf.c you will find functions that then map buffers onto stdio files.
So on return from an encoding function, either the input or the output or possibly both will have no more bytes available.
librsync never does IO or memory allocation, but relies on the caller. This is very nice for integration, but means that we have to be fairly flexible as to when we can ‘read’ or ‘write’ stuff internally.
librsync basically does two types of IO. It reads network integers of various lengths which encode command and control information such as versions and signatures. It also does bulk data transfer.
IO of network integers is internally buffered, because higher levels of the code need to see them transmitted atomically: it's no good to read half of a uint32. So there is a small and fixed length internal buffer which accumulates these. Unlike previous versions of the library, we don't require that the caller hold the start until the whole thing has arrived, which guarantees that we can always make progress.
On each call into a stream iterator, it should begin by trying to flush output. This may well use up all the remaining stream space, in which case nothing else can be done.
Definition in file stream.c.
int rs_buffers_copy | ( | rs_buffers_t * | stream, |
int | max_len | ||
) |
Copy up to max_len
bytes from input of stream to its output.
This always does the copy immediately. Most functions should call rs_tube_copy() to cause the copy to happen gradually as space becomes available.
void rs_buffers_check_exit | ( | rs_buffers_t const * | stream | ) |