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