a large change to make rsync much more memory efficient. This is done
[rsync/rsync.git] / util.c
... / ...
CommitLineData
1/*
2 Copyright (C) Andrew Tridgell 1996
3 Copyright (C) Paul Mackerras 1996
4
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.
9
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.
14
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.
18*/
19
20/*
21 Utilities used in rsync
22
23 tridge, June 1996
24 */
25#include "rsync.h"
26
27int num_waiting(int fd)
28{
29 int len=0;
30 ioctl(fd,FIONREAD,&len);
31 return(len);
32}
33
34
35struct map_struct *map_file(int fd,off_t len)
36{
37 struct map_struct *ret;
38 ret = (struct map_struct *)malloc(sizeof(*ret));
39 if (!ret) out_of_memory("map_file");
40
41 ret->map = NULL;
42 ret->fd = fd;
43 ret->size = len;
44 ret->p = NULL;
45 ret->p_size = 0;
46 ret->p_offset = 0;
47 ret->p_len = 0;
48
49#ifdef HAVE_MMAP
50 if (len < MAX_MAP_SIZE)
51 ret->map = (char *)mmap(NULL,len,PROT_READ,MAP_SHARED,fd,0);
52#endif
53 return ret;
54}
55
56char *map_ptr(struct map_struct *map,off_t offset,int len)
57{
58 int nread = -2;
59
60 if (map->map)
61 return map->map+offset;
62
63 if (len == 0)
64 return NULL;
65
66 len = MIN(len,map->size-offset);
67
68 if (offset >= map->p_offset &&
69 offset+len <= map->p_offset+map->p_len) {
70 return (map->p + (offset - map->p_offset));
71 }
72
73 len = MAX(len,CHUNK_SIZE);
74 len = MIN(len,map->size - offset);
75
76 if (len > map->p_size) {
77 if (map->p) free(map->p);
78 map->p = (char *)malloc(len);
79 if (!map->p) out_of_memory("map_ptr");
80 map->p_size = len;
81 }
82
83 if (lseek(map->fd,offset,SEEK_SET) != offset ||
84 (nread=read(map->fd,map->p,len)) != len) {
85 fprintf(FERROR,"EOF in map_ptr! (offset=%d len=%d nread=%d errno=%d)\n",
86 (int)offset, len, nread, errno);
87 exit_cleanup(1);
88 }
89
90 map->p_offset = offset;
91 map->p_len = len;
92
93 return map->p;
94}
95
96
97void unmap_file(struct map_struct *map)
98{
99#ifdef HAVE_MMAP
100 if (map->map)
101 munmap(map->map,map->size);
102#endif
103 if (map->p) free(map->p);
104 free(map);
105}
106
107
108/* this is taken from CVS */
109int piped_child(char **command,int *f_in,int *f_out)
110{
111 int pid;
112 int to_child_pipe[2];
113 int from_child_pipe[2];
114
115 if (pipe(to_child_pipe) < 0 ||
116 pipe(from_child_pipe) < 0) {
117 fprintf(FERROR,"pipe: %s\n",strerror(errno));
118 exit_cleanup(1);
119 }
120
121
122 pid = fork();
123 if (pid < 0) {
124 fprintf(FERROR,"fork: %s\n",strerror(errno));
125 exit_cleanup(1);
126 }
127
128 if (pid == 0)
129 {
130 extern int orig_umask;
131 if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
132 close(to_child_pipe[1]) < 0 ||
133 close(from_child_pipe[0]) < 0 ||
134 dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
135 fprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
136 exit_cleanup(1);
137 }
138 if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
139 if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
140 umask(orig_umask);
141 execvp(command[0], command);
142 fprintf(FERROR,"Failed to exec %s : %s\n",
143 command[0],strerror(errno));
144 exit_cleanup(1);
145 }
146
147 if (close(from_child_pipe[1]) < 0 ||
148 close(to_child_pipe[0]) < 0) {
149 fprintf(FERROR,"Failed to close : %s\n",strerror(errno));
150 exit_cleanup(1);
151 }
152
153 *f_in = from_child_pipe[0];
154 *f_out = to_child_pipe[1];
155
156 return pid;
157}
158
159
160void out_of_memory(char *str)
161{
162 fprintf(FERROR,"out of memory in %s\n",str);
163 exit_cleanup(1);
164}
165
166
167
168int set_modtime(char *fname,time_t modtime)
169{
170#ifdef HAVE_UTIMBUF
171 struct utimbuf tbuf;
172 tbuf.actime = time(NULL);
173 tbuf.modtime = modtime;
174 return utime(fname,&tbuf);
175#elif defined(HAVE_UTIME)
176 time_t t[2];
177 t[0] = time(NULL);
178 t[1] = modtime;
179 return utime(fname,t);
180#else
181 struct timeval t[2];
182 t[0].tv_sec = time(NULL);
183 t[0].tv_usec = 0;
184 t[1].tv_sec = modtime;
185 t[1].tv_usec = 0;
186 return utimes(fname,t);
187#endif
188}
189
190
191
192/****************************************************************************
193Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
194else
195if SYSV use O_NDELAY
196if BSD use FNDELAY
197****************************************************************************/
198int set_blocking(int fd, int set)
199{
200 int val;
201#ifdef O_NONBLOCK
202#define FLAG_TO_SET O_NONBLOCK
203#else
204#ifdef SYSV
205#define FLAG_TO_SET O_NDELAY
206#else /* BSD */
207#define FLAG_TO_SET FNDELAY
208#endif
209#endif
210
211 if((val = fcntl(fd, F_GETFL, 0)) == -1)
212 return -1;
213 if(set) /* Turn blocking on - ie. clear nonblock flag */
214 val &= ~FLAG_TO_SET;
215 else
216 val |= FLAG_TO_SET;
217 return fcntl( fd, F_SETFL, val);
218#undef FLAG_TO_SET
219}
220
221/****************************************************************************
222create any necessary directories in fname. Unfortunately we don't know
223what perms to give the directory when this is called so we need to rely
224on the umask
225****************************************************************************/
226int create_directory_path(char *fname)
227{
228 extern int orig_umask;
229 char *p;
230
231 while (*fname == '/') fname++;
232 while (strncmp(fname,"./",2)==0) fname += 2;
233
234 p = fname;
235 while ((p=strchr(p,'/'))) {
236 *p = 0;
237 mkdir(fname,0777 & ~orig_umask);
238 *p = '/';
239 p++;
240 }
241 return 0;
242}
243
244
245/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted.
246 Return LEN upon success, write's (negative) error code otherwise.
247
248 derived from GNU C's cccp.c.
249*/
250int full_write(int desc, char *ptr, int len)
251{
252 int total_written;
253
254 total_written = 0;
255 while (len > 0) {
256 int written = write (desc, ptr, len);
257 if (written < 0) {
258#ifdef EINTR
259 if (errno == EINTR)
260 continue;
261#endif
262 return written;
263 }
264 total_written += written;
265 ptr += written;
266 len -= written;
267 }
268 return total_written;
269}
270
271/* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted.
272 Return the actual number of bytes read, zero for EOF, or negative
273 for an error.
274
275 derived from GNU C's cccp.c. */
276int safe_read(int desc, char *ptr, int len)
277{
278 int n_chars;
279
280 if (len <= 0)
281 return len;
282
283#ifdef EINTR
284 do {
285 n_chars = read(desc, ptr, len);
286 } while (n_chars < 0 && errno == EINTR);
287#else
288 n_chars = read(desc, ptr, len);
289#endif
290
291 return n_chars;
292}
293
294
295/* copy a file - this is used in conjunction with the --temp-dir option */
296int copy_file(char *source, char *dest, mode_t mode)
297{
298 int ifd;
299 int ofd;
300 char buf[1024 * 8];
301 int len; /* Number of bytes read into `buf'. */
302
303 ifd = open(source, O_RDONLY);
304 if (ifd == -1) {
305 fprintf(FERROR,"open %s: %s\n",
306 source,strerror(errno));
307 return -1;
308 }
309
310 if (unlink(dest) && errno != ENOENT) {
311 fprintf(FERROR,"unlink %s: %s\n",
312 dest,strerror(errno));
313 return -1;
314 }
315
316 ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
317 if (ofd < 0) {
318 fprintf(FERROR,"open %s: %s\n",
319 dest,strerror(errno));
320 close(ifd);
321 return -1;
322 }
323
324 while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
325 if (full_write(ofd, buf, len) < 0) {
326 fprintf(FERROR,"write %s: %s\n",
327 dest,strerror(errno));
328 close(ifd);
329 close(ofd);
330 return -1;
331 }
332 }
333
334 close(ifd);
335 close(ofd);
336
337 if (len < 0) {
338 fprintf(FERROR,"read %s: %s\n",
339 source,strerror(errno));
340 return -1;
341 }
342
343 return 0;
344}