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