No need to conditionally-compile EINTR code -- no other files do this.
[rsync/rsync.git] / util.c
1 /*  -*- c-file-style: "linux" -*-
2  * 
3  * Copyright (C) 1996-2000 by Andrew Tridgell 
4  * Copyright (C) Paul Mackerras 1996
5  * Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
6  * 
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  * 
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 /**
23  * @file
24  *
25  * Utilities used in rsync 
26  **/
27
28 #include "rsync.h"
29
30 extern int verbose;
31
32 int sanitize_paths = 0;
33
34
35
36 /**
37  * Set a fd into nonblocking mode
38  **/
39 void set_nonblocking(int fd)
40 {
41         int val;
42
43         if ((val = fcntl(fd, F_GETFL, 0)) == -1)
44                 return;
45         if (!(val & NONBLOCK_FLAG)) {
46                 val |= NONBLOCK_FLAG;
47                 fcntl(fd, F_SETFL, val);
48         }
49 }
50
51 /**
52  * Set a fd into blocking mode
53  **/
54 void set_blocking(int fd)
55 {
56         int val;
57
58         if ((val = fcntl(fd, F_GETFL, 0)) == -1)
59                 return;
60         if (val & NONBLOCK_FLAG) {
61                 val &= ~NONBLOCK_FLAG;
62                 fcntl(fd, F_SETFL, val);
63         }
64 }
65
66
67 /**
68  * Create a file descriptor pair - like pipe() but use socketpair if
69  * possible (because of blocking issues on pipes).
70  * 
71  * Always set non-blocking.
72  */
73 int fd_pair(int fd[2])
74 {
75         int ret;
76
77 #if HAVE_SOCKETPAIR
78         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
79 #else
80         ret = pipe(fd);
81 #endif
82
83         if (ret == 0) {
84                 set_nonblocking(fd[0]);
85                 set_nonblocking(fd[1]);
86         }
87
88         return ret;
89 }
90
91
92 void print_child_argv(char **cmd)
93 {
94         rprintf(FINFO, "opening connection using ");
95         for (; *cmd; cmd++) {
96                 /* Look for characters that ought to be quoted.  This
97                 * is not a great quoting algorithm, but it's
98                 * sufficient for a log message. */
99                 if (strspn(*cmd, "abcdefghijklmnopqrstuvwxyz"
100                            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
101                            "0123456789"
102                            ",.-_=+@/") != strlen(*cmd)) {
103                         rprintf(FINFO, "\"%s\" ", *cmd);
104                 } else {
105                         rprintf(FINFO, "%s ", *cmd);
106                 }
107         }
108         rprintf(FINFO, "\n");
109 }
110
111
112 void out_of_memory(char *str)
113 {
114   rprintf(FERROR,"ERROR: out of memory in %s\n",str);
115   exit_cleanup(RERR_MALLOC);
116 }
117
118 void overflow(char *str)
119 {
120   rprintf(FERROR,"ERROR: buffer overflow in %s\n",str);
121   exit_cleanup(RERR_MALLOC);
122 }
123
124
125
126 int set_modtime(char *fname, time_t modtime)
127 {
128         extern int dry_run;
129         if (dry_run)
130                 return 0;
131
132         if (verbose > 2) {
133                 rprintf(FINFO, "set modtime of %s to (%ld) %s",
134                         fname, (long) modtime,
135                         asctime(localtime(&modtime)));
136         }
137         
138         {
139 #ifdef HAVE_UTIMBUF
140                 struct utimbuf tbuf;  
141                 tbuf.actime = time(NULL);
142                 tbuf.modtime = modtime;
143                 return utime(fname,&tbuf);
144 #elif defined(HAVE_UTIME)
145                 time_t t[2];
146                 t[0] = time(NULL);
147                 t[1] = modtime;
148                 return utime(fname,t);
149 #else
150                 struct timeval t[2];
151                 t[0].tv_sec = time(NULL);
152                 t[0].tv_usec = 0;
153                 t[1].tv_sec = modtime;
154                 t[1].tv_usec = 0;
155                 return utimes(fname,t);
156 #endif
157         }
158 }
159
160
161 /**
162    Create any necessary directories in fname. Unfortunately we don't know
163    what perms to give the directory when this is called so we need to rely
164    on the umask
165 **/
166 int create_directory_path(char *fname, int base_umask)
167 {
168         char *p;
169
170         while (*fname == '/') fname++;
171         while (strncmp(fname,"./",2)==0) fname += 2;
172
173         p = fname;
174         while ((p=strchr(p,'/'))) {
175                 *p = 0;
176                 do_mkdir(fname, 0777 & ~base_umask); 
177                 *p = '/';
178                 p++;
179         }
180         return 0;
181 }
182
183
184 /**
185  * Write @p len bytes at @p ptr to descriptor @p desc, retrying if
186  * interrupted.
187  *
188  * @retval len upon success
189  *
190  * @retval <0 write's (negative) error code
191  *
192  * Derived from GNU C's cccp.c.
193  */
194 static int full_write(int desc, char *ptr, size_t len)
195 {
196         int total_written;
197         
198         total_written = 0;
199         while (len > 0) {
200                 int written = write(desc, ptr, len);
201                 if (written < 0)  {
202                         if (errno == EINTR)
203                                 continue;
204                         return written;
205                 }
206                 total_written += written;
207                 ptr += written;
208                 len -= written;
209         }
210         return total_written;
211 }
212
213
214 /**
215  * Read @p len bytes at @p ptr from descriptor @p desc, retrying if
216  * interrupted.
217  *
218  * @retval >0 the actual number of bytes read
219  *
220  * @retval 0 for EOF
221  *
222  * @retval <0 for an error.
223  *
224  * Derived from GNU C's cccp.c. */
225 static int safe_read(int desc, char *ptr, size_t len)
226 {
227         int n_chars;
228  
229         if (len == 0)
230                 return len;
231  
232         do {
233                 n_chars = read(desc, ptr, len);
234         } while (n_chars < 0 && errno == EINTR);
235  
236         return n_chars;
237 }
238
239
240 /** Copy a file.
241  *
242  * This is used in conjunction with the --temp-dir option */
243 int copy_file(char *source, char *dest, mode_t mode)
244 {
245         int ifd;
246         int ofd;
247         char buf[1024 * 8];
248         int len;   /* Number of bytes read into `buf'. */
249
250         ifd = do_open(source, O_RDONLY, 0);
251         if (ifd == -1) {
252                 rprintf(FERROR,"open %s: %s\n",
253                         source,strerror(errno));
254                 return -1;
255         }
256
257         if (robust_unlink(dest) && errno != ENOENT) {
258                 rprintf(FERROR,"unlink %s: %s\n",
259                         dest,strerror(errno));
260                 return -1;
261         }
262
263         ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
264         if (ofd == -1) {
265                 rprintf(FERROR,"open %s: %s\n",
266                         dest,strerror(errno));
267                 close(ifd);
268                 return -1;
269         }
270
271         while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
272                 if (full_write(ofd, buf, len) < 0) {
273                         rprintf(FERROR,"write %s: %s\n",
274                                 dest,strerror(errno));
275                         close(ifd);
276                         close(ofd);
277                         return -1;
278                 }
279         }
280
281         close(ifd);
282         close(ofd);
283
284         if (len < 0) {
285                 rprintf(FERROR,"read %s: %s\n",
286                         source,strerror(errno));
287                 return -1;
288         }
289
290         return 0;
291 }
292
293 /* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
294 #define MAX_RENAMES_DIGITS 3
295 #define MAX_RENAMES 1000
296
297 /**
298  * Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
299  * rename to <path>/.rsyncNNN instead.
300  *
301  * Note that successive rsync runs will shuffle the filenames around a
302  * bit as long as the file is still busy; this is because this function
303  * does not know if the unlink call is due to a new file coming in, or
304  * --delete trying to remove old .rsyncNNN files, hence it renames it
305  * each time.
306  **/
307 int robust_unlink(char *fname)
308 {
309 #ifndef ETXTBSY
310         return do_unlink(fname);
311 #else
312         static int counter = 1;
313         int rc, pos, start;
314         char path[MAXPATHLEN];
315
316         rc = do_unlink(fname);
317         if ((rc == 0) || (errno != ETXTBSY))
318                 return rc;
319
320         strlcpy(path, fname, MAXPATHLEN);
321
322         pos = strlen(path);
323         while((path[--pos] != '/') && (pos >= 0))
324                 ;
325         ++pos;
326         strlcpy(&path[pos], ".rsync", MAXPATHLEN-pos);
327         pos += sizeof(".rsync")-1;
328
329         if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
330                 errno = ETXTBSY;
331                 return -1;
332         }
333
334         /* start where the last one left off to reduce chance of clashes */
335         start = counter;
336         do {
337                 sprintf(&path[pos], "%03d", counter);
338                 if (++counter >= MAX_RENAMES)
339                         counter = 1;
340         } while (((rc = access(path, 0)) == 0) && (counter != start));
341
342         if (verbose > 0) {
343                 rprintf(FINFO,"renaming %s to %s because of text busy\n",
344                         fname, path);
345         }
346
347         /* maybe we should return rename()'s exit status? Nah. */
348         if (do_rename(fname, path) != 0) {
349                 errno = ETXTBSY;
350                 return -1;
351         }
352         return 0;
353 #endif
354 }
355
356 int robust_rename(char *from, char *to)
357 {
358 #ifndef ETXTBSY
359         return do_rename(from, to);
360 #else
361         int rc = do_rename(from, to);
362         if ((rc == 0) || (errno != ETXTBSY))
363                 return rc;
364         if (robust_unlink(to) != 0)
365                 return -1;
366         return do_rename(from, to);
367 #endif
368 }
369
370
371 static pid_t all_pids[10];
372 static int num_pids;
373
374 /** Fork and record the pid of the child. **/
375 pid_t do_fork(void)
376 {
377         pid_t newpid = fork();
378         
379         if (newpid != 0  &&  newpid != -1) {
380                 all_pids[num_pids++] = newpid;
381         }
382         return newpid;
383 }
384
385 /**
386  * Kill all children.
387  *
388  * @todo It would be kind of nice to make sure that they are actually
389  * all our children before we kill them, because their pids may have
390  * been recycled by some other process.  Perhaps when we wait for a
391  * child, we should remove it from this array.  Alternatively we could
392  * perhaps use process groups, but I think that would not work on
393  * ancient Unix versions that don't support them.
394  **/
395 void kill_all(int sig)
396 {
397         int i;
398
399         for (i = 0; i < num_pids; i++) {
400                 /* Let's just be a little careful where we
401                  * point that gun, hey?  See kill(2) for the
402                  * magic caused by negative values. */
403                 pid_t p = all_pids[i];
404
405                 if (p == getpid())
406                         continue;
407                 if (p <= 0)
408                         continue;
409
410                 kill(p, sig);
411         }
412 }
413
414
415 /** Turn a user name into a uid */
416 int name_to_uid(char *name, uid_t *uid)
417 {
418         struct passwd *pass;
419         if (!name || !*name) return 0;
420         pass = getpwnam(name);
421         if (pass) {
422                 *uid = pass->pw_uid;
423                 return 1;
424         }
425         return 0;
426 }
427
428 /** Turn a group name into a gid */
429 int name_to_gid(char *name, gid_t *gid)
430 {
431         struct group *grp;
432         if (!name || !*name) return 0;
433         grp = getgrnam(name);
434         if (grp) {
435                 *gid = grp->gr_gid;
436                 return 1;
437         }
438         return 0;
439 }
440
441
442 /** Lock a byte range in a open file */
443 int lock_range(int fd, int offset, int len)
444 {
445         struct flock lock;
446
447         lock.l_type = F_WRLCK;
448         lock.l_whence = SEEK_SET;
449         lock.l_start = offset;
450         lock.l_len = len;
451         lock.l_pid = 0;
452         
453         return fcntl(fd,F_SETLK,&lock) == 0;
454 }
455
456 static int exclude_server_path(char *arg)
457 {
458         char *s;
459         extern struct exclude_struct **server_exclude_list;
460
461         if (server_exclude_list) {
462                 for (s = arg; (s = strchr(s, '/')) != NULL; ) {
463                         *s = '\0';
464                         if (check_exclude(server_exclude_list, arg, 1)) {
465                                 /* We must leave arg truncated! */
466                                 return 1;
467                         }
468                         *s++ = '/';
469                 }
470         }
471         return 0;
472 }
473
474 static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
475 {
476 #if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
477         if (!*s) s = ".";
478         s = argv[*argc] = strdup(s);
479         exclude_server_path(s);
480         (*argc)++;
481 #else
482         extern int sanitize_paths;
483         glob_t globbuf;
484         int i;
485
486         if (!*s) s = ".";
487
488         s = argv[*argc] = strdup(s);
489         if (sanitize_paths) {
490                 sanitize_path(s, NULL);
491         }
492
493         memset(&globbuf, 0, sizeof(globbuf));
494         if (!exclude_server_path(s))
495                 glob(s, 0, NULL, &globbuf);
496         if (globbuf.gl_pathc == 0) {
497                 (*argc)++;
498                 globfree(&globbuf);
499                 return;
500         }
501         for (i=0; i<(maxargs - (*argc)) && i < (int) globbuf.gl_pathc;i++) {
502                 if (i == 0) free(s);
503                 argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
504                 if (!argv[(*argc) + i]) out_of_memory("glob_expand");
505         }
506         globfree(&globbuf);
507         (*argc) += i;
508 #endif
509 }
510
511 /* This routine is only used in daemon mode. */
512 void glob_expand(char *base1, char **argv, int *argc, int maxargs)
513 {
514         char *s = argv[*argc];
515         char *p, *q;
516         char *base = base1;
517         int base_len = strlen(base);
518
519         if (!s || !*s) return;
520
521         if (strncmp(s, base, base_len) == 0)
522                 s += base_len;
523
524         s = strdup(s);
525         if (!s) out_of_memory("glob_expand");
526
527         if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
528         base_len++;
529
530         q = s;
531         while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
532                 /* split it at this point */
533                 *p = 0;
534                 glob_expand_one(q, argv, argc, maxargs);
535                 q = p + base_len;
536         }
537
538         if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
539
540         free(s);
541         free(base);
542 }
543
544 /**
545  * Convert a string to lower case
546  **/
547 void strlower(char *s)
548 {
549         while (*s) {
550                 if (isupper(* (unsigned char *) s))
551                         *s = tolower(* (unsigned char *) s);
552                 s++;
553         }
554 }
555
556 void clean_fname(char *name)
557 {
558         char *p;
559         int l;
560         int modified = 1;
561
562         if (!name) return;
563
564         while (modified) {
565                 modified = 0;
566
567                 if ((p=strstr(name,"/./"))) {
568                         modified = 1;
569                         while (*p) {
570                                 p[0] = p[2];
571                                 p++;
572                         }
573                 }
574
575                 if ((p=strstr(name,"//"))) {
576                         modified = 1;
577                         while (*p) {
578                                 p[0] = p[1];
579                                 p++;
580                         }
581                 }
582
583                 if (strncmp(p=name,"./",2) == 0) {      
584                         modified = 1;
585                         do {
586                                 p[0] = p[2];
587                         } while (*p++);
588                 }
589
590                 l = strlen(p=name);
591                 if (l > 1 && p[l-1] == '/') {
592                         modified = 1;
593                         p[l-1] = 0;
594                 }
595         }
596 }
597
598 /**
599  * Make path appear as if a chroot had occurred:
600  *
601  * @li 1. remove leading "/" (or replace with "." if at end)
602  *
603  * @li 2. remove leading ".." components (except those allowed by @p reldir)
604  *
605  * @li 3. delete any other "<dir>/.." (recursively)
606  *
607  * Can only shrink paths, so sanitizes in place.
608  *
609  * While we're at it, remove double slashes and "." components like
610  *   clean_fname() does, but DON'T remove a trailing slash because that
611  *   is sometimes significant on command line arguments.
612  *
613  * If @p reldir is non-null, it is a sanitized directory that the path will be
614  *    relative to, so allow as many ".." at the beginning of the path as
615  *    there are components in reldir.  This is used for symbolic link targets.
616  *    If reldir is non-null and the path began with "/", to be completely like
617  *    a chroot we should add in depth levels of ".." at the beginning of the
618  *    path, but that would blow the assumption that the path doesn't grow and
619  *    it is not likely to end up being a valid symlink anyway, so just do
620  *    the normal removal of the leading "/" instead.
621  *
622  * Contributed by Dave Dykstra <dwd@bell-labs.com>
623  */
624 void sanitize_path(char *p, char *reldir)
625 {
626         char *start, *sanp;
627         int depth = 0;
628         int allowdotdot = 0;
629
630         if (reldir) {
631                 depth++;
632                 while (*reldir) {
633                         if (*reldir++ == '/') {
634                                 depth++;
635                         }
636                 }
637         }
638         start = p;
639         sanp = p;
640         while (*p == '/') {
641                 /* remove leading slashes */
642                 p++;
643         }
644         while (*p != '\0') {
645                 /* this loop iterates once per filename component in p.
646                  * both p (and sanp if the original had a slash) should
647                  * always be left pointing after a slash
648                  */
649                 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
650                         /* skip "." component */
651                         while (*++p == '/') {
652                                 /* skip following slashes */
653                                 ;
654                         }
655                         continue;
656                 }
657                 allowdotdot = 0;
658                 if ((*p == '.') && (*(p+1) == '.') &&
659                     ((*(p+2) == '/') || (*(p+2) == '\0'))) {
660                         /* ".." component followed by slash or end */
661                         if ((depth > 0) && (sanp == start)) {
662                                 /* allow depth levels of .. at the beginning */
663                                 --depth;
664                                 allowdotdot = 1;
665                         } else {
666                                 p += 2;
667                                 if (*p == '/')
668                                         p++;
669                                 if (sanp != start) {
670                                         /* back up sanp one level */
671                                         --sanp; /* now pointing at slash */
672                                         while ((sanp > start) && (*(sanp - 1) != '/')) {
673                                                 /* skip back up to slash */
674                                                 sanp--;
675                                         }
676                                 }
677                                 continue;
678                         }
679                 }
680                 while (1) {
681                         /* copy one component through next slash */
682                         *sanp++ = *p++;
683                         if ((*p == '\0') || (*(p-1) == '/')) {
684                                 while (*p == '/') {
685                                         /* skip multiple slashes */
686                                         p++;
687                                 }
688                                 break;
689                         }
690                 }
691                 if (allowdotdot) {
692                         /* move the virtual beginning to leave the .. alone */
693                         start = sanp;
694                 }
695         }
696         if ((sanp == start) && !allowdotdot) {
697                 /* ended up with nothing, so put in "." component */
698                 /*
699                  * note that the !allowdotdot doesn't prevent this from
700                  *  happening in all allowed ".." situations, but I didn't
701                  *  think it was worth putting in an extra variable to ensure
702                  *  it since an extra "." won't hurt in those situations.
703                  */
704                 *sanp++ = '.';
705         }
706         *sanp = '\0';
707 }
708
709
710 char curr_dir[MAXPATHLEN];
711
712 /**
713  * Like chdir() but can be reversed with pop_dir() if @p save is set.
714  * It is also much faster as it remembers where we have been.
715  **/
716 char *push_dir(char *dir, int save)
717 {
718         char *ret = curr_dir;
719         static int initialised;
720
721         if (!initialised) {
722                 initialised = 1;
723                 getcwd(curr_dir, sizeof(curr_dir)-1);
724         }
725
726         if (!dir) return NULL; /* this call was probably just to initialize */
727
728         if (chdir(dir)) return NULL;
729
730         if (save) {
731                 ret = strdup(curr_dir);
732         }
733
734         if (*dir == '/') {
735                 strlcpy(curr_dir, dir, sizeof(curr_dir));
736         } else if (dir[0] != '.' || dir[1] != '\0') {
737                 strlcat(curr_dir,"/", sizeof(curr_dir));
738                 strlcat(curr_dir,dir, sizeof(curr_dir));
739         }
740
741         clean_fname(curr_dir);
742
743         return ret;
744 }
745
746 /** Reverse a push_dir() call */
747 int pop_dir(char *dir)
748 {
749         int ret;
750
751         ret = chdir(dir);
752         if (ret) {
753                 free(dir);
754                 return ret;
755         }
756
757         strlcpy(curr_dir, dir, sizeof(curr_dir));
758
759         free(dir);
760
761         return 0;
762 }
763
764 /**
765  * Return a quoted string with the full pathname of the indicated filename.
766  * The string " (in MODNAME)" may also be appended.  The returned pointer
767  * remains valid until the next time full_fname() is called.
768  **/
769 char *full_fname(char *fn)
770 {
771         extern int module_id;
772         static char *result = NULL;
773         char *m1, *m2, *m3;
774         char *p1, *p2;
775
776         if (result)
777                 free(result);
778
779         if (*fn == '/')
780                 p1 = p2 = "";
781         else {
782                 p1 = curr_dir;
783                 p2 = "/";
784         }
785         if (module_id >= 0) {
786                 m1 = " (in ";
787                 m2 = lp_name(module_id);
788                 m3 = ")";
789                 if (*p1) {
790                         if (!lp_use_chroot(module_id)) {
791                                 char *p = lp_path(module_id);
792                                 if (*p != '/' || p[1])
793                                         p1 += strlen(p);
794                         }
795                         if (!*p1)
796                                 p2++;
797                         else
798                                 p1++;
799                 }
800                 else
801                         fn++;
802         } else
803                 m1 = m2 = m3 = "";
804
805         asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3);
806
807         return result;
808 }
809
810 /** We need to supply our own strcmp function for file list comparisons
811    to ensure that signed/unsigned usage is consistent between machines. */
812 int u_strcmp(const char *cs1, const char *cs2)
813 {
814         const uchar *s1 = (const uchar *)cs1;
815         const uchar *s2 = (const uchar *)cs2;
816
817         while (*s1 && *s2 && (*s1 == *s2)) {
818                 s1++; s2++;
819         }
820         
821         return (int)*s1 - (int)*s2;
822 }
823
824
825
826 /**
827  * Determine if a symlink points outside the current directory tree.
828  * This is considered "unsafe" because e.g. when mirroring somebody
829  * else's machine it might allow them to establish a symlink to
830  * /etc/passwd, and then read it through a web server.
831  *
832  * Null symlinks and absolute symlinks are always unsafe.
833  *
834  * Basically here we are concerned with symlinks whose target contains
835  * "..", because this might cause us to walk back up out of the
836  * transferred directory.  We are not allowed to go back up and
837  * reenter.
838  *
839  * @param dest Target of the symlink in question.
840  *
841  * @param src Top source directory currently applicable.  Basically this
842  * is the first parameter to rsync in a simple invocation, but it's
843  * modified by flist.c in slightly complex ways.
844  *
845  * @retval True if unsafe
846  * @retval False is unsafe
847  *
848  * @sa t_unsafe.c
849  **/
850 int unsafe_symlink(const char *dest, const char *src)
851 {
852         const char *name, *slash;
853         int depth = 0;
854
855         /* all absolute and null symlinks are unsafe */
856         if (!dest || !*dest || *dest == '/') return 1;
857
858         /* find out what our safety margin is */
859         for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
860                 if (strncmp(name, "../", 3) == 0) {
861                         depth=0;
862                 } else if (strncmp(name, "./", 2) == 0) {
863                         /* nothing */
864                 } else {
865                         depth++;
866                 }
867         }
868         if (strcmp(name, "..") == 0)
869                 depth = 0;
870
871         for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) {
872                 if (strncmp(name, "../", 3) == 0) {
873                         /* if at any point we go outside the current directory
874                            then stop - it is unsafe */
875                         if (--depth < 0)
876                                 return 1;
877                 } else if (strncmp(name, "./", 2) == 0) {
878                         /* nothing */
879                 } else {
880                         depth++;
881                 }
882         }
883         if (strcmp(name, "..") == 0)
884                 depth--;
885
886         return (depth < 0);
887 }
888
889
890 /**
891  * Return the date and time as a string
892  **/
893 char *timestring(time_t t)
894 {
895         static char TimeBuf[200];
896         struct tm *tm = localtime(&t);
897
898 #ifdef HAVE_STRFTIME
899         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
900 #else
901         strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
902 #endif
903
904         if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
905                 TimeBuf[strlen(TimeBuf)-1] = 0;
906         }
907
908         return(TimeBuf);
909 }
910
911
912 /**
913  * Sleep for a specified number of milliseconds.
914  *
915  * Always returns TRUE.  (In the future it might return FALSE if
916  * interrupted.)
917  **/
918 int msleep(int t)
919 {
920         int tdiff=0;
921         struct timeval tval,t1,t2;  
922
923         gettimeofday(&t1, NULL);
924         gettimeofday(&t2, NULL);
925   
926         while (tdiff < t) {
927                 tval.tv_sec = (t-tdiff)/1000;
928                 tval.tv_usec = 1000*((t-tdiff)%1000);
929  
930                 errno = 0;
931                 select(0,NULL,NULL, NULL, &tval);
932
933                 gettimeofday(&t2, NULL);
934                 tdiff = (t2.tv_sec - t1.tv_sec)*1000 + 
935                         (t2.tv_usec - t1.tv_usec)/1000;
936         }
937
938         return True;
939 }
940
941
942 /**
943  * Determine if two file modification times are equivalent (either
944  * exact or in the modification timestamp window established by
945  * --modify-window).
946  *
947  * @retval 0 if the times should be treated as the same
948  *
949  * @retval +1 if the first is later
950  *
951  * @retval -1 if the 2nd is later
952  **/
953 int cmp_modtime(time_t file1, time_t file2)
954 {
955         extern int modify_window;
956
957         if (file2 > file1) {
958                 if (file2 - file1 <= modify_window) return 0;
959                 return -1;
960         }
961         if (file1 - file2 <= modify_window) return 0;
962         return 1;
963 }
964
965
966 #ifdef __INSURE__XX
967 #include <dlfcn.h>
968
969 /**
970    This routine is a trick to immediately catch errors when debugging
971    with insure. A xterm with a gdb is popped up when insure catches
972    a error. It is Linux specific.
973 **/
974 int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
975 {
976         static int (*fn)();
977         int ret;
978         char *cmd;
979
980         asprintf(&cmd, "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; gdb /proc/%d/exe %d'", 
981                 getpid(), getpid(), getpid());
982
983         if (!fn) {
984                 static void *h;
985                 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
986                 fn = dlsym(h, "_Insure_trap_error");
987         }
988
989         ret = fn(a1, a2, a3, a4, a5, a6);
990
991         system(cmd);
992
993         free(cmd);
994
995         return ret;
996 }
997 #endif
998
999
1000 #define MALLOC_MAX 0x40000000
1001
1002 void *_new_array(unsigned int size, unsigned long num)
1003 {
1004         if (num >= MALLOC_MAX/size)
1005                 return NULL;
1006         return malloc(size * num);
1007 }
1008
1009 void *_realloc_array(void *ptr, unsigned int size, unsigned long num)
1010 {
1011         if (num >= MALLOC_MAX/size)
1012                 return NULL;
1013         /* No realloc should need this, but just in case... */
1014         if (!ptr)
1015                 return malloc(size * num);
1016         return realloc(ptr, size * num);
1017 }