Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

fileio.c

Go to the documentation of this file.
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 static char last_byte;
00026 static int last_sparse;
00027 extern int sparse_files;
00028 
00029 int sparse_end(int f)
00030 {
00031         if (last_sparse) {
00032                 do_lseek(f,-1,SEEK_CUR);
00033                 return (write(f,&last_byte,1) == 1 ? 0 : -1);
00034         }
00035         last_sparse = 0;
00036         return 0;
00037 }
00038 
00039 
00040 static int write_sparse(int f,char *buf,size_t len)
00041 {
00042         size_t l1=0, l2=0;
00043         int ret;
00044 
00045         for (l1=0;l1<len && buf[l1]==0;l1++) ;
00046         for (l2=0;l2<(len-l1) && buf[len-(l2+1)]==0;l2++) ;
00047 
00048         last_byte = buf[len-1];
00049 
00050         if (l1 == len || l2 > 0)
00051                 last_sparse=1;
00052 
00053         if (l1 > 0) {
00054                 do_lseek(f,l1,SEEK_CUR);  
00055         }
00056 
00057         if (l1 == len) 
00058                 return len;
00059 
00060         ret = write(f, buf + l1, len - (l1+l2));
00061         if (ret == -1 || ret == 0)
00062                 return ret;
00063         else if (ret != (int) (len - (l1+l2))) 
00064                 return (l1+ret);
00065 
00066         if (l2 > 0)
00067                 do_lseek(f,l2,SEEK_CUR);
00068         
00069         return len;
00070 }
00071 
00072 
00073 
00074 int write_file(int f,char *buf,size_t len)
00075 {
00076         int ret = 0;
00077 
00078         if (!sparse_files) {
00079                 return write(f,buf,len);
00080         }
00081 
00082         while (len>0) {
00083                 int len1 = MIN(len, SPARSE_WRITE_SIZE);
00084                 int r1 = write_sparse(f, buf, len1);
00085                 if (r1 <= 0) {
00086                         if (ret > 0) return ret;
00087                         return r1;
00088                 }
00089                 len -= r1;
00090                 buf += r1;
00091                 ret += r1;
00092         }
00093         return ret;
00094 }
00095 
00096 
00097 
00098 /* this provides functionality somewhat similar to mmap() but using
00099    read(). It gives sliding window access to a file. mmap() is not
00100    used because of the possibility of another program (such as a
00101    mailer) truncating the file thus giving us a SIGBUS */
00102 struct map_struct *map_file(int fd,OFF_T len)
00103 {
00104         struct map_struct *map;
00105         map = (struct map_struct *)malloc(sizeof(*map));
00106         if (!map) out_of_memory("map_file");
00107 
00108         map->fd = fd;
00109         map->file_size = len;
00110         map->p = NULL;
00111         map->p_size = 0;
00112         map->p_offset = 0;
00113         map->p_fd_offset = 0;
00114         map->p_len = 0;
00115 
00116         return map;
00117 }
00118 
00119 /* slide the read window in the file */
00120 char *map_ptr(struct map_struct *map,OFF_T offset,int len)
00121 {
00122         int nread;
00123         OFF_T window_start, read_start;
00124         int window_size, read_size, read_offset;
00125 
00126         if (len == 0) {
00127                 return NULL;
00128         }
00129 
00130         /* can't go beyond the end of file */
00131         if (len > (map->file_size - offset)) {
00132                 len = map->file_size - offset;
00133         }
00134 
00135         /* in most cases the region will already be available */
00136         if (offset >= map->p_offset && 
00137             offset+len <= map->p_offset+map->p_len) {
00138                 return (map->p + (offset - map->p_offset));
00139         }
00140 
00141 
00142         /* nope, we are going to have to do a read. Work out our desired window */
00143         if (offset > 2*CHUNK_SIZE) {
00144                 window_start = offset - 2*CHUNK_SIZE;
00145                 window_start &= ~((OFF_T)(CHUNK_SIZE-1)); /* assumes power of 2 */
00146         } else {
00147                 window_start = 0;
00148         }
00149         window_size = MAX_MAP_SIZE;
00150         if (window_start + window_size > map->file_size) {
00151                 window_size = map->file_size - window_start;
00152         }
00153         if (offset + len > window_start + window_size) {
00154                 window_size = (offset+len) - window_start;
00155         }
00156 
00157         /* make sure we have allocated enough memory for the window */
00158         if (window_size > map->p_size) {
00159                 map->p = (char *)Realloc(map->p, window_size);
00160                 if (!map->p) out_of_memory("map_ptr");
00161                 map->p_size = window_size;
00162         }
00163 
00164         /* now try to avoid re-reading any bytes by reusing any bytes from the previous
00165            buffer. */
00166         if (window_start >= map->p_offset &&
00167             window_start < map->p_offset + map->p_len &&
00168             window_start + window_size >= map->p_offset + map->p_len) {
00169                 read_start = map->p_offset + map->p_len;
00170                 read_offset = read_start - window_start;
00171                 read_size = window_size - read_offset;
00172                 memmove(map->p, map->p + (map->p_len - read_offset), read_offset);
00173         } else {
00174                 read_start = window_start;
00175                 read_size = window_size;
00176                 read_offset = 0;
00177         }
00178 
00179         if (read_size <= 0) {
00180                 rprintf(FINFO,"Warning: unexpected read size of %d in map_ptr\n", read_size);
00181         } else {
00182                 if (map->p_fd_offset != read_start) {
00183                         if (do_lseek(map->fd,read_start,SEEK_SET) != read_start) {
00184                                 rprintf(FERROR,"lseek failed in map_ptr\n");
00185                                 exit_cleanup(RERR_FILEIO);
00186                         }
00187                         map->p_fd_offset = read_start;
00188                 }
00189 
00190                 if ((nread=read(map->fd,map->p + read_offset,read_size)) != read_size) {
00191                         if (nread < 0) nread = 0;
00192                         /* the best we can do is zero the buffer - the file
00193                            has changed mid transfer! */
00194                         memset(map->p+read_offset+nread, 0, read_size - nread);
00195                 }
00196                 map->p_fd_offset += nread;
00197         }
00198 
00199         map->p_offset = window_start;
00200         map->p_len = window_size;
00201   
00202         return map->p + (offset - map->p_offset); 
00203 }
00204 
00205 
00206 void unmap_file(struct map_struct *map)
00207 {
00208         if (map->p) {
00209                 free(map->p);
00210                 map->p = NULL;
00211         }
00212         memset(map, 0, sizeof(*map));
00213         free(map);
00214 }
00215 

Generated on Tue Apr 16 12:37:36 2002 for rsync by doxygen1.2.15