fixed man page typo
[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
370 }
371
372
feaa89c4
AT
373/* sleep for a while via select */
374void u_sleep(int usec)
375{
376 struct timeval tv;
377
378 tv.tv_sec = 0;
379 tv.tv_usec = usec;
380 select(0, NULL, NULL, NULL, &tv);
381}
3ba62a83
AT
382
383
384static pid_t all_pids[10];
385static int num_pids;
386
387/* fork and record the pid of the child */
388pid_t do_fork(void)
389{
390 pid_t newpid = fork();
391
392 if (newpid) {
393 all_pids[num_pids++] = newpid;
394 }
395 return newpid;
396}
397
398/* kill all children */
399void kill_all(int sig)
400{
401 int i;
402 for (i=0;i<num_pids;i++) {
403 if (all_pids[i] != getpid())
404 kill(all_pids[i], sig);
405 }
406}
9486289c 407
8ef4ffd6
AT
408/* turn a user name into a uid */
409int name_to_uid(char *name, uid_t *uid)
410{
411 struct passwd *pass;
412 if (!name || !*name) return 0;
413 pass = getpwnam(name);
414 if (pass) {
415 *uid = pass->pw_uid;
416 return 1;
417 }
418 return 0;
419}
420
421/* turn a group name into a gid */
422int name_to_gid(char *name, gid_t *gid)
423{
424 struct group *grp;
425 if (!name || !*name) return 0;
426 grp = getgrnam(name);
427 if (grp) {
428 *gid = grp->gr_gid;
429 return 1;
430 }
431 return 0;
432}
433
ff8b29b8 434
31593dd6
AT
435/* lock a byte range in a open file */
436int lock_range(int fd, int offset, int len)
0c515f17 437{
31593dd6 438 struct flock lock;
0c515f17 439
31593dd6
AT
440 lock.l_type = F_WRLCK;
441 lock.l_whence = SEEK_SET;
442 lock.l_start = offset;
443 lock.l_len = len;
444 lock.l_pid = 0;
445
446 return fcntl(fd,F_SETLK,&lock) == 0;
0c515f17 447}
874895d5
AT
448
449
cb13abfe 450static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
874895d5 451{
932be9aa 452#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
e42c9458 453 if (!*s) s = ".";
087bf010 454 argv[*argc] = strdup(s);
874895d5
AT
455 (*argc)++;
456 return;
457#else
cb13abfe 458 extern int sanitize_paths;
874895d5
AT
459 glob_t globbuf;
460 int i;
461
e42c9458
AT
462 if (!*s) s = ".";
463
cb13abfe
DD
464 argv[*argc] = strdup(s);
465 if (sanitize_paths) {
466 sanitize_path(argv[*argc], NULL);
467 }
087bf010 468
874895d5
AT
469 memset(&globbuf, 0, sizeof(globbuf));
470 glob(argv[*argc], 0, NULL, &globbuf);
471 if (globbuf.gl_pathc == 0) {
472 (*argc)++;
473 globfree(&globbuf);
474 return;
475 }
476 for (i=0; i<(maxargs - (*argc)) && i<globbuf.gl_pathc;i++) {
477 if (i == 0) free(argv[*argc]);
478 argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
479 if (!argv[(*argc) + i]) out_of_memory("glob_expand");
480 }
481 globfree(&globbuf);
482 (*argc) += i;
483#endif
484}
5a96ee05 485
cb13abfe 486void glob_expand(char *base1, char **argv, int *argc, int maxargs)
087bf010
AT
487{
488 char *s = argv[*argc];
489 char *p, *q;
ba5e128d 490 char *base = base1;
087bf010
AT
491
492 if (!s || !*s) return;
493
e42c9458
AT
494 if (strncmp(s, base, strlen(base)) == 0) {
495 s += strlen(base);
496 }
497
087bf010
AT
498 s = strdup(s);
499 if (!s) out_of_memory("glob_expand");
500
ba5e128d
AT
501 base = (char *)malloc(strlen(base1)+3);
502 if (!base) out_of_memory("glob_expand");
503
504 sprintf(base," %s/", base1);
505
087bf010
AT
506 q = s;
507 while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
ba5e128d
AT
508 /* split it at this point */
509 *p = 0;
cb13abfe 510 glob_expand_one(q, argv, argc, maxargs);
ba5e128d 511 q = p+strlen(base);
087bf010
AT
512 }
513
cb13abfe 514 if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
087bf010
AT
515
516 free(s);
ba5e128d 517 free(base);
087bf010 518}
5a96ee05
AT
519
520/*******************************************************************
521 convert a string to lower case
522********************************************************************/
523void strlower(char *s)
524{
525 while (*s) {
526 if (isupper(*s)) *s = tolower(*s);
527 s++;
528 }
529}
e42c9458 530
37f9805d
AT
531/* this is like vsnprintf but it always null terminates, so you
532 can fit at most n-1 chars in */
e42c9458
AT
533int vslprintf(char *str, int n, const char *format, va_list ap)
534{
e42c9458 535 int ret = vsnprintf(str, n, format, ap);
37f9805d
AT
536 if (ret >= n || ret < 0) {
537 str[n-1] = 0;
e42c9458
AT
538 return -1;
539 }
540 str[ret] = 0;
541 return ret;
e42c9458
AT
542}
543
544
545/* like snprintf but always null terminates */
546int slprintf(char *str, int n, char *format, ...)
547{
548 va_list ap;
549 int ret;
550
551 va_start(ap, format);
552 ret = vslprintf(str,n,format,ap);
553 va_end(ap);
554 return ret;
555}
8d9dc9f9 556
fe8c0a98
AT
557
558void *Realloc(void *p, int size)
559{
560 if (!p) return (void *)malloc(size);
561 return (void *)realloc(p, size);
562}
5243c216
AT
563
564
565void clean_fname(char *name)
566{
567 char *p;
568 int l;
569 int modified = 1;
570
571 if (!name) return;
572
573 while (modified) {
574 modified = 0;
575
576 if ((p=strstr(name,"/./"))) {
577 modified = 1;
578 while (*p) {
579 p[0] = p[2];
580 p++;
581 }
582 }
583
584 if ((p=strstr(name,"//"))) {
585 modified = 1;
586 while (*p) {
587 p[0] = p[1];
588 p++;
589 }
590 }
591
592 if (strncmp(p=name,"./",2) == 0) {
593 modified = 1;
594 do {
595 p[0] = p[2];
596 } while (*p++);
597 }
598
599 l = strlen(p=name);
600 if (l > 1 && p[l-1] == '/') {
601 modified = 1;
602 p[l-1] = 0;
603 }
604 }
605}
606
1b8e662a
DD
607/*
608 * Make path appear as if a chroot had occurred:
1b8e662a 609 * 1. remove leading "/" (or replace with "." if at end)
cb13abfe 610 * 2. remove leading ".." components (except those allowed by "reldir")
1b8e662a 611 * 3. delete any other "<dir>/.." (recursively)
79452d46 612 * Can only shrink paths, so sanitizes in place.
b5f9e67d
DD
613 * While we're at it, remove double slashes and "." components like
614 * clean_fname does(), but DON'T remove a trailing slash because that
615 * is sometimes significant on command line arguments.
79452d46
DD
616 * If "reldir" is non-null, it is a sanitized directory that the path will be
617 * relative to, so allow as many ".." at the beginning of the path as
618 * there are components in reldir. This is used for symbolic link targets.
619 * If reldir is non-null and the path began with "/", to be completely like
620 * a chroot we should add in depth levels of ".." at the beginning of the
621 * path, but that would blow the assumption that the path doesn't grow and
622 * it is not likely to end up being a valid symlink anyway, so just do
623 * the normal removal of the leading "/" instead.
1b8e662a
DD
624 * Contributed by Dave Dykstra <dwd@bell-labs.com>
625 */
626
cb13abfe 627void sanitize_path(char *p, char *reldir)
1b8e662a 628{
44e2e578 629 char *start, *sanp;
cb13abfe
DD
630 int depth = 0;
631 int allowdotdot = 0;
632
633 if (reldir) {
634 depth++;
635 while (*reldir) {
636 if (*reldir++ == '/') {
637 depth++;
638 }
639 }
640 }
44e2e578
DD
641 start = p;
642 sanp = p;
b5f9e67d
DD
643 while (*p == '/') {
644 /* remove leading slashes */
645 p++;
646 }
1b8e662a 647 while (*p != '\0') {
b5f9e67d 648 /* this loop iterates once per filename component in p.
44e2e578 649 * both p (and sanp if the original had a slash) should
b5f9e67d
DD
650 * always be left pointing after a slash
651 */
652 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
653 /* skip "." component */
654 while (*++p == '/') {
655 /* skip following slashes */
656 ;
657 }
cb13abfe
DD
658 continue;
659 }
660 allowdotdot = 0;
661 if ((*p == '.') && (*(p+1) == '.') &&
1b8e662a 662 ((*(p+2) == '/') || (*(p+2) == '\0'))) {
cb13abfe
DD
663 /* ".." component followed by slash or end */
664 if ((depth > 0) && (sanp == start)) {
665 /* allow depth levels of .. at the beginning */
666 --depth;
667 allowdotdot = 1;
668 } else {
669 p += 2;
670 if (*p == '/')
671 p++;
672 if (sanp != start) {
673 /* back up sanp one level */
674 --sanp; /* now pointing at slash */
675 while ((sanp > start) && (*(sanp - 1) != '/')) {
676 /* skip back up to slash */
677 sanp--;
678 }
b5f9e67d 679 }
cb13abfe 680 continue;
1b8e662a 681 }
cb13abfe
DD
682 }
683 while (1) {
684 /* copy one component through next slash */
685 *sanp++ = *p++;
686 if ((*p == '\0') || (*(p-1) == '/')) {
687 while (*p == '/') {
688 /* skip multiple slashes */
689 p++;
b5f9e67d 690 }
cb13abfe 691 break;
1b8e662a
DD
692 }
693 }
cb13abfe
DD
694 if (allowdotdot) {
695 /* move the virtual beginning to leave the .. alone */
696 start = sanp;
697 }
1b8e662a 698 }
cb13abfe 699 if ((sanp == start) && !allowdotdot) {
b5f9e67d 700 /* ended up with nothing, so put in "." component */
79452d46
DD
701 /*
702 * note that the !allowdotdot doesn't prevent this from
703 * happening in all allowed ".." situations, but I didn't
704 * think it was worth putting in an extra variable to ensure
705 * it since an extra "." won't hurt in those situations.
706 */
44e2e578 707 *sanp++ = '.';
b5f9e67d 708 }
44e2e578 709 *sanp = '\0';
1b8e662a
DD
710}
711
5243c216
AT
712
713static char curr_dir[MAXPATHLEN];
714
715/* like chdir() but can be reversed with pop_dir() if save is set. It
716 is also much faster as it remembers where we have been */
717char *push_dir(char *dir, int save)
718{
719 char *ret = curr_dir;
720 static int initialised;
721
722 if (!initialised) {
723 initialised = 1;
724 getcwd(curr_dir, sizeof(curr_dir)-1);
725 }
726
c226b7c2
DD
727 if (!dir) return NULL; /* this call was probably just to initialize */
728
5243c216
AT
729 if (chdir(dir)) return NULL;
730
731 if (save) {
732 ret = strdup(curr_dir);
733 }
734
735 if (*dir == '/') {
37f9805d 736 strlcpy(curr_dir, dir, sizeof(curr_dir));
5243c216 737 } else {
37f9805d
AT
738 strlcat(curr_dir,"/", sizeof(curr_dir));
739 strlcat(curr_dir,dir, sizeof(curr_dir));
5243c216
AT
740 }
741
742 clean_fname(curr_dir);
743
744 return ret;
745}
746
747/* reverse a push_dir call */
748int pop_dir(char *dir)
749{
750 int ret;
751
752 ret = chdir(dir);
753 if (ret) {
754 free(dir);
755 return ret;
756 }
757
37f9805d 758 strlcpy(curr_dir, dir, sizeof(curr_dir));
5243c216
AT
759
760 free(dir);
761
762 return 0;
763}
aa9b77a5
AT
764
765/* we need to supply our own strcmp function for file list comparisons
766 to ensure that signed/unsigned usage is consistent between machines. */
767int u_strcmp(const char *cs1, const char *cs2)
768{
5a788ade
AT
769 const uchar *s1 = (const uchar *)cs1;
770 const uchar *s2 = (const uchar *)cs2;
aa9b77a5
AT
771
772 while (*s1 && *s2 && (*s1 == *s2)) {
773 s1++; s2++;
774 }
775
776 return (int)*s1 - (int)*s2;
777}
eb86d661 778
43b06eea 779static OFF_T last_ofs;
eb86d661
AT
780
781void end_progress(void)
782{
783 extern int do_progress, am_server;
784
785 if (do_progress && !am_server) {
786 rprintf(FINFO,"\n");
787 }
43b06eea 788 last_ofs = 0;
eb86d661
AT
789}
790
791void show_progress(OFF_T ofs, OFF_T size)
792{
793 extern int do_progress, am_server;
794
795 if (do_progress && !am_server) {
43b06eea
AT
796 if (ofs > last_ofs + 1000) {
797 int pct = (int)((100.0*ofs)/size);
eb86d661 798 rprintf(FINFO,"%.0f (%d%%)\r", (double)ofs, pct);
43b06eea 799 last_ofs = ofs;
eb86d661
AT
800 }
801 }
802}
4b957c22
AT
803
804/* determine if a symlink points outside the current directory tree */
805int unsafe_symlink(char *dest, char *src)
806{
807 char *tok;
808 int depth = 0;
809
810 /* all absolute and null symlinks are unsafe */
811 if (!dest || !(*dest) || (*dest == '/')) return 1;
812
813 src = strdup(src);
814 if (!src) out_of_memory("unsafe_symlink");
815
816 /* find out what our safety margin is */
817 for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
818 if (strcmp(tok,"..") == 0) {
819 depth=0;
820 } else if (strcmp(tok,".") == 0) {
821 /* nothing */
822 } else {
823 depth++;
824 }
825 }
826 free(src);
827
828 /* drop by one to account for the filename portion */
829 depth--;
830
831 dest = strdup(dest);
832 if (!dest) out_of_memory("unsafe_symlink");
833
834 for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
835 if (strcmp(tok,"..") == 0) {
836 depth--;
837 } else if (strcmp(tok,".") == 0) {
838 /* nothing */
839 } else {
840 depth++;
841 }
842 /* if at any point we go outside the current directory then
843 stop - it is unsafe */
844 if (depth < 0) break;
845 }
846
847 free(dest);
848 return (depth < 0);
849}
375a4556 850
f7632fc6
AT
851
852/****************************************************************************
853 return the date and time as a string
854****************************************************************************/
855char *timestring(time_t t)
856{
857 static char TimeBuf[200];
858 struct tm *tm = localtime(&t);
859
860#ifdef HAVE_STRFTIME
861 strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
862#else
37f9805d 863 strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
f7632fc6
AT
864#endif
865
866 if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
867 TimeBuf[strlen(TimeBuf)-1] = 0;
868 }
869
870 return(TimeBuf);
871}
872