This test must specify --times because it compares listings that
[rsync/rsync.git] / util.c
... / ...
CommitLineData
1/* -*- c-file-style: "linux" -*-
2
3 Copyright (C) 1996-2000 by Andrew Tridgell
4 Copyright (C) Paul Mackerras 1996
5 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22/*
23 Utilities used in rsync
24
25 tridge, June 1996
26 */
27#include "rsync.h"
28
29extern int verbose;
30
31
32/****************************************************************************
33Set a fd into nonblocking mode
34****************************************************************************/
35void set_nonblocking(int fd)
36{
37 int val;
38
39 if((val = fcntl(fd, F_GETFL, 0)) == -1)
40 return;
41 if (!(val & NONBLOCK_FLAG)) {
42 val |= NONBLOCK_FLAG;
43 fcntl(fd, F_SETFL, val);
44 }
45}
46
47/****************************************************************************
48Set a fd into blocking mode
49****************************************************************************/
50void set_blocking(int fd)
51{
52 int val;
53
54 if((val = fcntl(fd, F_GETFL, 0)) == -1)
55 return;
56 if (val & NONBLOCK_FLAG) {
57 val &= ~NONBLOCK_FLAG;
58 fcntl(fd, F_SETFL, val);
59 }
60}
61
62
63/* create a file descriptor pair - like pipe() but use socketpair if
64 possible (because of blocking issues on pipes)
65
66 always set non-blocking
67 */
68int fd_pair(int fd[2])
69{
70 int ret;
71
72#if HAVE_SOCKETPAIR
73 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
74#else
75 ret = pipe(fd);
76#endif
77
78 if (ret == 0) {
79 set_nonblocking(fd[0]);
80 set_nonblocking(fd[1]);
81 }
82
83 return ret;
84}
85
86
87void print_child_argv(char **cmd)
88{
89 rprintf(FINFO, "opening connection using ");
90 for (; *cmd; cmd++) {
91 /* Look for characters that ought to be quoted. This
92 * is not a great quoting algorithm, but it's
93 * sufficient for a log message. */
94 if (strspn(*cmd, "abcdefghijklmnopqrstuvwxyz"
95 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
96 "0123456789"
97 ",.-_=+@/") != strlen(*cmd)) {
98 rprintf(FINFO, "\"%s\" ", *cmd);
99 } else {
100 rprintf(FINFO, "%s ", *cmd);
101 }
102 }
103 rprintf(FINFO, "\n");
104}
105
106
107/* this is derived from CVS code
108
109 note that in the child STDIN is set to blocking and STDOUT
110 is set to non-blocking. This is necessary as rsh relies on stdin being blocking
111 and ssh relies on stdout being non-blocking
112
113 if blocking_io is set then use blocking io on both fds. That can be
114 used to cope with badly broken rsh implementations like the one on
115 solaris.
116 */
117pid_t piped_child(char **command, int *f_in, int *f_out)
118{
119 pid_t pid;
120 int to_child_pipe[2];
121 int from_child_pipe[2];
122 extern int blocking_io;
123
124 if (verbose >= 2) {
125 print_child_argv(command);
126 }
127
128 if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
129 rprintf(FERROR, "pipe: %s\n", strerror(errno));
130 exit_cleanup(RERR_IPC);
131 }
132
133
134 pid = do_fork();
135 if (pid == -1) {
136 rprintf(FERROR, "fork: %s\n", strerror(errno));
137 exit_cleanup(RERR_IPC);
138 }
139
140 if (pid == 0) {
141 extern int orig_umask;
142 if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
143 close(to_child_pipe[1]) < 0 ||
144 close(from_child_pipe[0]) < 0 ||
145 dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
146 rprintf(FERROR, "Failed to dup/close : %s\n",
147 strerror(errno));
148 exit_cleanup(RERR_IPC);
149 }
150 if (to_child_pipe[0] != STDIN_FILENO)
151 close(to_child_pipe[0]);
152 if (from_child_pipe[1] != STDOUT_FILENO)
153 close(from_child_pipe[1]);
154 umask(orig_umask);
155 set_blocking(STDIN_FILENO);
156 if (blocking_io) {
157 set_blocking(STDOUT_FILENO);
158 }
159 execvp(command[0], command);
160 rprintf(FERROR, "Failed to exec %s : %s\n",
161 command[0], strerror(errno));
162 exit_cleanup(RERR_IPC);
163 }
164
165 if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
166 rprintf(FERROR, "Failed to close : %s\n", strerror(errno));
167 exit_cleanup(RERR_IPC);
168 }
169
170 *f_in = from_child_pipe[0];
171 *f_out = to_child_pipe[1];
172
173 return pid;
174}
175
176pid_t local_child(int argc, char **argv,int *f_in,int *f_out)
177{
178 pid_t pid;
179 int to_child_pipe[2];
180 int from_child_pipe[2];
181 extern int read_batch; /* dw */
182
183 if (fd_pair(to_child_pipe) < 0 ||
184 fd_pair(from_child_pipe) < 0) {
185 rprintf(FERROR,"pipe: %s\n",strerror(errno));
186 exit_cleanup(RERR_IPC);
187 }
188
189
190 pid = do_fork();
191 if (pid == -1) {
192 rprintf(FERROR,"fork: %s\n",strerror(errno));
193 exit_cleanup(RERR_IPC);
194 }
195
196 if (pid == 0) {
197 extern int am_sender;
198 extern int am_server;
199
200 am_sender = read_batch ? 0 : !am_sender;
201 am_server = 1;
202
203 if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
204 close(to_child_pipe[1]) < 0 ||
205 close(from_child_pipe[0]) < 0 ||
206 dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
207 rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
208 exit_cleanup(RERR_IPC);
209 }
210 if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
211 if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
212 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
213 }
214
215 if (close(from_child_pipe[1]) < 0 ||
216 close(to_child_pipe[0]) < 0) {
217 rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
218 exit_cleanup(RERR_IPC);
219 }
220
221 *f_in = from_child_pipe[0];
222 *f_out = to_child_pipe[1];
223
224 return pid;
225}
226
227
228
229void out_of_memory(char *str)
230{
231 rprintf(FERROR,"ERROR: out of memory in %s\n",str);
232 exit_cleanup(RERR_MALLOC);
233}
234
235void overflow(char *str)
236{
237 rprintf(FERROR,"ERROR: buffer overflow in %s\n",str);
238 exit_cleanup(RERR_MALLOC);
239}
240
241
242
243int set_modtime(char *fname,time_t modtime)
244{
245 extern int dry_run;
246 if (dry_run) return 0;
247 {
248#ifdef HAVE_UTIMBUF
249 struct utimbuf tbuf;
250 tbuf.actime = time(NULL);
251 tbuf.modtime = modtime;
252 return utime(fname,&tbuf);
253#elif defined(HAVE_UTIME)
254 time_t t[2];
255 t[0] = time(NULL);
256 t[1] = modtime;
257 return utime(fname,t);
258#else
259 struct timeval t[2];
260 t[0].tv_sec = time(NULL);
261 t[0].tv_usec = 0;
262 t[1].tv_sec = modtime;
263 t[1].tv_usec = 0;
264 return utimes(fname,t);
265#endif
266 }
267}
268
269
270/****************************************************************************
271create any necessary directories in fname. Unfortunately we don't know
272what perms to give the directory when this is called so we need to rely
273on the umask
274****************************************************************************/
275int create_directory_path(char *fname)
276{
277 extern int orig_umask;
278 char *p;
279
280 while (*fname == '/') fname++;
281 while (strncmp(fname,"./",2)==0) fname += 2;
282
283 p = fname;
284 while ((p=strchr(p,'/'))) {
285 *p = 0;
286 do_mkdir(fname,0777 & ~orig_umask);
287 *p = '/';
288 p++;
289 }
290 return 0;
291}
292
293
294/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted.
295 Return LEN upon success, write's (negative) error code otherwise.
296
297 derived from GNU C's cccp.c.
298*/
299static int full_write(int desc, char *ptr, size_t len)
300{
301 int total_written;
302
303 total_written = 0;
304 while (len > 0) {
305 int written = write (desc, ptr, len);
306 if (written < 0) {
307#ifdef EINTR
308 if (errno == EINTR)
309 continue;
310#endif
311 return written;
312 }
313 total_written += written;
314 ptr += written;
315 len -= written;
316 }
317 return total_written;
318}
319
320/* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted.
321 Return the actual number of bytes read, zero for EOF, or negative
322 for an error.
323
324 derived from GNU C's cccp.c. */
325static int safe_read(int desc, char *ptr, size_t len)
326{
327 int n_chars;
328
329 if (len == 0)
330 return len;
331
332#ifdef EINTR
333 do {
334 n_chars = read(desc, ptr, len);
335 } while (n_chars < 0 && errno == EINTR);
336#else
337 n_chars = read(desc, ptr, len);
338#endif
339
340 return n_chars;
341}
342
343
344/* copy a file - this is used in conjunction with the --temp-dir option */
345int copy_file(char *source, char *dest, mode_t mode)
346{
347 int ifd;
348 int ofd;
349 char buf[1024 * 8];
350 int len; /* Number of bytes read into `buf'. */
351
352 ifd = do_open(source, O_RDONLY, 0);
353 if (ifd == -1) {
354 rprintf(FERROR,"open %s: %s\n",
355 source,strerror(errno));
356 return -1;
357 }
358
359 if (robust_unlink(dest) && errno != ENOENT) {
360 rprintf(FERROR,"unlink %s: %s\n",
361 dest,strerror(errno));
362 return -1;
363 }
364
365 ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
366 if (ofd == -1) {
367 rprintf(FERROR,"open %s: %s\n",
368 dest,strerror(errno));
369 close(ifd);
370 return -1;
371 }
372
373 while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
374 if (full_write(ofd, buf, len) < 0) {
375 rprintf(FERROR,"write %s: %s\n",
376 dest,strerror(errno));
377 close(ifd);
378 close(ofd);
379 return -1;
380 }
381 }
382
383 close(ifd);
384 close(ofd);
385
386 if (len < 0) {
387 rprintf(FERROR,"read %s: %s\n",
388 source,strerror(errno));
389 return -1;
390 }
391
392 return 0;
393}
394
395/*
396 Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
397 rename to <path>/.rsyncNNN instead. Note that successive rsync runs
398 will shuffle the filenames around a bit as long as the file is still
399 busy; this is because this function does not know if the unlink call
400 is due to a new file coming in, or --delete trying to remove old
401 .rsyncNNN files, hence it renames it each time.
402*/
403/* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
404#define MAX_RENAMES_DIGITS 3
405#define MAX_RENAMES 1000
406
407int robust_unlink(char *fname)
408{
409#ifndef ETXTBSY
410 return do_unlink(fname);
411#else
412 static int counter = 1;
413 int rc, pos, start;
414 char path[MAXPATHLEN];
415
416 rc = do_unlink(fname);
417 if ((rc == 0) || (errno != ETXTBSY))
418 return rc;
419
420 strlcpy(path, fname, MAXPATHLEN);
421
422 pos = strlen(path);
423 while((path[--pos] != '/') && (pos >= 0))
424 ;
425 ++pos;
426 strlcpy(&path[pos], ".rsync", MAXPATHLEN-pos);
427 pos += sizeof(".rsync")-1;
428
429 if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
430 errno = ETXTBSY;
431 return -1;
432 }
433
434 /* start where the last one left off to reduce chance of clashes */
435 start = counter;
436 do {
437 sprintf(&path[pos], "%03d", counter);
438 if (++counter >= MAX_RENAMES)
439 counter = 1;
440 } while (((rc = access(path, 0)) == 0) && (counter != start));
441
442 if (verbose > 0)
443 rprintf(FINFO,"renaming %s to %s because of text busy\n",
444 fname, path);
445
446 /* maybe we should return rename()'s exit status? Nah. */
447 if (do_rename(fname, path) != 0) {
448 errno = ETXTBSY;
449 return -1;
450 }
451 return 0;
452#endif
453}
454
455int robust_rename(char *from, char *to)
456{
457#ifndef ETXTBSY
458 return do_rename(from, to);
459#else
460 int rc = do_rename(from, to);
461 if ((rc == 0) || (errno != ETXTBSY))
462 return rc;
463 if (robust_unlink(to) != 0)
464 return -1;
465 return do_rename(from, to);
466#endif
467}
468
469
470static pid_t all_pids[10];
471static int num_pids;
472
473/* fork and record the pid of the child */
474pid_t do_fork(void)
475{
476 pid_t newpid = fork();
477
478 if (newpid) {
479 all_pids[num_pids++] = newpid;
480 }
481 return newpid;
482}
483
484/* kill all children */
485void kill_all(int sig)
486{
487 int i;
488 for (i=0;i<num_pids;i++) {
489 if (all_pids[i] != getpid())
490 kill(all_pids[i], sig);
491 }
492}
493
494/* turn a user name into a uid */
495int name_to_uid(char *name, uid_t *uid)
496{
497 struct passwd *pass;
498 if (!name || !*name) return 0;
499 pass = getpwnam(name);
500 if (pass) {
501 *uid = pass->pw_uid;
502 return 1;
503 }
504 return 0;
505}
506
507/* turn a group name into a gid */
508int name_to_gid(char *name, gid_t *gid)
509{
510 struct group *grp;
511 if (!name || !*name) return 0;
512 grp = getgrnam(name);
513 if (grp) {
514 *gid = grp->gr_gid;
515 return 1;
516 }
517 return 0;
518}
519
520
521/* lock a byte range in a open file */
522int lock_range(int fd, int offset, int len)
523{
524 struct flock lock;
525
526 lock.l_type = F_WRLCK;
527 lock.l_whence = SEEK_SET;
528 lock.l_start = offset;
529 lock.l_len = len;
530 lock.l_pid = 0;
531
532 return fcntl(fd,F_SETLK,&lock) == 0;
533}
534
535
536static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
537{
538#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
539 if (!*s) s = ".";
540 argv[*argc] = strdup(s);
541 (*argc)++;
542 return;
543#else
544 extern int sanitize_paths;
545 glob_t globbuf;
546 int i;
547
548 if (!*s) s = ".";
549
550 argv[*argc] = strdup(s);
551 if (sanitize_paths) {
552 sanitize_path(argv[*argc], NULL);
553 }
554
555 memset(&globbuf, 0, sizeof(globbuf));
556 glob(argv[*argc], 0, NULL, &globbuf);
557 if (globbuf.gl_pathc == 0) {
558 (*argc)++;
559 globfree(&globbuf);
560 return;
561 }
562 for (i=0; i<(maxargs - (*argc)) && i < (int) globbuf.gl_pathc;i++) {
563 if (i == 0) free(argv[*argc]);
564 argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
565 if (!argv[(*argc) + i]) out_of_memory("glob_expand");
566 }
567 globfree(&globbuf);
568 (*argc) += i;
569#endif
570}
571
572void glob_expand(char *base1, char **argv, int *argc, int maxargs)
573{
574 char *s = argv[*argc];
575 char *p, *q;
576 char *base = base1;
577
578 if (!s || !*s) return;
579
580 if (strncmp(s, base, strlen(base)) == 0) {
581 s += strlen(base);
582 }
583
584 s = strdup(s);
585 if (!s) out_of_memory("glob_expand");
586
587 if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
588
589 q = s;
590 while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
591 /* split it at this point */
592 *p = 0;
593 glob_expand_one(q, argv, argc, maxargs);
594 q = p+strlen(base);
595 }
596
597 if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
598
599 free(s);
600 free(base);
601}
602
603/*******************************************************************
604 convert a string to lower case
605********************************************************************/
606void strlower(char *s)
607{
608 while (*s) {
609 if (isupper(*s)) *s = tolower(*s);
610 s++;
611 }
612}
613
614void *Realloc(void *p, int size)
615{
616 if (!p) return (void *)malloc(size);
617 return (void *)realloc(p, size);
618}
619
620
621void clean_fname(char *name)
622{
623 char *p;
624 int l;
625 int modified = 1;
626
627 if (!name) return;
628
629 while (modified) {
630 modified = 0;
631
632 if ((p=strstr(name,"/./"))) {
633 modified = 1;
634 while (*p) {
635 p[0] = p[2];
636 p++;
637 }
638 }
639
640 if ((p=strstr(name,"//"))) {
641 modified = 1;
642 while (*p) {
643 p[0] = p[1];
644 p++;
645 }
646 }
647
648 if (strncmp(p=name,"./",2) == 0) {
649 modified = 1;
650 do {
651 p[0] = p[2];
652 } while (*p++);
653 }
654
655 l = strlen(p=name);
656 if (l > 1 && p[l-1] == '/') {
657 modified = 1;
658 p[l-1] = 0;
659 }
660 }
661}
662
663/*
664 * Make path appear as if a chroot had occurred:
665 * 1. remove leading "/" (or replace with "." if at end)
666 * 2. remove leading ".." components (except those allowed by "reldir")
667 * 3. delete any other "<dir>/.." (recursively)
668 * Can only shrink paths, so sanitizes in place.
669 * While we're at it, remove double slashes and "." components like
670 * clean_fname does(), but DON'T remove a trailing slash because that
671 * is sometimes significant on command line arguments.
672 * If "reldir" is non-null, it is a sanitized directory that the path will be
673 * relative to, so allow as many ".." at the beginning of the path as
674 * there are components in reldir. This is used for symbolic link targets.
675 * If reldir is non-null and the path began with "/", to be completely like
676 * a chroot we should add in depth levels of ".." at the beginning of the
677 * path, but that would blow the assumption that the path doesn't grow and
678 * it is not likely to end up being a valid symlink anyway, so just do
679 * the normal removal of the leading "/" instead.
680 * Contributed by Dave Dykstra <dwd@bell-labs.com>
681 */
682
683void sanitize_path(char *p, char *reldir)
684{
685 char *start, *sanp;
686 int depth = 0;
687 int allowdotdot = 0;
688
689 if (reldir) {
690 depth++;
691 while (*reldir) {
692 if (*reldir++ == '/') {
693 depth++;
694 }
695 }
696 }
697 start = p;
698 sanp = p;
699 while (*p == '/') {
700 /* remove leading slashes */
701 p++;
702 }
703 while (*p != '\0') {
704 /* this loop iterates once per filename component in p.
705 * both p (and sanp if the original had a slash) should
706 * always be left pointing after a slash
707 */
708 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
709 /* skip "." component */
710 while (*++p == '/') {
711 /* skip following slashes */
712 ;
713 }
714 continue;
715 }
716 allowdotdot = 0;
717 if ((*p == '.') && (*(p+1) == '.') &&
718 ((*(p+2) == '/') || (*(p+2) == '\0'))) {
719 /* ".." component followed by slash or end */
720 if ((depth > 0) && (sanp == start)) {
721 /* allow depth levels of .. at the beginning */
722 --depth;
723 allowdotdot = 1;
724 } else {
725 p += 2;
726 if (*p == '/')
727 p++;
728 if (sanp != start) {
729 /* back up sanp one level */
730 --sanp; /* now pointing at slash */
731 while ((sanp > start) && (*(sanp - 1) != '/')) {
732 /* skip back up to slash */
733 sanp--;
734 }
735 }
736 continue;
737 }
738 }
739 while (1) {
740 /* copy one component through next slash */
741 *sanp++ = *p++;
742 if ((*p == '\0') || (*(p-1) == '/')) {
743 while (*p == '/') {
744 /* skip multiple slashes */
745 p++;
746 }
747 break;
748 }
749 }
750 if (allowdotdot) {
751 /* move the virtual beginning to leave the .. alone */
752 start = sanp;
753 }
754 }
755 if ((sanp == start) && !allowdotdot) {
756 /* ended up with nothing, so put in "." component */
757 /*
758 * note that the !allowdotdot doesn't prevent this from
759 * happening in all allowed ".." situations, but I didn't
760 * think it was worth putting in an extra variable to ensure
761 * it since an extra "." won't hurt in those situations.
762 */
763 *sanp++ = '.';
764 }
765 *sanp = '\0';
766}
767
768
769static char curr_dir[MAXPATHLEN];
770
771/* like chdir() but can be reversed with pop_dir() if save is set. It
772 is also much faster as it remembers where we have been */
773char *push_dir(char *dir, int save)
774{
775 char *ret = curr_dir;
776 static int initialised;
777
778 if (!initialised) {
779 initialised = 1;
780 getcwd(curr_dir, sizeof(curr_dir)-1);
781 }
782
783 if (!dir) return NULL; /* this call was probably just to initialize */
784
785 if (chdir(dir)) return NULL;
786
787 if (save) {
788 ret = strdup(curr_dir);
789 }
790
791 if (*dir == '/') {
792 strlcpy(curr_dir, dir, sizeof(curr_dir));
793 } else {
794 strlcat(curr_dir,"/", sizeof(curr_dir));
795 strlcat(curr_dir,dir, sizeof(curr_dir));
796 }
797
798 clean_fname(curr_dir);
799
800 return ret;
801}
802
803/* reverse a push_dir call */
804int pop_dir(char *dir)
805{
806 int ret;
807
808 ret = chdir(dir);
809 if (ret) {
810 free(dir);
811 return ret;
812 }
813
814 strlcpy(curr_dir, dir, sizeof(curr_dir));
815
816 free(dir);
817
818 return 0;
819}
820
821/* we need to supply our own strcmp function for file list comparisons
822 to ensure that signed/unsigned usage is consistent between machines. */
823int u_strcmp(const char *cs1, const char *cs2)
824{
825 const uchar *s1 = (const uchar *)cs1;
826 const uchar *s2 = (const uchar *)cs2;
827
828 while (*s1 && *s2 && (*s1 == *s2)) {
829 s1++; s2++;
830 }
831
832 return (int)*s1 - (int)*s2;
833}
834
835static OFF_T last_ofs;
836static struct timeval print_time;
837static struct timeval start_time;
838static OFF_T start_ofs;
839
840static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
841{
842 return (t2->tv_sec - t1->tv_sec) * 1000
843 + (t2->tv_usec - t1->tv_usec) / 1000;
844}
845
846
847/**
848 * @param ofs Current position in file
849 * @param size Total size of file
850 * @param is_last True if this is the last time progress will be
851 * printed for this file, so we should output a newline. (Not
852 * necessarily the same as all bytes being received.)
853 **/
854static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
855 int is_last)
856{
857 int pct = (ofs == size) ? 100 : (int)((100.0*ofs)/size);
858 unsigned long diff = msdiff(&start_time, now);
859 double rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0;
860 const char *units;
861 double remain = rate ? (double) (size-ofs) / rate / 1000.0: 0.0;
862 int remain_h, remain_m, remain_s;
863
864 if (rate > 1024*1024) {
865 rate /= 1024.0 * 1024.0;
866 units = "GB/s";
867 } else if (rate > 1024) {
868 rate /= 1024.0;
869 units = "MB/s";
870 } else {
871 units = "kB/s";
872 }
873
874 remain_s = (int) remain % 60;
875 remain_m = (int) (remain / 60.0) % 60;
876 remain_h = (int) (remain / 3600.0);
877
878 rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
879 (double) ofs, pct, rate, units,
880 remain_h, remain_m, remain_s,
881 is_last ? "\n" : "\r");
882}
883
884void end_progress(OFF_T size)
885{
886 extern int do_progress, am_server;
887
888 if (do_progress && !am_server) {
889 struct timeval now;
890 gettimeofday(&now, NULL);
891 rprint_progress(size, size, &now, True);
892 }
893 last_ofs = 0;
894 start_ofs = 0;
895 print_time.tv_sec = print_time.tv_usec = 0;
896 start_time.tv_sec = start_time.tv_usec = 0;
897}
898
899void show_progress(OFF_T ofs, OFF_T size)
900{
901 extern int do_progress, am_server;
902 struct timeval now;
903
904 gettimeofday(&now, NULL);
905
906 if (!start_time.tv_sec && !start_time.tv_usec) {
907 start_time.tv_sec = now.tv_sec;
908 start_time.tv_usec = now.tv_usec;
909 start_ofs = ofs;
910 }
911
912 if (do_progress
913 && !am_server
914 && ofs > last_ofs + 1000
915 && msdiff(&print_time, &now) > 250) {
916 rprint_progress(ofs, size, &now, False);
917 last_ofs = ofs;
918 print_time.tv_sec = now.tv_sec;
919 print_time.tv_usec = now.tv_usec;
920 }
921}
922
923/* determine if a symlink points outside the current directory tree */
924int unsafe_symlink(char *dest, char *src)
925{
926 char *tok;
927 int depth = 0;
928
929 /* all absolute and null symlinks are unsafe */
930 if (!dest || !(*dest) || (*dest == '/')) return 1;
931
932 src = strdup(src);
933 if (!src) out_of_memory("unsafe_symlink");
934
935 /* find out what our safety margin is */
936 for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
937 if (strcmp(tok,"..") == 0) {
938 depth=0;
939 } else if (strcmp(tok,".") == 0) {
940 /* nothing */
941 } else {
942 depth++;
943 }
944 }
945 free(src);
946
947 /* drop by one to account for the filename portion */
948 depth--;
949
950 dest = strdup(dest);
951 if (!dest) out_of_memory("unsafe_symlink");
952
953 for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
954 if (strcmp(tok,"..") == 0) {
955 depth--;
956 } else if (strcmp(tok,".") == 0) {
957 /* nothing */
958 } else {
959 depth++;
960 }
961 /* if at any point we go outside the current directory then
962 stop - it is unsafe */
963 if (depth < 0) break;
964 }
965
966 free(dest);
967 return (depth < 0);
968}
969
970
971/****************************************************************************
972 return the date and time as a string
973****************************************************************************/
974char *timestring(time_t t)
975{
976 static char TimeBuf[200];
977 struct tm *tm = localtime(&t);
978
979#ifdef HAVE_STRFTIME
980 strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
981#else
982 strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
983#endif
984
985 if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
986 TimeBuf[strlen(TimeBuf)-1] = 0;
987 }
988
989 return(TimeBuf);
990}
991
992
993/**
994 * Sleep for a specified number of milliseconds.
995 *
996 * Always returns TRUE. (In the future it might return FALSE if
997 * interrupted.)
998 **/
999int msleep(int t)
1000{
1001 int tdiff=0;
1002 struct timeval tval,t1,t2;
1003
1004 gettimeofday(&t1, NULL);
1005 gettimeofday(&t2, NULL);
1006
1007 while (tdiff < t) {
1008 tval.tv_sec = (t-tdiff)/1000;
1009 tval.tv_usec = 1000*((t-tdiff)%1000);
1010
1011 errno = 0;
1012 select(0,NULL,NULL, NULL, &tval);
1013
1014 gettimeofday(&t2, NULL);
1015 tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
1016 (t2.tv_usec - t1.tv_usec)/1000;
1017 }
1018
1019 return True;
1020}
1021
1022
1023/*******************************************************************
1024 Determine if two file modification times are equivalent (either exact
1025 or in the modification timestamp window established by --modify-window)
1026 Returns 0 if the times should be treated as the same, 1 if the
1027 first is later and -1 if the 2nd is later
1028 *******************************************************************/
1029int cmp_modtime(time_t file1, time_t file2)
1030{
1031 extern int modify_window;
1032
1033 if (file2 > file1) {
1034 if (file2 - file1 <= modify_window) return 0;
1035 return -1;
1036 }
1037 if (file1 - file2 <= modify_window) return 0;
1038 return 1;
1039}
1040
1041
1042#ifdef __INSURE__XX
1043#include <dlfcn.h>
1044
1045/*******************************************************************
1046This routine is a trick to immediately catch errors when debugging
1047with insure. A xterm with a gdb is popped up when insure catches
1048a error. It is Linux specific.
1049********************************************************************/
1050int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
1051{
1052 static int (*fn)();
1053 int ret;
1054 char *cmd;
1055
1056 asprintf(&cmd, "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; gdb /proc/%d/exe %d'",
1057 getpid(), getpid(), getpid());
1058
1059 if (!fn) {
1060 static void *h;
1061 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
1062 fn = dlsym(h, "_Insure_trap_error");
1063 }
1064
1065 ret = fn(a1, a2, a3, a4, a5, a6);
1066
1067 system(cmd);
1068
1069 free(cmd);
1070
1071 return ret;
1072}
1073#endif