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