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