X-Git-Url: http://sjero.net/git/?p=wget;a=blobdiff_plain;f=src%2Fmswindows.c;h=179773e05fccfd99a9d566b6385540ca0ddbc9c5;hp=d1867fcf9c512ad8bed4d062f47e66c74c818a9d;hb=HEAD;hpb=c1fb83c53b27ffd1635fda24702f2a115d939511 diff --git a/src/mswindows.c b/src/mswindows.c index d1867fcf..179773e0 100644 --- a/src/mswindows.c +++ b/src/mswindows.c @@ -1,12 +1,13 @@ /* mswindows.c -- Windows-specific support - Copyright (C) 1995, 1996, 1997, 1998, 2004 - Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, + Inc. This file is part of GNU Wget. GNU Wget is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or +the Free Software Foundation; either version 3 of the License, or (at your option) any later version. GNU Wget is distributed in the hope that it will be useful, @@ -15,42 +16,30 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Wget; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +along with Wget. If not, see . -In addition, as a special exception, the Free Software Foundation -gives permission to link the code of its release of Wget with the -OpenSSL project's "OpenSSL" library (or with modified versions of it -that use the same license as the "OpenSSL" library), and distribute -the linked executables. You must obey the GNU General Public License -in all respects for all of the code used other than "OpenSSL". If you -modify this file, you may extend this exception to your version of the -file, but you are not obligated to do so. If you do not wish to do -so, delete this exception statement from your version. */ +Additional permission under GNU GPL version 3 section 7 -#include +If you modify this program, or any covered work, by linking or +combining it with the OpenSSL project's OpenSSL library (or a +modified version of that library), containing parts covered by the +terms of the OpenSSL or SSLeay licenses, the Free Software Foundation +grants you additional permission to convey the resulting work. +Corresponding Source for a non-source form of such a combination +shall include the source code for the parts of OpenSSL used as well +as that of the covered work. */ + +#define INHIBIT_WRAP /* avoid wrapping of socket, bind, ... */ + +#include "wget.h" #include #include #include -#include #include #include -#ifdef HACK_BCC_UTIME_BUG -# include -# include -# ifdef HAVE_UTIME_H -# include -# endif -# ifdef HAVE_SYS_UTIME_H -# include -# endif -#endif -#define INHIBIT_WRAP /* avoid wrapping of socket, bind, ... */ - -#include "wget.h" #include "utils.h" #include "url.h" @@ -71,144 +60,21 @@ void log_request_redirect_output (const char *); void xsleep (double seconds) { -#ifdef HAVE_USLEEP +#if defined(HAVE_USLEEP) && defined(HAVE_SLEEP) if (seconds > 1000) { /* Explained in utils.c. */ sleep (seconds); seconds -= (long) seconds; } - usleep (seconds * 1000000L); + usleep (seconds * 1000000); #else /* not HAVE_USLEEP */ SleepEx ((DWORD) (seconds * 1000 + .5), FALSE); #endif /* not HAVE_USLEEP */ } -#if defined(__BORLANDC__) || (defined(_MSC_VER) && _MSC_VER < 1300) - -static inline int -char_value (char c, int base) -{ - int value; - if (c < '0') - return -1; - if ('0' <= c && c <= '9') - value = c - '0'; - else if ('a' <= c && c <= 'z') - value = c - 'a' + 10; - else if ('A' <= c && c <= 'Z') - value = c - 'A' + 10; - else - return -1; - if (value >= base) - return -1; - return value; -} - -/* A fairly simple strtoll replacement for MS VC versions that don't - supply _strtoi64. */ - -__int64 -str_to_int64 (const char *nptr, char **endptr, int base) -{ -#define INT64_OVERFLOW 9223372036854775807I64 -#define INT64_UNDERFLOW (-INT64_OVERFLOW - 1) - - __int64 result = 0; - bool negative; - - if (base != 0 && (base < 2 || base > 36)) - { - errno = EINVAL; - return 0; - } - - while (*nptr == ' ' || *nptr == '\t') - ++nptr; - if (*nptr == '-') - { - negative = true; - ++nptr; - } - else if (*nptr == '+') - { - negative = false; - ++nptr; - } - else - negative = false; - - /* If base is 0, determine the real base based on the beginning on - the number; octal numbers begin with "0", hexadecimal with "0x", - and the others are considered octal. */ - if (*nptr == '0') - { - if ((base == 0 || base == 16) - && - (*(nptr + 1) == 'x' || *(nptr + 1) == 'X')) - { - base = 16; - nptr += 2; - } - else if (base == 0) - base = 8; - } - else if (base == 0) - base = 10; - - if (!negative) - { - /* Parse positive number, checking for overflow. */ - int val; - for (; (val = char_value (*nptr, base)) != -1; ++nptr) - { - __int64 newresult = base * result + val; - if (newresult < result) - { - result = INT64_OVERFLOW; - errno = ERANGE; - break; - } - result = newresult; - } - } - else - { - /* Parse negative number, checking for underflow. */ - int val; - for (; (val = char_value (*nptr, base)) != -1; ++nptr) - { - __int64 newresult = base * result - val; - if (newresult > result) - { - result = INT64_UNDERFLOW; - errno = ERANGE; - break; - } - result = newresult; - } - } - if (endptr) - *endptr = (char *) nptr; - return result; -} - -#else /* !defined(__BORLANDC__) && (!defined(_MSC_VER) || _MSC_VER >= 1300) */ - -__int64 -str_to_int64 (const char *nptr, char **endptr, int base) -{ -#ifdef _MSC_VER - return _strtoi64 (nptr, endptr, base); -#else - return strtoll (nptr, endptr, base); -#endif -} - -#endif /* !defined(__BORLANDC__) && (!defined(_MSC_VER) || _MSC_VER >= 1300) */ - void -windows_main (int *argc, char **argv, char **exec_name) +windows_main (char **exec_name) { char *p; @@ -222,9 +88,11 @@ windows_main (int *argc, char **argv, char **exec_name) static void ws_cleanup (void) { + xfree ((char*)exec_name); WSACleanup (); } +#if defined(CTRLBREAK_BACKGND) || defined(CTRLC_BACKGND) static void ws_hangup (const char *reason) { @@ -238,6 +106,7 @@ ws_hangup (const char *reason) gesture as the parent will wait for us to terminate before resuming. */ FreeConsole (); } +#endif /* Construct the name for a named section (a.k.a. `file mapping') object. The returned string is dynamically allocated and needs to be xfree()'d. */ @@ -288,17 +157,17 @@ fake_fork_child (void) event = info->event; info->logfile_changed = false; - if (!opt.lfilename) + if (!opt.lfilename && (!opt.quiet || opt.server_response)) { /* See utils:fork_to_background for explanation. */ FILE *new_log_fp = unique_create (DEFAULT_LOGFILE, false, &opt.lfilename); if (new_log_fp) - { - info->logfile_changed = true; - strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename)); - info->lfilename[sizeof (info->lfilename) - 1] = '\0'; - fclose (new_log_fp); - } + { + info->logfile_changed = true; + strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename)); + info->lfilename[sizeof (info->lfilename) - 1] = '\0'; + fclose (new_log_fp); + } } UnmapViewOfFile (info); @@ -422,7 +291,7 @@ fake_fork (void) printf (_("Continuing in background, pid %lu.\n"), pi.dwProcessId); if (info->logfile_changed) - printf (_("Output will be written to `%s'.\n"), info->lfilename); + printf (_("Output will be written to %s.\n"), quote (info->lfilename)); UnmapViewOfFile (info); @@ -454,7 +323,7 @@ fork_to_background (void) rv = fake_fork_child (); if (rv < 0) { - fprintf (stderr, "fake_fork_child() failed\n"); + fprintf (stderr, _("fake_fork_child() failed\n")); abort (); } else if (rv == 0) @@ -462,7 +331,7 @@ fork_to_background (void) /* We're the parent. */ fake_fork (); /* If fake_fork() returns, it failed. */ - fprintf (stderr, "fake_fork() failed\n"); + fprintf (stderr, _("fake_fork() failed\n")); abort (); } /* If we get here, we're the child. */ @@ -591,14 +460,14 @@ ws_startup (void) if (err != 0) { fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"), - exec_name); + exec_name); exit (1); } if (data.wVersion < requested) { fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"), - exec_name); + exec_name); WSACleanup (); exit (1); } @@ -607,34 +476,6 @@ ws_startup (void) set_sleep_mode (); SetConsoleCtrlHandler (ws_handler, TRUE); } - -/* Replacement utime function for buggy Borland C++Builder 5.5 compiler. - (The Borland utime function only works on Windows NT.) */ - -#ifdef HACK_BCC_UTIME_BUG -int -borland_utime (const char *path, const struct utimbuf *times) -{ - int fd; - int res; - struct ftime ft; - struct tm *ptr_tm; - - if ((fd = open (path, O_RDWR)) < 0) - return -1; - - ptr_tm = localtime (×->modtime); - ft.ft_tsec = ptr_tm->tm_sec >> 1; - ft.ft_min = ptr_tm->tm_min; - ft.ft_hour = ptr_tm->tm_hour; - ft.ft_day = ptr_tm->tm_mday; - ft.ft_month = ptr_tm->tm_mon + 1; - ft.ft_year = ptr_tm->tm_year - 80; - res = setftime (fd, &ft); - close (fd); - return res; -} -#endif /* run_with_timeout Windows implementation. */ @@ -686,7 +527,7 @@ thread_helper (void *arg) bool run_with_timeout (double seconds, void (*fun) (void *), void *arg) { - static HANDLE thread_hnd = NULL; + HANDLE thread_hnd; struct thread_data thread_arg; DWORD thread_id; bool rc; @@ -700,17 +541,15 @@ run_with_timeout (double seconds, void (*fun) (void *), void *arg) return false; } - /* Should never happen, but test for recursivety anyway. */ - assert (thread_hnd == NULL); - thread_arg.fun = fun; thread_arg.arg = arg; thread_arg.ws_error = WSAGetLastError (); thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper, - &thread_arg, 0, &thread_id); + &thread_arg, 0, &thread_id); if (!thread_hnd) { - DEBUGP (("CreateThread() failed; %s\n", strerror (GetLastError ()))); + DEBUGP (("CreateThread() failed; [%#lx]\n", + (unsigned long) GetLastError ())); goto blocking_fallback; } @@ -718,7 +557,7 @@ run_with_timeout (double seconds, void (*fun) (void *), void *arg) == WAIT_OBJECT_0) { /* Propagate error state (which is per-thread) to this thread, - so the caller can inspect it. */ + so the caller can inspect it. */ WSASetLastError (thread_arg.ws_error); DEBUGP (("Winsock error: %d\n", WSAGetLastError ())); rc = false; @@ -729,143 +568,46 @@ run_with_timeout (double seconds, void (*fun) (void *), void *arg) rc = true; } - CloseHandle (thread_hnd); /* Clear-up after TerminateThread(). */ + CloseHandle (thread_hnd); /* Clear-up after TerminateThread(). */ thread_hnd = NULL; return rc; } - -/* Wget expects network calls such as connect, recv, send, etc., to set - errno on failure. To achieve that, Winsock calls are wrapped with code - that, in case of error, sets errno to the value of WSAGetLastError(). - In addition, we provide a wrapper around strerror, which recognizes - Winsock errors and prints the appropriate error message. */ - -/* Define a macro that creates a function definition that wraps FUN into - a function that sets errno the way the rest of the code expects. */ - -#define WRAP(fun, decl, call) int wrapped_##fun decl { \ - int retval = fun call; \ - if (retval < 0) \ - errno = WSAGetLastError (); \ - return retval; \ -} - -WRAP (socket, (int domain, int type, int protocol), (domain, type, protocol)) -WRAP (bind, (int s, struct sockaddr *a, int alen), (s, a, alen)) -WRAP (connect, (int s, const struct sockaddr *a, int alen), (s, a, alen)) -WRAP (recv, (int s, void *buf, int len, int flags), (s, buf, len, flags)) -WRAP (send, (int s, const void *buf, int len, int flags), (s, buf, len, flags)) -WRAP (select, (int n, fd_set *r, fd_set *w, fd_set *e, const struct timeval *tm), - (n, r, w, e, tm)) -WRAP (getsockname, (int s, struct sockaddr *n, int *nlen), (s, n, nlen)) -WRAP (getpeername, (int s, struct sockaddr *n, int *nlen), (s, n, nlen)) -WRAP (setsockopt, (int s, int level, int opt, const void *val, int len), - (s, level, opt, val, len)) -WRAP (closesocket, (int s), (s)) - -/* Return the text of the error message for Winsock error WSERR. */ - -static const char * -get_winsock_error (int wserr) -{ - switch (wserr) { - case WSAEINTR: return "Interrupted system call"; - case WSAEBADF: return "Bad file number"; - case WSAEACCES: return "Permission denied"; - case WSAEFAULT: return "Bad address"; - case WSAEINVAL: return "Invalid argument"; - case WSAEMFILE: return "Too many open files"; - case WSAEWOULDBLOCK: return "Resource temporarily unavailable"; - case WSAEINPROGRESS: return "Operation now in progress"; - case WSAEALREADY: return "Operation already in progress"; - case WSAENOTSOCK: return "Socket operation on nonsocket"; - case WSAEDESTADDRREQ: return "Destination address required"; - case WSAEMSGSIZE: return "Message too long"; - case WSAEPROTOTYPE: return "Protocol wrong type for socket"; - case WSAENOPROTOOPT: return "Bad protocol option"; - case WSAEPROTONOSUPPORT: return "Protocol not supported"; - case WSAESOCKTNOSUPPORT: return "Socket type not supported"; - case WSAEOPNOTSUPP: return "Operation not supported"; - case WSAEPFNOSUPPORT: return "Protocol family not supported"; - case WSAEAFNOSUPPORT: return "Address family not supported by protocol family"; - case WSAEADDRINUSE: return "Address already in use"; - case WSAEADDRNOTAVAIL: return "Cannot assign requested address"; - case WSAENETDOWN: return "Network is down"; - case WSAENETUNREACH: return "Network is unreachable"; - case WSAENETRESET: return "Network dropped connection on reset"; - case WSAECONNABORTED: return "Software caused connection abort"; - case WSAECONNRESET: return "Connection reset by peer"; - case WSAENOBUFS: return "No buffer space available"; - case WSAEISCONN: return "Socket is already connected"; - case WSAENOTCONN: return "Socket is not connected"; - case WSAESHUTDOWN: return "Cannot send after socket shutdown"; - case WSAETOOMANYREFS: return "Too many references"; - case WSAETIMEDOUT: return "Connection timed out"; - case WSAECONNREFUSED: return "Connection refused"; - case WSAELOOP: return "Too many levels of symbolic links"; - case WSAENAMETOOLONG: return "File name too long"; - case WSAEHOSTDOWN: return "Host is down"; - case WSAEHOSTUNREACH: return "No route to host"; - case WSAENOTEMPTY: return "Not empty"; - case WSAEPROCLIM: return "Too many processes"; - case WSAEUSERS: return "Too many users"; - case WSAEDQUOT: return "Bad quota"; - case WSAESTALE: return "Something is stale"; - case WSAEREMOTE: return "Remote error"; - case WSAEDISCON: return "Disconnected"; - - /* Extended Winsock errors */ - case WSASYSNOTREADY: return "Winsock library is not ready"; - case WSANOTINITIALISED: return "Winsock library not initalised"; - case WSAVERNOTSUPPORTED: return "Winsock version not supported"; - - case WSAHOST_NOT_FOUND: return "Host not found"; - case WSATRY_AGAIN: return "Host not found, try again"; - case WSANO_RECOVERY: return "Unrecoverable error in call to nameserver"; - case WSANO_DATA: return "No data record of requested type"; - - default: - return NULL; - } -} -/* Return the error message corresponding to ERR. This is different - from Windows libc strerror() in that it handles Winsock errors - correctly. */ -const char * -windows_strerror (int err) -{ - const char *p; - if (err >= 0 && err < sys_nerr) - return strerror (err); - else if ((p = get_winsock_error (err)) != NULL) - return p; - else - { - static char buf[32]; - snprintf (buf, sizeof (buf), "Unknown error %d (%#x)", err, err); - return buf; - } -} - #ifdef ENABLE_IPV6 -/* An IPv6-only inet_ntop that prints with WSAAddressToString. (Wget - uses inet_ntoa for IPv4 addresses -- see print_address.) Prototype - complies with POSIX 1003.1-2004. */ +/* An inet_ntop implementation that uses WSAAddressToString. + Prototype complies with POSIX 1003.1-2004. This is only used under + IPv6 because Wget prints IPv4 addresses using inet_ntoa. */ const char * inet_ntop (int af, const void *src, char *dst, socklen_t cnt) { - struct sockaddr_in6 sin6; + /* struct sockaddr can't accomodate struct sockaddr_in6. */ + union { + struct sockaddr_in6 sin6; + struct sockaddr_in sin; + } sa; DWORD dstlen = cnt; + size_t srcsize; - assert (af == AF_INET6); - xzero (sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = *(struct in6_addr *) src; - if (WSAAddressToString ((struct sockaddr *) &sin6, sizeof (sin6), - NULL, dst, &dstlen) != 0) + xzero (sa); + switch (af) + { + case AF_INET: + sa.sin.sin_family = AF_INET; + sa.sin.sin_addr = *(struct in_addr *) src; + srcsize = sizeof (sa.sin); + break; + case AF_INET6: + sa.sin6.sin6_family = AF_INET6; + sa.sin6.sin6_addr = *(struct in6_addr *) src; + srcsize = sizeof (sa.sin6); + break; + default: + abort (); + } + + if (WSAAddressToString ((struct sockaddr *) &sa, srcsize, NULL, dst, &dstlen) != 0) { errno = WSAGetLastError(); return NULL; @@ -873,3 +615,40 @@ inet_ntop (int af, const void *src, char *dst, socklen_t cnt) return (const char *) dst; } #endif + + +void +set_windows_fd_as_blocking_socket (int fd) +{ + /* 04/2011 + gnulib select() converts blocking sockets to nonblocking in windows + discussed here: + http://old.nabble.com/blocking-socket-is-nonblocking-after-calling-gnulib- + select%28%29-in-windows-td31432857.html + + wget uses blocking sockets so we must convert them back to blocking. + */ + int ret = 0; + int wsagle = 0; + const int zero = 0; + + do + { + if(wsagle == WSAEINPROGRESS) + Sleep(1); /* use windows sleep */ + + WSASetLastError (0); + ret = ioctl (fd, FIONBIO, &zero); + wsagle = WSAGetLastError (); + } + while (ret && (wsagle == WSAEINPROGRESS)); + + if(ret) + { + fprintf (stderr, + _("ioctl() failed. The socket could not be set as blocking.\n") ); + DEBUGP (("Winsock error: %d\n", WSAGetLastError ())); + abort (); + } + return; +}