Annotation of embedaddon/rsync/fileio.c, revision 1.1.1.1
1.1 misho 1: /*
2: * File IO utilities used in rsync.
3: *
4: * Copyright (C) 1998 Andrew Tridgell
5: * Copyright (C) 2002 Martin Pool
6: * Copyright (C) 2004-2009 Wayne Davison
7: *
8: * This program is free software; you can redistribute it and/or modify
9: * it under the terms of the GNU General Public License as published by
10: * the Free Software Foundation; either version 3 of the License, or
11: * (at your option) any later version.
12: *
13: * This program is distributed in the hope that it will be useful,
14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: * GNU General Public License for more details.
17: *
18: * You should have received a copy of the GNU General Public License along
19: * with this program; if not, visit the http://fsf.org website.
20: */
21:
22: #include "rsync.h"
23:
24: #ifndef ENODATA
25: #define ENODATA EAGAIN
26: #endif
27:
28: extern int sparse_files;
29:
30: static OFF_T sparse_seek = 0;
31:
32: int sparse_end(int f, OFF_T size)
33: {
34: int ret;
35:
36: if (!sparse_seek)
37: return 0;
38:
39: #ifdef HAVE_FTRUNCATE
40: ret = do_ftruncate(f, size);
41: #else
42: if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1)
43: ret = -1;
44: else {
45: do {
46: ret = write(f, "", 1);
47: } while (ret < 0 && errno == EINTR);
48:
49: ret = ret <= 0 ? -1 : 0;
50: }
51: #endif
52:
53: sparse_seek = 0;
54:
55: return ret;
56: }
57:
58:
59: static int write_sparse(int f, char *buf, int len)
60: {
61: int l1 = 0, l2 = 0;
62: int ret;
63:
64: for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {}
65: for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {}
66:
67: sparse_seek += l1;
68:
69: if (l1 == len)
70: return len;
71:
72: if (sparse_seek)
73: do_lseek(f, sparse_seek, SEEK_CUR);
74: sparse_seek = l2;
75:
76: while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) {
77: if (ret < 0 && errno == EINTR)
78: continue;
79: return ret;
80: }
81:
82: if (ret != (int)(len - (l1+l2)))
83: return l1+ret;
84:
85: return len;
86: }
87:
88:
89: static char *wf_writeBuf;
90: static size_t wf_writeBufSize;
91: static size_t wf_writeBufCnt;
92:
93: int flush_write_file(int f)
94: {
95: int ret = 0;
96: char *bp = wf_writeBuf;
97:
98: while (wf_writeBufCnt > 0) {
99: if ((ret = write(f, bp, wf_writeBufCnt)) < 0) {
100: if (errno == EINTR)
101: continue;
102: return ret;
103: }
104: wf_writeBufCnt -= ret;
105: bp += ret;
106: }
107: return ret;
108: }
109:
110:
111: /*
112: * write_file does not allow incomplete writes. It loops internally
113: * until len bytes are written or errno is set.
114: */
115: int write_file(int f, char *buf, int len)
116: {
117: int ret = 0;
118:
119: while (len > 0) {
120: int r1;
121: if (sparse_files > 0) {
122: int len1 = MIN(len, SPARSE_WRITE_SIZE);
123: r1 = write_sparse(f, buf, len1);
124: } else {
125: if (!wf_writeBuf) {
126: wf_writeBufSize = WRITE_SIZE * 8;
127: wf_writeBufCnt = 0;
128: wf_writeBuf = new_array(char, wf_writeBufSize);
129: if (!wf_writeBuf)
130: out_of_memory("write_file");
131: }
132: r1 = (int)MIN((size_t)len, wf_writeBufSize - wf_writeBufCnt);
133: if (r1) {
134: memcpy(wf_writeBuf + wf_writeBufCnt, buf, r1);
135: wf_writeBufCnt += r1;
136: }
137: if (wf_writeBufCnt == wf_writeBufSize) {
138: if (flush_write_file(f) < 0)
139: return -1;
140: if (!r1 && len)
141: continue;
142: }
143: }
144: if (r1 <= 0) {
145: if (ret > 0)
146: return ret;
147: return r1;
148: }
149: len -= r1;
150: buf += r1;
151: ret += r1;
152: }
153: return ret;
154: }
155:
156:
157: /* This provides functionality somewhat similar to mmap() but using read().
158: * It gives sliding window access to a file. mmap() is not used because of
159: * the possibility of another program (such as a mailer) truncating the
160: * file thus giving us a SIGBUS. */
161: struct map_struct *map_file(int fd, OFF_T len, int32 read_size,
162: int32 blk_size)
163: {
164: struct map_struct *map;
165:
166: if (!(map = new0(struct map_struct)))
167: out_of_memory("map_file");
168:
169: if (blk_size && (read_size % blk_size))
170: read_size += blk_size - (read_size % blk_size);
171:
172: map->fd = fd;
173: map->file_size = len;
174: map->def_window_size = read_size;
175:
176: return map;
177: }
178:
179:
180: /* slide the read window in the file */
181: char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
182: {
183: int32 nread;
184: OFF_T window_start, read_start;
185: int32 window_size, read_size, read_offset;
186:
187: if (len == 0)
188: return NULL;
189: if (len < 0) {
190: rprintf(FERROR, "invalid len passed to map_ptr: %ld\n",
191: (long)len);
192: exit_cleanup(RERR_FILEIO);
193: }
194:
195: /* in most cases the region will already be available */
196: if (offset >= map->p_offset && offset+len <= map->p_offset+map->p_len)
197: return map->p + (offset - map->p_offset);
198:
199: /* nope, we are going to have to do a read. Work out our desired window */
200: window_start = offset;
201: window_size = map->def_window_size;
202: if (window_start + window_size > map->file_size)
203: window_size = (int32)(map->file_size - window_start);
204: if (len > window_size)
205: window_size = len;
206:
207: /* make sure we have allocated enough memory for the window */
208: if (window_size > map->p_size) {
209: map->p = realloc_array(map->p, char, window_size);
210: if (!map->p)
211: out_of_memory("map_ptr");
212: map->p_size = window_size;
213: }
214:
215: /* Now try to avoid re-reading any bytes by reusing any bytes
216: * from the previous buffer. */
217: if (window_start >= map->p_offset &&
218: window_start < map->p_offset + map->p_len &&
219: window_start + window_size >= map->p_offset + map->p_len) {
220: read_start = map->p_offset + map->p_len;
221: read_offset = (int32)(read_start - window_start);
222: read_size = window_size - read_offset;
223: memmove(map->p, map->p + (map->p_len - read_offset), read_offset);
224: } else {
225: read_start = window_start;
226: read_size = window_size;
227: read_offset = 0;
228: }
229:
230: if (read_size <= 0) {
231: rprintf(FERROR, "invalid read_size of %ld in map_ptr\n",
232: (long)read_size);
233: exit_cleanup(RERR_FILEIO);
234: }
235:
236: if (map->p_fd_offset != read_start) {
237: OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET);
238: if (ret != read_start) {
239: rsyserr(FERROR, errno, "lseek returned %.0f, not %.0f",
240: (double)ret, (double)read_start);
241: exit_cleanup(RERR_FILEIO);
242: }
243: map->p_fd_offset = read_start;
244: }
245: map->p_offset = window_start;
246: map->p_len = window_size;
247:
248: while (read_size > 0) {
249: nread = read(map->fd, map->p + read_offset, read_size);
250: if (nread <= 0) {
251: if (!map->status)
252: map->status = nread ? errno : ENODATA;
253: /* The best we can do is zero the buffer -- the file
254: * has changed mid transfer! */
255: memset(map->p + read_offset, 0, read_size);
256: break;
257: }
258: map->p_fd_offset += nread;
259: read_offset += nread;
260: read_size -= nread;
261: }
262:
263: return map->p;
264: }
265:
266:
267: int unmap_file(struct map_struct *map)
268: {
269: int ret;
270:
271: if (map->p) {
272: free(map->p);
273: map->p = NULL;
274: }
275: ret = map->status;
276: memset(map, 0, sizeof map[0]);
277: free(map);
278:
279: return ret;
280: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>