]> code.delx.au - gnu-emacs/blobdiff - src/w32.c
(init_environment): Remove EMACSLOCKDIR.
[gnu-emacs] / src / w32.c
index a7fd59366d647b749d6b281324f75e8bdb78b0d9..b789bb47e5273682126386249becbf441456132d 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -1,5 +1,5 @@
 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
-   Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1994, 1995, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -35,7 +35,11 @@ Boston, MA 02111-1307, USA.
 #include <sys/utime.h>
 
 /* must include CRT headers *before* config.h */
-#include "config.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #undef access
 #undef chdir
 #undef chmod
@@ -63,6 +67,10 @@ Boston, MA 02111-1307, USA.
 
 #include <pwd.h>
 
+#ifdef __GNUC__
+#define _ANONYMOUS_UNION
+#define _ANONYMOUS_STRUCT
+#endif
 #include <windows.h>
 
 #ifdef HAVE_SOCKETS    /* TCP connection support, if kernel can do it */
@@ -76,23 +84,45 @@ Boston, MA 02111-1307, USA.
 #undef gethostname
 #undef gethostbyname
 #undef getservbyname
+#undef getpeername
 #undef shutdown
+#undef setsockopt
+#undef listen
+#undef getsockname
+#undef accept
+#undef recvfrom
+#undef sendto
 #endif
 
 #include "w32.h"
 #include "ndir.h"
 #include "w32heap.h"
-#undef min
-#undef max
-#define min(x, y) (((x) < (y)) ? (x) : (y))
-#define max(x, y) (((x) > (y)) ? (x) : (y))
+#include "systime.h"
 
 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;
 
+\f
+/* Equivalent of strerror for W32 error codes.  */
+char *
+w32_strerror (int error_no)
+{
+  static char buf[500];
+
+  if (error_no == 0)
+    error_no = GetLastError ();
+
+  buf[0] = '\0';
+  if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
+                     error_no,
+                     0, /* choose most suitable language */
+                     buf, sizeof (buf), NULL))
+    sprintf (buf, "w32 error %u", error_no);
+  return buf;
+}
+
 static char startup_dir[MAXPATHLEN];
 
 /* Get the current working directory.  */
@@ -289,9 +319,9 @@ init_user_info ()
 
   /* Ensure HOME and SHELL are defined. */
   if (getenv ("HOME") == NULL)
-    putenv ("HOME=c:/");
+    abort ();
   if (getenv ("SHELL") == NULL)
-    putenv (os_subtype == OS_WIN95 ? "SHELL=command" : "SHELL=cmd");
+    abort ();
 
   /* Set dir and shell from environment variables. */
   strcpy (the_passwd.pw_dir, getenv ("HOME"));
@@ -656,7 +686,6 @@ extern Lisp_Object Vsystem_configuration;
 void
 init_environment (char ** argv)
 {
-  int len;
   static const char * const tempdirs[] = {
     "$TMPDIR", "$TEMP", "$TMP", "c:/"
   };
@@ -677,11 +706,11 @@ init_environment (char ** argv)
         read-only filesystem, like CD-ROM or a write-protected floppy.
         The only way to be really sure is to actually create a file and
         see if it succeeds.  But I think that's too much to ask.  */
-      if (tmp && access (tmp, D_OK) == 0)
+      if (tmp && _access (tmp, D_OK) == 0)
        {
          char * var = alloca (strlen (tmp) + 8);
          sprintf (var, "TMPDIR=%s", tmp);
-         putenv (var);
+         _putenv (strdup (var));
          break;
        }
     }
@@ -692,52 +721,112 @@ init_environment (char ** argv)
                     Qnil)),
        "While setting TMPDIR: ");
 
