/* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
-Copyright (C) 1994-1995, 2000-2015 Free Software Foundation, Inc.
+Copyright (C) 1994-1995, 2000-2016 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#undef localtime
#include "lisp.h"
-#include "epaths.h" /* for SHELL */
+#include "epaths.h" /* for PATH_EXEC */
#include <pwd.h>
#include <grp.h>
/* MinGW64 defines these in its _mingw.h. */
-#if defined(__GNUC__) && !defined(MINGW_W64)
-#define _ANONYMOUS_UNION
-#define _ANONYMOUS_STRUCT
+#ifndef _ANONYMOUS_UNION
+# define _ANONYMOUS_UNION
+#endif
+#ifndef _ANONYMOUS_STRUCT
+# define _ANONYMOUS_STRUCT
#endif
#include <windows.h>
/* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
#include <iphlpapi.h> /* should be after winsock2.h */
+#include <c-strcase.h>
+
#include "w32.h"
#include <dirent.h>
#include "w32common.h"
-#include "w32heap.h"
#include "w32select.h"
-#include "systime.h"
+#include "systime.h" /* for current_timespec, struct timespec */
#include "dispextern.h" /* for xstrcasecmp */
#include "coding.h" /* for Vlocale_coding_system */
#include "careadlinkat.h"
#include "allocator.h"
-/* For serial_configure and serial_open. */
+/* For Lisp_Process, serial_configure and serial_open. */
#include "process.h"
+#include "systty.h"
typedef HRESULT (WINAPI * ShGetFolderPath_fn)
(IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
-Lisp_Object QCloaded_from;
-
void globals_of_w32 (void);
static DWORD get_rid (PSID);
static int is_symlink (const char *);
static BOOL g_b_init_set_named_security_info_a;
static BOOL g_b_init_get_adapters_info;
+BOOL g_b_init_compare_string_w;
+
/*
BEGIN: Wrapper functions around OpenProcessToken
and other functions in advapi32.dll that are only
g_b_init_set_named_security_info_a = 1;
hm_advapi32 = LoadLibrary ("Advapi32.dll");
s_pfn_Set_Named_Security_InfoA =
- (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
+ (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
"SetNamedSecurityInfoA");
}
if (s_pfn_Set_Named_Security_InfoA == NULL)
/* Produce a Windows ANSI codepage suitable for encoding file names.
Return the information about that codepage in CP_INFO. */
-static int
+int
codepage_for_filenames (CPINFO *cp_info)
{
/* A simple cache to avoid calling GetCPInfo every time we need to
if (NILP (current_encoding))
{
- char *cpname = SDATA (SYMBOL_NAME (current_encoding));
+ char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
char *cp = NULL, *end;
int cpnum;
/* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
static struct load_sample samples[16*60];
static int first_idx = -1, last_idx = -1;
-static int max_idx = sizeof (samples) / sizeof (samples[0]);
+static int max_idx = ARRAYELTS (samples);
static int
buf_next (int from)
(From msdos.c...probably should figure out a way to share it,
although this code isn't going to ever change.) */
static int
-crlf_to_lf (register int n, register unsigned char *buf)
+crlf_to_lf (register int n, register char *buf)
{
- unsigned char *np = buf;
- unsigned char *startp = buf;
- unsigned char *endp = buf + n;
+ unsigned char *np = (unsigned char *)buf;
+ unsigned char *startp = np;
+ char *endp = buf + n;
if (n == 0)
return n;
/* Get long name for file, if possible (assumed to be absolute). */
BOOL
-w32_get_long_filename (char * name, char * buf, int size)
+w32_get_long_filename (const char * name, char * buf, int size)
{
char * o = buf;
char * p;
}
unsigned int
-w32_get_short_filename (char * name, char * buf, int size)
+w32_get_short_filename (const char * name, char * buf, int size)
{
if (w32_unicode_filenames)
{
{
char shortname[MAX_PATH];
- if (w32_get_short_filename (SDATA (filename), shortname, MAX_PATH))
+ if (w32_get_short_filename (SSDATA (filename), shortname, MAX_PATH))
{
dostounix_filename (shortname);
encoded_filename = build_string (shortname);
{
char *var;
size_t name_len;
- int retval;
if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
{
int i;
- const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
+ const int imax = ARRAYELTS (tempdirs);
/* Implementation note: This function explicitly works with ANSI
file names, not with UTF-8 encoded file names. This is because
{"LANG", NULL},
};
-#define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
+#define N_ENV_VARS ARRAYELTS (dflt_envvars)
/* We need to copy dflt_envvars[] and work on the copy because we
don't want the dumped Emacs to inherit the values of
/* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
else if (dir_find_handle == INVALID_HANDLE_VALUE)
{
- char filename[MAX_UTF8_PATH + 2];
+ char filename[MAX_UTF8_PATH];
int ln;
+ bool last_slash = true;
+ /* Note: We don't need to worry about dir_pathname being longer
+ than MAX_UTF8_PATH, as sys_opendir already took care of that
+ when it called map_w32_filename: that function will put a "?"
+ in its return value in that case, thus failing all the calls
+ below. */
strcpy (filename, dir_pathname);
- ln = strlen (filename) - 1;
- if (!IS_DIRECTORY_SEP (filename[ln]))
- strcat (filename, "\\");
- strcat (filename, "*");
+ ln = strlen (filename);
+ if (!IS_DIRECTORY_SEP (filename[ln - 1]))
+ last_slash = false;
/* Note: No need to resolve symlinks in FILENAME, because
FindFirst opens the directory that is the target of a
symlink. */
if (w32_unicode_filenames)
{
- wchar_t fnw[MAX_PATH];
+ wchar_t fnw[MAX_PATH + 2];
filename_to_utf16 (filename, fnw);
+ if (!last_slash)
+ wcscat (fnw, L"\\");
+ wcscat (fnw, L"*");
dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
}
else
{
- char fna[MAX_PATH];
+ char fna[MAX_PATH + 2];
filename_to_ansi (filename, fna);
+ if (!last_slash)
+ strcat (fna, "\\");
+ strcat (fna, "*");
/* If FILENAME is not representable by the current ANSI
codepage, we don't want FindFirstFileA to interpret the
'?' characters as a wildcard. */
if (dir_find_handle == INVALID_HANDLE_VALUE)
{
+ /* Any changes in the value of errno here should be in sync
+ with what directory_files_internal does when it calls
+ readdir. */
switch (GetLastError ())
{
- case ERROR_PATH_NOT_FOUND:
+ /* Windows uses this value when FindFirstFile finds no
+ files that match the wildcard. This is not supposed
+ to happen, since our wildcard is "*", but just in
+ case, if there's some weird empty directory with not
+ even "." and ".." entries... */
+ case ERROR_FILE_NOT_FOUND:
+ errno = 0;
+ /* FALLTHRU */
+ default:
+ break;
case ERROR_ACCESS_DENIED:
+ case ERROR_NETWORK_ACCESS_DENIED:
+ errno = EACCES;
+ break;
+ case ERROR_PATH_NOT_FOUND:
case ERROR_INVALID_DRIVE:
+ case ERROR_NOT_READY:
case ERROR_BAD_NETPATH:
- /* This special value will be noticed by
- directory_files_internal, which see. */
- errno = ENOTDIR;
- break;
- default:
+ case ERROR_BAD_NET_NAME:
+ errno = ENOENT;
break;
}
return NULL;
else if (w32_unicode_filenames)
{
if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
- return NULL;
+ {
+ errno = 0;
+ return NULL;
+ }
}
else
{
if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
- return NULL;
+ {
+ errno = 0;
+ return NULL;
+ }
}
/* Emacs never uses this value, so don't bother making it match
if (result == NO_ERROR)
return henum;
else
- return INVALID_HANDLE_VALUE;
+ {
+ /* Make sure directory_files_internal reports a sensible error. */
+ errno = ENOENT;
+ return INVALID_HANDLE_VALUE;
+ }
}
static void *
errno = EACCES;
return -1;
}
- break;
+ goto check_attrs;
}
/* FALLTHROUGH */
case ERROR_FILE_NOT_FOUND:
}
return -1;
}
+
+ check_attrs:
if ((mode & X_OK) != 0
&& !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
{
return 0;
}
+/* A special test for DIRNAME being a directory accessible by the
+ current user. This is needed because the security permissions in
+ directory's ACLs are not visible in the Posix-style mode bits
+ returned by 'stat' and in attributes returned by GetFileAttributes.
+ So a directory would seem like it's readable by the current user,
+ but will in fact error out with EACCES when they actually try. */
+int
+w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
+{
+ char pattern[MAX_UTF8_PATH];
+ bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
+ HANDLE dh;
+
+ /* Network volumes need a different reading method. */
+ if (is_unc_volume (dirname))
+ {
+ void *read_result = NULL;
+ wchar_t fnw[MAX_PATH];
+ char fna[MAX_PATH];
+
+ dh = open_unc_volume (dirname);
+ if (dh != INVALID_HANDLE_VALUE)
+ {
+ read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
+ close_unc_volume (dh);
+ }
+ /* Treat empty volumes as accessible. */
+ return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
+ }
+
+ /* Note: map_w32_filename makes sure DIRNAME is not longer than
+ MAX_UTF8_PATH. */
+ strcpy (pattern, map_w32_filename (dirname, NULL));
+
+ /* Note: No need to resolve symlinks in FILENAME, because FindFirst
+ opens the directory that is the target of a symlink. */
+ if (w32_unicode_filenames)
+ {
+ wchar_t pat_w[MAX_PATH + 2];
+ WIN32_FIND_DATAW dfd_w;
+
+ filename_to_utf16 (pattern, pat_w);
+ if (!last_slash)
+ wcscat (pat_w, L"\\");
+ wcscat (pat_w, L"*");
+ dh = FindFirstFileW (pat_w, &dfd_w);
+ }
+ else
+ {
+ char pat_a[MAX_PATH + 2];
+ WIN32_FIND_DATAA dfd_a;
+
+ filename_to_ansi (pattern, pat_a);
+ if (!last_slash)
+ strcpy (pat_a, "\\");
+ strcat (pat_a, "*");
+ /* In case DIRNAME cannot be expressed in characters from the
+ current ANSI codepage. */
+ if (_mbspbrk (pat_a, "?"))
+ dh = INVALID_HANDLE_VALUE;
+ else
+ dh = FindFirstFileA (pat_a, &dfd_a);
+ }
+
+ if (dh == INVALID_HANDLE_VALUE)
+ return 0;
+ FindClose (dh);
+ return 1;
+}
+
/* A version of 'access' to be used locally with file names in
locale-specific encoding. Does not resolve symlinks and does not
support file names on FAT12 and FAT16 volumes, but that's OK, since
int
sys_unlink (const char * path)
{
+ int rmstatus, e;
+
path = map_w32_filename (path, NULL);
if (w32_unicode_filenames)
wchar_t path_w[MAX_PATH];
filename_to_utf16 (path, path_w);
- /* On Unix, unlink works without write permission. */
+ /* On Unix, unlink works without write permission. */
_wchmod (path_w, 0666);
- return _wunlink (path_w);
+ rmstatus = _wunlink (path_w);
+ e = errno;
+ /* Symlinks to directories can only be deleted by _rmdir;
+ _unlink returns EACCES. */
+ if (rmstatus != 0
+ && errno == EACCES
+ && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ rmstatus = _wrmdir (path_w);
+ else
+ errno = e;
}
else
{
filename_to_ansi (path, path_a);
_chmod (path_a, 0666);
- return _unlink (path_a);
+ rmstatus = _unlink (path_a);
+ e = errno;
+ if (rmstatus != 0
+ && errno == EACCES
+ && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ rmstatus = _rmdir (path_a);
+ else
+ errno = e;
}
+
+ return rmstatus;
}
static FILETIME utc_base_ft;
{
/* Make sure root directories end in a slash. */
if (!IS_DIRECTORY_SEP (name[len-1]))
- strcat (name, "\\");
+ strcpy (name + len, "\\");
if (GetDriveType (name) < 2)
{
errno = ENOENT;
p--;
if (p > linkfn)
strncpy (tem, linkfn, p - linkfn);
- tem[p - linkfn] = '\0';
- strcat (tem, filename);
+ strcpy (tem + (p - linkfn), filename);
dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
}
else
/* A quick inexpensive test of whether FILENAME identifies a file that
is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
must already be in the normalized form returned by
- map_w32_filename.
+ map_w32_filename. If the symlink is to a directory, the
+ FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
Note: for repeated operations on many files, it is best to test
whether the underlying volume actually supports symlinks, by
attrs_mean_symlink =
(wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
&& (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
+ if (attrs_mean_symlink)
+ attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
}
else if (_mbspbrk (filename_a, "?"))
{
attrs_mean_symlink =
(wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
&& (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
+ if (attrs_mean_symlink)
+ attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
}
if (fh == INVALID_HANDLE_VALUE)
return 0;
Lisp_Object
list_system_processes (void)
{
- struct gcpro gcpro1;
Lisp_Object proclist = Qnil;
HANDLE h_snapshot;
DWORD proc_id;
BOOL res;
- GCPRO1 (proclist);
-
proc_entry.dwSize = sizeof (PROCESSENTRY32);
for (res = process32_first (h_snapshot, &proc_entry); res;
res = process32_next (h_snapshot, &proc_entry))
}
CloseHandle (h_snapshot);
- UNGCPRO;
proclist = Fnreverse (proclist);
}
Lisp_Object
system_process_attributes (Lisp_Object pid)
{
- struct gcpro gcpro1, gcpro2, gcpro3;
Lisp_Object attrs = Qnil;
Lisp_Object cmd_str, decoded_cmd, tem;
HANDLE h_snapshot, h_proc;
h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
- GCPRO3 (attrs, decoded_cmd, tem);
-
if (h_snapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 pe;
}
if (!found_proc)
- {
- UNGCPRO;
- return Qnil;
- }
+ return Qnil;
h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, proc_id);
if (h_proc)
CloseHandle (h_proc);
- UNGCPRO;
return attrs;
}
+int
+w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
+ unsigned long long *totalswap, unsigned long long *freeswap)
+{
+ MEMORYSTATUS memst;
+ MEMORY_STATUS_EX memstex;
+
+ /* Use GlobalMemoryStatusEx if available, as it can report more than
+ 2GB of memory. */
+ if (global_memory_status_ex (&memstex))
+ {
+ *totalram = memstex.ullTotalPhys;
+ *freeram = memstex.ullAvailPhys;
+ *totalswap = memstex.ullTotalPageFile;
+ *freeswap = memstex.ullAvailPageFile;
+ return 0;
+ }
+ else if (global_memory_status (&memst))
+ {
+ *totalram = memst.dwTotalPhys;
+ *freeram = memst.dwAvailPhys;
+ *totalswap = memst.dwTotalPageFile;
+ *freeswap = memst.dwAvailPageFile;
+ return 0;
+ }
+ else
+ return -1;
+}
+
\f
/* Wrappers for winsock functions to map between our file descriptors
and winsock's handles; also set h_errno for convenience.
void (PASCAL *pfn_WSASetLastError) (int iError);
int (PASCAL *pfn_WSAGetLastError) (void);
int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
+int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
+ WSANETWORKEVENTS *NetworkEvents);
+
HANDLE (PASCAL *pfn_WSACreateEvent) (void);
int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
int (PASCAL *pfn_socket) (int af, int type, int protocol);
LOAD_PROC (WSASetLastError);
LOAD_PROC (WSAGetLastError);
LOAD_PROC (WSAEventSelect);
+ LOAD_PROC (WSAEnumNetworkEvents);
LOAD_PROC (WSACreateEvent);
LOAD_PROC (WSACloseEvent);
LOAD_PROC (socket);
case WSAEMFILE: errno = EMFILE; break;
case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
case WSAENOTEMPTY: errno = ENOTEMPTY; break;
+ case WSAEWOULDBLOCK: errno = EWOULDBLOCK; break;
+ case WSAENOTCONN: errno = ENOTCONN; break;
default: errno = wsa_err; break;
}
}
if (winsock_lib == NULL)
{
errno = ENETDOWN;
- return INVALID_SOCKET;
+ return -1;
}
check_errno ();
though the socket wasn't really a kernel handle,
because a real handle has the same value. So
test whether the new handle really is a socket. */
- long nonblocking = 0;
+ unsigned long nonblocking = 0;
if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
{
pfn_closesocket (s);
{
int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
if (rc == SOCKET_ERROR)
- set_errno ();
+ {
+ set_errno ();
+ /* If this is a non-blocking 'connect', set the bit in flags
+ that will tell reader_thread to wait for connection
+ before trying to read. */
+ if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
+ {
+ errno = EINPROGRESS; /* that's what process.c expects */
+ fd_info[s].flags |= FILE_CONNECT;
+ }
+ }
return rc;
}
errno = ENOTSOCK;
int rc;
unsigned flags;
- eassert (pipe2_flags == O_CLOEXEC);
+ eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
/* make pipe handles non-inheritable; when we spawn a child, we
replace the relevant handle with an inheritable one. Also put
emacs_abort ();
}
+ if ((fd_info[fd].flags & FILE_CONNECT) != 0)
+ DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
cp->status = STATUS_READ_IN_PROGRESS;
if (fd_info[fd].flags & FILE_PIPE)
return cp->status;
}
+int
+_sys_wait_connect (int fd)
+{
+ HANDLE hEv;
+ child_process * cp;
+ int rc;
+
+ if (fd < 0 || fd >= MAXDESC)
+ return STATUS_READ_ERROR;
+
+ cp = fd_info[fd].cp;
+ if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
+ return STATUS_READ_ERROR;
+
+ cp->status = STATUS_READ_FAILED;
+
+ hEv = pfn_WSACreateEvent ();
+ rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
+ if (rc != SOCKET_ERROR)
+ {
+ do {
+ rc = WaitForSingleObject (hEv, 500);
+ Sleep (5);
+ } while (rc == WAIT_TIMEOUT
+ && cp->status != STATUS_READ_ERROR
+ && cp->char_avail);
+ if (rc == WAIT_OBJECT_0)
+ {
+ /* We've got an event, but it could be a successful
+ connection, or it could be a failure. Find out
+ which one is it. */
+ WSANETWORKEVENTS events;
+
+ pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
+ if ((events.lNetworkEvents & FD_CONNECT) != 0
+ && events.iErrorCode[FD_CONNECT_BIT])
+ {
+ cp->status = STATUS_CONNECT_FAILED;
+ cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
+ }
+ else
+ {
+ cp->status = STATUS_READ_SUCCEEDED;
+ cp->errcode = 0;
+ }
+ }
+ pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
+ }
+ else
+ pfn_WSACloseEvent (hEv);
+
+ return cp->status;
+}
+
int
sys_read (int fd, char * buffer, unsigned int count)
{
ResetEvent (cp->char_avail);
case STATUS_READ_ACKNOWLEDGED:
+ case STATUS_CONNECT_FAILED:
break;
default:
{
if (winsock_lib == NULL) emacs_abort ();
- /* do the equivalent of a non-blocking read */
+ /* When a non-blocking 'connect' call fails,
+ wait_reading_process_output detects this by calling
+ 'getpeername', and then attempts to obtain the connection
+ error code by trying to read 1 byte from the socket. If
+ we try to serve that read by calling 'recv' below, the
+ error we get is a generic WSAENOTCONN, not the actual
+ connection error. So instead, we use the actual error
+ code stashed by '_sys_wait_connect' in cp->errcode.
+ Alternatively, we could have used 'getsockopt', like on
+ GNU/Linux, but: (a) I have no idea whether the winsock
+ version could hang, as it does "on some systems" (see the
+ comment in process.c); and (b) 'getsockopt' on Windows is
+ documented to clear the socket error for the entire
+ process, which I'm not sure is TRT; FIXME. */
+ if (current_status == STATUS_CONNECT_FAILED
+ && (fd_info[fd].flags & FILE_CONNECT) != 0
+ && cp->errcode != 0)
+ {
+ pfn_WSASetLastError (cp->errcode);
+ set_errno ();
+ return -1;
+ }
+ /* Do the equivalent of a non-blocking read. */
pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
if (waiting == 0 && nchars == 0)
{
int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
if (res == SOCKET_ERROR)
{
- DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
- pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
set_errno ();
+ DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
+ errno, SOCK_HANDLE (fd)));
return -1;
}
nchars += res;
sys_write (int fd, const void * buffer, unsigned int count)
{
int nchars;
+ USE_SAFE_ALLOCA;
if (fd < 0)
{
/* Perform text mode translation if required. */
if ((fd_info[fd].flags & FILE_BINARY) == 0)
{
- char * tmpbuf = alloca (count * 2);
- unsigned char * src = (void *)buffer;
- unsigned char * dst = tmpbuf;
+ char * tmpbuf;
+ const unsigned char * src = buffer;
+ unsigned char * dst;
int nbytes = count;
+ SAFE_NALLOCA (tmpbuf, 2, count);
+ dst = (unsigned char *)tmpbuf;
+
while (1)
{
unsigned char *next;
- /* copy next line or remaining bytes */
+ /* Copy next line or remaining bytes. */
next = _memccpy (dst, src, '\n', nbytes);
if (next)
{
- /* copied one line ending with '\n' */
+ /* Copied one line ending with '\n'. */
int copied = next - dst;
nbytes -= copied;
src += copied;
- /* insert '\r' before '\n' */
+ /* Insert '\r' before '\n'. */
next[-1] = '\r';
next[0] = '\n';
dst = next + 1;
count++;
}
else
- /* copied remaining partial line -> now finished */
+ /* Copied remaining partial line -> now finished. */
break;
}
buffer = tmpbuf;
HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
DWORD active = 0;
+ /* This is async (a.k.a. "overlapped") I/O, so the return value
+ of FALSE from WriteFile means either an error or the output
+ will be completed asynchronously (ERROR_IO_PENDING). */
if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
{
if (GetLastError () != ERROR_IO_PENDING)
{
errno = EIO;
- return -1;
+ nchars = -1;
}
- if (detect_input_pending ())
- active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
- QS_ALLINPUT);
else
- active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
- if (active == WAIT_OBJECT_0)
- { /* User pressed C-g, cancel write, then leave. Don't bother
- cleaning up as we may only get stuck in buggy drivers. */
- PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
- CancelIo (hnd);
- errno = EIO;
- return -1;
- }
- if (active == WAIT_OBJECT_0 + 1
- && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
{
- errno = EIO;
- return -1;
+ /* Wait for the write to complete, and watch C-g while
+ at that. */
+ if (detect_input_pending ())
+ active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
+ INFINITE, QS_ALLINPUT);
+ else
+ active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
+ switch (active)
+ {
+ case WAIT_OBJECT_0:
+ /* User pressed C-g, cancel write, then leave.
+ Don't bother cleaning up as we may only get stuck
+ in buggy drivers. */
+ PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
+ CancelIo (hnd);
+ errno = EIO; /* Why not EINTR? */
+ nchars = -1;
+ break;
+ case WAIT_OBJECT_0 + 1:
+ if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
+ {
+ errno = EIO;
+ nchars = -1;
+ }
+ break;
+ }
}
}
}
}
}
+ SAFE_FREE ();
return nchars;
}
/* Possibly truncated */
? make_specified_string (name, -1, len, 1)
: Qnil);
+ /* This prevents thread start and end notifications
+ from being sent to the DLL, for every thread we
+ start. We don't need those notifications because
+ threads we create never use any of these DLLs, only
+ the main thread uses them. This is supposed to
+ speed up thread creation. */
+ DisableThreadLibraryCalls (dll_handle);
break;
}
}
if (fd < 0)
{
Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
- char *init_file_name = SDATA (init_file);
- char *load_path = SDATA (load_path_print);
+ char *init_file_name = SSDATA (init_file);
+ char *load_path = SSDATA (load_path_print);
char *buffer = alloca (1024
+ strlen (init_file_name)
+ strlen (load_path));
pointers, and assign the correct addresses to these
pointers at program startup (see emacs.c, which calls
this function early on). */
- pMultiByteToWideChar = GetProcAddress (ret, "MultiByteToWideChar");
- pWideCharToMultiByte = GetProcAddress (ret, "WideCharToMultiByte");
+ pMultiByteToWideChar =
+ (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
+ pWideCharToMultiByte =
+ (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
return ret;
}
else
g_b_init_set_named_security_info_w = 0;
g_b_init_set_named_security_info_a = 0;
g_b_init_get_adapters_info = 0;
+ g_b_init_compare_string_w = 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
w32_unicode_filenames = 0;
else
w32_unicode_filenames = 1;
+
+#ifdef HAVE_MODULES
+ extern void dynlib_reset_last_error (void);
+ dynlib_reset_last_error ();
+#endif
}
/* For make-serial-process */
pset_childp (p, childp2);
}
+/* For make-pipe-process */
+void
+register_aux_fd (int infd)
+{
+ child_process *cp;
+
+ cp = new_child ();
+ if (!cp)
+ error ("Could not create child process");
+ cp->fd = infd;
+ cp->status = STATUS_READ_ACKNOWLEDGED;
+
+ if (fd_info[ infd ].cp != NULL)
+ {
+ error ("fd_info[fd = %d] is already in use", infd);
+ }
+ fd_info[ infd ].cp = cp;
+ fd_info[ infd ].hnd = (HANDLE) _get_osfhandle (infd);
+}
+
#ifdef HAVE_GNUTLS
ssize_t
emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
{
int n, err;
- SELECT_TYPE fdset;
- struct timespec timeout;
struct Lisp_Process *process = (struct Lisp_Process *)p;
int fd = process->infd;