Fix doc-string of pop-to-buffer-same-window. (Bug#15492)
[bpt/emacs.git] / src / w32.c
index 214fb7f..1dcf46b 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -29,10 +29,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <ctype.h>
 #include <signal.h>
 #include <sys/file.h>
+#include <time.h>      /* must be before nt/inc/sys/time.h, for MinGW64 */
 #include <sys/time.h>
 #include <sys/utime.h>
 #include <math.h>
-#include <time.h>
 
 /* must include CRT headers *before* config.h */
 
@@ -47,7 +47,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #undef fopen
 #undef link
 #undef mkdir
-#undef mktemp
 #undef open
 #undef rename
 #undef rmdir
@@ -65,11 +64,13 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #undef localtime
 
 #include "lisp.h"
+#include "epaths.h"    /* for SHELL */
 
 #include <pwd.h>
 #include <grp.h>
 
-#ifdef __GNUC__
+/* MinGW64 (_W64) defines these in its _mingw.h.  */
+#if defined(__GNUC__) && !defined(_W64)
 #define _ANONYMOUS_UNION
 #define _ANONYMOUS_STRUCT
 #endif
@@ -88,6 +89,21 @@ typedef struct _MEMORY_STATUS_EX {
   DWORDLONG ullAvailExtendedVirtual;
 } 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
+   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
+   call-stack of the main thread, so going to that call frame and
+   looking at the argument to _gnu_exception_handler, which is a
+   PEXCEPTION_POINTERS pointer, can reveal the exception code
+   (excptr->ExceptionRecord->ExceptionCode) and the address where the
+   exception happened (excptr->ExceptionRecord->ExceptionAddress), as
+   well as some additional information specific to the exception.  */
+PEXCEPTION_POINTERS excptr;
+PEXCEPTION_RECORD excprec;
+PCONTEXT ctxrec;
+
 #include <lmcons.h>
 #include <shlobj.h>
 
@@ -96,6 +112,7 @@ typedef struct _MEMORY_STATUS_EX {
 #ifndef _MSC_VER
 #include <w32api.h>
 #endif
+#if _WIN32_WINNT < 0x0500
 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
 /* This either is not in psapi.h or guarded by higher value of
    _WIN32_WINNT than what we use.  w32api supplied with MinGW 3.15
@@ -114,15 +131,25 @@ typedef struct _PROCESS_MEMORY_COUNTERS_EX {
   SIZE_T PrivateUsage;
 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
 #endif
+#endif
 
 #include <winioctl.h>
 #include <aclapi.h>
+#include <sddl.h>
 
-#ifdef _MSC_VER
-/* MSVC doesn't provide the definition of REPARSE_DATA_BUFFER and the
-   associated macros, except on ntifs.h, which cannot be included
-   because it triggers conflicts with other Windows API headers.  So
-   we define it here by hand.  */
+#include <sys/acl.h>
+
+/* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
+   define them by hand if not already defined.  */
+#ifndef SDDL_REVISION_1
+#define SDDL_REVISION_1        1
+#endif /* SDDL_REVISION_1 */
+
+#if defined(_MSC_VER) || defined(_W64)
+/* MSVC and MinGW64 don't provide the definition of
+   REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
+   which cannot be included because it triggers conflicts with other
+   Windows API headers.  So we define it here by hand.  */
 
 typedef struct _REPARSE_DATA_BUFFER {
     ULONG  ReparseTag;
@@ -162,9 +189,12 @@ typedef struct _REPARSE_DATA_BUFFER {
 #ifndef CTL_CODE
 #define CTL_CODE(t,f,m,a)       (((t)<<16)|((a)<<14)|((f)<<2)|(m))
 #endif
+/* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h.  */
+#ifndef FSCTL_GET_REPARSE_POINT
 #define FSCTL_GET_REPARSE_POINT \
   CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
 #endif
+#endif
 
 /* TCP connection support.  */
 #include <sys/socket.h>
@@ -187,7 +217,7 @@ typedef struct _REPARSE_DATA_BUFFER {
 #undef sendto
 
 #include "w32.h"
-#include "ndir.h"
+#include <dirent.h>
 #include "w32common.h"
 #include "w32heap.h"
 #include "w32select.h"
@@ -217,7 +247,9 @@ static BOOL WINAPI revert_to_self (void);
 extern int sys_access (const char *, int);
 extern void *e_malloc (size_t);
 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
-                      EMACS_TIME *, void *);
+                      struct timespec *, void *);
+extern int sys_dup (int);
+
 
 
 \f
@@ -257,6 +289,11 @@ static BOOL g_b_init_copy_sid;
 static BOOL g_b_init_get_native_system_info;
 static BOOL g_b_init_get_system_times;
 static BOOL g_b_init_create_symbolic_link;
+static BOOL g_b_init_get_security_descriptor_dacl;
+static BOOL g_b_init_convert_sd_to_sddl;
+static BOOL g_b_init_convert_sddl_to_sd;
+static BOOL g_b_init_is_valid_security_descriptor;
+static BOOL g_b_init_set_file_security;
 
 /*
   BEGIN: Wrapper functions around OpenProcessToken
@@ -286,9 +323,11 @@ GetProcessTimes_Proc get_process_times_fn = NULL;
 #ifdef _UNICODE
 const char * const LookupAccountSid_Name = "LookupAccountSidW";
 const char * const GetFileSecurity_Name =  "GetFileSecurityW";
+const char * const SetFileSecurity_Name =  "SetFileSecurityW";
 #else
 const char * const LookupAccountSid_Name = "LookupAccountSidA";
 const char * const GetFileSecurity_Name =  "GetFileSecurityA";
+const char * const SetFileSecurity_Name =  "SetFileSecurityA";
 #endif
 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
     LPCTSTR lpSystemName,
@@ -318,6 +357,10 @@ typedef BOOL (WINAPI * GetFileSecurity_Proc) (
     PSECURITY_DESCRIPTOR pSecurityDescriptor,
     DWORD nLength,
     LPDWORD lpnLengthNeeded);
+typedef BOOL (WINAPI *SetFileSecurity_Proc) (
+    LPCTSTR lpFileName,
+    SECURITY_INFORMATION SecurityInformation,
+    PSECURITY_DESCRIPTOR pSecurityDescriptor);
 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
     PSECURITY_DESCRIPTOR pSecurityDescriptor,
     PSID *pOwner,
@@ -326,6 +369,11 @@ typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
     PSECURITY_DESCRIPTOR pSecurityDescriptor,
     PSID *pGroup,
     LPBOOL lpbGroupDefaulted);
+typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
+    PSECURITY_DESCRIPTOR pSecurityDescriptor,
+    LPBOOL lpbDaclPresent,
+    PACL *pDacl,
+    LPBOOL lpbDaclDefaulted);
 typedef BOOL (WINAPI * IsValidSid_Proc) (
     PSID sid);
 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
@@ -376,6 +424,18 @@ typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) (
     LPTSTR lpSymlinkFileName,
     LPTSTR lpTargetFileName,
     DWORD  dwFlags);
+typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
+    LPCTSTR StringSecurityDescriptor,
+    DWORD StringSDRevision,
+    PSECURITY_DESCRIPTOR  *SecurityDescriptor,
+    PULONG  SecurityDescriptorSize);
+typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
+    PSECURITY_DESCRIPTOR  SecurityDescriptor,
+    DWORD RequestedStringSDRevision,
+    SECURITY_INFORMATION SecurityInformation,
+    LPTSTR  *StringSecurityDescriptor,
+    PULONG StringSecurityDescriptorLen);
+typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
 
   /* ** A utility function ** */
 static BOOL
@@ -621,6 +681,7 @@ get_file_security (LPCTSTR lpFileName,
   HMODULE hm_advapi32 = NULL;
   if (is_windows_9x () == TRUE)
     {
+      errno = ENOTSUP;
       return FALSE;
     }
   if (g_b_init_get_file_security == 0)
@@ -633,6 +694,7 @@ get_file_security (LPCTSTR lpFileName,
     }
   if (s_pfn_Get_File_Security == NULL)
     {
+      errno = ENOTSUP;
       return FALSE;
     }
   return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
@@ -640,6 +702,35 @@ get_file_security (LPCTSTR lpFileName,
                                   lpnLengthNeeded));
 }
 
+static BOOL WINAPI
+set_file_security (LPCTSTR lpFileName,
+                  SECURITY_INFORMATION SecurityInformation,
+                  PSECURITY_DESCRIPTOR pSecurityDescriptor)
+{
+  static SetFileSecurity_Proc s_pfn_Set_File_Security = NULL;
+  HMODULE hm_advapi32 = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      errno = ENOTSUP;
+      return FALSE;
+    }
+  if (g_b_init_set_file_security == 0)
+    {
+      g_b_init_set_file_security = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Set_File_Security =
+        (SetFileSecurity_Proc) GetProcAddress (
+            hm_advapi32, SetFileSecurity_Name);
+    }
+  if (s_pfn_Set_File_Security == NULL)
+    {
+      errno = ENOTSUP;
+      return FALSE;
+    }
+  return (s_pfn_Set_File_Security (lpFileName, SecurityInformation,
+                                  pSecurityDescriptor));
+}
+
 static BOOL WINAPI
 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
                               PSID *pOwner,
@@ -649,6 +740,7 @@ get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
   HMODULE hm_advapi32 = NULL;
   if (is_windows_9x () == TRUE)
     {
+      errno = ENOTSUP;
       return FALSE;
     }
   if (g_b_init_get_security_descriptor_owner == 0)
@@ -661,6 +753,7 @@ get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
     }
   if (s_pfn_Get_Security_Descriptor_Owner == NULL)
     {
+      errno = ENOTSUP;
       return FALSE;
     }
   return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