-  /* Check for environment variables and use registry if they don't exist */
+  /* Check for environment variables and use registry settings if they
+     don't exist.  Fallback on default values where applicable.  */
   {
     int i;
     LPBYTE lpval;
     DWORD dwType;
+    char locale_name[32];
 
-    static char * env_vars[] = 
-    {
-      "HOME",
-      "PRELOAD_WINSOCK",
-      "emacs_dir",
-      "EMACSLOADPATH",
-      "SHELL",
-      "CMDPROXY",
-      "EMACSDATA",
-      "EMACSPATH",
-      "EMACSLOCKDIR",
+    static struct env_entry
+    {
+      char * name;
+      char * def_value;
+    } env_vars[] = 
+    {
+      {"HOME", "C:/"},
+      {"PRELOAD_WINSOCK", NULL},
+      {"emacs_dir", "C:/emacs"},
+      {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
+      {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
+      {"EMACSDATA", "%emacs_dir%/etc"},
+      {"EMACSPATH", "%emacs_dir%/bin"},
       /* We no longer set INFOPATH because Info-default-directory-list
-        is then ignored.  We use a hook in winnt.el instead.  */
-      /*      "INFOPATH", */
-      "EMACSDOC",
-      "TERM",
+        is then ignored.  */
+      /*  {"INFOPATH", "%emacs_dir%/info"},  */
+      {"EMACSDOC", "%emacs_dir%/etc"},
+      {"TERM", "cmd"},
+      {"LANG", NULL},
     };
 
-    for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++) 
+  /* Get default locale info and use it for LANG.  */
+  if (GetLocaleInfo (LOCALE_USER_DEFAULT,
+                     LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
+                     locale_name, sizeof (locale_name)))
+    {
+      for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
+        {
+          if (strcmp (env_vars[i].name, "LANG") == 0)
+            {
+              env_vars[i].def_value = locale_name;
+              break;
+            }
+        }
+    }
+
+#define SET_ENV_BUF_SIZE (4 * MAX_PATH)        /* to cover EMACSLOADPATH */
+
+    /* Treat emacs_dir specially: set it unconditionally based on our
+       location, if it appears that we are running from the bin subdir
+       of a standard installation.  */
+    {
+      char *p;
+      char modname[MAX_PATH];
+
+      if (!GetModuleFileName (NULL, modname, MAX_PATH))
+       abort ();
+      if ((p = strrchr (modname, '\\')) == NULL)
+       abort ();
+      *p = 0;
+
+      if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 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++)
       {
-       if (!getenv (env_vars[i])
-           && (lpval = w32_get_resource (env_vars[i], &dwType)) != NULL)
+       if (!getenv (env_vars[i].name))
          {
-           if (dwType == REG_EXPAND_SZ)
-             {
-               char buf1[500], buf2[500];
+           int dont_free = 0;
 
-               ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
-               _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
-               putenv (strdup (buf2));
+           if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL)
+             {
+               lpval = env_vars[i].def_value;
+               dwType = REG_EXPAND_SZ;
+               dont_free = 1;
              }
-           else if (dwType == REG_SZ)
+
+           if (lpval)
              {
-               char buf[500];
+               if (dwType == REG_EXPAND_SZ)
+                 {
+                   char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
+
+                   ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
+                   _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name, buf1);
+                   _putenv (strdup (buf2));
+                 }
+               else if (dwType == REG_SZ)
+                 {
+                   char buf[SET_ENV_BUF_SIZE];
                  
-               _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
-               putenv (strdup (buf));
-             }
+                   _snprintf (buf, sizeof(buf)-1, "%s=%s", env_vars[i].name, lpval);
+                   _putenv (strdup (buf));
+                 }
 
-           xfree (lpval);
+               if (!dont_free)
+                 xfree (lpval);
+             }
          }
       }
   }
@@ -796,18 +885,32 @@ init_environment (char ** argv)
   init_user_info ();
 }
 
