summaryrefslogtreecommitdiff
path: root/rsync/buf.c
Unidiff
Diffstat (limited to 'rsync/buf.c') (more/less context) (ignore whitespace changes)
-rw-r--r--rsync/buf.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/rsync/buf.c b/rsync/buf.c
new file mode 100644
index 0000000..2814583
--- a/dev/null
+++ b/rsync/buf.c
@@ -0,0 +1,214 @@
1/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 *
3 * librsync -- the library for network deltas
4 * $Id$
5 *
6 * Copyright (C) 2000, 2001 by Martin Pool <mbp@samba.org>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /*
24 | Pick a window, Jimmy, you're leaving.
25 | -- Martin Schwenke, regularly
26 */
27
28
29/*
30 * buf.c -- Buffers that map between stdio file streams and librsync
31 * streams. As the stream consumes input and produces output, it is
32 * refilled from appropriate input and output FILEs. A dynamically
33 * allocated buffer of configurable size is used as an intermediary.
34 *
35 * TODO: Perhaps be more efficient by filling the buffer on every call
36 * even if not yet completely empty. Check that it's really our
37 * buffer, and shuffle remaining data down to the front.
38 *
39 * TODO: Perhaps expose a routine for shuffling the buffers.
40 */
41
42
43#include <config_rsync.h>
44
45#include <assert.h>
46#include <stdlib.h>
47#include <stdio.h>
48#include <errno.h>
49#include <string.h>
50
51#include "rsync.h"
52#include "trace.h"
53#include "buf.h"
54#include "util.h"
55
56/**
57 * File IO buffer sizes.
58 */
59int rs_inbuflen = 16000, rs_outbuflen = 16000;
60
61
62struct rs_filebuf {
63 FILE *f;
64 char *buf;
65 size_t buf_len;
66};
67
68
69
70rs_filebuf_t *rs_filebuf_new(FILE *f, size_t buf_len)
71{
72 rs_filebuf_t *pf = rs_alloc_struct(rs_filebuf_t);
73
74 pf->buf = rs_alloc(buf_len, "file buffer");
75 pf->buf_len = buf_len;
76 pf->f = f;
77
78 return pf;
79}
80
81
82void rs_filebuf_free(rs_filebuf_t *fb)
83{
84 if ( fb->buf )
85 free ( fb->buf );
86 rs_bzero(fb, sizeof *fb);
87 free(fb);
88}
89
90
91/*
92 * If the stream has no more data available, read some from F into
93 * BUF, and let the stream use that. On return, SEEN_EOF is true if
94 * the end of file has passed into the stream.
95 */
96rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf,
97 void *opaque)
98{
99 int len;
100 rs_filebuf_t *fb = (rs_filebuf_t *) opaque;
101 FILE *f = fb->f;
102
103 /* This is only allowed if either the buf has no input buffer
104 * yet, or that buffer could possibly be BUF. */
105 if (buf->next_in != NULL) {
106 assert(buf->avail_in <= fb->buf_len);
107 assert(buf->next_in >= fb->buf);
108 assert(buf->next_in <= fb->buf + fb->buf_len);
109 } else {
110 assert(buf->avail_in == 0);
111 }
112
113 if (buf->eof_in || (buf->eof_in = feof(f))) {
114 rs_trace("seen end of file on input");
115 buf->eof_in = 1;
116 return RS_DONE;
117 }
118
119 if (buf->avail_in)
120 /* Still some data remaining. Perhaps we should read
121 anyhow? */
122 return RS_DONE;
123
124 len = fread(fb->buf, 1, fb->buf_len, f);
125 if (len < 0) {
126 if (ferror(f)) {
127 rs_error("error filling buf from file: %s",
128 strerror(errno));
129 return RS_IO_ERROR;
130 } else {
131 rs_error("no error bit, but got %d return when trying to read",
132 len);
133 return RS_IO_ERROR;
134 }
135 }
136 buf->avail_in = len;
137 buf->next_in = fb->buf;
138
139 return RS_DONE;
140}
141
142
143/*
144 * The buf is already using BUF for an output buffer, and probably
145 * contains some buffered output now. Write this out to F, and reset
146 * the buffer cursor.
147 */
148rs_result rs_outfilebuf_drain(rs_job_t *job, rs_buffers_t *buf, void *opaque)
149{
150 int present;
151 rs_filebuf_t *fb = (rs_filebuf_t *) opaque;
152 FILE *f = fb->f;
153
154 /* This is only allowed if either the buf has no output buffer
155 * yet, or that buffer could possibly be BUF. */
156 if (buf->next_out == NULL) {
157 assert(buf->avail_out == 0);
158
159 buf->next_out = fb->buf;
160 buf->avail_out = fb->buf_len;
161
162 return RS_DONE;
163 }
164
165 assert(buf->avail_out <= fb->buf_len);
166 assert(buf->next_out >= fb->buf);
167 assert(buf->next_out <= fb->buf + fb->buf_len);
168
169 present = buf->next_out - fb->buf;
170 if (present > 0) {
171 int result;
172
173 assert(present > 0);
174
175 result = fwrite(fb->buf, 1, present, f);
176 if (present != result) {
177 rs_error("error draining buf to file: %s",
178 strerror(errno));
179 return RS_IO_ERROR;
180 }
181
182 buf->next_out = fb->buf;
183 buf->avail_out = fb->buf_len;
184 }
185
186 return RS_DONE;
187}
188
189
190/**
191 * Default copy implementation that retrieves a part of a stdio file.
192 */
193rs_result rs_file_copy_cb(void *arg, off_t pos, size_t *len, void **buf)
194{
195 int got;
196 FILE *f = (FILE *) arg;
197
198 if (fseek(f, pos, SEEK_SET)) {
199 rs_log(RS_LOG_ERR, "seek failed: %s", strerror(errno));
200 return RS_IO_ERROR;
201 }
202
203 got = fread(*buf, 1, *len, f);
204 if (got == -1) {
205 rs_error(strerror(errno));
206 return RS_IO_ERROR;
207 } else if (got == 0) {
208 rs_error("unexpected eof on fd%d", fileno(f));
209 return RS_INPUT_ENDED;
210 } else {
211 *len = got;
212 return RS_DONE;
213 }
214}