X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/aef2281c76c1a6ec9cb988b8c339a1ed569f1114..ad8a47b89fc3c5a3302255f318b1ed805838cf72:/src/w32.c diff --git a/src/w32.c b/src/w32.c index f42b83af60..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 @@ -29,10 +31,10 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include /* must be before nt/inc/sys/time.h, for MinGW64 */ #include #include #include -#include /* must include CRT headers *before* config.h */ @@ -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 @@ -65,11 +66,13 @@ along with GNU Emacs. If not, see . */ #undef localtime #include "lisp.h" +#include "epaths.h" /* for SHELL */ #include #include -#ifdef __GNUC__ +/* MinGW64 (_W64) defines these in its _mingw.h. */ +#if defined(__GNUC__) && !defined(_W64) #define _ANONYMOUS_UNION #define _ANONYMOUS_STRUCT #endif @@ -88,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 @@ -96,6 +114,7 @@ typedef struct _MEMORY_STATUS_EX { #ifndef _MSC_VER #include #endif +#if _WIN32_WINNT < 0x0500 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15) /* This either is not in psapi.h or guarded by higher value of _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15 @@ -114,6 +133,7 @@ typedef struct _PROCESS_MEMORY_COUNTERS_EX { SIZE_T PrivateUsage; } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX; #endif +#endif #include #include @@ -127,11 +147,11 @@ typedef struct _PROCESS_MEMORY_COUNTERS_EX { #define SDDL_REVISION_1 1 #endif /* SDDL_REVISION_1 */ -#ifdef _MSC_VER -/* MSVC doesn't provide the definition of REPARSE_DATA_BUFFER and the - associated macros, except on ntifs.h, which cannot be included - because it triggers conflicts with other Windows API headers. So - we define it here by hand. */ +#if defined(_MSC_VER) || defined(_W64) +/* MSVC and MinGW64 don't provide the definition of + REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h, + which cannot be included because it triggers conflicts with other + Windows API headers. So we define it here by hand. */ typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; @@ -171,9 +191,12 @@ typedef struct _REPARSE_DATA_BUFFER { #ifndef CTL_CODE #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m)) #endif +/* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */ +#ifndef FSCTL_GET_REPARSE_POINT #define FSCTL_GET_REPARSE_POINT \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) #endif +#endif /* TCP connection support. */ #include @@ -195,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" @@ -226,7 +251,9 @@ 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); + @@ -271,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 @@ -413,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 @@ -1105,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 @@ -2012,7 +2065,7 @@ init_environment (char ** argv) {"PRELOAD_WINSOCK", NULL}, {"emacs_dir", "C:/emacs"}, {"EMACSLOADPATH", NULL}, - {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"}, + {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */ {"EMACSDATA", NULL}, {"EMACSPATH", NULL}, {"INFOPATH", NULL}, @@ -2035,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 @@ -2088,9 +2141,12 @@ init_environment (char ** argv) emacs_abort (); *p = 0; - if ((p = _mbsrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0) + if ((p = _mbsrchr (modname, '\\')) + /* From bin means installed Emacs, from src means uninstalled. */ + && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0)) { char buf[SET_ENV_BUF_SIZE]; + int within_build_tree = xstrcasecmp (p, "\\src") == 0; *p = 0; for (p = modname; *p; p = CharNext (p)) @@ -2098,6 +2154,15 @@ init_environment (char ** argv) _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname); _putenv (strdup (buf)); + /* If we are running from the Posix-like build tree, define + SHELL to point to our own cmdproxy. The loop below will + then disregard PATH_EXEC and the default value. */ + if (within_build_tree) + { + _snprintf (buf, sizeof (buf) - 1, + "SHELL=%s/nt/cmdproxy.exe", modname); + _putenv (strdup (buf)); + } } /* Handle running emacs from the build directory: src/oo-spd/i386/ */ @@ -2133,16 +2198,61 @@ init_environment (char ** argv) if (!getenv (env_vars[i].name)) { int dont_free = 0; + char bufc[SET_ENV_BUF_SIZE]; if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL /* Also ignore empty environment variables. */ || *lpval == 0) { xfree (lpval); - lpval = env_vars[i].def_value; - dwType = REG_EXPAND_SZ; dont_free = 1; - if (!strcmp (env_vars[i].name, "HOME") && !appdata) + if (strcmp (env_vars[i].name, "SHELL") == 0) + { + /* Look for cmdproxy.exe in every directory in + PATH_EXEC. FIXME: This does not find cmdproxy + in nt/ when we run uninstalled. */ + char fname[MAX_PATH]; + const char *pstart = PATH_EXEC, *pend; + + do { + pend = _mbschr (pstart, ';'); + if (!pend) + pend = pstart + strlen (pstart); + /* Be defensive against series of ;;; characters. */ + if (pend > pstart) + { + strncpy (fname, pstart, pend - pstart); + fname[pend - pstart] = '/'; + strcpy (&fname[pend - pstart + 1], "cmdproxy.exe"); + ExpandEnvironmentStrings ((LPSTR) fname, bufc, + sizeof (bufc)); + if (faccessat (AT_FDCWD, bufc, F_OK, AT_EACCESS) + == 0) + { + lpval = bufc; + dwType = REG_SZ; + break; + } + } + if (*pend) + pstart = pend + 1; + else + pstart = pend; + if (!*pstart) + { + /* If not found in any directory, use the + default as the last resort. */ + lpval = env_vars[i].def_value; + dwType = REG_EXPAND_SZ; + } + } while (*pstart); + } + else + { + lpval = env_vars[i].def_value; + dwType = REG_EXPAND_SZ; + } + if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata) Vdelayed_warnings_list = Fcons (listn (CONSTYPE_HEAP, 2, intern ("initialization"), @@ -2388,8 +2498,8 @@ get_emacs_configuration_options (void) #include /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */ -void -gettimeofday (struct timeval *tv, struct timezone *tz) +int +gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz) { struct _timeb tb; _ftime (&tb); @@ -2407,6 +2517,7 @@ gettimeofday (struct timeval *tv, struct timezone *tz) tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */ tz->tz_dsttime = tb.dstflag; /* type of dst correction */ } + return 0; } /* Emulate fdutimens. */ @@ -2423,8 +2534,6 @@ gettimeofday (struct timeval *tv, struct timezone *tz) int fdutimens (int fd, char const *file, struct timespec const timespec[2]) { - struct _utimbuf ut; - if (!timespec) { errno = ENOSYS; @@ -2435,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); + } } @@ -3348,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; + + /* 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 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) + 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 */ @@ -3381,42 +3527,32 @@ 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; + /* Template is badly formed or else we can't generate a unique name. */ + return -1; } int -sys_open (const char * path, int oflag, int mode) +fchmod (int fd, mode_t 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; + return 0; } int -sys_rename (const char * oldname, const char * newname) +sys_rename_replace (const char *oldname, const char *newname, BOOL force) { BOOL result; char temp[MAX_PATH]; @@ -3472,7 +3608,7 @@ sys_rename (const char * oldname, const char * newname) return -1; } - /* Emulate Unix behavior - newname is deleted if it already exists + /* If FORCE, emulate Unix behavior - newname is deleted if it already exists (at least if it is a file; don't do this for directories). Since we mustn't do this if we are just changing the case of the @@ -3490,7 +3626,7 @@ sys_rename (const char * oldname, const char * newname) result = rename (temp, newname); - if (result < 0) + if (result < 0 && force) { DWORD w32err = GetLastError (); @@ -3529,6 +3665,12 @@ sys_rename (const char * oldname, const char * newname) return result; } +int +sys_rename (char const *old, char const *new) +{ + return sys_rename_replace (old, new, TRUE); +} + int sys_rmdir (const char * path) { @@ -3709,12 +3851,6 @@ get_rid (PSID sid) /* 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; @@ -4410,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) { @@ -5568,10 +5707,8 @@ ltime (ULONGLONG time_100ns) { ULONGLONG time_sec = time_100ns / 10000000; int subsec = time_100ns % 10000000; - return list4 (make_number (time_sec >> 16), - make_number (time_sec & 0xffff), - make_number (subsec / 10), - make_number (subsec % 10 * 100000)); + return list4i (time_sec >> 16, time_sec & 0xffff, + subsec / 10, subsec % 10 * 100000); } #define U64_TO_LISP_TIME(time) ltime (time) @@ -5680,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); @@ -5986,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. */ @@ -6651,10 +6789,16 @@ sys_sendto (int s, const char * buf, int len, int flags, } /* Windows does not have an fcntl function. Provide an implementation - solely for making sockets non-blocking. */ + good enough for Emacs. */ int fcntl (int s, int cmd, int options) { + /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always + invoked in a context where fd1 is closed and all descriptors less + than fd1 are open, so sys_dup is an adequate implementation. */ + if (cmd == F_DUPFD_CLOEXEC) + return sys_dup (s); + if (winsock_lib == NULL) { errno = ENETDOWN; @@ -6796,13 +6940,14 @@ sys_dup2 (int src, int dst) return rc; } -/* Unix pipe() has only one arg */ int -sys_pipe (int * phandles) +pipe2 (int * phandles, int pipe2_flags) { int rc; unsigned flags; + eassert (pipe2_flags == O_CLOEXEC); + /* 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 @@ -6963,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; @@ -7313,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 @@ -7614,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 @@ -7630,8 +8044,9 @@ globals_of_w32 (void) /* For make-serial-process */ int -serial_open (char *port) +serial_open (Lisp_Object port_obj) { + char *port = SSDATA (port_obj); HANDLE hnd; child_process *cp; int fd = -1; @@ -7825,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;