summaryrefslogtreecommitdiff
path: root/rsync/stream.c
blob: d20d866e63fcb099519648f5c186de8854b7d43e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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);
}