#include <ctype.h>
#include <signal.h>
#include <sys/file.h>
+#include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
#include <sys/time.h>
#include <sys/utime.h>
#include <math.h>
-#include <time.h>
/* must include CRT headers *before* config.h */
#undef fopen
#undef link
#undef mkdir
-#undef mktemp
#undef open
#undef rename
#undef rmdir
#undef localtime
#include "lisp.h"
+#include "epaths.h" /* for SHELL */
#include <pwd.h>
#include <grp.h>
-#ifdef __GNUC__
+/* MinGW64 (_W64) defines these in its _mingw.h. */
+#if defined(__GNUC__) && !defined(_W64)
#define _ANONYMOUS_UNION
#define _ANONYMOUS_STRUCT
#endif
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 <lmcons.h>
#include <shlobj.h>
#ifndef _MSC_VER
#include <w32api.h>
#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
SIZE_T PrivateUsage;
} PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
#endif
+#endif
#include <winioctl.h>
#include <aclapi.h>
#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;
#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 <sys/socket.h>
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);
+
\f
{"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},
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))
_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/ */
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 (check_existing (bufc))
+ {
+ 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"),
#include <sys/timeb.h>
/* 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);
tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
tz->tz_dsttime = tb.dstflag; /* type of dst correction */
}
+ return 0;
}
/* Emulate fdutimens. */
int
fdutimens (int fd, char const *file, struct timespec const timespec[2])
{
- struct _utimbuf ut;
-
if (!timespec)
{
errno = ENOSYS;
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);
+ }
}
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;
- 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)
+ /* 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 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 */
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);
- /* Try to open file without _O_CREAT, to be able to write to hidden
- and system files. Force all file handles to be
- non-inheritable. */
- int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
- if (res < 0)
- res = _open (mpath, oflag | _O_NOINHERIT, mode);
- if (res >= 0 && res < MAXDESC)
- fd_info[res].flags = 0;
-
- 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];
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
result = rename (temp, newname);
- if (result < 0)
+ if (result < 0 && force)
{
DWORD w32err = GetLastError ();
return result;
}
+int
+sys_rename (char const *old, char const *new)
+{
+ return sys_rename_replace (old, new, TRUE);
+}
+
int
sys_rmdir (const char * path)
{
/* 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;
return 0;
}
+/* A version of 'utime' which handles directories as well as
+ files. */
+
int
utime (const char *name, struct utimbuf *times)
{
{
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)
{
/* 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);
{
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. */
}
/* 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;
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
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;
/* 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;
ssize_t
emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
{
- int n, sc, err;
+ int n, err;
SELECT_TYPE fdset;
- EMACS_TIME timeout;
+ struct timespec timeout;
struct Lisp_Process *process = (struct Lisp_Process *)p;
int fd = process->infd;
- for (;;)
- {
- n = sys_read (fd, (char*)buf, sz);
+ n = sys_read (fd, (char*)buf, sz);
- if (n >= 0)
- return n;
+ if (n >= 0)
+ return n;
- err = errno;
+ err = errno;
- if (err == EWOULDBLOCK)
- {
- /* Set a small timeout. */
- timeout = make_emacs_time (1, 0);
- FD_ZERO (&fdset);
- FD_SET ((int)fd, &fdset);
-
- /* Use select with the timeout to poll the selector. */
- sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
- &timeout, NULL);
-
- if (sc > 0)
- continue; /* Try again. */
-
- /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
- Also accept select return 0 as an indicator to EAGAIN. */
- if (sc == 0 || errno == EWOULDBLOCK)
- err = EAGAIN;
- else
- err = errno; /* Other errors are just passed on. */
- }
+ /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
+ if (err == EWOULDBLOCK)
+ err = EAGAIN;
- emacs_gnutls_transport_set_errno (process->gnutls_state, err);
+ emacs_gnutls_transport_set_errno (process->gnutls_state, err);
- return -1;
- }
+ return -1;
}
ssize_t