Now that whole_file and no_whole_file are separate variables, have the
[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
87static void 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)
247 return 0;
248
249 if (verbose > 2) {
250 rprintf(FINFO, "set modtime of %s to (%ld) %s",
251 fname, (long) modtime,
252 asctime(localtime(&modtime)));
253 }
254
255 {
256#ifdef HAVE_UTIMBUF
257 struct utimbuf tbuf;
258 tbuf.actime = time(NULL);
259 tbuf.modtime = modtime;
260 return utime(fname,&tbuf);
261#elif defined(HAVE_UTIME)
262 time_t t[2];
263 t[0] = time(NULL);
264 t[1] = modtime;
265 return utime(fname,t);
266#else
267 struct timeval t[2];
268 t[0].tv_sec = time(NULL);
269 t[0].tv_usec = 0;
270 t[1].tv_sec = modtime;
271 t[1].tv_usec = 0;
272 return utimes(fname,t);
273#endif
274 }
275}
276
277
278/****************************************************************************
279create any necessary directories in fname. Unfortunately we don't know
280what perms to give the directory when this is called so we need to rely
281on the umask
282****************************************************************************/
283int create_directory_path(char *fname)
284{
285 extern int orig_umask;
286 char *p;
287
288 while (*fname == '/') fname++;
289 while (strncmp(fname,"./",2)==0) fname += 2;
290
291 p = fname;
292 while ((p=strchr(p,'/'))) {
293 *p = 0;
294 do_mkdir(fname,0777 & ~orig_umask);
295 *p = '/';
296 p++;
297 }
298 return 0;
299}
300
301
302/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted.
303 Return LEN upon success, write's (negative) error code otherwise.
304
305 derived from GNU C's cccp.c.
306*/
307static int full_write(int desc, char *ptr, size_t len)
308{
309 int total_written;
310
311 total_written = 0;
312 while (len > 0) {
313 int written = write (desc, ptr, len);
314 if (written < 0) {
315#ifdef EINTR
316 if (errno == EINTR)
317 continue;
318#endif
319 return written;
320 }
321 total_written += written;
322 ptr += written;
323 len -= written;
324 }
325 return total_written;
326}
327
328/* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted.
329 Return the actual number of bytes read, zero for EOF, or negative
330 for an error.
331
332 derived from GNU C's cccp.c. */
333static int safe_read(int desc, char *ptr, size_t len)
334{
335 int n_chars;
336
337 if (len == 0)
338 return len;
339
340#ifdef EINTR
341 do {
342 n_chars = read(desc, ptr, len);
343 } while (n_chars < 0 && errno == EINTR);
344#else
345 n_chars = read(desc, ptr, len);
346#endif
347
348 return n_chars;
349}
350
351
352/* copy a file - this is used in conjunction with the --temp-dir option */
353int copy_file(char *source, char *dest, mode_t mode)
354{
355 int ifd;
356 int ofd;
357 char buf[1024 * 8];
358 int len; /* Number of bytes read into `buf'. */
359
360 ifd = do_open(source, O_RDONLY, 0);
361 if (ifd == -1) {
362 rprintf(FERROR,"open %s: %s\n",
363 source,strerror(errno));
364 return -1;
365 }
366
367 if (robust_unlink(dest) && errno != ENOENT) {
368 rprintf(FERROR,"unlink %s: %s\n",
369 dest,strerror(errno));
370 return -1;
371 }
372
373 ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
374 if (ofd == -1) {
375 rprintf(FERROR,"open %s: %s\n",
376 dest,strerror(errno));
377 close(ifd);
378 return -1;
379 }
380
381 while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
382 if (full_write(ofd, buf, len) < 0) {
383 rprintf(FERROR,"write %s: %s\n",
384 dest,strerror(errno));
385 close(ifd);
386 close(ofd);
387 return -1;
388 }
389 }
390
391 close(ifd);
392 close(ofd);
393
394 if (len < 0) {
395 rprintf(FERROR,"read %s: %s\n",
396 source,strerror(errno));
397 return -1;
398 }
399
400 return 0;
401}
402
403/*
404 Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
405 rename to <path>/.rsyncNNN instead. Note that successive rsync runs
406 will shuffle the filenames around a bit as long as the file is still
407 busy; this is because this function does not know if the unlink call
408 is due to a new file coming in, or --delete trying to remove old
409 .rsyncNNN files, hence it renames it each time.
410*/
411/* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
412#define MAX_RENAMES_DIGITS 3
413#define MAX_RENAMES 1000
414
415int robust_unlink(char *fname)
416{
417#ifndef ETXTBSY
418 return do_unlink(fname);
419#else
420 static int counter = 1;
421 int rc, pos, start;
422 char path[MAXPATHLEN];
423
424 rc = do_unlink(fname);
425 if ((rc == 0) || (errno != ETXTBSY))
426 return rc;
427
428 strlcpy(path, fname, MAXPATHLEN);
429
430 pos = strlen(path);
431 while((path[--pos] != '/') && (pos >= 0))
432 ;
433 ++pos;
434 strlcpy(&path[pos], ".rsync", MAXPATHLEN-pos);
435 pos += sizeof(".rsync")-1;
436
437 if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
438 errno = ETXTBSY;
439 return -1;
440 }
441
442 /* start where the last one left off to reduce chance of clashes */
443 start = counter;
444 do {
445 sprintf(&path[pos], "%03d", counter);
446 if (++counter >= MAX_RENAMES)
447 counter = 1;
448 } while (((rc = access(path, 0)) == 0) && (counter != start));
449
450 if (verbose > 0)
451 rprintf(FINFO,"renaming %s to %s because of text busy\n",
452 fname, path);
453
454 /* maybe we should return rename()'s exit status? Nah. */
455 if (do_rename(fname, path) != 0) {
456 errno = ETXTBSY;
457 return -1;
458 }
459 return 0;
460#endif
461}
462
463int robust_rename(char *from, char *to)
464{
465#ifndef ETXTBSY
466 return do_rename(from, to);
467#else
468 int rc = do_rename(from, to);
469 if ((rc == 0) || (errno != ETXTBSY))
470 return rc;
471 if (robust_unlink(to) != 0)
472 return -1;
473 return do_rename(from, to);
474#endif
475}
476
477
478static pid_t all_pids[10];
479static int num_pids;
480
481/* fork and record the pid of the child */
482pid_t do_fork(void)
483{
484 pid_t newpid = fork();
485
486 if (newpid) {
487 all_pids[num_pids++] = newpid;
488 }
489 return newpid;
490}
491
492/* kill all children */
493void kill_all(int sig)
494{
495 int i;
496 for (i=0;i<num_pids;i++) {
497 if (all_pids[i] != getpid())
498 kill(all_pids[i], sig);
499 }
500}
501
502/* turn a user name into a uid */
503int name_to_uid(char *name, uid_t *uid)
504{
505 struct passwd *pass;
506 if (!name || !*name) return 0;
507 pass = getpwnam(name);
508 if (pass) {
509 *uid = pass->pw_uid;
510 return 1;
511 }
512 return 0;
513}
514
515/* turn a group name into a gid */
516int name_to_gid(char *name, gid_t *gid)
517{
518 struct group *grp;
519 if (!name || !*name) return 0;
520 grp = getgrnam(name);
521 if (grp) {
522 *gid = grp->gr_gid;
523 return 1;
524 }
525 return 0;
526}
527
528
529/* lock a byte range in a open file */
530int lock_range(int fd, int offset, int len)
531{
532 struct flock lock;
533
534 lock.l_type = F_WRLCK;
535 lock.l_whence = SEEK_SET;
536 lock.l_start = offset;
537 lock.l_len = len;
538 lock.l_pid = 0;
539
540 return fcntl(fd,F_SETLK,&lock) == 0;
541}
542
543
544static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
545{
546#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
547 if (!*s) s = ".";
548 argv[*argc] = strdup(s);
549 (*argc)++;
550 return;
551#else
552 extern int sanitize_paths;
553 glob_t globbuf;
554 int i;
555
556 if (!*s) s = ".";
557
558 argv[*argc] = strdup(s);
559 if (sanitize_paths) {
560 sanitize_path(argv[*argc], NULL);
561 }
562
563 memset(&globbuf, 0, sizeof(globbuf));
564 glob(argv[*argc], 0, NULL, &globbuf);
565 if (globbuf.gl_pathc == 0) {
566 (*argc)++;
567 globfree(&globbuf);
568 return;
569 }
570 for (i=0; i<(maxargs - (*argc)) && i < (int) globbuf.gl_pathc;i++) {
571 if (i == 0) free(argv[*argc]);
572 argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
573 if (!argv[(*argc) + i]) out_of_memory("glob_expand");
574 }
575 globfree(&globbuf);
576 (*argc) += i;
577#endif
578}
579
580void glob_expand(char *base1, char **argv, int *argc, int maxargs)
581{
582 char *s = argv[*argc];
583 char *p, *q;
584 char *base = base1;
585
586 if (!s || !*s) return;
587
588 if (strncmp(s, base, strlen(base)) == 0) {
589 s += strlen(base);
590 }
591
592 s = strdup(s);
593 if (!s) out_of_memory("glob_expand");
594
595 if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
596
597 q = s;
598 while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
599 /* split it at this point */
600 *p = 0;
601 glob_expand_one(q, argv, argc, maxargs);
602 q = p+strlen(base);
603 }
604
605 if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
606
607 free(s);
608 free(base);
609}
610
611/*******************************************************************
612 convert a string to lower case
613********************************************************************/
614void strlower(char *s)
615{
616 while (*s) {
617 if (isupper(*s)) *s = tolower(*s);
618 s++;
619 }
620}
621
622void *Realloc(void *p, int size)
623{
624 if (!p) return (void *)malloc(size);
625 return (void *)realloc(p, size);
626}
627
628
629void clean_fname(char *name)
630{
631 char *p;
632 int l;
633 int modified = 1;
634
635 if (!name) return;
636
637 while (modified) {
638 modified = 0;
639
640 if ((p=strstr(name,"/./"))) {
641 modified = 1;
642 while (*p) {
643 p[0] = p[2];
644 p++;
645 }
646 }
647
648 if ((p=strstr(name,"//"))) {
649 modified = 1;
650 while (*p) {
651 p[0] = p[1];
652 p++;
653 }
654 }
655
656 if (strncmp(p=name,"./",2) == 0) {
657 modified = 1;
658 do {
659 p[0] = p[2];
660 } while (*p++);
661 }
662
663 l = strlen(p=name);
664 if (l > 1 && p[l-1] == '/') {
665 modified = 1;
666 p[l-1] = 0;
667 }
668 }
669}
670
671/*
672 * Make path appear as if a chroot had occurred:
673 * 1. remove leading "/" (or replace with "." if at end)
674 * 2. remove leading ".." components (except those allowed by "reldir")
675 * 3. delete any other "<dir>/.." (recursively)
676 * Can only shrink paths, so sanitizes in place.
677 * While we're at it, remove double slashes and "." components like
678 * clean_fname does(), but DON'T remove a trailing slash because that
679 * is sometimes significant on command line arguments.
680 * If "reldir" is non-null, it is a sanitized directory that the path will be
681 * relative to, so allow as many ".." at the beginning of the path as
682 * there are components in reldir. This is used for symbolic link targets.
683 * If reldir is non-null and the path began with "/", to be completely like
684 * a chroot we should add in depth levels of ".." at the beginning of the
685 * path, but that would blow the assumption that the path doesn't grow and
686 * it is not likely to end up being a valid symlink anyway, so just do
687 * the normal removal of the leading "/" instead.
688 * Contributed by Dave Dykstra <dwd@bell-labs.com>
689 */
690
691void sanitize_path(char *p, char *reldir)
692{
693 char *start, *sanp;
694 int depth = 0;
695 int allowdotdot = 0;
696
697 if (reldir) {
698 depth++;
699 while (*reldir) {
700 if (*reldir++ == '/') {
701 depth++;
702 }
703 }
704 }
705 start = p;
706 sanp = p;
707 while (*p == '/') {
708 /* remove leading slashes */
709 p++;
710 }
711 while (*p != '\0') {
712 /* this loop iterates once per filename component in p.
713 * both p (and sanp if the original had a slash) should
714 * always be left pointing after a slash
715 */
716 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
717 /* skip "." component */
718 while (*++p == '/') {
719 /* skip following slashes */
720 ;
721 }
722 continue;
723 }
724 allowdotdot = 0;
725 if ((*p == '.') && (*(p+1) == '.') &&
726 ((*(p+2) == '/') || (*(p+2) == '\0'))) {
727 /* ".." component followed by slash or end */
728 if ((depth > 0) && (sanp == start)) {
729 /* allow depth levels of .. at the beginning */
730 --depth;
731 allowdotdot = 1;
732 } else {
733 p += 2;
734 if (*p == '/')
735 p++;
736 if (sanp != start) {
737 /* back up sanp one level */
738 --sanp; /* now pointing at slash */
739 while ((sanp > start) && (*(sanp - 1) != '/')) {
740 /* skip back up to slash */
741 sanp--;
742 }
743 }
744 continue;
745 }
746 }
747 while (1) {
748 /* copy one component through next slash */
749 *sanp++ = *p++;
750 if ((*p == '\0') || (*(p-1) == '/')) {
751 while (*p == '/') {
752 /* skip multiple slashes */
753 p++;
754 }
755 break;
756 }
757 }
758 if (allowdotdot) {
759 /* move the virtual beginning to leave the .. alone */
760 start = sanp;
761 }
762 }
763 if ((sanp == start) && !allowdotdot) {
764 /* ended up with nothing, so put in "." component */
765 /*
766 * note that the !allowdotdot doesn't prevent this from
767 * happening in all allowed ".." situations, but I didn't
768 * think it was worth putting in an extra variable to ensure
769 * it since an extra "." won't hurt in those situations.
770 */
771 *sanp++ = '.';
772 }
773 *sanp = '\0';
774}
775
776
777static char curr_dir[MAXPATHLEN];
778
779/* like chdir() but can be reversed with pop_dir() if save is set. It
780 is also much faster as it remembers where we have been */
781char *push_dir(char *dir, int save)
782{
783 char *ret = curr_dir;
784 static int initialised;
785
786 if (!initialised) {
787 initialised = 1;
788 getcwd(curr_dir, sizeof(curr_dir)-1);
789 }
790
791 if (!dir) return NULL; /* this call was probably just to initialize */
792
793 if (chdir(dir)) return NULL;
794
795 if (save) {
796 ret = strdup(curr_dir);
797 }
798
799 if (*dir == '/') {
800 strlcpy(curr_dir, dir, sizeof(curr_dir));
801 } else {
802 strlcat(curr_dir,"/", sizeof(curr_dir));
803 strlcat(curr_dir,dir, sizeof(curr_dir));
804 }
805
806 clean_fname(curr_dir);
807
808 return ret;
809}
810
811/* reverse a push_dir call */
812int pop_dir(char *dir)
813{
814 int ret;
815
816 ret = chdir(dir);
817 if (ret) {
818 free(dir);
819 return ret;
820 }
821
822 strlcpy(curr_dir, dir, sizeof(curr_dir));
823
824 free(dir);
825
826 return 0;
827}
828
829/* we need to supply our own strcmp function for file list comparisons
830 to ensure that signed/unsigned usage is consistent between machines. */
831int u_strcmp(const char *cs1, const char *cs2)
832{
833 const uchar *s1 = (const uchar *)cs1;
834 const uchar *s2 = (const uchar *)cs2;
835
836 while (*s1 && *s2 && (*s1 == *s2)) {
837 s1++; s2++;
838 }
839
840 return (int)*s1 - (int)*s2;
841}
842
843static OFF_T last_ofs;
844static struct timeval print_time;
845static struct timeval start_time;
846static OFF_T start_ofs;
847
848static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
849{
850 return (t2->tv_sec - t1->tv_sec) * 1000
851 + (t2->tv_usec - t1->tv_usec) / 1000;
852}
853
854
855/**
856 * @param ofs Current position in file
857 * @param size Total size of file
858 * @param is_last True if this is the last time progress will be
859 * printed for this file, so we should output a newline. (Not
860 * necessarily the same as all bytes being received.)
861 **/
862static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
863 int is_last)
864{
865 int pct = (ofs == size) ? 100 : (int)((100.0*ofs)/size);
866 unsigned long diff = msdiff(&start_time, now);
867 double rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0;
868 const char *units;
869 /* If we've finished transferring this file, show the time taken;
870 * otherwise show expected time to complete. That's kind of
871 * inconsistent, but people can probably cope. Hopefully we'll
872 * get more consistent and complete progress reporting soon. --
873 * mbp */
874 double remain = is_last
875 ? (double) diff / 1000.0
876 : rate ? (double) (size-ofs) / rate / 1000.0 : 0.0;
877 int remain_h, remain_m, remain_s;
878
879 if (rate > 1024*1024) {
880 rate /= 1024.0 * 1024.0;
881 units = "GB/s";
882 } else if (rate > 1024) {
883 rate /= 1024.0;
884 units = "MB/s";
885 } else {
886 units = "kB/s";
887 }
888
889 remain_s = (int) remain % 60;
890 remain_m = (int) (remain / 60.0) % 60;
891 remain_h = (int) (remain / 3600.0);
892
893 rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
894 (double) ofs, pct, rate, units,
895 remain_h, remain_m, remain_s,
896 is_last ? "\n" : "\r");
897}
898
899void end_progress(OFF_T size)
900{
901 extern int do_progress, am_server;
902
903 if (do_progress && !am_server) {
904 struct timeval now;
905 gettimeofday(&now, NULL);
906 rprint_progress(size, size, &now, True);
907 }
908 last_ofs = 0;
909 start_ofs = 0;
910 print_time.tv_sec = print_time.tv_usec = 0;
911 start_time.tv_sec = start_time.tv_usec = 0;
912}
913
914void show_progress(OFF_T ofs, OFF_T size)
915{
916 extern int do_progress, am_server;
917 struct timeval now;
918
919 gettimeofday(&now, NULL);
920
921 if (!start_time.tv_sec && !start_time.tv_usec) {
922 start_time.tv_sec = now.tv_sec;
923 start_time.tv_usec = now.tv_usec;
924 start_ofs = ofs;
925 }
926
927 if (do_progress
928 && !am_server
929 && ofs > last_ofs + 1000
930 && msdiff(&print_time, &now) > 250) {
931 rprint_progress(ofs, size, &now, False);
932 last_ofs = ofs;
933 print_time.tv_sec = now.tv_sec;
934 print_time.tv_usec = now.tv_usec;
935 }
936}
937
938/* determine if a symlink points outside the current directory tree */
939int unsafe_symlink(char *dest, char *src)
940{
941 char *tok;
942 int depth = 0;
943
944 /* all absolute and null symlinks are unsafe */
945 if (!dest || !(*dest) || (*dest == '/')) return 1;
946
947 src = strdup(src);
948 if (!src) out_of_memory("unsafe_symlink");
949
950 /* find out what our safety margin is */
951 for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
952 if (strcmp(tok,"..") == 0) {
953 depth=0;
954 } else if (strcmp(tok,".") == 0) {
955 /* nothing */
956 } else {
957 depth++;
958 }
959 }
960 free(src);
961
962 /* drop by one to account for the filename portion */
963 depth--;
964
965 dest = strdup(dest);
966 if (!dest) out_of_memory("unsafe_symlink");
967
968 for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
969 if (strcmp(tok,"..") == 0) {
970 depth--;
971 } else if (strcmp(tok,".") == 0) {
972 /* nothing */
973 } else {
974 depth++;
975 }
976 /* if at any point we go outside the current directory then
977 stop - it is unsafe */
978 if (depth < 0) break;
979 }
980
981 free(dest);
982 return (depth < 0);
983}
984
985
986/****************************************************************************
987 return the date and time as a string
988****************************************************************************/
989char *timestring(time_t t)
990{
991 static char TimeBuf[200];
992 struct tm *tm = localtime(&t);
993
994#ifdef HAVE_STRFTIME
995 strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
996#else
997 strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
998#endif
999
1000 if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
1001 TimeBuf[strlen(TimeBuf)-1] = 0;
1002 }
1003
1004 return(TimeBuf);
1005}
1006
1007
1008/**
1009 * Sleep for a specified number of milliseconds.
1010 *
1011 * Always returns TRUE. (In the future it might return FALSE if
1012 * interrupted.)
1013 **/
1014int msleep(int t)
1015{
1016 int tdiff=0;
1017 struct timeval tval,t1,t2;
1018
1019 gettimeofday(&t1, NULL);
1020 gettimeofday(&t2, NULL);
1021
1022 while (tdiff < t) {
1023 tval.tv_sec = (t-tdiff)/1000;
1024 tval.tv_usec = 1000*((t-tdiff)%1000);
1025
1026 errno = 0;
1027 select(0,NULL,NULL, NULL, &tval);
1028
1029 gettimeofday(&t2, NULL);
1030 tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
1031 (t2.tv_usec - t1.tv_usec)/1000;
1032 }
1033
1034 return True;
1035}
1036
1037
1038/*******************************************************************
1039 Determine if two file modification times are equivalent (either exact
1040 or in the modification timestamp window established by --modify-window)
1041 Returns 0 if the times should be treated as the same, 1 if the
1042 first is later and -1 if the 2nd is later
1043 *******************************************************************/
1044int cmp_modtime(time_t file1, time_t file2)
1045{
1046 extern int modify_window;
1047
1048 if (file2 > file1) {
1049 if (file2 - file1 <= modify_window) return 0;
1050 return -1;
1051 }
1052 if (file1 - file2 <= modify_window) return 0;
1053 return 1;
1054}
1055
1056
1057#ifdef __INSURE__XX
1058#include <dlfcn.h>
1059
1060/*******************************************************************
1061This routine is a trick to immediately catch errors when debugging
1062with insure. A xterm with a gdb is popped up when insure catches
1063a error. It is Linux specific.
1064********************************************************************/
1065int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
1066{
1067 static int (*fn)();
1068 int ret;
1069 char *cmd;
1070
1071 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'",
1072 getpid(), getpid(), getpid());
1073
1074 if (!fn) {
1075 static void *h;
1076 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
1077 fn = dlsym(h, "_Insure_trap_error");
1078 }
1079
1080 ret = fn(a1, a2, a3, a4, a5, a6);
1081
1082 system(cmd);
1083
1084 free(cmd);
1085
1086 return ret;
1087}
1088#endif