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