X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/4e604a5d70c4f26abe8bb3494346c598389906b3..ad8a47b89fc3c5a3302255f318b1ed805838cf72:/src/w32.c
diff --git a/src/w32.c b/src/w32.c
index fb2d7c7597..e48078aec9 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -19,6 +19,8 @@ along with GNU Emacs. If not, see . */
/*
Geoff Voelker (voelker@cs.washington.edu) 7-29-94
*/
+
+#include
#include /* for offsetof */
#include
#include
@@ -47,7 +49,6 @@ along with GNU Emacs. If not, see . */
#undef fopen
#undef link
#undef mkdir
-#undef mktemp
#undef open
#undef rename
#undef rmdir
@@ -90,6 +91,21 @@ typedef struct _MEMORY_STATUS_EX {
DWORDLONG ullAvailExtendedVirtual;
} MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
+/* These are here so that GDB would know about these data types. This
+ allows to attach GDB to Emacs when a fatal exception is triggered
+ and Windows pops up the "application needs to be closed" dialog.
+ At that point, _gnu_exception_handler, the top-level exception
+ handler installed by the MinGW startup code, is somewhere on the
+ call-stack of the main thread, so going to that call frame and
+ looking at the argument to _gnu_exception_handler, which is a
+ PEXCEPTION_POINTERS pointer, can reveal the exception code
+ (excptr->ExceptionRecord->ExceptionCode) and the address where the
+ exception happened (excptr->ExceptionRecord->ExceptionAddress), as
+ well as some additional information specific to the exception. */
+PEXCEPTION_POINTERS excptr;
+PEXCEPTION_RECORD excprec;
+PCONTEXT ctxrec;
+
#include
#include
@@ -202,6 +218,8 @@ typedef struct _REPARSE_DATA_BUFFER {
#undef recvfrom
#undef sendto
+#include /* should be after winsock2.h */
+
#include "w32.h"
#include
#include "w32common.h"
@@ -233,7 +251,7 @@ static BOOL WINAPI revert_to_self (void);
extern int sys_access (const char *, int);
extern void *e_malloc (size_t);
extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
- EMACS_TIME *, void *);
+ struct timespec *, void *);
extern int sys_dup (int);
@@ -280,6 +298,7 @@ static BOOL g_b_init_convert_sd_to_sddl;
static BOOL g_b_init_convert_sddl_to_sd;
static BOOL g_b_init_is_valid_security_descriptor;
static BOOL g_b_init_set_file_security;
+static BOOL g_b_init_get_adapters_info;
/*
BEGIN: Wrapper functions around OpenProcessToken
@@ -422,6 +441,9 @@ typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)
LPTSTR *StringSecurityDescriptor,
PULONG StringSecurityDescriptorLen);
typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
+typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
+ PIP_ADAPTER_INFO pAdapterInfo,
+ PULONG pOutBufLen);
/* ** A utility function ** */
static BOOL
@@ -1114,6 +1136,28 @@ convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
return retval;
}
+static DWORD WINAPI
+get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
+{
+ static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
+ HMODULE hm_iphlpapi = NULL;
+
+ if (is_windows_9x () == TRUE)
+ return ERROR_NOT_SUPPORTED;
+
+ if (g_b_init_get_adapters_info == 0)
+ {
+ g_b_init_get_adapters_info = 1;
+ hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
+ if (hm_iphlpapi)
+ s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
+ GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
+ }
+ if (s_pfn_Get_Adapters_Info == NULL)
+ return ERROR_NOT_SUPPORTED;
+ return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
+}
+
/* Return 1 if P is a valid pointer to an object of size SIZE. Return
@@ -2044,7 +2088,7 @@ init_environment (char ** argv)
/* For backwards compatibility, check if a .emacs file exists in C:/
If not, then we can try to default to the appdata directory under the
user's profile, which is more likely to be writable. */
- if (!check_existing ("C:/.emacs"))
+ if (faccessat (AT_FDCWD, "C:/.emacs", F_OK, AT_EACCESS) != 0)
{
HRESULT profile_result;
/* Dynamically load ShGetFolderPath, as it won't exist on versions
@@ -2182,7 +2226,8 @@ init_environment (char ** argv)
strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
ExpandEnvironmentStrings ((LPSTR) fname, bufc,
sizeof (bufc));
- if (check_existing (bufc))
+ if (faccessat (AT_FDCWD, bufc, F_OK, AT_EACCESS)
+ == 0)
{
lpval = bufc;
dwType = REG_SZ;
@@ -2489,8 +2534,6 @@ gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
int
fdutimens (int fd, char const *file, struct timespec const timespec[2])
{
- struct _utimbuf ut;
-
if (!timespec)
{
errno = ENOSYS;
@@ -2501,12 +2544,28 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2])
errno = EBADF;
return -1;
}
- ut.actime = timespec[0].tv_sec;
- ut.modtime = timespec[1].tv_sec;
+ /* _futime's prototype defines 2nd arg as having the type 'struct
+ _utimbuf', while utime needs to accept 'struct utimbuf' for
+ compatibility with Posix. So we need to use 2 different (but
+ equivalent) types to avoid compiler warnings, sigh. */
if (fd >= 0)
- return _futime (fd, &ut);
+ {
+ struct _utimbuf _ut;
+
+ _ut.actime = timespec[0].tv_sec;
+ _ut.modtime = timespec[1].tv_sec;
+ return _futime (fd, &_ut);
+ }
else
- return _utime (file, &ut);
+ {
+ struct utimbuf ut;
+
+ ut.actime = timespec[0].tv_sec;
+ ut.modtime = timespec[1].tv_sec;
+ /* Call 'utime', which is implemented below, not the MS library
+ function, which fails on directories. */
+ return utime (file, &ut);
+ }
}
@@ -3414,25 +3473,46 @@ sys_mkdir (const char * path)
return _mkdir (map_w32_filename (path, NULL));
}
-/* Because of long name mapping issues, we need to implement this
- ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
- a unique name, instead of setting the input template to an empty
- string.
+int
+sys_open (const char * path, int oflag, int mode)
+{
+ const char* mpath = map_w32_filename (path, NULL);
+ int res = -1;
- Standard algorithm seems to be use pid or tid with a letter on the
- front (in place of the 6 X's) and cycle through the letters to find a
- unique name. We extend that to allow any reasonable character as the
- first of the 6 X's. */
-char *
-sys_mktemp (char * template)
+ /* If possible, try to open file without _O_CREAT, to be able to
+ write to existing hidden and system files. Force all file
+ handles to be non-inheritable. */
+ if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
+ res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
+ if (res < 0)
+ res = _open (mpath, oflag | _O_NOINHERIT, mode);
+
+ return res;
+}
+
+/* Implementation of mkostemp for MS-Windows, to avoid race conditions
+ when using mktemp.
+
+ Standard algorithm for generating a temporary file name seems to be
+ use pid or tid with a letter on the front (in place of the 6 X's)
+ and cycle through the letters to find a unique name. We extend
+ that to allow any reasonable character as the first of the 6 X's,
+ so that the number of simultaneously used temporary files will be
+ greater. */
+
+int
+mkostemp (char * template, int flags)
{
char * p;
- int i;
+ int i, fd = -1;
unsigned uid = GetCurrentThreadId ();
+ int save_errno = errno;
static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
+ errno = EINVAL;
if (template == NULL)
- return NULL;
+ return -1;
+
p = template + strlen (template);
i = 5;
/* replace up to the last 5 X's with uid in decimal */
@@ -3447,38 +3527,22 @@ sys_mktemp (char * template)
i = 0;
do
{
- int save_errno = errno;
p[0] = first_char[i];
- if (faccessat (AT_FDCWD, template, F_OK, AT_EACCESS) < 0)
+ if ((fd = sys_open (template,
+ flags | _O_CREAT | _O_EXCL | _O_RDWR,
+ S_IRUSR | S_IWUSR)) >= 0
+ || errno != EEXIST)
{
- errno = save_errno;
- return template;
+ if (fd >= 0)
+ errno = save_errno;
+ return fd;
}
}
while (++i < sizeof (first_char));
}
- /* Template is badly formed or else we can't generate a unique name,
- so return empty string */
- template[0] = 0;
- return template;
-}
-
-int
-sys_open (const char * path, int oflag, int mode)
-{
- const char* mpath = map_w32_filename (path, NULL);
- int res = -1;
-
- /* If possible, try to open file without _O_CREAT, to be able to
- write to existing hidden and system files. Force all file
- handles to be non-inheritable. */
- if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
- res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
- if (res < 0)
- res = _open (mpath, oflag | _O_NOINHERIT, mode);
-
- return res;
+ /* Template is badly formed or else we can't generate a unique name. */
+ return -1;
}
int
@@ -4482,6 +4546,9 @@ fstat (int desc, struct stat * buf)
return 0;
}
+/* A version of 'utime' which handles directories as well as
+ files. */
+
int
utime (const char *name, struct utimbuf *times)
{
@@ -5750,8 +5817,8 @@ system_process_attributes (Lisp_Object pid)
{
/* Decode the command name from locale-specific
encoding. */
- cmd_str = make_unibyte_string (pe.szExeFile,
- strlen (pe.szExeFile));
+ cmd_str = build_unibyte_string (pe.szExeFile);
+
decoded_cmd =
code_convert_string_norecord (cmd_str,
Vlocale_coding_system, 0);
@@ -6056,6 +6123,7 @@ term_winsock (void)
{
if (winsock_lib != NULL && winsock_inuse == 0)
{
+ release_listen_threads ();
/* Not sure what would cause WSAENETDOWN, or even if it can happen
after WSAStartup returns successfully, but it seems reasonable
to allow unloading winsock anyway in that case. */
@@ -7040,7 +7108,12 @@ _sys_wait_accept (int fd)
rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
if (rc != SOCKET_ERROR)
{
- rc = WaitForSingleObject (hEv, INFINITE);
+ do {
+ rc = WaitForSingleObject (hEv, 500);
+ Sleep (5);
+ } while (rc == WAIT_TIMEOUT
+ && cp->status != STATUS_READ_ERROR
+ && cp->char_avail);
pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
if (rc == WAIT_OBJECT_0)
cp->status = STATUS_READ_SUCCEEDED;
@@ -7390,6 +7463,269 @@ sys_write (int fd, const void * buffer, unsigned int count)
return nchars;
}
+
+/* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
+
+extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
+
+/* Return information about network interface IFNAME, or about all
+ interfaces (if IFNAME is nil). */
+static Lisp_Object
+network_interface_get_info (Lisp_Object ifname)
+{
+ ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
+ IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
+ DWORD retval = get_adapters_info (ainfo, &ainfo_len);
+ Lisp_Object res = Qnil;
+
+ if (retval == ERROR_BUFFER_OVERFLOW)
+ {
+ ainfo = xrealloc (ainfo, ainfo_len);
+ retval = get_adapters_info (ainfo, &ainfo_len);
+ }
+
+ if (retval == ERROR_SUCCESS)
+ {
+ int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
+ int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
+ int if_num;
+ struct sockaddr_in sa;
+
+ /* For the below, we need some winsock functions, so make sure
+ the winsock DLL is loaded. If we cannot successfully load
+ it, they will have no use of the information we provide,
+ anyway, so punt. */
+ if (!winsock_lib && !init_winsock (1))
+ goto done;
+
+ for (adapter = ainfo; adapter; adapter = adapter->Next)
+ {
+ char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
+ u_long ip_addr;
+ /* Present Unix-compatible interface names, instead of the
+ Windows names, which are really GUIDs not readable by
+ humans. */
+ static const char *ifmt[] = {
+ "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
+ "lo", "ifx%d"
+ };
+ enum {
+ NONE = -1,
+ ETHERNET = 0,
+ TOKENRING = 1,
+ FDDI = 2,
+ PPP = 3,
+ SLIP = 4,
+ WLAN = 5,
+ LOOPBACK = 6,
+ OTHER_IF = 7
+ } ifmt_idx;
+
+ switch (adapter->Type)
+ {
+ case MIB_IF_TYPE_ETHERNET:
+ /* Windows before Vista reports wireless adapters as
+ Ethernet. Work around by looking at the Description
+ string. */
+ if (strstr (adapter->Description, "Wireless "))
+ {
+ ifmt_idx = WLAN;
+ if_num = wlan_count++;
+ }
+ else
+ {
+ ifmt_idx = ETHERNET;
+ if_num = eth_count++;
+ }
+ break;
+ case MIB_IF_TYPE_TOKENRING:
+ ifmt_idx = TOKENRING;
+ if_num = tr_count++;
+ break;
+ case MIB_IF_TYPE_FDDI:
+ ifmt_idx = FDDI;
+ if_num = fddi_count++;
+ break;
+ case MIB_IF_TYPE_PPP:
+ ifmt_idx = PPP;
+ if_num = ppp_count++;
+ break;
+ case MIB_IF_TYPE_SLIP:
+ ifmt_idx = SLIP;
+ if_num = sl_count++;
+ break;
+ case IF_TYPE_IEEE80211:
+ ifmt_idx = WLAN;
+ if_num = wlan_count++;
+ break;
+ case MIB_IF_TYPE_LOOPBACK:
+ if (lo_count < 0)
+ {
+ ifmt_idx = LOOPBACK;
+ if_num = lo_count++;
+ }
+ else
+ ifmt_idx = NONE;
+ break;
+ default:
+ ifmt_idx = OTHER_IF;
+ if_num = ifx_count++;
+ break;
+ }
+ if (ifmt_idx == NONE)
+ continue;
+ sprintf (namebuf, ifmt[ifmt_idx], if_num);
+
+ sa.sin_family = AF_INET;
+ ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
+ if (ip_addr == INADDR_NONE)
+ {
+ /* Bogus address, skip this interface. */
+ continue;
+ }
+ sa.sin_addr.s_addr = ip_addr;
+ sa.sin_port = 0;
+ if (NILP (ifname))
+ res = Fcons (Fcons (build_string (namebuf),
+ conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
+ sizeof (struct sockaddr))),
+ res);
+ else if (strcmp (namebuf, SSDATA (ifname)) == 0)
+ {
+ Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
+ register struct Lisp_Vector *p = XVECTOR (hwaddr);
+ Lisp_Object flags = Qnil;
+ int n;
+ u_long net_mask;
+
+ /* Flags. We guess most of them by type, since the
+ Windows flags are different and hard to get by. */
+ flags = Fcons (intern ("up"), flags);
+ if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
+ {
+ flags = Fcons (intern ("broadcast"), flags);
+ flags = Fcons (intern ("multicast"), flags);
+ }
+ flags = Fcons (intern ("running"), flags);
+ if (ifmt_idx == PPP)
+ {
+ flags = Fcons (intern ("pointopoint"), flags);
+ flags = Fcons (intern ("noarp"), flags);
+ }
+ if (adapter->HaveWins)
+ flags = Fcons (intern ("WINS"), flags);
+ if (adapter->DhcpEnabled)
+ flags = Fcons (intern ("dynamic"), flags);
+
+ res = Fcons (flags, res);
+
+ /* Hardware address and its family. */
+ for (n = 0; n < adapter->AddressLength; n++)
+ p->contents[n] = make_number ((int) adapter->Address[n]);
+ /* Windows does not support AF_LINK or AF_PACKET family
+ of addresses. Use an arbitrary family number that is
+ identical to what GNU/Linux returns. */
+ res = Fcons (Fcons (make_number (1), hwaddr), res);
+
+ /* Network mask. */
+ sa.sin_family = AF_INET;
+ net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
+ if (net_mask != INADDR_NONE)
+ {
+ sa.sin_addr.s_addr = net_mask;
+ sa.sin_port = 0;
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+ }
+ else
+ res = Fcons (Qnil, res);
+
+ sa.sin_family = AF_INET;
+ if (ip_addr != INADDR_NONE)
+ {
+ /* Broadcast address is only reported by
+ GetAdaptersAddresses, which is of limited
+ availability. Generate it on our own. */
+ u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
+
+ sa.sin_addr.s_addr = bcast_addr;
+ sa.sin_port = 0;
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+
+ /* IP address. */
+ sa.sin_addr.s_addr = ip_addr;
+ sa.sin_port = 0;
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+ }
+ else
+ res = Fcons (Qnil, Fcons (Qnil, res));
+ }
+ }
+ /* GetAdaptersInfo is documented to not report loopback
+ interfaces, so we generate one out of thin air. */
+ if (!lo_count)
+ {
+ sa.sin_family = AF_INET;
+ sa.sin_port = 0;
+ if (NILP (ifname))
+ {
+ sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
+ res = Fcons (Fcons (build_string ("lo"),
+ conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
+ sizeof (struct sockaddr))),
+ res);
+ }
+ else if (strcmp (SSDATA (ifname), "lo") == 0)
+ {
+ res = Fcons (Fcons (intern ("running"),
+ Fcons (intern ("loopback"),
+ Fcons (intern ("up"), Qnil))), Qnil);
+ /* 772 is what 3 different GNU/Linux systems report for
+ the loopback interface. */
+ res = Fcons (Fcons (make_number (772),
+ Fmake_vector (make_number (6),
+ make_number (0))),
+ res);
+ sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+ sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+ sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+ }
+
+ }
+ }
+
+ done:
+ xfree (ainfo);
+ return res;
+}
+
+Lisp_Object
+network_interface_list (void)
+{
+ return network_interface_get_info (Qnil);
+}
+
+Lisp_Object
+network_interface_info (Lisp_Object ifname)
+{
+ return network_interface_get_info (ifname);
+}
+
+
/* The Windows CRT functions are "optimized for speed", so they don't
check for timezone and DST changes if they were last called less
than 1 minute ago (see http://support.microsoft.com/kb/821231). So
@@ -7691,6 +8027,7 @@ globals_of_w32 (void)
g_b_init_convert_sddl_to_sd = 0;
g_b_init_is_valid_security_descriptor = 0;
g_b_init_set_file_security = 0;
+ g_b_init_get_adapters_info = 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
@@ -7903,7 +8240,7 @@ emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
{
int n, err;
SELECT_TYPE fdset;
- EMACS_TIME timeout;
+ struct timespec timeout;
struct Lisp_Process *process = (struct Lisp_Process *)p;
int fd = process->infd;