]> code.delx.au - gnu-emacs/blobdiff - src/w32.c
Merge from origin/emacs-25
[gnu-emacs] / src / w32.c
index cc55507919cd9f8c9bc438d748e5d8bca6d90245..94aa7d891d5d3fd5fd8a2ae50cabc0640f47358b 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -1,13 +1,13 @@
 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
 
-Copyright (C) 1994-1995, 2000-2015 Free Software Foundation, Inc.
+Copyright (C) 1994-1995, 2000-2016 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs 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 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -67,7 +67,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #undef localtime
 
 #include "lisp.h"
-#include "epaths.h"    /* for SHELL */
+#include "epaths.h"    /* for PATH_EXEC */
 
 #include <pwd.h>
 #include <grp.h>
@@ -95,7 +95,7 @@ typedef struct _MEMORY_STATUS_EX {
 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
 
 /* These are here so that GDB would know about these data types.  This
-   allows to attach GDB to Emacs when a fatal exception is triggered
+   allows attaching GDB to Emacs when a fatal exception is triggered
    and Windows pops up the "application needs to be closed" dialog.
    At that point, _gnu_exception_handler, the top-level exception
    handler installed by the MinGW startup code, is somewhere on the
@@ -224,20 +224,24 @@ typedef struct _REPARSE_DATA_BUFFER {
 
 #include <iphlpapi.h>  /* should be after winsock2.h */
 
+#include <wincrypt.h>
+
+#include <c-strcase.h>
+
 #include "w32.h"
 #include <dirent.h>
 #include "w32common.h"
-#include "w32heap.h"
 #include "w32select.h"
-#include "systime.h"
+#include "systime.h"           /* for current_timespec, struct timespec */
 #include "dispextern.h"                /* for xstrcasecmp */
 #include "coding.h"            /* for Vlocale_coding_system */
 
 #include "careadlinkat.h"
 #include "allocator.h"
 
-/* For serial_configure and serial_open.  */
+/* For Lisp_Process, serial_configure and serial_open.  */
 #include "process.h"
+#include "systty.h"
 
 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
   (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
@@ -482,6 +486,7 @@ typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
 
 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
+DWORD multiByteToWideCharFlags;
 
   /* ** A utility function ** */
 static BOOL
@@ -1511,7 +1516,7 @@ codepage_for_filenames (CPINFO *cp_info)
 
       if (NILP (current_encoding))
        {
-         char *cpname = SDATA (SYMBOL_NAME (current_encoding));
+         char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
          char *cp = NULL, *end;
          int cpnum;
 
@@ -1548,8 +1553,8 @@ codepage_for_filenames (CPINFO *cp_info)
 int
 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
 {
-  int result = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
-                                    fn_out, MAX_PATH);
+  int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
+                                    -1, fn_out, MAX_PATH);
 
   if (!result)
     {
@@ -1639,8 +1644,8 @@ filename_from_ansi (const char *fn_in, char *fn_out)
 {
   wchar_t fn_utf16[MAX_PATH];
   int codepage = codepage_for_filenames (NULL);
-  int result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
-                                    fn_utf16, MAX_PATH);
+  int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
+                                    -1, fn_utf16, MAX_PATH);
 
   if (!result)
     {
@@ -2091,6 +2096,34 @@ init_user_info (void)
     CloseHandle (token);
 }
 
+static HCRYPTPROV w32_crypto_hprov;
+static int
+w32_init_crypt_random (void)
+{
+  if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
+                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+    {
+      DebPrint (("CryptAcquireContext failed with error %x\n",
+                GetLastError ()));
+      w32_crypto_hprov = 0;
+      return -1;
+    }
+  return 0;
+}
+
+int
+w32_init_random (void *buf, ptrdiff_t buflen)
+{
+  if (!w32_crypto_hprov)
+    w32_init_crypt_random ();
+  if (w32_crypto_hprov)
+    {
+      if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
+       return 0;
+    }
+  return -1;
+}
+
 int
 random (void)
 {
@@ -2163,11 +2196,11 @@ unixtodos_filename (register char *p)
    (From msdos.c...probably should figure out a way to share it,
    although this code isn't going to ever change.)  */
 static int
-crlf_to_lf (register int n, register unsigned char *buf)
+crlf_to_lf (register int n, register char *buf)
 {
-  unsigned char *np = buf;
-  unsigned char *startp = buf;
-  unsigned char *endp = buf + n;
+  unsigned char *np = (unsigned char *)buf;
+  unsigned char *startp = np;
+  char *endp = buf + n;
 
   if (n == 0)
     return n;
@@ -2384,7 +2417,7 @@ ansi_encode_filename (Lisp_Object filename)
     {
       char shortname[MAX_PATH];
 
-      if (w32_get_short_filename (SDATA (filename), shortname, MAX_PATH))
+      if (w32_get_short_filename (SSDATA (filename), shortname, MAX_PATH))
        {
          dostounix_filename (shortname);
          encoded_filename = build_string (shortname);
@@ -3208,7 +3241,8 @@ map_w32_filename (const char * name, const char ** pPath)
       return shortname;
     }
 
-  if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
+  if (!fatal_error_in_progress /* disable fancy processing during crash */
+      && is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
     {
       register int left = 8;   /* maximum number of chars in part */
       register int extn = 0;   /* extension added? */
@@ -4534,6 +4568,8 @@ sys_rmdir (const char * path)
 int
 sys_unlink (const char * path)
 {
+  int rmstatus, e;
+
   path = map_w32_filename (path, NULL);
 
   if (w32_unicode_filenames)
@@ -4541,9 +4577,18 @@ sys_unlink (const char * path)
       wchar_t path_w[MAX_PATH];
 
       filename_to_utf16 (path, path_w);
-      /* On Unix, unlink works without write permission. */
+      /* On Unix, unlink works without write permission.  */
       _wchmod (path_w, 0666);
-      return _wunlink (path_w);
+      rmstatus = _wunlink (path_w);
+      e = errno;
+      /* Symlinks to directories can only be deleted by _rmdir;
+        _unlink returns EACCES.  */
+      if (rmstatus != 0
+         && errno == EACCES
+         && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
+       rmstatus = _wrmdir (path_w);
+      else
+       errno = e;
     }
   else
     {
@@ -4551,8 +4596,17 @@ sys_unlink (const char * path)
 
       filename_to_ansi (path, path_a);
       _chmod (path_a, 0666);
-      return _unlink (path_a);
+      rmstatus = _unlink (path_a);
+      e = errno;
+      if (rmstatus != 0
+         && errno == EACCES
+         && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
+       rmstatus = _rmdir (path_a);
+      else
+       errno = e;
     }
+
+  return rmstatus;
 }
 
 static FILETIME utc_base_ft;
@@ -5626,7 +5680,8 @@ symlink (char const *filename, char const *linkname)
 /* A quick inexpensive test of whether FILENAME identifies a file that
    is a symlink.  Returns non-zero if it is, zero otherwise.  FILENAME
    must already be in the normalized form returned by
-   map_w32_filename.
+   map_w32_filename.  If the symlink is to a directory, the
+   FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
 
    Note: for repeated operations on many files, it is best to test
    whether the underlying volume actually supports symlinks, by
@@ -5684,6 +5739,8 @@ is_symlink (const char *filename)
       attrs_mean_symlink =
        (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
        && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
+      if (attrs_mean_symlink)
+       attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
     }
   else if (_mbspbrk (filename_a, "?"))
     {
@@ -5697,6 +5754,8 @@ is_symlink (const char *filename)
       attrs_mean_symlink =
        (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
        && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
+      if (attrs_mean_symlink)
+       attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
     }
   if (fh == INVALID_HANDLE_VALUE)
     return 0;
@@ -7143,6 +7202,10 @@ int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
                          const struct sockaddr * to, int tolen);
 
+int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
+                              const struct addrinfo *, struct addrinfo **);
+void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
+
 /* SetHandleInformation is only needed to make sockets non-inheritable. */
 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
 #ifndef HANDLE_FLAG_INHERIT
@@ -7225,6 +7288,16 @@ init_winsock (int load_now)
       LOAD_PROC (sendto);
 #undef LOAD_PROC
 
+      /* Try loading functions not available before XP.  */
+      pfn_getaddrinfo = (void *) GetProcAddress (winsock_lib, "getaddrinfo");
+      pfn_freeaddrinfo = (void *) GetProcAddress (winsock_lib, "freeaddrinfo");
+      /* Paranoia: these two functions should go together, so if one
+        is absent, we cannot use the other.  */
+      if (pfn_getaddrinfo == NULL)
+       pfn_freeaddrinfo = NULL;
+      else if (pfn_freeaddrinfo == NULL)
+       pfn_getaddrinfo = NULL;
+
       /* specify version 1.1 of winsock */
       if (pfn_WSAStartup (0x101, &winsockData) == 0)
         {
@@ -7405,7 +7478,7 @@ sys_socket (int af, int type, int protocol)
   if (winsock_lib == NULL)
     {
       errno = ENETDOWN;
-      return INVALID_SOCKET;
+      return -1;
     }
 
   check_errno ();
@@ -7468,7 +7541,7 @@ socket_to_fd (SOCKET s)
                   though the socket wasn't really a kernel handle,
                   because a real handle has the same value.  So
                   test whether the new handle really is a socket.  */
-               long nonblocking = 0;
+               unsigned long nonblocking = 0;
                if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
                  {
                    pfn_closesocket (s);
@@ -7674,6 +7747,117 @@ sys_getpeername (int s, struct sockaddr *addr, int * namelen)
   return SOCKET_ERROR;
 }
 
+int
+sys_getaddrinfo (const char *node, const char *service,
+                const struct addrinfo *hints, struct addrinfo **res)
+{
+  int rc;
+
+  if (winsock_lib == NULL)
+    {
+      errno = ENETDOWN;
+      return SOCKET_ERROR;
+    }
+
+  check_errno ();
+  if (pfn_getaddrinfo)
+    rc = pfn_getaddrinfo (node, service, hints, res);
+  else
+    {
+      int port = 0;
+      struct hostent *host_info;
+      struct gai_storage {
+       struct addrinfo addrinfo;
+       struct sockaddr_in sockaddr_in;
+      } *gai_storage;
+
+      /* We don't (yet) support any flags, as Emacs doesn't need that.  */
+      if (hints && hints->ai_flags != 0)
+       return WSAEINVAL;
+      /* NODE cannot be NULL, since process.c has fallbacks for that.  */
+      if (!node)
+       return WSAHOST_NOT_FOUND;
+
+      if (service)
+       {
+         const char *protocol =
+           (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
+         struct servent *srv = sys_getservbyname (service, protocol);
+
+         if (srv)
+           port = srv->s_port;
+         else if (*service >= '0' && *service <= '9')
+           {
+             char *endp;
+
+             port = strtoul (service, &endp, 10);
+             if (*endp || port > 65536)
+               return WSAHOST_NOT_FOUND;
+             port = sys_htons ((unsigned short) port);
+           }
+         else
+           return WSAHOST_NOT_FOUND;
+       }
+
+      gai_storage = xzalloc (sizeof *gai_storage);
+      gai_storage->sockaddr_in.sin_port = port;
+      host_info = sys_gethostbyname (node);
+      if (host_info)
+       {
+         memcpy (&gai_storage->sockaddr_in.sin_addr,
+                 host_info->h_addr, host_info->h_length);
+         gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
+       }
+      else
+       {
+         /* Attempt to interpret host as numeric inet address.  */
+         unsigned long numeric_addr = sys_inet_addr (node);
+
+         if (numeric_addr == -1)
+           {
+             free (gai_storage);
+             return WSAHOST_NOT_FOUND;
+           }
+
+         memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
+                 sizeof (gai_storage->sockaddr_in.sin_addr));
+         gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
+       }
+
+      gai_storage->addrinfo.ai_addr =
+       (struct sockaddr *)&gai_storage->sockaddr_in;
+      gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
+      gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
+      gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
+      gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
+      gai_storage->addrinfo.ai_next = NULL;
+
+      *res = &gai_storage->addrinfo;
+      rc = 0;
+    }
+
+  return rc;
+}
+
+void
+sys_freeaddrinfo (struct addrinfo *ai)
+{
+  if (winsock_lib == NULL)
+    {
+      errno = ENETDOWN;
+      return;
+    }
+
+  check_errno ();
+  if (pfn_freeaddrinfo)
+    pfn_freeaddrinfo (ai);
+  else
+    {
+      eassert (ai->ai_next == NULL);
+      xfree (ai);
+    }
+}
+
 int
 sys_shutdown (int s, int how)
 {
@@ -7997,17 +8181,33 @@ sys_dup2 (int src, int dst)
       return -1;
     }
 
-  /* make sure we close the destination first if it's a pipe or socket */
-  if (src != dst && fd_info[dst].flags != 0)
+  /* MS _dup2 seems to have weird side effect when invoked with 2
+     identical arguments: an attempt to fclose the corresponding stdio
+     stream after that hangs (we do close standard streams in
+     init_ntproc).  Attempt to avoid that by not calling _dup2 that
+     way: if SRC is valid, we know that dup2 should be a no-op, so do
+     nothing and return DST.  */
+  if (src == dst)
+    {
+      if ((HANDLE)_get_osfhandle (src) == INVALID_HANDLE_VALUE)
+       {
+         errno = EBADF;
+         return -1;
+       }
+      return dst;
+    }
+
+  /* Make sure we close the destination first if it's a pipe or socket.  */
+  if (fd_info[dst].flags != 0)
     sys_close (dst);
 
   rc = _dup2 (src, dst);
   if (rc == 0)
     {
-      /* duplicate our internal info as well */
+      /* Duplicate our internal info as well.  */
       fd_info[dst] = fd_info[src];
     }
-  return rc;
+  return rc == 0 ? dst : rc;
 }
 
 int
@@ -8015,14 +8215,19 @@ pipe2 (int * phandles, int pipe2_flags)
 {
   int rc;
   unsigned flags;
+  unsigned pipe_size = 0;
 
   eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
 
+  /* Allow Lisp to override the default buffer size of the pipe.  */
+  if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
+    pipe_size = w32_pipe_buffer_size;
+
   /* make pipe handles non-inheritable; when we spawn a child, we
      replace the relevant handle with an inheritable one.  Also put
      pipes into binary mode; we will do text mode translation ourselves
      if required.  */
-  rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
+  rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
 
   if (rc == 0)
     {
@@ -8305,7 +8510,17 @@ sys_read (int fd, char * buffer, unsigned int count)
 
            case STATUS_READ_READY:
            case STATUS_READ_IN_PROGRESS:
-             DebPrint (("sys_read called when read is in progress\n"));
+#if 0
+             /* This happens all the time during GnuTLS handshake
+                with the remote, evidently because GnuTLS waits for
+                the read to complete by retrying the read operation
+                upon EAGAIN.  So I'm disabling the DebPrint to avoid
+                wasting cycles on something that is not a real
+                problem.  Enable if you need to debug something that
+                bumps into this.  */
+             DebPrint (("sys_read called when read is in progress %d\n",
+                        current_status));
+#endif
              errno = EWOULDBLOCK;
              return -1;
 
@@ -8493,7 +8708,7 @@ sys_write (int fd, const void * buffer, unsigned int count)
          int nbytes = count;
 
          SAFE_NALLOCA (tmpbuf, 2, count);
-         dst = tmpbuf;
+         dst = (unsigned char *)tmpbuf;
 
          while (1)
            {
@@ -8573,6 +8788,30 @@ sys_write (int fd, const void * buffer, unsigned int count)
       unsigned long nblock = 0;
       if (winsock_lib == NULL) emacs_abort ();
 
+      child_process *cp = fd_info[fd].cp;
+
+      /* If this is a non-blocking socket whose connection is in
+        progress or terminated with an error already, return the
+        proper error code to the caller. */
+      if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
+       {
+         /* In case connection is in progress, ENOTCONN that would
+            result from calling pfn_send is not what callers expect. */
+         if (cp->status != STATUS_CONNECT_FAILED)
+           {
+             errno = EWOULDBLOCK;
+             return -1;
+           }
+         /* In case connection failed, use the actual error code
+            stashed by '_sys_wait_connect' in cp->errcode. */
+         else if (cp->errcode != 0)
+           {
+             pfn_WSASetLastError (cp->errcode);
+             set_errno ();
+             return -1;
+           }
+       }
+
       /* TODO: implement select() properly so non-blocking I/O works. */
       /* For now, make sure the write blocks.  */
       if (fd_info[fd].flags & FILE_NDELAY)
@@ -8580,6 +8819,13 @@ sys_write (int fd, const void * buffer, unsigned int count)
 
       nchars =  pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
 
+      if (nchars == SOCKET_ERROR)
+        {
+         set_errno ();
+         DebPrint (("sys_write.send failed with error %d on socket %ld\n",
+                    pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
+       }
+
       /* Set the socket back to non-blocking if it was before,
         for other operations that support it.  */
       if (fd_info[fd].flags & FILE_NDELAY)
@@ -8587,13 +8833,6 @@ sys_write (int fd, const void * buffer, unsigned int count)
          nblock = 1;
          pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
        }
-
-      if (nchars == SOCKET_ERROR)
-        {
-         DebPrint (("sys_write.send failed with error %d on socket %ld\n",
-                    pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
-         set_errno ();
-       }
     }
   else
     {
@@ -8604,15 +8843,35 @@ sys_write (int fd, const void * buffer, unsigned int count)
         http://thread.gmane.org/gmane.comp.version-control.git/145294
         in the git mailing list.  */
       const unsigned char *p = buffer;
-      const unsigned chunk = 30 * 1024 * 1024;
+      const bool is_pipe = (fd < MAXDESC
+                           && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
+                               == (FILE_PIPE | FILE_NDELAY)));
+      /* Some programs, notably Node.js's node.exe, seem to never
+        completely empty the pipe, so writing more than the size of
+        the pipe's buffer always returns ENOSPC, and we loop forever
+        between send_process and here.  As a workaround, write no
+        more than the pipe's buffer can hold.  */
+      DWORD pipe_buffer_size;
+      if (is_pipe)
+       {
+         if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
+                               NULL, &pipe_buffer_size, NULL, NULL))
+           {
+             DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
+             pipe_buffer_size = 4096;
+           }
+       }
+      const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
 
       nchars = 0;
+      errno = 0;
       while (count > 0)
        {
          unsigned this_chunk = count < chunk ? count : chunk;
          int n = _write (fd, p, this_chunk);
 
-         nchars += n;
+         if (n > 0)
+           nchars += n;
          if (n < 0)
            {
              /* When there's no buffer space in a pipe that is in the
@@ -8626,12 +8885,10 @@ sys_write (int fd, const void * buffer, unsigned int count)
                 avoiding deadlock whereby each side of the pipe is
                 blocked on write, waiting for the other party to read
                 its end of the pipe.  */
-             if (errno == ENOSPC
-                 && fd < MAXDESC
-                 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
-                     == (FILE_PIPE | FILE_NDELAY)))
+             if (errno == ENOSPC && is_pipe)
                errno = EAGAIN;
-             nchars = n;
+             if (nchars == 0)
+               nchars = -1;
              break;
            }
          else if (n < this_chunk)
@@ -8648,7 +8905,7 @@ sys_write (int fd, const void * buffer, unsigned int count)
 \f
 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c.  */
 
-extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
+extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, ptrdiff_t);
 
 /* Return information about network interface IFNAME, or about all
    interfaces (if IFNAME is nil).  */
@@ -9035,8 +9292,8 @@ check_windows_init_file (void)
       if (fd < 0)
        {
          Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
-         char *init_file_name = SDATA (init_file);
-         char *load_path = SDATA (load_path_print);
+         char *init_file_name = SSDATA (init_file);
+         char *load_path = SSDATA (load_path_print);
          char *buffer = alloca (1024
                                 + strlen (init_file_name)
                                 + strlen (load_path));
@@ -9053,14 +9310,14 @@ check_windows_init_file (void)
                   "not unpacked properly.\nSee the README.W32 file in the "
                   "top-level Emacs directory for more information.",
                   init_file_name, load_path);
-         needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
-                                        -1, NULL, 0);
+         needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
+                                        buffer, -1, NULL, 0);
          if (needed > 0)
            {
              wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
 
-             pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
-                                   msg_w, needed);
+             pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
+                                   -1, msg_w, needed);
              needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
                                             NULL, 0, NULL, NULL);
              if (needed > 0)
@@ -9243,8 +9500,11 @@ maybe_load_unicows_dll (void)
             pointers, and assign the correct addresses to these
             pointers at program startup (see emacs.c, which calls
             this function early on).  */
-         pMultiByteToWideChar = GetProcAddress (ret, "MultiByteToWideChar");
-         pWideCharToMultiByte = GetProcAddress (ret, "WideCharToMultiByte");
+         pMultiByteToWideChar =
+           (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
+         pWideCharToMultiByte =
+           (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
+          multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
          return ret;
        }
       else
@@ -9274,6 +9534,11 @@ maybe_load_unicows_dll (void)
         pointers; no need for the LoadLibrary dance.  */
       pMultiByteToWideChar = MultiByteToWideChar;
       pWideCharToMultiByte = WideCharToMultiByte;
+      /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported.  */
+      if (w32_major_version < 5)
+        multiByteToWideCharFlags = 0;
+      else
+        multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
       return LoadLibrary ("Gdi32.dll");
     }
 }
@@ -9352,6 +9617,13 @@ globals_of_w32 (void)
     w32_unicode_filenames = 0;
   else
     w32_unicode_filenames = 1;
+
+#ifdef HAVE_MODULES
+  extern void dynlib_reset_last_error (void);
+  dynlib_reset_last_error ();
+#endif
+
+  w32_crypto_hprov = (HCRYPTPROV)0;
 }
 
 /* For make-serial-process  */