@@ -676,6 +769,7 @@ get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
   HMODULE hm_advapi32 = NULL;
   if (is_windows_9x () == TRUE)
     {
+      errno = ENOTSUP;
       return FALSE;
     }
   if (g_b_init_get_security_descriptor_group == 0)
@@ -688,12 +782,44 @@ get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
     }
   if (s_pfn_Get_Security_Descriptor_Group == NULL)
     {
+      errno = ENOTSUP;
       return FALSE;
     }
   return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
                                               lpbGroupDefaulted));
 }
 
+static BOOL WINAPI
+get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
+                             LPBOOL lpbDaclPresent,
+                             PACL *pDacl,
+                             LPBOOL lpbDaclDefaulted)
+{
+  static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
+  HMODULE hm_advapi32 = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      errno = ENOTSUP;
+      return FALSE;
+    }
+  if (g_b_init_get_security_descriptor_dacl == 0)
+    {
+      g_b_init_get_security_descriptor_dacl = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Get_Security_Descriptor_Dacl =
+        (GetSecurityDescriptorDacl_Proc) GetProcAddress (
+            hm_advapi32, "GetSecurityDescriptorDacl");
+    }
+  if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
+    {
+      errno = ENOTSUP;
+      return FALSE;
+    }
+  return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
+                                             lpbDaclPresent, pDacl,
+                                             lpbDaclDefaulted));
+}
+
 static BOOL WINAPI
 is_valid_sid (PSID sid)
 {
@@ -888,6 +1014,120 @@ create_symbolic_link (LPTSTR lpSymlinkFilename,
     }
   return retval;
 }