+char *
+emacs_root_dir (void)
+{
+  static char root_dir[FILENAME_MAX];
+  const char *p;
+
+  p = getenv ("emacs_dir");
+  if (p == NULL)
+    abort ();
+  strcpy (root_dir, p);
+  root_dir[parse_root (root_dir, NULL)] = '\0';
+  dostounix_filename (root_dir);
+  return root_dir;
+}
+
 /* We don't have scripts to automatically determine the system configuration
    for Emacs before it's compiled, and we don't want to have to make the
    user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
    routine.  */
 
-static char configuration_buffer[32];
-
 char *
 get_emacs_configuration (void)
 {
   char *arch, *oem, *os;
   int build_num;
+  static char configuration_buffer[32];
 
   /* Determine the processor type.  */
   switch (get_processor_type ()) 
@@ -846,8 +949,17 @@ get_emacs_configuration (void)
       break;
     }
 
-  /* Let oem be "*" until we figure out how to decode the OEM field.  */
-  oem = "*";
+  /* Use the OEM field to reflect the compiler/library combination.  */
+#ifdef _MSC_VER
+#define COMPILER_NAME  "msvc"
+#else
+#ifdef __GNUC__
+#define COMPILER_NAME  "mingw"
+#else
+#define COMPILER_NAME  "unknown"
+#endif
+#endif
+  oem = COMPILER_NAME;
 
   switch (osinfo_cache.dwPlatformId) {
   case VER_PLATFORM_WIN32_NT:
@@ -883,13 +995,45 @@ get_emacs_configuration (void)
   return configuration_buffer;
 }
 
+char *
+get_emacs_configuration_options (void)
+{
+  static char options_buffer[256];
+
+/* Work out the effective configure options for this build.  */
+#ifdef _MSC_VER
+#define COMPILER_VERSION       "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
+#else
+#ifdef __GNUC__
+#define COMPILER_VERSION       "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
+#else
+#define COMPILER_VERSION       ""
+#endif
+#endif
+
+  sprintf (options_buffer, COMPILER_VERSION);
+#ifdef EMACSDEBUG
+  strcat (options_buffer, " --no-opt");
+#endif
+#ifdef USER_CFLAGS
+  strcat (options_buffer, " --cflags");
+  strcat (options_buffer, USER_CFLAGS);
+#endif
+#ifdef USER_LDFLAGS
+  strcat (options_buffer, " --ldflags");
+  strcat (options_buffer, USER_LDFLAGS);
+#endif
+  return options_buffer;
+}
+
+
 #include <sys/timeb.h>
 
 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95).  */
 void 
 gettimeofday (struct timeval *tv, struct timezone *tz)
 {
-  struct _timeb tb;
+  struct timeb tb;
   _ftime (&tb);
 
   tv->tv_sec = tb.time;
@@ -980,7 +1124,7 @@ lookup_volume_info (char * root_dir)
 static void
 add_volume_info (char * root_dir, volume_info_data * info)
 {
-  info->root_dir = strdup (root_dir);
+  info->root_dir = xstrdup (root_dir);
   info->next = volume_cache;
   volume_cache = info;
 }
@@ -1063,15 +1207,15 @@ GetCachedVolumeInformation (char * root_dir)
       }
     else
       {
-       free (info->name);
-       free (info->type);
+       xfree (info->name);
+       xfree (info->type);
       }
 
-    info->name = strdup (name);
+    info->name = xstrdup (name);
     info->serialnum = serialnum;
     info->maxcomp = maxcomp;
     info->flags = flags;
-    info->type = strdup (type);
+    info->type = xstrdup (type);
     info->timestamp = GetTickCount ();
   }
 
@@ -1149,7 +1293,14 @@ map_w32_filename (const char * name, const char ** pPath)
   char * path;
   const char * save_name = name;
 
