Fix previous conflict.
[bpt/emacs.git] / src / w32.c
index ddb4898..1933574 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -1,6 +1,6 @@
 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
    Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-                 2007, 2008  Free Software Foundation, Inc.
+                 2007, 2008, 2009, 2010  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -23,6 +23,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <stddef.h> /* for offsetof */
 #include <stdlib.h>
 #include <stdio.h>
+#include <float.h>     /* for DBL_EPSILON */
 #include <io.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -33,6 +34,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <sys/utime.h>
 #include <mbstring.h>  /* for _mbspbrk */
 #include <math.h>
+#include <setjmp.h>
 
 /* must include CRT headers *before* config.h */
 
@@ -146,7 +148,7 @@ extern Lisp_Object QCflowcontrol, Qhw, Qsw, QCsummary;
 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
   (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
 
-void globals_of_w32 ();
+void globals_of_w32 (void);
 static DWORD get_rid (PSID);
 
 extern Lisp_Object Vw32_downcase_file_names;
@@ -188,6 +190,11 @@ static BOOL g_b_init_get_process_memory_info;
 static BOOL g_b_init_get_process_working_set_size;
 static BOOL g_b_init_global_memory_status;
 static BOOL g_b_init_global_memory_status_ex;
+static BOOL g_b_init_get_length_sid;
+static BOOL g_b_init_equal_sid;
+static BOOL g_b_init_copy_sid;
+static BOOL g_b_init_get_native_system_info;
+static BOOL g_b_init_get_system_times;
 
 /*
   BEGIN: Wrapper functions around OpenProcessToken
@@ -281,18 +288,35 @@ typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
     LPMEMORYSTATUS lpBuffer);
 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
     LPMEMORY_STATUS_EX lpBuffer);
+typedef BOOL (WINAPI * CopySid_Proc) (
+    DWORD nDestinationSidLength,
+    PSID pDestinationSid,
+    PSID pSourceSid);
+typedef BOOL (WINAPI * EqualSid_Proc) (
+    PSID pSid1,
+    PSID pSid2);
+typedef DWORD (WINAPI * GetLengthSid_Proc) (
+    PSID pSid);
+typedef void (WINAPI * GetNativeSystemInfo_Proc) (
+    LPSYSTEM_INFO lpSystemInfo);
+typedef BOOL (WINAPI * GetSystemTimes_Proc) (
+    LPFILETIME lpIdleTime,
+    LPFILETIME lpKernelTime,
+    LPFILETIME lpUserTime);
+
+
 
   /* ** A utility function ** */
 static BOOL
-is_windows_9x ()
+is_windows_9x (void)
 {
   static BOOL s_b_ret=0;
   OSVERSIONINFO os_ver;
   if (g_b_init_is_windows_9x == 0)
     {
       g_b_init_is_windows_9x = 1;
-      ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
-      os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+      ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
+      os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
       if (GetVersionEx (&os_ver))
         {
           s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
@@ -305,12 +329,12 @@ is_windows_9x ()
    Returns a list of three integers if the times are provided by the OS
    (NT derivatives), otherwise it returns the result of current-time. */
 Lisp_Object
-w32_get_internal_run_time ()
+w32_get_internal_run_time (void)
 {
   if (get_process_times_fn)
     {
       FILETIME create, exit, kernel, user;
-      HANDLE proc = GetCurrentProcess();
+      HANDLE proc = GetCurrentProcess ();
       if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
         {
           LARGE_INTEGER user_int, kernel_int, total;
@@ -628,12 +652,128 @@ BOOL WINAPI is_valid_sid (
   return (s_pfn_Is_Valid_Sid (sid));
 }
 
+BOOL WINAPI equal_sid (
+    PSID sid1,
+    PSID sid2)
+{
+  static EqualSid_Proc s_pfn_Equal_Sid = NULL;
+  HMODULE hm_advapi32 = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_equal_sid == 0)
+    {
+      g_b_init_equal_sid = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Equal_Sid =
+        (EqualSid_Proc) GetProcAddress (
+            hm_advapi32, "EqualSid");
+    }
+  if (s_pfn_Equal_Sid == NULL)
+    {
+      return FALSE;
+    }
+  return (s_pfn_Equal_Sid (sid1, sid2));
+}
+
+DWORD WINAPI get_length_sid (
+    PSID sid)
+{
+  static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
+  HMODULE hm_advapi32 = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return 0;
+    }
+  if (g_b_init_get_length_sid == 0)
+    {
+      g_b_init_get_length_sid = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Get_Length_Sid =
+        (GetLengthSid_Proc) GetProcAddress (
+            hm_advapi32, "GetLengthSid");
+    }
+  if (s_pfn_Get_Length_Sid == NULL)
+    {
+      return 0;
+    }
+  return (s_pfn_Get_Length_Sid (sid));
+}
+
+BOOL WINAPI copy_sid (
+    DWORD destlen,
+    PSID dest,
+    PSID src)
+{
+  static CopySid_Proc s_pfn_Copy_Sid = NULL;
+  HMODULE hm_advapi32 = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_copy_sid == 0)
+    {
+      g_b_init_copy_sid = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Copy_Sid =
+        (CopySid_Proc) GetProcAddress (
+            hm_advapi32, "CopySid");
+    }
+  if (s_pfn_Copy_Sid == NULL)
+    {
+      return FALSE;
+    }
+  return (s_pfn_Copy_Sid (destlen, dest, src));
+}
+
 /*
   END: Wrapper functions around OpenProcessToken
   and other functions in advapi32.dll that are only
   supported in Windows NT / 2k / XP
 */
 
+void WINAPI get_native_system_info (
+    LPSYSTEM_INFO lpSystemInfo)
+{
+  static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
+  if (is_windows_9x () != TRUE)
+    {
+      if (g_b_init_get_native_system_info == 0)
+       {
+         g_b_init_get_native_system_info = 1;
+         s_pfn_Get_Native_System_Info =
+           (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                                                     "GetNativeSystemInfo");
+       }
+      if (s_pfn_Get_Native_System_Info != NULL)
+       s_pfn_Get_Native_System_Info (lpSystemInfo);
+    }
+  else
+    lpSystemInfo->dwNumberOfProcessors = -1;
+}
+
+BOOL WINAPI get_system_times (
+    LPFILETIME lpIdleTime,
+    LPFILETIME lpKernelTime,
+    LPFILETIME lpUserTime)
+{
+  static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_get_system_times == 0)
+    {
+      g_b_init_get_system_times = 1;
+      s_pfn_Get_System_times =
+       (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                                            "GetSystemTimes");
+    }
+  if (s_pfn_Get_System_times == NULL)
+    return FALSE;
+  return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
+}
 \f
 /* Equivalent of strerror for W32 error codes.  */
 char *
@@ -706,17 +846,160 @@ gethostname (char *buffer, int size)
 #endif /* HAVE_SOCKETS */
 
 /* Emulate getloadavg.  */
+
+struct load_sample {
+  time_t sample_time;
+  ULONGLONG idle;
+  ULONGLONG kernel;
+  ULONGLONG user;
+};
+
+/* Number of processors on this machine.  */
+static unsigned num_of_processors;
+
+/* We maintain 1-sec samples for the last 16 minutes in a circular buffer.  */
+static struct load_sample samples[16*60];
+static int first_idx = -1, last_idx = -1;
+static int max_idx = sizeof (samples) / sizeof (samples[0]);
+
+static int
+buf_next (int from)
+{
+  int next_idx = from + 1;
+
+  if (next_idx >= max_idx)
+    next_idx = 0;
+
+  return next_idx;
+}
+
+static int
+buf_prev (int from)
+{
+  int prev_idx = from - 1;
+
+  if (prev_idx < 0)
+    prev_idx = max_idx - 1;
+
+  return prev_idx;
+}
+
+static void
+sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
+{
+  SYSTEM_INFO sysinfo;
+  FILETIME ft_idle, ft_user, ft_kernel;
+
+  /* Initialize the number of processors on this machine.  */
+  if (num_of_processors <= 0)
+    {
+      get_native_system_info (&sysinfo);
+      num_of_processors = sysinfo.dwNumberOfProcessors;
+      if (num_of_processors <= 0)
+       {
+         GetSystemInfo (&sysinfo);
+         num_of_processors = sysinfo.dwNumberOfProcessors;
+       }
+      if (num_of_processors <= 0)
+       num_of_processors = 1;
+    }
+
+  /* TODO: Take into account threads that are ready to run, by
+     sampling the "\System\Processor Queue Length" performance
+     counter.  The code below accounts only for threads that are
+     actually running.  */
+
+  if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
+    {
+      ULARGE_INTEGER uidle, ukernel, uuser;
+
+      memcpy (&uidle, &ft_idle, sizeof (ft_idle));
+      memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
+      memcpy (&uuser, &ft_user, sizeof (ft_user));
+      *idle = uidle.QuadPart;
+      *kernel = ukernel.QuadPart;
+      *user = uuser.QuadPart;
+    }
+  else
+    {
+      *idle = 0;
+      *kernel = 0;
+      *user = 0;
+    }
+}
+
+/* Produce the load average for a given time interval, using the
+   samples in the samples[] array.  WHICH can be 0, 1, or 2, meaning
+   1-minute, 5-minute, or 15-minute average, respectively. */
+static double
+getavg (int which)
+{
+  double retval = -1.0;
+  double tdiff;
+  int idx;
+  double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
+  time_t now = samples[last_idx].sample_time;
+
+  if (first_idx != last_idx)
+    {
+      for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
+       {
+         tdiff = difftime (now, samples[idx].sample_time);
+         if (tdiff >= span - 2*DBL_EPSILON*now)
+           {
+             long double sys =
+               samples[last_idx].kernel + samples[last_idx].user
+               - (samples[idx].kernel + samples[idx].user);
+             long double idl = samples[last_idx].idle - samples[idx].idle;
+
+             retval = (1.0 - idl / sys) * num_of_processors;
+             break;
+           }
+         if (idx == first_idx)
+           break;
+       }
+    }
+
+  return retval;
+}
+
 int
 getloadavg (double loadavg[], int nelem)
 {
-  int i;
+  int elem;
+  ULONGLONG idle, kernel, user;
+  time_t now = time (NULL);
 
-  /* A faithful emulation is going to have to be saved for a rainy day.  */
-  for (i = 0; i < nelem; i++)
+  /* Store another sample.  We ignore samples that are less than 1 sec
+     apart.  */
+  if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
     {
-      loadavg[i] = 0.0;
+      sample_system_load (&idle, &kernel, &user);
+      last_idx = buf_next (last_idx);
+      samples[last_idx].sample_time = now;
+      samples[last_idx].idle = idle;
+      samples[last_idx].kernel = kernel;
+      samples[last_idx].user = user;
+      /* If the buffer has more that 15 min worth of samples, discard
+        the old ones.  */
+      if (first_idx == -1)
+       first_idx = last_idx;
+      while (first_idx != last_idx
+            && (difftime (now, samples[first_idx].sample_time)
+                >= 15.0*60 + 2*DBL_EPSILON*now))
+       first_idx = buf_next (first_idx);
+    }
+
+  for (elem = 0; elem < nelem; elem++)
+    {
+      double avg = getavg (elem);
+
+      if (avg < 0)
+       break;
+      loadavg[elem] = avg;
     }
-  return i;
+
+  return elem;
 }
 
 /* Emulate getpwuid, getpwnam and others.  */
@@ -751,14 +1034,14 @@ static struct group dflt_group =
   0,
 };
 
-int
-getuid ()
+unsigned
+getuid (void)
 {
   return dflt_passwd.pw_uid;
 }
 
-int
-geteuid ()
+unsigned
+geteuid (void)
 {
   /* I could imagine arguing for checking to see whether the user is
      in the Administrators group and returning a UID of 0 for that
@@ -766,20 +1049,20 @@ geteuid ()
   return getuid ();
 }
 
-int
-getgid ()
+unsigned
+getgid (void)
 {
   return dflt_passwd.pw_gid;
 }
 
-int
-getegid ()
+unsigned
+getegid (void)
 {
   return getgid ();
 }
 
 struct passwd *
-getpwuid (int uid)
+getpwuid (unsigned uid)
 {
   if (uid == dflt_passwd.pw_uid)
     return &dflt_passwd;
@@ -808,7 +1091,7 @@ getpwnam (char *name)
 }
 
 void
-init_user_info ()
+init_user_info (void)
 {
   /* Find the user's real name by opening the process token and
      looking up the name associated with the user-sid in that token.
@@ -818,20 +1101,37 @@ init_user_info ()
      primary group sid from the process token). */
 
   char         uname[UNLEN+1], gname[GNLEN+1], domain[1025];
-  DWORD        ulength = sizeof (uname), dlength = sizeof (domain), trash;
+  DWORD        ulength = sizeof (uname), dlength = sizeof (domain), needed;
   DWORD               glength = sizeof (gname);
   HANDLE       token = NULL;
   SID_NAME_USE user_type;
-  unsigned char buf[1024];
+  unsigned char *buf = NULL;
+  DWORD        blen = 0;
   TOKEN_USER   user_token;
   TOKEN_PRIMARY_GROUP group_token;
+  BOOL         result;
 
-  if (open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
-      && get_token_information (token, TokenUser,
-                               (PVOID)buf, sizeof (buf), &trash)
-      && (memcpy (&user_token, buf, sizeof (user_token)),
-         lookup_account_sid (NULL, user_token.User.Sid, uname, &ulength,
-                             domain, &dlength, &user_type)))
+  result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
+  if (result)
+    {
+      result = get_token_information (token, TokenUser, NULL, 0, &blen);
+      if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+       {
+         buf = xmalloc (blen);
+         result = get_token_information (token, TokenUser,
+                                         (LPVOID)buf, blen, &needed);
+         if (result)
+           {
+             memcpy (&user_token, buf, sizeof (user_token));
+             result = lookup_account_sid (NULL, user_token.User.Sid,
+                                          uname, &ulength,
+                                          domain, &dlength, &user_type);
+           }
+       }
+      else
+       result = FALSE;
+    }
+  if (result)
     {
       strcpy (dflt_passwd.pw_name, uname);
       /* Determine a reasonable uid value.  */
@@ -847,12 +1147,22 @@ init_user_info ()
          dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
 
          /* Get group id and name.  */
-         if (get_token_information (token, TokenPrimaryGroup,
-                                    (PVOID)buf, sizeof (buf), &trash))
+         result = get_token_information (token, TokenPrimaryGroup,
+                                         (LPVOID)buf, blen, &needed);
+         if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+           {
+             buf = xrealloc (buf, blen = needed);
+             result = get_token_information (token, TokenPrimaryGroup,
+                                             (LPVOID)buf, blen, &needed);
+           }
+         if (result)
            {
              memcpy (&group_token, buf, sizeof (group_token));
              dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
              dlength = sizeof (domain);
+             /* If we can get at the real Primary Group name, use that.
+                Otherwise, the default group name was already set to
+                "None" in globals_of_w32.  */
              if (lookup_account_sid (NULL, group_token.PrimaryGroup,
                                      gname, &glength, NULL, &dlength,
                                      &user_type))
@@ -863,7 +1173,7 @@ init_user_info ()
        }
     }
   /* If security calls are not supported (presumably because we
-     are running under Windows 95), fallback to this. */
+     are running under Windows 9X), fallback to this: */
   else if (GetUserName (uname, &ulength))
     {
       strcpy (dflt_passwd.pw_name, uname);
@@ -891,12 +1201,13 @@ init_user_info ()
   strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
   strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
 
+  xfree (buf);
   if (token)
     CloseHandle (token);
 }
 
 int
-random ()
+random (void)
 {
   /* rand () on NT gives us 15 random bits...hack together 30 bits.  */
   return ((rand () << 15) | rand ());
@@ -914,9 +1225,7 @@ srandom (int seed)
    case path name components to lower case.  */
 
 static void
-normalize_filename (fp, path_sep)
-     register char *fp;
-     char path_sep;
+normalize_filename (register char *fp, char path_sep)
 {
   char sep;
   char *elem;
@@ -972,16 +1281,14 @@ normalize_filename (fp, path_sep)
 
 /* Destructively turn backslashes into slashes.  */
 void
-dostounix_filename (p)
-     register char *p;
+dostounix_filename (register char *p)
 {
   normalize_filename (p, '/');
 }
 
 /* Destructively turn slashes into backslashes.  */
 void
-unixtodos_filename (p)
-     register char *p;
+unixtodos_filename (register char *p)
 {
   normalize_filename (p, '\\');
 }
@@ -990,9 +1297,7 @@ unixtodos_filename (p)
    (From msdos.c...probably should figure out a way to share it,
    although this code isn't going to ever change.)  */
 int
-crlf_to_lf (n, buf)
-     register int n;
-     register unsigned char *buf;
+crlf_to_lf (register int n, register unsigned char *buf)
 {
   unsigned char *np = buf;
   unsigned char *startp = buf;
@@ -1170,6 +1475,30 @@ sigunblock (int sig)
   return 0;
 }
 
+int
+sigemptyset (sigset_t *set)
+{
+  return 0;
+}
+
+int
+sigaddset (sigset_t *set, int signo)
+{
+  return 0;
+}
+
+int
+sigfillset (sigset_t *set)
+{
+  return 0;
+}
+
+int
+sigprocmask (int how, const sigset_t *set, sigset_t *oset)
+{
+  return 0;
+}
+
 int
 setpgrp (int pid, int gid)
 {
@@ -1185,9 +1514,7 @@ alarm (int seconds)
 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
 
 LPBYTE
-w32_get_resource (key, lpdwtype)
-    char *key;
-    LPDWORD lpdwtype;
+w32_get_resource (char *key, LPDWORD lpdwtype)
 {
   LPBYTE lpvalue;
   HKEY hrootkey = NULL;
@@ -1307,7 +1634,7 @@ init_environment (char ** argv)
       {"LANG", NULL},
     };
 
-#define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
+#define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
 
     /* We need to copy dflt_envvars[] and work on the copy because we
        don't want the dumped Emacs to inherit the values of
@@ -1326,12 +1653,10 @@ init_environment (char ** argv)
       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;
+        MSIE 5.  */
       ShGetFolderPath_fn get_folder_path;
-      shell32_dll = GetModuleHandle ("shell32.dll");
       get_folder_path = (ShGetFolderPath_fn)
-       GetProcAddress (shell32_dll, "SHGetFolderPathA");
+       GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
 
       if (get_folder_path != NULL)
        {
@@ -1342,9 +1667,6 @@ init_environment (char ** argv)
          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.  */
@@ -1385,7 +1707,7 @@ init_environment (char ** argv)
          for (p = modname; *p; p++)
            if (*p == '\\') *p = '/';
 
-         _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
+         _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
          _putenv (strdup (buf));
        }
       /* Handle running emacs from the build directory: src/oo-spd/i386/  */
@@ -1409,7 +1731,7 @@ init_environment (char ** argv)
                  for (p = modname; *p; p++)
                    if (*p == '\\') *p = '/';
 
-                 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
+                 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
                  _putenv (strdup (buf));
                }
            }
@@ -1437,12 +1759,12 @@ init_environment (char ** argv)
                char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
 
                if (dwType == REG_EXPAND_SZ)
-                 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
+                 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
                else if (dwType == REG_SZ)
                  strcpy (buf1, lpval);
                if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
                  {
-                   _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name,
+                   _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
                               buf1);
                    _putenv (strdup (buf2));
                  }
@@ -1785,7 +2107,7 @@ GetCachedVolumeInformation (char * root_dir)
      involve network access, and so is extremely quick).  */
 
   /* Map drive letter to UNC if remote. */
-  if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
+  if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
     {
       char remote_name[ 256 ];
       char drive[3] = { root_dir[0], ':' };
@@ -2184,8 +2506,8 @@ open_unc_volume (const char *path)
   nr.lpComment = NULL;
   nr.lpProvider = NULL;
 
-  result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
-                       RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
+  result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
+                        RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
 
   if (result == NO_ERROR)
     return henum;
@@ -2250,12 +2572,23 @@ logon_network_drive (const char *path)
   char share[MAX_PATH];
   int i, n_slashes;
   char drive[4];
+  UINT drvtype;
 
-  sprintf (drive, "%c:\\", path[0]);
+  if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
+    drvtype = DRIVE_REMOTE;
+  else if (path[0] == '\0' || path[1] != ':')
+    drvtype = GetDriveType (NULL);
+  else
+    {
+      drive[0] = path[0];
+      drive[1] = ':';
+      drive[2] = '\\';
+      drive[3] = '\0';
+      drvtype = GetDriveType (drive);
+    }
 
   /* Only logon to networked drives.  */
-  if ((!IS_DIRECTORY_SEP (path[0]) || !IS_DIRECTORY_SEP (path[1]))
-      && GetDriveType (drive) != DRIVE_REMOTE)
+  if (drvtype != DRIVE_REMOTE)
     return;
 
   n_slashes = 2;
@@ -2350,7 +2683,7 @@ sys_creat (const char * path, int mode)
 }
 
 FILE *
-sys_fopen(const char * path, const char * mode)
+sys_fopen (const char * path, const char * mode)
 {
   int fd;
   int oflag;
@@ -2437,7 +2770,7 @@ sys_link (const char * old, const char * new)
 
          data.wid.dwStreamId = BACKUP_LINK;
          data.wid.dwStreamAttributes = 0;
-         data.wid.Size.LowPart = wlen * sizeof(WCHAR);
+         data.wid.Size.LowPart = wlen * sizeof (WCHAR);
          data.wid.Size.HighPart = 0;
          data.wid.dwStreamNameSize = 0;
 
@@ -2627,76 +2960,69 @@ sys_unlink (const char * path)
 }
 
 static FILETIME utc_base_ft;
-static long double utc_base;
+static ULONGLONG utc_base;  /* In 100ns units */
 static int init = 0;
 
-static long double
-convert_time_raw (FILETIME ft)
+#define FILETIME_TO_U64(result, ft)        \
+  do {                                     \
+    ULARGE_INTEGER uiTemp;                 \
+    uiTemp.LowPart = (ft).dwLowDateTime;   \
+    uiTemp.HighPart = (ft).dwHighDateTime; \
+    result = uiTemp.QuadPart;              \
+  } while (0)
+
+static void
+initialize_utc_base (void)
 {
-  return
-    (long double) ft.dwHighDateTime
-    * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
+  /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
+  SYSTEMTIME st;
+
+  st.wYear = 1970;
+  st.wMonth = 1;
+  st.wDay = 1;
+  st.wHour = 0;
+  st.wMinute = 0;
+  st.wSecond = 0;
+  st.wMilliseconds = 0;
+
+  SystemTimeToFileTime (&st, &utc_base_ft);
+  FILETIME_TO_U64 (utc_base, utc_base_ft);
 }
 
 static time_t
 convert_time (FILETIME ft)
 {
-  long double ret;
+  ULONGLONG tmp;
 
   if (!init)
     {
-      /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
-      SYSTEMTIME st;
-
-      st.wYear = 1970;
-      st.wMonth = 1;
-      st.wDay = 1;
-      st.wHour = 0;
-      st.wMinute = 0;
-      st.wSecond = 0;
-      st.wMilliseconds = 0;
-
-      SystemTimeToFileTime (&st, &utc_base_ft);
-      utc_base = (long double) utc_base_ft.dwHighDateTime
-       * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
+      initialize_utc_base();
       init = 1;
     }
 
   if (CompareFileTime (&ft, &utc_base_ft) < 0)
     return 0;
 
-  return (time_t) ((convert_time_raw (ft) - utc_base) * 1e-7L);
+  FILETIME_TO_U64 (tmp, ft);
+  return (time_t) ((tmp - utc_base) / 10000000L);
 }
 
 
 void
 convert_from_time_t (time_t time, FILETIME * pft)
 {
-  long double tmp;
+  ULARGE_INTEGER tmp;
 
   if (!init)
     {
-      /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
-      SYSTEMTIME st;
-
-      st.wYear = 1970;
-      st.wMonth = 1;
-      st.wDay = 1;
-      st.wHour = 0;
-      st.wMinute = 0;
-      st.wSecond = 0;
-      st.wMilliseconds = 0;
-
-      SystemTimeToFileTime (&st, &utc_base_ft);
-      utc_base = (long double) utc_base_ft.dwHighDateTime
-       * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
+      initialize_utc_base ();
       init = 1;
     }
 
   /* time in 100ns units since 1-Jan-1601 */
-  tmp = (long double) time * 1e7 + utc_base;
-  pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
-  pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
+  tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
+  pft->dwHighDateTime = tmp.HighPart;
+  pft->dwLowDateTime = tmp.LowPart;
 }
 
 #if 0
@@ -2780,12 +3106,75 @@ get_rid (PSID sid)
   return *get_sid_sub_authority (sid, n_subauthorities - 1);
 }
 
+/* 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;
+  char name[GNLEN+1];
+  unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
+};
+
+static struct w32_id *w32_idlist;
+
+static int
+w32_cached_id (PSID sid, unsigned *id, char *name)
+{
+  struct w32_id *tail, *found;
+
+  for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
+    {
+      if (equal_sid ((PSID)tail->sid, sid))
+       {
+         found = tail;
+         break;
+       }
+    }
+  if (found)
+    {
+      *id = found->rid;
+      strcpy (name, found->name);
+      return 1;
+    }
+  else
+    return 0;
+}
+
+static void
+w32_add_to_cache (PSID sid, unsigned id, char *name)
+{
+  DWORD sid_len;
+  struct w32_id *new_entry;
+
+  /* We don't want to leave behind stale cache from when Emacs was
+     dumped.  */
+  if (initialized)
+    {
+      sid_len = get_length_sid (sid);
+      new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
+      if (new_entry)
+       {
+         new_entry->rid = id;
+         strcpy (new_entry->name, name);
+         copy_sid (sid_len, (PSID)new_entry->sid, sid);
+         new_entry->next = w32_idlist;
+         w32_idlist = new_entry;
+       }
+    }
+}
+
 #define UID 1
 #define GID 2
 
 static int
 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
