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