]> code.delx.au - gnu-emacs/blobdiff - src/w32.c
Update copyright year to 2016
[gnu-emacs] / src / w32.c
index aedf64942e09beaff23b6b1967eb01e9f1362d76..c77ed87b003041bab11f23e4f71025cbadd8bb9f 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -1,6 +1,6 @@
 /* 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.
 
@@ -67,15 +67,17 @@ 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>
 
 /* MinGW64 defines these in its _mingw.h.  */
-#if defined(__GNUC__) && !defined(MINGW_W64)
-#define _ANONYMOUS_UNION
-#define _ANONYMOUS_STRUCT
+#ifndef _ANONYMOUS_UNION
+# define _ANONYMOUS_UNION
+#endif
+#ifndef _ANONYMOUS_STRUCT
+# define _ANONYMOUS_STRUCT
 #endif
 #include <windows.h>
 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
@@ -222,26 +224,26 @@ typedef struct _REPARSE_DATA_BUFFER {
 
 #include <iphlpapi.h>  /* should be after winsock2.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 *);
 
-Lisp_Object QCloaded_from;
-
 void globals_of_w32 (void);
 static DWORD get_rid (PSID);
 static int is_symlink (const char *);
@@ -307,6 +309,8 @@ static BOOL g_b_init_set_named_security_info_w;
 static BOOL g_b_init_set_named_security_info_a;
 static BOOL g_b_init_get_adapters_info;
 
+BOOL g_b_init_compare_string_w;
+
 /*
   BEGIN: Wrapper functions around OpenProcessToken
   and other functions in advapi32.dll that are only
@@ -880,7 +884,7 @@ set_named_security_info (LPCTSTR lpObjectName,
          g_b_init_set_named_security_info_a = 1;
          hm_advapi32 = LoadLibrary ("Advapi32.dll");
          s_pfn_Set_Named_Security_InfoA =
-           (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32, 
+           (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
                                                         "SetNamedSecurityInfoA");
        }
       if (s_pfn_Set_Named_Security_InfoA == NULL)
@@ -1488,7 +1492,7 @@ static int file_name_codepage;
 
 /* Produce a Windows ANSI codepage suitable for encoding file names.
    Return the information about that codepage in CP_INFO.  */
-static int
+int
 codepage_for_filenames (CPINFO *cp_info)
 {
   /* A simple cache to avoid calling GetCPInfo every time we need to
@@ -1509,7 +1513,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;
 
@@ -1707,7 +1711,7 @@ static unsigned num_of_processors;
 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer.  */
 static struct load_sample samples[16*60];
 static int first_idx = -1, last_idx = -1;
-static int max_idx = sizeof (samples) / sizeof (samples[0]);
+static int max_idx = ARRAYELTS (samples);
 
 static int
 buf_next (int from)
@@ -2161,11 +2165,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;
@@ -2290,7 +2294,7 @@ get_long_basename (char * name, char * buf, int size)
 
 /* Get long name for file, if possible (assumed to be absolute).  */
 BOOL
-w32_get_long_filename (char * name, char * buf, int size)
+w32_get_long_filename (const char * name, char * buf, int size)
 {
   char * o = buf;
   char * p;
@@ -2341,7 +2345,7 @@ w32_get_long_filename (char * name, char * buf, int size)
 }
 
 unsigned int
-w32_get_short_filename (char * name, char * buf, int size)
+w32_get_short_filename (const char * name, char * buf, int size)
 {
   if (w32_unicode_filenames)
     {
@@ -2382,7 +2386,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);
@@ -2415,7 +2419,6 @@ unsetenv (const char *name)
 {
   char *var;
   size_t name_len;
-  int retval;
 
   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
     {
@@ -2514,7 +2517,7 @@ init_environment (char ** argv)
 
   int i;
 
-  const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
+  const int imax = ARRAYELTS (tempdirs);
 
   /* Implementation note: This function explicitly works with ANSI
      file names, not with UTF-8 encoded file names.  This is because
@@ -2587,7 +2590,7 @@ init_environment (char ** argv)
       {"LANG", NULL},
     };
 
-#define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
+#define N_ENV_VARS ARRAYELTS (dflt_envvars)
 
     /* We need to copy dflt_envvars[] and work on the copy because we
        don't want the dumped Emacs to inherit the values of
@@ -3398,30 +3401,41 @@ sys_readdir (DIR *dirp)
   /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
   else if (dir_find_handle == INVALID_HANDLE_VALUE)
     {
-      char filename[MAX_UTF8_PATH + 2];
+      char filename[MAX_UTF8_PATH];
       int ln;
+      bool last_slash = true;
 
+      /* Note: We don't need to worry about dir_pathname being longer
+        than MAX_UTF8_PATH, as sys_opendir already took care of that
+        when it called map_w32_filename: that function will put a "?"
+        in its return value in that case, thus failing all the calls
+        below.  */
       strcpy (filename, dir_pathname);
-      ln = strlen (filename) - 1;
-      if (!IS_DIRECTORY_SEP (filename[ln]))
-       strcat (filename, "\\");
-      strcat (filename, "*");
+      ln = strlen (filename);
+      if (!IS_DIRECTORY_SEP (filename[ln - 1]))
+       last_slash = false;
 
       /* Note: No need to resolve symlinks in FILENAME, because
         FindFirst opens the directory that is the target of a
         symlink.  */
       if (w32_unicode_filenames)
        {
-         wchar_t fnw[MAX_PATH];
+         wchar_t fnw[MAX_PATH + 2];
 
          filename_to_utf16 (filename, fnw);
+         if (!last_slash)
+           wcscat (fnw, L"\\");
+         wcscat (fnw, L"*");
          dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
        }
       else
        {
-         char fna[MAX_PATH];
+         char fna[MAX_PATH + 2];
 
          filename_to_ansi (filename, fna);
+         if (!last_slash)
+           strcat (fna, "\\");
+         strcat (fna, "*");
          /* If FILENAME is not representable by the current ANSI
             codepage, we don't want FindFirstFileA to interpret the
             '?' characters as a wildcard.  */
@@ -3433,17 +3447,31 @@ sys_readdir (DIR *dirp)
 
       if (dir_find_handle == INVALID_HANDLE_VALUE)
        {
+         /* Any changes in the value of errno here should be in sync
+            with what directory_files_internal does when it calls
+            readdir.  */
          switch (GetLastError ())
            {
-           case ERROR_PATH_NOT_FOUND:
+             /* Windows uses this value when FindFirstFile finds no
+                files that match the wildcard.  This is not supposed
+                to happen, since our wildcard is "*", but just in
+                case, if there's some weird empty directory with not
+                even "." and ".." entries...  */
+           case ERROR_FILE_NOT_FOUND:
+             errno = 0;
+             /* FALLTHRU */
+           default:
+             break;
            case ERROR_ACCESS_DENIED:
+           case ERROR_NETWORK_ACCESS_DENIED:
+             errno = EACCES;
+             break;
+           case ERROR_PATH_NOT_FOUND:
            case ERROR_INVALID_DRIVE:
+           case ERROR_NOT_READY:
            case ERROR_BAD_NETPATH:
-             /* This special value will be noticed by
-                directory_files_internal, which see.  */
-             errno = ENOTDIR;
-             break;
-           default:
+           case ERROR_BAD_NET_NAME:
+             errno = ENOENT;
              break;
            }
          return NULL;
@@ -3452,12 +3480,18 @@ sys_readdir (DIR *dirp)
   else if (w32_unicode_filenames)
     {
       if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
-       return NULL;
+       {
+         errno = 0;
+         return NULL;
+       }
     }
   else
     {
       if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
-       return NULL;
+       {
+         errno = 0;
+         return NULL;
+       }
     }
 
   /* Emacs never uses this value, so don't bother making it match
@@ -3559,7 +3593,11 @@ open_unc_volume (const char *path)
   if (result == NO_ERROR)
     return henum;
   else
-    return INVALID_HANDLE_VALUE;
+    {
+      /* Make sure directory_files_internal reports a sensible error.  */
+      errno = ENOENT;
+      return INVALID_HANDLE_VALUE;
+    }
 }
 
 static void *
@@ -3790,7 +3828,7 @@ faccessat (int dirfd, const char * path, int mode, int flags)
                  errno = EACCES;
                  return -1;
                }
-             break;
+             goto check_attrs;
            }
          /* FALLTHROUGH */
        case ERROR_FILE_NOT_FOUND:
@@ -3803,6 +3841,8 @@ faccessat (int dirfd, const char * path, int mode, int flags)
        }
       return -1;
     }
+
+ check_attrs:
   if ((mode & X_OK) != 0
       && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
     {
@@ -3822,6 +3862,76 @@ faccessat (int dirfd, const char * path, int mode, int flags)
   return 0;
 }
 
+/* A special test for DIRNAME being a directory accessible by the
+   current user.  This is needed because the security permissions in
+   directory's ACLs are not visible in the Posix-style mode bits
+   returned by 'stat' and in attributes returned by GetFileAttributes.
+   So a directory would seem like it's readable by the current user,
+   but will in fact error out with EACCES when they actually try.  */
+int
+w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
+{
+  char pattern[MAX_UTF8_PATH];
+  bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
+  HANDLE dh;
+
+  /* Network volumes need a different reading method.  */
+  if (is_unc_volume (dirname))
+    {
+      void *read_result = NULL;
+      wchar_t fnw[MAX_PATH];
+      char fna[MAX_PATH];
+
+      dh = open_unc_volume (dirname);
+      if (dh != INVALID_HANDLE_VALUE)
+       {
+         read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
+         close_unc_volume (dh);
+       }
+      /* Treat empty volumes as accessible.  */
+      return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
+    }
+
+  /* Note: map_w32_filename makes sure DIRNAME is not longer than
+     MAX_UTF8_PATH.  */
+  strcpy (pattern, map_w32_filename (dirname, NULL));
+
+  /* Note: No need to resolve symlinks in FILENAME, because FindFirst
+     opens the directory that is the target of a symlink.  */
+  if (w32_unicode_filenames)
+    {
+      wchar_t pat_w[MAX_PATH + 2];
+      WIN32_FIND_DATAW dfd_w;
+
+      filename_to_utf16 (pattern, pat_w);
+      if (!last_slash)
+       wcscat (pat_w, L"\\");
+      wcscat (pat_w, L"*");
+      dh = FindFirstFileW (pat_w, &dfd_w);
+    }
+  else
+    {
+      char pat_a[MAX_PATH + 2];
+      WIN32_FIND_DATAA dfd_a;
+
+      filename_to_ansi (pattern, pat_a);
+      if (!last_slash)
+       strcpy (pat_a, "\\");
+      strcat (pat_a, "*");
+      /* In case DIRNAME cannot be expressed in characters from the
+        current ANSI codepage.  */
+      if (_mbspbrk (pat_a, "?"))
+       dh = INVALID_HANDLE_VALUE;
+      else
+       dh = FindFirstFileA (pat_a, &dfd_a);
+    }
+
+  if (dh == INVALID_HANDLE_VALUE)
+    return 0;
+  FindClose (dh);
+  return 1;
+}
+
 /* A version of 'access' to be used locally with file names in
    locale-specific encoding.  Does not resolve symlinks and does not
    support file names on FAT12 and FAT16 volumes, but that's OK, since
@@ -4426,6 +4536,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)
@@ -4433,9 +4545,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
     {
@@ -4443,8 +4564,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;
@@ -4981,7 +5111,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
        {
          /* Make sure root directories end in a slash.  */
          if (!IS_DIRECTORY_SEP (name[len-1]))
-           strcat (name, "\\");
+           strcpy (name + len, "\\");
          if (GetDriveType (name) < 2)
            {
              errno = ENOENT;
@@ -5450,8 +5580,7 @@ symlink (char const *filename, char const *linkname)
        p--;
       if (p > linkfn)
        strncpy (tem, linkfn, p - linkfn);
-      tem[p - linkfn] = '\0';
-      strcat (tem, filename);
+      strcpy (tem + (p - linkfn), filename);
       dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
     }
   else
@@ -5519,7 +5648,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
@@ -5577,6 +5707,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, "?"))
     {
@@ -5590,6 +5722,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;
@@ -6520,7 +6654,6 @@ global_memory_status_ex (MEMORY_STATUS_EX *buf)
 Lisp_Object
 list_system_processes (void)
 {
-  struct gcpro gcpro1;
   Lisp_Object proclist = Qnil;
   HANDLE h_snapshot;
 
@@ -6532,8 +6665,6 @@ list_system_processes (void)
       DWORD proc_id;
       BOOL res;
 
-      GCPRO1 (proclist);
-
       proc_entry.dwSize = sizeof (PROCESSENTRY32);
       for (res = process32_first (h_snapshot, &proc_entry); res;
           res = process32_next  (h_snapshot, &proc_entry))
@@ -6543,7 +6674,6 @@ list_system_processes (void)
        }
 
       CloseHandle (h_snapshot);
-      UNGCPRO;
       proclist = Fnreverse (proclist);
     }
 
