Revert change from 1.39, because it causes a crash because of
[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
816 void end_progress(OFF_T size)
817 {
818         extern int do_progress, am_server;
819
820         if (do_progress && !am_server) {
821                 rprintf(FINFO,"%.0f (100%%)\n", (double)size);
822         }
823         last_ofs = 0;
824 }
825
826 void show_progress(OFF_T ofs, OFF_T size)
827 {
828         extern int do_progress, am_server;
829
830         if (do_progress && !am_server) {
831                 if (ofs > last_ofs + 1000) {
832                         int pct = (int)((100.0*ofs)/size);
833                         rprintf(FINFO,"%.0f (%d%%)\r", (double)ofs, pct);
834                         last_ofs = ofs;
835                 }
836         }
837 }
838
839 /* determine if a symlink points outside the current directory tree */
840 int unsafe_symlink(char *dest, char *src)
841 {
842         char *tok;
843         int depth = 0;
844
845         /* all absolute and null symlinks are unsafe */
846         if (!dest || !(*dest) || (*dest == '/')) return 1;
847
848         src = strdup(src);
849         if (!src) out_of_memory("unsafe_symlink");
850
851         /* find out what our safety margin is */
852         for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
853                 if (strcmp(tok,"..") == 0) {
854                         depth=0;
855                 } else if (strcmp(tok,".") == 0) {
856                         /* nothing */
857                 } else {
858                         depth++;
859                 }
860         }
861         free(src);
862
863         /* drop by one to account for the filename portion */
864         depth--;
865
866         dest = strdup(dest);
867         if (!dest) out_of_memory("unsafe_symlink");
868
869         for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
870                 if (strcmp(tok,"..") == 0) {
871                         depth--;
872                 } else if (strcmp(tok,".") == 0) {
873                         /* nothing */
874                 } else {
875                         depth++;
876                 }
877                 /* if at any point we go outside the current directory then
878                    stop - it is unsafe */
879                 if (depth < 0) break;
880         }
881
882         free(dest);
883         return (depth < 0);
884 }
885
886
887 /****************************************************************************
888   return the date and time as a string
889 ****************************************************************************/
890 char *timestring(time_t t)
891 {
892         static char TimeBuf[200];
893         struct tm *tm = localtime(&t);
894
895 #ifdef HAVE_STRFTIME
896         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
897 #else
898         strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
899 #endif
900
901         if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
902                 TimeBuf[strlen(TimeBuf)-1] = 0;
903         }
904
905         return(TimeBuf);
906 }
907
908
909 /**
910  * Sleep for a specified number of milliseconds.
911  *
912  * Always returns TRUE.  (In the future it might return FALSE if
913  * interrupted.)
914  **/
915 int msleep(int t)
916 {
917         int tdiff=0;
918         struct timeval tval,t1,t2;  
919
920         gettimeofday(&t1, NULL);
921         gettimeofday(&t2, NULL);
922   
923         while (tdiff < t) {
924                 tval.tv_sec = (t-tdiff)/1000;
925                 tval.tv_usec = 1000*((t-tdiff)%1000);
926  
927                 errno = 0;
928                 select(0,NULL,NULL, NULL, &tval);
929
930                 gettimeofday(&t2, NULL);
931                 tdiff = (t2.tv_sec - t1.tv_sec)*1000 + 
932                         (t2.tv_usec - t1.tv_usec)/1000;
933         }
934
935         return True;
936 }
937
938
939 /*******************************************************************
940  Determine if two file modification times are equivalent (either exact 
941  or in the modification timestamp window established by --modify-window) 
942  Returns 0 if the times should be treated as the same, 1 if the 
943  first is later and -1 if the 2nd is later
944  *******************************************************************/
945 int cmp_modtime(time_t file1, time_t file2)
946 {
947         extern int modify_window;
948
949         if (file2 > file1) {
950                 if (file2 - file1 <= modify_window) return 0;
951                 return -1;
952         }
953         if (file1 - file2 <= modify_window) return 0;
954         return 1;
955 }
956
957
958 #ifdef __INSURE__XX
959 #include <dlfcn.h>
960
961 /*******************************************************************
962 This routine is a trick to immediately catch errors when debugging
963 with insure. A xterm with a gdb is popped up when insure catches
964 a error. It is Linux specific.
965 ********************************************************************/
966 int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
967 {
968         static int (*fn)();
969         int ret;
970         char *cmd;
971
972         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'", 
973                 getpid(), getpid(), getpid());
974
975         if (!fn) {
976                 static void *h;
977                 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
978                 fn = dlsym(h, "_Insure_trap_error");
979         }
980
981         ret = fn(a1, a2, a3, a4, a5, a6);
982
983         system(cmd);
984
985         free(cmd);
986
987         return ret;
988 }
989 #endif