-  if (is_fat_volume (name, &path)) /* truncate to 8.3 */
+  if (strlen (name) >= MAX_PATH)
+    {
+      /* Return a filename which will cause callers to fail.  */
+      strcpy (shortname, "?");
+      return shortname;
+    }
+
+  if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
     {
       register int left = 8;   /* maximum number of chars in part */
       register int extn = 0;   /* extension added? */
@@ -1402,9 +1553,9 @@ open_unc_volume (char *path)
 char *
 read_unc_volume (HANDLE henum, char *readbuf, int size)
 {
-  int count;
+  DWORD count;
   int result;
-  int bufsize = 512;
+  DWORD bufsize = 512;
   char *buffer;
   char *ptr;
 
@@ -1688,14 +1839,20 @@ sys_mktemp (char * template)
 int
 sys_open (const char * path, int oflag, int mode)
 {
-  /* Force all file handles to be non-inheritable. */
-  return _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 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)
+    return res;
+  return _open (mpath, oflag | _O_NOINHERIT, mode);
 }
 
 int
 sys_rename (const char * oldname, const char * newname)
 {
-  int result;
+  BOOL result;
   char temp[MAX_PATH];
 
   /* MoveFile on Windows 95 doesn't correctly change the short file name
@@ -1739,7 +1896,7 @@ sys_rename (const char * oldname, const char * newname)
          result = rename (oldname, temp);
        }
       /* This loop must surely terminate!  */
-      while (result < 0 && (errno == EEXIST || errno == EACCES));
+      while (result < 0 && errno == EEXIST);
       if (result < 0)
        return -1;
     }
@@ -1759,7 +1916,7 @@ sys_rename (const char * oldname, const char * newname)
   result = rename (temp, newname);
 
   if (result < 0
-      && (errno == EEXIST || errno == EACCES)
+      && errno == EEXIST
       && _chmod (newname, 0666) == 0
       && _unlink (newname) == 0)
     result = rename (temp, newname);
@@ -1996,16 +2153,11 @@ stat (const char * path, struct stat * buf)
        }
     }
 
-  if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-    {
-      buf->st_mode = _S_IFDIR;
-      buf->st_nlink = 2;       /* doesn't really matter */
-      fake_inode = 0;          /* this doesn't either I think */
-    }
-  else if (!NILP (Vw32_get_true_file_attributes)
-          /* No access rights required to get info.  */
-          && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 0, NULL))
-             != INVALID_HANDLE_VALUE)
+  if (!NILP (Vw32_get_true_file_attributes)
+      /* No access rights required to get info.  */
+      && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
+                          FILE_FLAG_BACKUP_SEMANTICS, NULL))
+         != INVALID_HANDLE_VALUE)
     {
       /* This is more accurate in terms of gettting the correct number
         of links, but is quite slow (it is noticable when Emacs is
@@ -2028,25 +2180,33 @@ stat (const char * path, struct stat * buf)
          fake_inode = 0;
        }
 
-      switch (GetFileType (fh))
+      if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
-       case FILE_TYPE_DISK:
-         buf->st_mode = _S_IFREG;
-         break;
-       case FILE_TYPE_PIPE:
-         buf->st_mode = _S_IFIFO;
-         break;
-       case FILE_TYPE_CHAR:
-       case FILE_TYPE_UNKNOWN:
-       default:
-         buf->st_mode = _S_IFCHR;
+         buf->st_mode = _S_IFDIR;
+       }
+      else
+       {
+         switch (GetFileType (fh))
+           {
+           case FILE_TYPE_DISK:
+             buf->st_mode = _S_IFREG;
+             break;
+           case FILE_TYPE_PIPE:
+             buf->st_mode = _S_IFIFO;
+             break;
+           case FILE_TYPE_CHAR:
+           case FILE_TYPE_UNKNOWN:
+           default:
+             buf->st_mode = _S_IFCHR;
+           }
        }
       CloseHandle (fh);
     }
   else
     {
       /* Don't bother to make this information more accurate.  */
-      buf->st_mode = _S_IFREG;
+      buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
+       _S_IFDIR : _S_IFREG;
       buf->st_nlink = 1;
       fake_inode = 0;
     }