@@ -6672,7 +6802,6 @@ process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
 Lisp_Object
 system_process_attributes (Lisp_Object pid)
 {
-  struct gcpro gcpro1, gcpro2, gcpro3;
   Lisp_Object attrs = Qnil;
   Lisp_Object cmd_str, decoded_cmd, tem;
   HANDLE h_snapshot, h_proc;
@@ -6704,8 +6833,6 @@ system_process_attributes (Lisp_Object pid)
 
   h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
 
-  GCPRO3 (attrs, decoded_cmd, tem);
-
   if (h_snapshot != INVALID_HANDLE_VALUE)
     {
       PROCESSENTRY32 pe;
@@ -6747,10 +6874,7 @@ system_process_attributes (Lisp_Object pid)
     }
 
   if (!found_proc)
-    {
-      UNGCPRO;
-      return Qnil;
-    }
+    return Qnil;
 
   h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                        FALSE, proc_id);
@@ -6967,10 +7091,38 @@ system_process_attributes (Lisp_Object pid)
 
   if (h_proc)
     CloseHandle (h_proc);
-  UNGCPRO;
   return attrs;
 }
 
+int
+w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
+                unsigned long long *totalswap, unsigned long long *freeswap)
+{
+  MEMORYSTATUS memst;
+  MEMORY_STATUS_EX memstex;
+
+  /* Use GlobalMemoryStatusEx if available, as it can report more than
+     2GB of memory.  */
+  if (global_memory_status_ex (&memstex))
+    {
+      *totalram  = memstex.ullTotalPhys;
+      *freeram   = memstex.ullAvailPhys;
+      *totalswap = memstex.ullTotalPageFile;
+      *freeswap  = memstex.ullAvailPageFile;
+      return 0;
+    }
+  else if (global_memory_status (&memst))
+    {
+      *totalram = memst.dwTotalPhys;
+      *freeram   = memst.dwAvailPhys;
+      *totalswap = memst.dwTotalPageFile;
+      *freeswap  = memst.dwAvailPageFile;
+      return 0;
+    }
+  else
+    return -1;
+}
+
 \f
 /* Wrappers for  winsock functions to map between our file descriptors
    and winsock's handles; also set h_errno for convenience.
@@ -6985,6 +7137,9 @@ int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
 void (PASCAL *pfn_WSASetLastError) (int iError);
 int (PASCAL *pfn_WSAGetLastError) (void);
 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
+int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
+                                       WSANETWORKEVENTS *NetworkEvents);
+
 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
 int (PASCAL *pfn_socket) (int af, int type, int protocol);
@@ -7070,6 +7225,7 @@ init_winsock (int load_now)
       LOAD_PROC (WSASetLastError);
       LOAD_PROC (WSAGetLastError);
       LOAD_PROC (WSAEventSelect);
+      LOAD_PROC (WSAEnumNetworkEvents);
       LOAD_PROC (WSACreateEvent);
       LOAD_PROC (WSACloseEvent);
       LOAD_PROC (socket);
@@ -7153,6 +7309,8 @@ set_errno (void)
     case WSAEMFILE:            errno = EMFILE; break;
     case WSAENAMETOOLONG:      errno = ENAMETOOLONG; break;
     case WSAENOTEMPTY:         errno = ENOTEMPTY; break;
+    case WSAEWOULDBLOCK:       errno = EWOULDBLOCK; break;
+    case WSAENOTCONN:          errno = ENOTCONN; break;
     default:                   errno = wsa_err; break;
     }
 }
@@ -7274,7 +7432,7 @@ sys_socket (int af, int type, int protocol)
   if (winsock_lib == NULL)
     {
       errno = ENETDOWN;
-      return INVALID_SOCKET;
+      return -1;
     }
 
   check_errno ();
@@ -7337,7 +7495,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);
@@ -7420,7 +7578,17 @@ sys_connect (int s, const struct sockaddr * name, int namelen)
     {
       int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
       if (rc == SOCKET_ERROR)
-       set_errno ();
+       {
+         set_errno ();
+         /* If this is a non-blocking 'connect', set the bit in flags
+            that will tell reader_thread to wait for connection
+            before trying to read.  */
+         if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
+           {
+             errno = EINPROGRESS; /* that's what process.c expects */
+             fd_info[s].flags |= FILE_CONNECT;
+           }
+       }
       return rc;
     }
   errno = ENOTSOCK;
