X-Git-Url: http://sjero.net/git/?a=blobdiff_plain;f=src%2Futils.c;h=cd1e645d42e7968ec4eb5d8dfdf5d9400b818e5a;hb=f3d3a50a5697957befaf94cb44797234a68068c3;hp=2c6fd784570ed187ed54f424cd743716d06443a4;hpb=1365950c01a87e8ede70da4d3937d379e3050d13;p=wget diff --git a/src/utils.c b/src/utils.c index 2c6fd784..cd1e645d 100644 --- a/src/utils.c +++ b/src/utils.c @@ -59,6 +59,27 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ # include #endif +/* Needed for run_with_timeout. */ +#undef USE_SIGNAL_TIMEOUT +#ifdef HAVE_SIGNAL_H +# include +#endif +#ifdef HAVE_SETJMP_H +# include +#endif +/* If sigsetjmp is a macro, configure won't pick it up. */ +#ifdef sigsetjmp +# define HAVE_SIGSETJMP +#endif +#ifdef HAVE_SIGNAL +# ifdef HAVE_SIGSETJMP +# define USE_SIGNAL_TIMEOUT +# endif +# ifdef HAVE_SIGBLOCK +# define USE_SIGNAL_TIMEOUT +# endif +#endif + #include "wget.h" #include "utils.h" #include "fnmatch.h" @@ -466,126 +487,6 @@ fork_to_background (void) } #endif /* not WINDOWS */ -/* Resolve "." and ".." elements of PATH by destructively modifying - PATH. "." is resolved by removing that path element, and ".." is - resolved by removing the preceding path element. Leading and - trailing slashes are preserved. - - Return non-zero if any changes have been made. - - For example, "a/b/c/./../d/.." will yield "a/b/". More exhaustive - test examples are provided below. If you change anything in this - function, run test_path_simplify to make sure you haven't broken a - test case. - - A previous version of this function was based on path_simplify() - from GNU Bash, but it has been rewritten for Wget 1.8.1. */ - -int -path_simplify (char *path) -{ - int change = 0; - char *p, *end; - - if (path[0] == '/') - ++path; /* preserve the leading '/'. */ - - p = path; - end = p + strlen (p) + 1; /* position past the terminating zero. */ - - while (1) - { - again: - /* P should point to the beginning of a path element. */ - - if (*p == '.' && (*(p + 1) == '/' || *(p + 1) == '\0')) - { - /* Handle "./foo" by moving "foo" two characters to the - left. */ - if (*(p + 1) == '/') - { - change = 1; - memmove (p, p + 2, end - p); - end -= 2; - goto again; - } - else - { - change = 1; - *p = '\0'; - break; - } - } - else if (*p == '.' && *(p + 1) == '.' - && (*(p + 2) == '/' || *(p + 2) == '\0')) - { - /* Handle "../foo" by moving "foo" one path element to the - left. */ - char *b = p; /* not p-1 because P can equal PATH */ - - /* Backtrack by one path element, but not past the beginning - of PATH. */ - - /* foo/bar/../baz */ - /* ^ p */ - /* ^ b */ - - if (b > path) - { - /* Move backwards until B hits the beginning of the - previous path element or the beginning of path. */ - for (--b; b > path && *(b - 1) != '/'; b--) - ; - } - - change = 1; - if (*(p + 2) == '/') - { - memmove (b, p + 3, end - (p + 3)); - end -= (p + 3) - b; - p = b; - } - else - { - *b = '\0'; - break; - } - - goto again; - } - else if (*p == '/') - { - /* Remove empty path elements. Not mandated by rfc1808 et - al, but empty path elements are not all that useful, and - the rest of Wget might not deal with them well. */ - char *q = p; - while (*q == '/') - ++q; - change = 1; - if (*q == '\0') - { - *p = '\0'; - break; - } - memmove (p, q, end - q); - end -= q - p; - goto again; - } - - /* Skip to the next path element. */ - while (*p && *p != '/') - ++p; - if (*p == '\0') - break; - - /* Make sure P points to the beginning of the next path element, - which is location after the slash. */ - ++p; - } - - return change; -} - /* "Touch" FILE, i.e. make its atime and mtime equal to the time specified with TM. */ void @@ -699,6 +600,7 @@ make_directory (const char *directory) { int quit = 0; int i; + int ret = 0; char *dir; /* Make a copy of dir, to be able to write to it. Otherwise, the @@ -714,18 +616,19 @@ make_directory (const char *directory) if (!dir[i]) quit = 1; dir[i] = '\0'; - /* Check whether the directory already exists. */ + /* Check whether the directory already exists. Allow creation of + of intermediate directories to fail, as the initial path components + are not necessarily directories! */ if (!file_exists_p (dir)) - { - if (mkdir (dir, 0777) < 0) - return -1; - } + ret = mkdir (dir, 0777); + else + ret = 0; if (quit) break; else dir[i] = '/'; } - return 0; + return ret; } /* Merge BASE with FILE. BASE can be a directory or a file name, FILE @@ -910,6 +813,31 @@ suffix (const char *str) return NULL; } +/* Return non-zero if FNAME ends with a typical HTML suffix. The + following (case-insensitive) suffixes are presumed to be HTML files: + + html + htm + ?html (`?' matches one character) + + #### CAVEAT. This is not necessarily a good indication that FNAME + refers to a file that contains HTML! */ +int +has_html_suffix_p (const char *fname) +{ + char *suf; + + if ((suf = suffix (fname)) == NULL) + return 0; + if (!strcasecmp (suf, "html")) + return 1; + if (!strcasecmp (suf, "htm")) + return 1; + if (suf[0] && !strcasecmp (suf + 1, "html")) + return 1; + return 0; +} + /* Read a line from FP and return the pointer to freshly allocated storage. The stoarage space is obtained through malloc() and should be freed with free() when it is no longer needed. @@ -1774,6 +1702,49 @@ determine_screen_width (void) #endif /* TIOCGWINSZ */ } +/* Return a random number between 0 and MAX-1, inclusive. + + If MAX is greater than the value of RAND_MAX+1 on the system, the + returned value will be in the range [0, RAND_MAX]. This may be + fixed in a future release. + + The random number generator is seeded automatically the first time + it is called. + + This uses rand() for portability. It has been suggested that + random() offers better randomness, but this is not required for + Wget, so I chose to go for simplicity and use rand + unconditionally. */ + +int +random_number (int max) +{ + static int seeded; + double bounded; + int rnd; + + if (!seeded) + { + srand (time (NULL)); + seeded = 1; + } + rnd = rand (); + + /* On systems that don't define RAND_MAX, assume it to be 2**15 - 1, + and enforce that assumption by masking other bits. */ +#ifndef RAND_MAX +# define RAND_MAX 32767 + rnd &= RAND_MAX; +#endif + + /* This is equivalent to rand() % max, but uses the high-order bits + for better randomness on architecture where rand() is implemented + using a simple congruential generator. */ + + bounded = (double)max * rnd / (RAND_MAX + 1.0); + return (int)bounded; +} + #if 0 /* A debugging function for checking whether an MD5 library works. */ @@ -1807,96 +1778,73 @@ debug_test_md5 (char *buf) return res; } #endif + +/* Implementation of run_with_timeout, a generic timeout handler for + systems with Unix-like signal handling. */ +#ifdef HAVE_SIGSETJMP +#define SETJMP(env) sigsetjmp (env, 1) -#if 0 -/* Debugging and testing support for path_simplify. */ +static sigjmp_buf run_with_timeout_env; -/* Debug: run path_simplify on PATH and return the result in a new - string. Useful for calling from the debugger. */ -static char * -ps (char *path) +static RETSIGTYPE +abort_run_with_timeout (int sig) { - char *copy = xstrdup (path); - path_simplify (copy); - return copy; + assert (sig == SIGALRM); + siglongjmp (run_with_timeout_env, -1); } +#else /* not HAVE_SIGSETJMP */ +#define SETJMP(env) setjmp (env) -static void -run_test (char *test, char *expected_result, int expected_change) +static jmp_buf run_with_timeout_env; + +static RETSIGTYPE +abort_run_with_timeout (int sig) { - char *test_copy = xstrdup (test); - int modified = path_simplify (test_copy); + assert (sig == SIGALRM); + /* We don't have siglongjmp to preserve the set of blocked signals; + if we longjumped out of the handler at this point, SIGALRM would + remain blocked. We must unblock it manually. */ + int mask = siggetmask (); + mask &= ~sigmask(SIGALRM); + sigsetmask (mask); - if (0 != strcmp (test_copy, expected_result)) - { - printf ("Failed path_simplify(\"%s\"): expected \"%s\", got \"%s\".\n", - test, expected_result, test_copy); - } - if (modified != expected_change) - { - if (expected_change == 1) - printf ("Expected no modification with path_simplify(\"%s\").\n", - test); - else - printf ("Expected modification with path_simplify(\"%s\").\n", - test); - } - xfree (test_copy); + /* Now it's safe to longjump. */ + longjmp (run_with_timeout_env, -1); } +#endif /* not HAVE_SIGSETJMP */ -static void -test_path_simplify (void) -{ - static struct { - char *test, *result; - int should_modify; - } tests[] = { - { "", "", 0 }, - { ".", "", 1 }, - { "..", "", 1 }, - { "foo", "foo", 0 }, - { "foo/bar", "foo/bar", 0 }, - { "foo///bar", "foo/bar", 1 }, - { "foo/.", "foo/", 1 }, - { "foo/./", "foo/", 1 }, - { "foo./", "foo./", 0 }, - { "foo/../bar", "bar", 1 }, - { "foo/../bar/", "bar/", 1 }, - { "foo/bar/..", "foo/", 1 }, - { "foo/bar/../x", "foo/x", 1 }, - { "foo/bar/../x/", "foo/x/", 1 }, - { "foo/..", "", 1 }, - { "foo/../..", "", 1 }, - { "a/b/../../c", "c", 1 }, - { "./a/../b", "b", 1 } - }; - int i; +int +run_with_timeout (long timeout, void (*fun) (void *), void *arg) +{ +#ifndef USE_SIGNAL_TIMEOUT + fun (arg); + return 0; +#else + int saved_errno; - for (i = 0; i < ARRAY_SIZE (tests); i++) + if (timeout == 0) { - char *test = tests[i].test; - char *expected_result = tests[i].result; - int expected_change = tests[i].should_modify; - run_test (test, expected_result, expected_change); + fun (arg); + return 0; } - /* Now run all the tests with a leading slash before the test case, - to prove that the slash is being preserved. */ - for (i = 0; i < ARRAY_SIZE (tests); i++) + signal (SIGALRM, abort_run_with_timeout); + if (SETJMP (run_with_timeout_env) != 0) { - char *test, *expected_result; - int expected_change = tests[i].should_modify; - - test = xmalloc (1 + strlen (tests[i].test) + 1); - sprintf (test, "/%s", tests[i].test); - - expected_result = xmalloc (1 + strlen (tests[i].result) + 1); - sprintf (expected_result, "/%s", tests[i].result); + /* Longjumped out of FUN with a timeout. */ + signal (SIGALRM, SIG_DFL); + return 1; + } + alarm (timeout); + fun (arg); - run_test (test, expected_result, expected_change); + /* Preserve errno in case alarm() or signal() modifies it. */ + saved_errno = errno; + alarm (0); + signal (SIGALRM, SIG_DFL); + errno = saved_errno; - xfree (test); - xfree (expected_result); - } -} + return 0; #endif +} +