2 Copyright (C) Andrew Tridgell 1998
3 Copyright (C) 2002 by Martin Pool
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 File IO utilities used in rsync
25 extern int sparse_files
;
27 static char last_byte
;
28 static int last_sparse
;
33 do_lseek(f
,-1,SEEK_CUR
);
34 return (write(f
,&last_byte
,1) == 1 ? 0 : -1);
41 static int write_sparse(int f
,char *buf
,size_t len
)
46 for (l1
= 0; l1
< len
&& buf
[l1
] == 0; l1
++) {}
47 for (l2
= 0; l2
< len
-l1
&& buf
[len
-(l2
+1)] == 0; l2
++) {}
49 last_byte
= buf
[len
-1];
51 if (l1
== len
|| l2
> 0)
55 do_lseek(f
,l1
,SEEK_CUR
);
61 ret
= write(f
, buf
+ l1
, len
- (l1
+l2
));
62 if (ret
== -1 || ret
== 0)
64 else if (ret
!= (int) (len
- (l1
+l2
)))
68 do_lseek(f
,l2
,SEEK_CUR
);
74 static char *wf_writeBuf
;
75 static size_t wf_writeBufSize
;
76 static size_t wf_writeBufCnt
;
78 int flush_write_file(int f
)
81 char *bp
= wf_writeBuf
;
83 while (wf_writeBufCnt
> 0) {
84 if ((ret
= write(f
, bp
, wf_writeBufCnt
)) < 0) {
89 wf_writeBufCnt
-= ret
;
97 * write_file does not allow incomplete writes. It loops internally
98 * until len bytes are written or errno is set.
100 int write_file(int f
,char *buf
,size_t len
)
107 int len1
= MIN(len
, SPARSE_WRITE_SIZE
);
108 r1
= write_sparse(f
, buf
, len1
);
111 wf_writeBufSize
= WRITE_SIZE
* 8;
113 wf_writeBuf
= new_array(char, wf_writeBufSize
);
115 out_of_memory("write_file");
117 r1
= MIN(len
, wf_writeBufSize
- wf_writeBufCnt
);
119 memcpy(wf_writeBuf
+ wf_writeBufCnt
, buf
, r1
);
120 wf_writeBufCnt
+= r1
;
122 if (wf_writeBufCnt
== wf_writeBufSize
) {
123 if (flush_write_file(f
) < 0)
142 /* This provides functionality somewhat similar to mmap() but using read().
143 * It gives sliding window access to a file. mmap() is not used because of
144 * the possibility of another program (such as a mailer) truncating the
145 * file thus giving us a SIGBUS. */
146 struct map_struct
*map_file(int fd
, OFF_T len
, int32 read_size
,
149 struct map_struct
*map
;
151 if (!(map
= new(struct map_struct
)))
152 out_of_memory("map_file");
154 if (blk_size
&& (read_size
% blk_size
))
155 read_size
+= blk_size
- (read_size
% blk_size
);
157 memset(map
, 0, sizeof map
[0]);
159 map
->file_size
= len
;
160 map
->def_window_size
= read_size
;
166 /* slide the read window in the file */
167 char *map_ptr(struct map_struct
*map
, OFF_T offset
, int32 len
)
170 OFF_T window_start
, read_start
;
171 int32 window_size
, read_size
, read_offset
;
176 rprintf(FERROR
, "invalid len passed to map_ptr: %ld\n",
178 exit_cleanup(RERR_FILEIO
);
181 /* in most cases the region will already be available */
182 if (offset
>= map
->p_offset
&& offset
+len
<= map
->p_offset
+map
->p_len
)
183 return map
->p
+ (offset
- map
->p_offset
);
185 /* nope, we are going to have to do a read. Work out our desired window */
186 window_start
= offset
;
187 window_size
= map
->def_window_size
;
188 if (window_start
+ window_size
> map
->file_size
)
189 window_size
= map
->file_size
- window_start
;
190 if (len
> window_size
)
193 /* make sure we have allocated enough memory for the window */
194 if (window_size
> map
->p_size
) {
195 map
->p
= realloc_array(map
->p
, char, window_size
);
197 out_of_memory("map_ptr");
198 map
->p_size
= window_size
;
201 /* Now try to avoid re-reading any bytes by reusing any bytes
202 * from the previous buffer. */
203 if (window_start
>= map
->p_offset
&&
204 window_start
< map
->p_offset
+ map
->p_len
&&
205 window_start
+ window_size
>= map
->p_offset
+ map
->p_len
) {
206 read_start
= map
->p_offset
+ map
->p_len
;
207 read_offset
= read_start
- window_start
;
208 read_size
= window_size
- read_offset
;
209 memmove(map
->p
, map
->p
+ (map
->p_len
- read_offset
), read_offset
);
211 read_start
= window_start
;
212 read_size
= window_size
;
216 if (read_size
<= 0) {
217 rprintf(FERROR
, "invalid read_size of %ld in map_ptr\n",
219 exit_cleanup(RERR_FILEIO
);
221 if (map
->p_fd_offset
!= read_start
) {
222 OFF_T ret
= do_lseek(map
->fd
, read_start
, SEEK_SET
);
223 if (ret
!= read_start
) {
224 rsyserr(FERROR
, errno
,
225 "lseek returned %.0f, not %.0f",
226 (double)ret
, (double)read_start
);
227 exit_cleanup(RERR_FILEIO
);
229 map
->p_fd_offset
= read_start
;
232 if ((nread
=read(map
->fd
,map
->p
+ read_offset
,read_size
)) != read_size
) {
238 /* the best we can do is zero the buffer - the file
239 has changed mid transfer! */
240 memset(map
->p
+read_offset
+nread
, 0, read_size
- nread
);
242 map
->p_fd_offset
+= nread
;
245 map
->p_offset
= window_start
;
246 map
->p_len
= window_size
;
252 int unmap_file(struct map_struct
*map
)
261 memset(map
, 0, sizeof map
[0]);