@@ -2139,21 +2299,15 @@ fstat (int desc, struct stat * buf)
     }
 
   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-    {
       buf->st_mode = _S_IFDIR;
-      buf->st_nlink = 2;       /* doesn't really matter */
-      fake_inode = 0;          /* this doesn't either I think */
-    }
-  else
-    {
-      buf->st_nlink = info.nNumberOfLinks;
-      /* Might as well use file index to fake inode values, but this
-        is not guaranteed to be unique unless we keep a handle open
-        all the time (even then there are situations where it is
-        not unique).  Reputedly, there are at most 48 bits of info
-      (on NTFS, presumably less on FAT). */
-      fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
-    }
+
+  buf->st_nlink = info.nNumberOfLinks;
+  /* Might as well use file index to fake inode values, but this
+     is not guaranteed to be unique unless we keep a handle open
+     all the time (even then there are situations where it is
+     not unique).  Reputedly, there are at most 48 bits of info
+     (on NTFS, presumably less on FAT). */
+  fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
 
   /* MSVC defines _ino_t to be short; other libc's might not.  */
   if (sizeof (buf->st_ino) == 2)
@@ -2270,7 +2424,18 @@ unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
 int (PASCAL *pfn_gethostname) (char * name, int namelen);
 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
-  
+int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
+int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
+                             const char * optval, int optlen);
+int (PASCAL *pfn_listen) (SOCKET s, int backlog);
+int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
+                              int * namelen);
+SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
+int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
+                      struct sockaddr * from, int * fromlen);
+int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
+                         const struct sockaddr * to, int tolen);
+
 /* SetHandleInformation is only needed to make sockets non-inheritable. */
 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
 #ifndef HANDLE_FLAG_INHERIT
@@ -2339,8 +2504,14 @@ init_winsock (int load_now)
       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 */
@@ -2488,8 +2659,8 @@ sys_strerror(int error_no)
   int i;
   static char unknown_msg[40];
 
-  if (error_no >= 0 && error_no < _sys_nerr)
-    return _sys_errlist[error_no];
+  if (error_no >= 0 && error_no < sys_nerr)
+    return sys_errlist[error_no];
 
   for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
     if (_wsa_errlist[i].errnum == error_no)
@@ -2511,12 +2682,12 @@ sys_strerror(int error_no)
 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
 #endif
 
