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