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