1 /* -*- c-file-style: "linux" -*-
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>
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.
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.
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.
25 * Utilities used in rsync
33 extern int modify_window;
34 extern int relative_paths;
35 extern int human_readable;
36 extern char *partial_dir;
37 extern struct filter_list_struct server_filter_list;
39 int sanitize_paths = 0;
44 * Set a fd into nonblocking mode
46 void set_nonblocking(int fd)
50 if ((val = fcntl(fd, F_GETFL, 0)) == -1)
52 if (!(val & NONBLOCK_FLAG)) {
54 fcntl(fd, F_SETFL, val);
59 * Set a fd into blocking mode
61 void set_blocking(int fd)
65 if ((val = fcntl(fd, F_GETFL, 0)) == -1)
67 if (val & NONBLOCK_FLAG) {
68 val &= ~NONBLOCK_FLAG;
69 fcntl(fd, F_SETFL, val);
75 * Create a file descriptor pair - like pipe() but use socketpair if
76 * possible (because of blocking issues on pipes).
78 * Always set non-blocking.
80 int fd_pair(int fd[2])
84 #ifdef HAVE_SOCKETPAIR
85 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
91 set_nonblocking(fd[0]);
92 set_nonblocking(fd[1]);
99 void print_child_argv(char **cmd)
101 rprintf(FINFO, "opening connection using ");
102 for (; *cmd; cmd++) {
103 /* Look for characters that ought to be quoted. This
104 * is not a great quoting algorithm, but it's
105 * sufficient for a log message. */
106 if (strspn(*cmd, "abcdefghijklmnopqrstuvwxyz"
107 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
109 ",.-_=+@/") != strlen(*cmd)) {
110 rprintf(FINFO, "\"%s\" ", *cmd);
112 rprintf(FINFO, "%s ", *cmd);
115 rprintf(FINFO, "\n");
119 void out_of_memory(char *str)
121 rprintf(FERROR, "ERROR: out of memory in %s\n", str);
122 exit_cleanup(RERR_MALLOC);
125 void overflow_exit(char *str)
127 rprintf(FERROR, "ERROR: buffer overflow in %s\n", str);
128 exit_cleanup(RERR_MALLOC);
133 int set_modtime(char *fname, time_t modtime, mode_t mode)
135 #if !defined HAVE_LUTIMES || !defined HAVE_UTIMES
141 rprintf(FINFO, "set modtime of %s to (%ld) %s",
142 fname, (long)modtime,
143 asctime(localtime(&modtime)));
152 t[0].tv_sec = time(NULL);
154 t[1].tv_sec = modtime;
158 return lutimes(fname, t);
160 return utimes(fname, t);
161 #elif defined HAVE_UTIMBUF
163 tbuf.actime = time(NULL);
164 tbuf.modtime = modtime;
165 return utime(fname,&tbuf);
166 #elif defined HAVE_UTIME
170 return utime(fname,t);
172 #error No file-time-modification routine found!
179 Create any necessary directories in fname. Unfortunately we don't know
180 what perms to give the directory when this is called so we need to rely
183 int create_directory_path(char *fname, int base_umask)
187 while (*fname == '/')
189 while (strncmp(fname, "./", 2) == 0)
193 while ((p = strchr(p,'/')) != NULL) {
195 do_mkdir(fname, 0777 & ~base_umask);
204 * Write @p len bytes at @p ptr to descriptor @p desc, retrying if
207 * @retval len upon success
209 * @retval <0 write's (negative) error code
211 * Derived from GNU C's cccp.c.
213 int full_write(int desc, char *ptr, size_t len)
219 int written = write(desc, ptr, len);
225 total_written += written;
229 return total_written;
234 * Read @p len bytes at @p ptr from descriptor @p desc, retrying if
237 * @retval >0 the actual number of bytes read
241 * @retval <0 for an error.
243 * Derived from GNU C's cccp.c. */
244 static int safe_read(int desc, char *ptr, size_t len)
252 n_chars = read(desc, ptr, len);
253 } while (n_chars < 0 && errno == EINTR);
261 * This is used in conjunction with the --temp-dir, --backup, and
262 * --copy-dest options. */
263 int copy_file(const char *source, const char *dest, mode_t mode)
268 int len; /* Number of bytes read into `buf'. */
270 ifd = do_open(source, O_RDONLY, 0);
272 rsyserr(FERROR, errno, "open %s", full_fname(source));
276 if (robust_unlink(dest) && errno != ENOENT) {
277 rsyserr(FERROR, errno, "unlink %s", full_fname(dest));
281 ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
283 rsyserr(FERROR, errno, "open %s", full_fname(dest));
288 while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
289 if (full_write(ofd, buf, len) < 0) {
290 rsyserr(FERROR, errno, "write %s", full_fname(dest));
298 rsyserr(FERROR, errno, "read %s", full_fname(source));
304 if (close(ifd) < 0) {
305 rsyserr(FINFO, errno, "close failed on %s",
309 if (close(ofd) < 0) {
310 rsyserr(FERROR, errno, "close failed on %s",
318 /* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
319 #define MAX_RENAMES_DIGITS 3
320 #define MAX_RENAMES 1000
323 * Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
324 * rename to <path>/.rsyncNNN instead.
326 * Note that successive rsync runs will shuffle the filenames around a
327 * bit as long as the file is still busy; this is because this function
328 * does not know if the unlink call is due to a new file coming in, or
329 * --delete trying to remove old .rsyncNNN files, hence it renames it
332 int robust_unlink(const char *fname)
335 return do_unlink(fname);
337 static int counter = 1;
339 char path[MAXPATHLEN];
341 rc = do_unlink(fname);
342 if (rc == 0 || errno != ETXTBSY)
345 if ((pos = strlcpy(path, fname, MAXPATHLEN)) >= MAXPATHLEN)
346 pos = MAXPATHLEN - 1;
348 while (pos > 0 && path[pos-1] != '/')
350 pos += strlcpy(path+pos, ".rsync", MAXPATHLEN-pos);
352 if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
357 /* start where the last one left off to reduce chance of clashes */
360 sprintf(&path[pos], "%03d", counter);
361 if (++counter >= MAX_RENAMES)
363 } while ((rc = access(path, 0)) == 0 && counter != start);
366 rprintf(FINFO,"renaming %s to %s because of text busy\n",
370 /* maybe we should return rename()'s exit status? Nah. */
371 if (do_rename(fname, path) != 0) {
379 /* Returns 0 on successful rename, 1 if we successfully copied the file
380 * across filesystems, -2 if copy_file() failed, and -1 on other errors.
381 * If partialptr is not NULL and we need to do a copy, copy the file into
382 * the active partial-dir instead of over the destination file. */
383 int robust_rename(char *from, char *to, char *partialptr,
389 if (do_rename(from, to) == 0)
395 if (robust_unlink(to) != 0)
401 if (!handle_partial_dir(partialptr,PDIR_CREATE))
405 if (copy_file(from, to, mode) != 0)
417 static pid_t all_pids[10];
420 /** Fork and record the pid of the child. **/
423 pid_t newpid = fork();
425 if (newpid != 0 && newpid != -1) {
426 all_pids[num_pids++] = newpid;
434 * @todo It would be kind of nice to make sure that they are actually
435 * all our children before we kill them, because their pids may have
436 * been recycled by some other process. Perhaps when we wait for a
437 * child, we should remove it from this array. Alternatively we could
438 * perhaps use process groups, but I think that would not work on
439 * ancient Unix versions that don't support them.
441 void kill_all(int sig)
445 for (i = 0; i < num_pids; i++) {
446 /* Let's just be a little careful where we
447 * point that gun, hey? See kill(2) for the
448 * magic caused by negative values. */
449 pid_t p = all_pids[i];
461 /** Turn a user name into a uid */
462 int name_to_uid(char *name, uid_t *uid)
467 pass = getpwnam(name);
475 /** Turn a group name into a gid */
476 int name_to_gid(char *name, gid_t *gid)
481 grp = getgrnam(name);
490 /** Lock a byte range in a open file */
491 int lock_range(int fd, int offset, int len)
495 lock.l_type = F_WRLCK;
496 lock.l_whence = SEEK_SET;
497 lock.l_start = offset;
501 return fcntl(fd,F_SETLK,&lock) == 0;
504 static int filter_server_path(char *arg)
508 if (server_filter_list.head) {
509 for (s = arg; (s = strchr(s, '/')) != NULL; ) {
511 if (check_filter(&server_filter_list, arg, 1) < 0) {
512 /* We must leave arg truncated! */
521 static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr,
524 char **argv = *argv_ptr;
525 int argc = *argc_ptr;
526 int maxargs = *maxargs_ptr;
527 #if !defined HAVE_GLOB || !defined HAVE_GLOB_H
528 if (argc == maxargs) {
530 if (!(argv = realloc_array(argv, char *, maxargs)))
531 out_of_memory("glob_expand_one");
533 *maxargs_ptr = maxargs;
537 s = argv[argc++] = strdup(s);
538 filter_server_path(s);
548 s = sanitize_path(NULL, s, "", 0);
552 memset(&globbuf, 0, sizeof globbuf);
553 if (!filter_server_path(s))
554 glob(s, 0, NULL, &globbuf);
555 if (MAX((int)globbuf.gl_pathc, 1) > maxargs - argc) {
556 maxargs += globbuf.gl_pathc + MAX_ARGS;
557 if (!(argv = realloc_array(argv, char *, maxargs)))
558 out_of_memory("glob_expand_one");
560 *maxargs_ptr = maxargs;
562 if (globbuf.gl_pathc == 0)
567 for (i = 0; i < (int)globbuf.gl_pathc; i++) {
568 if (!(argv[argc++] = strdup(globbuf.gl_pathv[i])))
569 out_of_memory("glob_expand_one");
577 /* This routine is only used in daemon mode. */
578 void glob_expand(char *base1, char ***argv_ptr, int *argc_ptr, int *maxargs_ptr)
580 char *s = (*argv_ptr)[*argc_ptr];
583 int base_len = strlen(base);
588 if (strncmp(s, base, base_len) == 0)
591 if (!(s = strdup(s)))
592 out_of_memory("glob_expand");
594 if (asprintf(&base," %s/", base1) <= 0)
595 out_of_memory("glob_expand");
598 for (q = s; *q; q = p + base_len) {
599 if ((p = strstr(q, base)) != NULL)
600 *p = '\0'; /* split it at this point */
601 glob_expand_one(q, argv_ptr, argc_ptr, maxargs_ptr);
611 * Convert a string to lower case
613 void strlower(char *s)
616 if (isupper(*(unsigned char *)s))
617 *s = tolower(*(unsigned char *)s);
622 /* Join strings p1 & p2 into "dest" with a guaranteed '/' between them. (If
623 * p1 ends with a '/', no extra '/' is inserted.) Returns the length of both
624 * strings + 1 (if '/' was inserted), regardless of whether the null-terminated
625 * string fits into destsize. */
626 size_t pathjoin(char *dest, size_t destsize, const char *p1, const char *p2)
628 size_t len = strlcpy(dest, p1, destsize);
629 if (len < destsize - 1) {
630 if (!len || dest[len-1] != '/')
632 if (len < destsize - 1)
633 len += strlcpy(dest + len, p2, destsize - len);
640 len += strlen(p2) + 1; /* Assume we'd insert a '/'. */
644 /* Join any number of strings together, putting them in "dest". The return
645 * value is the length of all the strings, regardless of whether the null-
646 * terminated whole fits in destsize. Your list of string pointers must end
647 * with a NULL to indicate the end of the list. */
648 size_t stringjoin(char *dest, size_t destsize, ...)
654 va_start(ap, destsize);
656 if (!(src = va_arg(ap, const char *)))
663 memcpy(dest, src, len);
674 int count_dir_elements(const char *p)
676 int cnt = 0, new_component = 1;
680 else if (new_component) {
688 /* Turns multiple adjacent slashes into a single slash, gets rid of "./"
689 * elements (but not a trailing dot dir), removes a trailing slash, and
690 * optionally collapses ".." elements (except for those at the start of the
691 * string). If the resulting name would be empty, change it into a ".". */
692 unsigned int clean_fname(char *name, BOOL collapse_dot_dot)
694 char *limit = name - 1, *t = name, *f = name;
700 if ((anchored = *f == '/') != 0)
703 /* discard extra slashes */
709 /* discard "." dirs (but NOT a trailing '.'!) */
714 /* collapse ".." dirs */
716 && f[1] == '.' && (f[2] == '/' || !f[2])) {
718 if (s == name && anchored) {
722 while (s > limit && *--s != '/') {}
723 if (s != t - 1 && (s < name || *s == '/')) {
731 while (*f && (*t++ = *f++) != '/') {}
734 if (t > name+anchored && t[-1] == '/')
743 /* Make path appear as if a chroot had occurred. This handles a leading
744 * "/" (either removing it or expanding it) and any leading or embedded
745 * ".." components that attempt to escape past the module's top dir.
747 * If dest is NULL, a buffer is allocated to hold the result. It is legal
748 * to call with the dest and the path (p) pointing to the same buffer, but
749 * rootdir will be ignored to avoid expansion of the string.
751 * The rootdir string contains a value to use in place of a leading slash.
752 * Specify NULL to get the default of lp_path(module_id).
754 * If depth is >= 0, it is a count of how many '..'s to allow at the start
755 * of the path. Use -1 to allow unlimited depth.
757 * We also clean the path in a manner similar to clean_fname() but with a
760 * Turns multiple adjacent slashes into a single slash, gets rid of "." dir
761 * elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and
762 * ALWAYS collapses ".." elements (except for those at the start of the
763 * string up to "depth" deep). If the resulting name would be empty,
764 * change it into a ".". */
765 char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
768 int rlen = 0, leave_one_dotdir = relative_paths;
771 int plen = strlen(p);
774 rootdir = lp_path(module_id);
775 rlen = strlen(rootdir);
780 if (rlen + plen + 1 >= MAXPATHLEN)
782 } else if (!(dest = new_array(char, rlen + plen + 1)))
783 out_of_memory("sanitize_path");
785 memcpy(dest, rootdir, rlen);
791 start = sanp = dest + rlen;
793 /* discard leading or extra slashes */
798 /* this loop iterates once per filename component in p.
799 * both p (and sanp if the original had a slash) should
800 * always be left pointing after a slash
802 if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
803 if (leave_one_dotdir && p[1])
804 leave_one_dotdir = 0;
806 /* skip "." component */
811 if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
812 /* ".." component followed by slash or end */
813 if (depth <= 0 || sanp != start) {
816 /* back up sanp one level */
817 --sanp; /* now pointing at slash */
818 while (sanp > start && sanp[-1] != '/') {
819 /* skip back up to slash */
825 /* allow depth levels of .. at the beginning */
827 /* move the virtual beginning to leave the .. alone */
830 /* copy one component through next slash */
831 while (*p && (*sanp++ = *p++) != '/') {}
834 /* ended up with nothing, so put in "." component */
842 char curr_dir[MAXPATHLEN];
843 unsigned int curr_dir_len;
846 * Like chdir(), but it keeps track of the current directory (in the
847 * global "curr_dir"), and ensures that the path size doesn't overflow.
848 * Also cleans the path using the clean_fname() function.
850 int push_dir(char *dir)
852 static int initialised;
857 getcwd(curr_dir, sizeof curr_dir - 1);
858 curr_dir_len = strlen(curr_dir);
861 if (!dir) /* this call was probably just to initialize */
865 if (len == 1 && *dir == '.')
868 if ((*dir == '/' ? len : curr_dir_len + 1 + len) >= sizeof curr_dir)
875 memcpy(curr_dir, dir, len + 1);
878 curr_dir[curr_dir_len++] = '/';
879 memcpy(curr_dir + curr_dir_len, dir, len + 1);
883 curr_dir_len = clean_fname(curr_dir, 1);
889 * Reverse a push_dir() call. You must pass in an absolute path
890 * that was copied from a prior value of "curr_dir".
892 int pop_dir(char *dir)
897 curr_dir_len = strlcpy(curr_dir, dir, sizeof curr_dir);
898 if (curr_dir_len >= sizeof curr_dir)
899 curr_dir_len = sizeof curr_dir - 1;
905 * Return a quoted string with the full pathname of the indicated filename.
906 * The string " (in MODNAME)" may also be appended. The returned pointer
907 * remains valid until the next time full_fname() is called.
909 char *full_fname(const char *fn)
911 static char *result = NULL;
922 for (p2 = p1; *p2 == '/'; p2++) {}
926 if (module_id >= 0) {
928 m2 = lp_name(module_id);
930 if (p1 == curr_dir) {
931 if (!lp_use_chroot(module_id)) {
932 char *p = lp_path(module_id);
933 if (*p != '/' || p[1])
940 asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3);
945 static char partial_fname[MAXPATHLEN];
947 char *partial_dir_fname(const char *fname)
949 char *t = partial_fname;
950 int sz = sizeof partial_fname;
953 if ((fn = strrchr(fname, '/')) != NULL) {
955 if (*partial_dir != '/') {
956 int len = fn - fname;
957 strncpy(t, fname, len); /* safe */
963 if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
965 if (server_filter_list.head) {
968 len = strlen(partial_dir);
970 if (check_filter(&server_filter_list, partial_fname, 1) < 0)
973 if (check_filter(&server_filter_list, partial_fname, 0) < 0)
977 return partial_fname;
980 /* If no --partial-dir option was specified, we don't need to do anything
981 * (the partial-dir is essentially '.'), so just return success. */
982 int handle_partial_dir(const char *fname, int create)
986 if (fname != partial_fname)
988 if (!create && *partial_dir == '/')
990 if (!(fn = strrchr(partial_fname, '/')))
997 int statret = do_lstat(dir, &st);
998 if (statret == 0 && !S_ISDIR(st.st_mode)) {
999 if (do_unlink(dir) < 0)
1003 if (statret < 0 && do_mkdir(dir, 0700) < 0)
1013 * Determine if a symlink points outside the current directory tree.
1014 * This is considered "unsafe" because e.g. when mirroring somebody
1015 * else's machine it might allow them to establish a symlink to
1016 * /etc/passwd, and then read it through a web server.
1018 * Null symlinks and absolute symlinks are always unsafe.
1020 * Basically here we are concerned with symlinks whose target contains
1021 * "..", because this might cause us to walk back up out of the
1022 * transferred directory. We are not allowed to go back up and
1025 * @param dest Target of the symlink in question.
1027 * @param src Top source directory currently applicable. Basically this
1028 * is the first parameter to rsync in a simple invocation, but it's
1029 * modified by flist.c in slightly complex ways.
1031 * @retval True if unsafe
1032 * @retval False is unsafe
1036 int unsafe_symlink(const char *dest, const char *src)
1038 const char *name, *slash;
1041 /* all absolute and null symlinks are unsafe */
1042 if (!dest || !*dest || *dest == '/')
1045 /* find out what our safety margin is */
1046 for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
1047 if (strncmp(name, "../", 3) == 0) {
1049 } else if (strncmp(name, "./", 2) == 0) {
1055 if (strcmp(name, "..") == 0)
1058 for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) {
1059 if (strncmp(name, "../", 3) == 0) {
1060 /* if at any point we go outside the current directory
1061 then stop - it is unsafe */
1064 } else if (strncmp(name, "./", 2) == 0) {
1070 if (strcmp(name, "..") == 0)
1076 /* Return the int64 number as a string. If the --human-readable option was
1077 * specified, we may output the number in K, M, or G units. We can return
1078 * up to 4 buffers at a time. */
1079 char *human_num(int64 num)
1081 static char bufs[4][128]; /* more than enough room */
1082 static unsigned int n;
1085 n = (n + 1) % (sizeof bufs / sizeof bufs[0]);
1087 if (human_readable) {
1089 int mult = human_readable == 1 ? 1024 : 1000;
1091 if (num > mult*mult*mult) {
1092 dnum = (double)num / (mult*mult*mult);
1094 } else if (num > mult*mult) {
1095 dnum = (double)num / (mult*mult);
1097 } else if (num > mult) {
1098 dnum = (double)num / mult;
1102 sprintf(bufs[n], "%.2f%c", dnum, units);
1107 s = bufs[n] + sizeof bufs[0] - 1;
1113 *--s = (num % 10) + '0';
1119 /* Return the double number as a string. If the --human-readable option was
1120 * specified, we may output the number in K, M, or G units. We use a buffer
1121 * from human_num() to return our result. */
1122 char *human_dnum(double dnum, int decimal_digits)
1124 char *buf = human_num(dnum);
1125 int len = strlen(buf);
1126 if (isdigit(*(uchar*)(buf+len-1))) {
1127 /* There's extra room in buf prior to the start of the num. */
1128 buf -= decimal_digits + 1;
1129 snprintf(buf, len + decimal_digits + 2, "%.*f", decimal_digits, dnum);
1135 * Return the date and time as a string
1137 char *timestring(time_t t)
1139 static char TimeBuf[200];
1140 struct tm *tm = localtime(&t);
1143 #ifdef HAVE_STRFTIME
1144 strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm);
1146 strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf);
1149 if ((p = strchr(TimeBuf, '\n')) != NULL)
1157 * Sleep for a specified number of milliseconds.
1159 * Always returns TRUE. (In the future it might return FALSE if
1165 struct timeval tval, t1, t2;
1167 gettimeofday(&t1, NULL);
1170 tval.tv_sec = (t-tdiff)/1000;
1171 tval.tv_usec = 1000*((t-tdiff)%1000);
1174 select(0,NULL,NULL, NULL, &tval);
1176 gettimeofday(&t2, NULL);
1177 tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
1178 (t2.tv_usec - t1.tv_usec)/1000;
1186 * Determine if two file modification times are equivalent (either
1187 * exact or in the modification timestamp window established by
1190 * @retval 0 if the times should be treated as the same
1192 * @retval +1 if the first is later
1194 * @retval -1 if the 2nd is later
1196 int cmp_modtime(time_t file1, time_t file2)
1198 if (file2 > file1) {
1199 if (file2 - file1 <= modify_window)
1203 if (file1 - file2 <= modify_window)
1213 This routine is a trick to immediately catch errors when debugging
1214 with insure. A xterm with a gdb is popped up when insure catches
1215 a error. It is Linux specific.
1217 int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
1223 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'",
1224 getpid(), getpid(), getpid());
1228 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
1229 fn = dlsym(h, "_Insure_trap_error");
1232 ret = fn(a1, a2, a3, a4, a5, a6);
1243 #define MALLOC_MAX 0x40000000
1245 void *_new_array(unsigned int size, unsigned long num)
1247 if (num >= MALLOC_MAX/size)
1249 return malloc(size * num);
1252 void *_realloc_array(void *ptr, unsigned int size, unsigned long num)
1254 if (num >= MALLOC_MAX/size)
1256 /* No realloc should need this, but just in case... */
1258 return malloc(size * num);
1259 return realloc(ptr, size * num);
1262 /* Take a filename and filename length and return the most significant
1263 * filename suffix we can find. This ignores suffixes such as "~",
1264 * ".bak", ".orig", ".~1~", etc. */
1265 const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr)
1267 const char *suf, *s;
1271 /* One or more dots at the start aren't a suffix. */
1272 while (fn_len && *fn == '.') fn++, fn_len--;
1274 /* Ignore the ~ in a "foo~" filename. */
1275 if (fn_len > 1 && fn[fn_len-1] == '~')
1276 fn_len--, had_tilde = True;
1280 /* Assume we don't find an suffix. */
1284 /* Find the last significant suffix. */
1285 for (s = fn + fn_len; fn_len > 1; ) {
1286 while (*--s != '.' && s != fn) {}
1289 s_len = fn_len - (s - fn);
1292 if (strcmp(s+1, "bak") == 0
1293 || strcmp(s+1, "old") == 0)
1295 } else if (s_len == 5) {
1296 if (strcmp(s+1, "orig") == 0)
1298 } else if (s_len > 2 && had_tilde
1299 && s[1] == '~' && isdigit(*(uchar*)(s+2)))
1305 /* Determine if the suffix is all digits. */
1306 for (s++, s_len--; s_len > 0; s++, s_len--) {
1307 if (!isdigit(*(uchar*)s))
1310 /* An all-digit suffix may not be that signficant. */
1317 /* This is an implementation of the Levenshtein distance algorithm. It
1318 * was implemented to avoid needing a two-dimensional matrix (to save
1319 * memory). It was also tweaked to try to factor in the ASCII distance
1320 * between changed characters as a minor distance quantity. The normal
1321 * Levenshtein units of distance (each signifying a single change between
1322 * the two strings) are defined as a "UNIT". */
1324 #define UNIT (1 << 16)
1326 uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2)
1328 uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc;
1332 if (!len1 || !len2) {
1337 for (i1 = 0, cost = 0; i1 < len1; i1++)
1339 return (int32)len1 * UNIT + cost;
1342 for (i2 = 0; i2 < len2; i2++)
1343 a[i2] = (i2+1) * UNIT;
1345 for (i1 = 0; i1 < len1; i1++) {
1347 above = (i1+1) * UNIT;
1348 for (i2 = 0; i2 < len2; i2++) {
1350 if ((cost = *((uchar*)s1+i1) - *((uchar*)s2+i2)) != 0) {
1356 diag_inc = diag + cost;
1357 left_inc = left + UNIT + *((uchar*)s1+i1);
1358 above_inc = above + UNIT + *((uchar*)s2+i2);
1359 a[i2] = above = left < above
1360 ? (left_inc < diag_inc ? left_inc : diag_inc)
1361 : (above_inc < diag_inc ? above_inc : diag_inc);