fileio.c

説明を見る。
00001 /*
00002    Copyright (C) Andrew Tridgell 1998
00003    Copyright (C) 2002 by Martin Pool
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 2 of the License, or
00008    (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program; if not, write to the Free Software
00017    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 */
00019 
00020 /*
00021   File IO utilities used in rsync
00022   */
00023 #include "rsync.h"
00024 
00025 #ifndef ENODATA
00026 #define ENODATA EAGAIN
00027 #endif
00028 
00029 extern int sparse_files;
00030 
00031 static char last_byte;
00032 static int last_sparse;
00033 
00034 int sparse_end(int f)
00035 {
00036         if (last_sparse) {
00037                 do_lseek(f,-1,SEEK_CUR);
00038                 return (write(f,&last_byte,1) == 1 ? 0 : -1);
00039         }
00040         last_sparse = 0;
00041         return 0;
00042 }
00043 
00044 
00045 static int write_sparse(int f,char *buf,size_t len)
00046 {
00047         size_t l1=0, l2=0;
00048         int ret;
00049 
00050         for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {}
00051         for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {}
00052 
00053         last_byte = buf[len-1];
00054 
00055         if (l1 == len || l2 > 0)
00056                 last_sparse=1;
00057 
00058         if (l1 > 0) {
00059                 do_lseek(f,l1,SEEK_CUR);
00060         }
00061 
00062         if (l1 == len)
00063                 return len;
00064 
00065         ret = write(f, buf + l1, len - (l1+l2));
00066         if (ret == -1 || ret == 0)
00067                 return ret;
00068         else if (ret != (int) (len - (l1+l2)))
00069                 return (l1+ret);
00070 
00071         if (l2 > 0)
00072                 do_lseek(f,l2,SEEK_CUR);
00073 
00074         return len;
00075 }
00076 
00077 
00078 static char *wf_writeBuf;
00079 static size_t wf_writeBufSize;
00080 static size_t wf_writeBufCnt;
00081 
00082 int flush_write_file(int f)
00083 {
00084         int ret = 0;
00085         char *bp = wf_writeBuf;
00086 
00087         while (wf_writeBufCnt > 0) {
00088                 if ((ret = write(f, bp, wf_writeBufCnt)) < 0) {
00089                         if (errno == EINTR)
00090                                 continue;
00091                         return ret;
00092                 }
00093                 wf_writeBufCnt -= ret;
00094                 bp += ret;
00095         }
00096         return ret;
00097 }
00098 
00099 
00100 /*
00101  * write_file does not allow incomplete writes.  It loops internally
00102  * until len bytes are written or errno is set.
00103  */
00104 int write_file(int f,char *buf,size_t len)
00105 {
00106         int ret = 0;
00107 
00108         while (len > 0) {
00109                 int r1;
00110                 if (sparse_files) {
00111                         int len1 = MIN(len, SPARSE_WRITE_SIZE);
00112                         r1 = write_sparse(f, buf, len1);
00113                 } else {
00114                         if (!wf_writeBuf) {
00115                                 wf_writeBufSize = WRITE_SIZE * 8;
00116                                 wf_writeBufCnt  = 0;
00117                                 wf_writeBuf = new_array(char, wf_writeBufSize);
00118                                 if (!wf_writeBuf)
00119                                         out_of_memory("write_file");
00120                         }
00121                         r1 = MIN(len, wf_writeBufSize - wf_writeBufCnt);
00122                         if (r1) {
00123                                 memcpy(wf_writeBuf + wf_writeBufCnt, buf, r1);
00124                                 wf_writeBufCnt += r1;
00125                         }
00126                         if (wf_writeBufCnt == wf_writeBufSize) {
00127                                 if (flush_write_file(f) < 0)
00128                                         return -1;
00129                                 if (!r1 && len)
00130                                         continue;
00131                         }
00132                 }
00133                 if (r1 <= 0) {
00134                         if (ret > 0)
00135                                 return ret;
00136                         return r1;
00137                 }
00138                 len -= r1;
00139                 buf += r1;
00140                 ret += r1;
00141         }
00142         return ret;
00143 }
00144 
00145 
00146 /* This provides functionality somewhat similar to mmap() but using read().
00147  * It gives sliding window access to a file.  mmap() is not used because of
00148  * the possibility of another program (such as a mailer) truncating the
00149  * file thus giving us a SIGBUS. */
00150 struct map_struct *map_file(int fd, OFF_T len, int32 read_size,
00151                             int32 blk_size)
00152 {
00153         struct map_struct *map;
00154 
00155         if (!(map = new(struct map_struct)))
00156                 out_of_memory("map_file");
00157 
00158         if (blk_size && (read_size % blk_size))
00159                 read_size += blk_size - (read_size % blk_size);
00160 
00161         memset(map, 0, sizeof map[0]);
00162         map->fd = fd;
00163         map->file_size = len;
00164         map->def_window_size = read_size;
00165 
00166         return map;
00167 }
00168 
00169 
00170 /* slide the read window in the file */
00171 char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
00172 {
00173         int32 nread;
00174         OFF_T window_start, read_start;
00175         int32 window_size, read_size, read_offset;
00176 
00177         if (len == 0)
00178                 return NULL;
00179         if (len < 0) {
00180                 rprintf(FERROR, "invalid len passed to map_ptr: %ld\n",
00181                         (long)len);
00182                 exit_cleanup(RERR_FILEIO);
00183         }
00184 
00185         /* in most cases the region will already be available */
00186         if (offset >= map->p_offset && offset+len <= map->p_offset+map->p_len)
00187                 return map->p + (offset - map->p_offset);
00188 
00189         /* nope, we are going to have to do a read. Work out our desired window */
00190         window_start = offset;
00191         window_size = map->def_window_size;
00192         if (window_start + window_size > map->file_size)
00193                 window_size = map->file_size - window_start;
00194         if (len > window_size)
00195                 window_size = len;
00196 
00197         /* make sure we have allocated enough memory for the window */
00198         if (window_size > map->p_size) {
00199                 map->p = realloc_array(map->p, char, window_size);
00200                 if (!map->p)
00201                         out_of_memory("map_ptr");
00202                 map->p_size = window_size;
00203         }
00204 
00205         /* Now try to avoid re-reading any bytes by reusing any bytes
00206          * from the previous buffer. */
00207         if (window_start >= map->p_offset &&
00208             window_start < map->p_offset + map->p_len &&
00209             window_start + window_size >= map->p_offset + map->p_len) {
00210                 read_start = map->p_offset + map->p_len;
00211                 read_offset = read_start - window_start;
00212                 read_size = window_size - read_offset;
00213                 memmove(map->p, map->p + (map->p_len - read_offset), read_offset);
00214         } else {
00215                 read_start = window_start;
00216                 read_size = window_size;
00217                 read_offset = 0;
00218         }
00219 
00220         if (read_size <= 0) {
00221                 rprintf(FERROR, "invalid read_size of %ld in map_ptr\n",
00222                         (long)read_size);
00223                 exit_cleanup(RERR_FILEIO);
00224         }
00225 
00226         if (map->p_fd_offset != read_start) {
00227                 OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET);
00228                 if (ret != read_start) {
00229                         rsyserr(FERROR, errno, "lseek returned %.0f, not %.0f",
00230                                 (double)ret, (double)read_start);
00231                         exit_cleanup(RERR_FILEIO);
00232                 }
00233                 map->p_fd_offset = read_start;
00234         }
00235         map->p_offset = window_start;
00236         map->p_len = window_size;
00237 
00238         while (read_size > 0) {
00239                 nread = read(map->fd, map->p + read_offset, read_size);
00240                 if (nread <= 0) {
00241                         if (!map->status)
00242                                 map->status = nread ? errno : ENODATA;
00243                         /* The best we can do is zero the buffer -- the file
00244                          * has changed mid transfer! */
00245                         memset(map->p + read_offset, 0, read_size);
00246                         break;
00247                 }
00248                 map->p_fd_offset += nread;
00249                 read_offset += nread;
00250                 read_size -= nread;
00251         }
00252 
00253         return map->p;
00254 }
00255 
00256 
00257 int unmap_file(struct map_struct *map)
00258 {
00259         int     ret;
00260 
00261         if (map->p) {
00262                 free(map->p);
00263                 map->p = NULL;
00264         }
00265         ret = map->status;
00266         memset(map, 0, sizeof map[0]);
00267         free(map);
00268 
00269         return ret;
00270 }

rsyncに対してSat Dec 5 19:45:41 2009に生成されました。  doxygen 1.4.7