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