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