+
+static BOOL WINAPI
+is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
+{
+  static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
+
+  if (is_windows_9x () == TRUE)
+    {
+      errno = ENOTSUP;
+      return FALSE;
+    }
+
+  if (g_b_init_is_valid_security_descriptor == 0)
+    {
+      g_b_init_is_valid_security_descriptor = 1;
+      s_pfn_Is_Valid_Security_Descriptor_Proc =
+       (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
+                                                       "IsValidSecurityDescriptor");
+    }
+  if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
+    {
+      errno = ENOTSUP;
+      return FALSE;
+    }
+
+  return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
+}
+
+static BOOL WINAPI
+convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
+                   DWORD RequestedStringSDRevision,
+                   SECURITY_INFORMATION SecurityInformation,
+                   LPTSTR  *StringSecurityDescriptor,
+                   PULONG StringSecurityDescriptorLen)
+{
+  static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
+  BOOL retval;
+
+  if (is_windows_9x () == TRUE)
+    {
+      errno = ENOTSUP;
+      return FALSE;
+    }
+
+  if (g_b_init_convert_sd_to_sddl == 0)
+    {
+      g_b_init_convert_sd_to_sddl = 1;
+#ifdef _UNICODE
+      s_pfn_Convert_SD_To_SDDL =
+       (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
+                                                                                 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
+#else
+      s_pfn_Convert_SD_To_SDDL =
+       (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
+                                                                                 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
+#endif
+    }
+  if (s_pfn_Convert_SD_To_SDDL == NULL)
+    {
+      errno = ENOTSUP;
+      return FALSE;
+    }
+
+  retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
+                                    RequestedStringSDRevision,
+                                    SecurityInformation,
+                                    StringSecurityDescriptor,
+                                    StringSecurityDescriptorLen);
+
+  return retval;
+}
+
+static BOOL WINAPI
+convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
+                   DWORD StringSDRevision,
+                   PSECURITY_DESCRIPTOR  *SecurityDescriptor,
+                   PULONG  SecurityDescriptorSize)
+{
+  static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
+  BOOL retval;
+
+  if (is_windows_9x () == TRUE)
+    {
+      errno = ENOTSUP;
+      return FALSE;
+    }
+
+  if (g_b_init_convert_sddl_to_sd == 0)
+    {
+      g_b_init_convert_sddl_to_sd = 1;
+#ifdef _UNICODE
+      s_pfn_Convert_SDDL_To_SD =
+       (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
+                                                                                 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
+#else
+      s_pfn_Convert_SDDL_To_SD =
+       (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
+                                                                                 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
+#endif
+    }
+  if (s_pfn_Convert_SDDL_To_SD == NULL)
+    {
+      errno = ENOTSUP;
+      return FALSE;
+    }
+
+  retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
+                                    StringSDRevision,
+                                    SecurityDescriptor,
+                                    SecurityDescriptorSize);
+
+  return retval;
+}
+
 \f
 
 /* Return 1 if P is a valid pointer to an object of size SIZE.  Return
@@ -916,8 +1156,18 @@ static char startup_dir[MAXPATHLEN];
 
 /* Get the current working directory.  */
 char *
-getwd (char *dir)
+getcwd (char *dir, int dirsize)
 {
+  if (!dirsize)
+    {
+      errno = EINVAL;
+      return NULL;
+    }
+  if (dirsize <= strlen (startup_dir))
+    {
+      errno = ERANGE;
+      return NULL;
+    }
 #if 0
   if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
     return dir;
@@ -1371,12 +1621,17 @@ max_filename_mbslen (void)
    case path name components to lower case.  */
 
 static void
-normalize_filename (register char *fp, char path_sep)
+normalize_filename (register char *fp, char path_sep, int multibyte)
 {
   char sep;
   char *elem, *p2;
   int dbcs_p = max_filename_mbslen () > 1;
 
+  /* Multibyte file names are in the Emacs internal representation, so
+     we can traverse them by bytes with no problems.  */
+  if (multibyte)
+    dbcs_p = 0;
+
   /* Always lower-case drive letters a-z, even if the filesystem
      preserves case in filenames.
      This is so filenames can be compared by string comparison
@@ -1393,7 +1648,7 @@ normalize_filename (register char *fp, char path_sep)
       fp += 2;
     }
 
-  if (NILP (Vw32_downcase_file_names))
+  if (multibyte || NILP (Vw32_downcase_file_names))
     {
       while (*fp)
        {
@@ -1441,18 +1696,20 @@ normalize_filename (register char *fp, char path_sep)
   } while (*fp);
 }
 
-/* Destructively turn backslashes into slashes.  */
+/* Destructively turn backslashes into slashes.  MULTIBYTE non-zero
+   means the file name is a multibyte string in Emacs's internal
+   representation.  */
 void
-dostounix_filename (register char *p)
+dostounix_filename (register char *p, int multibyte)
 {
-  normalize_filename (p, '/');
+  normalize_filename (p, '/', multibyte);
 }
 
 /* Destructively turn slashes into backslashes.  */
 void
 unixtodos_filename (register char *p)
 {
-  normalize_filename (p, '\\');
+  normalize_filename (p, '\\', 0);
 }
 
 /* Remove all CR's that are followed by a LF.
@@ -1616,6 +1873,51 @@ is_unc_volume (const char *filename)
   return 1;
 }
 
+/* Emulate the Posix unsetenv.  */
+int
+unsetenv (const char *name)
+{
+  char *var;
+  size_t name_len;
+  int retval;
+
+  if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  name_len = strlen (name);
+  /* MS docs says an environment variable cannot be longer than 32K.  */
+  if (name_len > 32767)
+    {
+      errno = ENOMEM;
+      return 0;
+    }
+  /* It is safe to use 'alloca' with 32K size, since the stack is at
+     least 2MB, and we set it to 8MB in the link command line.  */
+  var = alloca (name_len + 2);
+  strncpy (var, name, name_len);
+  var[name_len++] = '=';
+  var[name_len] = '\0';
+  return _putenv (var);
+}
+
+/* MS _putenv doesn't support removing a variable when the argument
+   does not include the '=' character, so we fix that here.  */
+int
+sys_putenv (char *str)
+{
+  const char *const name_end = strchr (str, '=');
+
+  if (name_end == NULL)
+    {
+      /* Remove the variable from the environment.  */
+      return unsetenv (str);
+    }
+
+  return _putenv (str);
+}
+
 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
 
 LPBYTE
@@ -1694,7 +1996,7 @@ init_environment (char ** argv)
         see if it succeeds.  But I think that's too much to ask.  */
 
       /* MSVCRT's _access crashes with D_OK.  */
-      if (tmp && sys_access (tmp, D_OK) == 0)
+      if (tmp && faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0)
        {
          char * var = alloca (strlen (tmp) + 8);
          sprintf (var, "TMPDIR=%s", tmp);
@@ -1733,7 +2035,7 @@ init_environment (char ** argv)
       {"PRELOAD_WINSOCK", NULL},
       {"emacs_dir", "C:/emacs"},
       {"EMACSLOADPATH", NULL},
-      {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
+      {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
       {"EMACSDATA", NULL},
       {"EMACSPATH", NULL},
       {"INFOPATH", NULL},
@@ -1809,9 +2111,12 @@ init_environment (char ** argv)
        emacs_abort ();
       *p = 0;
 
-      if ((p = _mbsrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
+      if ((p = _mbsrchr (modname, '\\'))
+         /* From bin means installed Emacs, from src means uninstalled.  */
+         && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
        {
          char buf[SET_ENV_BUF_SIZE];
+         int within_build_tree = xstrcasecmp (p, "\\src") == 0;
 
          *p = 0;
          for (p = modname; *p; p = CharNext (p))
@@ -1819,6 +2124,15 @@ init_environment (char ** argv)
 
          _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
          _putenv (strdup (buf));
+         /* If we are running from the Posix-like build tree, define
+            SHELL to point to our own cmdproxy.  The loop below will
+            then disregard PATH_EXEC and the default value.  */
+         if (within_build_tree)
+           {
+             _snprintf (buf, sizeof (buf) - 1,
+                        "SHELL=%s/nt/cmdproxy.exe", modname);
+             _putenv (strdup (buf));
+           }
        }
       /* Handle running emacs from the build directory: src/oo-spd/i386/  */
 
@@ -1854,16 +2168,60 @@ init_environment (char ** argv)
        if (!getenv (env_vars[i].name))
          {
            int dont_free = 0;
+           char bufc[SET_ENV_BUF_SIZE];
 
            if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
                /* Also ignore empty environment variables.  */
                || *lpval == 0)
              {
                xfree (lpval);
-               lpval = env_vars[i].def_value;
-               dwType = REG_EXPAND_SZ;
                dont_free = 1;
-               if (!strcmp (env_vars[i].name, "HOME") && !appdata)
+               if (strcmp (env_vars[i].name, "SHELL") == 0)
+                 {
+                   /* Look for cmdproxy.exe in every directory in
+                      PATH_EXEC.  FIXME: This does not find cmdproxy
+                      in nt/ when we run uninstalled.  */
+                   char fname[MAX_PATH];
+                   const char *pstart = PATH_EXEC, *pend;
+
+                   do {
+                     pend = _mbschr (pstart, ';');
+                     if (!pend)
+                       pend = pstart + strlen (pstart);
+                     /* Be defensive against series of ;;; characters.  */
+                     if (pend > pstart)
+                       {
+                         strncpy (fname, pstart, pend - pstart);
+                         fname[pend - pstart] = '/';
+                         strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
+                         ExpandEnvironmentStrings ((LPSTR) fname, bufc,
+                                                   sizeof (bufc));
+                         if (check_existing (bufc))
+                           {
+                             lpval = bufc;
+                             dwType = REG_SZ;
+                             break;
+                           }
+                       }
+                     if (*pend)
+                       pstart = pend + 1;
+                     else
+                       pstart = pend;
+                     if (!*pstart)
+                       {
+                         /* If not found in any directory, use the
+                            default as the last resort.  */
+                         lpval = env_vars[i].def_value;
+                         dwType = REG_EXPAND_SZ;
+                       }
+                   } while (*pstart);
+                 }
+               else
+                 {
+                   lpval = env_vars[i].def_value;
+                   dwType = REG_EXPAND_SZ;
+                 }
+               if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
                  Vdelayed_warnings_list
                    = Fcons (listn (CONSTYPE_HEAP, 2,
                                    intern ("initialization"),
@@ -1915,7 +2273,7 @@ init_environment (char ** argv)
        memcpy (*envp, "COMSPEC=", 8);
   }
 
-  /* Remember the initial working directory for getwd.  */
+  /* Remember the initial working directory for getcwd.  */
   /* FIXME: Do we need to resolve possible symlinks in startup_dir?
      Does it matter anywhere in Emacs?  */
   if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
@@ -1950,7 +2308,7 @@ emacs_root_dir (void)
     emacs_abort ();
   strcpy (root_dir, p);
   root_dir[parse_root (root_dir, NULL)] = '\0';
-  dostounix_filename (root_dir);
+  dostounix_filename (root_dir, 0);
   return root_dir;
 }
 
@@ -2109,8 +2467,8 @@ get_emacs_configuration_options (void)
 #include <sys/timeb.h>
 
 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95).  */
-void
-gettimeofday (struct timeval *tv, struct timezone *tz)
+int
+gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
 {
   struct _timeb tb;
   _ftime (&tb);
@@ -2128,6 +2486,7 @@ gettimeofday (struct timeval *tv, struct timezone *tz)
       tz->tz_minuteswest = tb.timezone;        /* minutes west of Greenwich  */
       tz->tz_dsttime = tb.dstflag;     /* type of dst correction  */
     }
+  return 0;
 }
 
 /* Emulate fdutimens.  */
@@ -2144,8 +2503,6 @@ gettimeofday (struct timeval *tv, struct timezone *tz)
 int
 fdutimens (int fd, char const *file, struct timespec const timespec[2])
 {
-  struct _utimbuf ut;
-
   if (!timespec)
     {
       errno = ENOSYS;
@@ -2156,12 +2513,28 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2])
       errno = EBADF;
       return -1;
     }
-  ut.actime = timespec[0].tv_sec;
-  ut.modtime = timespec[1].tv_sec;
+  /* _futime's prototype defines 2nd arg as having the type 'struct
+     _utimbuf', while utime needs to accept 'struct utimbuf' for
+     compatibility with Posix.  So we need to use 2 different (but
+     equivalent) types to avoid compiler warnings, sigh.  */
   if (fd >= 0)
-    return _futime (fd, &ut);
+    {
+      struct _utimbuf _ut;
+
+      _ut.actime = timespec[0].tv_sec;
+      _ut.modtime = timespec[1].tv_sec;
+      return _futime (fd, &_ut);
+    }
   else
-    return _utime (file, &ut);
+    {
+      struct utimbuf ut;
+
+      ut.actime = timespec[0].tv_sec;
+      ut.modtime = timespec[1].tv_sec;
+      /* Call 'utime', which is implemented below, not the MS library
+        function, which fails on directories.  */
+      return utime (file, &ut);
+    }
 }
 
 
@@ -2539,7 +2912,7 @@ is_exec (const char * name)
    and readdir.  We can't use the procedures supplied in sysdep.c,
    so we provide them here.  */
 
-struct direct dir_static;       /* simulated directory contents */
+struct dirent dir_static;       /* simulated directory contents */
 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
 static int    dir_is_fat;
 static char   dir_pathname[MAXPATHLEN+1];
@@ -2553,7 +2926,7 @@ static char  *read_unc_volume (HANDLE, char *, int);
 static void   close_unc_volume (HANDLE);
 
 DIR *
-opendir (char *filename)
+opendir (const char *filename)
 {
   DIR *dirp;
 
@@ -2609,7 +2982,7 @@ closedir (DIR *dirp)
   xfree ((char *) dirp);
 }
 
-struct direct *
+struct dirent *
 readdir (DIR *dirp)
 {
   int downcase = !NILP (Vw32_downcase_file_names);
@@ -2675,7 +3048,7 @@ readdir (DIR *dirp)
       downcase = 1;    /* 8+3 aliases are returned in all caps */
     }
   dir_static.d_namlen = strlen (dir_static.d_name);
-  dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
+  dir_static.d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
     dir_static.d_namlen - dir_static.d_namlen % 4;
 
   /* If the file name in cFileName[] includes `?' characters, it means
@@ -2849,16 +3222,20 @@ logon_network_drive (const char *path)
   WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
 }
 
-/* Shadow some MSVC runtime functions to map requests for long filenames
-   to reasonable short names if necessary.  This was originally added to
-   permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
-   long file names.  */
-
+/* Emulate faccessat(2).  */
 int
-sys_access (const char * path, int mode)
+faccessat (int dirfd, const char * path, int mode, int flags)
 {
   DWORD attributes;
 
+  if (dirfd != AT_FDCWD
+      && !(IS_DIRECTORY_SEP (path[0])
+          || IS_DEVICE_SEP (path[1])))
+    {
+      errno = EBADF;
+      return -1;
+    }
+
   /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
      newer versions blow up when passed D_OK.  */
   path = map_w32_filename (path, NULL);
@@ -2866,7 +3243,8 @@ sys_access (const char * path, int mode)
      to get the attributes of its target file.  Note: any symlinks in
      PATH elements other than the last one are transparently resolved
      by GetFileAttributes below.  */
-  if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
+  if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
+      && (flags & AT_SYMLINK_NOFOLLOW) == 0)
     path = chase_symlinks (path);
 
   if ((attributes = GetFileAttributes (path)) == -1)
@@ -2898,7 +3276,8 @@ sys_access (const char * path, int mode)
        }
       return -1;
     }
-  if ((mode & X_OK) != 0 && !is_exec (path))
+  if ((mode & X_OK) != 0
+      && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
     {
       errno = EACCES;
       return -1;
@@ -2916,6 +3295,11 @@ sys_access (const char * path, int mode)
   return 0;
 }
 
+/* Shadow some MSVC runtime functions to map requests for long filenames
+   to reasonable short names if necessary.  This was originally added to
+   permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
+   long file names.  */
+
 int
 sys_chdir (const char * path)
 {
@@ -2929,14 +3313,6 @@ sys_chmod (const char * path, int mode)
   return _chmod (path, mode);
 }
 
-int
-sys_chown (const char *path, uid_t owner, gid_t group)
-{
-  if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
-    return -1;
-  return 0;
-}
-
 int
 sys_creat (const char * path, int mode)
 {
@@ -3066,25 +3442,46 @@ sys_mkdir (const char * path)
   return _mkdir (map_w32_filename (path, NULL));
 }
 
-/* Because of long name mapping issues, we need to implement this
-   ourselves.  Also, MSVC's _mktemp returns NULL when it can't generate
-   a unique name, instead of setting the input template to an empty
-   string.
+int
+sys_open (const char * path, int oflag, int mode)
+{
+  const char* mpath = map_w32_filename (path, NULL);
+  int res = -1;
 
-   Standard algorithm seems to be use pid or tid with a letter on the
-   front (in place of the 6 X's) and cycle through the letters to find a
-   unique name.  We extend that to allow any reasonable character as the
-   first of the 6 X's.  */
-char *
-sys_mktemp (char * template)
+  /* If possible, try to open file without _O_CREAT, to be able to
+     write to existing hidden and system files.  Force all file
+     handles to be non-inheritable. */
+  if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
+    res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
+  if (res < 0)
+    res = _open (mpath, oflag | _O_NOINHERIT, mode);
+
+  return res;
+}
+
+/* Implementation of mkostemp for MS-Windows, to avoid race conditions
+   when using mktemp.
+
+   Standard algorithm for generating a temporary file name seems to be
+   use pid or tid with a letter on the front (in place of the 6 X's)
+   and cycle through the letters to find a unique name.  We extend
+   that to allow any reasonable character as the first of the 6 X's,
+   so that the number of simultaneously used temporary files will be
+   greater.  */
+
+int
+mkostemp (char * template, int flags)
 {
   char * p;
-  int i;
+  int i, fd = -1;
   unsigned uid = GetCurrentThreadId ();
+  int save_errno = errno;
   static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
 
+  errno = EINVAL;
   if (template == NULL)
-    return NULL;
+    return -1;
+
   p = template + strlen (template);
   i = 5;
   /* replace up to the last 5 X's with uid in decimal */
@@ -3099,41 +3496,32 @@ sys_mktemp (char * template)
       i = 0;
       do
        {
-         int save_errno = errno;
          p[0] = first_char[i];
-         if (sys_access (template, 0) < 0)
+         if ((fd = sys_open (template,
+                             flags | _O_CREAT | _O_EXCL | _O_RDWR,
+                             S_IRUSR | S_IWUSR)) >= 0
+             || errno != EEXIST)
            {
-             errno = save_errno;
-             return template;
+             if (fd >= 0)
+               errno = save_errno;
+             return fd;
            }
        }
       while (++i < sizeof (first_char));
     }
 
-  /* Template is badly formed or else we can't generate a unique name,
-     so return empty string */
-  template[0] = 0;
-  return template;
+  /* Template is badly formed or else we can't generate a unique name.  */
+  return -1;
 }
 
 int
-sys_open (const char * path, int oflag, int mode)
+fchmod (int fd, mode_t mode)
 {
-  const char* mpath = map_w32_filename (path, NULL);
-  /* Try to open file without _O_CREAT, to be able to write to hidden
-     and system files. Force all file handles to be
-     non-inheritable. */
-  int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
-  if (res < 0)
-    res = _open (mpath, oflag | _O_NOINHERIT, mode);
-  if (res >= 0 && res < MAXDESC)
-    fd_info[res].flags = 0;
-
-  return res;
+  return 0;
 }
 
 int
-sys_rename (const char * oldname, const char * newname)
+sys_rename_replace (const char *oldname, const char *newname, BOOL force)
 {
   BOOL result;
   char temp[MAX_PATH];
@@ -3189,7 +3577,7 @@ sys_rename (const char * oldname, const char * newname)
        return -1;
     }
 
-  /* Emulate Unix behavior - newname is deleted if it already exists
+  /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
      (at least if it is a file; don't do this for directories).
 
      Since we mustn't do this if we are just changing the case of the
@@ -3207,7 +3595,7 @@ sys_rename (const char * oldname, const char * newname)
 
   result = rename (temp, newname);
 
-  if (result < 0)
+  if (result < 0 && force)
     {
       DWORD w32err = GetLastError ();
 
@@ -3246,6 +3634,12 @@ sys_rename (const char * oldname, const char * newname)
   return result;
 }
 
+int
+sys_rename (char const *old, char const *new)
+{
+  return sys_rename_replace (old, new, TRUE);
+}
+
 int
 sys_rmdir (const char * path)
 {
@@ -3426,12 +3820,6 @@ get_rid (PSID sid)
 
 /* Caching SID and account values for faster lokup.  */
 
-#ifdef __GNUC__
-# define FLEXIBLE_ARRAY_MEMBER
-#else
-# define FLEXIBLE_ARRAY_MEMBER 1
-#endif
-
 struct w32_id {
   unsigned rid;
   struct w32_id *next;
@@ -3494,7 +3882,6 @@ static int
 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
 {
   PSID sid = NULL;
-  char machine[MAX_COMPUTERNAME_LENGTH+1];
   BOOL dflt;
   SID_NAME_USE ignore;
   char name[UNLEN+1];
@@ -3582,6 +3969,10 @@ is_slow_fs (const char *name)
   return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
 }
 
+/* If this is non-zero, the caller wants accurate information about
+   file's owner and group, which could be expensive to get.  */
+int w32_stat_get_owner_group;
+
 /* MSVC stat function can't cope with UNC names and has other bugs, so
    replace it with our own.  This also allows us to calculate consistent
    inode values and owner/group without hacks in the main Emacs code. */
@@ -3754,6 +4145,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
       /* We produce the fallback owner and group data, based on the
         current user that runs Emacs, in the following cases:
 
+         . caller didn't request owner and group info
          . this is Windows 9X
          . getting security by handle failed, and we need to produce
            information for the target of a symlink (this is better
@@ -3762,23 +4154,25 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
 
         If getting security by handle fails, and we don't need to
         resolve symlinks, we try getting security by name.  */
-      if (is_windows_9x () != TRUE)
-       psd = get_file_security_desc_by_handle (fh);
-      if (psd)
-       {
-         get_file_owner_and_group (psd, buf);
-         LocalFree (psd);
-       }
-      else if (is_windows_9x () == TRUE)
+      if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
        get_file_owner_and_group (NULL, buf);
-      else if (!(is_a_symlink && follow_symlinks))
+      else
        {
-         psd = get_file_security_desc_by_name (name);
-         get_file_owner_and_group (psd, buf);
-         xfree (psd);
+         psd = get_file_security_desc_by_handle (fh);
+         if (psd)
+           {
+             get_file_owner_and_group (psd, buf);
+             LocalFree (psd);
+           }
+         else if (!(is_a_symlink && follow_symlinks))
+           {
+             psd = get_file_security_desc_by_name (name);
+             get_file_owner_and_group (psd, buf);
+             xfree (psd);
+           }
+         else
+           get_file_owner_and_group (NULL, buf);
        }
-      else
-       get_file_owner_and_group (NULL, buf);
       CloseHandle (fh);
     }
   else
@@ -3985,6 +4379,30 @@ lstat (const char * path, struct stat * buf)
   return stat_worker (path, buf, 0);
 }
 
+int
+fstatat (int fd, char const *name, struct stat *st, int flags)
+{
+  /* Rely on a hack: an open directory is modeled as file descriptor 0.
+     This is good enough for the current usage in Emacs, but is fragile.
+
+     FIXME: Add proper support for fdopendir, fstatat, readlinkat.
+     Gnulib does this and can serve as a model.  */
+  char fullname[MAX_PATH];
+
+  if (fd != AT_FDCWD)
+    {
+      if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
+         < 0)
+       {
+         errno = ENAMETOOLONG;
+         return -1;
+       }
+      name = fullname;
+    }
+
+  return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
+}
+
 /* Provide fstat and utime as well as stat for consistent handling of
    file timestamps. */
 int
@@ -4039,13 +4457,23 @@ fstat (int desc, struct stat * buf)
   else
     buf->st_ino = fake_inode;
 
-  /* Consider files to belong to current user.
-     FIXME: this should use GetSecurityInfo API, but it is only
-     available for _WIN32_WINNT >= 0x501.  */
-  buf->st_uid = dflt_passwd.pw_uid;
-  buf->st_gid = dflt_passwd.pw_gid;
-  strcpy (buf->st_uname, dflt_passwd.pw_name);
-  strcpy (buf->st_gname, dflt_group.gr_name);
+  /* If the caller so requested, get the true file owner and group.
+     Otherwise, consider the file to belong to the current user.  */
+  if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
+    get_file_owner_and_group (NULL, buf);
+  else
+    {
+      PSECURITY_DESCRIPTOR psd = NULL;
+
+      psd = get_file_security_desc_by_handle (fh);
+      if (psd)
+       {
+         get_file_owner_and_group (psd, buf);
+         LocalFree (psd);
+       }
+      else
+       get_file_owner_and_group (NULL, buf);
+    }
 
   buf->st_dev = info.dwVolumeSerialNumber;
   buf->st_rdev = info.dwVolumeSerialNumber;
@@ -4087,6 +4515,9 @@ fstat (int desc, struct stat * buf)
   return 0;
 }
 
