#include "wget.h"
#include "utils.h"
-#include "fnmatch.h"
#include "hash.h"
#ifndef errno
that way we can also verify whether the file is readable.
Inspired by the POST patch by Arnaud Wylie. */
FILE *fp = fopen (filename, "rb");
+ if (!fp)
+ return -1;
fseek (fp, 0, SEEK_END);
size = ftell (fp);
fclose (fp);
return NULL;
}
+/* Return non-zero if S contains globbing wildcards (`*', `?', `[' or
+ `]'). */
+
+int
+has_wildcards_p (const char *s)
+{
+ for (; *s; s++)
+ if (*s == '*' || *s == '?' || *s == '[' || *s == ']')
+ return 1;
+ return 0;
+}
+
/* Return non-zero if FNAME ends with a typical HTML suffix. The
following (case-insensitive) suffixes are presumed to be HTML files:
}
/* 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.
+ storage. The storage space is obtained through malloc() and should
+ be freed with free() when it is no longer needed.
The length of the line is not limited, except by available memory.
The newline character at the end of line is retained. The line is
/* Normally, we grow SIZE exponentially to make the number
of calls to read() and realloc() logarithmic in relation
to file size. However, read() can read an amount of data
- smaller than requested, and it would be unreasonably to
+ smaller than requested, and it would be unreasonable to
double SIZE every time *something* was read. Therefore,
we double SIZE only when the length exceeds half of the
entire allocated size. */
#endif
#ifdef TIMER_TIME
- /* This is clear. */
return 1000;
#endif
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. */
+ unconditionally.
+
+ DO NOT use this for cryptographic purposes. It is only meant to be
+ used in situations where quality of the random numbers returned
+ doesn't really matter. */
int
random_number (int max)
return (int)bounded;
}
+/* Return a random uniformly distributed floating point number in the
+ [0, 1) range. The precision of returned numbers is 9 digits.
+
+ Modify this to use erand48() where available! */
+
+double
+random_float (void)
+{
+ /* We can't rely on any specific value of RAND_MAX, but I'm pretty
+ sure it's greater than 1000. */
+ int rnd1 = random_number (1000);
+ int rnd2 = random_number (1000);
+ int rnd3 = random_number (1000);
+ return rnd1 / 1000.0 + rnd2 / 1000000.0 + rnd3 / 1000000000.0;
+}
+
#if 0
/* A debugging function for checking whether an MD5 library works. */
}
#endif
\f
-/* Implementation of run_with_timeout, a generic timeout handler for
- systems with Unix-like signal handling. */
+/* Implementation of run_with_timeout, a generic timeout-forcing
+ routine for systems with Unix-like signal handling. */
+
#ifdef USE_SIGNAL_TIMEOUT
# ifdef HAVE_SIGSETJMP
# define SETJMP(env) sigsetjmp (env, 1)
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);
+ mask &= ~sigmask (SIGALRM);
sigsetmask (mask);
/* Now it's safe to longjump. */
longjmp (run_with_timeout_env, -1);
}
# endif /* not HAVE_SIGSETJMP */
-#endif /* USE_SIGNAL_TIMEOUT */
+
+/* Arrange for SIGALRM to be delivered in TIMEOUT seconds. This uses
+ setitimer where available, alarm otherwise.
+
+ TIMEOUT should be non-zero. If the timeout value is so small that
+ it would be rounded to zero, it is rounded to the least legal value
+ instead (1us for setitimer, 1s for alarm). That ensures that
+ SIGALRM will be delivered in all cases. */
+
+static void
+alarm_set (double timeout)
+{
+#ifdef ITIMER_REAL
+ /* Use the modern itimer interface. */
+ struct itimerval itv;
+ memset (&itv, 0, sizeof (itv));
+ itv.it_value.tv_sec = (long) timeout;
+ itv.it_value.tv_usec = 1000000L * (timeout - (long)timeout);
+ if (itv.it_value.tv_sec == 0 && itv.it_value.tv_usec == 0)
+ /* Ensure that we wait for at least the minimum interval.
+ Specifying zero would mean "wait forever". */
+ itv.it_value.tv_usec = 1;
+ setitimer (ITIMER_REAL, &itv, NULL);
+#else /* not ITIMER_REAL */
+ /* Use the old alarm() interface. */
+ int secs = (int) timeout;
+ if (secs == 0)
+ /* Round TIMEOUTs smaller than 1 to 1, not to zero. This is
+ because alarm(0) means "never deliver the alarm", i.e. "wait
+ forever", which is not what someone who specifies a 0.5s
+ timeout would expect. */
+ secs = 1;
+ alarm (secs);
+#endif /* not ITIMER_REAL */
+}
+
+/* Cancel the alarm set with alarm_set. */
+
+static void
+alarm_cancel (void)
+{
+#ifdef ITIMER_REAL
+ struct itimerval disable;
+ memset (&disable, 0, sizeof (disable));
+ setitimer (ITIMER_REAL, &disable, NULL);
+#else /* not ITIMER_REAL */
+ alarm (0);
+#endif /* not ITIMER_REAL */
+}
+
+/* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
+ seconds. Returns non-zero if the function was interrupted with a
+ timeout, zero otherwise.
+
+ This works by setting up SIGALRM to be delivered in TIMEOUT seconds
+ using setitimer() or alarm(). The timeout is enforced by
+ longjumping out of the SIGALRM handler. This has several
+ advantages compared to the traditional approach of relying on
+ signals causing system calls to exit with EINTR:
+
+ * The callback function is *forcibly* interrupted after the
+ timeout expires, (almost) regardless of what it was doing and
+ whether it was in a syscall. For example, a calculation that
+ takes a long time is interrupted as reliably as an IO
+ operation.
+
+ * It works with both SYSV and BSD signals because it doesn't
+ depend on the default setting of SA_RESTART.
+
+ * It doesn't special handler setup beyond a simple call to
+ signal(). (It does use sigsetjmp/siglongjmp, but they're
+ optional.)
+
+ The only downside is that, if FUN allocates internal resources that
+ are normally freed prior to exit from the functions, they will be
+ lost in case of timeout. */
int
-run_with_timeout (long timeout, void (*fun) (void *), void *arg)
+run_with_timeout (double timeout, void (*fun) (void *), void *arg)
{
-#ifndef USE_SIGNAL_TIMEOUT
- fun (arg);
- return 0;
-#else
int saved_errno;
if (timeout == 0)
signal (SIGALRM, SIG_DFL);
return 1;
}
- alarm (timeout);
+ alarm_set (timeout);
fun (arg);
/* Preserve errno in case alarm() or signal() modifies it. */
saved_errno = errno;
- alarm (0);
+ alarm_cancel ();
signal (SIGALRM, SIG_DFL);
errno = saved_errno;
return 0;
-#endif
}
+#else /* not USE_SIGNAL_TIMEOUT */
+
+#ifndef WINDOWS
+/* A stub version of run_with_timeout that just calls FUN(ARG). Don't
+ define it under Windows, because Windows has its own version of
+ run_with_timeout that uses threads. */
+
+int
+run_with_timeout (double timeout, void (*fun) (void *), void *arg)
+{
+ fun (arg);
+ return 0;
+}
+#endif /* not WINDOWS */
+#endif /* not USE_SIGNAL_TIMEOUT */