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