+/* A version of 'utime' which handles directories as well as
+   files.  */
+
 int
 utime (const char *name, struct utimbuf *times)
 {
@@ -4174,7 +4605,7 @@ symlink (char const *filename, char const *linkname)
     {
       /* Non-absolute FILENAME is understood as being relative to
         LINKNAME's directory.  We need to prepend that directory to
-        FILENAME to get correct results from sys_access below, since
+        FILENAME to get correct results from faccessat below, since
         otherwise it will interpret FILENAME relative to the
         directory where the Emacs process runs.  Note that
         make-symbolic-link always makes sure LINKNAME is a fully
@@ -4201,10 +4632,10 @@ symlink (char const *filename, char const *linkname)
        strncpy (tem, linkfn, p - linkfn);
       tem[p - linkfn] = '\0';
       strcat (tem, filename);
-      dir_access = sys_access (tem, D_OK);
+      dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
     }
   else
-    dir_access = sys_access (filename, D_OK);
+    dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
 
   /* Since Windows distinguishes between symlinks to directories and
      to files, we provide a kludgy feature: if FILENAME doesn't
@@ -4398,7 +4829,7 @@ readlink (const char *name, char *buf, size_t buf_size)
        errno = EINVAL;
       else
        {
-         /* Copy the link target name, in wide characters, fro
+         /* Copy the link target name, in wide characters, from
             reparse_data, then convert it to multibyte encoding in
             the current locale's codepage.  */
          WCHAR *lwname;
@@ -4517,6 +4948,28 @@ readlink (const char *name, char *buf, size_t buf_size)
   return retval;
 }
 
+ssize_t
+readlinkat (int fd, char const *name, char *buffer,
+           size_t buffer_size)
+{
+  /* Rely on a hack: an open directory is modeled as file descriptor 0,
+     as in fstatat.  FIXME: Add proper support for readlinkat.  */
+  char fullname[MAX_PATH];
+
+  if (fd != AT_FDCWD)
+    {
+      if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
+         < 0)
+       {
+         errno = ENAMETOOLONG;
+         return -1;
+       }
+      name = fullname;
+    }
+
+  return readlink (name, buffer, buffer_size);
+}
+
 /* If FILE is a symlink, return its target (stored in a static
    buffer); otherwise return FILE.
 
@@ -4617,6 +5070,245 @@ chase_symlinks (const char *file)
   return target;
 }
 
+\f
+/* Posix ACL emulation.  */
+
+int
+acl_valid (acl_t acl)
+{
+  return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
+}
+
+char *
+acl_to_text (acl_t acl, ssize_t *size)
+{
+  LPTSTR str_acl;
+  SECURITY_INFORMATION flags =
+    OWNER_SECURITY_INFORMATION |
+    GROUP_SECURITY_INFORMATION |
+    DACL_SECURITY_INFORMATION;
+  char *retval = NULL;
+  ULONG local_size;
+  int e = errno;
+
+  errno = 0;
+
+  if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
+    {
+      errno = e;
+      /* We don't want to mix heaps, so we duplicate the string in our
+        heap and free the one allocated by the API.  */
+      retval = xstrdup (str_acl);
+      if (size)
+       *size = local_size;
+      LocalFree (str_acl);
+    }
+  else if (errno != ENOTSUP)
+    errno = EINVAL;
+
+  return retval;
+}
+
+acl_t
+acl_from_text (const char *acl_str)
+{
+  PSECURITY_DESCRIPTOR psd, retval = NULL;
+  ULONG sd_size;
+  int e = errno;
+
+  errno = 0;
+
+  if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
+    {
+      errno = e;
+      retval = xmalloc (sd_size);
+      memcpy (retval, psd, sd_size);
+      LocalFree (psd);
+    }
+  else if (errno != ENOTSUP)
+    errno = EINVAL;
+
+  return retval;
+}
+
+int
+acl_free (void *ptr)
+{
+  xfree (ptr);
+  return 0;
+}
+
+acl_t
+acl_get_file (const char *fname, acl_type_t type)
+{
+  PSECURITY_DESCRIPTOR psd = NULL;
+  const char *filename;
+
+  if (type == ACL_TYPE_ACCESS)
+    {
+      DWORD sd_len, err;
+      SECURITY_INFORMATION si =
+       OWNER_SECURITY_INFORMATION |
+       GROUP_SECURITY_INFORMATION |
+       DACL_SECURITY_INFORMATION ;
+      int e = errno;
+
+      filename = map_w32_filename (fname, NULL);
+      if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
+       fname = chase_symlinks (filename);
+      else
+       fname = filename;
+
+      errno = 0;
+      if (!get_file_security (fname, si, psd, 0, &sd_len)
+         && errno != ENOTSUP)
+       {
+         err = GetLastError ();
+         if (err == ERROR_INSUFFICIENT_BUFFER)
+           {
+             psd = xmalloc (sd_len);
+             if (!get_file_security (fname, si, psd, sd_len, &sd_len))
+               {
+                 xfree (psd);
+                 errno = EIO;
+                 psd = NULL;
+               }
+           }
+         else if (err == ERROR_FILE_NOT_FOUND
+                  || err == ERROR_PATH_NOT_FOUND)
+           errno = ENOENT;
+         else
+           errno = EIO;
+       }
+      else if (!errno)
+       errno = e;
+    }
+  else if (type != ACL_TYPE_DEFAULT)
+    errno = EINVAL;
+
+  return psd;
+}
+
+int
+acl_set_file (const char *fname, acl_type_t type, acl_t acl)
+{
+  TOKEN_PRIVILEGES old1, old2;
+  DWORD err;
+  int st = 0, retval = -1;
+  SECURITY_INFORMATION flags = 0;
+  PSID psid;
+  PACL pacl;
+  BOOL dflt;
+  BOOL dacl_present;
+  int e;
+  const char *filename;
+
+  if (acl_valid (acl) != 0
+      || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  if (type == ACL_TYPE_DEFAULT)
+    {
+      errno = ENOSYS;
+      return -1;
+    }
+
+  filename = map_w32_filename (fname, NULL);
+  if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
+    fname = chase_symlinks (filename);
+  else
+    fname = filename;
+
+  if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
+      && psid)
+    flags |= OWNER_SECURITY_INFORMATION;
+  if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
+      && psid)
+    flags |= GROUP_SECURITY_INFORMATION;
+  if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
+                                   &pacl, &dflt)
+      && dacl_present)
+    flags |= DACL_SECURITY_INFORMATION;
+  if (!flags)
+    return 0;
+
+  /* According to KB-245153, setting the owner will succeed if either:
+     (1) the caller is the user who will be the new owner, and has the
+         SE_TAKE_OWNERSHIP privilege, or
+     (2) the caller has the SE_RESTORE privilege, in which case she can
+         set any valid user or group as the owner
+
+     We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
+     privileges, and disregard any failures in obtaining them.  If
+     these privileges cannot be obtained, and do not already exist in
+     the calling thread's security token, this function could fail
+     with EPERM.  */
+  if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
+    st++;
+  if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
+    st++;
+
+  e = errno;
+  errno = 0;
+  if (!set_file_security ((char *)fname, flags, (PSECURITY_DESCRIPTOR)acl))
+    {
+      err = GetLastError ();
+
+      if (errno == ENOTSUP)
+       ;
+      else if (err == ERROR_INVALID_OWNER
+              || err == ERROR_NOT_ALL_ASSIGNED
+              || err == ERROR_ACCESS_DENIED)
+       {
+         /* Maybe the requested ACL and the one the file already has
+            are identical, in which case we can silently ignore the
+            failure.  (And no, Windows doesn't.)  */
+         acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
+
+         errno = EPERM;
+         if (current_acl)
+           {
+             char *acl_from = acl_to_text (current_acl, NULL);
+             char *acl_to = acl_to_text (acl, NULL);
+
+             if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
+               {
+                 retval = 0;
+                 errno = e;
+               }
+             if (acl_from)
+               acl_free (acl_from);
+             if (acl_to)
+               acl_free (acl_to);
+             acl_free (current_acl);
+           }
+       }
+      else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
+       errno = ENOENT;
+      else
+       errno = EACCES;
+    }
+  else
+    {
+      retval = 0;
+      errno = e;
+    }
+
+  if (st)
+    {
+      if (st >= 2)
+       restore_privilege (&old2);
+      restore_privilege (&old1);
+      revert_to_self ();
+    }
+
+  return retval;
+}
+
+\f
 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c).  We
    have a fixed max size for file names, so we don't need the kind of
    alloc/malloc/realloc dance the gnulib version does.  We also don't