@@ -7875,7 +8043,7 @@ pipe2 (int * phandles, int pipe2_flags)
   int rc;
   unsigned flags;
 
-  eassert (pipe2_flags == O_CLOEXEC);
+  eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
 
   /* make pipe handles non-inheritable; when we spawn a child, we
      replace the relevant handle with an inheritable one.  Also put
@@ -7931,6 +8099,8 @@ _sys_read_ahead (int fd)
       emacs_abort ();
     }
 
+  if ((fd_info[fd].flags & FILE_CONNECT) != 0)
+    DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
   cp->status = STATUS_READ_IN_PROGRESS;
 
   if (fd_info[fd].flags & FILE_PIPE)
@@ -8052,6 +8222,60 @@ _sys_wait_accept (int fd)
   return cp->status;
 }
 
+int
+_sys_wait_connect (int fd)
+{
+  HANDLE hEv;
+  child_process * cp;
+  int rc;
+
+  if (fd < 0 || fd >= MAXDESC)
+    return STATUS_READ_ERROR;
+
+  cp = fd_info[fd].cp;
+  if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
+    return STATUS_READ_ERROR;
+
+  cp->status = STATUS_READ_FAILED;
+
+  hEv = pfn_WSACreateEvent ();
+  rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
+  if (rc != SOCKET_ERROR)
+    {
+      do {
+       rc = WaitForSingleObject (hEv, 500);
+       Sleep (5);
+      } while (rc == WAIT_TIMEOUT
+              && cp->status != STATUS_READ_ERROR
+              && cp->char_avail);
+      if (rc == WAIT_OBJECT_0)
+       {
+         /* We've got an event, but it could be a successful
+            connection, or it could be a failure.  Find out
+            which one is it.  */
+         WSANETWORKEVENTS events;
+
+         pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
+         if ((events.lNetworkEvents & FD_CONNECT) != 0
+             && events.iErrorCode[FD_CONNECT_BIT])
+           {
+             cp->status = STATUS_CONNECT_FAILED;
+             cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
+           }
+         else
+           {
+             cp->status = STATUS_READ_SUCCEEDED;
+             cp->errcode = 0;
+           }
+       }
+      pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
+    }
+  else
+    pfn_WSACloseEvent (hEv);
+
+  return cp->status;
+}
+
 int
 sys_read (int fd, char * buffer, unsigned int count)
 {
@@ -8121,6 +8345,7 @@ sys_read (int fd, char * buffer, unsigned int count)
              ResetEvent (cp->char_avail);
 
            case STATUS_READ_ACKNOWLEDGED:
+           case STATUS_CONNECT_FAILED:
              break;
 
            default:
@@ -8186,7 +8411,29 @@ sys_read (int fd, char * buffer, unsigned int count)
            {
              if (winsock_lib == NULL) emacs_abort ();
 
-             /* do the equivalent of a non-blocking read */
+             /* When a non-blocking 'connect' call fails,
+                wait_reading_process_output detects this by calling
+                'getpeername', and then attempts to obtain the connection
+                error code by trying to read 1 byte from the socket.  If
+                we try to serve that read by calling 'recv' below, the
+                error we get is a generic WSAENOTCONN, not the actual
+                connection error.  So instead, we use the actual error
+                code stashed by '_sys_wait_connect' in cp->errcode.
+                Alternatively, we could have used 'getsockopt', like on
+                GNU/Linux, but: (a) I have no idea whether the winsock
+                version could hang, as it does "on some systems" (see the
+                comment in process.c); and (b) 'getsockopt' on Windows is
+                documented to clear the socket error for the entire
+                process, which I'm not sure is TRT; FIXME.  */
+             if (current_status == STATUS_CONNECT_FAILED
+                 && (fd_info[fd].flags & FILE_CONNECT) != 0
+                 && cp->errcode != 0)
+               {
+                 pfn_WSASetLastError (cp->errcode);
+                 set_errno ();
+                 return -1;
+               }
+             /* Do the equivalent of a non-blocking read.  */
              pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
              if (waiting == 0 && nchars == 0)
                {
@@ -8200,9 +8447,9 @@ sys_read (int fd, char * buffer, unsigned int count)
                  int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
                  if (res == SOCKET_ERROR)
                    {
-                     DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
-                                pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
                      set_errno ();
+                     DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
+                                errno, SOCK_HANDLE (fd)));
                      return -1;
                    }
                  nchars += res;
@@ -8248,6 +8495,7 @@ int
 sys_write (int fd, const void * buffer, unsigned int count)
 {
   int nchars;
+  USE_SAFE_ALLOCA;
 
   if (fd < 0)
     {
@@ -8266,30 +8514,33 @@ sys_write (int fd, const void * buffer, unsigned int count)
       /* Perform text mode translation if required.  */
       if ((fd_info[fd].flags & FILE_BINARY) == 0)
        {
-         char * tmpbuf = alloca (count * 2);
-         unsigned char * src = (void *)buffer;
-         unsigned char * dst = tmpbuf;
+         char * tmpbuf;
+         const unsigned char * src = buffer;
+         unsigned char * dst;
          int nbytes = count;
 
+         SAFE_NALLOCA (tmpbuf, 2, count);
+         dst = (unsigned char *)tmpbuf;
+
          while (1)
            {
              unsigned char *next;
-             /* copy next line or remaining bytes */
+             /* Copy next line or remaining bytes.  */
              next = _memccpy (dst, src, '\n', nbytes);
              if (next)
                {
-                 /* copied one line ending with '\n' */
+                 /* Copied one line ending with '\n'.  */
                  int copied = next - dst;
                  nbytes -= copied;
                  src += copied;
-                 /* insert '\r' before '\n' */
+                 /* Insert '\r' before '\n'.  */
                  next[-1] = '\r';
                  next[0] = '\n';
                  dst = next + 1;
                  count++;
                }
              else
-               /* copied remaining partial line -> now finished */
+               /* Copied remaining partial line -> now finished.  */
                break;
            }
          buffer = tmpbuf;
@@ -8303,31 +8554,44 @@ sys_write (int fd, const void * buffer, unsigned int count)
       HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
       DWORD active = 0;
 
+      /* This is async (a.k.a. "overlapped") I/O, so the return value
+        of FALSE from WriteFile means either an error or the output
+        will be completed asynchronously (ERROR_IO_PENDING).  */
       if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
        {
          if (GetLastError () != ERROR_IO_PENDING)
            {
              errno = EIO;
-             return -1;
+             nchars = -1;
            }
-         if (detect_input_pending ())
-           active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
-                                               QS_ALLINPUT);
          else
-           active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
-         if (active == WAIT_OBJECT_0)
-           { /* User pressed C-g, cancel write, then leave.  Don't bother
-                cleaning up as we may only get stuck in buggy drivers.  */
-             PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
-             CancelIo (hnd);
-             errno = EIO;
-             return -1;
-           }
-         if (active == WAIT_OBJECT_0 + 1
-             && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
            {
-             errno = EIO;
-             return -1;
+             /* Wait for the write to complete, and watch C-g while
+                at that.  */
+             if (detect_input_pending ())
+               active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
+                                                   INFINITE, QS_ALLINPUT);
+             else
+               active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
+             switch (active)
+               {
+               case WAIT_OBJECT_0:
+                 /* User pressed C-g, cancel write, then leave.
+                    Don't bother cleaning up as we may only get stuck
+                    in buggy drivers.  */
+                 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
+                 CancelIo (hnd);
+                 errno = EIO;  /* Why not EINTR? */
+                 nchars = -1;
+                 break;
+               case WAIT_OBJECT_0 + 1:
+                 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
+                   {
+                     errno = EIO;
+                     nchars = -1;
+                   }
+                 break;
+               }
            }
        }
     }
@@ -8404,6 +8668,7 @@ sys_write (int fd, const void * buffer, unsigned int count)
        }
     }
 
