/* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Emacs.
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/utime.h>
/* must include CRT headers *before* config.h */
-#include "config.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#undef access
#undef chdir
#undef chmod
#undef read
#undef write
+#undef strerror
+
#include "lisp.h"
#include <pwd.h>
+#include <grp.h>
+#ifdef __GNUC__
+#define _ANONYMOUS_UNION
+#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>
#undef gethostname
#undef gethostbyname
#undef getservbyname
+#undef getpeername
#undef shutdown
+#undef setsockopt
+#undef listen
+#undef getsockname
+#undef accept
+#undef recvfrom
+#undef sendto
#endif
#include "w32.h"
#include "ndir.h"
#include "w32heap.h"
-
-#undef min
-#undef max
-#define min(x, y) (((x) < (y)) ? (x) : (y))
-#define max(x, y) (((x) > (y)) ? (x) : (y))
+#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;
extern Lisp_Object Vw32_generate_fake_inodes;
extern Lisp_Object Vw32_get_true_file_attributes;
+extern int w32_num_mouse_buttons;
+
+\f
+/*
+ Initialization states
+ */
+static BOOL g_b_init_is_windows_9x;
+static BOOL g_b_init_open_process_token;
+static BOOL g_b_init_get_token_information;
+static BOOL g_b_init_lookup_account_sid;
+static BOOL g_b_init_get_sid_identifier_authority;
+
+/*
+ BEGIN: Wrapper functions around OpenProcessToken
+ and other functions in advapi32.dll that are only
+ supported in Windows NT / 2k / XP
+*/
+ /* ** Function pointer typedefs ** */
+typedef BOOL (WINAPI * OpenProcessToken_Proc) (
+ HANDLE ProcessHandle,
+ DWORD DesiredAccess,
+ PHANDLE TokenHandle);
+typedef BOOL (WINAPI * GetTokenInformation_Proc) (
+ HANDLE TokenHandle,
+ TOKEN_INFORMATION_CLASS TokenInformationClass,
+ LPVOID TokenInformation,
+ DWORD TokenInformationLength,
+ PDWORD ReturnLength);
+#ifdef _UNICODE
+const char * const LookupAccountSid_Name = "LookupAccountSidW";
+#else
+const char * const LookupAccountSid_Name = "LookupAccountSidA";
+#endif
+typedef BOOL (WINAPI * LookupAccountSid_Proc) (
+ LPCTSTR lpSystemName,
+ PSID Sid,
+ LPTSTR Name,
+ LPDWORD cbName,
+ LPTSTR DomainName,
+ LPDWORD cbDomainName,
+ PSID_NAME_USE peUse);
+typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) (
+ PSID pSid);
+
+ /* ** A utility function ** */
+static BOOL is_windows_9x ()
+{
+ static BOOL s_b_ret=0;
+ OSVERSIONINFO os_ver;
+ if (g_b_init_is_windows_9x == 0)
+ {
+ g_b_init_is_windows_9x = 1;
+ ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
+ os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (GetVersionEx (&os_ver))
+ {
+ s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
+ }
+ }
+ return s_b_ret;
+}
+
+ /* ** The wrapper functions ** */
+
+BOOL WINAPI open_process_token (
+ HANDLE ProcessHandle,
+ DWORD DesiredAccess,
+ PHANDLE TokenHandle)
+{
+ static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_open_process_token == 0)
+ {
+ g_b_init_open_process_token = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Open_Process_Token =
+ (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
+ }
+ if (s_pfn_Open_Process_Token == NULL)
+ {
+ return FALSE;
+ }
+ return (
+ s_pfn_Open_Process_Token (
+ ProcessHandle,
+ DesiredAccess,
+ TokenHandle)
+ );
+}
+
+BOOL WINAPI get_token_information (
+ HANDLE TokenHandle,
+ TOKEN_INFORMATION_CLASS TokenInformationClass,
+ LPVOID TokenInformation,
+ DWORD TokenInformationLength,
+ PDWORD ReturnLength)
+{
+ static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_get_token_information == 0)
+ {
+ g_b_init_get_token_information = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Get_Token_Information =
+ (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
+ }
+ if (s_pfn_Get_Token_Information == NULL)
+ {
+ return FALSE;
+ }
+ return (
+ s_pfn_Get_Token_Information (
+ TokenHandle,
+ TokenInformationClass,
+ TokenInformation,
+ TokenInformationLength,
+ ReturnLength)
+ );
+}
+
+BOOL WINAPI lookup_account_sid (
+ LPCTSTR lpSystemName,
+ PSID Sid,
+ LPTSTR Name,
+ LPDWORD cbName,
+ LPTSTR DomainName,
+ LPDWORD cbDomainName,
+ PSID_NAME_USE peUse)
+{
+ static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_lookup_account_sid == 0)
+ {
+ g_b_init_lookup_account_sid = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Lookup_Account_Sid =
+ (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
+ }
+ if (s_pfn_Lookup_Account_Sid == NULL)
+ {
+ return FALSE;
+ }
+ return (
+ s_pfn_Lookup_Account_Sid (
+ lpSystemName,
+ Sid,
+ Name,
+ cbName,
+ DomainName,
+ cbDomainName,
+ peUse)
+ );
+}
+
+PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority (
+ PSID pSid)
+{
+ static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return NULL;
+ }
+ if (g_b_init_get_sid_identifier_authority == 0)
+ {
+ g_b_init_get_sid_identifier_authority = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Get_Sid_Identifier_Authority =
+ (GetSidIdentifierAuthority_Proc) GetProcAddress (
+ hm_advapi32, "GetSidIdentifierAuthority");
+ }
+ if (s_pfn_Get_Sid_Identifier_Authority == NULL)
+ {
+ return NULL;
+ }
+ return (s_pfn_Get_Sid_Identifier_Authority (pSid));
+}
+
+/*
+ END: Wrapper functions around OpenProcessToken
+ and other functions in advapi32.dll that are only
+ supported in Windows NT / 2k / XP
+*/
+
+\f
+/* Equivalent of strerror for W32 error codes. */
+char *
+w32_strerror (int error_no)
+{
+ static char buf[500];
+
+ if (error_no == 0)
+ error_no = GetLastError ();
+
+ buf[0] = '\0';
+ if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
+ error_no,
+ 0, /* choose most suitable language */
+ buf, sizeof (buf), NULL))
+ sprintf (buf, "w32 error %u", error_no);
+ return buf;
+}
static char startup_dir[MAXPATHLEN];
int
gethostname (char *buffer, int size)
{
- /* NT only allows small host names, so the buffer is
+ /* NT only allows small host names, so the buffer is
certainly large enough. */
return !GetComputerName (buffer, &size);
}
int i;
/* A faithful emulation is going to have to be saved for a rainy day. */
- for (i = 0; i < nelem; i++)
+ for (i = 0; i < nelem; i++)
{
loadavg[i] = 0.0;
}
static char the_passwd_dir[PASSWD_FIELD_SIZE];
static char the_passwd_shell[PASSWD_FIELD_SIZE];
-static struct passwd the_passwd =
+static struct passwd the_passwd =
{
the_passwd_name,
the_passwd_passwd,
the_passwd_shell,
};
-int
-getuid ()
-{
+static struct group the_group =
+{
+ /* There are no groups on NT, so we just return "root" as the
+ group name. */
+ "root",
+};
+
+int
+getuid ()
+{
return the_passwd.pw_uid;
}
-int
-geteuid ()
-{
+int
+geteuid ()
+{
/* I could imagine arguing for checking to see whether the user is
in the Administrators group and returning a UID of 0 for that
case, but I don't know how wise that would be in the long run. */
- return getuid ();
+ return getuid ();
}
-int
-getgid ()
-{
+int
+getgid ()
+{
return the_passwd.pw_gid;
}
-int
-getegid ()
-{
+int
+getegid ()
+{
return getgid ();
}
return NULL;
}
+struct group *
+getgrgid (gid_t gid)
+{
+ return &the_group;
+}
+
struct passwd *
getpwnam (char *name)
{
struct passwd *pw;
-
+
pw = getpwuid (getuid ());
if (!pw)
return pw;
HANDLE token = NULL;
SID_NAME_USE user_type;
- if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)
- && GetTokenInformation (token, TokenUser,
+ if (
+ open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
+ && get_token_information (
+ token, TokenUser,
(PVOID) user_sid, sizeof (user_sid), &trash)
- && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,
- domain, &dlength, &user_type))
+ && lookup_account_sid (
+ NULL, *((PSID *) user_sid), name, &length,
+ domain, &dlength, &user_type)
+ )
{
strcpy (the_passwd.pw_name, name);
/* Determine a reasonable uid value. */
{
SID_IDENTIFIER_AUTHORITY * pSIA;
- pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
+ pSIA = get_sid_identifier_authority (*((PSID *) user_sid));
/* I believe the relative portion is the last 4 bytes (of 6)
with msb first. */
the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
the_passwd.pw_uid = the_passwd.pw_uid % 60001;
/* Get group id */
- if (GetTokenInformation (token, TokenPrimaryGroup,
+ if (get_token_information (token, TokenPrimaryGroup,
(PVOID) user_sid, sizeof (user_sid), &trash))
{
SID_IDENTIFIER_AUTHORITY * pSIA;
- pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
+ pSIA = get_sid_identifier_authority (*((PSID *) user_sid));
the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
(pSIA->Value[3] << 16) +
(pSIA->Value[4] << 8) +
/* Ensure HOME and SHELL are defined. */
if (getenv ("HOME") == NULL)
- putenv ("HOME=c:/");
+ abort ();
if (getenv ("SHELL") == NULL)
- putenv (os_subtype == OS_WIN95 ? "SHELL=command" : "SHELL=cmd");
+ abort ();
/* Set dir and shell from environment variables. */
strcpy (the_passwd.pw_dir, getenv ("HOME"));
HANDLE dir_handle;
int len = 0;
- /* must be valid filename, no wild cards or other illegal characters */
+ /* must be valid filename, no wild cards or other invalid characters */
if (strpbrk (name, "*?|<>\""))
return 0;
len = parse_root (full, &p);
memcpy (o, full, len);
o += len;
+ *o = '\0';
size -= len;
- do
+ while (p != NULL && *p)
{
q = p;
p = strchr (q, '\\');
else
return FALSE;
}
- while (p != NULL && *p);
return TRUE;
}
/* Routines that are no-ops on NT but are defined to get Emacs to compile. */
-int
-sigsetmask (int signal_mask)
-{
+int
+sigsetmask (int signal_mask)
+{
+ return 0;
+}
+
+int
+sigmask (int sig)
+{
return 0;
}
-int
-sigblock (int sig)
-{
+int
+sigblock (int sig)
+{
+ return 0;
+}
+
+int
+sigunblock (int sig)
+{
return 0;
}
-int
-setpgrp (int pid, int gid)
-{
+int
+setpgrp (int pid, int gid)
+{
return 0;
}
-int
-alarm (int seconds)
-{
+int
+alarm (int seconds)
+{
return 0;
}
-void
-unrequest_sigio (void)
-{
+void
+unrequest_sigio (void)
+{
return;
}
void
-request_sigio (void)
-{
+request_sigio (void)
+{
return;
}
#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
-LPBYTE
+LPBYTE
w32_get_resource (key, lpdwtype)
char *key;
LPDWORD lpdwtype;
HKEY hrootkey = NULL;
DWORD cbData;
BOOL ok = FALSE;
-
- /* Check both the current user and the local machine to see if
+
+ /* Check both the current user and the local machine to see if
we have any resources. */
-
+
if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
{
lpvalue = NULL;
- if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
- && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
+ if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
+ && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
&& RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
{
return (lpvalue);
}
if (lpvalue) xfree (lpvalue);
-
+
RegCloseKey (hrootkey);
- }
-
+ }
+
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
{
lpvalue = NULL;
-
+
if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
&& (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
&& RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
{
return (lpvalue);
}
-
+
if (lpvalue) xfree (lpvalue);
-
+
RegCloseKey (hrootkey);
- }
-
+ }
+
return (NULL);
}
extern Lisp_Object Vsystem_configuration;
void
-init_environment ()
+init_environment (char ** argv)
{
- int len;
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
read-only filesystem, like CD-ROM or a write-protected floppy.
The only way to be really sure is to actually create a file and
see if it succeeds. But I think that's too much to ask. */
- if (tmp && access (tmp, D_OK) == 0)
+ if (tmp && _access (tmp, D_OK) == 0)
{
char * var = alloca (strlen (tmp) + 8);
sprintf (var, "TMPDIR=%s", tmp);
- putenv (var);
+ _putenv (strdup (var));
break;
}
}
Qnil)),
"While setting TMPDIR: ");
- /* Check for environment variables and use registry if they don't exist */
+ /* Check for environment variables and use registry settings if they
+ don't exist. Fallback on default values where applicable. */
{
int i;
LPBYTE lpval;
DWORD dwType;
-
- static char * env_vars[] =
- {
- "HOME",
- "PRELOAD_WINSOCK",
- "emacs_dir",
- "EMACSLOADPATH",
- "SHELL",
- "CMDPROXY",
- "EMACSDATA",
- "EMACSPATH",
- "EMACSLOCKDIR",
+ char locale_name[32];
+ struct stat ignored;
+ char default_home[MAX_PATH];
+
+ static struct env_entry
+ {
+ char * name;
+ char * def_value;
+ } env_vars[] =
+ {
+ {"HOME", "C:/"},
+ {"PRELOAD_WINSOCK", NULL},
+ {"emacs_dir", "C:/emacs"},
+ {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
+ {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
+ {"EMACSDATA", "%emacs_dir%/etc"},
+ {"EMACSPATH", "%emacs_dir%/bin"},
/* We no longer set INFOPATH because Info-default-directory-list
- is then ignored. We use a hook in winnt.el instead. */
- /* "INFOPATH", */
- "EMACSDOC",
- "TERM",
+ is then ignored. */
+ /* {"INFOPATH", "%emacs_dir%/info"}, */
+ {"EMACSDOC", "%emacs_dir%/etc"},
+ {"TERM", "cmd"},
+ {"LANG", NULL},
};
- for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); 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++)
+ {
+ if (strcmp (env_vars[i].name, "LANG") == 0)
+ {
+ env_vars[i].def_value = locale_name;
+ break;
+ }
+ }
+ }
+
+#define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
+
+ /* Treat emacs_dir specially: set it unconditionally based on our
+ location, if it appears that we are running from the bin subdir
+ of a standard installation. */
+ {
+ char *p;
+ char modname[MAX_PATH];
+
+ if (!GetModuleFileName (NULL, modname, MAX_PATH))
+ abort ();
+ if ((p = strrchr (modname, '\\')) == NULL)
+ abort ();
+ *p = 0;
+
+ if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 0)
+ {
+ char buf[SET_ENV_BUF_SIZE];
+
+ *p = 0;
+ for (p = modname; *p; p++)
+ if (*p == '\\') *p = '/';
+
+ _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
+ _putenv (strdup (buf));
+ }
+ /* Handle running emacs from the build directory: src/oo-spd/i386/ */
+
+ /* FIXME: should use substring of get_emacs_configuration ().
+ But I don't think the Windows build supports alpha, mips etc
+ anymore, so have taken the easy option for now. */
+ else if (p && stricmp (p, "\\i386") == 0)
+ {
+ *p = 0;
+ p = strrchr (modname, '\\');
+ if (p != NULL)
+ {
+ *p = 0;
+ p = strrchr (modname, '\\');
+ if (p && stricmp (p, "\\src") == 0)
+ {
+ char buf[SET_ENV_BUF_SIZE];
+
+ *p = 0;
+ for (p = modname; *p; p++)
+ if (*p == '\\') *p = '/';
+
+ _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
+ _putenv (strdup (buf));
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
{
- if (!getenv (env_vars[i])
- && (lpval = w32_get_resource (env_vars[i], &dwType)) != NULL)
+ if (!getenv (env_vars[i].name))
{
- if (dwType == REG_EXPAND_SZ)
- {
- char buf1[500], buf2[500];
+ int dont_free = 0;
- ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
- _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
- putenv (strdup (buf2));
- }
- else if (dwType == REG_SZ)
+ if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL)
{
- char buf[500];
-
- _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
- putenv (strdup (buf));
+ lpval = env_vars[i].def_value;
+ dwType = REG_EXPAND_SZ;
+ dont_free = 1;
}
- xfree (lpval);
+ if (lpval)
+ {
+ if (dwType == REG_EXPAND_SZ)
+ {
+ 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));
+ }
+ else if (dwType == REG_SZ)
+ {
+ char buf[SET_ENV_BUF_SIZE];
+
+ _snprintf (buf, sizeof(buf)-1, "%s=%s", env_vars[i].name, lpval);
+ _putenv (strdup (buf));
+ }
+
+ if (!dont_free)
+ xfree (lpval);
+ }
}
}
}
{
char *p;
- char modname[MAX_PATH];
+ static char modname[MAX_PATH];
if (!GetModuleFileName (NULL, modname, MAX_PATH))
abort ();
*p = 0;
SetCurrentDirectory (modname);
+
+ /* Ensure argv[0] has the full path to Emacs. */
+ *p = '\\';
+ argv[0] = modname;
}
+ /* Determine if there is a middle mouse button, to allow parse_button
+ to decide whether right mouse events should be mouse-2 or
+ mouse-3. */
+ w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
+
init_user_info ();
}
+char *
+emacs_root_dir (void)
+{
+ static char root_dir[FILENAME_MAX];
+ const char *p;
+
+ p = getenv ("emacs_dir");
+ if (p == NULL)
+ abort ();
+ strcpy (root_dir, p);
+ root_dir[parse_root (root_dir, NULL)] = '\0';
+ dostounix_filename (root_dir);
+ return root_dir;
+}
+
/* We don't have scripts to automatically determine the system configuration
for Emacs before it's compiled, and we don't want to have to make the
user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
routine. */
-static char configuration_buffer[32];
-
char *
get_emacs_configuration (void)
{
char *arch, *oem, *os;
+ int build_num;
+ static char configuration_buffer[32];
/* Determine the processor type. */
- switch (get_processor_type ())
+ switch (get_processor_type ())
{
#ifdef PROCESSOR_INTEL_386
break;
}
- /* Let oem be "*" until we figure out how to decode the OEM field. */
- oem = "*";
+ /* Use the OEM field to reflect the compiler/library combination. */
+#ifdef _MSC_VER
+#define COMPILER_NAME "msvc"
+#else
+#ifdef __GNUC__
+#define COMPILER_NAME "mingw"
+#else
+#define COMPILER_NAME "unknown"
+#endif
+#endif
+ oem = COMPILER_NAME;
+
+ switch (osinfo_cache.dwPlatformId) {
+ case VER_PLATFORM_WIN32_NT:
+ os = "nt";
+ build_num = osinfo_cache.dwBuildNumber;
+ break;
+ case VER_PLATFORM_WIN32_WINDOWS:
+ if (osinfo_cache.dwMinorVersion == 0) {
+ os = "windows95";
+ } else {
+ os = "windows98";
+ }
+ build_num = LOWORD (osinfo_cache.dwBuildNumber);
+ break;
+ case VER_PLATFORM_WIN32s:
+ /* Not supported, should not happen. */
+ os = "windows32s";
+ build_num = LOWORD (osinfo_cache.dwBuildNumber);
+ break;
+ default:
+ os = "unknown";
+ build_num = 0;
+ break;
+ }
- os = (GetVersion () & OS_WIN95) ? "windows95" : "nt";
+ if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+ sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
+ get_w32_major_version (), get_w32_minor_version (), build_num);
+ } else {
+ sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
+ }
- sprintf (configuration_buffer, "%s-%s-%s%d.%d", arch, oem, os,
- get_w32_major_version (), get_w32_minor_version ());
return configuration_buffer;
}
+char *
+get_emacs_configuration_options (void)
+{
+ static char options_buffer[256];
+
+/* Work out the effective configure options for this build. */
+#ifdef _MSC_VER
+#define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
+#else
+#ifdef __GNUC__
+#define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
+#else
+#define COMPILER_VERSION ""
+#endif
+#endif
+
+ sprintf (options_buffer, COMPILER_VERSION);
+#ifdef EMACSDEBUG
+ strcat (options_buffer, " --no-opt");
+#endif
+#ifdef USER_CFLAGS
+ strcat (options_buffer, " --cflags");
+ strcat (options_buffer, USER_CFLAGS);
+#endif
+#ifdef USER_LDFLAGS
+ strcat (options_buffer, " --ldflags");
+ strcat (options_buffer, USER_LDFLAGS);
+#endif
+ return options_buffer;
+}
+
+
#include <sys/timeb.h>
/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
-void
+void
gettimeofday (struct timeval *tv, struct timezone *tz)
{
struct _timeb tb;
tv->tv_sec = tb.time;
tv->tv_usec = tb.millitm * 1000L;
- if (tz)
+ if (tz)
{
tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
tz->tz_dsttime = tb.dstflag; /* type of dst correction */
/* ------------------------------------------------------------------------- */
/* Place a wrapper around the MSVC version of ctime. It returns NULL
- on network directories, so we handle that case here.
+ on network directories, so we handle that case here.
(Ulrich Leodolter, 1/11/95). */
char *
sys_ctime (const time_t *t)
static void
add_volume_info (char * root_dir, volume_info_data * info)
{
- info->root_dir = strdup (root_dir);
+ info->root_dir = xstrdup (root_dir);
info->next = volume_cache;
volume_cache = info;
}
tell whether they are or not. Also, the UNC association of drive
letters mapped to remote volumes can be changed at any time (even
by other processes) without notice.
-
+
As a compromise, so we can benefit from caching info for remote
volumes, we use a simple expiry mechanism to invalidate cache
entries that are more than ten seconds old. */
}
else
{
- free (info->name);
- free (info->type);
+ xfree (info->name);
+ xfree (info->type);
}
- info->name = strdup (name);
+ info->name = xstrdup (name);
info->serialnum = serialnum;
info->maxcomp = maxcomp;
info->flags = flags;
- info->type = strdup (type);
+ info->type = xstrdup (type);
info->timestamp = GetTickCount ();
}
if (pPath)
*pPath = name;
-
+
info = GetCachedVolumeInformation (rootname);
if (info != NULL)
{
char * path;
const char * save_name = name;
- if (is_fat_volume (name, &path)) /* truncate to 8.3 */
+ if (strlen (name) >= MAX_PATH)
+ {
+ /* Return a filename which will cause callers to fail. */
+ strcpy (shortname, "?");
+ return shortname;
+ }
+
+ if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
{
register int left = 8; /* maximum number of chars in part */
register int extn = 0; /* extension added? */
stricmp (p, ".cmd") == 0));
}
-/* Emulate the Unix directory procedures opendir, closedir,
+/* Emulate the Unix directory procedures opendir, closedir,
and readdir. We can't use the procedures supplied in sysdep.c,
so we provide them here. */
/* Support shares on a network resource as subdirectories of a read-only
root directory. */
static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
-HANDLE open_unc_volume (char *);
+HANDLE open_unc_volume (const char *);
char *read_unc_volume (HANDLE, char *, int);
void close_unc_volume (HANDLE);
{
if (wnet_enum_handle != INVALID_HANDLE_VALUE)
{
- if (!read_unc_volume (wnet_enum_handle,
- dir_find_data.cFileName,
+ if (!read_unc_volume (wnet_enum_handle,
+ dir_find_data.cFileName,
MAX_PATH))
return NULL;
}
if (!FindNextFile (dir_find_handle, &dir_find_data))
return NULL;
}
-
+
/* Emacs never uses this value, so don't bother making it match
value returned by stat(). */
dir_static.d_ino = 1;
-
+
dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
dir_static.d_namlen - dir_static.d_namlen % 4;
-
+
dir_static.d_namlen = strlen (dir_find_data.cFileName);
strcpy (dir_static.d_name, dir_find_data.cFileName);
if (dir_is_fat)
if (!*p)
_strlwr (dir_static.d_name);
}
-
+
return &dir_static;
}
HANDLE
-open_unc_volume (char *path)
+open_unc_volume (const char *path)
{
- NETRESOURCE nr;
+ NETRESOURCE nr;
HANDLE henum;
int result;
- nr.dwScope = RESOURCE_GLOBALNET;
- nr.dwType = RESOURCETYPE_DISK;
- nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
- nr.dwUsage = RESOURCEUSAGE_CONTAINER;
- nr.lpLocalName = NULL;
- nr.lpRemoteName = map_w32_filename (path, NULL);
- nr.lpComment = NULL;
- nr.lpProvider = NULL;
+ nr.dwScope = RESOURCE_GLOBALNET;
+ nr.dwType = RESOURCETYPE_DISK;
+ nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
+ nr.dwUsage = RESOURCEUSAGE_CONTAINER;
+ nr.lpLocalName = NULL;
+ nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
+ nr.lpComment = NULL;
+ nr.lpProvider = NULL;
- result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
+ result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
if (result == NO_ERROR)
char *
read_unc_volume (HANDLE henum, char *readbuf, int size)
{
- int count;
+ DWORD count;
int result;
- int bufsize = 512;
+ DWORD bufsize = 512;
char *buffer;
char *ptr;
}
DWORD
-unc_volume_file_attributes (char *path)
+unc_volume_file_attributes (const char *path)
{
HANDLE henum;
DWORD attrs;
/* Shadow some MSVC runtime functions to map requests for long filenames
to reasonable short names if necessary. This was originally added to
- permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
+ permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
long file names. */
int
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)
{
int
sys_open (const char * path, int oflag, int mode)
{
- /* Force all file handles to be non-inheritable. */
- return _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 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)
+ return res;
+ return _open (mpath, oflag | _O_NOINHERIT, mode);
}
int
sys_rename (const char * oldname, const char * newname)
{
- int result;
+ BOOL result;
char temp[MAX_PATH];
/* MoveFile on Windows 95 doesn't correctly change the short file name
result = rename (oldname, temp);
}
/* This loop must surely terminate! */
- while (result < 0 && (errno == EEXIST || errno == EACCES));
+ while (result < 0 && errno == EEXIST);
if (result < 0)
return -1;
}
result = rename (temp, newname);
if (result < 0
- && (errno == EEXIST || errno == EACCES)
+ && errno == EEXIST
&& _chmod (newname, 0666) == 0
&& _unlink (newname) == 0)
result = rename (temp, newname);
}
name = (char *) map_w32_filename (path, &path);
- /* must be valid filename, no wild cards or other illegal characters */
+ /* must be valid filename, no wild cards or other invalid characters */
if (strpbrk (name, "*?|<>\""))
{
errno = ENOENT;
/* (This is hacky, but helps when doing file completions on
network drives.) Optimize by using information available from
active readdir if possible. */
+ len = strlen (dir_pathname);
+ if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
+ len--;
if (dir_find_handle != INVALID_HANDLE_VALUE
- && (len = strlen (dir_pathname)),
- strnicmp (name, dir_pathname, len) == 0
+ && strnicmp (name, dir_pathname, len) == 0
&& IS_DIRECTORY_SEP (name[len])
&& stricmp (name + len + 1, dir_static.d_name) == 0)
{
}
}
- if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- buf->st_mode = _S_IFDIR;
- buf->st_nlink = 2; /* doesn't really matter */
- fake_inode = 0; /* this doesn't either I think */
- }
- else if (!NILP (Vw32_get_true_file_attributes)
- /* No access rights required to get info. */
- && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 0, NULL))
- != INVALID_HANDLE_VALUE)
+ if (!NILP (Vw32_get_true_file_attributes)
+ /* No access rights required to get info. */
+ && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL))
+ != 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
BY_HANDLE_FILE_INFORMATION info;
if (GetFileInformationByHandle (fh, &info))
+ {
+ buf->st_nlink = info.nNumberOfLinks;
+ /* Might as well use file index to fake inode values, but this
+ is not guaranteed to be unique unless we keep a handle open
+ all the time (even then there are situations where it is
+ not unique). Reputedly, there are at most 48 bits of info
+ (on NTFS, presumably less on FAT). */
+ fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
+ }
+ else
+ {
+ buf->st_nlink = 1;
+ fake_inode = 0;
+ }
+
+ if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ buf->st_mode = _S_IFDIR;
+ }
+ else
{
switch (GetFileType (fh))
{
default:
buf->st_mode = _S_IFCHR;
}
- buf->st_nlink = info.nNumberOfLinks;
- /* Might as well use file index to fake inode values, but this
- is not guaranteed to be unique unless we keep a handle open
- all the time (even then there are situations where it is
- not unique). Reputedly, there are at most 48 bits of info
- (on NTFS, presumably less on FAT). */
- fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
- CloseHandle (fh);
- }
- else
- {
- errno = EACCES;
- return -1;
}
+ CloseHandle (fh);
}
else
{
/* Don't bother to make this information more accurate. */
- buf->st_mode = _S_IFREG;
+ buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
+ _S_IFDIR : _S_IFREG;
buf->st_nlink = 1;
fake_inode = 0;
}
permission = _S_IREAD;
else
permission = _S_IREAD | _S_IWRITE;
-
+
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
permission |= _S_IEXEC;
else if (is_exec (name))
}
if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
buf->st_mode = _S_IFDIR;
- buf->st_nlink = 2; /* doesn't really matter */
- fake_inode = 0; /* this doesn't either I think */
- }
- else
- {
- buf->st_nlink = info.nNumberOfLinks;
- /* Might as well use file index to fake inode values, but this
- is not guaranteed to be unique unless we keep a handle open
- all the time (even then there are situations where it is
- not unique). Reputedly, there are at most 48 bits of info
- (on NTFS, presumably less on FAT). */
- fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
- }
+
+ buf->st_nlink = info.nNumberOfLinks;
+ /* Might as well use file index to fake inode values, but this
+ is not guaranteed to be unique unless we keep a handle open
+ all the time (even then there are situations where it is
+ not unique). Reputedly, there are at most 48 bits of info
+ (on NTFS, presumably less on FAT). */
+ fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
/* MSVC defines _ino_t to be short; other libc's might not. */
if (sizeof (buf->st_ino) == 2)
permission = _S_IREAD;
else
permission = _S_IREAD | _S_IWRITE;
-
+
if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
permission |= _S_IEXEC;
else
int (PASCAL *pfn_gethostname) (char * name, int namelen);
struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
-
+int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
+int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
+ const char * optval, int optlen);
+int (PASCAL *pfn_listen) (SOCKET s, int backlog);
+int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
+ int * namelen);
+SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
+int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
+ struct sockaddr * from, int * fromlen);
+int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
+ const struct sockaddr * to, int tolen);
+
/* SetHandleInformation is only needed to make sockets non-inheritable. */
BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
#ifndef HANDLE_FLAG_INHERIT
LOAD_PROC( gethostname );
LOAD_PROC( gethostbyname );
LOAD_PROC( getservbyname );
+ LOAD_PROC( getpeername );
LOAD_PROC( WSACleanup );
-
+ LOAD_PROC( setsockopt );
+ LOAD_PROC( listen );
+ LOAD_PROC( getsockname );
+ LOAD_PROC( accept );
+ LOAD_PROC( recvfrom );
+ LOAD_PROC( sendto );
#undef LOAD_PROC
/* specify version 1.1 of winsock */
pfn_WSASetLastError (0);
}
+/* Extend strerror to handle the winsock-specific error codes. */
+struct {
+ int errnum;
+ char * msg;
+} _wsa_errlist[] = {
+ WSAEINTR , "Interrupted function call",
+ WSAEBADF , "Bad file descriptor",
+ WSAEACCES , "Permission denied",
+ WSAEFAULT , "Bad address",
+ WSAEINVAL , "Invalid argument",
+ WSAEMFILE , "Too many open files",
+
+ WSAEWOULDBLOCK , "Resource temporarily unavailable",
+ WSAEINPROGRESS , "Operation now in progress",
+ WSAEALREADY , "Operation already in progress",
+ WSAENOTSOCK , "Socket operation on non-socket",
+ WSAEDESTADDRREQ , "Destination address required",
+ WSAEMSGSIZE , "Message too long",
+ WSAEPROTOTYPE , "Protocol wrong type for socket",
+ WSAENOPROTOOPT , "Bad protocol option",
+ WSAEPROTONOSUPPORT , "Protocol not supported",
+ WSAESOCKTNOSUPPORT , "Socket type not supported",
+ WSAEOPNOTSUPP , "Operation not supported",
+ WSAEPFNOSUPPORT , "Protocol family not supported",
+ WSAEAFNOSUPPORT , "Address family not supported by protocol family",
+ WSAEADDRINUSE , "Address already in use",
+ WSAEADDRNOTAVAIL , "Cannot assign requested address",
+ WSAENETDOWN , "Network is down",
+ WSAENETUNREACH , "Network is unreachable",
+ WSAENETRESET , "Network dropped connection on reset",
+ WSAECONNABORTED , "Software caused connection abort",
+ WSAECONNRESET , "Connection reset by peer",
+ WSAENOBUFS , "No buffer space available",
+ WSAEISCONN , "Socket is already connected",
+ WSAENOTCONN , "Socket is not connected",
+ WSAESHUTDOWN , "Cannot send after socket shutdown",
+ WSAETOOMANYREFS , "Too many references", /* not sure */
+ WSAETIMEDOUT , "Connection timed out",
+ WSAECONNREFUSED , "Connection refused",
+ WSAELOOP , "Network loop", /* not sure */
+ WSAENAMETOOLONG , "Name is too long",
+ WSAEHOSTDOWN , "Host is down",
+ WSAEHOSTUNREACH , "No route to host",
+ WSAENOTEMPTY , "Buffer not empty", /* not sure */
+ WSAEPROCLIM , "Too many processes",
+ WSAEUSERS , "Too many users", /* not sure */
+ WSAEDQUOT , "Double quote in host name", /* really not sure */
+ WSAESTALE , "Data is stale", /* not sure */
+ WSAEREMOTE , "Remote error", /* not sure */
+
+ WSASYSNOTREADY , "Network subsystem is unavailable",
+ WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
+ WSANOTINITIALISED , "Winsock not initialized successfully",
+ WSAEDISCON , "Graceful shutdown in progress",
+#ifdef WSAENOMORE
+ WSAENOMORE , "No more operations allowed", /* not sure */
+ WSAECANCELLED , "Operation cancelled", /* not sure */
+ WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
+ WSAEINVALIDPROVIDER , "Invalid service provider version number",
+ WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
+ WSASYSCALLFAILURE , "System call failured",
+ 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 */
+ WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
+ WSAEREFUSED , "Operation refused", /* not sure */
+#endif
+
+ WSAHOST_NOT_FOUND , "Host not found",
+ WSATRY_AGAIN , "Authoritative host not found during name lookup",
+ WSANO_RECOVERY , "Non-recoverable error during name lookup",
+ WSANO_DATA , "Valid name, no data record of requested type",
+
+ -1, NULL
+};
+
+char *
+sys_strerror(int error_no)
+{
+ int i;
+ static char unknown_msg[40];
+
+ if (error_no >= 0 && error_no < sys_nerr)
+ return sys_errlist[error_no];
+
+ for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
+ if (_wsa_errlist[i].errnum == error_no)
+ return _wsa_errlist[i].msg;
+
+ sprintf(unknown_msg, "Unidentified error: %d", error_no);
+ return unknown_msg;
+}
+
/* [andrewi 3-May-96] I've had conflicting results using both methods,
but I believe the method of keeping the socket handle separate (and
insuring it is not inheritable) is the correct one. */
#define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
#endif
+int socket_to_fd (SOCKET s);
+
int
sys_socket(int af, int type, int protocol)
{
- int fd;
- long s;
- child_process * cp;
+ SOCKET s;
if (winsock_lib == NULL)
{
check_errno ();
/* call the real socket function */
- s = (long) pfn_socket (af, type, protocol);
-
+ s = pfn_socket (af, type, protocol);
+
if (s != INVALID_SOCKET)
- {
- /* Although under NT 3.5 _open_osfhandle will accept a socket
- handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
- that does not work under NT 3.1. However, we can get the same
- effect by using a backdoor function to replace an existing
- descriptor handle with the one we want. */
+ return socket_to_fd (s);
- /* allocate a file descriptor (with appropriate flags) */
- fd = _open ("NUL:", _O_RDWR);
- if (fd >= 0)
- {
+ set_errno ();
+ return -1;
+}
+
+/* Convert a SOCKET to a file descriptor. */
+int
+socket_to_fd (SOCKET s)
+{
+ int fd;
+ child_process * cp;
+
+ /* Although under NT 3.5 _open_osfhandle will accept a socket
+ handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
+ that does not work under NT 3.1. However, we can get the same
+ effect by using a backdoor function to replace an existing
+ descriptor handle with the one we want. */
+
+ /* allocate a file descriptor (with appropriate flags) */
+ fd = _open ("NUL:", _O_RDWR);
+ if (fd >= 0)
+ {
#ifdef SOCK_REPLACE_HANDLE
- /* now replace handle to NUL with our socket handle */
- CloseHandle ((HANDLE) _get_osfhandle (fd));
- _free_osfhnd (fd);
- _set_osfhnd (fd, s);
- /* setmode (fd, _O_BINARY); */
+ /* now replace handle to NUL with our socket handle */
+ CloseHandle ((HANDLE) _get_osfhandle (fd));
+ _free_osfhnd (fd);
+ _set_osfhnd (fd, s);
+ /* setmode (fd, _O_BINARY); */
#else
- /* Make a non-inheritable copy of the socket handle. */
+ /* Make a non-inheritable copy of the socket handle. Note
+ that it is possible that sockets aren't actually kernel
+ handles, which appears to be the case on Windows 9x when
+ the MS Proxy winsock client is installed. */
+ {
+ /* Apparently there is a bug in NT 3.51 with some service
+ packs, which prevents using DuplicateHandle to make a
+ socket handle non-inheritable (causes WSACleanup to
+ hang). The work-around is to use SetHandleInformation
+ instead if it is available and implemented. */
+ if (pfn_SetHandleInformation)
+ {
+ pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
+ }
+ else
{
- HANDLE parent;
+ HANDLE parent = GetCurrentProcess ();
HANDLE new_s = INVALID_HANDLE_VALUE;
- parent = GetCurrentProcess ();
-
- /* Apparently there is a bug in NT 3.51 with some service
- packs, which prevents using DuplicateHandle to make a
- socket handle non-inheritable (causes WSACleanup to
- hang). The work-around is to use SetHandleInformation
- instead if it is available and implemented. */
- if (!pfn_SetHandleInformation
- || !pfn_SetHandleInformation ((HANDLE) s,
- HANDLE_FLAG_INHERIT,
- 0))
- {
- DuplicateHandle (parent,
+ if (DuplicateHandle (parent,
(HANDLE) s,
parent,
&new_s,
0,
FALSE,
- DUPLICATE_SAME_ACCESS);
- pfn_closesocket (s);
- s = (SOCKET) new_s;
+ DUPLICATE_SAME_ACCESS))
+ {
+ /* It is possible that DuplicateHandle succeeds even
+ 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;
+ if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
+ {
+ pfn_closesocket (s);
+ s = (SOCKET) new_s;
+ }
+ else
+ {
+ CloseHandle (new_s);
+ }
}
- fd_info[fd].hnd = (HANDLE) s;
}
+ }
+ fd_info[fd].hnd = (HANDLE) s;
#endif
- /* set our own internal flags */
- fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
-
- cp = new_child ();
- if (cp)
- {
- cp->fd = fd;
- cp->status = STATUS_READ_ACKNOWLEDGED;
-
- /* attach child_process to fd_info */
- if (fd_info[ fd ].cp != NULL)
- {
- DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
- abort ();
- }
+ /* set our own internal flags */
+ fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
- fd_info[ fd ].cp = cp;
+ cp = new_child ();
+ if (cp)
+ {
+ cp->fd = fd;
+ cp->status = STATUS_READ_ACKNOWLEDGED;
- /* success! */
- winsock_inuse++; /* count open sockets */
- return fd;
+ /* attach child_process to fd_info */
+ if (fd_info[ fd ].cp != NULL)
+ {
+ DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
+ abort ();
}
- /* clean up */
- _close (fd);
+ fd_info[ fd ].cp = cp;
+
+ /* success! */
+ winsock_inuse++; /* count open sockets */
+ return fd;
}
- pfn_closesocket (s);
- h_errno = EMFILE;
- }
- set_errno ();
+ /* clean up */
+ _close (fd);
+ }
+ pfn_closesocket (s);
+ h_errno = EMFILE;
return -1;
}
return pfn_gethostname (name, namelen);
if (namelen > MAX_COMPUTERNAME_LENGTH)
- return !GetComputerName (name, &namelen);
+ return !GetComputerName (name, (DWORD *)&namelen);
h_errno = EFAULT;
return SOCKET_ERROR;
}
int
-sys_shutdown (int s, int how)
+sys_getpeername (int s, struct sockaddr *addr, int * namelen)
{
- int rc;
+ if (winsock_lib == NULL)
+ {
+ h_errno = ENETDOWN;
+ return SOCKET_ERROR;
+ }
+
+ check_errno ();
+ if (fd_info[s].flags & FILE_SOCKET)
+ {
+ int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
+ if (rc == SOCKET_ERROR)
+ set_errno ();
+ return rc;
+ }
+ h_errno = ENOTSOCK;
+ return SOCKET_ERROR;
+}
+
+int
+sys_shutdown (int s, int how)
+{
if (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return SOCKET_ERROR;
}
+int
+sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
+{
+ if (winsock_lib == NULL)
+ {
+ h_errno = ENETDOWN;
+ return SOCKET_ERROR;
+ }
+
+ check_errno ();
+ if (fd_info[s].flags & FILE_SOCKET)
+ {
+ int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
+ (const char *)optval, optlen);
+ if (rc == SOCKET_ERROR)
+ set_errno ();
+ return rc;
+ }
+ h_errno = ENOTSOCK;
+ return SOCKET_ERROR;
+}
+
+int
+sys_listen (int s, int backlog)
+{
+ if (winsock_lib == NULL)
+ {
+ h_errno = ENETDOWN;
+ return SOCKET_ERROR;
+ }
+
+ check_errno ();
+ if (fd_info[s].flags & FILE_SOCKET)
+ {
+ int rc = pfn_listen (SOCK_HANDLE (s), backlog);
+ if (rc == SOCKET_ERROR)
+ set_errno ();
+ return rc;
+ }
+ h_errno = ENOTSOCK;
+ return SOCKET_ERROR;
+}
+
+int
+sys_getsockname (int s, struct sockaddr * name, int * namelen)
+{
+ if (winsock_lib == NULL)
+ {
+ h_errno = ENETDOWN;
+ return SOCKET_ERROR;
+ }
+
+ check_errno ();
+ if (fd_info[s].flags & FILE_SOCKET)
+ {
+ int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
+ if (rc == SOCKET_ERROR)
+ set_errno ();
+ return rc;
+ }
+ h_errno = ENOTSOCK;
+ return SOCKET_ERROR;
+}
+
+int
+sys_accept (int s, struct sockaddr * addr, int * addrlen)
+{
+ if (winsock_lib == NULL)
+ {
+ h_errno = ENETDOWN;
+ return -1;
+ }
+
+ check_errno ();
+ if (fd_info[s].flags & FILE_SOCKET)
+ {
+ SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
+ if (t != INVALID_SOCKET)
+ return socket_to_fd (t);
+
+ set_errno ();
+ return -1;
+ }
+ h_errno = ENOTSOCK;
+ return -1;
+}
+
+int
+sys_recvfrom (int s, char * buf, int len, int flags,
+ struct sockaddr * from, int * fromlen)
+{
+ if (winsock_lib == NULL)
+ {
+ h_errno = ENETDOWN;
+ return SOCKET_ERROR;
+ }
+
+ check_errno ();
+ if (fd_info[s].flags & FILE_SOCKET)
+ {
+ int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
+ if (rc == SOCKET_ERROR)
+ set_errno ();
+ return rc;
+ }
+ h_errno = ENOTSOCK;
+ return SOCKET_ERROR;
+}
+
+int
+sys_sendto (int s, const char * buf, int len, int flags,
+ const struct sockaddr * to, int tolen)
+{
+ if (winsock_lib == NULL)
+ {
+ h_errno = ENETDOWN;
+ return SOCKET_ERROR;
+ }
+
+ check_errno ();
+ if (fd_info[s].flags & FILE_SOCKET)
+ {
+ int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
+ if (rc == SOCKET_ERROR)
+ set_errno ();
+ return rc;
+ }
+ h_errno = ENOTSOCK;
+ return SOCKET_ERROR;
+}
+
+/* Windows does not have an fcntl function. Provide an implementation
+ solely for making sockets non-blocking. */
+int
+fcntl (int s, int cmd, int options)
+{
+ if (winsock_lib == NULL)
+ {
+ h_errno = ENETDOWN;
+ return -1;
+ }
+
+ check_errno ();
+ if (fd_info[s].flags & FILE_SOCKET)
+ {
+ if (cmd == F_SETFL && options == O_NDELAY)
+ {
+ unsigned long nblock = 1;
+ int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
+ if (rc == SOCKET_ERROR)
+ set_errno();
+ /* Keep track of the fact that we set this to non-blocking. */
+ fd_info[s].flags |= FILE_NDELAY;
+ return rc;
+ }
+ else
+ {
+ h_errno = EINVAL;
+ return SOCKET_ERROR;
+ }
+ }
+ h_errno = ENOTSOCK;
+ return SOCKET_ERROR;
+}
+
#endif /* HAVE_SOCKETS */
/* make sure we close the destination first if it's a pipe or socket */
if (src != dst && fd_info[dst].flags != 0)
sys_close (dst);
-
+
rc = _dup2 (src, dst);
if (rc == 0)
{
{
int rc;
unsigned flags;
- child_process * cp;
/* make pipe handles non-inheritable; when we spawn a child, we
replace the relevant handle with an inheritable one. Also put
if (rc == 0)
{
- flags = FILE_PIPE | FILE_READ | FILE_BINARY;
- fd_info[phandles[0]].flags = flags;
+ /* Protect against overflow, since Windows can open more handles than
+ our fd_info array has room for. */
+ if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
+ {
+ _close (phandles[0]);
+ _close (phandles[1]);
+ rc = -1;
+ }
+ else
+ {
+ flags = FILE_PIPE | FILE_READ | FILE_BINARY;
+ fd_info[phandles[0]].flags = flags;
- flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
- fd_info[phandles[1]].flags = flags;
+ flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
+ fd_info[phandles[1]].flags = flags;
+ }
}
return rc;
}
/* From ntproc.c */
-extern Lisp_Object Vw32_pipe_read_delay;
+extern int w32_pipe_read_delay;
/* Function to do blocking read of one byte, needed to implement
select. It is only allowed on sockets and pipes. */
DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
abort ();
}
-
+
cp->status = STATUS_READ_IN_PROGRESS;
-
+
if (fd_info[fd].flags & FILE_PIPE)
{
rc = _read (fd, &cp->chr, sizeof (char));
shell on NT is very slow if we don't do this. */
if (rc > 0)
{
- int wait = XINT (Vw32_pipe_read_delay);
+ int wait = w32_pipe_read_delay;
if (wait > 0)
Sleep (wait);
}
#ifdef HAVE_SOCKETS
else if (fd_info[fd].flags & FILE_SOCKET)
- rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
+ {
+ unsigned long nblock = 0;
+ /* We always want this to block, so temporarily disable NDELAY. */
+ if (fd_info[fd].flags & FILE_NDELAY)
+ pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
+
+ rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
+
+ if (fd_info[fd].flags & FILE_NDELAY)
+ {
+ nblock = 1;
+ pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
+ }
+ }
#endif
-
+
if (rc == sizeof (char))
cp->status = STATUS_READ_SUCCEEDED;
else
next[0] = '\n';
dst = next + 1;
count++;
- }
+ }
else
/* copied remaining partial line -> now finished */
break;
#ifdef HAVE_SOCKETS
if (fd_info[fd].flags & FILE_SOCKET)
{
+ unsigned long nblock = 0;
if (winsock_lib == NULL) abort ();
+
+ /* TODO: implement select() properly so non-blocking I/O works. */
+ /* For now, make sure the write blocks. */
+ if (fd_info[fd].flags & FILE_NDELAY)
+ pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
+
nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
+
+ /* Set the socket back to non-blocking if it was before,
+ for other operations that support it. */
+ if (fd_info[fd].flags & FILE_NDELAY)
+ {
+ nblock = 1;
+ pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
+ }
+
if (nchars == SOCKET_ERROR)
{
- DebPrint(("sys_read.send failed with error %d on socket %ld\n",
+ DebPrint(("sys_write.send failed with error %d on socket %ld\n",
pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
set_errno ();
}
it cannot find the Windows installation file. If this file does
not exist in the expected place, tell the user. */
- if (!noninteractive && !inhibit_window_system) {
- extern Lisp_Object Vwindow_system, Vload_path;
- Lisp_Object init_file;
- int fd;
-
- init_file = build_string ("term/w32-win");
- fd = openp (Vload_path, init_file, ".el:.elc", NULL, 0);
- if (fd < 0) {
- Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
- char *init_file_name = XSTRING (init_file)->data;
- char *load_path = XSTRING (load_path_print)->data;
- char *buffer = alloca (1024);
-
- sprintf (buffer,
- "The Emacs Windows initialization file \"%s.el\" "
- "could not be found in your Emacs installation. "
- "Emacs checked the following directories for this file:\n"
- "\n%s\n\n"
- "When Emacs cannot find this file, it usually means that it "
- "was not installed properly, or its distribution file was "
- "not unpacked properly.\nSee the README.W32 file in the "
- "top-level Emacs directory for more information.",
- init_file_name, load_path);
- MessageBox (NULL,
- buffer,
- "Emacs Abort Dialog",
- MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
- close (fd);
+ if (!noninteractive && !inhibit_window_system)
+ {
+ extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
+ Lisp_Object objs[2];
+ Lisp_Object full_load_path;
+ Lisp_Object init_file;
+ int fd;
+ objs[0] = Vload_path;
+ 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);
+ 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);
+
+ sprintf (buffer,
+ "The Emacs Windows initialization file \"%s.el\" "
+ "could not be found in your Emacs installation. "
+ "Emacs checked the following directories for this file:\n"
+ "\n%s\n\n"
+ "When Emacs cannot find this file, it usually means that it "
+ "was not installed properly, or its distribution file was "
+ "not unpacked properly.\nSee the README.W32 file in the "
+ "top-level Emacs directory for more information.",
+ init_file_name, load_path);
+ MessageBox (NULL,
+ buffer,
+ "Emacs Abort Dialog",
+ MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
/* Use the low-level Emacs abort. */
#undef abort
- abort ();
+ abort ();
+ }
+ else
+ {
+ _close (fd);
+ }
}
- }
}
void
term_winsock ();
#endif
- /* Check whether we are shutting down because we cannot find the
- Windows initialization file. Do this during shutdown so that
- Emacs is initialized as possible, and so that it is out of the
- critical startup path. */
- check_windows_init_file ();
+ term_w32select ();
}
void
/* ignore errors when duplicating and closing; typically the
handles will be invalid when running as a gui program. */
- DuplicateHandle (parent,
- GetStdHandle (STD_INPUT_HANDLE),
+ DuplicateHandle (parent,
+ GetStdHandle (STD_INPUT_HANDLE),
parent,
- &stdin_save,
- 0,
- FALSE,
+ &stdin_save,
+ 0,
+ FALSE,
DUPLICATE_SAME_ACCESS);
-
+
DuplicateHandle (parent,
GetStdHandle (STD_OUTPUT_HANDLE),
parent,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
-
+
DuplicateHandle (parent,
GetStdHandle (STD_ERROR_HANDLE),
parent,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
-
+
fclose (stdin);
fclose (stdout);
fclose (stderr);
while (*drive <= 'Z')
{
/* Record if this drive letter refers to a fixed drive. */
- fixed_drives[DRIVE_INDEX (*drive)] =
+ fixed_drives[DRIVE_INDEX (*drive)] =
(GetDriveType (drive) == DRIVE_FIXED);
(*drive)++;
}
+
+ /* Reset the volume info cache. */
+ volume_cache = NULL;
}
+
+ /* Check to see if Emacs has been installed correctly. */
+ check_windows_init_file ();
+}
+
+/*
+ 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 ()
+{
+ 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;
}
/* end of nt.c */
+
+/* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
+ (do not change this comment) */