@@ -4630,12 +5322,6 @@ careadlinkat (int fd, char const *filename,
   char linkname[MAX_PATH];
   ssize_t link_size;
 
-  if (fd != AT_FDCWD)
-    {
-      errno = EINVAL;
-      return NULL;
-    }
-
   link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
 
   if (link_size > 0)
@@ -4653,14 +5339,6 @@ careadlinkat (int fd, char const *filename,
   return NULL;
 }
 
-ssize_t
-careadlinkatcwd (int fd, char const *filename, char *buffer,
-                 size_t buffer_size)
-{
-  (void) fd;
-  return readlink (filename, buffer, buffer_size);
-}
-
 \f
 /* Support for browsing other processes and their attributes.  See
    process.c for the Lisp bindings.  */
@@ -4998,10 +5676,8 @@ ltime (ULONGLONG time_100ns)
 {
   ULONGLONG time_sec = time_100ns / 10000000;
   int subsec = time_100ns % 10000000;
-  return list4 (make_number (time_sec >> 16),
-               make_number (time_sec & 0xffff),
-               make_number (subsec / 10),
-               make_number (subsec % 10 * 100000));
+  return list4i (time_sec >> 16, time_sec & 0xffff,
+                subsec / 10, subsec % 10 * 100000);
 }
 
 #define U64_TO_LISP_TIME(time) ltime (time)
@@ -5110,8 +5786,8 @@ system_process_attributes (Lisp_Object pid)
                {
                  /* Decode the command name from locale-specific
                     encoding.  */
-                 cmd_str = make_unibyte_string (pe.szExeFile,
-                                                strlen (pe.szExeFile));
+                 cmd_str = build_unibyte_string (pe.szExeFile);
+
                  decoded_cmd =
                    code_convert_string_norecord (cmd_str,
                                                  Vlocale_coding_system, 0);
@@ -5416,6 +6092,7 @@ term_winsock (void)
 {
   if (winsock_lib != NULL && winsock_inuse == 0)
     {
+      release_listen_threads ();
       /* Not sure what would cause WSAENETDOWN, or even if it can happen
         after WSAStartup returns successfully, but it seems reasonable
         to allow unloading winsock anyway in that case. */
@@ -5515,35 +6192,39 @@ init_winsock (int load_now)
 
 int h_errno = 0;
 
-/* function to set h_errno for compatibility; map winsock error codes to
-   normal system codes where they overlap (non-overlapping definitions
-   are already in <sys/socket.h> */
+/* Function to map winsock error codes to errno codes for those errno
+   code defined in errno.h (errno values not defined by errno.h are
+   already in nt/inc/sys/socket.h).  */
 static void
 set_errno (void)
 {
+  int wsa_err;
+
+  h_errno = 0;
   if (winsock_lib == NULL)
-    h_errno = EINVAL;
+    wsa_err = EINVAL;
   else
-    h_errno = pfn_WSAGetLastError ();
+    wsa_err = pfn_WSAGetLastError ();
 
-  switch (h_errno)
+  switch (wsa_err)
     {
-    case WSAEACCES:            h_errno = EACCES; break;
-    case WSAEBADF:             h_errno = EBADF; break;
-    case WSAEFAULT:            h_errno = EFAULT; break;
-    case WSAEINTR:             h_errno = EINTR; break;
-    case WSAEINVAL:            h_errno = EINVAL; break;
-    case WSAEMFILE:            h_errno = EMFILE; break;
-    case WSAENAMETOOLONG:      h_errno = ENAMETOOLONG; break;
-    case WSAENOTEMPTY:         h_errno = ENOTEMPTY; break;
+    case WSAEACCES:            errno = EACCES; break;
+    case WSAEBADF:             errno = EBADF; break;
+    case WSAEFAULT:            errno = EFAULT; break;
+    case WSAEINTR:             errno = EINTR; break;
+    case WSAEINVAL:            errno = EINVAL; break;
+    case WSAEMFILE:            errno = EMFILE; break;
+    case WSAENAMETOOLONG:      errno = ENAMETOOLONG; break;
+    case WSAENOTEMPTY:         errno = ENOTEMPTY; break;
+    default:                   errno = wsa_err; break;
     }
-  errno = h_errno;
 }
 
 static void
 check_errno (void)
 {
-  if (h_errno == 0 && winsock_lib != NULL)
+  h_errno = 0;
+  if (winsock_lib != NULL)
     pfn_WSASetLastError (0);
 }
 
@@ -5655,7 +6336,7 @@ sys_socket (int af, int type, int protocol)
 
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      errno = ENETDOWN;
       return INVALID_SOCKET;
     }
 
@@ -5732,6 +6413,7 @@ socket_to_fd (SOCKET s)
              }
          }
       }
