went back to non-blokcing IO
[rsync/rsync.git] / util.c
... / ...
CommitLineData
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
27extern int verbose;
28
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 */
54int fd_pair(int fd[2])
55{
56 int ret;
57
58#if HAVE_SOCKETPAIR
59 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
60#else
61 ret = pipe(fd);
62#endif
63
64 if (ret == 0) {
65 set_nonblocking(fd[0]);
66 set_nonblocking(fd[1]);
67 }
68
69 return ret;
70}
71
72
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
80 if (fd_pair(to_child_pipe) < 0 ||
81 fd_pair(from_child_pipe) < 0) {
82 rprintf(FERROR,"pipe: %s\n",strerror(errno));
83 exit_cleanup(RERR_IPC);
84 }
85
86
87 pid = do_fork();
88 if (pid < 0) {
89 rprintf(FERROR,"fork: %s\n",strerror(errno));
90 exit_cleanup(RERR_IPC);
91 }
92
93 if (pid == 0)
94 {
95 extern int orig_umask;
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) {
100 rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
101 exit_cleanup(RERR_IPC);
102 }
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]);
105 umask(orig_umask);
106 execvp(command[0], command);
107 rprintf(FERROR,"Failed to exec %s : %s\n",
108 command[0],strerror(errno));
109 exit_cleanup(RERR_IPC);
110 }
111
112 if (close(from_child_pipe[1]) < 0 ||
113 close(to_child_pipe[0]) < 0) {
114 rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
115 exit_cleanup(RERR_IPC);
116 }
117
118 *f_in = from_child_pipe[0];
119 *f_out = to_child_pipe[1];
120
121 return pid;
122}
123
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
130 if (fd_pair(to_child_pipe) < 0 ||
131 fd_pair(from_child_pipe) < 0) {
132 rprintf(FERROR,"pipe: %s\n",strerror(errno));
133 exit_cleanup(RERR_IPC);
134 }
135
136
137 pid = do_fork();
138 if (pid < 0) {
139 rprintf(FERROR,"fork: %s\n",strerror(errno));
140 exit_cleanup(RERR_IPC);
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) {
154 rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
155 exit_cleanup(RERR_IPC);
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]);
159 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
160 }
161
162 if (close(from_child_pipe[1]) < 0 ||
163 close(to_child_pipe[0]) < 0) {
164 rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
165 exit_cleanup(RERR_IPC);
166 }
167
168 *f_in = from_child_pipe[0];
169 *f_out = to_child_pipe[1];
170
171 return pid;
172}
173
174
175
176void out_of_memory(char *str)
177{
178 rprintf(FERROR,"ERROR: out of memory in %s\n",str);
179 exit_cleanup(RERR_MALLOC);
180}
181
182void overflow(char *str)
183{
184 rprintf(FERROR,"ERROR: buffer overflow in %s\n",str);
185 exit_cleanup(RERR_MALLOC);
186}
187
188
189
190int set_modtime(char *fname,time_t modtime)
191{
192 extern int dry_run;
193 if (dry_run) return 0;
194 {
195#ifdef HAVE_UTIMBUF
196 struct utimbuf tbuf;
197 tbuf.actime = time(NULL);
198 tbuf.modtime = modtime;
199 return utime(fname,&tbuf);
200#elif defined(HAVE_UTIME)
201 time_t t[2];
202 t[0] = time(NULL);
203 t[1] = modtime;
204 return utime(fname,t);
205#else
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);
212#endif
213 }
214}
215
216
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;
233 do_mkdir(fname,0777 & ~orig_umask);
234 *p = '/';
235 p++;
236 }
237 return 0;
238}
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*/
246static int full_write(int desc, char *ptr, int len)
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. */
272static int safe_read(int desc, char *ptr, int len)
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
299 ifd = do_open(source, O_RDONLY, 0);
300 if (ifd == -1) {
301 rprintf(FERROR,"open %s: %s\n",
302 source,strerror(errno));
303 return -1;
304 }
305
306 if (robust_unlink(dest) && errno != ENOENT) {
307 rprintf(FERROR,"unlink %s: %s\n",
308 dest,strerror(errno));
309 return -1;
310 }
311
312 ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
313 if (ofd == -1) {
314 rprintf(FERROR,"open %s: %s\n",
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) {
322 rprintf(FERROR,"write %s: %s\n",
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) {
334 rprintf(FERROR,"read %s: %s\n",
335 source,strerror(errno));
336 return -1;
337 }
338
339 return 0;
340}
341
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
414}
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}
440
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
467
468/* lock a byte range in a open file */
469int lock_range(int fd, int offset, int len)
470{
471 struct flock lock;
472
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;
480}
481
482
483static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
484{
485#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
486 if (!*s) s = ".";
487 argv[*argc] = strdup(s);
488 (*argc)++;
489 return;
490#else
491 extern int sanitize_paths;
492 glob_t globbuf;
493 int i;
494
495 if (!*s) s = ".";
496
497 argv[*argc] = strdup(s);
498 if (sanitize_paths) {
499 sanitize_path(argv[*argc], NULL);
500 }
501
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}
518
519void glob_expand(char *base1, char **argv, int *argc, int maxargs)
520{
521 char *s = argv[*argc];
522 char *p, *q;
523 char *base = base1;
524
525 if (!s || !*s) return;
526
527 if (strncmp(s, base, strlen(base)) == 0) {
528 s += strlen(base);
529 }
530
531 s = strdup(s);
532 if (!s) out_of_memory("glob_expand");
533
534 base = (char *)malloc(strlen(base1)+3);
535 if (!base) out_of_memory("glob_expand");
536
537 sprintf(base," %s/", base1);
538
539 q = s;
540 while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
541 /* split it at this point */
542 *p = 0;
543 glob_expand_one(q, argv, argc, maxargs);
544 q = p+strlen(base);
545 }
546
547 if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
548
549 free(s);
550 free(base);
551}
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}
563
564/* this is like vsnprintf but it always null terminates, so you
565 can fit at most n-1 chars in */
566int vslprintf(char *str, int n, const char *format, va_list ap)
567{
568 int ret = vsnprintf(str, n, format, ap);
569 if (ret >= n || ret < 0) {
570 str[n-1] = 0;
571 return -1;
572 }
573 str[ret] = 0;
574 return ret;
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}
589
590
591void *Realloc(void *p, int size)
592{
593 if (!p) return (void *)malloc(size);
594 return (void *)realloc(p, size);
595}
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
640/*
641 * Make path appear as if a chroot had occurred:
642 * 1. remove leading "/" (or replace with "." if at end)
643 * 2. remove leading ".." components (except those allowed by "reldir")
644 * 3. delete any other "<dir>/.." (recursively)
645 * Can only shrink paths, so sanitizes in place.
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.
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.
657 * Contributed by Dave Dykstra <dwd@bell-labs.com>
658 */
659
660void sanitize_path(char *p, char *reldir)
661{
662 char *start, *sanp;
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 }
674 start = p;
675 sanp = p;
676 while (*p == '/') {
677 /* remove leading slashes */
678 p++;
679 }
680 while (*p != '\0') {
681 /* this loop iterates once per filename component in p.
682 * both p (and sanp if the original had a slash) should
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 }
691 continue;
692 }
693 allowdotdot = 0;
694 if ((*p == '.') && (*(p+1) == '.') &&
695 ((*(p+2) == '/') || (*(p+2) == '\0'))) {
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 }
712 }
713 continue;
714 }
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++;
723 }
724 break;
725 }
726 }
727 if (allowdotdot) {
728 /* move the virtual beginning to leave the .. alone */
729 start = sanp;
730 }
731 }
732 if ((sanp == start) && !allowdotdot) {
733 /* ended up with nothing, so put in "." component */
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 */
740 *sanp++ = '.';
741 }
742 *sanp = '\0';
743}
744
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
760 if (!dir) return NULL; /* this call was probably just to initialize */
761
762 if (chdir(dir)) return NULL;
763
764 if (save) {
765 ret = strdup(curr_dir);
766 }
767
768 if (*dir == '/') {
769 strlcpy(curr_dir, dir, sizeof(curr_dir));
770 } else {
771 strlcat(curr_dir,"/", sizeof(curr_dir));
772 strlcat(curr_dir,dir, sizeof(curr_dir));
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
791 strlcpy(curr_dir, dir, sizeof(curr_dir));
792
793 free(dir);
794
795 return 0;
796}
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{
802 const uchar *s1 = (const uchar *)cs1;
803 const uchar *s2 = (const uchar *)cs2;
804
805 while (*s1 && *s2 && (*s1 == *s2)) {
806 s1++; s2++;
807 }
808
809 return (int)*s1 - (int)*s2;
810}
811
812static OFF_T last_ofs;
813
814void end_progress(OFF_T size)
815{
816 extern int do_progress, am_server;
817
818 if (do_progress && !am_server) {
819 rprintf(FINFO,"%.0f (100%%)\n", (double)size);
820 }
821 last_ofs = 0;
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) {
829 if (ofs > last_ofs + 1000) {
830 int pct = (int)((100.0*ofs)/size);
831 rprintf(FINFO,"%.0f (%d%%)\r", (double)ofs, pct);
832 last_ofs = ofs;
833 }
834 }
835}
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}
883
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
896 strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
897#endif
898
899 if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
900 TimeBuf[strlen(TimeBuf)-1] = 0;
901 }
902
903 return(TimeBuf);
904}
905
906
907/****************************************************************************
908 like waitpid but does the WEXITSTATUS
909****************************************************************************/
910#ifndef WEXITSTATUS
911#define WEXITSTATUS(stat) ((int)(((stat)>>8)&0xFF))
912#endif
913void wait_process(pid_t pid, int *status)
914{
915 waitpid(pid, status, 0);
916 *status = WEXITSTATUS(*status);
917}