Allow sigaction() to be used even if sigprocmask() isn't around
[rsync/rsync.git] / util.c
CommitLineData
1960e228 1/* -*- c-file-style: "linux" -*-
5cb37436
WD
2 *
3 * Copyright (C) 1996-2000 by Andrew Tridgell
0ecfbf27
MP
4 * Copyright (C) Paul Mackerras 1996
5 * Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
5cb37436 6 *
0ecfbf27
MP
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.
5cb37436 11 *
0ecfbf27
MP
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.
5cb37436 16 *
0ecfbf27
MP
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 */
c627d613 21
ac13ad10 22/**
0ecfbf27 23 * @file
ac13ad10 24 *
5cb37436 25 * Utilities used in rsync
ac13ad10 26 **/
c627d613 27
c627d613
AT
28#include "rsync.h"
29
c7c11a0d 30extern int verbose;
bc6ebcd2
WD
31extern int dry_run;
32extern int module_id;
33extern int modify_window;
7e43da81 34extern int relative_paths;
e175fb07 35extern int human_readable;
a7260c40 36extern char *partial_dir;
7842418b 37extern struct filter_list_struct server_filter_list;
c7c11a0d 38
0ecfbf27
MP
39int sanitize_paths = 0;
40
41
f0359dd0 42
ac13ad10 43/**
0ecfbf27
MP
44 * Set a fd into nonblocking mode
45 **/
f0359dd0
AT
46void set_nonblocking(int fd)
47{
48 int val;
49
0ecfbf27 50 if ((val = fcntl(fd, F_GETFL, 0)) == -1)
f0359dd0
AT
51 return;
52 if (!(val & NONBLOCK_FLAG)) {
53 val |= NONBLOCK_FLAG;
54 fcntl(fd, F_SETFL, val);
55 }
56}
57
ac13ad10 58/**
0ecfbf27
MP
59 * Set a fd into blocking mode
60 **/
36349ea0
AT
61void set_blocking(int fd)
62{
63 int val;
64
0ecfbf27 65 if ((val = fcntl(fd, F_GETFL, 0)) == -1)
36349ea0
AT
66 return;
67 if (val & NONBLOCK_FLAG) {
68 val &= ~NONBLOCK_FLAG;
69 fcntl(fd, F_SETFL, val);
70 }
71}
72
f0359dd0 73
ac13ad10 74/**
0ecfbf27
MP
75 * Create a file descriptor pair - like pipe() but use socketpair if
76 * possible (because of blocking issues on pipes).
5cb37436 77 *
0ecfbf27 78 * Always set non-blocking.
f0359dd0 79 */
08f15335
AT
80int fd_pair(int fd[2])
81{
f0359dd0
AT
82 int ret;
83
4f5b0756 84#ifdef HAVE_SOCKETPAIR
f0359dd0 85 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
08f15335 86#else
f0359dd0 87 ret = pipe(fd);
08f15335 88#endif
f0359dd0
AT
89
90 if (ret == 0) {
91 set_nonblocking(fd[0]);
92 set_nonblocking(fd[1]);
93 }
0ecfbf27 94
f0359dd0 95 return ret;
08f15335
AT
96}
97
98
0ecfbf27 99void print_child_argv(char **cmd)
5ad0e46f 100{
1bbd10fe 101 rprintf(FINFO, "opening connection using ");
5ad0e46f
MP
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"
108 "0123456789"
109 ",.-_=+@/") != strlen(*cmd)) {
785abd48 110 rprintf(FINFO, "\"%s\" ", *cmd);
5ad0e46f 111 } else {
785abd48 112 rprintf(FINFO, "%s ", *cmd);
5ad0e46f
MP
113 }
114 }
115 rprintf(FINFO, "\n");
116}
117
118
c627d613
AT
119void out_of_memory(char *str)
120{
c284f34a
WD
121 rprintf(FERROR, "ERROR: out of memory in %s\n", str);
122 exit_cleanup(RERR_MALLOC);
575f2fca
AT
123}
124
a1f99493 125void overflow_exit(char *str)
575f2fca 126{
c284f34a
WD
127 rprintf(FERROR, "ERROR: buffer overflow in %s\n", str);
128 exit_cleanup(RERR_MALLOC);
c627d613
AT
129}
130
131
c627d613 132
25007999 133int set_modtime(char *fname, time_t modtime, mode_t mode)
c627d613 134{
25007999
WD
135#if !defined HAVE_LUTIMES || !defined HAVE_UTIMES
136 if (S_ISLNK(mode))
137 return 1;
138#endif
139
404e813c
MP
140 if (verbose > 2) {
141 rprintf(FINFO, "set modtime of %s to (%ld) %s",
785abd48 142 fname, (long)modtime,
404e813c
MP
143 asctime(localtime(&modtime)));
144 }
5cb37436 145
15778afb
WD
146 if (dry_run)
147 return 0;
148
31e12522 149 {
25007999
WD
150#ifdef HAVE_UTIMES
151 struct timeval t[2];
152 t[0].tv_sec = time(NULL);
153 t[0].tv_usec = 0;
154 t[1].tv_sec = modtime;
155 t[1].tv_usec = 0;
156# ifdef HAVE_LUTIMES
157 if (S_ISLNK(mode))
158 return lutimes(fname, t);
159# endif
160 return utimes(fname, t);
161#elif defined HAVE_UTIMBUF
5cb37436 162 struct utimbuf tbuf;
31e12522
AT
163 tbuf.actime = time(NULL);
164 tbuf.modtime = modtime;
165 return utime(fname,&tbuf);
4f5b0756 166#elif defined HAVE_UTIME
31e12522
AT
167 time_t t[2];
168 t[0] = time(NULL);
169 t[1] = modtime;
170 return utime(fname,t);
c627d613 171#else
25007999 172#error No file-time-modification routine found!
c627d613 173#endif
31e12522 174 }
c627d613 175}
94481d91 176
720b47f2 177
ac13ad10
MP
178/**
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
181 on the umask
182**/
0ecfbf27 183int create_directory_path(char *fname, int base_umask)
6574b4f7 184{
6574b4f7
AT
185 char *p;
186
c284f34a
WD
187 while (*fname == '/')
188 fname++;
189 while (strncmp(fname, "./", 2) == 0)
190 fname += 2;
6574b4f7
AT
191
192 p = fname;
c284f34a 193 while ((p = strchr(p,'/')) != NULL) {
6574b4f7 194 *p = 0;
5cb37436 195 do_mkdir(fname, 0777 & ~base_umask);
6574b4f7
AT
196 *p = '/';
197 p++;
198 }
199 return 0;
200}
950ab32d
AT
201
202
ac13ad10
MP
203/**
204 * Write @p len bytes at @p ptr to descriptor @p desc, retrying if
205 * interrupted.
206 *
207 * @retval len upon success
208 *
209 * @retval <0 write's (negative) error code
210 *
211 * Derived from GNU C's cccp.c.
212 */
6566d205 213int full_write(int desc, char *ptr, size_t len)
950ab32d
AT
214{
215 int total_written;
5cb37436 216
950ab32d
AT
217 total_written = 0;
218 while (len > 0) {
5c1b7bfd 219 int written = write(desc, ptr, len);
950ab32d 220 if (written < 0) {
950ab32d
AT
221 if (errno == EINTR)
222 continue;
950ab32d
AT
223 return written;
224 }
225 total_written += written;
226 ptr += written;
227 len -= written;
228 }
229 return total_written;
230}
231
950ab32d 232
ac13ad10
MP
233/**
234 * Read @p len bytes at @p ptr from descriptor @p desc, retrying if
235 * interrupted.
236 *
237 * @retval >0 the actual number of bytes read
238 *
239 * @retval 0 for EOF
240 *
241 * @retval <0 for an error.
242 *
243 * Derived from GNU C's cccp.c. */
9dd891bb 244static int safe_read(int desc, char *ptr, size_t len)
950ab32d
AT
245{
246 int n_chars;
5cb37436 247
9dd891bb 248 if (len == 0)
950ab32d 249 return len;
5cb37436 250
950ab32d
AT
251 do {
252 n_chars = read(desc, ptr, len);
253 } while (n_chars < 0 && errno == EINTR);
5cb37436 254
950ab32d
AT
255 return n_chars;
256}
257
258
ac13ad10
MP
259/** Copy a file.
260 *
3e13004b
WD
261 * This is used in conjunction with the --temp-dir, --backup, and
262 * --copy-dest options. */
63cf5ae7 263int copy_file(const char *source, const char *dest, mode_t mode)
950ab32d
AT
264{
265 int ifd;
266 int ofd;
267 char buf[1024 * 8];
268 int len; /* Number of bytes read into `buf'. */
269
8c9fd200 270 ifd = do_open(source, O_RDONLY, 0);
950ab32d 271 if (ifd == -1) {
d62bcc17 272 rsyserr(FERROR, errno, "open %s", full_fname(source));
950ab32d
AT
273 return -1;
274 }
275
c7c11a0d 276 if (robust_unlink(dest) && errno != ENOENT) {
d62bcc17 277 rsyserr(FERROR, errno, "unlink %s", full_fname(dest));
950ab32d
AT
278 return -1;
279 }
280
31e12522 281 ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
c46ded46 282 if (ofd == -1) {
d62bcc17 283 rsyserr(FERROR, errno, "open %s", full_fname(dest));
950ab32d
AT
284 close(ifd);
285 return -1;
286 }
287
5cb37436 288 while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
950ab32d 289 if (full_write(ofd, buf, len) < 0) {
d62bcc17 290 rsyserr(FERROR, errno, "write %s", full_fname(dest));
950ab32d
AT
291 close(ifd);
292 close(ofd);
293 return -1;
294 }
295 }
296
8b602edd 297 if (len < 0) {
d62bcc17 298 rsyserr(FERROR, errno, "read %s", full_fname(source));
8b602edd
WD
299 close(ifd);
300 close(ofd);
301 return -1;
302 }
303
9f27cd8c 304 if (close(ifd) < 0) {
d62bcc17
WD
305 rsyserr(FINFO, errno, "close failed on %s",
306 full_fname(source));
9f27cd8c
WD
307 }
308
309 if (close(ofd) < 0) {
d62bcc17
WD
310 rsyserr(FERROR, errno, "close failed on %s",
311 full_fname(dest));
9f27cd8c
WD
312 return -1;
313 }
950ab32d 314
950ab32d
AT
315 return 0;
316}
feaa89c4 317
c7c11a0d
DD
318/* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
319#define MAX_RENAMES_DIGITS 3
320#define MAX_RENAMES 1000
321
ac13ad10 322/**
b4235b31
MP
323 * Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
324 * rename to <path>/.rsyncNNN instead.
325 *
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
330 * each time.
331 **/
63cf5ae7 332int robust_unlink(const char *fname)
c7c11a0d
DD
333{
334#ifndef ETXTBSY
335 return do_unlink(fname);
336#else
337 static int counter = 1;
338 int rc, pos, start;
339 char path[MAXPATHLEN];
340
341 rc = do_unlink(fname);
c284f34a 342 if (rc == 0 || errno != ETXTBSY)
c7c11a0d
DD
343 return rc;
344
c284f34a
WD
345 if ((pos = strlcpy(path, fname, MAXPATHLEN)) >= MAXPATHLEN)
346 pos = MAXPATHLEN - 1;
c7c11a0d 347
c284f34a
WD
348 while (pos > 0 && path[pos-1] != '/')
349 pos--;
5cb37436 350 pos += strlcpy(path+pos, ".rsync", MAXPATHLEN-pos);
c7c11a0d
DD
351
352 if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
353 errno = ETXTBSY;
354 return -1;
355 }
356
357 /* start where the last one left off to reduce chance of clashes */
358 start = counter;
359 do {
360 sprintf(&path[pos], "%03d", counter);
361 if (++counter >= MAX_RENAMES)
362 counter = 1;
c284f34a 363 } while ((rc = access(path, 0)) == 0 && counter != start);
c7c11a0d 364
4791825d 365 if (verbose > 0) {
c7c11a0d 366 rprintf(FINFO,"renaming %s to %s because of text busy\n",
785abd48 367 fname, path);
4791825d 368 }
c7c11a0d
DD
369
370 /* maybe we should return rename()'s exit status? Nah. */
371 if (do_rename(fname, path) != 0) {
372 errno = ETXTBSY;
373 return -1;
374 }
375 return 0;
376#endif
377}
378
630f548f 379/* Returns 0 on successful rename, 1 if we successfully copied the file
3ed8eafc
WD
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. */
383int robust_rename(char *from, char *to, char *partialptr,
384 int mode)
c7c11a0d 385{
62c9e6b3
WD
386 int tries = 4;
387
388 while (tries--) {
389 if (do_rename(from, to) == 0)
390 return 0;
391
392 switch (errno) {
393#ifdef ETXTBSY
394 case ETXTBSY:
395 if (robust_unlink(to) != 0)
396 return -1;
397 break;
c7c11a0d 398#endif
62c9e6b3 399 case EXDEV:
3ed8eafc
WD
400 if (partialptr) {
401 if (!handle_partial_dir(partialptr,PDIR_CREATE))
402 return -1;
403 to = partialptr;
404 }
62c9e6b3
WD
405 if (copy_file(from, to, mode) != 0)
406 return -2;
407 do_unlink(from);
630f548f 408 return 1;
62c9e6b3
WD
409 default:
410 return -1;
411 }
412 }
413 return -1;
feaa89c4 414}
3ba62a83
AT
415
416
417static pid_t all_pids[10];
418static int num_pids;
419
4cf64834 420/** Fork and record the pid of the child. **/
3ba62a83
AT
421pid_t do_fork(void)
422{
423 pid_t newpid = fork();
5cb37436 424
4cf64834 425 if (newpid != 0 && newpid != -1) {
3ba62a83
AT
426 all_pids[num_pids++] = newpid;
427 }
428 return newpid;
429}
430
4cf64834
MP
431/**
432 * Kill all children.
433 *
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.
440 **/
3ba62a83
AT
441void kill_all(int sig)
442{
443 int i;
4cf64834
MP
444
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];
450
451 if (p == getpid())
452 continue;
453 if (p <= 0)
454 continue;
455
456 kill(p, sig);
3ba62a83
AT
457 }
458}
9486289c 459
4cf64834 460
ac13ad10 461/** Turn a user name into a uid */
8ef4ffd6
AT
462int name_to_uid(char *name, uid_t *uid)
463{
464 struct passwd *pass;
b5bd5542
WD
465 if (!name || !*name)
466 return 0;
8ef4ffd6
AT
467 pass = getpwnam(name);
468 if (pass) {
469 *uid = pass->pw_uid;
470 return 1;
471 }
472 return 0;
473}
474
ac13ad10 475/** Turn a group name into a gid */
8ef4ffd6
AT
476int name_to_gid(char *name, gid_t *gid)
477{
478 struct group *grp;
b5bd5542
WD
479 if (!name || !*name)
480 return 0;
8ef4ffd6
AT
481 grp = getgrnam(name);
482 if (grp) {
483 *gid = grp->gr_gid;
484 return 1;
485 }
486 return 0;
487}
488
ff8b29b8 489
ac13ad10 490/** Lock a byte range in a open file */
31593dd6 491int lock_range(int fd, int offset, int len)
0c515f17 492{
31593dd6 493 struct flock lock;
0c515f17 494
31593dd6
AT
495 lock.l_type = F_WRLCK;
496 lock.l_whence = SEEK_SET;
497 lock.l_start = offset;
498 lock.l_len = len;
499 lock.l_pid = 0;
5cb37436 500
31593dd6 501 return fcntl(fd,F_SETLK,&lock) == 0;
0c515f17 502}
874895d5 503
7842418b 504static int filter_server_path(char *arg)
4791825d
WD
505{
506 char *s;
4791825d 507
7842418b 508 if (server_filter_list.head) {
4791825d
WD
509 for (s = arg; (s = strchr(s, '/')) != NULL; ) {
510 *s = '\0';
7842418b 511 if (check_filter(&server_filter_list, arg, 1) < 0) {
4791825d
WD
512 /* We must leave arg truncated! */
513 return 1;
514 }
515 *s++ = '/';
516 }
517 }
518 return 0;
519}
874895d5 520
b7061c82
WD
521static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr,
522 int *maxargs_ptr)
874895d5 523{
b7061c82 524 char **argv = *argv_ptr;
b5bd5542 525 int argc = *argc_ptr;
b7061c82 526 int maxargs = *maxargs_ptr;
4f5b0756 527#if !defined HAVE_GLOB || !defined HAVE_GLOB_H
b7061c82
WD
528 if (argc == maxargs) {
529 maxargs += MAX_ARGS;
530 if (!(argv = realloc_array(argv, char *, maxargs)))
531 out_of_memory("glob_expand_one");
532 *argv_ptr = argv;
533 *maxargs_ptr = maxargs;
534 }
4135d091
WD
535 if (!*s)
536 s = ".";
b5bd5542 537 s = argv[argc++] = strdup(s);
7842418b 538 filter_server_path(s);
874895d5
AT
539#else
540 glob_t globbuf;
874895d5 541
b5bd5542
WD
542 if (maxargs <= argc)
543 return;
4135d091
WD
544 if (!*s)
545 s = ".";
e42c9458 546
4135d091 547 if (sanitize_paths)
1d6b8f9a 548 s = sanitize_path(NULL, s, "", 0);
84a63795
WD
549 else
550 s = strdup(s);
087bf010 551
5cb37436 552 memset(&globbuf, 0, sizeof globbuf);
7842418b 553 if (!filter_server_path(s))
4791825d 554 glob(s, 0, NULL, &globbuf);
b7061c82
WD
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");
559 *argv_ptr = argv;
560 *maxargs_ptr = maxargs;
561 }
b5bd5542
WD
562 if (globbuf.gl_pathc == 0)
563 argv[argc++] = s;
564 else {
c8933031 565 int i;
b5bd5542 566 free(s);
c8933031 567 for (i = 0; i < (int)globbuf.gl_pathc; i++) {
b5bd5542
WD
568 if (!(argv[argc++] = strdup(globbuf.gl_pathv[i])))
569 out_of_memory("glob_expand_one");
570 }
874895d5
AT
571 }
572 globfree(&globbuf);
874895d5 573#endif
b5bd5542 574 *argc_ptr = argc;
874895d5 575}
5a96ee05 576
4791825d 577/* This routine is only used in daemon mode. */
b7061c82 578void glob_expand(char *base1, char ***argv_ptr, int *argc_ptr, int *maxargs_ptr)
087bf010 579{
b7061c82 580 char *s = (*argv_ptr)[*argc_ptr];
087bf010 581 char *p, *q;
ba5e128d 582 char *base = base1;
4791825d 583 int base_len = strlen(base);
087bf010 584
b5bd5542
WD
585 if (!s || !*s)
586 return;
087bf010 587
4791825d
WD
588 if (strncmp(s, base, base_len) == 0)
589 s += base_len;
e42c9458 590
b5bd5542
WD
591 if (!(s = strdup(s)))
592 out_of_memory("glob_expand");
087bf010 593
b5bd5542
WD
594 if (asprintf(&base," %s/", base1) <= 0)
595 out_of_memory("glob_expand");
4791825d 596 base_len++;
ba5e128d 597
b5bd5542
WD
598 for (q = s; *q; q = p + base_len) {
599 if ((p = strstr(q, base)) != NULL)
600 *p = '\0'; /* split it at this point */
b7061c82 601 glob_expand_one(q, argv_ptr, argc_ptr, maxargs_ptr);
b5bd5542
WD
602 if (!p)
603 break;
087bf010
AT
604 }
605
087bf010 606 free(s);
ba5e128d 607 free(base);
087bf010 608}
5a96ee05 609
ac13ad10
MP
610/**
611 * Convert a string to lower case
612 **/
5a96ee05
AT
613void strlower(char *s)
614{
615 while (*s) {
b5bd5542
WD
616 if (isupper(*(unsigned char *)s))
617 *s = tolower(*(unsigned char *)s);
5a96ee05
AT
618 s++;
619 }
620}
e42c9458 621
368ad70e
WD
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
a8f7e4b8
WD
624 * strings + 1 (if '/' was inserted), regardless of whether the null-terminated
625 * string fits into destsize. */
368ad70e
WD
626size_t pathjoin(char *dest, size_t destsize, const char *p1, const char *p2)
627{
628 size_t len = strlcpy(dest, p1, destsize);
629 if (len < destsize - 1) {
630 if (!len || dest[len-1] != '/')
631 dest[len++] = '/';
632 if (len < destsize - 1)
633 len += strlcpy(dest + len, p2, destsize - len);
634 else {
635 dest[len] = '\0';
636 len += strlen(p2);
637 }
638 }
639 else
640 len += strlen(p2) + 1; /* Assume we'd insert a '/'. */
641 return len;
642}
643
644/* Join any number of strings together, putting them in "dest". The return
a8f7e4b8
WD
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. */
368ad70e
WD
648size_t stringjoin(char *dest, size_t destsize, ...)
649{
5cb37436 650 va_list ap;
368ad70e
WD
651 size_t len, ret = 0;
652 const char *src;
653
654 va_start(ap, destsize);
655 while (1) {
656 if (!(src = va_arg(ap, const char *)))
657 break;
658 len = strlen(src);
659 ret += len;
660 if (destsize > 1) {
661 if (len >= destsize)
662 len = destsize - 1;
663 memcpy(dest, src, len);
664 destsize -= len;
665 dest += len;
666 }
667 }
668 *dest = '\0';
669 va_end(ap);
670
671 return ret;
672}
673
1d6b8f9a
WD
674int count_dir_elements(const char *p)
675{
676 int cnt = 0, new_component = 1;
677 while (*p) {
678 if (*p++ == '/')
679 new_component = 1;
680 else if (new_component) {
681 new_component = 0;
682 cnt++;
683 }
684 }
685 return cnt;
686}
687
b92693da
WD
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 ".". */
692unsigned int clean_fname(char *name, BOOL collapse_dot_dot)
5243c216 693{
e012b94f 694 char *limit = name - 1, *t = name, *f = name;
ebdd24d6 695 int anchored;
5243c216 696
b5bd5542 697 if (!name)
3104620c 698 return 0;
5243c216 699
ebdd24d6
WD
700 if ((anchored = *f == '/') != 0)
701 *t++ = *f++;
702 while (*f) {
703 /* discard extra slashes */
704 if (*f == '/') {
705 f++;
706 continue;
5243c216 707 }
ebdd24d6
WD
708 if (*f == '.') {
709 /* discard "." dirs (but NOT a trailing '.'!) */
710 if (f[1] == '/') {
e012b94f 711 f += 2;
ebdd24d6
WD
712 continue;
713 }
714 /* collapse ".." dirs */
b92693da
WD
715 if (collapse_dot_dot
716 && f[1] == '.' && (f[2] == '/' || !f[2])) {
ebdd24d6
WD
717 char *s = t - 1;
718 if (s == name && anchored) {
719 f += 2;
720 continue;
721 }
722 while (s > limit && *--s != '/') {}
e012b94f 723 if (s != t - 1 && (s < name || *s == '/')) {
ebdd24d6
WD
724 t = s + 1;
725 f += 2;
726 continue;
727 }
f55c2dfc 728 limit = t + 2;
5243c216
AT
729 }
730 }
ebdd24d6 731 while (*f && (*t++ = *f++) != '/') {}
5243c216 732 }
ebdd24d6
WD
733
734 if (t > name+anchored && t[-1] == '/')
735 t--;
736 if (t == name)
737 *t++ = '.';
738 *t = '\0';
3104620c
WD
739
740 return t - name;
5243c216
AT
741}
742
84a63795
WD
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.
b4235b31 746 *
1d6b8f9a
WD
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.
b4235b31 750 *
1d6b8f9a
WD
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).
ac13ad10 753 *
5886edfa
WD
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.
ac13ad10 756 *
b92693da
WD
757 * We also clean the path in a manner similar to clean_fname() but with a
758 * few differences:
759 *
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 ".". */
1d6b8f9a 765char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
1b8e662a 766{
44e2e578 767 char *start, *sanp;
7e43da81 768 int rlen = 0, leave_one_dotdir = relative_paths;
84a63795
WD
769
770 if (dest != p) {
771 int plen = strlen(p);
1d6b8f9a
WD
772 if (*p == '/') {
773 if (!rootdir)
774 rootdir = lp_path(module_id);
775 rlen = strlen(rootdir);
776 depth = 0;
84a63795
WD
777 p++;
778 }
779 if (dest) {
780 if (rlen + plen + 1 >= MAXPATHLEN)
781 return NULL;
782 } else if (!(dest = new_array(char, rlen + plen + 1)))
783 out_of_memory("sanitize_path");
784 if (rlen) {
1d6b8f9a 785 memcpy(dest, rootdir, rlen);
84a63795
WD
786 if (rlen > 1)
787 dest[rlen++] = '/';
788 }
789 }
cb13abfe 790
84a63795 791 start = sanp = dest + rlen;
1b8e662a 792 while (*p != '\0') {
2d41264e
WD
793 /* discard leading or extra slashes */
794 if (*p == '/') {
795 p++;
796 continue;
797 }
b5f9e67d 798 /* this loop iterates once per filename component in p.
44e2e578 799 * both p (and sanp if the original had a slash) should
b5f9e67d
DD
800 * always be left pointing after a slash
801 */
c284f34a 802 if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
35812ea1 803 if (leave_one_dotdir && p[1])
7e43da81
WD
804 leave_one_dotdir = 0;
805 else {
806 /* skip "." component */
807 p++;
808 continue;
809 }
cb13abfe 810 }
c284f34a 811 if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
cb13abfe 812 /* ".." component followed by slash or end */
8e5f029e
WD
813 if (depth <= 0 || sanp != start) {
814 p += 2;
815 if (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 */
820 sanp--;
821 }
b5f9e67d 822 }
8e5f029e 823 continue;
1b8e662a 824 }
8e5f029e
WD
825 /* allow depth levels of .. at the beginning */
826 depth--;
827 /* move the virtual beginning to leave the .. alone */
828 start = sanp + 3;
1b8e662a 829 }
2d41264e
WD
830 /* copy one component through next slash */
831 while (*p && (*sanp++ = *p++) != '/') {}
1b8e662a 832 }
84a63795 833 if (sanp == dest) {
b5f9e67d 834 /* ended up with nothing, so put in "." component */
44e2e578 835 *sanp++ = '.';
b5f9e67d 836 }
44e2e578 837 *sanp = '\0';
1b8e662a 838
84a63795 839 return dest;
14b61c63 840}
5243c216 841
4791825d 842char curr_dir[MAXPATHLEN];
4af8fe4e 843unsigned int curr_dir_len;
5243c216 844
4e5db0ad 845/**
a16d8f2b
WD
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.
4e5db0ad 849 **/
4af8fe4e 850int push_dir(char *dir)
5243c216 851{
5243c216 852 static int initialised;
4af8fe4e 853 unsigned int len;
5243c216
AT
854
855 if (!initialised) {
856 initialised = 1;
5cb37436 857 getcwd(curr_dir, sizeof curr_dir - 1);
4af8fe4e 858 curr_dir_len = strlen(curr_dir);
5243c216
AT
859 }
860
4af8fe4e
WD
861 if (!dir) /* this call was probably just to initialize */
862 return 0;
c226b7c2 863
4af8fe4e
WD
864 len = strlen(dir);
865 if (len == 1 && *dir == '.')
866 return 1;
5243c216 867
4af8fe4e
WD
868 if ((*dir == '/' ? len : curr_dir_len + 1 + len) >= sizeof curr_dir)
869 return 0;
870
871 if (chdir(dir))
872 return 0;
5243c216
AT
873
874 if (*dir == '/') {
4af8fe4e
WD
875 memcpy(curr_dir, dir, len + 1);
876 curr_dir_len = len;
877 } else {
878 curr_dir[curr_dir_len++] = '/';
879 memcpy(curr_dir + curr_dir_len, dir, len + 1);
880 curr_dir_len += len;
5243c216
AT
881 }
882
b92693da 883 curr_dir_len = clean_fname(curr_dir, 1);
5243c216 884
4af8fe4e 885 return 1;
5243c216
AT
886}
887
a16d8f2b
WD
888/**
889 * Reverse a push_dir() call. You must pass in an absolute path
890 * that was copied from a prior value of "curr_dir".
891 **/
5243c216
AT
892int pop_dir(char *dir)
893{
4af8fe4e
WD
894 if (chdir(dir))
895 return 0;
5243c216 896
4af8fe4e
WD
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;
5243c216 900
4af8fe4e 901 return 1;
5243c216 902}
aa9b77a5 903
eb61be19
WD
904/**
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.
908 **/
9a5ade18 909char *full_fname(const char *fn)
eb61be19 910{
eb61be19
WD
911 static char *result = NULL;
912 char *m1, *m2, *m3;
913 char *p1, *p2;
914
915 if (result)
916 free(result);
917
918 if (*fn == '/')
919 p1 = p2 = "";
920 else {
921 p1 = curr_dir;
bc83274a
WD
922 for (p2 = p1; *p2 == '/'; p2++) {}
923 if (*p2)
924 p2 = "/";
eb61be19
WD
925 }
926 if (module_id >= 0) {
927 m1 = " (in ";
928 m2 = lp_name(module_id);
929 m3 = ")";
bc83274a 930 if (p1 == curr_dir) {
eb61be19
WD
931 if (!lp_use_chroot(module_id)) {
932 char *p = lp_path(module_id);
933 if (*p != '/' || p[1])
934 p1 += strlen(p);
935 }
eb61be19 936 }
eb61be19
WD
937 } else
938 m1 = m2 = m3 = "";
939
940 asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3);
941
942 return result;
943}
944
a7260c40
WD
945static char partial_fname[MAXPATHLEN];
946
947char *partial_dir_fname(const char *fname)
948{
949 char *t = partial_fname;
950 int sz = sizeof partial_fname;
951 const char *fn;
952
953 if ((fn = strrchr(fname, '/')) != NULL) {
954 fn++;
955 if (*partial_dir != '/') {
956 int len = fn - fname;
957 strncpy(t, fname, len); /* safe */
958 t += len;
959 sz -= len;
960 }
961 } else
962 fn = fname;
963 if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
964 return NULL;
5aa7b20a
WD
965 if (server_filter_list.head) {
966 static int len;
967 if (!len)
968 len = strlen(partial_dir);
969 t[len] = '\0';
970 if (check_filter(&server_filter_list, partial_fname, 1) < 0)
971 return NULL;
972 t[len] = '/';
973 if (check_filter(&server_filter_list, partial_fname, 0) < 0)
974 return NULL;
975 }
a7260c40
WD
976
977 return partial_fname;
978}
979
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. */
982int handle_partial_dir(const char *fname, int create)
983{
984 char *fn, *dir;
985
986 if (fname != partial_fname)
987 return 1;
988 if (!create && *partial_dir == '/')
989 return 1;
990 if (!(fn = strrchr(partial_fname, '/')))
991 return 1;
992
993 *fn = '\0';
994 dir = partial_fname;
995 if (create) {
996 STRUCT_STAT st;
a7260c40 997 int statret = do_lstat(dir, &st);
a7260c40
WD
998 if (statret == 0 && !S_ISDIR(st.st_mode)) {
999 if (do_unlink(dir) < 0)
1000 return 0;
1001 statret = -1;
1002 }
1003 if (statret < 0 && do_mkdir(dir, 0700) < 0)
1004 return 0;
1005 } else
1006 do_rmdir(dir);
1007 *fn = '/';
1008
1009 return 1;
1010}
1011
ac13ad10
MP
1012/**
1013 * Determine if a symlink points outside the current directory tree.
036e70b0
MP
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.
1017 *
4e5db0ad
MP
1018 * Null symlinks and absolute symlinks are always unsafe.
1019 *
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
1023 * reenter.
1024 *
036e70b0
MP
1025 * @param dest Target of the symlink in question.
1026 *
25d34a5c 1027 * @param src Top source directory currently applicable. Basically this
036e70b0 1028 * is the first parameter to rsync in a simple invocation, but it's
25d34a5c 1029 * modified by flist.c in slightly complex ways.
036e70b0
MP
1030 *
1031 * @retval True if unsafe
1032 * @retval False is unsafe
4e5db0ad
MP
1033 *
1034 * @sa t_unsafe.c
ac13ad10 1035 **/
7afa3a4a 1036int unsafe_symlink(const char *dest, const char *src)
4b957c22 1037{
7afa3a4a 1038 const char *name, *slash;
4b957c22
AT
1039 int depth = 0;
1040
1041 /* all absolute and null symlinks are unsafe */
b5bd5542
WD
1042 if (!dest || !*dest || *dest == '/')
1043 return 1;
4b957c22
AT
1044
1045 /* find out what our safety margin is */
7afa3a4a
WD
1046 for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
1047 if (strncmp(name, "../", 3) == 0) {
c284f34a 1048 depth = 0;
7afa3a4a 1049 } else if (strncmp(name, "./", 2) == 0) {
4b957c22
AT
1050 /* nothing */
1051 } else {
1052 depth++;
1053 }
1054 }
7afa3a4a
WD
1055 if (strcmp(name, "..") == 0)
1056 depth = 0;
4b957c22 1057
7afa3a4a
WD
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 */
1062 if (--depth < 0)
1063 return 1;
1064 } else if (strncmp(name, "./", 2) == 0) {
4b957c22
AT
1065 /* nothing */
1066 } else {
1067 depth++;
1068 }
4b957c22 1069 }
7afa3a4a
WD
1070 if (strcmp(name, "..") == 0)
1071 depth--;
4b957c22 1072
4b957c22
AT
1073 return (depth < 0);
1074}
375a4556 1075
e175fb07
WD
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. */
1079char *human_num(int64 num)
1080{
1081 static char bufs[4][128]; /* more than enough room */
1082 static unsigned int n;
1083 char *s;
1084
1085 n = (n + 1) % (sizeof bufs / sizeof bufs[0]);
1086
1087 if (human_readable) {
1088 char units = '\0';
1089 int mult = human_readable == 1 ? 1024 : 1000;
1090 double dnum = 0;
1091 if (num > mult*mult*mult) {
1092 dnum = (double)num / (mult*mult*mult);
1093 units = 'G';
1094 } else if (num > mult*mult) {
1095 dnum = (double)num / (mult*mult);
1096 units = 'M';
1097 } else if (num > mult) {
1098 dnum = (double)num / mult;
1099 units = 'K';
1100 }
1101 if (units) {
1102 sprintf(bufs[n], "%.2f%c", dnum, units);
1103 return bufs[n];
1104 }
1105 }
1106
1107 s = bufs[n] + sizeof bufs[0] - 1;
1108 *s = '\0';
1109
1110 if (!num)
1111 *--s = '0';
1112 while (num) {
1113 *--s = (num % 10) + '0';
1114 num /= 10;
1115 }
1116 return s;
1117}
1118
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. */
1122char *human_dnum(double dnum, int decimal_digits)
1123{
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);
1130 }
1131 return buf;
1132}
f7632fc6 1133
ac13ad10 1134/**
b4235b31
MP
1135 * Return the date and time as a string
1136 **/
f7632fc6
AT
1137char *timestring(time_t t)
1138{
1139 static char TimeBuf[200];
1140 struct tm *tm = localtime(&t);
1141
4f5b0756 1142#ifdef HAVE_STRFTIME
5cb37436 1143 strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm);
f7632fc6 1144#else
5cb37436 1145 strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf);
f7632fc6
AT
1146#endif
1147
1148 if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
1149 TimeBuf[strlen(TimeBuf)-1] = 0;
1150 }
1151
1152 return(TimeBuf);
1153}
1154
9ec16c83 1155
e1bd49d6
MP
1156/**
1157 * Sleep for a specified number of milliseconds.
1158 *
1159 * Always returns TRUE. (In the future it might return FALSE if
1160 * interrupted.)
1161 **/
1162int msleep(int t)
9ec16c83 1163{
c284f34a
WD
1164 int tdiff = 0;
1165 struct timeval tval, t1, t2;
9ec16c83
AT
1166
1167 gettimeofday(&t1, NULL);
5cb37436 1168
9ec16c83
AT
1169 while (tdiff < t) {
1170 tval.tv_sec = (t-tdiff)/1000;
1171 tval.tv_usec = 1000*((t-tdiff)%1000);
5cb37436 1172
9ec16c83
AT
1173 errno = 0;
1174 select(0,NULL,NULL, NULL, &tval);
1175
1176 gettimeofday(&t2, NULL);
5cb37436 1177 tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
9ec16c83
AT
1178 (t2.tv_usec - t1.tv_usec)/1000;
1179 }
e1bd49d6
MP
1180
1181 return True;
9ec16c83
AT
1182}
1183
1184
ac13ad10
MP
1185/**
1186 * Determine if two file modification times are equivalent (either
1187 * exact or in the modification timestamp window established by
1188 * --modify-window).
1189 *
1190 * @retval 0 if the times should be treated as the same
1191 *
1192 * @retval +1 if the first is later
1193 *
1194 * @retval -1 if the 2nd is later
1195 **/
5b56cc19
AT
1196int cmp_modtime(time_t file1, time_t file2)
1197{
5b56cc19 1198 if (file2 > file1) {
bc6ebcd2
WD
1199 if (file2 - file1 <= modify_window)
1200 return 0;
5b56cc19
AT
1201 return -1;
1202 }
bc6ebcd2
WD
1203 if (file1 - file2 <= modify_window)
1204 return 0;
5b56cc19
AT
1205 return 1;
1206}
1207
1208
1209#ifdef __INSURE__XX
0f8f98c8
AT
1210#include <dlfcn.h>
1211
ac13ad10
MP
1212/**
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.
1216**/
0f8f98c8
AT
1217int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
1218{
1219 static int (*fn)();
1220 int ret;
8950ac03 1221 char *cmd;
0f8f98c8 1222
5cb37436 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'",
0f8f98c8
AT
1224 getpid(), getpid(), getpid());
1225
1226 if (!fn) {
1227 static void *h;
1228 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
1229 fn = dlsym(h, "_Insure_trap_error");
1230 }
1231
1232 ret = fn(a1, a2, a3, a4, a5, a6);
1233
1234 system(cmd);
1235
8950ac03
AT
1236 free(cmd);
1237
0f8f98c8
AT
1238 return ret;
1239}
1240#endif
58cadc86
WD
1241
1242
1243#define MALLOC_MAX 0x40000000
1244
1245void *_new_array(unsigned int size, unsigned long num)
1246{
1247 if (num >= MALLOC_MAX/size)
1248 return NULL;
1249 return malloc(size * num);
1250}
1251
1252void *_realloc_array(void *ptr, unsigned int size, unsigned long num)
1253{
1254 if (num >= MALLOC_MAX/size)
1255 return NULL;
1256 /* No realloc should need this, but just in case... */
1257 if (!ptr)
1258 return malloc(size * num);
1259 return realloc(ptr, size * num);
1260}
e64ae6d7
WD
1261
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. */
1265const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr)
1266{
1267 const char *suf, *s;
1268 BOOL had_tilde;
1269 int s_len;
1270
1271 /* One or more dots at the start aren't a suffix. */
1272 while (fn_len && *fn == '.') fn++, fn_len--;
1273
1274 /* Ignore the ~ in a "foo~" filename. */
1275 if (fn_len > 1 && fn[fn_len-1] == '~')
1276 fn_len--, had_tilde = True;
1277 else
1278 had_tilde = False;
1279
1280 /* Assume we don't find an suffix. */
1281 suf = "";
1282 *len_ptr = 0;
1283
1284 /* Find the last significant suffix. */
1285 for (s = fn + fn_len; fn_len > 1; ) {
1286 while (*--s != '.' && s != fn) {}
1287 if (s == fn)
1288 break;
1289 s_len = fn_len - (s - fn);
1290 fn_len = s - fn;
6012eaa1 1291 if (s_len == 4) {
e64ae6d7
WD
1292 if (strcmp(s+1, "bak") == 0
1293 || strcmp(s+1, "old") == 0)
1294 continue;
6012eaa1 1295 } else if (s_len == 5) {
e64ae6d7
WD
1296 if (strcmp(s+1, "orig") == 0)
1297 continue;
1298 } else if (s_len > 2 && had_tilde
73253721 1299 && s[1] == '~' && isdigit(*(uchar*)(s+2)))
e64ae6d7
WD
1300 continue;
1301 *len_ptr = s_len;
1302 suf = s;
1303 if (s_len == 1)
1304 break;
1305 /* Determine if the suffix is all digits. */
1306 for (s++, s_len--; s_len > 0; s++, s_len--) {
73253721 1307 if (!isdigit(*(uchar*)s))
e64ae6d7
WD
1308 return suf;
1309 }
1310 /* An all-digit suffix may not be that signficant. */
1311 s = suf;
1312 }
1313
1314 return suf;
1315}
1316
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". */
1323
1324#define UNIT (1 << 16)
1325
1326uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2)
1327{
1328 uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc;
1329 int32 cost;
1330 int i1, i2;
1331
1332 if (!len1 || !len2) {
1333 if (!len1) {
1334 s1 = s2;
1335 len1 = len2;
1336 }
1337 for (i1 = 0, cost = 0; i1 < len1; i1++)
1338 cost += s1[i1];
1339 return (int32)len1 * UNIT + cost;
1340 }
1341
1342 for (i2 = 0; i2 < len2; i2++)
1343 a[i2] = (i2+1) * UNIT;
1344
1345 for (i1 = 0; i1 < len1; i1++) {
1346 diag = i1 * UNIT;
1347 above = (i1+1) * UNIT;
1348 for (i2 = 0; i2 < len2; i2++) {
1349 left = a[i2];
1350 if ((cost = *((uchar*)s1+i1) - *((uchar*)s2+i2)) != 0) {
1351 if (cost < 0)
1352 cost = UNIT - cost;
1353 else
1354 cost = UNIT + cost;
1355 }
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);
1362 diag = left;
1363 }
1364 }
1365
1366 return a[len2-1];
1367}