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