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