+      eassert (fd < MAXDESC);
       fd_info[fd].hnd = (HANDLE) s;
 
       /* set our own internal flags */
@@ -5760,8 +6442,9 @@ socket_to_fd (SOCKET s)
       /* clean up */
       _close (fd);
     }
+  else
   pfn_closesocket (s);
-  h_errno = EMFILE;
+  errno = EMFILE;
   return -1;
 }
 
@@ -5770,7 +6453,7 @@ sys_bind (int s, const struct sockaddr * addr, int namelen)
 {
   if (winsock_lib == NULL)
     {
-      h_errno = ENOTSOCK;
+      errno = ENOTSOCK;
       return SOCKET_ERROR;
     }
 
@@ -5782,7 +6465,7 @@ sys_bind (int s, const struct sockaddr * addr, int namelen)
        set_errno ();
       return rc;
     }
-  h_errno = ENOTSOCK;
+  errno = ENOTSOCK;
   return SOCKET_ERROR;
 }
 
@@ -5791,7 +6474,7 @@ sys_connect (int s, const struct sockaddr * name, int namelen)
 {
   if (winsock_lib == NULL)
     {
-      h_errno = ENOTSOCK;
+      errno = ENOTSOCK;
       return SOCKET_ERROR;
     }
 
@@ -5803,7 +6486,7 @@ sys_connect (int s, const struct sockaddr * name, int namelen)
        set_errno ();
       return rc;
     }
