00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
00102
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
00147
00148
00149
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
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
00186 if (offset >= map->p_offset && offset+len <= map->p_offset+map->p_len)
00187 return map->p + (offset - map->p_offset);
00188
00189
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
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
00206
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
00244
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 }