summaryrefslogtreecommitdiff
path: root/src/w32.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/w32.c')
-rw-r--r--src/w32.c267
1 files changed, 242 insertions, 25 deletions
diff --git a/src/w32.c b/src/w32.c
index 793bc0f28d..1db3426097 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -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