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