]>
git.ipfire.org Git - thirdparty/rsync.git/blob - fileio.c
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
26 #define ENODATA EAGAIN
29 extern int sparse_files
;
31 static char last_byte
;
32 static int last_sparse
;
37 do_lseek(f
,-1,SEEK_CUR
);
38 return (write(f
,&last_byte
,1) == 1 ? 0 : -1);
45 static int write_sparse(int f
,char *buf
,size_t len
)
50 for (l1
= 0; l1
< len
&& buf
[l1
] == 0; l1
++) {}
51 for (l2
= 0; l2
< len
-l1
&& buf
[len
-(l2
+1)] == 0; l2
++) {}
53 last_byte
= buf
[len
-1];
55 if (l1
== len
|| l2
> 0)
59 do_lseek(f
,l1
,SEEK_CUR
);
65 ret
= write(f
, buf
+ l1
, len
- (l1
+l2
));
66 if (ret
== -1 || ret
== 0)
68 else if (ret
!= (int) (len
- (l1
+l2
)))
72 do_lseek(f
,l2
,SEEK_CUR
);
78 static char *wf_writeBuf
;
79 static size_t wf_writeBufSize
;
80 static size_t wf_writeBufCnt
;
82 int flush_write_file(int f
)
85 char *bp
= wf_writeBuf
;
87 while (wf_writeBufCnt
> 0) {
88 if ((ret
= write(f
, bp
, wf_writeBufCnt
)) < 0) {
93 wf_writeBufCnt
-= ret
;
101 * write_file does not allow incomplete writes. It loops internally
102 * until len bytes are written or errno is set.
104 int write_file(int f
,char *buf
,size_t len
)
111 int len1
= MIN(len
, SPARSE_WRITE_SIZE
);
112 r1
= write_sparse(f
, buf
, len1
);
115 wf_writeBufSize
= WRITE_SIZE
* 8;
117 wf_writeBuf
= new_array(char, wf_writeBufSize
);
119 out_of_memory("write_file");
121 r1
= MIN(len
, wf_writeBufSize
- wf_writeBufCnt
);
123 memcpy(wf_writeBuf
+ wf_writeBufCnt
, buf
, r1
);
124 wf_writeBufCnt
+= r1
;
126 if (wf_writeBufCnt
== wf_writeBufSize
) {
127 if (flush_write_file(f
) < 0)
146 /* This provides functionality somewhat similar to mmap() but using read().
147 * It gives sliding window access to a file. mmap() is not used because of
148 * the possibility of another program (such as a mailer) truncating the
149 * file thus giving us a SIGBUS. */
150 struct map_struct
*map_file(int fd
, OFF_T len
, int32 read_size
,
153 struct map_struct
*map
;
155 if (!(map
= new(struct map_struct
)))
156 out_of_memory("map_file");
158 if (blk_size
&& (read_size
% blk_size
))
159 read_size
+= blk_size
- (read_size
% blk_size
);
161 memset(map
, 0, sizeof map
[0]);
163 map
->file_size
= len
;
164 map
->def_window_size
= read_size
;
170 /* slide the read window in the file */
171 char *map_ptr(struct map_struct
*map
, OFF_T offset
, int32 len
)
174 OFF_T window_start
, read_start
;
175 int32 window_size
, read_size
, read_offset
;
180 rprintf(FERROR
, "invalid len passed to map_ptr: %ld\n",
182 exit_cleanup(RERR_FILEIO
);
185 /* in most cases the region will already be available */
186 if (offset
>= map
->p_offset
&& offset
+len
<= map
->p_offset
+map
->p_len
)
187 return map
->p
+ (offset
- map
->p_offset
);
189 /* nope, we are going to have to do a read. Work out our desired window */
190 window_start
= offset
;
191 window_size
= map
->def_window_size
;
192 if (window_start
+ window_size
> map
->file_size
)
193 window_size
= map
->file_size
- window_start
;
194 if (len
> window_size
)
197 /* make sure we have allocated enough memory for the window */
198 if (window_size
> map
->p_size
) {
199 map
->p
= realloc_array(map
->p
, char, window_size
);
201 out_of_memory("map_ptr");
202 map
->p_size
= window_size
;
205 /* Now try to avoid re-reading any bytes by reusing any bytes
206 * from the previous buffer. */
207 if (window_start
>= map
->p_offset
&&
208 window_start
< map
->p_offset
+ map
->p_len
&&
209 window_start
+ window_size
>= map
->p_offset
+ map
->p_len
) {
210 read_start
= map
->p_offset
+ map
->p_len
;
211 read_offset
= read_start
- window_start
;
212 read_size
= window_size
- read_offset
;
213 memmove(map
->p
, map
->p
+ (map
->p_len
- read_offset
), read_offset
);
215 read_start
= window_start
;
216 read_size
= window_size
;
220 if (read_size
<= 0) {
221 rprintf(FERROR
, "invalid read_size of %ld in map_ptr\n",
223 exit_cleanup(RERR_FILEIO
);
226 if (map
->p_fd_offset
!= read_start
) {
227 OFF_T ret
= do_lseek(map
->fd
, read_start
, SEEK_SET
);
228 if (ret
!= read_start
) {
229 rsyserr(FERROR
, errno
, "lseek returned %.0f, not %.0f",
230 (double)ret
, (double)read_start
);
231 exit_cleanup(RERR_FILEIO
);
233 map
->p_fd_offset
= read_start
;
235 map
->p_fd_offset
+= read_size
;
236 map
->p_offset
= window_start
;
237 map
->p_len
= window_size
;
239 while (read_size
> 0) {
240 nread
= read(map
->fd
, map
->p
+ read_offset
, read_size
);
243 map
->status
= nread
? errno
: ENODATA
;
244 /* The best we can do is zero the buffer -- the file
245 * has changed mid transfer! */
246 memset(map
->p
+ read_offset
, 0, read_size
);
249 read_offset
+= nread
;
257 int unmap_file(struct map_struct
*map
)
266 memset(map
, 0, sizeof map
[0]);