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