+  SAFE_FREE ();
   return nchars;
 }
 
@@ -8753,6 +9018,13 @@ w32_delayed_load (Lisp_Object library_id)
                               /* Possibly truncated */
                               ? make_specified_string (name, -1, len, 1)
                               : Qnil);
+               /* This prevents thread start and end notifications
+                  from being sent to the DLL, for every thread we
+                  start.  We don't need those notifications because
+                  threads we create never use any of these DLLs, only
+                  the main thread uses them.  This is supposed to
+                  speed up thread creation.  */
+               DisableThreadLibraryCalls (dll_handle);
                break;
              }
          }
@@ -8790,8 +9062,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));
@@ -8998,8 +9270,10 @@ 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");
          return ret;
        }
       else
@@ -9086,6 +9360,7 @@ globals_of_w32 (void)
   g_b_init_set_named_security_info_w = 0;
   g_b_init_set_named_security_info_a = 0;
   g_b_init_get_adapters_info = 0;
+  g_b_init_compare_string_w = 0;
   num_of_processors = 0;
   /* The following sets a handler for shutdown notifications for
      console apps. This actually applies to Emacs in both console and
@@ -9106,6 +9381,11 @@ 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
 }
 
 /* For make-serial-process  */
@@ -9299,14 +9579,32 @@ serial_configure (struct Lisp_Process *p, Lisp_Object contact)
   pset_childp (p, childp2);
 }
 
+/* For make-pipe-process */
+void
+register_aux_fd (int infd)
+{
+  child_process *cp;
+
+  cp = new_child ();
+  if (!cp)
+    error ("Could not create child process");
+  cp->fd = infd;
+  cp->status = STATUS_READ_ACKNOWLEDGED;
+
+  if (fd_info[ infd ].cp != NULL)
+    {
+      error ("fd_info[fd = %d] is already in use", infd);
+    }
+  fd_info[ infd ].cp = cp;
+  fd_info[ infd ].hnd = (HANDLE) _get_osfhandle (infd);
+}
+
 #ifdef HAVE_GNUTLS
 
 ssize_t
 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
 {
   int n, err;
-  SELECT_TYPE fdset;
-  struct timespec timeout;
   struct Lisp_Process *process = (struct Lisp_Process *)p;
   int fd = process->infd;