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