$treeview $search $mathjax $extrastylesheet
librsync
2.3.0
$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 00027 * Buffers that map between stdio file streams and librsync 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 <assert.h> 00041 #include <stdlib.h> 00042 #include <errno.h> 00043 #include <string.h> 00044 #include "librsync.h" 00045 #include "buf.h" 00046 #include "job.h" 00047 #include "trace.h" 00048 #include "util.h" 00049 00050 struct rs_filebuf { 00051 FILE *f; 00052 char *buf; 00053 size_t buf_len; 00054 }; 00055 00056 rs_filebuf_t *rs_filebuf_new(FILE *f, size_t buf_len) 00057 { 00058 rs_filebuf_t *pf = rs_alloc_struct(rs_filebuf_t); 00059 00060 pf->buf = rs_alloc(buf_len, "file buffer"); 00061 pf->buf_len = buf_len; 00062 pf->f = f; 00063 00064 return pf; 00065 } 00066 00067 void rs_filebuf_free(rs_filebuf_t *fb) 00068 { 00069 free(fb->buf); 00070 rs_bzero(fb, sizeof *fb); 00071 free(fb); 00072 } 00073 00074 /* If the stream has no more data available, read some from F into BUF, and let 00075 the stream use that. On return, SEEN_EOF is true if the end of file has 00076 passed into the stream. */ 00077 rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf, void *opaque) 00078 { 00079 size_t len; 00080 rs_filebuf_t *fb = (rs_filebuf_t *)opaque; 00081 FILE *f = fb->f; 00082 00083 /* This is only allowed if either the buf has no input buffer yet, or that 00084 buffer could possibly be BUF. */ 00085 if (buf->next_in != NULL) { 00086 assert(buf->avail_in <= fb->buf_len); 00087 assert(buf->next_in >= fb->buf); 00088 assert(buf->next_in <= fb->buf + fb->buf_len); 00089 } else { 00090 assert(buf->avail_in == 0); 00091 } 00092 00093 if (buf->eof_in || (buf->eof_in = feof(f))) { 00094 rs_trace("seen end of file on input"); 00095 buf->eof_in = 1; 00096 return RS_DONE; 00097 } 00098 00099 if (buf->avail_in) 00100 /* Still some data remaining. Perhaps we should read anyhow? */ 00101 return RS_DONE; 00102 00103 len = fread(fb->buf, 1, fb->buf_len, f); 00104 if (len == 0) { 00105 /* This will happen if file size is a multiple of input block len */ 00106 if (feof(f)) { 00107 rs_trace("seen end of file on input"); 00108 buf->eof_in = 1; 00109 return RS_DONE; 00110 } 00111 if (ferror(f)) { 00112 rs_error("error filling buf from file: %s", strerror(errno)); 00113 return RS_IO_ERROR; 00114 } else { 00115 rs_error("no error bit, but got " FMT_SIZE 00116 " return when trying to read", len); 00117 return RS_IO_ERROR; 00118 } 00119 } 00120 buf->avail_in = len; 00121 buf->next_in = fb->buf; 00122 00123 job->stats.in_bytes += len; 00124 00125 return RS_DONE; 00126 } 00127 00128 /* The buf is already using BUF for an output buffer, and probably contains 00129 some buffered output now. Write this out to F, and reset the buffer cursor. */ 00130 rs_result rs_outfilebuf_drain(rs_job_t *job, rs_buffers_t *buf, void *opaque) 00131 { 00132 int present; 00133 rs_filebuf_t *fb = (rs_filebuf_t *)opaque; 00134 FILE *f = fb->f; 00135 00136 /* This is only allowed if either the buf has no output buffer yet, or that 00137 buffer could possibly be BUF. */ 00138 if (buf->next_out == NULL) { 00139 assert(buf->avail_out == 0); 00140 00141 buf->next_out = fb->buf; 00142 buf->avail_out = fb->buf_len; 00143 00144 return RS_DONE; 00145 } 00146 00147 assert(buf->avail_out <= fb->buf_len); 00148 assert(buf->next_out >= fb->buf); 00149 assert(buf->next_out <= fb->buf + fb->buf_len); 00150 00151 present = buf->next_out - fb->buf; 00152 if (present > 0) { 00153 int result; 00154 00155 assert(present > 0); 00156 00157 result = fwrite(fb->buf, 1, present, f); 00158 if (present != result) { 00159 rs_error("error draining buf to file: %s", strerror(errno)); 00160 return RS_IO_ERROR; 00161 } 00162 00163 buf->next_out = fb->buf; 00164 buf->avail_out = fb->buf_len; 00165 00166 job->stats.out_bytes += result; 00167 } 00168 00169 return RS_DONE; 00170 }