diff options
Diffstat (limited to 'src/w32.c')
-rw-r--r-- | src/w32.c | 267 |
1 files changed, 242 insertions, 25 deletions
@@ -66,6 +66,24 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #undef localtime +char *sys_ctime (const time_t *); +int sys_chdir (const char *); +int sys_creat (const char *, int); +FILE *sys_fopen (const char *, const char *); +int sys_mkdir (const char *); +int sys_open (const char *, int, int); +int sys_rename (char const *, char const *); +int sys_rmdir (const char *); +int sys_close (int); +int sys_dup2 (int, int); +int sys_read (int, char *, unsigned int); +int sys_write (int, const void *, unsigned int); +struct tm *sys_localtime (const time_t *); + +#ifdef HAVE_MODULES +extern void dynlib_reset_last_error (void); +#endif + #include "lisp.h" #include "epaths.h" /* for PATH_EXEC */ @@ -227,6 +245,7 @@ typedef struct _REPARSE_DATA_BUFFER { #include <wincrypt.h> #include <c-strcase.h> +#include <utimens.h> /* for fdutimens */ #include "w32.h" #include <dirent.h> @@ -246,7 +265,6 @@ typedef struct _REPARSE_DATA_BUFFER { typedef HRESULT (WINAPI * ShGetFolderPath_fn) (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *); -void globals_of_w32 (void); static DWORD get_rid (PSID); static int is_symlink (const char *); static char * chase_symlinks (const char *); @@ -512,6 +530,8 @@ static Lisp_Object ltime (ULONGLONG); /* Get total user and system times for get-internal-run-time. Returns a list of 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 (void); + Lisp_Object w32_get_internal_run_time (void) { @@ -2485,13 +2505,42 @@ sys_putenv (char *str) return unsetenv (str); } + if (strncmp (str, "TZ=<", 4) == 0) + { + /* MS-Windows does not support POSIX.1-2001 angle-bracket TZ + abbreviation syntax. Convert to POSIX.1-1988 syntax if possible, + and to the undocumented placeholder "ZZZ" otherwise. */ + bool supported_abbr = true; + for (char *p = str + 4; *p; p++) + { + if (('0' <= *p && *p <= '9') || *p == '-' || *p == '+') + supported_abbr = false; + else if (*p == '>') + { + ptrdiff_t abbrlen; + if (supported_abbr) + { + abbrlen = p - (str + 4); + memmove (str + 3, str + 4, abbrlen); + } + else + { + abbrlen = 3; + memset (str + 3, 'Z', abbrlen); + } + memmove (str + 3 + abbrlen, p + 1, strlen (p)); + break; + } + } + } + return _putenv (str); } #define REG_ROOT "SOFTWARE\\GNU\\Emacs" LPBYTE -w32_get_resource (char *key, LPDWORD lpdwtype) +w32_get_resource (const char *key, LPDWORD lpdwtype) { LPBYTE lpvalue; HKEY hrootkey = NULL; @@ -2600,8 +2649,8 @@ init_environment (char ** argv) static const struct env_entry { - char * name; - char * def_value; + const char * name; + const char * def_value; } dflt_envvars[] = { /* If the default value is NULL, we will use the value from the @@ -2761,14 +2810,14 @@ init_environment (char ** argv) { /* If not found in any directory, use the default as the last resort. */ - lpval = env_vars[i].def_value; + lpval = (char *)env_vars[i].def_value; dwType = REG_EXPAND_SZ; } } while (*pstart); } else { - lpval = env_vars[i].def_value; + lpval = (char *)env_vars[i].def_value; dwType = REG_EXPAND_SZ; } if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata) @@ -2789,7 +2838,7 @@ init_environment (char ** argv) if (dwType == REG_EXPAND_SZ) ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1)); else if (dwType == REG_SZ) - strcpy (buf1, lpval); + strcpy (buf1, (char *)lpval); if (dwType == REG_EXPAND_SZ || dwType == REG_SZ) { _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name, @@ -2964,7 +3013,7 @@ char * sys_ctime (const time_t *t) { char *str = (char *) ctime (t); - return (str ? str : "Sun Jan 01 00:00:00 1970"); + return (str ? str : (char *)"Sun Jan 01 00:00:00 1970"); } /* Emulate sleep...we could have done this with a define, but that @@ -3228,6 +3277,8 @@ is_fat_volume (const char * name, const char ** pPath) /* Convert all slashes in a filename to backslashes, and map filename to a valid 8.3 name if necessary. The result is a pointer to a static buffer, so CAVEAT EMPTOR! */ +const char *map_w32_filename (const char *, const char **); + const char * map_w32_filename (const char * name, const char ** pPath) { @@ -4433,7 +4484,7 @@ sys_rename_replace (const char *oldname, const char *newname, BOOL force) { /* Force temp name to require a manufactured 8.3 alias - this seems to make the second rename work properly. */ - sprintf (p, "_.%s.%u", o, i); + sprintf (p, "_.%s.%d", o, i); i++; result = rename (oldname_a, temp_a); } @@ -4861,6 +4912,8 @@ get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st) } /* Return non-zero if NAME is a potentially slow filesystem. */ +int is_slow_fs (const char *); + int is_slow_fs (const char *name) { @@ -7205,6 +7258,10 @@ int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags, 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 @@ -7214,6 +7271,8 @@ BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags) HANDLE winsock_lib; static int winsock_inuse; +BOOL term_winsock (void); + BOOL term_winsock (void) { @@ -7287,6 +7346,16 @@ init_winsock (int load_now) 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) { @@ -7361,7 +7430,7 @@ check_errno (void) /* Extend strerror to handle the winsock-specific error codes. */ struct { int errnum; - char * msg; + const char * msg; } _wsa_errlist[] = { {WSAEINTR , "Interrupted function call"}, {WSAEBADF , "Bad file descriptor"}, @@ -7445,7 +7514,7 @@ sys_strerror (int error_no) for (i = 0; _wsa_errlist[i].errnum >= 0; i++) if (_wsa_errlist[i].errnum == error_no) - return _wsa_errlist[i].msg; + return (char *)_wsa_errlist[i].msg; sprintf (unknown_msg, "Unidentified error: %d", error_no); return unknown_msg; @@ -7737,6 +7806,117 @@ sys_getpeername (int s, struct sockaddr *addr, int * namelen) } 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) { if (winsock_lib == NULL) @@ -8059,17 +8239,33 @@ sys_dup2 (int src, int dst) 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 @@ -8650,6 +8846,30 @@ sys_write (int fd, const void * buffer, unsigned int count) 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) @@ -8657,6 +8877,13 @@ sys_write (int fd, const void * buffer, unsigned int count) 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) @@ -8664,13 +8891,6 @@ sys_write (int fd, const void * buffer, unsigned int count) 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 { @@ -8743,8 +8963,6 @@ sys_write (int fd, const void * buffer, unsigned int count) /* 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 @@ -9457,7 +9675,6 @@ globals_of_w32 (void) w32_unicode_filenames = 1; #ifdef HAVE_MODULES - extern void dynlib_reset_last_error (void); dynlib_reset_last_error (); #endif |