]> code.delx.au - gnu-emacs/blobdiff - src/w32.c
(archive-l-e): New optional argument `float' means generate a float value.
[gnu-emacs] / src / w32.c
index c80c4232bc6a78ebd3c450a9eff3d671022f024d..71799befdbb42c98a015fee55e1b8244f94782e1 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -1,5 +1,6 @@
 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
-   Copyright (C) 1994, 1995, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004,
+                 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -15,13 +16,11 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
 
    Geoff Voelker (voelker@cs.washington.edu)                         7-29-94
 */
-
-
 #include <stddef.h> /* for offsetof */
 #include <stdlib.h>
 #include <stdio.h>
@@ -66,12 +65,14 @@ Boston, MA 02111-1307, USA.
 #include "lisp.h"
 
 #include <pwd.h>
+#include <grp.h>
 
 #ifdef __GNUC__
 #define _ANONYMOUS_UNION
 #define _ANONYMOUS_STRUCT
 #endif
 #include <windows.h>
+#include <shlobj.h>
 
 #ifdef HAVE_SOCKETS    /* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
@@ -99,12 +100,26 @@ Boston, MA 02111-1307, USA.
 #include "w32heap.h"
 #include "systime.h"
 
+typedef HRESULT (WINAPI * ShGetFolderPath_fn)
+  (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
+
+void globals_of_w32 ();
+
 extern Lisp_Object Vw32_downcase_file_names;
 extern Lisp_Object Vw32_generate_fake_inodes;
 extern Lisp_Object Vw32_get_true_file_attributes;
-extern Lisp_Object Vw32_num_mouse_buttons;
+extern int w32_num_mouse_buttons;
 
 \f
+/*
+       Initialization states
+ */
+static BOOL g_b_init_is_windows_9x;
+static BOOL g_b_init_open_process_token;
+static BOOL g_b_init_get_token_information;
+static BOOL g_b_init_lookup_account_sid;
+static BOOL g_b_init_get_sid_identifier_authority;
+
 /*
   BEGIN: Wrapper functions around OpenProcessToken
   and other functions in advapi32.dll that are only
@@ -140,15 +155,19 @@ typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) (
   /* ** A utility function ** */
 static BOOL is_windows_9x ()
 {
-  BOOL b_ret=0;
+  static BOOL s_b_ret=0;
   OSVERSIONINFO os_ver;
-  ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
-  os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-  if (GetVersionEx (&os_ver))
+  if (g_b_init_is_windows_9x == 0)
     {
-      b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
+      g_b_init_is_windows_9x = 1;
+      ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
+      os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+      if (GetVersionEx (&os_ver))
+        {
+          s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
+        }
     }
-  return b_ret;
+  return s_b_ret;
 }
 
   /* ** The wrapper functions ** */
@@ -158,21 +177,25 @@ BOOL WINAPI open_process_token (
     DWORD DesiredAccess,
     PHANDLE TokenHandle)
 {
-  OpenProcessToken_Proc pfn_Open_Process_Token = NULL;
+  static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
   HMODULE hm_advapi32 = NULL;
   if (is_windows_9x () == TRUE)
     {
       return FALSE;
     }
-  hm_advapi32 = LoadLibrary ("Advapi32.dll");
-  pfn_Open_Process_Token =
-    (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
-  if (pfn_Open_Process_Token == NULL)
+  if (g_b_init_open_process_token == 0)
+    {
+      g_b_init_open_process_token = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Open_Process_Token =
+        (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
+    }
+  if (s_pfn_Open_Process_Token == NULL)
     {
       return FALSE;
     }
   return (
-      pfn_Open_Process_Token (
+      s_pfn_Open_Process_Token (
           ProcessHandle,
           DesiredAccess,
           TokenHandle)
@@ -186,21 +209,25 @@ BOOL WINAPI get_token_information (
     DWORD TokenInformationLength,
     PDWORD ReturnLength)
 {
-  GetTokenInformation_Proc pfn_Get_Token_Information = NULL;
+  static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
   HMODULE hm_advapi32 = NULL;
   if (is_windows_9x () == TRUE)
     {
       return FALSE;
     }
-  hm_advapi32 = LoadLibrary ("Advapi32.dll");
-  pfn_Get_Token_Information =
-    (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
-  if (pfn_Get_Token_Information == NULL)
+  if (g_b_init_get_token_information == 0)
+    {
+      g_b_init_get_token_information = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Get_Token_Information =
+        (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
+    }
+  if (s_pfn_Get_Token_Information == NULL)
     {
       return FALSE;
     }
   return (
-      pfn_Get_Token_Information (
+      s_pfn_Get_Token_Information (
           TokenHandle,
           TokenInformationClass,
           TokenInformation,
@@ -218,21 +245,25 @@ BOOL WINAPI lookup_account_sid (
     LPDWORD cbDomainName,
     PSID_NAME_USE peUse)
 {
-  LookupAccountSid_Proc pfn_Lookup_Account_Sid = NULL;
+  static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
   HMODULE hm_advapi32 = NULL;
   if (is_windows_9x () == TRUE)
     {
       return FALSE;
     }
-  hm_advapi32 = LoadLibrary ("Advapi32.dll");
-  pfn_Lookup_Account_Sid =
-    (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
-  if (pfn_Lookup_Account_Sid == NULL)
+  if (g_b_init_lookup_account_sid == 0)
+    {
+      g_b_init_lookup_account_sid = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Lookup_Account_Sid =
+        (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
+    }
+  if (s_pfn_Lookup_Account_Sid == NULL)
     {
       return FALSE;
     }
   return (
-      pfn_Lookup_Account_Sid (
+      s_pfn_Lookup_Account_Sid (
           lpSystemName,
           Sid,
           Name,
@@ -246,21 +277,25 @@ BOOL WINAPI lookup_account_sid (
 PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority (
     PSID pSid)
 {
-  GetSidIdentifierAuthority_Proc pfn_Get_Sid_Identifier_Authority = NULL;
+  static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
   HMODULE hm_advapi32 = NULL;
   if (is_windows_9x () == TRUE)
     {
       return NULL;
     }
-  hm_advapi32 = LoadLibrary ("Advapi32.dll");
-  pfn_Get_Sid_Identifier_Authority =
-    (GetSidIdentifierAuthority_Proc) GetProcAddress (
-        hm_advapi32, "GetSidIdentifierAuthority");
-  if (pfn_Get_Sid_Identifier_Authority == NULL)
+  if (g_b_init_get_sid_identifier_authority == 0)
+    {
+      g_b_init_get_sid_identifier_authority = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Get_Sid_Identifier_Authority =
+        (GetSidIdentifierAuthority_Proc) GetProcAddress (
+            hm_advapi32, "GetSidIdentifierAuthority");
+    }
+  if (s_pfn_Get_Sid_Identifier_Authority == NULL)
     {
       return NULL;
     }
-  return (pfn_Get_Sid_Identifier_Authority (pSid));
+  return (s_pfn_Get_Sid_Identifier_Authority (pSid));
 }
 
 /*
@@ -312,7 +347,7 @@ getwd (char *dir)
 int
 gethostname (char *buffer, int size)
 {
-  /* NT only allows small host names, so the buffer is 
+  /* NT only allows small host names, so the buffer is
      certainly large enough.  */
   return !GetComputerName (buffer, &size);
 }
@@ -325,7 +360,7 @@ getloadavg (double loadavg[], int nelem)
   int i;
 
   /* A faithful emulation is going to have to be saved for a rainy day.  */
-  for (i = 0; i < nelem; i++) 
+  for (i = 0; i < nelem; i++)
     {
       loadavg[i] = 0.0;
     }
@@ -342,7 +377,7 @@ static char the_passwd_gecos[PASSWD_FIELD_SIZE];
 static char the_passwd_dir[PASSWD_FIELD_SIZE];
 static char the_passwd_shell[PASSWD_FIELD_SIZE];
 
-static struct passwd the_passwd = 
+static struct passwd the_passwd =
 {
   the_passwd_name,
   the_passwd_passwd,
@@ -354,30 +389,37 @@ static struct passwd the_passwd =
   the_passwd_shell,
 };
 
-int 
-getuid () 
-{ 
+static struct group the_group =
+{
+  /* There are no groups on NT, so we just return "root" as the
+     group name.  */
+  "root",
+};
+
+int
+getuid ()
+{
   return the_passwd.pw_uid;
 }
 
-int 
-geteuid () 
-{ 
+int
+geteuid ()
+{
   /* I could imagine arguing for checking to see whether the user is
      in the Administrators group and returning a UID of 0 for that
      case, but I don't know how wise that would be in the long run.  */
-  return getuid (); 
+  return getuid ();
 }
 
-int 
-getgid () 
-{ 
+int
+getgid ()
+{
   return the_passwd.pw_gid;
 }
 
-int 
-getegid () 
-{ 
+int
+getegid ()
+{
   return getgid ();
 }
 
@@ -389,11 +431,17 @@ getpwuid (int uid)
   return NULL;
 }
 
+struct group *
+getgrgid (gid_t gid)
+{
+  return &the_group;
+}
+
 struct passwd *
 getpwnam (char *name)
 {
   struct passwd *pw;
-  
+
   pw = getpwuid (getuid ());
   if (!pw)
     return pw;
@@ -751,57 +799,57 @@ is_unc_volume (const char *filename)
 
 /* Routines that are no-ops on NT but are defined to get Emacs to compile.  */
 
-int 
-sigsetmask (int signal_mask) 
-{ 
+int
+sigsetmask (int signal_mask)
+{
   return 0;
 }
 
-int 
-sigmask (int sig) 
-{ 
+int
+sigmask (int sig)
+{
   return 0;
 }
 
-int 
-sigblock (int sig) 
-{ 
+int
+sigblock (int sig)
+{
   return 0;
 }
 
-int 
-sigunblock (int sig) 
-{ 
+int
+sigunblock (int sig)
+{
   return 0;
 }
 
-int 
-setpgrp (int pid, int gid) 
-{ 
+int
+setpgrp (int pid, int gid)
+{
   return 0;
 }
 
-int 
-alarm (int seconds) 
-{ 
+int
+alarm (int seconds)
+{
   return 0;
 }
 
-void 
-unrequest_sigio (void) 
-{ 
+void
+unrequest_sigio (void)
+{
   return;
 }
 
 void
-request_sigio (void) 
-{ 
+request_sigio (void)
+{
   return;
 }
 
 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
 
-LPBYTE 
+LPBYTE
 w32_get_resource (key, lpdwtype)
     char *key;
     LPDWORD lpdwtype;
@@ -810,42 +858,42 @@ w32_get_resource (key, lpdwtype)
   HKEY hrootkey = NULL;
   DWORD cbData;
   BOOL ok = FALSE;
-  
-  /* Check both the current user and the local machine to see if 
+
+  /* Check both the current user and the local machine to see if
      we have any resources.  */
-  
+
   if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
     {
       lpvalue = NULL;
 
-      if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS 
-         && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL 
+      if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
+         && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
          && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
        {
          return (lpvalue);
        }
 
       if (lpvalue) xfree (lpvalue);
-       
+
       RegCloseKey (hrootkey);
-    } 
-  
+    }
+
   if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
     {
       lpvalue = NULL;
-       
+
       if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
          && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
          && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
        {
          return (lpvalue);
        }
-       
+
       if (lpvalue) xfree (lpvalue);
-       
+
       RegCloseKey (hrootkey);
-    } 
-  
+    }
+
   return (NULL);
 }
 
@@ -858,7 +906,9 @@ init_environment (char ** argv)
   static const char * const tempdirs[] = {
     "$TMPDIR", "$TEMP", "$TMP", "c:/"
   };
+
   int i;
+
   const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
 
   /* Make sure they have a usable $TMPDIR.  Many Emacs functions use
@@ -897,12 +947,14 @@ init_environment (char ** argv)
     LPBYTE lpval;
     DWORD dwType;
     char locale_name[32];
+    struct stat ignored;
+    char default_home[MAX_PATH];
 
     static struct env_entry
     {
       char * name;
       char * def_value;
-    } env_vars[] = 
+    } env_vars[] =
     {
       {"HOME", "C:/"},
       {"PRELOAD_WINSOCK", NULL},
@@ -919,6 +971,35 @@ init_environment (char ** argv)
       {"LANG", NULL},
     };
 
+    /* For backwards compatibility, check if a .emacs file exists in C:/
+       If not, then we can try to default to the appdata directory under the
+       user's profile, which is more likely to be writable.   */
+    if (stat ("C:/.emacs", &ignored) < 0)
+    {
+      HRESULT profile_result;
+      /* Dynamically load ShGetFolderPath, as it won't exist on versions
+        of Windows 95 and NT4 that have not been updated to include
+        MSIE 5.  Also we don't link with shell32.dll by default.  */
+      HMODULE shell32_dll;
+      ShGetFolderPath_fn get_folder_path;
+      shell32_dll = GetModuleHandle ("shell32.dll");
+      get_folder_path = (ShGetFolderPath_fn)
+       GetProcAddress (shell32_dll, "SHGetFolderPathA");
+
+      if (get_folder_path != NULL)
+       {
+         profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
+                                           0, default_home);
+
+         /* If we can't get the appdata dir, revert to old behaviour.  */
+         if (profile_result == S_OK)
+           env_vars[0].def_value = default_home;
+       }
+
+      /* Unload shell32.dll, it is not needed anymore.  */
+      FreeLibrary (shell32_dll);
+    }
+
   /* Get default locale info and use it for LANG.  */
   if (GetLocaleInfo (LOCALE_USER_DEFAULT,
                      LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
@@ -956,10 +1037,36 @@ init_environment (char ** argv)
          *p = 0;
          for (p = modname; *p; p++)
            if (*p == '\\') *p = '/';
-                 
+
          _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
          _putenv (strdup (buf));
        }
+      /* Handle running emacs from the build directory: src/oo-spd/i386/  */
+
+      /* FIXME: should use substring of get_emacs_configuration ().
+        But I don't think the Windows build supports alpha, mips etc
+         anymore, so have taken the easy option for now.  */
+      else if (p && stricmp (p, "\\i386") == 0)
+       {
+         *p = 0;
+         p = strrchr (modname, '\\');
+         if (p != NULL)
+           {
+             *p = 0;
+             p = strrchr (modname, '\\');
+             if (p && stricmp (p, "\\src") == 0)
+               {
+                 char buf[SET_ENV_BUF_SIZE];
+
+                 *p = 0;
+                 for (p = modname; *p; p++)
+                   if (*p == '\\') *p = '/';
+
+                 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
+                 _putenv (strdup (buf));
+               }
+           }
+       }
     }
 
     for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
@@ -988,7 +1095,7 @@ init_environment (char ** argv)
                else if (dwType == REG_SZ)
                  {
                    char buf[SET_ENV_BUF_SIZE];
-                 
+
                    _snprintf (buf, sizeof(buf)-1, "%s=%s", env_vars[i].name, lpval);
                    _putenv (strdup (buf));
                  }
@@ -1049,7 +1156,7 @@ init_environment (char ** argv)
   /* Determine if there is a middle mouse button, to allow parse_button
      to decide whether right mouse events should be mouse-2 or
      mouse-3. */
-  XSETINT (Vw32_num_mouse_buttons, GetSystemMetrics (SM_CMOUSEBUTTONS));
+  w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
 
   init_user_info ();
 }
@@ -1082,7 +1189,7 @@ get_emacs_configuration (void)
   static char configuration_buffer[32];
 
   /* Determine the processor type.  */
-  switch (get_processor_type ()) 
+  switch (get_processor_type ())
     {
 
 #ifdef PROCESSOR_INTEL_386
@@ -1199,15 +1306,15 @@ get_emacs_configuration_options (void)
 #include <sys/timeb.h>
 
 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95).  */
-void 
+void
 gettimeofday (struct timeval *tv, struct timezone *tz)
 {
-  struct timeb tb;
+  struct _timeb tb;
   _ftime (&tb);
 
   tv->tv_sec = tb.time;
   tv->tv_usec = tb.millitm * 1000L;
-  if (tz) 
+  if (tz)
     {
       tz->tz_minuteswest = tb.timezone;        /* minutes west of Greenwich  */
       tz->tz_dsttime = tb.dstflag;     /* type of dst correction  */
@@ -1219,7 +1326,7 @@ gettimeofday (struct timeval *tv, struct timezone *tz)
 /* ------------------------------------------------------------------------- */
 
 /* Place a wrapper around the MSVC version of ctime.  It returns NULL
-   on network directories, so we handle that case here.  
+   on network directories, so we handle that case here.
    (Ulrich Leodolter, 1/11/95).  */
 char *
 sys_ctime (const time_t *t)
@@ -1325,7 +1432,7 @@ GetCachedVolumeInformation (char * root_dir)
      tell whether they are or not.  Also, the UNC association of drive
      letters mapped to remote volumes can be changed at any time (even
      by other processes) without notice.
-   
+
      As a compromise, so we can benefit from caching info for remote
      volumes, we use a simple expiry mechanism to invalidate cache
      entries that are more than ten seconds old.  */
@@ -1431,7 +1538,7 @@ get_volume_info (const char * name, const char ** pPath)
 
   if (pPath)
     *pPath = name;
-    
+
   info = GetCachedVolumeInformation (rootname);
   if (info != NULL)
     {
@@ -1569,7 +1676,7 @@ is_exec (const char * name)
         stricmp (p, ".cmd") == 0));
 }
 
-/* Emulate the Unix directory procedures opendir, closedir, 
+/* Emulate the Unix directory procedures opendir, closedir,
    and readdir.  We can't use the procedures supplied in sysdep.c,
    so we provide them here.  */
 
@@ -1582,7 +1689,7 @@ static WIN32_FIND_DATA dir_find_data;
 /* Support shares on a network resource as subdirectories of a read-only
    root directory. */
 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
-HANDLE open_unc_volume (char *);
+HANDLE open_unc_volume (const char *);
 char  *read_unc_volume (HANDLE, char *, int);
 void   close_unc_volume (HANDLE);
 
@@ -1642,8 +1749,8 @@ readdir (DIR *dirp)
 {
   if (wnet_enum_handle != INVALID_HANDLE_VALUE)
     {
-      if (!read_unc_volume (wnet_enum_handle, 
-                             dir_find_data.cFileName, 
+      if (!read_unc_volume (wnet_enum_handle,
+                             dir_find_data.cFileName,
                              MAX_PATH))
        return NULL;
     }
@@ -1669,14 +1776,14 @@ readdir (DIR *dirp)
       if (!FindNextFile (dir_find_handle, &dir_find_data))
        return NULL;
     }
-  
+
   /* Emacs never uses this value, so don't bother making it match
      value returned by stat().  */
   dir_static.d_ino = 1;
-  
+
   dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
     dir_static.d_namlen - dir_static.d_namlen % 4;
-  
+
   dir_static.d_namlen = strlen (dir_find_data.cFileName);
   strcpy (dir_static.d_name, dir_find_data.cFileName);
   if (dir_is_fat)
@@ -1690,27 +1797,27 @@ readdir (DIR *dirp)
       if (!*p)
        _strlwr (dir_static.d_name);
     }
-  
+
   return &dir_static;
 }
 
 HANDLE
-open_unc_volume (char *path)
+open_unc_volume (const char *path)
 {
-  NETRESOURCE nr; 
+  NETRESOURCE nr;
   HANDLE henum;
   int result;
 
-  nr.dwScope = RESOURCE_GLOBALNET; 
-  nr.dwType = RESOURCETYPE_DISK; 
-  nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; 
-  nr.dwUsage = RESOURCEUSAGE_CONTAINER; 
-  nr.lpLocalName = NULL; 
-  nr.lpRemoteName = map_w32_filename (path, NULL);
-  nr.lpComment = NULL; 
-  nr.lpProvider = NULL;   
+  nr.dwScope = RESOURCE_GLOBALNET;
+  nr.dwType = RESOURCETYPE_DISK;
+  nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
+  nr.dwUsage = RESOURCEUSAGE_CONTAINER;
+  nr.lpLocalName = NULL;
+  nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
+  nr.lpComment = NULL;
+  nr.lpProvider = NULL;
 
-  result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,  
+  result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
                        RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
 
   if (result == NO_ERROR)
@@ -1752,7 +1859,7 @@ close_unc_volume (HANDLE henum)
 }
 
 DWORD
-unc_volume_file_attributes (char *path)
+unc_volume_file_attributes (const char *path)
 {
   HANDLE henum;
   DWORD attrs;
@@ -1771,7 +1878,7 @@ unc_volume_file_attributes (char *path)
 
 /* 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 
+   permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
    long file names.  */
 
 int
@@ -1826,6 +1933,14 @@ sys_chmod (const char * path, int mode)
   return _chmod (map_w32_filename (path, NULL), 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)
 {
@@ -2421,7 +2536,7 @@ stat (const char * path, struct stat * buf)
     permission = _S_IREAD;
   else
     permission = _S_IREAD | _S_IWRITE;
-  
+
   if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
     permission |= _S_IEXEC;
   else if (is_exec (name))
@@ -2505,7 +2620,7 @@ fstat (int desc, struct stat * buf)
     permission = _S_IREAD;
   else
     permission = _S_IREAD | _S_IWRITE;
-  
+
   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
     permission |= _S_IEXEC;
   else
@@ -2757,7 +2872,7 @@ struct {
   WSAEFAULT               , "Bad address",
   WSAEINVAL               , "Invalid argument",
   WSAEMFILE               , "Too many open files",
-                       
+
   WSAEWOULDBLOCK          , "Resource temporarily unavailable",
   WSAEINPROGRESS          , "Operation now in progress",
   WSAEALREADY             , "Operation already in progress",
@@ -2795,7 +2910,7 @@ struct {
   WSAEDQUOT               , "Double quote in host name",    /* really not sure */
   WSAESTALE               , "Data is stale",               /* not sure */
   WSAEREMOTE              , "Remote error",                /* not sure */
-                       
+
   WSASYSNOTREADY          , "Network subsystem is unavailable",
   WSAVERNOTSUPPORTED      , "WINSOCK.DLL version out of range",
   WSANOTINITIALISED       , "Winsock not initialized successfully",
@@ -2813,7 +2928,7 @@ struct {
   WSA_E_CANCELLED         , "Operation already cancelled",  /* really not sure */
   WSAEREFUSED             , "Operation refused",           /* not sure */
 #endif
-                       
+
   WSAHOST_NOT_FOUND       , "Host not found",
   WSATRY_AGAIN            , "Authoritative host not found during name lookup",
   WSANO_RECOVERY          , "Non-recoverable error during name lookup",
@@ -2868,7 +2983,7 @@ sys_socket(int af, int type, int protocol)
 
   /* call the real socket function */
   s = pfn_socket (af, type, protocol);
-  
+
   if (s != INVALID_SOCKET)
     return socket_to_fd (s);
 
@@ -2941,7 +3056,7 @@ socket_to_fd (SOCKET s)
                  {
                    CloseHandle (new_s);
                  }
-             } 
+             }
          }
       }
       fd_info[fd].hnd = (HANDLE) s;
@@ -3136,7 +3251,7 @@ sys_shutdown (int s, int how)
 }
 
 int
-sys_setsockopt (int s, int level, int optname, const char * optval, int optlen)
+sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
 {
   if (winsock_lib == NULL)
     {
@@ -3148,13 +3263,13 @@ sys_setsockopt (int s, int level, int optname, const char * optval, int optlen)
   if (fd_info[s].flags & FILE_SOCKET)
     {
       int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
-                              optval, optlen);
+                              (const char *)optval, optlen);
       if (rc == SOCKET_ERROR)
        set_errno ();
       return rc;
     }
   h_errno = ENOTSOCK;
-  return SOCKET_ERROR;      
+  return SOCKET_ERROR;
 }
 
 int
@@ -3175,7 +3290,7 @@ sys_listen (int s, int backlog)
       return rc;
     }
   h_errno = ENOTSOCK;
-  return SOCKET_ERROR;      
+  return SOCKET_ERROR;
 }
 
 int
@@ -3196,7 +3311,7 @@ sys_getsockname (int s, struct sockaddr * name, int * namelen)
       return rc;
     }
   h_errno = ENOTSOCK;
-  return SOCKET_ERROR;      
+  return SOCKET_ERROR;
 }
 
 int
@@ -3311,13 +3426,13 @@ sys_close (int fd)
 {
   int rc;
 
-  if (fd < 0 || fd >= MAXDESC)
+  if (fd < 0)
     {
       errno = EBADF;
       return -1;
     }
 
-  if (fd_info[fd].cp)
+  if (fd < MAXDESC && fd_info[fd].cp)
     {
       child_process * cp = fd_info[fd].cp;
 
@@ -3359,7 +3474,7 @@ sys_close (int fd)
      because socket handles are fully fledged kernel handles. */
   rc = _close (fd);
 
-  if (rc == 0)
+  if (rc == 0 && fd < MAXDESC)
     fd_info[fd].flags = 0;
 
   return rc;
@@ -3371,7 +3486,7 @@ sys_dup (int fd)
   int new_fd;
 
   new_fd = _dup (fd);
-  if (new_fd >= 0)
+  if (new_fd >= 0 && new_fd < MAXDESC)
     {
       /* duplicate our internal info as well */
       fd_info[new_fd] = fd_info[fd];
@@ -3394,7 +3509,7 @@ sys_dup2 (int src, int dst)
   /* make sure we close the destination first if it's a pipe or socket */
   if (src != dst && fd_info[dst].flags != 0)
     sys_close (dst);
-  
+
   rc = _dup2 (src, dst);
   if (rc == 0)
     {
@@ -3419,18 +3534,29 @@ sys_pipe (int * phandles)
 
   if (rc == 0)
     {
-      flags = FILE_PIPE | FILE_READ | FILE_BINARY;
-      fd_info[phandles[0]].flags = flags;
+      /* Protect against overflow, since Windows can open more handles than
+        our fd_info array has room for.  */
+      if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
+       {
+         _close (phandles[0]);
+         _close (phandles[1]);
+         rc = -1;
+       }
+      else
+       {
+         flags = FILE_PIPE | FILE_READ | FILE_BINARY;
+         fd_info[phandles[0]].flags = flags;
 
-      flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
-      fd_info[phandles[1]].flags = flags;
+         flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
+         fd_info[phandles[1]].flags = flags;
+       }
     }
 
   return rc;
 }
 
 /* From ntproc.c */
-extern Lisp_Object Vw32_pipe_read_delay;
+extern int w32_pipe_read_delay;
 
 /* Function to do blocking read of one byte, needed to implement
    select.  It is only allowed on sockets and pipes. */
@@ -3454,9 +3580,9 @@ _sys_read_ahead (int fd)
       DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
       abort ();
     }
-  
+
   cp->status = STATUS_READ_IN_PROGRESS;
-  
+
   if (fd_info[fd].flags & FILE_PIPE)
     {
       rc = _read (fd, &cp->chr, sizeof (char));
@@ -3470,7 +3596,7 @@ _sys_read_ahead (int fd)
         shell on NT is very slow if we don't do this. */
       if (rc > 0)
        {
-         int wait = XINT (Vw32_pipe_read_delay);
+         int wait = w32_pipe_read_delay;
 
          if (wait > 0)
            Sleep (wait);
@@ -3498,7 +3624,7 @@ _sys_read_ahead (int fd)
        }
     }
 #endif
-  
+
   if (rc == sizeof (char))
     cp->status = STATUS_READ_SUCCEEDED;
   else
@@ -3515,13 +3641,13 @@ sys_read (int fd, char * buffer, unsigned int count)
   DWORD waiting;
   char * orig_buffer = buffer;
 
-  if (fd < 0 || fd >= MAXDESC)
+  if (fd < 0)
     {
       errno = EBADF;
       return -1;
     }
 
-  if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
+  if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
     {
       child_process *cp = fd_info[fd].cp;
 
@@ -3659,13 +3785,13 @@ sys_write (int fd, const void * buffer, unsigned int count)
 {
   int nchars;
 
-  if (fd < 0 || fd >= MAXDESC)
+  if (fd < 0)
     {
       errno = EBADF;
       return -1;
     }
 
-  if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
+  if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
     {
       if ((fd_info[fd].flags & FILE_WRITE) == 0)
        {
@@ -3697,7 +3823,7 @@ sys_write (int fd, const void * buffer, unsigned int count)
                  next[0] = '\n';
                  dst = next + 1;
                  count++;
-               }           
+               }
              else
                /* copied remaining partial line -> now finished */
                break;
@@ -3707,13 +3833,29 @@ sys_write (int fd, const void * buffer, unsigned int count)
     }
 
 #ifdef HAVE_SOCKETS
-  if (fd_info[fd].flags & FILE_SOCKET)
+  if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
     {
+      unsigned long nblock = 0;
       if (winsock_lib == NULL) abort ();
+
+      /* TODO: implement select() properly so non-blocking I/O works. */
+      /* For now, make sure the write blocks.  */
+      if (fd_info[fd].flags & FILE_NDELAY)
+       pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
+
       nchars =  pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
+
+      /* Set the socket back to non-blocking if it was before,
+        for other operations that support it.  */
+      if (fd_info[fd].flags & FILE_NDELAY)
+       {
+         nblock = 1;
+         pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
+       }
+
       if (nchars == SOCKET_ERROR)
         {
-         DebPrint(("sys_read.send failed with error %d on socket %ld\n",
+         DebPrint(("sys_write.send failed with error %d on socket %ld\n",
                    pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
          set_errno ();
        }
@@ -3734,7 +3876,7 @@ check_windows_init_file ()
      it cannot find the Windows installation file.  If this file does
      not exist in the expected place, tell the user.  */
 
-  if (!noninteractive && !inhibit_window_system) 
+  if (!noninteractive && !inhibit_window_system)
     {
       extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
       Lisp_Object objs[2];
@@ -3746,15 +3888,17 @@ check_windows_init_file ()
       objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
       full_load_path = Fappend (2, objs);
       init_file = build_string ("term/w32-win");
-      fd = openp (full_load_path, init_file, Vload_suffixes, NULL, Qnil);
-      if (fd < 0) 
+      fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
+      if (fd < 0)
        {
          Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
          char *init_file_name = SDATA (init_file);
          char *load_path = SDATA (load_path_print);
-         char *buffer = alloca (1024);
+         char *buffer = alloca (1024
+                                + strlen (init_file_name)
+                                + strlen (load_path));
 
-         sprintf (buffer, 
+         sprintf (buffer,
                   "The Emacs Windows initialization file \"%s.el\" "
                   "could not be found in your Emacs installation.  "
                   "Emacs checked the following directories for this file:\n"
@@ -3786,6 +3930,8 @@ term_ntproc ()
   /* shutdown the socket interface if necessary */
   term_winsock ();
 #endif
+
+  term_w32select ();
 }
 
 void
@@ -3819,14 +3965,14 @@ init_ntproc ()
 
     /* ignore errors when duplicating and closing; typically the
        handles will be invalid when running as a gui program. */
-    DuplicateHandle (parent, 
-                    GetStdHandle (STD_INPUT_HANDLE), 
+    DuplicateHandle (parent,
+                    GetStdHandle (STD_INPUT_HANDLE),
                     parent,
-                    &stdin_save, 
-                    0, 
-                    FALSE, 
+                    &stdin_save,
+                    0,
+                    FALSE,
                     DUPLICATE_SAME_ACCESS);
-    
+
     DuplicateHandle (parent,
                     GetStdHandle (STD_OUTPUT_HANDLE),
                     parent,
@@ -3834,7 +3980,7 @@ init_ntproc ()
                     0,
                     FALSE,
                     DUPLICATE_SAME_ACCESS);
-    
+
     DuplicateHandle (parent,
                     GetStdHandle (STD_ERROR_HANDLE),
                     parent,
@@ -3842,7 +3988,7 @@ init_ntproc ()
                     0,
                     FALSE,
                     DUPLICATE_SAME_ACCESS);
-    
+
     fclose (stdin);
     fclose (stdout);
     fclose (stderr);
@@ -3879,7 +4025,7 @@ init_ntproc ()
     while (*drive <= 'Z')
     {
       /* Record if this drive letter refers to a fixed drive. */
-      fixed_drives[DRIVE_INDEX (*drive)] = 
+      fixed_drives[DRIVE_INDEX (*drive)] =
        (GetDriveType (drive) == DRIVE_FIXED);
 
       (*drive)++;
@@ -3888,9 +4034,26 @@ init_ntproc ()
     /* Reset the volume info cache.  */
     volume_cache = NULL;
   }
-  
+
   /* Check to see if Emacs has been installed correctly.  */
   check_windows_init_file ();
 }
 
+/*
+       globals_of_w32 is used to initialize those global variables that
+       must always be initialized on startup even when the global variable
+       initialized is non zero (see the function main in emacs.c).
+*/
+void globals_of_w32 ()
+{
+  g_b_init_is_windows_9x = 0;
+  g_b_init_open_process_token = 0;
+  g_b_init_get_token_information = 0;
+  g_b_init_lookup_account_sid = 0;
+  g_b_init_get_sid_identifier_authority = 0;
+}
+
 /* end of nt.c */
+
+/* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
+   (do not change this comment) */