librsync  2.0.1
buf.c
1 /*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
2  *
3  * librsync -- the library for network deltas
4  *
5  * Copyright (C) 2000, 2001 by Martin Pool <[email protected]>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 
22  /*
23  | Pick a window, Jimmy, you're leaving.
24  */
25 
26 
27 /*
28  * buf.c -- Buffers that map between stdio file streams and librsync
29  * streams. As the stream consumes input and produces output, it is
30  * refilled from appropriate input and output FILEs. A dynamically
31  * allocated buffer of configurable size is used as an intermediary.
32  *
33  * TODO: Perhaps be more efficient by filling the buffer on every call
34  * even if not yet completely empty. Check that it's really our
35  * buffer, and shuffle remaining data down to the front.
36  *
37  * TODO: Perhaps expose a routine for shuffling the buffers.
38  */
39 
40 
41 #include "config.h"
42 #include <sys/types.h>
43 
44 #include <assert.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <errno.h>
48 #include <string.h>
49 
50 #include "librsync.h"
51 #include "trace.h"
52 #include "buf.h"
53 #include "job.h"
54 #include "util.h"
55 
56 /* use fseeko instead of fseek for long file support if we have it */
57 #ifdef HAVE_FSEEKO
58 #define fseek fseeko
59 #elif defined HAVE_FSEEKO64
60 #define fseek fseeko64
61 #endif
62 
63 /**
64  * File IO buffer sizes.
65  */
66 int rs_inbuflen = 16000, rs_outbuflen = 16000;
67 
68 
69 struct rs_filebuf {
70  FILE *f;
71  char *buf;
72  size_t buf_len;
73 };
74 
75 
76 rs_filebuf_t *rs_filebuf_new(FILE *f, size_t buf_len)
77 {
78  rs_filebuf_t *pf = rs_alloc_struct(rs_filebuf_t);
79 
80  pf->buf = rs_alloc(buf_len, "file buffer");
81  pf->buf_len = buf_len;
82  pf->f = f;
83 
84  return pf;
85 }
86 
87 
88 void rs_filebuf_free(rs_filebuf_t *fb)
89 {
90  free(fb->buf);
91  rs_bzero(fb, sizeof *fb);
92  free(fb);
93 }
94 
95 
96 /*
97  * If the stream has no more data available, read some from F into
98  * BUF, and let the stream use that. On return, SEEN_EOF is true if
99  * the end of file has passed into the stream.
100  */
101 rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf,
102  void *opaque)
103 {
104  int len;
105  rs_filebuf_t *fb = (rs_filebuf_t *) opaque;
106  FILE *f = fb->f;
107 
108  /* This is only allowed if either the buf has no input buffer
109  * yet, or that buffer could possibly be BUF. */
110  if (buf->next_in != NULL) {
111  assert(buf->avail_in <= fb->buf_len);
112  assert(buf->next_in >= fb->buf);
113  assert(buf->next_in <= fb->buf + fb->buf_len);
114  } else {
115  assert(buf->avail_in == 0);
116  }
117 
118  if (buf->eof_in || (buf->eof_in = feof(f))) {
119  rs_trace("seen end of file on input");
120  buf->eof_in = 1;
121  return RS_DONE;
122  }
123 
124  if (buf->avail_in)
125  /* Still some data remaining. Perhaps we should read
126  anyhow? */
127  return RS_DONE;
128 
129  len = fread(fb->buf, 1, fb->buf_len, f);
130  if (len <= 0) {
131  /* This will happen if file size is a multiple of input block len
132  */
133  if (feof(f)) {
134  rs_trace("seen end of file on input");
135  buf->eof_in = 1;
136  return RS_DONE;
137  }
138  if (ferror(f)) {
139  rs_error("error filling buf from file: %s",
140  strerror(errno));
141  return RS_IO_ERROR;
142  } else {
143  rs_error("no error bit, but got %d return when trying to read",
144  len);
145  return RS_IO_ERROR;
146  }
147  }
148  buf->avail_in = len;
149  buf->next_in = fb->buf;
150 
151  job->stats.in_bytes += len;
152 
153  return RS_DONE;
154 }
155 
156 
157 /*
158  * The buf is already using BUF for an output buffer, and probably
159  * contains some buffered output now. Write this out to F, and reset
160  * the buffer cursor.
161  */
162 rs_result rs_outfilebuf_drain(rs_job_t *job, rs_buffers_t *buf, void *opaque)
163 {
164  int present;
165  rs_filebuf_t *fb = (rs_filebuf_t *) opaque;
166  FILE *f = fb->f;
167 
168  /* This is only allowed if either the buf has no output buffer
169  * yet, or that buffer could possibly be BUF. */
170  if (buf->next_out == NULL) {
171  assert(buf->avail_out == 0);
172 
173  buf->next_out = fb->buf;
174  buf->avail_out = fb->buf_len;
175 
176  return RS_DONE;
177  }
178 
179  assert(buf->avail_out <= fb->buf_len);
180  assert(buf->next_out >= fb->buf);
181  assert(buf->next_out <= fb->buf + fb->buf_len);
182 
183  present = buf->next_out - fb->buf;
184  if (present > 0) {
185  int result;
186 
187  assert(present > 0);
188 
189  result = fwrite(fb->buf, 1, present, f);
190  if (present != result) {
191  rs_error("error draining buf to file: %s",
192  strerror(errno));
193  return RS_IO_ERROR;
194  }
195 
196  buf->next_out = fb->buf;
197  buf->avail_out = fb->buf_len;
198 
199  job->stats.out_bytes += result;
200  }
201 
202  return RS_DONE;
203 }
204 
205 
206 rs_result rs_file_copy_cb(void *arg, rs_long_t pos, size_t *len, void **buf)
207 {
208  int got;
209  FILE *f = (FILE *) arg;
210 
211  if (fseek(f, pos, SEEK_SET)) {
212  rs_log(RS_LOG_ERR, "seek failed: %s", strerror(errno));
213  return RS_IO_ERROR;
214  }
215 
216  got = fread(*buf, 1, *len, f);
217  if (got == -1) {
218  rs_error("read error: %s", strerror(errno));
219  return RS_IO_ERROR;
220  } else if (got == 0) {
221  rs_error("unexpected eof on fd%d", fileno(f));
222  return RS_INPUT_ENDED;
223  } else {
224  *len = got;
225  return RS_DONE;
226  }
227 }
Description of input and output buffers.
Definition: librsync.h:360
Definition: buf.c:69
size_t avail_out
Remaining free space at next_out.
Definition: librsync.h:396
long long rs_long_t
A long integer type that can handle the largest file offsets.
int rs_inbuflen
Buffer sizes for file IO.
Definition: buf.c:66
char * next_out
Next output byte should be put there References a pointer which on entry points to the start of the o...
Definition: librsync.h:388
size_t avail_in
Number of bytes available at next_in References the length of available input.
Definition: librsync.h:375
rs_long_t out_bytes
Total bytes written to output.
Definition: librsync.h:253
Error in file or network IO.
Definition: librsync.h:202
rs_stats_t stats
Encoding statistics.
Definition: job.h:69
rs_long_t in_bytes
Total bytes read from input.
Definition: librsync.h:252
Error conditions.
Definition: librsync.h:122
Public header for librsync.
char * next_in
Next input byte.
Definition: librsync.h:366
rs_result
Return codes from nonblocking rsync operations.
Definition: librsync.h:192
Unexpected end of input file, perhaps due to a truncated file or dropped network connection.
Definition: librsync.h:207
rs_result rs_file_copy_cb(void *arg, rs_long_t pos, size_t *len, void **buf)
rs_copy_cb that reads from a stdio file.
Definition: buf.c:206
int eof_in
True if there is no more data after this.
Definition: librsync.h:380
Completed successfully.
Definition: librsync.h:193
The contents of this structure are private.
Definition: job.h:29