Merged in the security fixes from 2.5.7.
[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 #ifdef EINTR
203                         if (errno == EINTR)
204                                 continue;
205 #endif
206                         return written;
207                 }
208                 total_written += written;
209                 ptr += written;
210                 len -= written;
211         }
212         return total_written;
213 }
214
215
216 /**
217  * Read @p len bytes at @p ptr from descriptor @p desc, retrying if
218  * interrupted.
219  *
220  * @retval >0 the actual number of bytes read
221  *
222  * @retval 0 for EOF
223  *
224  * @retval <0 for an error.
225  *
226  * Derived from GNU C's cccp.c. */
227 static int safe_read(int desc, char *ptr, size_t len)
228 {
229         int n_chars;
230  
231         if (len == 0)
232                 return len;
233  
234 #ifdef EINTR
235         do {
236                 n_chars = read(desc, ptr, len);
237         } while (n_chars < 0 && errno == EINTR);
238 #else
239         n_chars = read(desc, ptr, len);
240 #endif
241  
242         return n_chars;
243 }
244
245
246 /** Copy a file.
247  *
248  * This is used in conjunction with the --temp-dir option */
249 int copy_file(char *source, char *dest, mode_t mode)
250 {
251         int ifd;
252         int ofd;
253         char buf[1024 * 8];
254         int len;   /* Number of bytes read into `buf'. */
255
256         ifd = do_open(source, O_RDONLY, 0);
257         if (ifd == -1) {
258                 rprintf(FERROR,"open %s: %s\n",
259                         source,strerror(errno));
260                 return -1;
261         }
262
263         if (robust_unlink(dest) && errno != ENOENT) {
264                 rprintf(FERROR,"unlink %s: %s\n",
265                         dest,strerror(errno));
266                 return -1;
267         }
268
269         ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
270         if (ofd == -1) {
271                 rprintf(FERROR,"open %s: %s\n",
272                         dest,strerror(errno));
273                 close(ifd);
274                 return -1;
275         }
276
277         while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
278                 if (full_write(ofd, buf, len) < 0) {
279                         rprintf(FERROR,"write %s: %s\n",
280                                 dest,strerror(errno));
281                         close(ifd);
282                         close(ofd);
283                         return -1;
284                 }
285         }
286
287         close(ifd);
288         close(ofd);
289
290         if (len < 0) {
291                 rprintf(FERROR,"read %s: %s\n",
292                         source,strerror(errno));
293                 return -1;
294         }
295
296         return 0;
297 }
298
299 /* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
300 #define MAX_RENAMES_DIGITS 3
301 #define MAX_RENAMES 1000
302
303 /**
304  * Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
305  * rename to <path>/.rsyncNNN instead.
306  *
307  * Note that successive rsync runs will shuffle the filenames around a
308  * bit as long as the file is still busy; this is because this function
309  * does not know if the unlink call is due to a new file coming in, or
310  * --delete trying to remove old .rsyncNNN files, hence it renames it
311  * each time.
312  **/
313 int robust_unlink(char *fname)
314 {
315 #ifndef ETXTBSY
316         return do_unlink(fname);
317 #else
318         static int counter = 1;
319         int rc, pos, start;
320         char path[MAXPATHLEN];
321
322         rc = do_unlink(fname);
323         if ((rc == 0) || (errno != ETXTBSY))
324                 return rc;
325
326         strlcpy(path, fname, MAXPATHLEN);
327
328         pos = strlen(path);
329         while((path[--pos] != '/') && (pos >= 0))
330                 ;
331         ++pos;
332         strlcpy(&path[pos], ".rsync", MAXPATHLEN-pos);
333         pos += sizeof(".rsync")-1;
334
335         if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
336                 errno = ETXTBSY;
337                 return -1;
338         }
339
340         /* start where the last one left off to reduce chance of clashes */
341         start = counter;
342         do {
343                 sprintf(&path[pos], "%03d", counter);
344                 if (++counter >= MAX_RENAMES)
345                         counter = 1;
346         } while (((rc = access(path, 0)) == 0) && (counter != start));
347
348         if (verbose > 0) {
349                 rprintf(FINFO,"renaming %s to %s because of text busy\n",
350                         fname, path);
351         }
352
353         /* maybe we should return rename()'s exit status? Nah. */
354         if (do_rename(fname, path) != 0) {
355                 errno = ETXTBSY;
356                 return -1;
357         }
358         return 0;
359 #endif
360 }
361
362 int robust_rename(char *from, char *to)
363 {
364 #ifndef ETXTBSY
365         return do_rename(from, to);
366 #else
367         int rc = do_rename(from, to);
368         if ((rc == 0) || (errno != ETXTBSY))
369                 return rc;
370         if (robust_unlink(to) != 0)
371                 return -1;
372         return do_rename(from, to);
373 #endif
374 }
375
376
377 static pid_t all_pids[10];
378 static int num_pids;
379
380 /** Fork and record the pid of the child. **/
381 pid_t do_fork(void)
382 {
383         pid_t newpid = fork();
384         
385         if (newpid != 0  &&  newpid != -1) {
386                 all_pids[num_pids++] = newpid;
387         }
388         return newpid;
389 }
390
391 /**
392  * Kill all children.
393  *
394  * @todo It would be kind of nice to make sure that they are actually
395  * all our children before we kill them, because their pids may have
396  * been recycled by some other process.  Perhaps when we wait for a
397  * child, we should remove it from this array.  Alternatively we could
398  * perhaps use process groups, but I think that would not work on
399  * ancient Unix versions that don't support them.
400  **/
401 void kill_all(int sig)
402 {
403         int i;
404
405         for (i = 0; i < num_pids; i++) {
406                 /* Let's just be a little careful where we
407                  * point that gun, hey?  See kill(2) for the
408                  * magic caused by negative values. */
409                 pid_t p = all_pids[i];
410
411                 if (p == getpid())
412                         continue;
413                 if (p <= 0)
414                         continue;
415
416                 kill(p, sig);
417         }
418 }
419
420
421 /** Turn a user name into a uid */
422 int name_to_uid(char *name, uid_t *uid)
423 {
424         struct passwd *pass;
425         if (!name || !*name) return 0;
426         pass = getpwnam(name);
427         if (pass) {
428                 *uid = pass->pw_uid;
429                 return 1;
430         }
431         return 0;
432 }
433
434 /** Turn a group name into a gid */
435 int name_to_gid(char *name, gid_t *gid)
436 {
437         struct group *grp;
438         if (!name || !*name) return 0;
439         grp = getgrnam(name);
440         if (grp) {
441                 *gid = grp->gr_gid;
442                 return 1;
443         }
444         return 0;
445 }
446
447
448 /** Lock a byte range in a open file */
449 int lock_range(int fd, int offset, int len)
450 {
451         struct flock lock;
452
453         lock.l_type = F_WRLCK;
454         lock.l_whence = SEEK_SET;
455         lock.l_start = offset;
456         lock.l_len = len;
457         lock.l_pid = 0;
458         
459         return fcntl(fd,F_SETLK,&lock) == 0;
460 }
461
462 static int exclude_server_path(char *arg)
463 {
464         char *s;
465         extern struct exclude_struct **server_exclude_list;
466
467         if (server_exclude_list) {
468                 for (s = arg; (s = strchr(s, '/')) != NULL; ) {
469                         *s = '\0';
470                         if (check_exclude(server_exclude_list, arg, 1)) {
471                                 /* We must leave arg truncated! */
472                                 return 1;
473                         }
474                         *s++ = '/';
475                 }
476         }
477         return 0;
478 }
479
480 static 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         s = argv[*argc] = strdup(s);
485         exclude_server_path(s);
486         (*argc)++;
487 #else
488         extern int sanitize_paths;
489         glob_t globbuf;
490         int i;
491
492         if (!*s) s = ".";
493
494         s = argv[*argc] = strdup(s);
495         if (sanitize_paths) {
496                 sanitize_path(s, NULL);
497         }
498
499         memset(&globbuf, 0, sizeof(globbuf));
500         if (!exclude_server_path(s))
501                 glob(s, 0, NULL, &globbuf);
502         if (globbuf.gl_pathc == 0) {
503                 (*argc)++;
504                 globfree(&globbuf);
505                 return;
506         }
507         for (i=0; i<(maxargs - (*argc)) && i < (int) globbuf.gl_pathc;i++) {
508                 if (i == 0) free(s);
509                 argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
510                 if (!argv[(*argc) + i]) out_of_memory("glob_expand");
511         }
512         globfree(&globbuf);
513         (*argc) += i;
514 #endif
515 }
516
517 /* This routine is only used in daemon mode. */
518 void glob_expand(char *base1, char **argv, int *argc, int maxargs)
519 {
520         char *s = argv[*argc];
521         char *p, *q;
522         char *base = base1;
523         int base_len = strlen(base);
524
525         if (!s || !*s) return;
526
527         if (strncmp(s, base, base_len) == 0)
528                 s += base_len;
529
530         s = strdup(s);
531         if (!s) out_of_memory("glob_expand");
532
533         if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
534         base_len++;
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 + base_len;
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  **/
553 void strlower(char *s)
554 {
555         while (*s) {
556                 if (isupper(* (unsigned char *) s))
557                         *s = tolower(* (unsigned char *) s);
558                 s++;
559         }
560 }
561
562 void clean_fname(char *name)
563 {
564         char *p;
565         int l;
566         int modified = 1;
567
568         if (!name) return;
569
570         while (modified) {
571                 modified = 0;
572
573                 if ((p=strstr(name,"/./"))) {
574                         modified = 1;
575                         while (*p) {
576                                 p[0] = p[2];
577                                 p++;
578                         }
579                 }
580
581                 if ((p=strstr(name,"//"))) {
582                         modified = 1;
583                         while (*p) {
584                                 p[0] = p[1];
585                                 p++;
586                         }
587                 }
588
589                 if (strncmp(p=name,"./",2) == 0) {      
590                         modified = 1;
591                         do {
592                                 p[0] = p[2];
593                         } while (*p++);
594                 }
595
596                 l = strlen(p=name);
597                 if (l > 1 && p[l-1] == '/') {
598                         modified = 1;
599                         p[l-1] = 0;
600                 }
601         }
602 }
603
604 /**
605  * Make path appear as if a chroot had occurred:
606  *
607  * @li 1. remove leading "/" (or replace with "." if at end)
608  *
609  * @li 2. remove leading ".." components (except those allowed by @p reldir)
610  *
611  * @li 3. delete any other "<dir>/.." (recursively)
612  *
613  * Can only shrink paths, so sanitizes in place.
614  *
615  * While we're at it, remove double slashes and "." components like
616  *   clean_fname() does, but DON'T remove a trailing slash because that
617  *   is sometimes significant on command line arguments.
618  *
619  * If @p reldir is non-null, it is a sanitized directory that the path will be
620  *    relative to, so allow as many ".." at the beginning of the path as
621  *    there are components in reldir.  This is used for symbolic link targets.
622  *    If reldir is non-null and the path began with "/", to be completely like
623  *    a chroot we should add in depth levels of ".." at the beginning of the
624  *    path, but that would blow the assumption that the path doesn't grow and
625  *    it is not likely to end up being a valid symlink anyway, so just do
626  *    the normal removal of the leading "/" instead.
627  *
628  * Contributed by Dave Dykstra <dwd@bell-labs.com>
629  */
630 void sanitize_path(char *p, char *reldir)
631 {
632         char *start, *sanp;
633         int depth = 0;
634         int allowdotdot = 0;
635
636         if (reldir) {
637                 depth++;
638                 while (*reldir) {
639                         if (*reldir++ == '/') {
640                                 depth++;
641                         }
642                 }
643         }
644         start = p;
645         sanp = p;
646         while (*p == '/') {
647                 /* remove leading slashes */
648                 p++;
649         }
650         while (*p != '\0') {
651                 /* this loop iterates once per filename component in p.
652                  * both p (and sanp if the original had a slash) should
653                  * always be left pointing after a slash
654                  */
655                 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
656                         /* skip "." component */
657                         while (*++p == '/') {
658                                 /* skip following slashes */
659                                 ;
660                         }
661                         continue;
662                 }
663                 allowdotdot = 0;
664                 if ((*p == '.') && (*(p+1) == '.') &&
665                     ((*(p+2) == '/') || (*(p+2) == '\0'))) {
666                         /* ".." component followed by slash or end */
667                         if ((depth > 0) && (sanp == start)) {
668                                 /* allow depth levels of .. at the beginning */
669                                 --depth;
670                                 allowdotdot = 1;
671                         } else {
672                                 p += 2;
673                                 if (*p == '/')
674                                         p++;
675                                 if (sanp != start) {
676                                         /* back up sanp one level */
677                                         --sanp; /* now pointing at slash */
678                                         while ((sanp > start) && (*(sanp - 1) != '/')) {
679                                                 /* skip back up to slash */
680                                                 sanp--;
681                                         }
682                                 }
683                                 continue;
684                         }
685                 }
686                 while (1) {
687                         /* copy one component through next slash */
688                         *sanp++ = *p++;
689                         if ((*p == '\0') || (*(p-1) == '/')) {
690                                 while (*p == '/') {
691                                         /* skip multiple slashes */
692                                         p++;
693                                 }
694                                 break;
695                         }
696                 }
697                 if (allowdotdot) {
698                         /* move the virtual beginning to leave the .. alone */
699                         start = sanp;
700                 }
701         }
702         if ((sanp == start) && !allowdotdot) {
703                 /* ended up with nothing, so put in "." component */
704                 /*
705                  * note that the !allowdotdot doesn't prevent this from
706                  *  happening in all allowed ".." situations, but I didn't
707                  *  think it was worth putting in an extra variable to ensure
708                  *  it since an extra "." won't hurt in those situations.
709                  */
710                 *sanp++ = '.';
711         }
712         *sanp = '\0';
713 }
714
715
716 char curr_dir[MAXPATHLEN];
717
718 /**
719  * Like chdir() but can be reversed with pop_dir() if @p save is set.
720  * It is also much faster as it remembers where we have been.
721  **/
722 char *push_dir(char *dir, int save)
723 {
724         char *ret = curr_dir;
725         static int initialised;
726
727         if (!initialised) {
728                 initialised = 1;
729                 getcwd(curr_dir, sizeof(curr_dir)-1);
730         }
731
732         if (!dir) return NULL; /* this call was probably just to initialize */
733
734         if (chdir(dir)) return NULL;
735
736         if (save) {
737                 ret = strdup(curr_dir);
738         }
739
740         if (*dir == '/') {
741                 strlcpy(curr_dir, dir, sizeof(curr_dir));
742         } else if (dir[0] != '.' || dir[1] != '\0') {
743                 strlcat(curr_dir,"/", sizeof(curr_dir));
744                 strlcat(curr_dir,dir, sizeof(curr_dir));
745         }
746
747         clean_fname(curr_dir);
748
749         return ret;
750 }
751
752 /** Reverse a push_dir() call */
753 int pop_dir(char *dir)
754 {
755         int ret;
756
757         ret = chdir(dir);
758         if (ret) {
759                 free(dir);
760                 return ret;
761         }
762
763         strlcpy(curr_dir, dir, sizeof(curr_dir));
764
765         free(dir);
766
767         return 0;
768 }
769
770 /**
771  * Return a quoted string with the full pathname of the indicated filename.
772  * The string " (in MODNAME)" may also be appended.  The returned pointer
773  * remains valid until the next time full_fname() is called.
774  **/
775 char *full_fname(char *fn)
776 {
777         extern int module_id;
778         static char *result = NULL;
779         char *m1, *m2, *m3;
780         char *p1, *p2;
781
782         if (result)
783                 free(result);
784
785         if (*fn == '/')
786                 p1 = p2 = "";
787         else {
788                 p1 = curr_dir;
789                 p2 = "/";
790         }
791         if (module_id >= 0) {
792                 m1 = " (in ";
793                 m2 = lp_name(module_id);
794                 m3 = ")";
795                 if (*p1) {
796                         if (!lp_use_chroot(module_id)) {
797                                 char *p = lp_path(module_id);
798                                 if (*p != '/' || p[1])
799                                         p1 += strlen(p);
800                         }
801                         if (!*p1)
802                                 p2++;
803                         else
804                                 p1++;
805                 }
806                 else
807                         fn++;
808         } else
809                 m1 = m2 = m3 = "";
810
811         asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3);
812
813         return result;
814 }
815
816 /** We need to supply our own strcmp function for file list comparisons
817    to ensure that signed/unsigned usage is consistent between machines. */
818 int u_strcmp(const char *cs1, const char *cs2)
819 {
820         const uchar *s1 = (const uchar *)cs1;
821         const uchar *s2 = (const uchar *)cs2;
822
823         while (*s1 && *s2 && (*s1 == *s2)) {
824                 s1++; s2++;
825         }
826         
827         return (int)*s1 - (int)*s2;
828 }
829
830
831
832 /**
833  * Determine if a symlink points outside the current directory tree.
834  * This is considered "unsafe" because e.g. when mirroring somebody
835  * else's machine it might allow them to establish a symlink to
836  * /etc/passwd, and then read it through a web server.
837  *
838  * Null symlinks and absolute symlinks are always unsafe.
839  *
840  * Basically here we are concerned with symlinks whose target contains
841  * "..", because this might cause us to walk back up out of the
842  * transferred directory.  We are not allowed to go back up and
843  * reenter.
844  *
845  * @param dest Target of the symlink in question.
846  *
847  * @param src Top source directory currently applicable.  Basically this
848  * is the first parameter to rsync in a simple invocation, but it's
849  * modified by flist.c in slightly complex ways.
850  *
851  * @retval True if unsafe
852  * @retval False is unsafe
853  *
854  * @sa t_unsafe.c
855  **/
856 int unsafe_symlink(const char *dest, const char *src)
857 {
858         const char *name, *slash;
859         int depth = 0;
860
861         /* all absolute and null symlinks are unsafe */
862         if (!dest || !*dest || *dest == '/') return 1;
863
864         /* find out what our safety margin is */
865         for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
866                 if (strncmp(name, "../", 3) == 0) {
867                         depth=0;
868                 } else if (strncmp(name, "./", 2) == 0) {
869                         /* nothing */
870                 } else {
871                         depth++;
872                 }
873         }
874         if (strcmp(name, "..") == 0)
875                 depth = 0;
876
877         for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) {
878                 if (strncmp(name, "../", 3) == 0) {
879                         /* if at any point we go outside the current directory
880                            then stop - it is unsafe */
881                         if (--depth < 0)
882                                 return 1;
883                 } else if (strncmp(name, "./", 2) == 0) {
884                         /* nothing */
885                 } else {
886                         depth++;
887                 }
888         }
889         if (strcmp(name, "..") == 0)
890                 depth--;
891
892         return (depth < 0);
893 }
894
895
896 /**
897  * Return the date and time as a string
898  **/
899 char *timestring(time_t t)
900 {
901         static char TimeBuf[200];
902         struct tm *tm = localtime(&t);
903
904 #ifdef HAVE_STRFTIME
905         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
906 #else
907         strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
908 #endif
909
910         if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
911                 TimeBuf[strlen(TimeBuf)-1] = 0;
912         }
913
914         return(TimeBuf);
915 }
916
917
918 /**
919  * Sleep for a specified number of milliseconds.
920  *
921  * Always returns TRUE.  (In the future it might return FALSE if
922  * interrupted.)
923  **/
924 int msleep(int t)
925 {
926         int tdiff=0;
927         struct timeval tval,t1,t2;  
928
929         gettimeofday(&t1, NULL);
930         gettimeofday(&t2, NULL);
931   
932         while (tdiff < t) {
933                 tval.tv_sec = (t-tdiff)/1000;
934                 tval.tv_usec = 1000*((t-tdiff)%1000);
935  
936                 errno = 0;
937                 select(0,NULL,NULL, NULL, &tval);
938
939                 gettimeofday(&t2, NULL);
940                 tdiff = (t2.tv_sec - t1.tv_sec)*1000 + 
941                         (t2.tv_usec - t1.tv_usec)/1000;
942         }
943
944         return True;
945 }
946
947
948 /**
949  * Determine if two file modification times are equivalent (either
950  * exact or in the modification timestamp window established by
951  * --modify-window).
952  *
953  * @retval 0 if the times should be treated as the same
954  *
955  * @retval +1 if the first is later
956  *
957  * @retval -1 if the 2nd is later
958  **/
959 int cmp_modtime(time_t file1, time_t file2)
960 {
961         extern int modify_window;
962
963         if (file2 > file1) {
964                 if (file2 - file1 <= modify_window) return 0;
965                 return -1;
966         }
967         if (file1 - file2 <= modify_window) return 0;
968         return 1;
969 }
970
971
972 #ifdef __INSURE__XX
973 #include <dlfcn.h>
974
975 /**
976    This routine is a trick to immediately catch errors when debugging
977    with insure. A xterm with a gdb is popped up when insure catches
978    a error. It is Linux specific.
979 **/
980 int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
981 {
982         static int (*fn)();
983         int ret;
984         char *cmd;
985
986         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'", 
987                 getpid(), getpid(), getpid());
988
989         if (!fn) {
990                 static void *h;
991                 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
992                 fn = dlsym(h, "_Insure_trap_error");
993         }
994
995         ret = fn(a1, a2, a3, a4, a5, a6);
996
997         system(cmd);
998
999         free(cmd);
1000
1001         return ret;
1002 }
1003 #endif
1004
1005
1006 #define MALLOC_MAX 0x40000000
1007
1008 void *_new_array(unsigned int size, unsigned long num)
1009 {
1010         if (num >= MALLOC_MAX/size)
1011                 return NULL;
1012         return malloc(size * num);
1013 }
1014
1015 void *_realloc_array(void *ptr, unsigned int size, unsigned long num)
1016 {
1017         if (num >= MALLOC_MAX/size)
1018                 return NULL;
1019         /* No realloc should need this, but just in case... */
1020         if (!ptr)
1021                 return malloc(size * num);
1022         return realloc(ptr, size * num);
1023 }