GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
} MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
/* These are here so that GDB would know about these data types. This
- allows to attach GDB to Emacs when a fatal exception is triggered
+ allows attaching GDB to Emacs when a fatal exception is triggered
and Windows pops up the "application needs to be closed" dialog.
At that point, _gnu_exception_handler, the top-level exception
handler installed by the MinGW startup code, is somewhere on the
#include <iphlpapi.h> /* should be after winsock2.h */
+#include <wincrypt.h>
+
#include <c-strcase.h>
#include "w32.h"
int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
+DWORD multiByteToWideCharFlags;
/* ** A utility function ** */
static BOOL
int
filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
{
- int result = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
- fn_out, MAX_PATH);
+ int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
+ -1, fn_out, MAX_PATH);
if (!result)
{
{
wchar_t fn_utf16[MAX_PATH];
int codepage = codepage_for_filenames (NULL);
- int result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
- fn_utf16, MAX_PATH);
+ int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
+ -1, fn_utf16, MAX_PATH);
if (!result)
{
CloseHandle (token);
}
+static HCRYPTPROV w32_crypto_hprov;
+static int
+w32_init_crypt_random (void)
+{
+ if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+ {
+ DebPrint (("CryptAcquireContext failed with error %x\n",
+ GetLastError ()));
+ w32_crypto_hprov = 0;
+ return -1;
+ }
+ return 0;
+}
+
+int
+w32_init_random (void *buf, ptrdiff_t buflen)
+{
+ if (!w32_crypto_hprov)
+ w32_init_crypt_random ();
+ if (w32_crypto_hprov)
+ {
+ if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
+ return 0;
+ }
+ return -1;
+}
+
int
random (void)
{
int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
const struct sockaddr * to, int tolen);
+int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
+ const struct addrinfo *, struct addrinfo **);
+void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
+
/* SetHandleInformation is only needed to make sockets non-inheritable. */
BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
#ifndef HANDLE_FLAG_INHERIT
LOAD_PROC (sendto);
#undef LOAD_PROC
+ /* Try loading functions not available before XP. */
+ pfn_getaddrinfo = (void *) GetProcAddress (winsock_lib, "getaddrinfo");
+ pfn_freeaddrinfo = (void *) GetProcAddress (winsock_lib, "freeaddrinfo");
+ /* Paranoia: these two functions should go together, so if one
+ is absent, we cannot use the other. */
+ if (pfn_getaddrinfo == NULL)
+ pfn_freeaddrinfo = NULL;
+ else if (pfn_freeaddrinfo == NULL)
+ pfn_getaddrinfo = NULL;
+
/* specify version 1.1 of winsock */
if (pfn_WSAStartup (0x101, &winsockData) == 0)
{
return SOCKET_ERROR;
}
+int
+sys_getaddrinfo (const char *node, const char *service,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ int rc;
+
+ if (winsock_lib == NULL)
+ {
+ errno = ENETDOWN;
+ return SOCKET_ERROR;
+ }
+
+ check_errno ();
+ if (pfn_getaddrinfo)
+ rc = pfn_getaddrinfo (node, service, hints, res);
+ else
+ {
+ int port = 0;
+ struct hostent *host_info;
+ struct gai_storage {
+ struct addrinfo addrinfo;
+ struct sockaddr_in sockaddr_in;
+ } *gai_storage;
+
+ /* We don't (yet) support any flags, as Emacs doesn't need that. */
+ if (hints && hints->ai_flags != 0)
+ return WSAEINVAL;
+ /* NODE cannot be NULL, since process.c has fallbacks for that. */
+ if (!node)
+ return WSAHOST_NOT_FOUND;
+
+ if (service)
+ {
+ const char *protocol =
+ (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
+ struct servent *srv = sys_getservbyname (service, protocol);
+
+ if (srv)
+ port = srv->s_port;
+ else if (*service >= '0' && *service <= '9')
+ {
+ char *endp;
+
+ port = strtoul (service, &endp, 10);
+ if (*endp || port > 65536)
+ return WSAHOST_NOT_FOUND;
+ port = sys_htons ((unsigned short) port);
+ }
+ else
+ return WSAHOST_NOT_FOUND;
+ }
+
+ gai_storage = xzalloc (sizeof *gai_storage);
+ gai_storage->sockaddr_in.sin_port = port;
+ host_info = sys_gethostbyname (node);
+ if (host_info)
+ {
+ memcpy (&gai_storage->sockaddr_in.sin_addr,
+ host_info->h_addr, host_info->h_length);
+ gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
+ }
+ else
+ {
+ /* Attempt to interpret host as numeric inet address. */
+ unsigned long numeric_addr = sys_inet_addr (node);
+
+ if (numeric_addr == -1)
+ {
+ free (gai_storage);
+ return WSAHOST_NOT_FOUND;
+ }
+
+ memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
+ sizeof (gai_storage->sockaddr_in.sin_addr));
+ gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
+ }
+
+ gai_storage->addrinfo.ai_addr =
+ (struct sockaddr *)&gai_storage->sockaddr_in;
+ gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
+ gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
+ gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
+ gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
+ gai_storage->addrinfo.ai_next = NULL;
+
+ *res = &gai_storage->addrinfo;
+ rc = 0;
+ }
+
+ return rc;
+}
+
+void
+sys_freeaddrinfo (struct addrinfo *ai)
+{
+ if (winsock_lib == NULL)
+ {
+ errno = ENETDOWN;
+ return;
+ }
+
+ check_errno ();
+ if (pfn_freeaddrinfo)
+ pfn_freeaddrinfo (ai);
+ else
+ {
+ eassert (ai->ai_next == NULL);
+ xfree (ai);
+ }
+}
+
int
sys_shutdown (int s, int how)
{
return -1;
}
- /* make sure we close the destination first if it's a pipe or socket */
- if (src != dst && fd_info[dst].flags != 0)
+ /* MS _dup2 seems to have weird side effect when invoked with 2
+ identical arguments: an attempt to fclose the corresponding stdio
+ stream after that hangs (we do close standard streams in
+ init_ntproc). Attempt to avoid that by not calling _dup2 that
+ way: if SRC is valid, we know that dup2 should be a no-op, so do
+ nothing and return DST. */
+ if (src == dst)
+ {
+ if ((HANDLE)_get_osfhandle (src) == INVALID_HANDLE_VALUE)
+ {
+ errno = EBADF;
+ return -1;
+ }
+ return dst;
+ }
+
+ /* Make sure we close the destination first if it's a pipe or socket. */
+ if (fd_info[dst].flags != 0)
sys_close (dst);
rc = _dup2 (src, dst);
if (rc == 0)
{
- /* duplicate our internal info as well */
+ /* Duplicate our internal info as well. */
fd_info[dst] = fd_info[src];
}
- return rc;
+ return rc == 0 ? dst : rc;
}
int
{
int rc;
unsigned flags;
+ unsigned pipe_size = 0;
eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
+ /* Allow Lisp to override the default buffer size of the pipe. */
+ if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
+ pipe_size = w32_pipe_buffer_size;
+
/* make pipe handles non-inheritable; when we spawn a child, we
replace the relevant handle with an inheritable one. Also put
pipes into binary mode; we will do text mode translation ourselves
if required. */
- rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
+ rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
if (rc == 0)
{
case STATUS_READ_READY:
case STATUS_READ_IN_PROGRESS:
- DebPrint (("sys_read called when read is in progress\n"));
+#if 0
+ /* This happens all the time during GnuTLS handshake
+ with the remote, evidently because GnuTLS waits for
+ the read to complete by retrying the read operation
+ upon EAGAIN. So I'm disabling the DebPrint to avoid
+ wasting cycles on something that is not a real
+ problem. Enable if you need to debug something that
+ bumps into this. */
+ DebPrint (("sys_read called when read is in progress %d\n",
+ current_status));
+#endif
errno = EWOULDBLOCK;
return -1;
unsigned long nblock = 0;
if (winsock_lib == NULL) emacs_abort ();
+ child_process *cp = fd_info[fd].cp;
+
+ /* If this is a non-blocking socket whose connection is in
+ progress or terminated with an error already, return the
+ proper error code to the caller. */
+ if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
+ {
+ /* In case connection is in progress, ENOTCONN that would
+ result from calling pfn_send is not what callers expect. */
+ if (cp->status != STATUS_CONNECT_FAILED)
+ {
+ errno = EWOULDBLOCK;
+ return -1;
+ }
+ /* In case connection failed, use the actual error code
+ stashed by '_sys_wait_connect' in cp->errcode. */
+ else if (cp->errcode != 0)
+ {
+ pfn_WSASetLastError (cp->errcode);
+ set_errno ();
+ return -1;
+ }
+ }
+
/* TODO: implement select() properly so non-blocking I/O works. */
/* For now, make sure the write blocks. */
if (fd_info[fd].flags & FILE_NDELAY)
nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
+ if (nchars == SOCKET_ERROR)
+ {
+ set_errno ();
+ DebPrint (("sys_write.send failed with error %d on socket %ld\n",
+ pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
+ }
+
/* 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_write.send failed with error %d on socket %ld\n",
- pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
- set_errno ();
- }
}
else
{
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;
+ const bool is_pipe = (fd < MAXDESC
+ && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
+ == (FILE_PIPE | FILE_NDELAY)));
+ /* Some programs, notably Node.js's node.exe, seem to never
+ completely empty the pipe, so writing more than the size of
+ the pipe's buffer always returns ENOSPC, and we loop forever
+ between send_process and here. As a workaround, write no
+ more than the pipe's buffer can hold. */
+ DWORD pipe_buffer_size;
+ if (is_pipe)
+ {
+ if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
+ NULL, &pipe_buffer_size, NULL, NULL))
+ {
+ DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
+ pipe_buffer_size = 4096;
+ }
+ }
+ const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
nchars = 0;
+ errno = 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;
if (n < 0)
{
/* When there's no buffer space in a pipe that is in the
avoiding deadlock whereby each side of the pipe is
blocked on write, waiting for the other party to read
its end of the pipe. */
- if (errno == ENOSPC
- && fd < MAXDESC
- && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
- == (FILE_PIPE | FILE_NDELAY)))
+ if (errno == ENOSPC && is_pipe)
errno = EAGAIN;
- nchars = n;
+ if (nchars == 0)
+ nchars = -1;
break;
}
else if (n < this_chunk)
\f
/* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
-extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
+extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, ptrdiff_t);
/* Return information about network interface IFNAME, or about all
interfaces (if IFNAME is nil). */
"not unpacked properly.\nSee the README.W32 file in the "
"top-level Emacs directory for more information.",
init_file_name, load_path);
- needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
- -1, NULL, 0);
+ needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
+ buffer, -1, NULL, 0);
if (needed > 0)
{
wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
- pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
- msg_w, needed);
+ pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
+ -1, msg_w, needed);
needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
NULL, 0, NULL, NULL);
if (needed > 0)
(MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
pWideCharToMultiByte =
(WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
+ multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
return ret;
}
else
pointers; no need for the LoadLibrary dance. */
pMultiByteToWideChar = MultiByteToWideChar;
pWideCharToMultiByte = WideCharToMultiByte;
+ /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported. */
+ if (w32_major_version < 5)
+ multiByteToWideCharFlags = 0;
+ else
+ multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
return LoadLibrary ("Gdi32.dll");
}
}
extern void dynlib_reset_last_error (void);
dynlib_reset_last_error ();
#endif
+
+ w32_crypto_hprov = (HCRYPTPROV)0;
}
/* For make-serial-process */