/* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
- Copyright (C) 1994, 1995, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004,
+ 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
Geoff Voelker (voelker@cs.washington.edu) 7-29-94
*/
-
-
#include <stddef.h> /* for offsetof */
#include <stdlib.h>
#include <stdio.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/utime.h>
+#include <mbstring.h> /* for _mbspbrk */
/* must include CRT headers *before* config.h */
#define _ANONYMOUS_STRUCT
#endif
#include <windows.h>
+#include <shlobj.h>
#ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
#include <sys/socket.h>
#include "w32heap.h"
#include "systime.h"
+typedef HRESULT (WINAPI * ShGetFolderPath_fn)
+ (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
+
void globals_of_w32 ();
extern Lisp_Object Vw32_downcase_file_names;
\f
/*
- Initialization states
+ Initialization states
*/
static BOOL g_b_init_is_windows_9x;
static BOOL g_b_init_open_process_token;
PSID pSid);
/* ** A utility function ** */
-static BOOL is_windows_9x ()
+static BOOL
+is_windows_9x ()
{
static BOOL s_b_ret=0;
OSVERSIONINFO os_ver;
return buf;
}
+/* Return 1 if P is a valid pointer to an object of size SIZE. Return
+ 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
+
+ This is called from alloc.c:valid_pointer_p. */
+int
+w32_valid_pointer_p (void *p, int size)
+{
+ SIZE_T done;
+ HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
+
+ if (h)
+ {
+ unsigned char *buf = alloca (size);
+ int retval = ReadProcessMemory (h, p, buf, size, &done);
+
+ CloseHandle (h);
+ return retval;
+ }
+ else
+ return -1;
+}
+
static char startup_dir[MAXPATHLEN];
/* Get the current working directory. */
the user-sid as the user id value (same for group id using the
primary group sid from the process token). */
- char user_sid[256], name[256], domain[256];
- DWORD length = sizeof (name), dlength = sizeof (domain), trash;
- HANDLE token = NULL;
- SID_NAME_USE user_type;
-
- if (
- open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
- && get_token_information (
- token, TokenUser,
- (PVOID) user_sid, sizeof (user_sid), &trash)
- && lookup_account_sid (
- NULL, *((PSID *) user_sid), name, &length,
- domain, &dlength, &user_type)
- )
+ char user_sid[256], name[256], domain[256];
+ DWORD length = sizeof (name), dlength = sizeof (domain), trash;
+ HANDLE token = NULL;
+ SID_NAME_USE user_type;
+
+ if (open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
+ && get_token_information (token, TokenUser,
+ (PVOID) user_sid, sizeof (user_sid), &trash)
+ && lookup_account_sid (NULL, *((PSID *) user_sid), name, &length,
+ domain, &dlength, &user_type))
{
strcpy (the_passwd.pw_name, name);
/* Determine a reasonable uid value. */
/* Get group id */
if (get_token_information (token, TokenPrimaryGroup,
- (PVOID) user_sid, sizeof (user_sid), &trash))
+ (PVOID) user_sid, sizeof (user_sid), &trash))
{
SID_IDENTIFIER_AUTHORITY * pSIA;
}
}
/* If security calls are not supported (presumably because we
- are running under Windows 95), fallback to this. */
+ are running under Windows 95), fallback to this. */
else if (GetUserName (name, &length))
{
strcpy (the_passwd.pw_name, name);
int len = 0;
/* must be valid filename, no wild cards or other invalid characters */
- if (strpbrk (name, "*?|<>\""))
+ if (_mbspbrk (name, "*?|<>\""))
return 0;
dir_handle = FindFirstFile (name, &find_data);
if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
return 0;
- if (strpbrk (ptr + 2, "*?|<>\"\\/"))
+ if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
return 0;
return 1;
static const char * const tempdirs[] = {
"$TMPDIR", "$TEMP", "$TMP", "c:/"
};
+
int i;
+
const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
/* Make sure they have a usable $TMPDIR. Many Emacs functions use
LPBYTE lpval;
DWORD dwType;
char locale_name[32];
+ struct stat ignored;
+ char default_home[MAX_PATH];
- static struct env_entry
+ static const struct env_entry
{
char * name;
char * def_value;
- } env_vars[] =
+ } dflt_envvars[] =
{
{"HOME", "C:/"},
{"PRELOAD_WINSOCK", NULL},
{"LANG", NULL},
};
+#define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
+
+ /* We need to copy dflt_envvars[] and work on the copy because we
+ don't want the dumped Emacs to inherit the values of
+ environment variables we saw during dumping (which could be on
+ a different system). The defaults above must be left intact. */
+ struct env_entry env_vars[N_ENV_VARS];
+
+ for (i = 0; i < N_ENV_VARS; i++)
+ env_vars[i] = dflt_envvars[i];
+
+ /* For backwards compatibility, check if a .emacs file exists in C:/
+ If not, then we can try to default to the appdata directory under the
+ user's profile, which is more likely to be writable. */
+ if (stat ("C:/.emacs", &ignored) < 0)
+ {
+ HRESULT profile_result;
+ /* Dynamically load ShGetFolderPath, as it won't exist on versions
+ of Windows 95 and NT4 that have not been updated to include
+ MSIE 5. Also we don't link with shell32.dll by default. */
+ HMODULE shell32_dll;
+ ShGetFolderPath_fn get_folder_path;
+ shell32_dll = GetModuleHandle ("shell32.dll");
+ get_folder_path = (ShGetFolderPath_fn)
+ GetProcAddress (shell32_dll, "SHGetFolderPathA");
+
+ if (get_folder_path != NULL)
+ {
+ profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
+ 0, default_home);
+
+ /* If we can't get the appdata dir, revert to old behaviour. */
+ if (profile_result == S_OK)
+ env_vars[0].def_value = default_home;
+ }
+
+ /* Unload shell32.dll, it is not needed anymore. */
+ FreeLibrary (shell32_dll);
+ }
+
/* Get default locale info and use it for LANG. */
if (GetLocaleInfo (LOCALE_USER_DEFAULT,
LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
locale_name, sizeof (locale_name)))
{
- for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
+ for (i = 0; i < N_ENV_VARS; i++)
{
if (strcmp (env_vars[i].name, "LANG") == 0)
{
}
}
- for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
+ for (i = 0; i < N_ENV_VARS; i++)
{
if (!getenv (env_vars[i].name))
{
int dont_free = 0;
- if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL)
+ if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
+ /* Also ignore empty environment variables. */
+ || *lpval == 0)
{
lpval = env_vars[i].def_value;
dwType = REG_EXPAND_SZ;
if (lpval)
{
- if (dwType == REG_EXPAND_SZ)
- {
- char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
+ char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
- ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
- _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name, buf1);
- _putenv (strdup (buf2));
- }
+ if (dwType == REG_EXPAND_SZ)
+ ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
else if (dwType == REG_SZ)
+ strcpy (buf1, lpval);
+ if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
{
- char buf[SET_ENV_BUF_SIZE];
-
- _snprintf (buf, sizeof(buf)-1, "%s=%s", env_vars[i].name, lpval);
- _putenv (strdup (buf));
+ _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name,
+ buf1);
+ _putenv (strdup (buf2));
}
if (!dont_free)
return _chmod (map_w32_filename (path, NULL), mode);
}
+int
+sys_chown (const char *path, uid_t owner, gid_t group)
+{
+ if (sys_chmod (path, _S_IREAD) == -1) /* check if file exists */
+ return -1;
+ return 0;
+}
+
int
sys_creat (const char * path, int mode)
{
SystemTimeToFileTime (&st, &utc_base_ft);
utc_base = (long double) utc_base_ft.dwHighDateTime
- * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
+ * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
init = 1;
}
if (CompareFileTime (&ft, &utc_base_ft) < 0)
return 0;
- ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
+ ret = (long double) ft.dwHighDateTime
+ * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
ret -= utc_base;
- return (time_t) (ret * 1e-7);
+ return (time_t) (ret * 1e-7L);
}
void
}
name = (char *) map_w32_filename (path, &path);
- /* must be valid filename, no wild cards or other invalid characters */
- if (strpbrk (name, "*?|<>\""))
+ /* Must be valid filename, no wild cards or other invalid
+ characters. We use _mbspbrk to support multibyte strings that
+ might look to strpbrk as if they included literal *, ?, and other
+ characters mentioned below that are disallowed by Windows
+ filesystems. */
+ if (_mbspbrk (name, "*?|<>\""))
{
errno = ENOENT;
return -1;
!= INVALID_HANDLE_VALUE)
{
/* This is more accurate in terms of gettting the correct number
- of links, but is quite slow (it is noticable when Emacs is
+ of links, but is quite slow (it is noticeable when Emacs is
making a list of file name completions). */
BY_HANDLE_FILE_INFORMATION info;
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);
+HANDLE (PASCAL *pfn_WSACreateEvent) (void);
+int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
int (PASCAL *pfn_socket) (int af, int type, int protocol);
int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
= (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
"SetHandleInformation");
- winsock_lib = LoadLibrary ("wsock32.dll");
+ winsock_lib = LoadLibrary ("Ws2_32.dll");
if (winsock_lib != NULL)
{
LOAD_PROC( WSAStartup );
LOAD_PROC( WSASetLastError );
LOAD_PROC( WSAGetLastError );
+ LOAD_PROC( WSAEventSelect );
+ LOAD_PROC( WSACreateEvent );
+ LOAD_PROC( WSACloseEvent );
LOAD_PROC( socket );
LOAD_PROC( bind );
LOAD_PROC( connect );
/* function to set h_errno for compatability; map winsock error codes to
normal system codes where they overlap (non-overlapping definitions
are already in <sys/socket.h> */
-static void set_errno ()
+static void
+set_errno ()
{
if (winsock_lib == NULL)
h_errno = EINVAL;
errno = h_errno;
}
-static void check_errno ()
+static void
+check_errno ()
{
if (h_errno == 0 && winsock_lib != NULL)
pfn_WSASetLastError (0);
WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
WSAEINVALIDPROVIDER , "Invalid service provider version number",
WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
- WSASYSCALLFAILURE , "System call failured",
+ WSASYSCALLFAILURE , "System call failure",
WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
WSATYPE_NOT_FOUND , "Class type not found",
WSA_E_NO_MORE , "No more resources available", /* really not sure */
int rc = pfn_listen (SOCK_HANDLE (s), backlog);
if (rc == SOCKET_ERROR)
set_errno ();
+ else
+ fd_info[s].flags |= FILE_LISTEN;
return rc;
}
h_errno = ENOTSOCK;
}
check_errno ();
- if (fd_info[s].flags & FILE_SOCKET)
+ if (fd_info[s].flags & FILE_LISTEN)
{
SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
- if (t != INVALID_SOCKET)
- return socket_to_fd (t);
+ int fd = -1;
+ if (t == INVALID_SOCKET)
+ set_errno ();
+ else
+ fd = socket_to_fd (t);
- set_errno ();
- return -1;
+ fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
+ ResetEvent (fd_info[s].cp->char_avail);
+ return fd;
}
h_errno = ENOTSOCK;
return -1;
{
int rc;
- if (fd < 0 || fd >= MAXDESC)
+ if (fd < 0)
{
errno = EBADF;
return -1;
}
- if (fd_info[fd].cp)
+ if (fd < MAXDESC && fd_info[fd].cp)
{
child_process * cp = fd_info[fd].cp;
because socket handles are fully fledged kernel handles. */
rc = _close (fd);
- if (rc == 0)
+ if (rc == 0 && fd < MAXDESC)
fd_info[fd].flags = 0;
return rc;
int new_fd;
new_fd = _dup (fd);
- if (new_fd >= 0)
+ if (new_fd >= 0 && new_fd < MAXDESC)
{
/* duplicate our internal info as well */
fd_info[new_fd] = fd_info[fd];
return cp->status;
}
+int
+_sys_wait_accept (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_ACCEPT);
+ if (rc != SOCKET_ERROR)
+ {
+ rc = WaitForSingleObject (hEv, INFINITE);
+ pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
+ if (rc == WAIT_OBJECT_0)
+ cp->status = STATUS_READ_SUCCEEDED;
+ }
+ pfn_WSACloseEvent (hEv);
+
+ return cp->status;
+}
+
int
sys_read (int fd, char * buffer, unsigned int count)
{
DWORD waiting;
char * orig_buffer = buffer;
- if (fd < 0 || fd >= MAXDESC)
+ if (fd < 0)
{
errno = EBADF;
return -1;
}
- if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
+ if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
{
child_process *cp = fd_info[fd].cp;
{
int nchars;
- if (fd < 0 || fd >= MAXDESC)
+ if (fd < 0)
{
errno = EBADF;
return -1;
}
- if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
+ if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
{
if ((fd_info[fd].flags & FILE_WRITE) == 0)
{
}
#ifdef HAVE_SOCKETS
- if (fd_info[fd].flags & FILE_SOCKET)
+ if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
{
unsigned long nblock = 0;
if (winsock_lib == NULL) abort ();
objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
full_load_path = Fappend (2, objs);
init_file = build_string ("term/w32-win");
- fd = openp (full_load_path, init_file, Vload_suffixes, NULL, Qnil);
+ fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
if (fd < 0)
{
Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
char *init_file_name = SDATA (init_file);
char *load_path = SDATA (load_path_print);
- char *buffer = alloca (1024);
+ char *buffer = alloca (1024
+ + strlen (init_file_name)
+ + strlen (load_path));
sprintf (buffer,
"The Emacs Windows initialization file \"%s.el\" "
check_windows_init_file ();
}
+/*
+ shutdown_handler ensures that buffers' autosave files are
+ up to date when the user logs off, or the system shuts down.
+*/
+BOOL WINAPI shutdown_handler(DWORD type)
+{
+ /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
+ if (type == CTRL_CLOSE_EVENT /* User closes console window. */
+ || type == CTRL_LOGOFF_EVENT /* User logs off. */
+ || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
+ {
+ /* Shut down cleanly, making sure autosave files are up to date. */
+ shut_down_emacs (0, 0, Qnil);
+ }
+
+ /* Allow other handlers to handle this signal. */
+ return FALSE;
+}
+
/*
globals_of_w32 is used to initialize those global variables that
must always be initialized on startup even when the global variable
initialized is non zero (see the function main in emacs.c).
*/
-void globals_of_w32 ()
+void
+globals_of_w32 ()
{
g_b_init_is_windows_9x = 0;
g_b_init_open_process_token = 0;
g_b_init_get_token_information = 0;
g_b_init_lookup_account_sid = 0;
g_b_init_get_sid_identifier_authority = 0;
+ /* The following sets a handler for shutdown notifications for
+ console apps. This actually applies to Emacs in both console and
+ GUI modes, since we had to fool windows into thinking emacs is a
+ console application to get console mode to work. */
+ SetConsoleCtrlHandler(shutdown_handler, TRUE);
}
-/* end of nt.c */
+/* end of w32.c */
/* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
(do not change this comment) */