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