-rw-r--r-- | rsync/stream.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/rsync/stream.c b/rsync/stream.c new file mode 100644 index 0000000..d20d866 --- a/dev/null +++ b/rsync/stream.c @@ -0,0 +1,155 @@ +/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- + * + * librsync -- dynamic caching and delta update in HTTP + * $Id$ + * + * Copyright (C) 2000, 2001 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + /* + * Programming languages should be designed not + * by piling feature on top of feature, but by + * removing the weaknesses and restrictions that + * make additional features appear necessary. + * -- Revised^5 Report on Scheme + */ + + +/* + * 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. + */ + +/* + * Manage librsync streams of IO. See scoop.c and tube.c for related + * code for input and output respectively. + * + * 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. + */ + +/* TODO: Return errors rather than aborting if something goes wrong. */ + + +#include <config_rsync.h> + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "rsync.h" +#include "stream.h" +#include "util.h" +#include "trace.h" + +static const int RS_STREAM_DOGTAG = 2001125; + + +/** + * \brief Copy up to \p max_len bytes from input of \b stream to its output. + * + * Return the number of bytes actually copied, which may be less than + * LEN if there is not enough space in one or the other stream. + * + * This always does the copy immediately. Most functions should call + * rs_tube_copy() to cause the copy to happen gradually as space + * becomes available. + */ +int rs_buffers_copy(rs_buffers_t *stream, int max_len) +{ + int len = max_len; + + assert(len > 0); + + if ((unsigned) len > stream->avail_in) { + rs_trace("copy limited to %d available input bytes", + stream->avail_in); + len = stream->avail_in; + } + + + if ((unsigned) len > stream->avail_out) { + rs_trace("copy limited to %d available output bytes", + stream->avail_out); + len = stream->avail_out; + } + + if (!len) + return 0; +/* rs_trace("stream copied chunk of %d bytes", len); */ + + memcpy(stream->next_out, stream->next_in, len); + + stream->next_out += len; + stream->avail_out -= len; + + stream->next_in += len; + stream->avail_in -= len; + + return len; +} + + +/** + * Whenever a stream processing function exits, it should have done so + * because it has either consumed all the input or has filled the + * output buffer. This function checks that simple postcondition. + */ +void rs_buffers_check_exit(rs_buffers_t const *stream) +{ + assert(stream->avail_in == 0 || stream->avail_out == 0); +} |