-  h_errno = ENOTSOCK;
+  errno = ENOTSOCK;
   return SOCKET_ERROR;
 }
 
@@ -5832,12 +6515,20 @@ int
 sys_gethostname (char * name, int namelen)
 {
   if (winsock_lib != NULL)
-    return pfn_gethostname (name, namelen);
+    {
+      int retval;
+
+      check_errno ();
+      retval = pfn_gethostname (name, namelen);
+      if (retval == SOCKET_ERROR)
+       set_errno ();
+      return retval;
+    }
 
   if (namelen > MAX_COMPUTERNAME_LENGTH)
     return !GetComputerName (name, (DWORD *)&namelen);
 
-  h_errno = EFAULT;
+  errno = EFAULT;
   return SOCKET_ERROR;
 }
 
@@ -5845,17 +6536,24 @@ struct hostent *
 sys_gethostbyname (const char * name)
 {
   struct hostent * host;
+  int h_err = h_errno;
 
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      h_errno = NO_RECOVERY;
+      errno = ENETDOWN;
       return NULL;
     }
 
   check_errno ();
   host = pfn_gethostbyname (name);
   if (!host)
-    set_errno ();
+    {
+      set_errno ();
+      h_errno = errno;
+    }
+  else
+    h_errno = h_err;
   return host;
 }
 
@@ -5866,7 +6564,7 @@ sys_getservbyname (const char * name, const char * proto)
 
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      errno = ENETDOWN;
       return NULL;
     }
 
@@ -5882,7 +6580,7 @@ sys_getpeername (int s, struct sockaddr *addr, int * namelen)
 {
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      errno = ENETDOWN;
       return SOCKET_ERROR;
     }
 
@@ -5894,7 +6592,7 @@ sys_getpeername (int s, struct sockaddr *addr, int * namelen)
        set_errno ();
       return rc;
     }
-  h_errno = ENOTSOCK;
+  errno = ENOTSOCK;
   return SOCKET_ERROR;
 }
 
@@ -5903,7 +6601,7 @@ sys_shutdown (int s, int how)
 {
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      errno = ENETDOWN;
       return SOCKET_ERROR;
     }
 
@@ -5915,7 +6613,7 @@ sys_shutdown (int s, int how)
        set_errno ();
       return rc;
     }
-  h_errno = ENOTSOCK;
+  errno = ENOTSOCK;
   return SOCKET_ERROR;
 }
 
@@ -5924,7 +6622,7 @@ sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
 {
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      errno = ENETDOWN;
       return SOCKET_ERROR;
     }
 
@@ -5937,7 +6635,7 @@ sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
        set_errno ();
       return rc;
     }
-  h_errno = ENOTSOCK;
+  errno = ENOTSOCK;
   return SOCKET_ERROR;
 }
 
@@ -5946,7 +6644,7 @@ sys_listen (int s, int backlog)
 {
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      errno = ENETDOWN;
       return SOCKET_ERROR;
     }
 
@@ -5960,7 +6658,7 @@ sys_listen (int s, int backlog)
        fd_info[s].flags |= FILE_LISTEN;
       return rc;
     }
-  h_errno = ENOTSOCK;
+  errno = ENOTSOCK;
   return SOCKET_ERROR;
 }
 
@@ -5969,7 +6667,7 @@ sys_getsockname (int s, struct sockaddr * name, int * namelen)
 {
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      errno = ENETDOWN;
       return SOCKET_ERROR;
     }
 
@@ -5981,7 +6679,7 @@ sys_getsockname (int s, struct sockaddr * name, int * namelen)
        set_errno ();
       return rc;
     }
-  h_errno = ENOTSOCK;
+  errno = ENOTSOCK;
   return SOCKET_ERROR;
 }
 
