Tweaked some whitespace to match the latest version from autoconf.
[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;
e9357a2d 36extern mode_t orig_umask;
a7260c40 37extern char *partial_dir;
7842418b 38extern struct filter_list_struct server_filter_list;
c7c11a0d 39
0ecfbf27
MP
40int sanitize_paths = 0;
41
42
f0359dd0 43
ac13ad10 44/**
0ecfbf27
MP
45 * Set a fd into nonblocking mode
46 **/
f0359dd0
AT
47void set_nonblocking(int fd)
48{
49 int val;
50
0ecfbf27 51 if ((val = fcntl(fd, F_GETFL, 0)) == -1)
f0359dd0
AT
52 return;
53 if (!(val & NONBLOCK_FLAG)) {
54 val |= NONBLOCK_FLAG;
55 fcntl(fd, F_SETFL, val);
56 }
57}
58
ac13ad10 59/**
0ecfbf27
MP
60 * Set a fd into blocking mode
61 **/
36349ea0
AT
62void set_blocking(int fd)
63{
64 int val;
65
0ecfbf27 66 if ((val = fcntl(fd, F_GETFL, 0)) == -1)
36349ea0
AT
67 return;
68 if (val & NONBLOCK_FLAG) {
69 val &= ~NONBLOCK_FLAG;
70 fcntl(fd, F_SETFL, val);
71 }
72}
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
0ecfbf27 98void print_child_argv(char **cmd)
5ad0e46f 99{
1bbd10fe 100 rprintf(FINFO, "opening connection using ");
5ad0e46f
MP
101 for (; *cmd; cmd++) {
102 /* Look for characters that ought to be quoted. This
103 * is not a great quoting algorithm, but it's
104 * sufficient for a log message. */
105 if (strspn(*cmd, "abcdefghijklmnopqrstuvwxyz"
106 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
107 "0123456789"
108 ",.-_=+@/") != strlen(*cmd)) {
785abd48 109 rprintf(FINFO, "\"%s\" ", *cmd);
5ad0e46f 110 } else {
785abd48 111 rprintf(FINFO, "%s ", *cmd);
5ad0e46f
MP
112 }
113 }
114 rprintf(FINFO, "\n");
115}
116
c627d613
AT
117void out_of_memory(char *str)
118{
c284f34a
WD
119 rprintf(FERROR, "ERROR: out of memory in %s\n", str);
120 exit_cleanup(RERR_MALLOC);
575f2fca
AT
121}
122
a1f99493 123void overflow_exit(char *str)
575f2fca 124{
c284f34a
WD
125 rprintf(FERROR, "ERROR: buffer overflow in %s\n", str);
126 exit_cleanup(RERR_MALLOC);
c627d613
AT
127}
128
25007999 129int set_modtime(char *fname, time_t modtime, mode_t mode)
c627d613 130{
25007999
WD
131#if !defined HAVE_LUTIMES || !defined HAVE_UTIMES
132 if (S_ISLNK(mode))
133 return 1;
134#endif
135
404e813c
MP
136 if (verbose > 2) {
137 rprintf(FINFO, "set modtime of %s to (%ld) %s",
785abd48 138 fname, (long)modtime,
404e813c
MP
139 asctime(localtime(&modtime)));
140 }
5cb37436 141
15778afb
WD
142 if (dry_run)
143 return 0;
144
31e12522 145 {
25007999
WD
146#ifdef HAVE_UTIMES
147 struct timeval t[2];
148 t[0].tv_sec = time(NULL);
149 t[0].tv_usec = 0;
150 t[1].tv_sec = modtime;
151 t[1].tv_usec = 0;
152# ifdef HAVE_LUTIMES
153 if (S_ISLNK(mode))
154 return lutimes(fname, t);
155# endif
156 return utimes(fname, t);
157#elif defined HAVE_UTIMBUF
5cb37436 158 struct utimbuf tbuf;
31e12522
AT
159 tbuf.actime = time(NULL);
160 tbuf.modtime = modtime;
161 return utime(fname,&tbuf);
4f5b0756 162#elif defined HAVE_UTIME
31e12522
AT
163 time_t t[2];
164 t[0] = time(NULL);
165 t[1] = modtime;
166 return utime(fname,t);
c627d613 167#else
25007999 168#error No file-time-modification routine found!
c627d613 169#endif
31e12522 170 }
c627d613 171}
94481d91 172
e9357a2d
WD
173/* This creates a new directory with default permissions. Since there
174 * might be some directory-default permissions affecting this, we can't
175 * force the permissions directly using the original umask and mkdir(). */
176int mkdir_defmode(char *fname)
177{
178 int ret;
179
180 umask(orig_umask);
181 ret = do_mkdir(fname, ACCESSPERMS);
182 umask(0);
183
184 return ret;
185}
186
85c41757
WD
187/* Create any necessary directories in fname. Any missing directories are
188 * created with default permissions. */
e9357a2d 189int create_directory_path(char *fname)
6574b4f7 190{
6574b4f7 191 char *p;
85c41757 192 int ret = 0;
6574b4f7 193
c284f34a
WD
194 while (*fname == '/')
195 fname++;
196 while (strncmp(fname, "./", 2) == 0)
197 fname += 2;
6574b4f7 198
85c41757 199 umask(orig_umask);
6574b4f7 200 p = fname;
c284f34a 201 while ((p = strchr(p,'/')) != NULL) {
85c41757
WD
202 *p = '\0';
203 if (do_mkdir(fname, ACCESSPERMS) < 0 && errno != EEXIST)
204 ret = -1;
205 *p++ = '/';
6574b4f7 206 }
85c41757
WD
207 umask(0);
208
209 return ret;
6574b4f7 210}
950ab32d 211
ac13ad10
MP
212/**
213 * Write @p len bytes at @p ptr to descriptor @p desc, retrying if
214 * interrupted.
215 *
216 * @retval len upon success
217 *
218 * @retval <0 write's (negative) error code
219 *
220 * Derived from GNU C's cccp.c.
221 */
6566d205 222int full_write(int desc, char *ptr, size_t len)
950ab32d
AT
223{
224 int total_written;
5cb37436 225
950ab32d
AT
226 total_written = 0;
227 while (len > 0) {
5c1b7bfd 228 int written = write(desc, ptr, len);
950ab32d 229 if (written < 0) {
950ab32d
AT
230 if (errno == EINTR)
231 continue;
950ab32d
AT
232 return written;
233 }
234 total_written += written;
235 ptr += written;
236 len -= written;
237 }
238 return total_written;
239}
240
ac13ad10
MP
241/**
242 * Read @p len bytes at @p ptr from descriptor @p desc, retrying if
243 * interrupted.
244 *
245 * @retval >0 the actual number of bytes read
246 *
247 * @retval 0 for EOF
248 *
249 * @retval <0 for an error.
250 *
251 * Derived from GNU C's cccp.c. */
9dd891bb 252static int safe_read(int desc, char *ptr, size_t len)
950ab32d
AT
253{
254 int n_chars;
5cb37436 255
9dd891bb 256 if (len == 0)
950ab32d 257 return len;
5cb37436 258
950ab32d
AT
259 do {
260 n_chars = read(desc, ptr, len);
261 } while (n_chars < 0 && errno == EINTR);
5cb37436 262
950ab32d
AT
263 return n_chars;
264}
265
ac13ad10
MP
266/** Copy a file.
267 *
3e13004b
WD
268 * This is used in conjunction with the --temp-dir, --backup, and
269 * --copy-dest options. */
63cf5ae7 270int copy_file(const char *source, const char *dest, mode_t mode)
950ab32d
AT
271{
272 int ifd;
273 int ofd;
274 char buf[1024 * 8];
275 int len; /* Number of bytes read into `buf'. */
276
8c9fd200 277 ifd = do_open(source, O_RDONLY, 0);
950ab32d 278 if (ifd == -1) {
d62bcc17 279 rsyserr(FERROR, errno, "open %s", full_fname(source));
950ab32d
AT
280 return -1;
281 }
282
c7c11a0d 283 if (robust_unlink(dest) && errno != ENOENT) {
d62bcc17 284 rsyserr(FERROR, errno, "unlink %s", full_fname(dest));
950ab32d
AT
285 return -1;
286 }
287
31e12522 288 ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
c46ded46 289 if (ofd == -1) {
d62bcc17 290 rsyserr(FERROR, errno, "open %s", full_fname(dest));
950ab32d
AT
291 close(ifd);
292 return -1;
293 }
294
5cb37436 295 while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
950ab32d 296 if (full_write(ofd, buf, len) < 0) {
d62bcc17 297 rsyserr(FERROR, errno, "write %s", full_fname(dest));
950ab32d
AT
298 close(ifd);
299 close(ofd);
300 return -1;
301 }
302 }
303
8b602edd 304 if (len < 0) {
d62bcc17 305 rsyserr(FERROR, errno, "read %s", full_fname(source));
8b602edd
WD
306 close(ifd);
307 close(ofd);
308 return -1;
309 }
310
9f27cd8c 311 if (close(ifd) < 0) {
d62bcc17
WD
312 rsyserr(FINFO, errno, "close failed on %s",
313 full_fname(source));
9f27cd8c
WD
314 }
315
316 if (close(ofd) < 0) {
d62bcc17
WD
317 rsyserr(FERROR, errno, "close failed on %s",
318 full_fname(dest));
9f27cd8c
WD
319 return -1;
320 }
950ab32d 321
950ab32d
AT
322 return 0;
323}
feaa89c4 324
c7c11a0d
DD
325/* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
326#define MAX_RENAMES_DIGITS 3
327#define MAX_RENAMES 1000
328
ac13ad10 329/**
b4235b31
MP
330 * Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
331 * rename to <path>/.rsyncNNN instead.
332 *
333 * Note that successive rsync runs will shuffle the filenames around a
334 * bit as long as the file is still busy; this is because this function
335 * does not know if the unlink call is due to a new file coming in, or
336 * --delete trying to remove old .rsyncNNN files, hence it renames it
337 * each time.
338 **/
63cf5ae7 339int robust_unlink(const char *fname)
c7c11a0d
DD
340{
341#ifndef ETXTBSY
342 return do_unlink(fname);
343#else
344 static int counter = 1;
345 int rc, pos, start;
346 char path[MAXPATHLEN];
347
348 rc = do_unlink(fname);
c284f34a 349 if (rc == 0 || errno != ETXTBSY)
c7c11a0d
DD
350 return rc;
351
c284f34a
WD
352 if ((pos = strlcpy(path, fname, MAXPATHLEN)) >= MAXPATHLEN)
353 pos = MAXPATHLEN - 1;
c7c11a0d 354
c284f34a
WD
355 while (pos > 0 && path[pos-1] != '/')
356 pos--;
5cb37436 357 pos += strlcpy(path+pos, ".rsync", MAXPATHLEN-pos);
c7c11a0d
DD
358
359 if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
360 errno = ETXTBSY;
361 return -1;
362 }
363
364 /* start where the last one left off to reduce chance of clashes */
365 start = counter;
366 do {
367 sprintf(&path[pos], "%03d", counter);
368 if (++counter >= MAX_RENAMES)
369 counter = 1;
c284f34a 370 } while ((rc = access(path, 0)) == 0 && counter != start);
c7c11a0d 371
4791825d 372 if (verbose > 0) {
c7c11a0d 373 rprintf(FINFO,"renaming %s to %s because of text busy\n",
785abd48 374 fname, path);
4791825d 375 }
c7c11a0d
DD
376
377 /* maybe we should return rename()'s exit status? Nah. */
378 if (do_rename(fname, path) != 0) {
379 errno = ETXTBSY;
380 return -1;
381 }
382 return 0;
383#endif
384}
385
630f548f 386/* Returns 0 on successful rename, 1 if we successfully copied the file
3ed8eafc
WD
387 * across filesystems, -2 if copy_file() failed, and -1 on other errors.
388 * If partialptr is not NULL and we need to do a copy, copy the file into
389 * the active partial-dir instead of over the destination file. */
390int robust_rename(char *from, char *to, char *partialptr,
391 int mode)
c7c11a0d 392{
62c9e6b3
WD
393 int tries = 4;
394
395 while (tries--) {
396 if (do_rename(from, to) == 0)
397 return 0;
398
399 switch (errno) {
400#ifdef ETXTBSY
401 case ETXTBSY:
402 if (robust_unlink(to) != 0)
403 return -1;
404 break;
c7c11a0d 405#endif
62c9e6b3 406 case EXDEV:
3ed8eafc
WD
407 if (partialptr) {
408 if (!handle_partial_dir(partialptr,PDIR_CREATE))
409 return -1;
410 to = partialptr;
411 }
62c9e6b3
WD
412 if (copy_file(from, to, mode) != 0)
413 return -2;
414 do_unlink(from);
630f548f 415 return 1;
62c9e6b3
WD
416 default:
417 return -1;
418 }
419 }
420 return -1;
feaa89c4 421}
3ba62a83 422
3ba62a83
AT
423static pid_t all_pids[10];
424static int num_pids;
425
4cf64834 426/** Fork and record the pid of the child. **/
3ba62a83
AT
427pid_t do_fork(void)
428{
429 pid_t newpid = fork();
5cb37436 430
4cf64834 431 if (newpid != 0 && newpid != -1) {
3ba62a83
AT
432 all_pids[num_pids++] = newpid;
433 }
434 return newpid;
435}
436
4cf64834
MP
437/**
438 * Kill all children.
439 *
440 * @todo It would be kind of nice to make sure that they are actually
441 * all our children before we kill them, because their pids may have
442 * been recycled by some other process. Perhaps when we wait for a
443 * child, we should remove it from this array. Alternatively we could
444 * perhaps use process groups, but I think that would not work on
445 * ancient Unix versions that don't support them.
446 **/
3ba62a83
AT
447void kill_all(int sig)
448{
449 int i;
4cf64834
MP
450
451 for (i = 0; i < num_pids; i++) {
452 /* Let's just be a little careful where we
453 * point that gun, hey? See kill(2) for the
454 * magic caused by negative values. */
455 pid_t p = all_pids[i];
456
457 if (p == getpid())
458 continue;
459 if (p <= 0)
460 continue;
461
462 kill(p, sig);
3ba62a83
AT
463 }
464}
9486289c 465
ac13ad10 466/** Turn a user name into a uid */
8ef4ffd6
AT
467int name_to_uid(char *name, uid_t *uid)
468{
469 struct passwd *pass;
b5bd5542
WD
470 if (!name || !*name)
471 return 0;
8ef4ffd6
AT
472 pass = getpwnam(name);
473 if (pass) {
474 *uid = pass->pw_uid;
475 return 1;
476 }
477 return 0;
478}
479
ac13ad10 480/** Turn a group name into a gid */
8ef4ffd6
AT
481int name_to_gid(char *name, gid_t *gid)
482{
483 struct group *grp;
b5bd5542
WD
484 if (!name || !*name)
485 return 0;
8ef4ffd6
AT
486 grp = getgrnam(name);
487 if (grp) {
488 *gid = grp->gr_gid;
489 return 1;
490 }
491 return 0;
492}
493
ac13ad10 494/** Lock a byte range in a open file */
31593dd6 495int lock_range(int fd, int offset, int len)
0c515f17 496{
31593dd6 497 struct flock lock;
0c515f17 498
31593dd6
AT
499 lock.l_type = F_WRLCK;
500 lock.l_whence = SEEK_SET;
501 lock.l_start = offset;
502 lock.l_len = len;
503 lock.l_pid = 0;
5cb37436 504
31593dd6 505 return fcntl(fd,F_SETLK,&lock) == 0;
0c515f17 506}
874895d5 507
7842418b 508static int filter_server_path(char *arg)
4791825d
WD
509{
510 char *s;
4791825d 511
7842418b 512 if (server_filter_list.head) {
4791825d
WD
513 for (s = arg; (s = strchr(s, '/')) != NULL; ) {
514 *s = '\0';
7842418b 515 if (check_filter(&server_filter_list, arg, 1) < 0) {
4791825d
WD
516 /* We must leave arg truncated! */
517 return 1;
518 }
519 *s++ = '/';
520 }
521 }
522 return 0;
523}
874895d5 524
b7061c82
WD
525static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr,
526 int *maxargs_ptr)
874895d5 527{
b7061c82 528 char **argv = *argv_ptr;
b5bd5542 529 int argc = *argc_ptr;
b7061c82 530 int maxargs = *maxargs_ptr;
4f5b0756 531#if !defined HAVE_GLOB || !defined HAVE_GLOB_H
b7061c82
WD
532 if (argc == maxargs) {
533 maxargs += MAX_ARGS;
534 if (!(argv = realloc_array(argv, char *, maxargs)))
535 out_of_memory("glob_expand_one");
536 *argv_ptr = argv;
537 *maxargs_ptr = maxargs;
538 }
4135d091
WD
539 if (!*s)
540 s = ".";
b5bd5542 541 s = argv[argc++] = strdup(s);
7842418b 542 filter_server_path(s);
874895d5
AT
543#else
544 glob_t globbuf;
874895d5 545
b5bd5542
WD
546 if (maxargs <= argc)
547 return;
4135d091
WD
548 if (!*s)
549 s = ".";
e42c9458 550
4135d091 551 if (sanitize_paths)
1d6b8f9a 552 s = sanitize_path(NULL, s, "", 0);
84a63795
WD
553 else
554 s = strdup(s);
087bf010 555
5cb37436 556 memset(&globbuf, 0, sizeof globbuf);
7842418b 557 if (!filter_server_path(s))
4791825d 558 glob(s, 0, NULL, &globbuf);
b7061c82
WD
559 if (MAX((int)globbuf.gl_pathc, 1) > maxargs - argc) {
560 maxargs += globbuf.gl_pathc + MAX_ARGS;
561 if (!(argv = realloc_array(argv, char *, maxargs)))
562 out_of_memory("glob_expand_one");
563 *argv_ptr = argv;
564 *maxargs_ptr = maxargs;
565 }
b5bd5542
WD
566 if (globbuf.gl_pathc == 0)
567 argv[argc++] = s;
568 else {
c8933031 569 int i;
b5bd5542 570 free(s);
c8933031 571 for (i = 0; i < (int)globbuf.gl_pathc; i++) {
b5bd5542
WD
572 if (!(argv[argc++] = strdup(globbuf.gl_pathv[i])))
573 out_of_memory("glob_expand_one");
574 }
874895d5
AT
575 }
576 globfree(&globbuf);
874895d5 577#endif
b5bd5542 578 *argc_ptr = argc;
874895d5 579}
5a96ee05 580
4791825d 581/* This routine is only used in daemon mode. */
b7061c82 582void glob_expand(char *base1, char ***argv_ptr, int *argc_ptr, int *maxargs_ptr)
087bf010 583{
b7061c82 584 char *s = (*argv_ptr)[*argc_ptr];
087bf010 585 char *p, *q;
ba5e128d 586 char *base = base1;
4791825d 587 int base_len = strlen(base);
087bf010 588
b5bd5542
WD
589 if (!s || !*s)
590 return;
087bf010 591
4791825d
WD
592 if (strncmp(s, base, base_len) == 0)
593 s += base_len;
e42c9458 594
b5bd5542
WD
595 if (!(s = strdup(s)))
596 out_of_memory("glob_expand");
087bf010 597
b5bd5542
WD
598 if (asprintf(&base," %s/", base1) <= 0)
599 out_of_memory("glob_expand");
4791825d 600 base_len++;
ba5e128d 601
b5bd5542
WD
602 for (q = s; *q; q = p + base_len) {
603 if ((p = strstr(q, base)) != NULL)
604 *p = '\0'; /* split it at this point */
b7061c82 605 glob_expand_one(q, argv_ptr, argc_ptr, maxargs_ptr);
b5bd5542
WD
606 if (!p)
607 break;
087bf010
AT
608 }
609
087bf010 610 free(s);
ba5e128d 611 free(base);
087bf010 612}
5a96ee05 613
ac13ad10
MP
614/**
615 * Convert a string to lower case
616 **/
5a96ee05
AT
617void strlower(char *s)
618{
619 while (*s) {
b5bd5542
WD
620 if (isupper(*(unsigned char *)s))
621 *s = tolower(*(unsigned char *)s);
5a96ee05
AT
622 s++;
623 }
624}
e42c9458 625
368ad70e
WD
626/* Join strings p1 & p2 into "dest" with a guaranteed '/' between them. (If
627 * p1 ends with a '/', no extra '/' is inserted.) Returns the length of both
a8f7e4b8
WD
628 * strings + 1 (if '/' was inserted), regardless of whether the null-terminated
629 * string fits into destsize. */
368ad70e
WD
630size_t pathjoin(char *dest, size_t destsize, const char *p1, const char *p2)
631{
632 size_t len = strlcpy(dest, p1, destsize);
633 if (len < destsize - 1) {
634 if (!len || dest[len-1] != '/')
635 dest[len++] = '/';
636 if (len < destsize - 1)
637 len += strlcpy(dest + len, p2, destsize - len);
638 else {
639 dest[len] = '\0';
640 len += strlen(p2);
641 }
642 }
643 else
644 len += strlen(p2) + 1; /* Assume we'd insert a '/'. */
645 return len;
646}
647
648/* Join any number of strings together, putting them in "dest". The return
a8f7e4b8
WD
649 * value is the length of all the strings, regardless of whether the null-
650 * terminated whole fits in destsize. Your list of string pointers must end
651 * with a NULL to indicate the end of the list. */
368ad70e
WD
652size_t stringjoin(char *dest, size_t destsize, ...)
653{
5cb37436 654 va_list ap;
368ad70e
WD
655 size_t len, ret = 0;
656 const char *src;
657
658 va_start(ap, destsize);
659 while (1) {
660 if (!(src = va_arg(ap, const char *)))
661 break;
662 len = strlen(src);
663 ret += len;
664 if (destsize > 1) {
665 if (len >= destsize)
666 len = destsize - 1;
667 memcpy(dest, src, len);
668 destsize -= len;
669 dest += len;
670 }
671 }
672 *dest = '\0';
673 va_end(ap);
674
675 return ret;
676}
677
1d6b8f9a
WD
678int count_dir_elements(const char *p)
679{
680 int cnt = 0, new_component = 1;
681 while (*p) {
682 if (*p++ == '/')
683 new_component = 1;
684 else if (new_component) {
685 new_component = 0;
686 cnt++;
687 }
688 }
689 return cnt;
690}
691
b92693da
WD
692/* Turns multiple adjacent slashes into a single slash, gets rid of "./"
693 * elements (but not a trailing dot dir), removes a trailing slash, and
694 * optionally collapses ".." elements (except for those at the start of the
695 * string). If the resulting name would be empty, change it into a ".". */
696unsigned int clean_fname(char *name, BOOL collapse_dot_dot)
5243c216 697{
e012b94f 698 char *limit = name - 1, *t = name, *f = name;
ebdd24d6 699 int anchored;
5243c216 700
b5bd5542 701 if (!name)
3104620c 702 return 0;
5243c216 703
ebdd24d6
WD
704 if ((anchored = *f == '/') != 0)
705 *t++ = *f++;
706 while (*f) {
707 /* discard extra slashes */
708 if (*f == '/') {
709 f++;
710 continue;
5243c216 711 }
ebdd24d6
WD
712 if (*f == '.') {
713 /* discard "." dirs (but NOT a trailing '.'!) */
714 if (f[1] == '/') {
e012b94f 715 f += 2;
ebdd24d6
WD
716 continue;
717 }
718 /* collapse ".." dirs */
b92693da
WD
719 if (collapse_dot_dot
720 && f[1] == '.' && (f[2] == '/' || !f[2])) {
ebdd24d6
WD
721 char *s = t - 1;
722 if (s == name && anchored) {
723 f += 2;
724 continue;
725 }
726 while (s > limit && *--s != '/') {}
e012b94f 727 if (s != t - 1 && (s < name || *s == '/')) {
ebdd24d6
WD
728 t = s + 1;
729 f += 2;
730 continue;
731 }
f55c2dfc 732 limit = t + 2;
5243c216
AT
733 }
734 }
ebdd24d6 735 while (*f && (*t++ = *f++) != '/') {}
5243c216 736 }
ebdd24d6
WD
737
738 if (t > name+anchored && t[-1] == '/')
739 t--;
740 if (t == name)
741 *t++ = '.';
742 *t = '\0';
3104620c
WD
743
744 return t - name;
5243c216
AT
745}
746
84a63795
WD
747/* Make path appear as if a chroot had occurred. This handles a leading
748 * "/" (either removing it or expanding it) and any leading or embedded
749 * ".." components that attempt to escape past the module's top dir.
b4235b31 750 *
1d6b8f9a
WD
751 * If dest is NULL, a buffer is allocated to hold the result. It is legal
752 * to call with the dest and the path (p) pointing to the same buffer, but
753 * rootdir will be ignored to avoid expansion of the string.
b4235b31 754 *
1d6b8f9a
WD
755 * The rootdir string contains a value to use in place of a leading slash.
756 * Specify NULL to get the default of lp_path(module_id).
ac13ad10 757 *
5886edfa
WD
758 * If depth is >= 0, it is a count of how many '..'s to allow at the start
759 * of the path. Use -1 to allow unlimited depth.
ac13ad10 760 *
b92693da
WD
761 * We also clean the path in a manner similar to clean_fname() but with a
762 * few differences:
763 *
764 * Turns multiple adjacent slashes into a single slash, gets rid of "." dir
765 * elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and
766 * ALWAYS collapses ".." elements (except for those at the start of the
767 * string up to "depth" deep). If the resulting name would be empty,
768 * change it into a ".". */
1d6b8f9a 769char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
1b8e662a 770{
44e2e578 771 char *start, *sanp;
7e43da81 772 int rlen = 0, leave_one_dotdir = relative_paths;
84a63795
WD
773
774 if (dest != p) {
775 int plen = strlen(p);
1d6b8f9a
WD
776 if (*p == '/') {
777 if (!rootdir)
778 rootdir = lp_path(module_id);
779 rlen = strlen(rootdir);
780 depth = 0;
84a63795
WD
781 p++;
782 }
783 if (dest) {
784 if (rlen + plen + 1 >= MAXPATHLEN)
785 return NULL;
786 } else if (!(dest = new_array(char, rlen + plen + 1)))
787 out_of_memory("sanitize_path");
788 if (rlen) {
1d6b8f9a 789 memcpy(dest, rootdir, rlen);
84a63795
WD
790 if (rlen > 1)
791 dest[rlen++] = '/';
792 }
793 }
cb13abfe 794
84a63795 795 start = sanp = dest + rlen;
1b8e662a 796 while (*p != '\0') {
2d41264e
WD
797 /* discard leading or extra slashes */
798 if (*p == '/') {
799 p++;
800 continue;
801 }
b5f9e67d 802 /* this loop iterates once per filename component in p.
44e2e578 803 * both p (and sanp if the original had a slash) should
b5f9e67d
DD
804 * always be left pointing after a slash
805 */
c284f34a 806 if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
35812ea1 807 if (leave_one_dotdir && p[1])
7e43da81
WD
808 leave_one_dotdir = 0;
809 else {
810 /* skip "." component */
811 p++;
812 continue;
813 }
cb13abfe 814 }
c284f34a 815 if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
cb13abfe 816 /* ".." component followed by slash or end */
8e5f029e
WD
817 if (depth <= 0 || sanp != start) {
818 p += 2;
819 if (sanp != start) {
820 /* back up sanp one level */
821 --sanp; /* now pointing at slash */
822 while (sanp > start && sanp[-1] != '/') {
823 /* skip back up to slash */
824 sanp--;
825 }
b5f9e67d 826 }
8e5f029e 827 continue;
1b8e662a 828 }
8e5f029e
WD
829 /* allow depth levels of .. at the beginning */
830 depth--;
831 /* move the virtual beginning to leave the .. alone */
832 start = sanp + 3;
1b8e662a 833 }
2d41264e
WD
834 /* copy one component through next slash */
835 while (*p && (*sanp++ = *p++) != '/') {}
1b8e662a 836 }
84a63795 837 if (sanp == dest) {
b5f9e67d 838 /* ended up with nothing, so put in "." component */
44e2e578 839 *sanp++ = '.';
b5f9e67d 840 }
44e2e578 841 *sanp = '\0';
1b8e662a 842
84a63795 843 return dest;
14b61c63 844}
5243c216 845
4791825d 846char curr_dir[MAXPATHLEN];
4af8fe4e 847unsigned int curr_dir_len;
5243c216 848
4e5db0ad 849/**
a16d8f2b
WD
850 * Like chdir(), but it keeps track of the current directory (in the
851 * global "curr_dir"), and ensures that the path size doesn't overflow.
852 * Also cleans the path using the clean_fname() function.
4e5db0ad 853 **/
4af8fe4e 854int push_dir(char *dir)
5243c216 855{
5243c216 856 static int initialised;
4af8fe4e 857 unsigned int len;
5243c216
AT
858
859 if (!initialised) {
860 initialised = 1;
5cb37436 861 getcwd(curr_dir, sizeof curr_dir - 1);
4af8fe4e 862 curr_dir_len = strlen(curr_dir);
5243c216
AT
863 }
864
4af8fe4e
WD
865 if (!dir) /* this call was probably just to initialize */
866 return 0;
c226b7c2 867
4af8fe4e
WD
868 len = strlen(dir);
869 if (len == 1 && *dir == '.')
870 return 1;
5243c216 871
4af8fe4e
WD
872 if ((*dir == '/' ? len : curr_dir_len + 1 + len) >= sizeof curr_dir)
873 return 0;
874
875 if (chdir(dir))
876 return 0;
5243c216
AT
877
878 if (*dir == '/') {
4af8fe4e
WD
879 memcpy(curr_dir, dir, len + 1);
880 curr_dir_len = len;
881 } else {
882 curr_dir[curr_dir_len++] = '/';
883 memcpy(curr_dir + curr_dir_len, dir, len + 1);
884 curr_dir_len += len;
5243c216
AT
885 }
886
b92693da 887 curr_dir_len = clean_fname(curr_dir, 1);
5243c216 888
4af8fe4e 889 return 1;
5243c216
AT
890}
891
a16d8f2b
WD
892/**
893 * Reverse a push_dir() call. You must pass in an absolute path
894 * that was copied from a prior value of "curr_dir".
895 **/
5243c216
AT
896int pop_dir(char *dir)
897{
4af8fe4e
WD
898 if (chdir(dir))
899 return 0;
5243c216 900
4af8fe4e
WD
901 curr_dir_len = strlcpy(curr_dir, dir, sizeof curr_dir);
902 if (curr_dir_len >= sizeof curr_dir)
903 curr_dir_len = sizeof curr_dir - 1;
5243c216 904
4af8fe4e 905 return 1;
5243c216 906}
aa9b77a5 907
eb61be19
WD
908/**
909 * Return a quoted string with the full pathname of the indicated filename.
910 * The string " (in MODNAME)" may also be appended. The returned pointer
911 * remains valid until the next time full_fname() is called.
912 **/
9a5ade18 913char *full_fname(const char *fn)
eb61be19 914{
eb61be19
WD
915 static char *result = NULL;
916 char *m1, *m2, *m3;
917 char *p1, *p2;
918
919 if (result)
920 free(result);
921
922 if (*fn == '/')
923 p1 = p2 = "";
924 else {
925 p1 = curr_dir;
bc83274a
WD
926 for (p2 = p1; *p2 == '/'; p2++) {}
927 if (*p2)
928 p2 = "/";
eb61be19
WD
929 }
930 if (module_id >= 0) {
931 m1 = " (in ";
932 m2 = lp_name(module_id);
933 m3 = ")";
bc83274a 934 if (p1 == curr_dir) {
eb61be19
WD
935 if (!lp_use_chroot(module_id)) {
936 char *p = lp_path(module_id);
937 if (*p != '/' || p[1])
938 p1 += strlen(p);
939 }
eb61be19 940 }
eb61be19
WD
941 } else
942 m1 = m2 = m3 = "";
943
944 asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3);
945
946 return result;
947}
948
a7260c40
WD
949static char partial_fname[MAXPATHLEN];
950
951char *partial_dir_fname(const char *fname)
952{
953 char *t = partial_fname;
954 int sz = sizeof partial_fname;
955 const char *fn;
956
957 if ((fn = strrchr(fname, '/')) != NULL) {
958 fn++;
959 if (*partial_dir != '/') {
960 int len = fn - fname;
961 strncpy(t, fname, len); /* safe */
962 t += len;
963 sz -= len;
964 }
965 } else
966 fn = fname;
967 if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
968 return NULL;
5aa7b20a
WD
969 if (server_filter_list.head) {
970 static int len;
971 if (!len)
972 len = strlen(partial_dir);
973 t[len] = '\0';
974 if (check_filter(&server_filter_list, partial_fname, 1) < 0)
975 return NULL;
976 t[len] = '/';
977 if (check_filter(&server_filter_list, partial_fname, 0) < 0)
978 return NULL;
979 }
a7260c40
WD
980
981 return partial_fname;
982}
983
984/* If no --partial-dir option was specified, we don't need to do anything
985 * (the partial-dir is essentially '.'), so just return success. */
986int handle_partial_dir(const char *fname, int create)
987{
988 char *fn, *dir;
989
990 if (fname != partial_fname)
991 return 1;
992 if (!create && *partial_dir == '/')
993 return 1;
994 if (!(fn = strrchr(partial_fname, '/')))
995 return 1;
996
997 *fn = '\0';
998 dir = partial_fname;
999 if (create) {
1000 STRUCT_STAT st;
a7260c40 1001 int statret = do_lstat(dir, &st);
a7260c40
WD
1002 if (statret == 0 && !S_ISDIR(st.st_mode)) {
1003 if (do_unlink(dir) < 0)
1004 return 0;
1005 statret = -1;
1006 }
1007 if (statret < 0 && do_mkdir(dir, 0700) < 0)
1008 return 0;
1009 } else
1010 do_rmdir(dir);
1011 *fn = '/';
1012
1013 return 1;
1014}
1015
ac13ad10
MP
1016/**
1017 * Determine if a symlink points outside the current directory tree.
036e70b0
MP
1018 * This is considered "unsafe" because e.g. when mirroring somebody
1019 * else's machine it might allow them to establish a symlink to
1020 * /etc/passwd, and then read it through a web server.
1021 *
4e5db0ad
MP
1022 * Null symlinks and absolute symlinks are always unsafe.
1023 *
1024 * Basically here we are concerned with symlinks whose target contains
1025 * "..", because this might cause us to walk back up out of the
1026 * transferred directory. We are not allowed to go back up and
1027 * reenter.
1028 *
036e70b0
MP
1029 * @param dest Target of the symlink in question.
1030 *
25d34a5c 1031 * @param src Top source directory currently applicable. Basically this
036e70b0 1032 * is the first parameter to rsync in a simple invocation, but it's
25d34a5c 1033 * modified by flist.c in slightly complex ways.
036e70b0
MP
1034 *
1035 * @retval True if unsafe
1036 * @retval False is unsafe
4e5db0ad
MP
1037 *
1038 * @sa t_unsafe.c
ac13ad10 1039 **/
7afa3a4a 1040int unsafe_symlink(const char *dest, const char *src)
4b957c22 1041{
7afa3a4a 1042 const char *name, *slash;
4b957c22
AT
1043 int depth = 0;
1044
1045 /* all absolute and null symlinks are unsafe */
b5bd5542
WD
1046 if (!dest || !*dest || *dest == '/')
1047 return 1;
4b957c22
AT
1048
1049 /* find out what our safety margin is */
7afa3a4a
WD
1050 for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
1051 if (strncmp(name, "../", 3) == 0) {
c284f34a 1052 depth = 0;
7afa3a4a 1053 } else if (strncmp(name, "./", 2) == 0) {
4b957c22
AT
1054 /* nothing */
1055 } else {
1056 depth++;
1057 }
1058 }
7afa3a4a
WD
1059 if (strcmp(name, "..") == 0)
1060 depth = 0;
4b957c22 1061
7afa3a4a
WD
1062 for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) {
1063 if (strncmp(name, "../", 3) == 0) {
1064 /* if at any point we go outside the current directory
1065 then stop - it is unsafe */
1066 if (--depth < 0)
1067 return 1;
1068 } else if (strncmp(name, "./", 2) == 0) {
4b957c22
AT
1069 /* nothing */
1070 } else {
1071 depth++;
1072 }
4b957c22 1073 }
7afa3a4a
WD
1074 if (strcmp(name, "..") == 0)
1075 depth--;
4b957c22 1076
4b957c22
AT
1077 return (depth < 0);
1078}
375a4556 1079
e175fb07
WD
1080/* Return the int64 number as a string. If the --human-readable option was
1081 * specified, we may output the number in K, M, or G units. We can return
1082 * up to 4 buffers at a time. */
1083char *human_num(int64 num)
1084{
1085 static char bufs[4][128]; /* more than enough room */
1086 static unsigned int n;
1087 char *s;
1088
1089 n = (n + 1) % (sizeof bufs / sizeof bufs[0]);
1090
1091 if (human_readable) {
1092 char units = '\0';
7794db7c 1093 int mult = human_readable == 1 ? 1000 : 1024;
e175fb07
WD
1094 double dnum = 0;
1095 if (num > mult*mult*mult) {
1096 dnum = (double)num / (mult*mult*mult);
1097 units = 'G';
1098 } else if (num > mult*mult) {
1099 dnum = (double)num / (mult*mult);
1100 units = 'M';
1101 } else if (num > mult) {
1102 dnum = (double)num / mult;
1103 units = 'K';
1104 }
1105 if (units) {
1106 sprintf(bufs[n], "%.2f%c", dnum, units);
1107 return bufs[n];
1108 }
1109 }
1110
1111 s = bufs[n] + sizeof bufs[0] - 1;
1112 *s = '\0';
1113
1114 if (!num)
1115 *--s = '0';
1116 while (num) {
1117 *--s = (num % 10) + '0';
1118 num /= 10;
1119 }
1120 return s;
1121}
1122
1123/* Return the double number as a string. If the --human-readable option was
1124 * specified, we may output the number in K, M, or G units. We use a buffer
1125 * from human_num() to return our result. */
1126char *human_dnum(double dnum, int decimal_digits)
1127{
1128 char *buf = human_num(dnum);
1129 int len = strlen(buf);
1130 if (isdigit(*(uchar*)(buf+len-1))) {
1131 /* There's extra room in buf prior to the start of the num. */
1132 buf -= decimal_digits + 1;
1133 snprintf(buf, len + decimal_digits + 2, "%.*f", decimal_digits, dnum);
1134 }
1135 return buf;
1136}
f7632fc6 1137
ac13ad10 1138/**
b4235b31
MP
1139 * Return the date and time as a string
1140 **/
f7632fc6
AT
1141char *timestring(time_t t)
1142{
1143 static char TimeBuf[200];
1144 struct tm *tm = localtime(&t);
afa73c75 1145 char *p;
f7632fc6 1146
4f5b0756 1147#ifdef HAVE_STRFTIME
5cb37436 1148 strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm);
f7632fc6 1149#else
5cb37436 1150 strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf);
f7632fc6
AT
1151#endif
1152
afa73c75
WD
1153 if ((p = strchr(TimeBuf, '\n')) != NULL)
1154 *p = '\0';
f7632fc6 1155
afa73c75 1156 return TimeBuf;
f7632fc6
AT
1157}
1158
e1bd49d6
MP
1159/**
1160 * Sleep for a specified number of milliseconds.
1161 *
1162 * Always returns TRUE. (In the future it might return FALSE if
1163 * interrupted.)
1164 **/
1165int msleep(int t)
9ec16c83 1166{
c284f34a
WD
1167 int tdiff = 0;
1168 struct timeval tval, t1, t2;
9ec16c83
AT
1169
1170 gettimeofday(&t1, NULL);
5cb37436 1171
9ec16c83
AT
1172 while (tdiff < t) {
1173 tval.tv_sec = (t-tdiff)/1000;
1174 tval.tv_usec = 1000*((t-tdiff)%1000);
5cb37436 1175
9ec16c83
AT
1176 errno = 0;
1177 select(0,NULL,NULL, NULL, &tval);
1178
1179 gettimeofday(&t2, NULL);
5cb37436 1180 tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
9ec16c83
AT
1181 (t2.tv_usec - t1.tv_usec)/1000;
1182 }
e1bd49d6
MP
1183
1184 return True;
9ec16c83
AT
1185}
1186
c2b54076
WD
1187/* Determine if two time_t values are equivalent (either exact, or in
1188 * the modification timestamp window established by --modify-window).
ac13ad10
MP
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 **/
c2b54076 1196int cmp_time(time_t file1, time_t file2)
5b56cc19 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 1241
58cadc86
WD
1242#define MALLOC_MAX 0x40000000
1243
1244void *_new_array(unsigned int size, unsigned long num)
1245{
1246 if (num >= MALLOC_MAX/size)
1247 return NULL;
1248 return malloc(size * num);
1249}
1250
1251void *_realloc_array(void *ptr, unsigned int size, unsigned long num)
1252{
1253 if (num >= MALLOC_MAX/size)
1254 return NULL;
1255 /* No realloc should need this, but just in case... */
1256 if (!ptr)
1257 return malloc(size * num);
1258 return realloc(ptr, size * num);
1259}
e64ae6d7
WD
1260
1261/* Take a filename and filename length and return the most significant
1262 * filename suffix we can find. This ignores suffixes such as "~",
1263 * ".bak", ".orig", ".~1~", etc. */
1264const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr)
1265{
1266 const char *suf, *s;
1267 BOOL had_tilde;
1268 int s_len;
1269
1270 /* One or more dots at the start aren't a suffix. */
1271 while (fn_len && *fn == '.') fn++, fn_len--;
1272
1273 /* Ignore the ~ in a "foo~" filename. */
1274 if (fn_len > 1 && fn[fn_len-1] == '~')
1275 fn_len--, had_tilde = True;
1276 else
1277 had_tilde = False;
1278
1279 /* Assume we don't find an suffix. */
1280 suf = "";
1281 *len_ptr = 0;
1282
1283 /* Find the last significant suffix. */
1284 for (s = fn + fn_len; fn_len > 1; ) {
1285 while (*--s != '.' && s != fn) {}
1286 if (s == fn)
1287 break;
1288 s_len = fn_len - (s - fn);
1289 fn_len = s - fn;
6012eaa1 1290 if (s_len == 4) {
e64ae6d7
WD
1291 if (strcmp(s+1, "bak") == 0
1292 || strcmp(s+1, "old") == 0)
1293 continue;
6012eaa1 1294 } else if (s_len == 5) {
e64ae6d7
WD
1295 if (strcmp(s+1, "orig") == 0)
1296 continue;
1297 } else if (s_len > 2 && had_tilde
73253721 1298 && s[1] == '~' && isdigit(*(uchar*)(s+2)))
e64ae6d7
WD
1299 continue;
1300 *len_ptr = s_len;
1301 suf = s;
1302 if (s_len == 1)
1303 break;
1304 /* Determine if the suffix is all digits. */
1305 for (s++, s_len--; s_len > 0; s++, s_len--) {
73253721 1306 if (!isdigit(*(uchar*)s))
e64ae6d7
WD
1307 return suf;
1308 }
1309 /* An all-digit suffix may not be that signficant. */
1310 s = suf;
1311 }
1312
1313 return suf;
1314}
1315
1316/* This is an implementation of the Levenshtein distance algorithm. It
1317 * was implemented to avoid needing a two-dimensional matrix (to save
1318 * memory). It was also tweaked to try to factor in the ASCII distance
1319 * between changed characters as a minor distance quantity. The normal
1320 * Levenshtein units of distance (each signifying a single change between
1321 * the two strings) are defined as a "UNIT". */
1322
1323#define UNIT (1 << 16)
1324
1325uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2)
1326{
1327 uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc;
1328 int32 cost;
1329 int i1, i2;
1330
1331 if (!len1 || !len2) {
1332 if (!len1) {
1333 s1 = s2;
1334 len1 = len2;
1335 }
1336 for (i1 = 0, cost = 0; i1 < len1; i1++)
1337 cost += s1[i1];
1338 return (int32)len1 * UNIT + cost;
1339 }
1340
1341 for (i2 = 0; i2 < len2; i2++)
1342 a[i2] = (i2+1) * UNIT;
1343
1344 for (i1 = 0; i1 < len1; i1++) {
1345 diag = i1 * UNIT;
1346 above = (i1+1) * UNIT;
1347 for (i2 = 0; i2 < len2; i2++) {
1348 left = a[i2];
1349 if ((cost = *((uchar*)s1+i1) - *((uchar*)s2+i2)) != 0) {
1350 if (cost < 0)
1351 cost = UNIT - cost;
1352 else
1353 cost = UNIT + cost;
1354 }
1355 diag_inc = diag + cost;
1356 left_inc = left + UNIT + *((uchar*)s1+i1);
1357 above_inc = above + UNIT + *((uchar*)s2+i2);
1358 a[i2] = above = left < above
1359 ? (left_inc < diag_inc ? left_inc : diag_inc)
1360 : (above_inc < diag_inc ? above_inc : diag_inc);
1361 diag = left;
1362 }
1363 }
1364
1365 return a[len2-1];
1366}
c2b54076
WD
1367
1368#define BB_SLOT_SIZE (16*1024) /* Desired size in bytes */
1369#define BB_PER_SLOT_BITS (BB_SLOT_SIZE * 8) /* Number of bits per slot */
1370#define BB_PER_SLOT_INTS (BB_SLOT_SIZE / 4) /* Number of int32s per slot */
1371
1372struct bitbag {
1373 uint32 **bits;
1374 int slot_cnt;
1375};
1376
1377struct bitbag *bitbag_create(int max_ndx)
1378{
1379 struct bitbag *bb = new(struct bitbag);
1380 bb->slot_cnt = (max_ndx + BB_PER_SLOT_BITS - 1) / BB_PER_SLOT_BITS;
1381
1382 if (!(bb->bits = (uint32**)calloc(bb->slot_cnt, sizeof (uint32*))))
1383 out_of_memory("bitbag_create");
1384
1385 return bb;
1386}
1387
1388void bitbag_set_bit(struct bitbag *bb, int ndx)
1389{
1390 int slot = ndx / BB_PER_SLOT_BITS;
1391 ndx %= BB_PER_SLOT_BITS;
1392
1393 if (!bb->bits[slot]) {
1394 if (!(bb->bits[slot] = (uint32*)calloc(BB_PER_SLOT_INTS, 4)))
1395 out_of_memory("bitbag_set_bit");
1396 }
1397
1398 bb->bits[slot][ndx/32] |= 1u << (ndx % 32);
1399}
1400
1401#if 0 /* not needed yet */
1402void bitbag_clear_bit(struct bitbag *bb, int ndx)
1403{
1404 int slot = ndx / BB_PER_SLOT_BITS;
1405 ndx %= BB_PER_SLOT_BITS;
1406
1407 if (!bb->bits[slot])
1408 return;
1409
1410 bb->bits[slot][ndx/32] &= ~(1u << (ndx % 32));
1411}
1412
1413int bitbag_check_bit(struct bitbag *bb, int ndx)
1414{
1415 int slot = ndx / BB_PER_SLOT_BITS;
1416 ndx %= BB_PER_SLOT_BITS;
1417
1418 if (!bb->bits[slot])
1419 return 0;
1420
1421 return bb->bits[slot][ndx/32] & (1u << (ndx % 32)) ? 1 : 0;
1422}
1423#endif
1424
1425/* Call this with -1 to start checking from 0. Returns -1 at the end. */
1426int bitbag_next_bit(struct bitbag *bb, int after)
1427{
1428 uint32 bits, mask;
1429 int i, ndx = after + 1;
1430 int slot = ndx / BB_PER_SLOT_BITS;
1431 ndx %= BB_PER_SLOT_BITS;
1432
1433 mask = (1u << (ndx % 32)) - 1;
1434 for (i = ndx / 32; slot < bb->slot_cnt; slot++, i = mask = 0) {
1435 if (!bb->bits[slot])
1436 continue;
1437 for ( ; i < BB_PER_SLOT_INTS; i++, mask = 0) {
1438 if (!(bits = bb->bits[slot][i] & ~mask))
1439 continue;
1440 /* The xor magic figures out the lowest enabled bit in
1441 * bits, and the switch quickly computes log2(bit). */
1442 switch (bits ^ (bits & (bits-1))) {
1443#define LOG2(n) case 1u << n: return slot*BB_PER_SLOT_BITS + i*32 + n
1444 LOG2(0); LOG2(1); LOG2(2); LOG2(3);
1445 LOG2(4); LOG2(5); LOG2(6); LOG2(7);
1446 LOG2(8); LOG2(9); LOG2(10); LOG2(11);
1447 LOG2(12); LOG2(13); LOG2(14); LOG2(15);
1448 LOG2(16); LOG2(17); LOG2(18); LOG2(19);
1449 LOG2(20); LOG2(21); LOG2(22); LOG2(23);
1450 LOG2(24); LOG2(25); LOG2(26); LOG2(27);
1451 LOG2(28); LOG2(29); LOG2(30); LOG2(31);
1452 }
1453 return -1; /* impossible... */
1454 }
1455 }
1456
1457 return -1;
1458}