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