+int socket_to_fd (SOCKET s);
+
 int
 sys_socket(int af, int type, int protocol)
 {
-  int fd;
-  long s;
-  child_process * cp;
+  SOCKET s;
 
   if (winsock_lib == NULL)
     {
@@ -2527,89 +2698,114 @@ sys_socket(int af, int type, int protocol)
   check_errno ();
 
   /* call the real socket function */
-  s = (long) pfn_socket (af, type, protocol);
+  s = pfn_socket (af, type, protocol);
   
   if (s != INVALID_SOCKET)
-    {
-      /* Although under NT 3.5 _open_osfhandle will accept a socket
-        handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
-        that does not work under NT 3.1.  However, we can get the same
-        effect by using a backdoor function to replace an existing
-        descriptor handle with the one we want. */
+    return socket_to_fd (s);
 
-      /* allocate a file descriptor (with appropriate flags) */
-      fd = _open ("NUL:", _O_RDWR);
-      if (fd >= 0)
-        {
+  set_errno ();
+  return -1;
+}
+
+/* Convert a SOCKET to a file descriptor.  */
+int
+socket_to_fd (SOCKET s)
+{
+  int fd;
+  child_process * cp;
+
+  /* Although under NT 3.5 _open_osfhandle will accept a socket
+     handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
+     that does not work under NT 3.1.  However, we can get the same
+     effect by using a backdoor function to replace an existing
+     descriptor handle with the one we want. */
+
+  /* allocate a file descriptor (with appropriate flags) */
+  fd = _open ("NUL:", _O_RDWR);
+  if (fd >= 0)
+    {
 #ifdef SOCK_REPLACE_HANDLE
-         /* now replace handle to NUL with our socket handle */
-         CloseHandle ((HANDLE) _get_osfhandle (fd));
-         _free_osfhnd (fd);
-         _set_osfhnd (fd, s);
-         /* setmode (fd, _O_BINARY); */
+      /* now replace handle to NUL with our socket handle */
+      CloseHandle ((HANDLE) _get_osfhandle (fd));
+      _free_osfhnd (fd);
+      _set_osfhnd (fd, s);
+      /* setmode (fd, _O_BINARY); */
 #else
-         /* Make a non-inheritable copy of the socket handle. */
+      /* Make a non-inheritable copy of the socket handle.  Note
+        that it is possible that sockets aren't actually kernel
+        handles, which appears to be the case on Windows 9x when
+        the MS Proxy winsock client is installed.  */
+      {
+       /* Apparently there is a bug in NT 3.51 with some service
+          packs, which prevents using DuplicateHandle to make a
+          socket handle non-inheritable (causes WSACleanup to
+          hang).  The work-around is to use SetHandleInformation
+          instead if it is available and implemented. */
+       if (pfn_SetHandleInformation)
          {
-           HANDLE parent;
+           pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
+         }
+       else
+         {
+           HANDLE parent = GetCurrentProcess ();
            HANDLE new_s = INVALID_HANDLE_VALUE;
 
-           parent = GetCurrentProcess ();
-
-           /* Apparently there is a bug in NT 3.51 with some service
-              packs, which prevents using DuplicateHandle to make a
-              socket handle non-inheritable (causes WSACleanup to
-              hang).  The work-around is to use SetHandleInformation
-              instead if it is available and implemented. */
-           if (!pfn_SetHandleInformation
-               || !pfn_SetHandleInformation ((HANDLE) s,
-                                             HANDLE_FLAG_INHERIT,
-                                             0))
-             {
-               DuplicateHandle (parent,
+           if (DuplicateHandle (parent,
                                 (HANDLE) s,
                                 parent,
                                 &new_s,
                                 0,
                                 FALSE,
-                                DUPLICATE_SAME_ACCESS);
-               pfn_closesocket (s);
-               s = (SOCKET) new_s;
-             }
-           fd_info[fd].hnd = (HANDLE) s;
+                                DUPLICATE_SAME_ACCESS))
+             {
+               /* It is possible that DuplicateHandle succeeds even
+                  though the socket wasn't really a kernel handle,
+                  because a real handle has the same value.  So
+                  test whether the new handle really is a socket.  */
+               long nonblocking = 0;
+               if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
+                 {
+                   pfn_closesocket (s);
+                   s = (SOCKET) new_s;
+                 }
+               else
+                 {
+                   CloseHandle (new_s);
+                 }
+             } 
          }
+      }
+      fd_info[fd].hnd = (HANDLE) s;
 #endif
 
-         /* set our own internal flags */
-         fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
-
-         cp = new_child ();
-         if (cp)
-           {
-             cp->fd = fd;
-             cp->status = STATUS_READ_ACKNOWLEDGED;
+      /* set our own internal flags */
+      fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
 
-             /* attach child_process to fd_info */
-             if (fd_info[ fd ].cp != NULL)
-               {
-                 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
-                 abort ();
-               }
-
-             fd_info[ fd ].cp = cp;
+      cp = new_child ();
+      if (cp)
+       {
+         cp->fd = fd;
+         cp->status = STATUS_READ_ACKNOWLEDGED;
 
-             /* success! */
-             winsock_inuse++;  /* count open sockets */
-             return fd;
+         /* attach child_process to fd_info */
+         if (fd_info[ fd ].cp != NULL)
+           {
+             DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
+             abort ();
            }
 
-         /* clean up */
-         _close (fd);
+         fd_info[ fd ].cp = cp;
+
+         /* success! */
+         winsock_inuse++;      /* count open sockets */
+         return fd;
        }
-      pfn_closesocket (s);
-      h_errno = EMFILE;
-    }
-  set_errno ();
 
+      /* clean up */
+      _close (fd);
+    }
+  pfn_closesocket (s);
+  h_errno = EMFILE;
   return -1;
 }
 
@@ -2685,7 +2881,7 @@ sys_gethostname (char * name, int namelen)
     return pfn_gethostname (name, namelen);
 
   if (namelen > MAX_COMPUTERNAME_LENGTH)
-    return !GetComputerName (name, &namelen);
+    return !GetComputerName (name, (DWORD *)&namelen);
 
   h_errno = EFAULT;
   return SOCKET_ERROR;
@@ -2728,10 +2924,30 @@ sys_getservbyname(const char * name, const char * proto)
 }
 
 int
-sys_shutdown (int s, int how)
+sys_getpeername (int s, struct sockaddr *addr, int * namelen)
 {
-  int rc;
+  if (winsock_lib == NULL)
+    {
+      h_errno = ENETDOWN;
+      return SOCKET_ERROR;
+    }
+
+  check_errno ();
+  if (fd_info[s].flags & FILE_SOCKET)
+    {
+      int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
+      if (rc == SOCKET_ERROR)
+       set_errno ();
+      return rc;
+    }
+  h_errno = ENOTSOCK;
+  return SOCKET_ERROR;
+}
+
 
+int
+sys_shutdown (int s, int how)
+{
   if (winsock_lib == NULL)
     {
       h_errno = ENETDOWN;
@@ -2750,6 +2966,171 @@ sys_shutdown (int s, int how)
   return SOCKET_ERROR;
 }
 
+int
+sys_setsockopt (int s, int level, int optname, const char * optval, int optlen)
+{
+  if (winsock_lib == NULL)
+    {
+      h_errno = ENETDOWN;
+      return SOCKET_ERROR;
+    }
+
+  check_errno ();
+  if (fd_info[s].flags & FILE_SOCKET)
+    {
+      int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
+                              optval, optlen);
+      if (rc == SOCKET_ERROR)
+       set_errno ();
+      return rc;
+    }
+  h_errno = ENOTSOCK;
+  return SOCKET_ERROR;      
+}
+
+int
+sys_listen (int s, int backlog)
+{
+  if (winsock_lib == NULL)
+    {
+      h_errno = ENETDOWN;
+      return SOCKET_ERROR;
+    }
+
+  check_errno ();
+  if (fd_info[s].flags & FILE_SOCKET)
+    {
+      int rc = pfn_listen (SOCK_HANDLE (s), backlog);
+      if (rc == SOCKET_ERROR)
+       set_errno ();
+      return rc;
+    }
+  h_errno = ENOTSOCK;
+  return SOCKET_ERROR;      
+}
+
+int
+sys_getsockname (int s, struct sockaddr * name, int * namelen)
+{
+  if (winsock_lib == NULL)
+    {
+      h_errno = ENETDOWN;
+      return SOCKET_ERROR;
+    }
+
+  check_errno ();
+  if (fd_info[s].flags & FILE_SOCKET)
+    {
+      int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
+      if (rc == SOCKET_ERROR)
+       set_errno ();
+      return rc;
+    }
+  h_errno = ENOTSOCK;
+  return SOCKET_ERROR;      
+}
+
+int
+sys_accept (int s, struct sockaddr * addr, int * addrlen)
+{
+  if (winsock_lib == NULL)
+    {
+      h_errno = ENETDOWN;
+      return -1;
+    }
+
+  check_errno ();
+  if (fd_info[s].flags & FILE_SOCKET)
+    {
+      SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
+      if (t != INVALID_SOCKET)
+       return socket_to_fd (t);
+
+      set_errno ();
+      return -1;
+    }
+  h_errno = ENOTSOCK;
+  return -1;
+}
+
+int
+sys_recvfrom (int s, char * buf, int len, int flags,
+         struct sockaddr * from, int * fromlen)
+{
+  if (winsock_lib == NULL)
+    {
+      h_errno = ENETDOWN;
+      return SOCKET_ERROR;
+    }
+
+  check_errno ();
+  if (fd_info[s].flags & FILE_SOCKET)
+    {
+      int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
+      if (rc == SOCKET_ERROR)
+       set_errno ();
+      return rc;
+    }
+  h_errno = ENOTSOCK;
+  return SOCKET_ERROR;
+}
+
+int
+sys_sendto (int s, const char * buf, int len, int flags,
+           const struct sockaddr * to, int tolen)
+{
+  if (winsock_lib == NULL)
+    {
+      h_errno = ENETDOWN;
+      return SOCKET_ERROR;
+    }
+
+  check_errno ();
+  if (fd_info[s].flags & FILE_SOCKET)
+    {
+      int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
+      if (rc == SOCKET_ERROR)
+       set_errno ();
+      return rc;
+    }
+  h_errno = ENOTSOCK;
+  return SOCKET_ERROR;
+}
+
+/* Windows does not have an fcntl function.  Provide an implementation
+   solely for making sockets non-blocking.  */
+int
+fcntl (int s, int cmd, int options)
+{
+  if (winsock_lib == NULL)
+    {
+      h_errno = ENETDOWN;
+      return -1;
+    }
+
+  check_errno ();
+  if (fd_info[s].flags & FILE_SOCKET)
+    {
+      if (cmd == F_SETFL && options == O_NDELAY)
+       {
+         unsigned long nblock = 1;
+         int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
+         if (rc == SOCKET_ERROR)
+           set_errno();
+         /* Keep track of the fact that we set this to non-blocking.  */
+         fd_info[s].flags |= FILE_NDELAY;
+         return rc;
+       }
+      else
+       {
+         h_errno = EINVAL;
+         return SOCKET_ERROR;
+       }
+    }
+  h_errno = ENOTSOCK;
+  return SOCKET_ERROR;
+}
+
 #endif /* HAVE_SOCKETS */
 
 
@@ -2860,7 +3241,6 @@ sys_pipe (int * phandles)
 {
   int rc;
   unsigned flags;
-  child_process * cp;
 
   /* make pipe handles non-inheritable; when we spawn a child, we
      replace the relevant handle with an inheritable one.  Also put
@@ -2934,7 +3314,20 @@ _sys_read_ahead (int fd)
     }
 #ifdef HAVE_SOCKETS
   else if (fd_info[fd].flags & FILE_SOCKET)
-    rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
+    {
+      unsigned long nblock = 0;
+      /* We always want this to block, so temporarily disable NDELAY.  */
+      if (fd_info[fd].flags & FILE_NDELAY)
+       pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
+
+      rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
+
+      if (fd_info[fd].flags & FILE_NDELAY)
+       {
+         nblock = 1;
+         pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
+       }
+    }
 #endif
   
   if (rc == sizeof (char))
@@ -3184,7 +3577,7 @@ 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, ".el:.elc", NULL, 0);
+      fd = openp (full_load_path, init_file, Vload_suffixes, NULL, Qnil);
       if (fd < 0) 
        {
          Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
@@ -3212,7 +3605,7 @@ check_windows_init_file ()
        }
       else
        {
-         close (fd);
+         _close (fd);
        }
     }
 }
@@ -3322,6 +3715,9 @@ init_ntproc ()
 
       (*drive)++;
     }
+
+    /* Reset the volume info cache.  */
+    volume_cache = NULL;
   }
   
   /* Check to see if Emacs has been installed correctly.  */