X-Git-Url: http://sjero.net/git/?p=wget;a=blobdiff_plain;f=src%2Fmswindows.c;h=179773e05fccfd99a9d566b6385540ca0ddbc9c5;hp=e2be4dd5a86d87b74bc716103aea7ea59db848f9;hb=HEAD;hpb=8ae7bc8333cc9591dfa0aadde6c3ee53182dc70a diff --git a/src/mswindows.c b/src/mswindows.c index e2be4dd5..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,47 +16,33 @@ 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 -#include "wget.h" #include "utils.h" #include "url.h" -#ifndef errno -extern int errno; -#endif - #ifndef ES_SYSTEM_REQUIRED #define ES_SYSTEM_REQUIRED 0x00000001 #endif @@ -66,28 +53,28 @@ extern int errno; /* Defined in log.c. */ -void log_request_redirect_output PARAMS ((const char *)); +void log_request_redirect_output (const char *); /* Windows version of xsleep in utils.c. */ 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 (seconds * 1000, FALSE); + SleepEx ((DWORD) (seconds * 1000 + .5), FALSE); #endif /* not HAVE_USLEEP */ } void -windows_main_junk (int *argc, char **argv, char **exec_name) +windows_main (char **exec_name) { char *p; @@ -101,24 +88,15 @@ windows_main_junk (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) { - /* Whether we arrange our own version of opt.lfilename here. */ - int changedp = 0; - - if (!opt.lfilename) - { - opt.lfilename = unique_name (DEFAULT_LOGFILE, 0); - changedp = 1; - } - printf (_("Continuing in background.\n")); - if (changedp) - printf (_("Output will be written to `%s'.\n"), opt.lfilename); - + fprintf (stderr, _("Continuing in background.\n")); log_request_redirect_output (reason); /* Detach process from the current console. Under Windows 9x, if we @@ -128,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. */ @@ -142,7 +121,7 @@ make_section_name (DWORD pid) struct fake_fork_info { HANDLE event; - int changedp; + bool logfile_changed; char lfilename[MAX_PATH + 1]; }; @@ -158,19 +137,15 @@ fake_fork_child (void) HANDLE section, event; struct fake_fork_info *info; char *name; - DWORD le; name = make_section_name (GetCurrentProcessId ()); section = OpenFileMapping (FILE_MAP_WRITE, FALSE, name); - le = GetLastError (); xfree (name); + /* It seems that Windows 9x and NT set last-error inconsistently when + OpenFileMapping() fails; so we assume it failed because the section + object does not exist. */ if (!section) - { - if (le == ERROR_FILE_NOT_FOUND) - return 0; /* Section object does not exist; we are the parent. */ - else - return -1; - } + return 0; /* We are the parent. */ info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0); if (!info) @@ -181,15 +156,19 @@ fake_fork_child (void) event = info->event; - if (!opt.lfilename) + info->logfile_changed = false; + if (!opt.lfilename && (!opt.quiet || opt.server_response)) { - opt.lfilename = unique_name (DEFAULT_LOGFILE, 0); - info->changedp = 1; - strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename)); - info->lfilename[sizeof (info->lfilename) - 1] = '\0'; + /* 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); + } } - else - info->changedp = 0; UnmapViewOfFile (info); CloseHandle (section); @@ -213,7 +192,6 @@ fake_fork_child (void) static void fake_fork (void) { - char *cmdline, *args; char exe[MAX_PATH + 1]; DWORD exe_len, le; SECURITY_ATTRIBUTES sa; @@ -224,23 +202,7 @@ fake_fork (void) char *name; BOOL rv; - event = section = pi.hProcess = pi.hThread = NULL; - - /* Get command line arguments to pass to the child process. - We need to skip the name of the command (what amounts to argv[0]). */ - cmdline = GetCommandLine (); - if (*cmdline == '"') - { - args = strchr (cmdline + 1, '"'); - if (args) - ++args; - } - else - args = strchr (cmdline, ' '); - - /* It's ok if args is NULL, that would mean there were no arguments - after the command name. As it is now though, we would never get here - if that were true. */ + section = pi.hProcess = pi.hThread = NULL; /* Get the fully qualified name of our executable. This is more reliable than using argv[0]. */ @@ -258,12 +220,13 @@ fake_fork (void) if (!event) return; - /* Creat the child process detached form the current console and in a + /* Create the child process detached form the current console and in a suspended state. */ - memset (&si, 0, sizeof (si)); + xzero (si); si.cb = sizeof (si); - rv = CreateProcess (exe, args, NULL, NULL, TRUE, CREATE_SUSPENDED | - DETACHED_PROCESS, NULL, NULL, &si, &pi); + rv = CreateProcess (exe, GetCommandLine (), NULL, NULL, TRUE, + CREATE_SUSPENDED | DETACHED_PROCESS, + NULL, NULL, &si, &pi); if (!rv) goto cleanup; @@ -319,7 +282,7 @@ fake_fork (void) } /* Ensure string is properly terminated. */ - if (info->changedp && + if (info->logfile_changed && !memchr (info->lfilename, '\0', sizeof (info->lfilename))) { rv = FALSE; @@ -327,8 +290,8 @@ fake_fork (void) } printf (_("Continuing in background, pid %lu.\n"), pi.dwProcessId); - if (info->changedp) - printf (_("Output will be written to `%s'.\n"), info->lfilename); + if (info->logfile_changed) + printf (_("Output will be written to %s.\n"), quote (info->lfilename)); UnmapViewOfFile (info); @@ -360,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) @@ -368,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. */ @@ -405,7 +368,7 @@ ws_changetitle (const char *url) { xfree_null (title_buf); xfree_null (curr_url); - title_buf = (char *)xmalloc (strlen (url) + 20); + title_buf = xmalloc (strlen (url) + 20); curr_url = xstrdup (url); old_percentage = -1; sprintf (title_buf, "Wget %s", curr_url); @@ -491,23 +454,20 @@ set_sleep_mode (void) void ws_startup (void) { - WORD requested; WSADATA data; - int err; - - requested = MAKEWORD (1, 1); - err = WSAStartup (requested, &data); + WORD requested = MAKEWORD (1, 1); + int err = WSAStartup (requested, &data); 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); } @@ -516,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. */ @@ -586,19 +518,19 @@ thread_helper (void *arg) } /* 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. + seconds. Returns true if the function was interrupted with a + timeout, false otherwise. This works by running FUN in a separate thread and terminating the thread if it doesn't finish in the specified time. */ -int +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; - int rc = 0; + bool rc; DEBUGP (("seconds %.2f, ", seconds)); @@ -606,20 +538,18 @@ run_with_timeout (double seconds, void (*fun) (void *), void *arg) { blocking_fallback: fun (arg); - return 0; + 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; } @@ -627,18 +557,98 @@ 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 = 0; + rc = false; } else { TerminateThread (thread_hnd, 1); - rc = 1; + rc = true; } - CloseHandle (thread_hnd); /* Clear-up after TerminateThread(). */ + CloseHandle (thread_hnd); /* Clear-up after TerminateThread(). */ thread_hnd = NULL; return rc; } + + +#ifdef ENABLE_IPV6 +/* 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 can't accomodate struct sockaddr_in6. */ + union { + struct sockaddr_in6 sin6; + struct sockaddr_in sin; + } sa; + DWORD dstlen = cnt; + size_t srcsize; + + 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; + } + 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; +}