Patch from Paul Haas:
[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 != 0  &&  newpid != -1) {
487                 all_pids[num_pids++] = newpid;
488         }
489         return newpid;
490 }
491
492 /**
493  * Kill all children.
494  *
495  * @todo It would be kind of nice to make sure that they are actually
496  * all our children before we kill them, because their pids may have
497  * been recycled by some other process.  Perhaps when we wait for a
498  * child, we should remove it from this array.  Alternatively we could
499  * perhaps use process groups, but I think that would not work on
500  * ancient Unix versions that don't support them.
501  **/
502 void kill_all(int sig)
503 {
504         int i;
505
506         for (i = 0; i < num_pids; i++) {
507                 /* Let's just be a little careful where we
508                  * point that gun, hey?  See kill(2) for the
509                  * magic caused by negative values. */
510                 pid_t p = all_pids[i];
511
512                 if (p == getpid())
513                         continue;
514                 if (p <= 0)
515                         continue;
516
517                 kill(p, sig);
518         }
519 }
520
521
522 /* turn a user name into a uid */
523 int name_to_uid(char *name, uid_t *uid)
524 {
525         struct passwd *pass;
526         if (!name || !*name) return 0;
527         pass = getpwnam(name);
528         if (pass) {
529                 *uid = pass->pw_uid;
530                 return 1;
531         }
532         return 0;
533 }
534
535 /* turn a group name into a gid */
536 int name_to_gid(char *name, gid_t *gid)
537 {
538         struct group *grp;
539         if (!name || !*name) return 0;
540         grp = getgrnam(name);
541         if (grp) {
542                 *gid = grp->gr_gid;
543                 return 1;
544         }
545         return 0;
546 }
547
548
549 /* lock a byte range in a open file */
550 int lock_range(int fd, int offset, int len)
551 {
552         struct flock lock;
553
554         lock.l_type = F_WRLCK;
555         lock.l_whence = SEEK_SET;
556         lock.l_start = offset;
557         lock.l_len = len;
558         lock.l_pid = 0;
559         
560         return fcntl(fd,F_SETLK,&lock) == 0;
561 }
562
563
564 static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
565 {
566 #if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
567         if (!*s) s = ".";
568         argv[*argc] = strdup(s);
569         (*argc)++;
570         return;
571 #else
572         extern int sanitize_paths;
573         glob_t globbuf;
574         int i;
575
576         if (!*s) s = ".";
577
578         argv[*argc] = strdup(s);
579         if (sanitize_paths) {
580                 sanitize_path(argv[*argc], NULL);
581         }
582
583         memset(&globbuf, 0, sizeof(globbuf));
584         glob(argv[*argc], 0, NULL, &globbuf);
585         if (globbuf.gl_pathc == 0) {
586                 (*argc)++;
587                 globfree(&globbuf);
588                 return;
589         }
590         for (i=0; i<(maxargs - (*argc)) && i < (int) globbuf.gl_pathc;i++) {
591                 if (i == 0) free(argv[*argc]);
592                 argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
593                 if (!argv[(*argc) + i]) out_of_memory("glob_expand");
594         }
595         globfree(&globbuf);
596         (*argc) += i;
597 #endif
598 }
599
600 void glob_expand(char *base1, char **argv, int *argc, int maxargs)
601 {
602         char *s = argv[*argc];
603         char *p, *q;
604         char *base = base1;
605
606         if (!s || !*s) return;
607
608         if (strncmp(s, base, strlen(base)) == 0) {
609                 s += strlen(base);
610         }
611
612         s = strdup(s);
613         if (!s) out_of_memory("glob_expand");
614
615         if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
616
617         q = s;
618         while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
619                 /* split it at this point */
620                 *p = 0;
621                 glob_expand_one(q, argv, argc, maxargs);
622                 q = p+strlen(base);
623         }
624
625         if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
626
627         free(s);
628         free(base);
629 }
630
631 /*******************************************************************
632   convert a string to lower case
633 ********************************************************************/
634 void strlower(char *s)
635 {
636         while (*s) {
637                 if (isupper(*s)) *s = tolower(*s);
638                 s++;
639         }
640 }
641
642 void *Realloc(void *p, int size)
643 {
644         if (!p) return (void *)malloc(size);
645         return (void *)realloc(p, size);
646 }
647
648
649 void clean_fname(char *name)
650 {
651         char *p;
652         int l;
653         int modified = 1;
654
655         if (!name) return;
656
657         while (modified) {
658                 modified = 0;
659
660                 if ((p=strstr(name,"/./"))) {
661                         modified = 1;
662                         while (*p) {
663                                 p[0] = p[2];
664                                 p++;
665                         }
666                 }
667
668                 if ((p=strstr(name,"//"))) {
669                         modified = 1;
670                         while (*p) {
671                                 p[0] = p[1];
672                                 p++;
673                         }
674                 }
675
676                 if (strncmp(p=name,"./",2) == 0) {      
677                         modified = 1;
678                         do {
679                                 p[0] = p[2];
680                         } while (*p++);
681                 }
682
683                 l = strlen(p=name);
684                 if (l > 1 && p[l-1] == '/') {
685                         modified = 1;
686                         p[l-1] = 0;
687                 }
688         }
689 }
690
691 /*
692  * Make path appear as if a chroot had occurred:
693  *    1. remove leading "/" (or replace with "." if at end)
694  *    2. remove leading ".." components (except those allowed by "reldir")
695  *    3. delete any other "<dir>/.." (recursively)
696  * Can only shrink paths, so sanitizes in place.
697  * While we're at it, remove double slashes and "." components like
698  *   clean_fname does(), but DON'T remove a trailing slash because that
699  *   is sometimes significant on command line arguments.
700  * If "reldir" is non-null, it is a sanitized directory that the path will be
701  *    relative to, so allow as many ".." at the beginning of the path as
702  *    there are components in reldir.  This is used for symbolic link targets.
703  *    If reldir is non-null and the path began with "/", to be completely like
704  *    a chroot we should add in depth levels of ".." at the beginning of the
705  *    path, but that would blow the assumption that the path doesn't grow and
706  *    it is not likely to end up being a valid symlink anyway, so just do
707  *    the normal removal of the leading "/" instead.
708  * Contributed by Dave Dykstra <dwd@bell-labs.com>
709  */
710
711 void sanitize_path(char *p, char *reldir)
712 {
713         char *start, *sanp;
714         int depth = 0;
715         int allowdotdot = 0;
716
717         if (reldir) {
718                 depth++;
719                 while (*reldir) {
720                         if (*reldir++ == '/') {
721                                 depth++;
722                         }
723                 }
724         }
725         start = p;
726         sanp = p;
727         while (*p == '/') {
728                 /* remove leading slashes */
729                 p++;
730         }
731         while (*p != '\0') {
732                 /* this loop iterates once per filename component in p.
733                  * both p (and sanp if the original had a slash) should
734                  * always be left pointing after a slash
735                  */
736                 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
737                         /* skip "." component */
738                         while (*++p == '/') {
739                                 /* skip following slashes */
740                                 ;
741                         }
742                         continue;
743                 }
744                 allowdotdot = 0;
745                 if ((*p == '.') && (*(p+1) == '.') &&
746                             ((*(p+2) == '/') || (*(p+2) == '\0'))) {
747                         /* ".." component followed by slash or end */
748                         if ((depth > 0) && (sanp == start)) {
749                                 /* allow depth levels of .. at the beginning */
750                                 --depth;
751                                 allowdotdot = 1;
752                         } else {
753                                 p += 2;
754                                 if (*p == '/')
755                                         p++;
756                                 if (sanp != start) {
757                                         /* back up sanp one level */
758                                         --sanp; /* now pointing at slash */
759                                         while ((sanp > start) && (*(sanp - 1) != '/')) {
760                                                 /* skip back up to slash */
761                                                 sanp--;
762                                         }
763                                 }
764                                 continue;
765                         }
766                 }
767                 while (1) {
768                         /* copy one component through next slash */
769                         *sanp++ = *p++;
770                         if ((*p == '\0') || (*(p-1) == '/')) {
771                                 while (*p == '/') {
772                                         /* skip multiple slashes */
773                                         p++;
774                                 }
775                                 break;
776                         }
777                 }
778                 if (allowdotdot) {
779                         /* move the virtual beginning to leave the .. alone */
780                         start = sanp;
781                 }
782         }
783         if ((sanp == start) && !allowdotdot) {
784                 /* ended up with nothing, so put in "." component */
785                 /*
786                  * note that the !allowdotdot doesn't prevent this from
787                  *  happening in all allowed ".." situations, but I didn't
788                  *  think it was worth putting in an extra variable to ensure
789                  *  it since an extra "." won't hurt in those situations.
790                  */
791                 *sanp++ = '.';
792         }
793         *sanp = '\0';
794 }
795
796
797 static char curr_dir[MAXPATHLEN];
798
799 /* like chdir() but can be reversed with pop_dir() if save is set. It
800    is also much faster as it remembers where we have been */
801 char *push_dir(char *dir, int save)
802 {
803         char *ret = curr_dir;
804         static int initialised;
805
806         if (!initialised) {
807                 initialised = 1;
808                 getcwd(curr_dir, sizeof(curr_dir)-1);
809         }
810
811         if (!dir) return NULL; /* this call was probably just to initialize */
812
813         if (chdir(dir)) return NULL;
814
815         if (save) {
816                 ret = strdup(curr_dir);
817         }
818
819         if (*dir == '/') {
820                 strlcpy(curr_dir, dir, sizeof(curr_dir));
821         } else {
822                 strlcat(curr_dir,"/", sizeof(curr_dir));
823                 strlcat(curr_dir,dir, sizeof(curr_dir));
824         }
825
826         clean_fname(curr_dir);
827
828         return ret;
829 }
830
831 /* reverse a push_dir call */
832 int pop_dir(char *dir)
833 {
834         int ret;
835
836         ret = chdir(dir);
837         if (ret) {
838                 free(dir);
839                 return ret;
840         }
841
842         strlcpy(curr_dir, dir, sizeof(curr_dir));
843
844         free(dir);
845
846         return 0;
847 }
848
849 /* we need to supply our own strcmp function for file list comparisons
850    to ensure that signed/unsigned usage is consistent between machines. */
851 int u_strcmp(const char *cs1, const char *cs2)
852 {
853         const uchar *s1 = (const uchar *)cs1;
854         const uchar *s2 = (const uchar *)cs2;
855
856         while (*s1 && *s2 && (*s1 == *s2)) {
857                 s1++; s2++;
858         }
859         
860         return (int)*s1 - (int)*s2;
861 }
862
863 static OFF_T  last_ofs;
864 static struct timeval print_time;
865 static struct timeval start_time;
866 static OFF_T  start_ofs;
867
868 static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
869 {
870     return (t2->tv_sec - t1->tv_sec) * 1000
871         + (t2->tv_usec - t1->tv_usec) / 1000;
872 }
873
874
875 /**
876  * @param ofs Current position in file
877  * @param size Total size of file
878  * @param is_last True if this is the last time progress will be
879  * printed for this file, so we should output a newline.  (Not
880  * necessarily the same as all bytes being received.)
881  **/
882 static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
883                             int is_last)
884 {
885     int           pct  = (ofs == size) ? 100 : (int)((100.0*ofs)/size);
886     unsigned long diff = msdiff(&start_time, now);
887     double        rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0;
888     const char    *units;
889     /* If we've finished transferring this file, show the time taken;
890      * otherwise show expected time to complete.  That's kind of
891      * inconsistent, but people can probably cope.  Hopefully we'll
892      * get more consistent and complete progress reporting soon. --
893      * mbp */
894     double        remain = is_last
895                         ? (double) diff / 1000.0
896                         : rate ? (double) (size-ofs) / rate / 1000.0 : 0.0;
897     int           remain_h, remain_m, remain_s;
898
899     if (rate > 1024*1024) {
900             rate /= 1024.0 * 1024.0;
901             units = "GB/s";
902     } else if (rate > 1024) {
903             rate /= 1024.0;
904             units = "MB/s";
905     } else {
906             units = "kB/s";
907     }
908
909     remain_s = (int) remain % 60;
910     remain_m = (int) (remain / 60.0) % 60;
911     remain_h = (int) (remain / 3600.0);
912     
913     rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
914             (double) ofs, pct, rate, units,
915             remain_h, remain_m, remain_s,
916             is_last ? "\n" : "\r");
917 }
918
919 void end_progress(OFF_T size)
920 {
921         extern int do_progress, am_server;
922
923         if (do_progress && !am_server) {
924                 struct timeval now;
925                 gettimeofday(&now, NULL);
926                 rprint_progress(size, size, &now, True);
927         }
928         last_ofs   = 0;
929         start_ofs  = 0;
930         print_time.tv_sec  = print_time.tv_usec  = 0;
931         start_time.tv_sec  = start_time.tv_usec  = 0;
932 }
933
934 void show_progress(OFF_T ofs, OFF_T size)
935 {
936         extern int do_progress, am_server;
937         struct timeval now;
938
939         gettimeofday(&now, NULL);
940
941         if (!start_time.tv_sec && !start_time.tv_usec) {
942                 start_time.tv_sec  = now.tv_sec;
943                 start_time.tv_usec = now.tv_usec;
944                 start_ofs          = ofs;
945         }
946
947         if (do_progress
948             && !am_server
949             && ofs > last_ofs + 1000
950             && msdiff(&print_time, &now) > 250) {
951                 rprint_progress(ofs, size, &now, False);
952                 last_ofs = ofs;
953                 print_time.tv_sec  = now.tv_sec;
954                 print_time.tv_usec = now.tv_usec;
955         }
956 }
957
958 /* determine if a symlink points outside the current directory tree */
959 int unsafe_symlink(char *dest, char *src)
960 {
961         char *tok;
962         int depth = 0;
963
964         /* all absolute and null symlinks are unsafe */
965         if (!dest || !(*dest) || (*dest == '/')) return 1;
966
967         src = strdup(src);
968         if (!src) out_of_memory("unsafe_symlink");
969
970         /* find out what our safety margin is */
971         for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
972                 if (strcmp(tok,"..") == 0) {
973                         depth=0;
974                 } else if (strcmp(tok,".") == 0) {
975                         /* nothing */
976                 } else {
977                         depth++;
978                 }
979         }
980         free(src);
981
982         /* drop by one to account for the filename portion */
983         depth--;
984
985         dest = strdup(dest);
986         if (!dest) out_of_memory("unsafe_symlink");
987
988         for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
989                 if (strcmp(tok,"..") == 0) {
990                         depth--;
991                 } else if (strcmp(tok,".") == 0) {
992                         /* nothing */
993                 } else {
994                         depth++;
995                 }
996                 /* if at any point we go outside the current directory then
997                    stop - it is unsafe */
998                 if (depth < 0) break;
999         }
1000
1001         free(dest);
1002         return (depth < 0);
1003 }
1004
1005
1006 /****************************************************************************
1007   return the date and time as a string
1008 ****************************************************************************/
1009 char *timestring(time_t t)
1010 {
1011         static char TimeBuf[200];
1012         struct tm *tm = localtime(&t);
1013
1014 #ifdef HAVE_STRFTIME
1015         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
1016 #else
1017         strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
1018 #endif
1019
1020         if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
1021                 TimeBuf[strlen(TimeBuf)-1] = 0;
1022         }
1023
1024         return(TimeBuf);
1025 }
1026
1027
1028 /**
1029  * Sleep for a specified number of milliseconds.
1030  *
1031  * Always returns TRUE.  (In the future it might return FALSE if
1032  * interrupted.)
1033  **/
1034 int msleep(int t)
1035 {
1036         int tdiff=0;
1037         struct timeval tval,t1,t2;  
1038
1039         gettimeofday(&t1, NULL);
1040         gettimeofday(&t2, NULL);
1041   
1042         while (tdiff < t) {
1043                 tval.tv_sec = (t-tdiff)/1000;
1044                 tval.tv_usec = 1000*((t-tdiff)%1000);
1045  
1046                 errno = 0;
1047                 select(0,NULL,NULL, NULL, &tval);
1048
1049                 gettimeofday(&t2, NULL);
1050                 tdiff = (t2.tv_sec - t1.tv_sec)*1000 + 
1051                         (t2.tv_usec - t1.tv_usec)/1000;
1052         }
1053
1054         return True;
1055 }
1056
1057
1058 /*******************************************************************
1059  Determine if two file modification times are equivalent (either exact 
1060  or in the modification timestamp window established by --modify-window) 
1061  Returns 0 if the times should be treated as the same, 1 if the 
1062  first is later and -1 if the 2nd is later
1063  *******************************************************************/
1064 int cmp_modtime(time_t file1, time_t file2)
1065 {
1066         extern int modify_window;
1067
1068         if (file2 > file1) {
1069                 if (file2 - file1 <= modify_window) return 0;
1070                 return -1;
1071         }
1072         if (file1 - file2 <= modify_window) return 0;
1073         return 1;
1074 }
1075
1076
1077 #ifdef __INSURE__XX
1078 #include <dlfcn.h>
1079
1080 /*******************************************************************
1081 This routine is a trick to immediately catch errors when debugging
1082 with insure. A xterm with a gdb is popped up when insure catches
1083 a error. It is Linux specific.
1084 ********************************************************************/
1085 int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
1086 {
1087         static int (*fn)();
1088         int ret;
1089         char *cmd;
1090
1091         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'", 
1092                 getpid(), getpid(), getpid());
1093
1094         if (!fn) {
1095                 static void *h;
1096                 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
1097                 fn = dlsym(h, "_Insure_trap_error");
1098         }
1099
1100         ret = fn(a1, a2, a3, a4, a5, a6);
1101
1102         system(cmd);
1103
1104         free(cmd);
1105
1106         return ret;
1107 }
1108 #endif