@@ -5990,7 +6688,7 @@ sys_accept (int s, struct sockaddr * addr, int * addrlen)
 {
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      errno = ENETDOWN;
       return -1;
     }
 
@@ -6004,11 +6702,14 @@ sys_accept (int s, struct sockaddr * addr, int * addrlen)
       else
        fd = socket_to_fd (t);
 
-      fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
-      ResetEvent (fd_info[s].cp->char_avail);
+      if (fd >= 0)
+       {
+         fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
+         ResetEvent (fd_info[s].cp->char_avail);
+       }
       return fd;
     }
-  h_errno = ENOTSOCK;
+  errno = ENOTSOCK;
   return -1;
 }
 
@@ -6018,7 +6719,7 @@ sys_recvfrom (int s, char * buf, int len, int flags,
 {
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      errno = ENETDOWN;
       return SOCKET_ERROR;
     }
 
@@ -6030,7 +6731,7 @@ sys_recvfrom (int s, char * buf, int len, int flags,
        set_errno ();
       return rc;
     }
-  h_errno = ENOTSOCK;
+  errno = ENOTSOCK;
   return SOCKET_ERROR;
 }
 
@@ -6040,7 +6741,7 @@ sys_sendto (int s, const char * buf, int len, int flags,
 {
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      errno = ENETDOWN;
       return SOCKET_ERROR;
     }
 
@@ -6052,25 +6753,31 @@ sys_sendto (int s, const char * buf, int len, int flags,
        set_errno ();
       return rc;
     }
-  h_errno = ENOTSOCK;
+  errno = ENOTSOCK;
   return SOCKET_ERROR;
 }
 
 /* Windows does not have an fcntl function.  Provide an implementation
-   solely for making sockets non-blocking.  */
+   good enough for Emacs.  */
 int
 fcntl (int s, int cmd, int options)
 {
+  /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
+     invoked in a context where fd1 is closed and all descriptors less
+     than fd1 are open, so sys_dup is an adequate implementation.  */
+  if (cmd == F_DUPFD_CLOEXEC)
+    return sys_dup (s);
+
   if (winsock_lib == NULL)
     {
-      h_errno = ENETDOWN;
+      errno = ENETDOWN;
       return -1;
     }
 
   check_errno ();
   if (fd_info[s].flags & FILE_SOCKET)
     {
-      if (cmd == F_SETFL && options == O_NDELAY)
+      if (cmd == F_SETFL && options == O_NONBLOCK)
        {
          unsigned long nblock = 1;
          int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
@@ -6082,11 +6789,11 @@ fcntl (int s, int cmd, int options)
        }
       else
        {
-         h_errno = EINVAL;
+         errno = EINVAL;
          return SOCKET_ERROR;
        }
     }
-  h_errno = ENOTSOCK;
+  errno = ENOTSOCK;
   return SOCKET_ERROR;
 }
 
@@ -6133,7 +6840,21 @@ sys_close (int fd)
 
                  winsock_inuse--; /* count open sockets */
                }
-             delete_child (cp);
+             /* If the process handle is NULL, it's either a socket
+                or serial connection, or a subprocess that was
+                already reaped by reap_subprocess, but whose
+                resources were not yet freed, because its output was
+                not fully read yet by the time it was reaped.  (This
+                usually happens with async subprocesses whose output
+                is being read by Emacs.)  Otherwise, this process was
+                not reaped yet, so we set its FD to a negative value
+                to make sure sys_select will eventually get to
+                calling the SIGCHLD handler for it, which will then
+                invoke waitpid and reap_subprocess.  */
+             if (cp->procinfo.hProcess == NULL)
+               delete_child (cp);
+             else
+               cp->fd = -1;
            }
        }
     }
@@ -6188,13 +6909,14 @@ sys_dup2 (int src, int dst)
   return rc;
 }
 
-/* Unix pipe() has only one arg */
 int
-sys_pipe (int * phandles)
+pipe2 (int * phandles, int pipe2_flags)
 {
   int rc;
   unsigned flags;
 
+  eassert (pipe2_flags == O_CLOEXEC);
+
   /* 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
@@ -6226,7 +6948,8 @@ sys_pipe (int * phandles)
 }
 
 /* Function to do blocking read of one byte, needed to implement
-   select.  It is only allowed on sockets and pipes. */
+   select.  It is only allowed on communication ports, sockets, or
+   pipes. */
 int
 _sys_read_ahead (int fd)
 {
@@ -6354,7 +7077,12 @@ _sys_wait_accept (int fd)
   rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
   if (rc != SOCKET_ERROR)
     {
-      rc = WaitForSingleObject (hEv, INFINITE);
+      do {
+       rc = WaitForSingleObject (hEv, 500);
+       Sleep (5);
+      } while (rc == WAIT_TIMEOUT
+              && cp->status != STATUS_READ_ERROR
+              && cp->char_avail);
       pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
       if (rc == WAIT_OBJECT_0)
        cp->status = STATUS_READ_SUCCEEDED;
@@ -6502,7 +7230,7 @@ sys_read (int fd, char * buffer, unsigned int count)
              pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
              if (waiting == 0 && nchars == 0)
                {
-                 h_errno = errno = EWOULDBLOCK;
+                 errno = EWOULDBLOCK;
                  return -1;
                }
 
@@ -7000,6 +7728,11 @@ globals_of_w32 (void)
   g_b_init_get_native_system_info = 0;
   g_b_init_get_system_times = 0;
   g_b_init_create_symbolic_link = 0;
+  g_b_init_get_security_descriptor_dacl = 0;
+  g_b_init_convert_sd_to_sddl = 0;
+  g_b_init_convert_sddl_to_sd = 0;
+  g_b_init_is_valid_security_descriptor = 0;
+  g_b_init_set_file_security = 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
@@ -7009,12 +7742,16 @@ globals_of_w32 (void)
 
   /* "None" is the default group name on standalone workstations.  */
   strcpy (dflt_group_name, "None");
+
+  /* Reset, in case it has some value inherited from dump time.  */
+  w32_stat_get_owner_group = 0;
 }
 
 /* For make-serial-process  */
 int
-serial_open (char *port)
+serial_open (Lisp_Object port_obj)
 {
+  char *port = SSDATA (port_obj);
   HANDLE hnd;
   child_process *cp;
   int fd = -1;
@@ -7206,47 +7943,26 @@ serial_configure (struct Lisp_Process *p, Lisp_Object contact)
 ssize_t
 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
 {
-  int n, sc, err;
+  int n, err;
   SELECT_TYPE fdset;
-  EMACS_TIME timeout;
+  struct timespec timeout;
   struct Lisp_Process *process = (struct Lisp_Process *)p;
   int fd = process->infd;
 
-  for (;;)
-    {
-      n = sys_read (fd, (char*)buf, sz);
+  n = sys_read (fd, (char*)buf, sz);
 
-      if (n >= 0)
-        return n;
+  if (n >= 0)
+    return n;
 
-      err = errno;
+  err = errno;
 
-      if (err == EWOULDBLOCK)
-        {
-          /* Set a small timeout.  */
-         timeout = make_emacs_time (1, 0);
-          FD_ZERO (&fdset);
-          FD_SET ((int)fd, &fdset);
-
-          /* Use select with the timeout to poll the selector.  */
-          sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
-                       &timeout, NULL);
-
-          if (sc > 0)
-            continue;  /* Try again.  */
-
-          /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
-             Also accept select return 0 as an indicator to EAGAIN.  */
-          if (sc == 0 || errno == EWOULDBLOCK)
-            err = EAGAIN;
-          else
-            err = errno; /* Other errors are just passed on.  */
-        }
+  /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
+  if (err == EWOULDBLOCK)
+    err = EAGAIN;
 
-      emacs_gnutls_transport_set_errno (process->gnutls_state, err);
+  emacs_gnutls_transport_set_errno (process->gnutls_state, err);
 
-      return -1;
-    }
+  return -1;
 }
 
 ssize_t