heaps of cleanup in the io code.
[rsync/rsync.git] / fileio.c
CommitLineData
4c36ddbe
AT
1/*
2 Copyright (C) Andrew Tridgell 1998
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17*/
18
19/*
20 File IO utilities used in rsync
21 */
22#include "rsync.h"
23
24static char last_byte;
25static int last_sparse;
26extern int sparse_files;
27
28int sparse_end(int f)
29{
30 if (last_sparse) {
31 do_lseek(f,-1,SEEK_CUR);
32 return (write(f,&last_byte,1) == 1 ? 0 : -1);
33 }
34 last_sparse = 0;
35 return 0;
36}
37
38
39static int write_sparse(int f,char *buf,int len)
40{
41 int l1=0,l2=0;
42 int ret;
43
44 for (l1=0;l1<len && buf[l1]==0;l1++) ;
45 for (l2=0;l2<(len-l1) && buf[len-(l2+1)]==0;l2++) ;
46
47 last_byte = buf[len-1];
48
49 if (l1 == len || l2 > 0)
50 last_sparse=1;
51
52 if (l1 > 0)
53 do_lseek(f,l1,SEEK_CUR);
54
55 if (l1 == len)
56 return len;
57
58 if ((ret=write(f,buf+l1,len-(l1+l2))) != len-(l1+l2)) {
59 if (ret == -1 || ret == 0) return ret;
60 return (l1+ret);
61 }
62
63 if (l2 > 0)
64 do_lseek(f,l2,SEEK_CUR);
65
66 return len;
67}
68
69
70
71int write_file(int f,char *buf,int len)
72{
73 int ret = 0;
74
75 if (!sparse_files)
76 return write(f,buf,len);
77
78 while (len>0) {
79 int len1 = MIN(len, SPARSE_WRITE_SIZE);
80 int r1 = write_sparse(f, buf, len1);
81 if (r1 <= 0) {
82 if (ret > 0) return ret;
83 return r1;
84 }
85 len -= r1;
86 buf += r1;
87 ret += r1;
88 }
89 return ret;
90}
91
92
93
94struct map_struct *map_file(int fd,OFF_T len)
95{
96 struct map_struct *ret;
97 ret = (struct map_struct *)malloc(sizeof(*ret));
98 if (!ret) out_of_memory("map_file");
99
100 ret->map = NULL;
101 ret->fd = fd;
102 ret->size = len;
103 ret->p = NULL;
104 ret->p_size = 0;
105 ret->p_offset = 0;
106 ret->p_len = 0;
107
108#ifdef USE_MMAP
109 len = MIN(len, MAX_MAP_SIZE);
110 ret->map = (char *)do_mmap(NULL,len,PROT_READ,MAP_SHARED,fd,0);
111 if (ret->map == (char *)-1) {
112 ret->map = NULL;
113 } else {
114 ret->p_len = len;
115 }
116#endif
117 return ret;
118}
119
120
121char *map_ptr(struct map_struct *map,OFF_T offset,int len)
122{
123 int nread;
124
125 if (len == 0)
126 return NULL;
127
128 if (len > (map->size-offset))
129 len = map->size-offset;
130
131#ifdef USE_MMAP
132 if (map->map) {
133 if (offset >= map->p_offset &&
134 offset+len <= map->p_offset+map->p_len) {
135 return (map->map + (offset - map->p_offset));
136 }
137 if (munmap(map->map, map->p_len) != 0) {
138 rprintf(FERROR,"munmap failed : %s\n", strerror(errno));
139 exit_cleanup(1);
140 }
141
142 /* align the mmap region on a nice boundary back a bit from
143 where it is asked for to allow for some seeking */
144 if (offset > 2*CHUNK_SIZE) {
145 map->p_offset = offset - 2*CHUNK_SIZE;
146 map->p_offset &= ~((OFF_T)(CHUNK_SIZE-1));
147 } else {
148 map->p_offset = 0;
149 }
150
151 /* map up to MAX_MAP_SIZE */
152 map->p_len = MAX(len, MAX_MAP_SIZE);
153 map->p_len = MIN(map->p_len, map->size - map->p_offset);
154
155 map->map = (char *)do_mmap(NULL,map->p_len,PROT_READ,
156 MAP_SHARED,map->fd,map->p_offset);
157
158 if (map->map == (char *)-1) {
159 map->map = NULL;
160 map->p_len = 0;
161 map->p_offset = 0;
162 } else {
163 return (map->map + (offset - map->p_offset));
164 }
165 }
166#endif
167
168 if (offset >= map->p_offset &&
169 offset+len <= map->p_offset+map->p_len) {
170 return (map->p + (offset - map->p_offset));
171 }
172
173 len = MAX(len,CHUNK_SIZE);
174 if (len > (map->size-offset))
175 len = map->size-offset;
176
177 if (len > map->p_size) {
178 if (map->p) free(map->p);
179 map->p = (char *)malloc(len);
180 if (!map->p) out_of_memory("map_ptr");
181 map->p_size = len;
182 }
183
184 map->p_offset = offset;
185 map->p_len = len;
186
187 if (do_lseek(map->fd,offset,SEEK_SET) != offset) {
188 rprintf(FERROR,"lseek failed in map_ptr\n");
189 exit_cleanup(1);
190 }
191
192 if ((nread=read(map->fd,map->p,len)) != len) {
193 if (nread < 0) nread = 0;
194 /* the best we can do is zero the buffer - the file
195 has changed mid transfer! */
196 memset(map->p+nread, 0, len - nread);
197 }
198
199 return map->p;
200}
201
202
203void unmap_file(struct map_struct *map)
204{
205#ifdef USE_MMAP
206 if (map->map) {
207 munmap(map->map,map->p_len);
208 map->map = NULL;
209 }
210#endif
211 if (map->p) {
212 free(map->p);
213 map->p = NULL;
214 }
215 memset(map, 0, sizeof(*map));
216 free(map);
217}
218