$treeview $search $mathjax $extrastylesheet
librsync
2.0.2
$projectbrief
|
$projectbrief
|
$searchbox |
00001 /*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- 00002 * 00003 * librsync -- the library for network deltas 00004 * 00005 * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net> 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public License 00009 * as published by the Free Software Foundation; either version 2.1 of 00010 * the License, or (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, but 00013 * WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this program; if not, write to the Free Software 00019 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00020 */ 00021 00022 /*= 00023 | Pick a window, Jimmy, you're leaving. 00024 */ 00025 00026 /** \file buf.c Buffers that map between stdio file streams and librsync 00027 * streams. 00028 * 00029 * As the stream consumes input and produces output, it is refilled from 00030 * appropriate input and output FILEs. A dynamically allocated buffer of 00031 * configurable size is used as an intermediary. 00032 * 00033 * \todo Perhaps be more efficient by filling the buffer on every call even if 00034 * not yet completely empty. Check that it's really our buffer, and shuffle 00035 * remaining data down to the front. 00036 * 00037 * \todo Perhaps expose a routine for shuffling the buffers. */ 00038 00039 #include "config.h" 00040 #include <sys/types.h> 00041 00042 #include <assert.h> 00043 #include <stdlib.h> 00044 #include <stdio.h> 00045 #include <errno.h> 00046 #include <string.h> 00047 00048 #include "librsync.h" 00049 #include "trace.h" 00050 #include "buf.h" 00051 #include "job.h" 00052 #include "util.h" 00053 00054 struct rs_filebuf { 00055 FILE *f; 00056 char *buf; 00057 size_t buf_len; 00058 }; 00059 00060 rs_filebuf_t *rs_filebuf_new(FILE *f, size_t buf_len) 00061 { 00062 rs_filebuf_t *pf = rs_alloc_struct(rs_filebuf_t); 00063 00064 pf->buf = rs_alloc(buf_len, "file buffer"); 00065 pf->buf_len = buf_len; 00066 pf->f = f; 00067 00068 return pf; 00069 } 00070 00071 void rs_filebuf_free(rs_filebuf_t *fb) 00072 { 00073 free(fb->buf); 00074 rs_bzero(fb, sizeof *fb); 00075 free(fb); 00076 } 00077 00078 /* If the stream has no more data available, read some from F into BUF, and let 00079 the stream use that. On return, SEEN_EOF is true if the end of file has 00080 passed into the stream. */ 00081 rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf, void *opaque) 00082 { 00083 size_t len; 00084 rs_filebuf_t *fb = (rs_filebuf_t *)opaque; 00085 FILE *f = fb->f; 00086 00087 /* This is only allowed if either the buf has no input buffer yet, or that 00088 buffer could possibly be BUF. */ 00089 if (buf->next_in != NULL) { 00090 assert(buf->avail_in <= fb->buf_len); 00091 assert(buf->next_in >= fb->buf); 00092 assert(buf->next_in <= fb->buf + fb->buf_len); 00093 } else { 00094 assert(buf->avail_in == 0); 00095 } 00096 00097 if (buf->eof_in || (buf->eof_in = feof(f))) { 00098 rs_trace("seen end of file on input"); 00099 buf->eof_in = 1; 00100 return RS_DONE; 00101 } 00102 00103 if (buf->avail_in) 00104 /* Still some data remaining. Perhaps we should read anyhow? */ 00105 return RS_DONE; 00106 00107 len = fread(fb->buf, 1, fb->buf_len, f); 00108 if (len <= 0) { 00109 /* This will happen if file size is a multiple of input block len */ 00110 if (feof(f)) { 00111 rs_trace("seen end of file on input"); 00112 buf->eof_in = 1; 00113 return RS_DONE; 00114 } 00115 if (ferror(f)) { 00116 rs_error("error filling buf from file: %s", strerror(errno)); 00117 return RS_IO_ERROR; 00118 } else { 00119 rs_error("no error bit, but got " FMT_SIZE 00120 " return when trying to read", len); 00121 return RS_IO_ERROR; 00122 } 00123 } 00124 buf->avail_in = len; 00125 buf->next_in = fb->buf; 00126 00127 job->stats.in_bytes += len; 00128 00129 return RS_DONE; 00130 } 00131 00132 /* The buf is already using BUF for an output buffer, and probably contains 00133 some buffered output now. Write this out to F, and reset the buffer cursor. */ 00134 rs_result rs_outfilebuf_drain(rs_job_t *job, rs_buffers_t *buf, void *opaque) 00135 { 00136 int present; 00137 rs_filebuf_t *fb = (rs_filebuf_t *)opaque; 00138 FILE *f = fb->f; 00139 00140 /* This is only allowed if either the buf has no output buffer yet, or that 00141 buffer could possibly be BUF. */ 00142 if (buf->next_out == NULL) { 00143 assert(buf->avail_out == 0); 00144 00145 buf->next_out = fb->buf; 00146 buf->avail_out = fb->buf_len; 00147 00148 return RS_DONE; 00149 } 00150 00151 assert(buf->avail_out <= fb->buf_len); 00152 assert(buf->next_out >= fb->buf); 00153 assert(buf->next_out <= fb->buf + fb->buf_len); 00154 00155 present = buf->next_out - fb->buf; 00156 if (present > 0) { 00157 int result; 00158 00159 assert(present > 0); 00160 00161 result = fwrite(fb->buf, 1, present, f); 00162 if (present != result) { 00163 rs_error("error draining buf to file: %s", strerror(errno)); 00164 return RS_IO_ERROR; 00165 } 00166 00167 buf->next_out = fb->buf; 00168 buf->avail_out = fb->buf_len; 00169 00170 job->stats.out_bytes += result; 00171 } 00172 00173 return RS_DONE; 00174 }