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