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