X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/8e9166c92c97e7c2041eecee4e00d412a1eca1be..0e963201d03d9229bb8ac4323291d2b0119526ed:/src/w32.c
diff --git a/src/w32.c b/src/w32.c
index 31b13289b5..c77ed87b00 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -1,6 +1,6 @@
/* 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.
@@ -67,7 +67,7 @@ along with GNU Emacs. If not, see . */
#undef localtime
#include "lisp.h"
-#include "epaths.h" /* for SHELL */
+#include "epaths.h" /* for PATH_EXEC */
#include
#include
@@ -224,20 +224,22 @@ typedef struct _REPARSE_DATA_BUFFER {
#include /* should be after winsock2.h */
+#include
+
#include "w32.h"
#include
#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 *);
@@ -1490,7 +1492,7 @@ static int file_name_codepage;
/* 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
@@ -1511,7 +1513,7 @@ codepage_for_filenames (CPINFO *cp_info)
if (NILP (current_encoding))
{
- char *cpname = SDATA (SYMBOL_NAME (current_encoding));
+ char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
char *cp = NULL, *end;
int cpnum;
@@ -2163,11 +2165,11 @@ unixtodos_filename (register char *p)
(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;
@@ -2384,7 +2386,7 @@ ansi_encode_filename (Lisp_Object filename)
{
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);
@@ -3399,30 +3401,41 @@ sys_readdir (DIR *dirp)
/* 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);
if (!IS_DIRECTORY_SEP (filename[ln - 1]))
- filename[ln++] = '\\';
- strcpy (filename + ln, "*");
+ 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. */
@@ -3433,17 +3446,52 @@ sys_readdir (DIR *dirp)
}
if (dir_find_handle == INVALID_HANDLE_VALUE)
- return NULL;
+ {
+ /* Any changes in the value of errno here should be in sync
+ with what directory_files_internal does when it calls
+ readdir. */
+ switch (GetLastError ())
+ {
+ /* 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:
+ 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
@@ -3545,7 +3593,11 @@ open_unc_volume (const char *path)
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 *
@@ -3776,7 +3828,7 @@ faccessat (int dirfd, const char * path, int mode, int flags)
errno = EACCES;
return -1;
}
- break;
+ goto check_attrs;
}
/* FALLTHROUGH */
case ERROR_FILE_NOT_FOUND:
@@ -3789,6 +3841,8 @@ faccessat (int dirfd, const char * path, int mode, int flags)
}
return -1;
}
+
+ check_attrs:
if ((mode & X_OK) != 0
&& !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
{
@@ -3808,6 +3862,76 @@ faccessat (int dirfd, const char * path, int mode, int flags)
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
@@ -4412,6 +4536,8 @@ sys_rmdir (const char * path)
int
sys_unlink (const char * path)
{
+ int rmstatus, e;
+
path = map_w32_filename (path, NULL);
if (w32_unicode_filenames)
@@ -4419,9 +4545,18 @@ sys_unlink (const char * path)
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
{
@@ -4429,8 +4564,17 @@ sys_unlink (const char * path)
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;
@@ -5504,7 +5648,8 @@ symlink (char const *filename, char const *linkname)
/* 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
@@ -5562,6 +5707,8 @@ is_symlink (const char *filename)
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, "?"))
{
@@ -5575,6 +5722,8 @@ is_symlink (const char *filename)
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;
@@ -6505,7 +6654,6 @@ global_memory_status_ex (MEMORY_STATUS_EX *buf)
Lisp_Object
list_system_processes (void)
{
- struct gcpro gcpro1;
Lisp_Object proclist = Qnil;
HANDLE h_snapshot;
@@ -6517,8 +6665,6 @@ list_system_processes (void)
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))
@@ -6528,7 +6674,6 @@ list_system_processes (void)
}
CloseHandle (h_snapshot);
- UNGCPRO;
proclist = Fnreverse (proclist);
}
@@ -6657,7 +6802,6 @@ process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
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;
@@ -6689,8 +6833,6 @@ system_process_attributes (Lisp_Object pid)
h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
- GCPRO3 (attrs, decoded_cmd, tem);
-
if (h_snapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 pe;
@@ -6732,10 +6874,7 @@ system_process_attributes (Lisp_Object pid)
}
if (!found_proc)
- {
- UNGCPRO;
- return Qnil;
- }
+ return Qnil;
h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, proc_id);
@@ -6952,7 +7091,6 @@ system_process_attributes (Lisp_Object pid)
if (h_proc)
CloseHandle (h_proc);
- UNGCPRO;
return attrs;
}
@@ -6999,6 +7137,9 @@ int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
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);
@@ -7084,6 +7225,7 @@ init_winsock (int load_now)
LOAD_PROC (WSASetLastError);
LOAD_PROC (WSAGetLastError);
LOAD_PROC (WSAEventSelect);
+ LOAD_PROC (WSAEnumNetworkEvents);
LOAD_PROC (WSACreateEvent);
LOAD_PROC (WSACloseEvent);
LOAD_PROC (socket);
@@ -7167,6 +7309,8 @@ set_errno (void)
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;
}
}
@@ -7288,7 +7432,7 @@ sys_socket (int af, int type, int protocol)
if (winsock_lib == NULL)
{
errno = ENETDOWN;
- return INVALID_SOCKET;
+ return -1;
}
check_errno ();
@@ -7351,7 +7495,7 @@ socket_to_fd (SOCKET s)
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);
@@ -7434,7 +7578,17 @@ sys_connect (int s, const struct sockaddr * name, int namelen)
{
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;
@@ -7945,6 +8099,8 @@ _sys_read_ahead (int fd)
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)
@@ -8066,6 +8222,60 @@ _sys_wait_accept (int fd)
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)
{
@@ -8135,6 +8345,7 @@ sys_read (int fd, char * buffer, unsigned int count)
ResetEvent (cp->char_avail);
case STATUS_READ_ACKNOWLEDGED:
+ case STATUS_CONNECT_FAILED:
break;
default:
@@ -8200,7 +8411,29 @@ sys_read (int fd, char * buffer, unsigned int count)
{
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)
{
@@ -8214,9 +8447,9 @@ sys_read (int fd, char * buffer, unsigned int count)
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;
@@ -8287,7 +8520,7 @@ sys_write (int fd, const void * buffer, unsigned int count)
int nbytes = count;
SAFE_NALLOCA (tmpbuf, 2, count);
- dst = tmpbuf;
+ dst = (unsigned char *)tmpbuf;
while (1)
{
@@ -8829,8 +9062,8 @@ check_windows_init_file (void)
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));
@@ -9037,8 +9270,10 @@ maybe_load_unicows_dll (void)
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
@@ -9146,6 +9381,11 @@ globals_of_w32 (void)
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 */
@@ -9339,6 +9579,26 @@ serial_configure (struct Lisp_Process *p, Lisp_Object contact)
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