]> sjero.net Git - wget/blobdiff - src/mswindows.c
Fix build when libpsl is not available
[wget] / src / mswindows.c
index ca1f46a8e541abece471743897b4de5855419e04..179773e05fccfd99a9d566b6385540ca0ddbc9c5 100644 (file)
@@ -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 <http://www.gnu.org/licenses/>.
 
-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 <config.h>
+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 <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 #include <errno.h>
 #include <math.h>
 
-#ifdef HACK_BCC_UTIME_BUG
-# include <io.h>
-# include <fcntl.h>
-# ifdef HAVE_UTIME_H
-#  include <utime.h>
-# endif
-# ifdef HAVE_SYS_UTIME_H
-#  include <sys/utime.h>
-# 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,151 +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 */
 }
 
-#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 OVERFLOW 9223372036854775807I64
-#define UNDERFLOW (-OVERFLOW - 1)
-
-  __int64 result = 0;
-  int negative;
-
-  if (base != 0 && (base < 2 || base > 36))
-    {
-      errno = EINVAL;
-      return 0;
-    }
-
-  while (*nptr == ' ' || *nptr == '\t')
-    ++nptr;
-  if (*nptr == '-')
-    {
-      negative = 1;
-      ++nptr;
-    }
-  else if (*nptr == '+')
-    {
-      negative = 0;
-      ++nptr;
-    }
-  else
-    negative = 0;
-
-  /* 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 = 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 = 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_junk (int *argc, char **argv, char **exec_name)
+windows_main (char **exec_name)
 {
   char *p;
 
@@ -224,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
@@ -251,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.  */
@@ -265,7 +121,7 @@ make_section_name (DWORD pid)
 struct fake_fork_info
 {
   HANDLE event;
-  int changedp;
+  bool logfile_changed;
   char lfilename[MAX_PATH + 1];
 };
 
@@ -300,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);
@@ -342,7 +202,7 @@ fake_fork (void)
   char *name;
   BOOL rv;
 
-  event = section = pi.hProcess = pi.hThread = NULL;
+  section = pi.hProcess = pi.hThread = NULL;
 
   /* Get the fully qualified name of our executable.  This is more reliable
      than using argv[0].  */
@@ -362,7 +222,7 @@ fake_fork (void)
 
   /* 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, GetCommandLine (), NULL, NULL, TRUE,
                       CREATE_SUSPENDED | DETACHED_PROCESS,
@@ -422,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;
@@ -430,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);
 
@@ -463,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)
@@ -471,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.  */
@@ -508,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);
@@ -594,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);
     }
@@ -619,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 (&times->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
 \f
 /* run_with_timeout Windows implementation.  */
 
@@ -689,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));
 
@@ -709,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;
     }
 
@@ -730,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;
+}