-                int *id, char *nm, int what)
+                unsigned *id, char *nm, int what)
 {
   PSID sid = NULL;
   char machine[MAX_COMPUTERNAME_LENGTH+1];
@@ -2794,7 +3183,7 @@ get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
   char name[UNLEN+1];
   DWORD name_len = sizeof (name);
   char domain[1024];
-  DWORD domain_len = sizeof(domain);
+  DWORD domain_len = sizeof (domain);
   char *mp = NULL;
   int use_dflt = 0;
   int result;
@@ -2808,7 +3197,7 @@ get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
 
   if (!result || !is_valid_sid (sid))
     use_dflt = 1;
-  else
+  else if (!w32_cached_id (sid, id, nm))
     {
       /* If FNAME is a UNC, we need to lookup account on the
         specified machine.  */
@@ -2833,6 +3222,7 @@ get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
        {
          *id = get_rid (sid);
          strcpy (nm, name);
+         w32_add_to_cache (sid, *id, name);
        }
     }
   return use_dflt;
@@ -2872,6 +3262,28 @@ get_file_owner_and_group (
     }
 }
 
+/* Return non-zero if NAME is a potentially slow filesystem.  */
+int
+is_slow_fs (const char *name)
+{
+  char drive_root[4];
+  UINT devtype;
+
+  if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
+    devtype = DRIVE_REMOTE;       /* assume UNC name is remote */
+  else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
+    devtype = GetDriveType (NULL); /* use root of current drive */
+  else
+    {
+      /* GetDriveType needs the root directory of the drive.  */
+      strncpy (drive_root, name, 2);
+      drive_root[2] = '\\';
+      drive_root[3] = '\0';
+      devtype = GetDriveType (drive_root);
+    }
+  return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
+}
+
 /* 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 without hacks in the main Emacs code. */
