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