@@ -2985,19 +3397,8 @@ stat (const char * path, struct stat * buf)
        }
     }
 
-  /* GetDriveType needs the root directory of NAME's drive.  */
-  if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
-    devtype = GetDriveType (NULL); /* use root of current diectory */
-  else
-    {
-      strncpy (drive_root, name, 3);
-      drive_root[3] = '\0';
-      devtype = GetDriveType (drive_root);
-    }
-
   if (!(NILP (Vw32_get_true_file_attributes)
-       || (EQ (Vw32_get_true_file_attributes, Qlocal)
-           && devtype != DRIVE_FIXED && devtype != DRIVE_RAMDISK))
+       || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
       /* No access rights required to get info.  */
       && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
                           FILE_FLAG_BACKUP_SEMANTICS, NULL))
@@ -3257,7 +3658,7 @@ utime (const char *name, struct utimbuf *times)
 
 /* Helper wrapper functions.  */
 
-HANDLE WINAPI create_toolhelp32_snapshot(
+HANDLE WINAPI create_toolhelp32_snapshot (
     DWORD Flags,
     DWORD Ignored)
 {
@@ -3277,7 +3678,7 @@ HANDLE WINAPI create_toolhelp32_snapshot(
   return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
 }
 
-BOOL WINAPI process32_first(
+BOOL WINAPI process32_first (
     HANDLE hSnapshot,
     LPPROCESSENTRY32 lppe)
 {
@@ -3297,7 +3698,7 @@ BOOL WINAPI process32_first(
   return (s_pfn_Process32_First (hSnapshot, lppe));
 }
 
-BOOL WINAPI process32_next(
+BOOL WINAPI process32_next (
     HANDLE hSnapshot,
     LPPROCESSENTRY32 lppe)
 {
@@ -3495,7 +3896,7 @@ BOOL WINAPI global_memory_status_ex (
 }
 
 Lisp_Object
-w32_list_system_processes ()
+list_system_processes (void)
 {
   struct gcpro gcpro1;
   Lisp_Object proclist = Qnil;
@@ -3586,53 +3987,54 @@ restore_privilege (TOKEN_PRIVILEGES *priv)
 }
 
 static Lisp_Object
-ltime (time_sec, time_usec)
-     long time_sec, time_usec;
+ltime (long time_sec, long time_usec)
 {
   return list3 (make_number ((time_sec >> 16) & 0xffff),
                make_number (time_sec & 0xffff),
                make_number (time_usec));
 }
 
+#define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
+
 static int
-process_times (h_proc, ctime, etime, stime, utime, pcpu)
-     HANDLE h_proc;
-     Lisp_Object *ctime, *etime, *stime, *utime;
-     double *pcpu;
+process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
+              Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
+              double *pcpu)
 {
   FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
-  long ctime_sec, ctime_usec, stime_sec, stime_usec, utime_sec, utime_usec;
-  long etime_sec, etime_usec;
-  long double tem1, tem2, tem;
+  ULONGLONG tem1, tem2, tem3, tem;
 
   if (!h_proc
       || !get_process_times_fn
-      || !(*get_process_times_fn)(h_proc, &ft_creation, &ft_exit,
-                                 &ft_kernel, &ft_user))
+      || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
+                                  &ft_kernel, &ft_user))
     return 0;
 
   GetSystemTimeAsFileTime (&ft_current);
 
-  tem1 = convert_time_raw (ft_kernel) * 0.1L;
-  stime_usec = fmodl (tem1, 1000000.0L);
-  stime_sec = tem1 * 0.000001L;
-  *stime = ltime (stime_sec, stime_usec);
-  tem2 = convert_time_raw (ft_user) * 0.1L;
-  utime_usec = fmodl (tem2, 1000000.0L);
-  utime_sec = tem2 * 0.000001L;
-  *utime = ltime (utime_sec, utime_usec);
-  tem = convert_time_raw (ft_creation);
+  FILETIME_TO_U64 (tem1, ft_kernel);
+  tem1 /= 10L;
+  *stime = U64_TO_LISP_TIME (tem1);
+
+  FILETIME_TO_U64 (tem2, ft_user);
+  tem2 /= 10L;
+  *utime = U64_TO_LISP_TIME (tem2);
+
+  tem3 = tem1 + tem2;
+  *ttime = U64_TO_LISP_TIME (tem3);
+
+  FILETIME_TO_U64 (tem, ft_creation);
   /* Process no 4 (System) returns zero creation time.  */
   if (tem)
-    tem = (tem - utc_base) * 0.1;
-  ctime_usec = fmodl (tem, 1000000.0L);
-  ctime_sec = tem * 0.000001L;
-  *ctime = ltime (ctime_sec, ctime_usec);
+    tem = (tem - utc_base) / 10L;
+  *ctime = U64_TO_LISP_TIME (tem);
+
   if (tem)
-    tem = (convert_time_raw (ft_current) - utc_base) * 0.1L - tem;
-  etime_usec = fmodl (tem, 1000000.0L);
-  etime_sec = tem * 0.000001L;
-  *etime = ltime (etime_sec, etime_usec);
+    {
+      FILETIME_TO_U64 (tem3, ft_current);
+      tem = (tem3 - utc_base) / 10L - tem;
+    }
+  *etime = U64_TO_LISP_TIME (tem);
 
   if (tem)
     {
@@ -3647,8 +4049,7 @@ process_times (h_proc, ctime, etime, stime, utime, pcpu)
 }
 
 Lisp_Object
-w32_system_process_attributes (pid)
-     Lisp_Object pid;
+system_process_attributes (Lisp_Object pid)
 {
   struct gcpro gcpro1, gcpro2, gcpro3;
   Lisp_Object attrs = Qnil;
@@ -3657,15 +4058,16 @@ w32_system_process_attributes (pid)
   DWORD proc_id;
   int found_proc = 0;
   char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
-  DWORD ulength = sizeof (uname), dlength = sizeof (domain), trash;
+  DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
   DWORD glength = sizeof (gname);
   HANDLE token = NULL;
   SID_NAME_USE user_type;
-  unsigned char buf[1024];
+  unsigned char *buf = NULL;
+  DWORD blen = 0;
   TOKEN_USER user_token;
   TOKEN_PRIMARY_GROUP group_token;
-  int euid;
-  int egid;
+  unsigned euid;
+  unsigned egid;
   DWORD sess;
   PROCESS_MEMORY_COUNTERS mem;
   PROCESS_MEMORY_COUNTERS_EX mem_ex;
@@ -3673,8 +4075,9 @@ w32_system_process_attributes (pid)
   MEMORYSTATUS memst;
   MEMORY_STATUS_EX memstex;
   double totphys = 0.0;
-  Lisp_Object ctime, stime, utime, etime;
+  Lisp_Object ctime, stime, utime, etime, ttime;
   double pcpu;
+  BOOL result = FALSE;
 
   CHECK_NUMBER_OR_FLOAT (pid);
   proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
@@ -3745,78 +4148,124 @@ w32_system_process_attributes (pid)
          revert_to_self ();
        }
     }
-  if (h_proc
-      && open_process_token (h_proc, TOKEN_QUERY, &token)
-      && get_token_information (token, TokenUser,
-                               (PVOID)buf, sizeof (buf), &trash)
-      && (memcpy (&user_token, buf, sizeof (user_token)),
-         lookup_account_sid (NULL, user_token.User.Sid, uname, &ulength,
-                             domain, &dlength, &user_type)))
-    {
-      /* Determine a reasonable euid and gid values.  */
-      if (xstrcasecmp ("administrator", uname) == 0)
+  if (h_proc)
+    {
+      result = open_process_token (h_proc, TOKEN_QUERY, &token);
+      if (result)
        {
-         euid = 500;   /* well-known Administrator uid */
-         egid = 513;   /* well-known None gid */
+         result = get_token_information (token, TokenUser, NULL, 0, &blen);
+         if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+           {
+             buf = xmalloc (blen);
+             result = get_token_information (token, TokenUser,
+                                             (LPVOID)buf, blen, &needed);
+             if (result)
+               {
+                 memcpy (&user_token, buf, sizeof (user_token));
+                 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
+                   {
+                     euid = get_rid (user_token.User.Sid);
+                     result = lookup_account_sid (NULL, user_token.User.Sid,
+                                                  uname, &ulength,
+                                                  domain, &dlength,
+                                                  &user_type);
+                     if (result)
+                       w32_add_to_cache (user_token.User.Sid, euid, uname);
+                     else
+                       {
+                         strcpy (uname, "unknown");
+                         result = TRUE;
+                       }
+                   }
+                 ulength = strlen (uname);
+               }
+           }
        }
-      else
+      if (result)
        {
-         /* Use the last sub-authority value of the RID, the relative
-            portion of the SID, as user/group ID. */
-         euid = get_rid (user_token.User.Sid);
-
-         /* Get group id and name.  */
-         if (get_token_information (token, TokenPrimaryGroup,
-                                    (PVOID)buf, sizeof (buf), &trash))
+         /* Determine a reasonable euid and gid values.  */
+         if (xstrcasecmp ("administrator", uname) == 0)
            {
-             memcpy (&group_token, buf, sizeof (group_token));
-             egid = get_rid (group_token.PrimaryGroup);
-             dlength = sizeof (domain);
-             lookup_account_sid (NULL, group_token.PrimaryGroup,
-                                 gname, &glength, NULL, &dlength,
-                                 &user_type);
+             euid = 500;       /* well-known Administrator uid */
+             egid = 513;       /* well-known None gid */
            }
          else
-           egid = euid;
+           {
+             /* Get group id and name.  */
+             result = get_token_information (token, TokenPrimaryGroup,
+                                             (LPVOID)buf, blen, &needed);
+             if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+               {
+                 buf = xrealloc (buf, blen = needed);
+                 result = get_token_information (token, TokenPrimaryGroup,
+                                                 (LPVOID)buf, blen, &needed);
+               }
+             if (result)
+               {
+                 memcpy (&group_token, buf, sizeof (group_token));
+                 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
+                   {
+                     egid = get_rid (group_token.PrimaryGroup);
+                     dlength = sizeof (domain);
+                     result =
+                       lookup_account_sid (NULL, group_token.PrimaryGroup,
+                                           gname, &glength, NULL, &dlength,
+                                           &user_type);
+                     if (result)
+                       w32_add_to_cache (group_token.PrimaryGroup,
+                                         egid, gname);
+                     else
+                       {
+                         strcpy (gname, "None");
+                         result = TRUE;
+                       }
+                   }
+                 glength = strlen (gname);
+               }
+           }
        }
+      xfree (buf);
     }
-  else if (!is_windows_9x ())
-    {
-      /* We couldn't open the process token, presumably because of
-        insufficient access rights.  Assume this process is run by
-        the system.  */
-      strcpy (uname, "SYSTEM");
-      strcpy (gname, "None");
-      euid = 18;       /* SYSTEM */
-      egid = 513;      /* None */
-      glength = strlen (gname);
-      ulength = strlen (uname);
-    }
-  /* If we are running under Windows 9X, where security calls are not
-     supported, we assume all processes are run by the current
-     user.  */
-  else if (GetUserName (uname, &ulength))
+  if (!result)
     {
-      if (xstrcasecmp ("administrator", uname) == 0)
-       euid = 0;
+      if (!is_windows_9x ())
+       {
+         /* We couldn't open the process token, presumably because of
+            insufficient access rights.  Assume this process is run
+            by the system.  */
+         strcpy (uname, "SYSTEM");
+         strcpy (gname, "None");
+         euid = 18;    /* SYSTEM */
+         egid = 513;   /* None */
+         glength = strlen (gname);
+         ulength = strlen (uname);
+       }
+      /* If we are running under Windows 9X, where security calls are
+        not supported, we assume all processes are run by the current
+        user.  */
+      else if (GetUserName (uname, &ulength))
+       {
+         if (xstrcasecmp ("administrator", uname) == 0)
+           euid = 0;
+         else
+           euid = 123;
+         egid = euid;
+         strcpy (gname, "None");
+         glength = strlen (gname);
+         ulength = strlen (uname);
+       }
       else
-       euid = 123;
-      egid = euid;
-      strcpy (gname, "None");
-      glength = strlen (gname);
-      ulength = strlen (uname);
-    }
-  else
-    {
-      euid = 123;
-      egid = 123;
-      strcpy (uname, "administrator");
-      ulength = strlen (uname);
-      strcpy (gname, "None");
-      glength = strlen (gname);
+       {
+         euid = 123;
+         egid = 123;
+         strcpy (uname, "administrator");
+         ulength = strlen (uname);
+         strcpy (gname, "None");
+         glength = strlen (gname);
+       }
+      if (token)
+       CloseHandle (token);
     }
-  if (token)
-    CloseHandle (token);
 
   attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
   tem = make_unibyte_string (uname, ulength);
@@ -3830,7 +4279,19 @@ w32_system_process_attributes (pid)
                 attrs);
 
   if (global_memory_status_ex (&memstex))
+#if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
     totphys = memstex.ullTotalPhys / 1024.0;
+#else
+  /* Visual Studio 6 cannot convert an unsigned __int64 type to
+     double, so we need to do this for it...  */
+    {
+      DWORD tot_hi = memstex.ullTotalPhys >> 32;
+      DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
+      DWORD tot_lo = memstex.ullTotalPhys % 1024;
+
+      totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
+    }
+#endif /* __GNUC__ || _MSC_VER >= 1300 */
   else if (global_memory_status (&memst))
     totphys = memst.dwTotalPhys / 1024.0;
 
@@ -3872,10 +4333,11 @@ w32_system_process_attributes (pid)
        attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
     }
 
-  if (process_times (h_proc, &ctime, &etime, &stime, &utime, &pcpu))
+  if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
     {
       attrs = Fcons (Fcons (Qutime, utime), attrs);
       attrs = Fcons (Fcons (Qstime, stime), attrs);
+      attrs = Fcons (Fcons (Qtime,  ttime), attrs);
       attrs = Fcons (Fcons (Qstart, ctime), attrs);
       attrs = Fcons (Fcons (Qetime, etime), attrs);
       attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
@@ -3986,34 +4448,34 @@ init_winsock (int load_now)
       if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
         goto fail;
 
-      LOAD_PROC( WSAStartup );
-      LOAD_PROC( WSASetLastError );
-      LOAD_PROC( WSAGetLastError );
-      LOAD_PROC( WSAEventSelect );
-      LOAD_PROC( WSACreateEvent );
-      LOAD_PROC( WSACloseEvent );
-      LOAD_PROC( socket );
-      LOAD_PROC( bind );
-      LOAD_PROC( connect );
-      LOAD_PROC( ioctlsocket );
-      LOAD_PROC( recv );
-      LOAD_PROC( send );
-      LOAD_PROC( closesocket );
-      LOAD_PROC( shutdown );
-      LOAD_PROC( htons );
-      LOAD_PROC( ntohs );
-      LOAD_PROC( inet_addr );
-      LOAD_PROC( gethostname );
-      LOAD_PROC( gethostbyname );
-      LOAD_PROC( getservbyname );
-      LOAD_PROC( getpeername );
-      LOAD_PROC( WSACleanup );
-      LOAD_PROC( setsockopt );
-      LOAD_PROC( listen );
-      LOAD_PROC( getsockname );
-      LOAD_PROC( accept );
-      LOAD_PROC( recvfrom );
-      LOAD_PROC( sendto );
+      LOAD_PROC (WSAStartup);
+      LOAD_PROC (WSASetLastError);
+      LOAD_PROC (WSAGetLastError);
+      LOAD_PROC (WSAEventSelect);
+      LOAD_PROC (WSACreateEvent);
+      LOAD_PROC (WSACloseEvent);
+      LOAD_PROC (socket);
+      LOAD_PROC (bind);
+      LOAD_PROC (connect);
+      LOAD_PROC (ioctlsocket);
+      LOAD_PROC (recv);
+      LOAD_PROC (send);
+      LOAD_PROC (closesocket);
+      LOAD_PROC (shutdown);
+      LOAD_PROC (htons);
+      LOAD_PROC (ntohs);
+      LOAD_PROC (inet_addr);
+      LOAD_PROC (gethostname);
+      LOAD_PROC (gethostbyname);
+      LOAD_PROC (getservbyname);
+      LOAD_PROC (getpeername);
+      LOAD_PROC (WSACleanup);
+      LOAD_PROC (setsockopt);
+      LOAD_PROC (listen);
+      LOAD_PROC (getsockname);
+      LOAD_PROC (accept);
+      LOAD_PROC (recvfrom);
+      LOAD_PROC (sendto);
 #undef LOAD_PROC
 
       /* specify version 1.1 of winsock */
@@ -4053,7 +4515,7 @@ int h_errno = 0;
    normal system codes where they overlap (non-overlapping definitions
    are already in <sys/socket.h> */
 static void
-set_errno ()
+set_errno (void)
 {
   if (winsock_lib == NULL)
     h_errno = EINVAL;
@@ -4075,7 +4537,7 @@ set_errno ()
 }
 
 static void
-check_errno ()
+check_errno (void)
 {
   if (h_errno == 0 && winsock_lib != NULL)
     pfn_WSASetLastError (0);
@@ -4158,7 +4620,7 @@ struct {
 };
 
 char *
-sys_strerror(int error_no)
+sys_strerror (int error_no)
 {
   int i;
   static char unknown_msg[40];
@@ -4170,7 +4632,7 @@ sys_strerror(int error_no)
     if (_wsa_errlist[i].errnum == error_no)
       return _wsa_errlist[i].msg;
 
-  sprintf(unknown_msg, "Unidentified error: %d", error_no);
+  sprintf (unknown_msg, "Unidentified error: %d", error_no);
   return unknown_msg;
 }
 
@@ -4189,7 +4651,7 @@ sys_strerror(int error_no)
 int socket_to_fd (SOCKET s);
 
 int
-sys_socket(int af, int type, int protocol)
+sys_socket (int af, int type, int protocol)
 {
   SOCKET s;
 
@@ -4392,7 +4854,7 @@ sys_gethostname (char * name, int namelen)
 }
 
 struct hostent *
-sys_gethostbyname(const char * name)
+sys_gethostbyname (const char * name)
 {
   struct hostent * host;
 
@@ -4410,7 +4872,7 @@ sys_gethostbyname(const char * name)
 }
 
 struct servent *
-sys_getservbyname(const char * name, const char * proto)
+sys_getservbyname (const char * name, const char * proto)
 {
   struct servent * serv;
 
@@ -4565,7 +5027,7 @@ sys_accept (int s, struct sockaddr * addr, int * addrlen)
 
 int
 sys_recvfrom (int s, char * buf, int len, int flags,
-         struct sockaddr * from, int * fromlen)
+             struct sockaddr * from, int * fromlen)
 {
   if (winsock_lib == NULL)
     {
@@ -5063,8 +5525,8 @@ sys_read (int fd, char * buffer, unsigned int count)
                  int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
                  if (res == SOCKET_ERROR)
                    {
-                     DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
-                               pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
+                     DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
+                                pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
                      set_errno ();
                      return -1;
                    }
@@ -5220,20 +5682,47 @@ sys_write (int fd, const void * buffer, unsigned int count)
 
       if (nchars == SOCKET_ERROR)
         {
-         DebPrint(("sys_write.send failed with error %d on socket %ld\n",
-                   pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
+         DebPrint (("sys_write.send failed with error %d on socket %ld\n",
+                    pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
          set_errno ();
        }
     }
   else
 #endif
-    nchars = _write (fd, buffer, count);
+    {
+      /* Some networked filesystems don't like too large writes, so
+        break them into smaller chunks.  See the Comments section of
+        the MSDN documentation of WriteFile for details behind the
+        choice of the value of CHUNK below.  See also the thread
+        http://thread.gmane.org/gmane.comp.version-control.git/145294
+        in the git mailing list.  */
+      const unsigned char *p = buffer;
+      const unsigned chunk = 30 * 1024 * 1024;
+
+      nchars = 0;
+      while (count > 0)
+       {
+         unsigned this_chunk = count < chunk ? count : chunk;
+         int n = _write (fd, p, this_chunk);
+
+         nchars += n;
+         if (n < 0)
+           {
+             nchars = n;
+             break;
+           }
+         else if (n < this_chunk)
+           break;
+         count -= n;
+         p += n;
+       }
+    }
 
   return nchars;
 }
 
 static void
-check_windows_init_file ()
+check_windows_init_file (void)
 {
   extern int noninteractive, inhibit_window_system;
 
@@ -5289,7 +5778,7 @@ check_windows_init_file ()
 }
 
 void
-term_ntproc ()
+term_ntproc (void)
 {
 #ifdef HAVE_SOCKETS
   /* shutdown the socket interface if necessary */
@@ -5300,7 +5789,7 @@ term_ntproc ()
 }
 
 void
-init_ntproc ()
+init_ntproc (void)
 {
 #ifdef HAVE_SOCKETS
   /* Initialise the socket interface now if available and requested by
@@ -5408,7 +5897,8 @@ init_ntproc ()
         shutdown_handler ensures that buffers' autosave files are
        up to date when the user logs off, or the system shuts down.
 */
-BOOL WINAPI shutdown_handler(DWORD type)
+BOOL WINAPI
+shutdown_handler (DWORD type)
 {
   /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them.  */
   if (type == CTRL_CLOSE_EVENT        /* User closes console window.  */
@@ -5429,7 +5919,7 @@ BOOL WINAPI shutdown_handler(DWORD type)
        initialized is non zero (see the function main in emacs.c).
 */
 void
-globals_of_w32 ()
+globals_of_w32 (void)
 {
   HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
 
@@ -5457,18 +5947,25 @@ globals_of_w32 ()
   g_b_init_get_process_working_set_size = 0;
   g_b_init_global_memory_status = 0;
   g_b_init_global_memory_status_ex = 0;
+  g_b_init_equal_sid = 0;
+  g_b_init_copy_sid = 0;
+  g_b_init_get_length_sid = 0;
+  g_b_init_get_native_system_info = 0;
+  g_b_init_get_system_times = 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
      GUI modes, since we had to fool windows into thinking emacs is a
      console application to get console mode to work.  */
-  SetConsoleCtrlHandler(shutdown_handler, TRUE);
+  SetConsoleCtrlHandler (shutdown_handler, TRUE);
 
   /* "None" is the default group name on standalone workstations.  */
   strcpy (dflt_group_name, "None");
 }
 
 /* For make-serial-process  */
-int serial_open (char *port)
+int
+serial_open (char *port)
 {
   HANDLE hnd;
   child_process *cp;
@@ -5508,7 +6005,7 @@ int serial_open (char *port)
 /* For serial-process-configure  */
 void
 serial_configure (struct Lisp_Process *p,
-                     Lisp_Object contact)
+                 Lisp_Object contact)
 {
   Lisp_Object childp2 = Qnil;
   Lisp_Object tem = Qnil;