/* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
- Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
This file is part of GNU Emacs.
-GNU Emacs is free software; you can redistribute it and/or modify
+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 3, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
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., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.
+along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
+/*
Geoff Voelker (voelker@cs.washington.edu) 7-29-94
*/
#include <stddef.h> /* for offsetof */
#include <stdlib.h>
#include <stdio.h>
+#include <float.h> /* for DBL_EPSILON */
#include <io.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/utime.h>
#include <mbstring.h> /* for _mbspbrk */
+#include <math.h>
+#include <setjmp.h>
/* must include CRT headers *before* config.h */
#define _ANONYMOUS_STRUCT
#endif
#include <windows.h>
+/* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
+ use a different name to avoid compilation problems. */
+typedef struct _MEMORY_STATUS_EX {
+ DWORD dwLength;
+ DWORD dwMemoryLoad;
+ DWORDLONG ullTotalPhys;
+ DWORDLONG ullAvailPhys;
+ DWORDLONG ullTotalPageFile;
+ DWORDLONG ullAvailPageFile;
+ DWORDLONG ullTotalVirtual;
+ DWORDLONG ullAvailVirtual;
+ DWORDLONG ullAvailExtendedVirtual;
+} MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
+
#include <lmcons.h>
#include <shlobj.h>
-#ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
+#include <tlhelp32.h>
+#include <psapi.h>
+#include <w32api.h>
+#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 suplied with MinGW 3.15
+ defines it in psapi.h */
+typedef struct _PROCESS_MEMORY_COUNTERS_EX {
+ DWORD cb;
+ DWORD PageFaultCount;
+ DWORD PeakWorkingSetSize;
+ DWORD WorkingSetSize;
+ DWORD QuotaPeakPagedPoolUsage;
+ DWORD QuotaPagedPoolUsage;
+ DWORD QuotaPeakNonPagedPoolUsage;
+ DWORD QuotaNonPagedPoolUsage;
+ DWORD PagefileUsage;
+ DWORD PeakPagefileUsage;
+ DWORD PrivateUsage;
+} PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
+#endif
+
+/* TCP connection support. */
#include <sys/socket.h>
#undef socket
#undef bind
#undef accept
#undef recvfrom
#undef sendto
-#endif
#include "w32.h"
#include "ndir.h"
#include "w32heap.h"
#include "systime.h"
+#include "dispextern.h" /* for xstrcasecmp */
+#include "coding.h" /* for Vlocale_coding_system */
+
+/* For serial_configure and serial_open. */
+#include "process.h"
typedef HRESULT (WINAPI * ShGetFolderPath_fn)
(IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
-void globals_of_w32 ();
+void globals_of_w32 (void);
+static DWORD get_rid (PSID);
extern Lisp_Object Vw32_downcase_file_names;
extern Lisp_Object Vw32_generate_fake_inodes;
extern Lisp_Object Vw32_get_true_file_attributes;
+/* Defined in process.c for its own purpose. */
+extern Lisp_Object Qlocal;
+
extern int w32_num_mouse_buttons;
\f
static BOOL g_b_init_get_sid_identifier_authority;
static BOOL g_b_init_get_sid_sub_authority;
static BOOL g_b_init_get_sid_sub_authority_count;
+static BOOL g_b_init_get_file_security;
+static BOOL g_b_init_get_security_descriptor_owner;
+static BOOL g_b_init_get_security_descriptor_group;
+static BOOL g_b_init_is_valid_sid;
+static BOOL g_b_init_create_toolhelp32_snapshot;
+static BOOL g_b_init_process32_first;
+static BOOL g_b_init_process32_next;
+static BOOL g_b_init_open_thread_token;
+static BOOL g_b_init_impersonate_self;
+static BOOL g_b_init_revert_to_self;
+static BOOL g_b_init_get_process_memory_info;
+static BOOL g_b_init_get_process_working_set_size;
+static BOOL g_b_init_global_memory_status;
+static BOOL g_b_init_global_memory_status_ex;
+static BOOL g_b_init_get_length_sid;
+static BOOL g_b_init_equal_sid;
+static BOOL g_b_init_copy_sid;
+static BOOL g_b_init_get_native_system_info;
+static BOOL g_b_init_get_system_times;
/*
BEGIN: Wrapper functions around OpenProcessToken
#ifdef _UNICODE
const char * const LookupAccountSid_Name = "LookupAccountSidW";
+const char * const GetFileSecurity_Name = "GetFileSecurityW";
#else
const char * const LookupAccountSid_Name = "LookupAccountSidA";
+const char * const GetFileSecurity_Name = "GetFileSecurityA";
#endif
typedef BOOL (WINAPI * LookupAccountSid_Proc) (
LPCTSTR lpSystemName,
DWORD n);
typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
PSID pSid);
+typedef BOOL (WINAPI * GetFileSecurity_Proc) (
+ LPCTSTR lpFileName,
+ SECURITY_INFORMATION RequestedInformation,
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ DWORD nLength,
+ LPDWORD lpnLengthNeeded);
+typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ PSID *pOwner,
+ LPBOOL lpbOwnerDefaulted);
+typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ PSID *pGroup,
+ LPBOOL lpbGroupDefaulted);
+typedef BOOL (WINAPI * IsValidSid_Proc) (
+ PSID sid);
+typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
+ DWORD dwFlags,
+ DWORD th32ProcessID);
+typedef BOOL (WINAPI * Process32First_Proc) (
+ HANDLE hSnapshot,
+ LPPROCESSENTRY32 lppe);
+typedef BOOL (WINAPI * Process32Next_Proc) (
+ HANDLE hSnapshot,
+ LPPROCESSENTRY32 lppe);
+typedef BOOL (WINAPI * OpenThreadToken_Proc) (
+ HANDLE ThreadHandle,
+ DWORD DesiredAccess,
+ BOOL OpenAsSelf,
+ PHANDLE TokenHandle);
+typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
+ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
+typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
+typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
+ HANDLE Process,
+ PPROCESS_MEMORY_COUNTERS ppsmemCounters,
+ DWORD cb);
+typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
+ HANDLE hProcess,
+ DWORD * lpMinimumWorkingSetSize,
+ DWORD * lpMaximumWorkingSetSize);
+typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
+ LPMEMORYSTATUS lpBuffer);
+typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
+ LPMEMORY_STATUS_EX lpBuffer);
+typedef BOOL (WINAPI * CopySid_Proc) (
+ DWORD nDestinationSidLength,
+ PSID pDestinationSid,
+ PSID pSourceSid);
+typedef BOOL (WINAPI * EqualSid_Proc) (
+ PSID pSid1,
+ PSID pSid2);
+typedef DWORD (WINAPI * GetLengthSid_Proc) (
+ PSID pSid);
+typedef void (WINAPI * GetNativeSystemInfo_Proc) (
+ LPSYSTEM_INFO lpSystemInfo);
+typedef BOOL (WINAPI * GetSystemTimes_Proc) (
+ LPFILETIME lpIdleTime,
+ LPFILETIME lpKernelTime,
+ LPFILETIME lpUserTime);
+
/* ** A utility function ** */
static BOOL
-is_windows_9x ()
+is_windows_9x (void)
{
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);
+ ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
+ os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if (GetVersionEx (&os_ver))
{
s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
Returns a list of three integers if the times are provided by the OS
(NT derivatives), otherwise it returns the result of current-time. */
Lisp_Object
-w32_get_internal_run_time ()
+w32_get_internal_run_time (void)
{
if (get_process_times_fn)
{
FILETIME create, exit, kernel, user;
- HANDLE proc = GetCurrentProcess();
+ HANDLE proc = GetCurrentProcess ();
if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
{
LARGE_INTEGER user_int, kernel_int, total;
return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
}
+BOOL WINAPI get_file_security (
+ LPCTSTR lpFileName,
+ SECURITY_INFORMATION RequestedInformation,
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ DWORD nLength,
+ LPDWORD lpnLengthNeeded)
+{
+ static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_get_file_security == 0)
+ {
+ g_b_init_get_file_security = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Get_File_Security =
+ (GetFileSecurity_Proc) GetProcAddress (
+ hm_advapi32, GetFileSecurity_Name);
+ }
+ if (s_pfn_Get_File_Security == NULL)
+ {
+ return FALSE;
+ }
+ return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
+ pSecurityDescriptor, nLength,
+ lpnLengthNeeded));
+}
+
+BOOL WINAPI get_security_descriptor_owner (
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ PSID *pOwner,
+ LPBOOL lpbOwnerDefaulted)
+{
+ static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_get_security_descriptor_owner == 0)
+ {
+ g_b_init_get_security_descriptor_owner = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Get_Security_Descriptor_Owner =
+ (GetSecurityDescriptorOwner_Proc) GetProcAddress (
+ hm_advapi32, "GetSecurityDescriptorOwner");
+ }
+ if (s_pfn_Get_Security_Descriptor_Owner == NULL)
+ {
+ return FALSE;
+ }
+ return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
+ lpbOwnerDefaulted));
+}
+
+BOOL WINAPI get_security_descriptor_group (
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ PSID *pGroup,
+ LPBOOL lpbGroupDefaulted)
+{
+ static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_get_security_descriptor_group == 0)
+ {
+ g_b_init_get_security_descriptor_group = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Get_Security_Descriptor_Group =
+ (GetSecurityDescriptorGroup_Proc) GetProcAddress (
+ hm_advapi32, "GetSecurityDescriptorGroup");
+ }
+ if (s_pfn_Get_Security_Descriptor_Group == NULL)
+ {
+ return FALSE;
+ }
+ return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
+ lpbGroupDefaulted));
+}
+
+BOOL WINAPI is_valid_sid (
+ PSID sid)
+{
+ static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_is_valid_sid == 0)
+ {
+ g_b_init_is_valid_sid = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Is_Valid_Sid =
+ (IsValidSid_Proc) GetProcAddress (
+ hm_advapi32, "IsValidSid");
+ }
+ if (s_pfn_Is_Valid_Sid == NULL)
+ {
+ return FALSE;
+ }
+ return (s_pfn_Is_Valid_Sid (sid));
+}
+
+BOOL WINAPI equal_sid (
+ PSID sid1,
+ PSID sid2)
+{
+ static EqualSid_Proc s_pfn_Equal_Sid = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_equal_sid == 0)
+ {
+ g_b_init_equal_sid = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Equal_Sid =
+ (EqualSid_Proc) GetProcAddress (
+ hm_advapi32, "EqualSid");
+ }
+ if (s_pfn_Equal_Sid == NULL)
+ {
+ return FALSE;
+ }
+ return (s_pfn_Equal_Sid (sid1, sid2));
+}
+
+DWORD WINAPI get_length_sid (
+ PSID sid)
+{
+ static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return 0;
+ }
+ if (g_b_init_get_length_sid == 0)
+ {
+ g_b_init_get_length_sid = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Get_Length_Sid =
+ (GetLengthSid_Proc) GetProcAddress (
+ hm_advapi32, "GetLengthSid");
+ }
+ if (s_pfn_Get_Length_Sid == NULL)
+ {
+ return 0;
+ }
+ return (s_pfn_Get_Length_Sid (sid));
+}
+
+BOOL WINAPI copy_sid (
+ DWORD destlen,
+ PSID dest,
+ PSID src)
+{
+ static CopySid_Proc s_pfn_Copy_Sid = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_copy_sid == 0)
+ {
+ g_b_init_copy_sid = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Copy_Sid =
+ (CopySid_Proc) GetProcAddress (
+ hm_advapi32, "CopySid");
+ }
+ if (s_pfn_Copy_Sid == NULL)
+ {
+ return FALSE;
+ }
+ return (s_pfn_Copy_Sid (destlen, dest, src));
+}
+
/*
END: Wrapper functions around OpenProcessToken
and other functions in advapi32.dll that are only
supported in Windows NT / 2k / XP
*/
+void WINAPI get_native_system_info (
+ LPSYSTEM_INFO lpSystemInfo)
+{
+ static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
+ if (is_windows_9x () != TRUE)
+ {
+ if (g_b_init_get_native_system_info == 0)
+ {
+ g_b_init_get_native_system_info = 1;
+ s_pfn_Get_Native_System_Info =
+ (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
+ "GetNativeSystemInfo");
+ }
+ if (s_pfn_Get_Native_System_Info != NULL)
+ s_pfn_Get_Native_System_Info (lpSystemInfo);
+ }
+ else
+ lpSystemInfo->dwNumberOfProcessors = -1;
+}
+
+BOOL WINAPI get_system_times (
+ LPFILETIME lpIdleTime,
+ LPFILETIME lpKernelTime,
+ LPFILETIME lpUserTime)
+{
+ static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_get_system_times == 0)
+ {
+ g_b_init_get_system_times = 1;
+ s_pfn_Get_System_times =
+ (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
+ "GetSystemTimes");
+ }
+ if (s_pfn_Get_System_times == NULL)
+ return FALSE;
+ return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
+}
\f
/* Equivalent of strerror for W32 error codes. */
char *
#endif
}
-#ifndef HAVE_SOCKETS
-/* Emulate gethostname. */
-int
-gethostname (char *buffer, int size)
+/* Emulate getloadavg. */
+
+struct load_sample {
+ time_t sample_time;
+ ULONGLONG idle;
+ ULONGLONG kernel;
+ ULONGLONG user;
+};
+
+/* Number of processors on this machine. */
+static unsigned num_of_processors;
+
+/* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
+static struct load_sample samples[16*60];
+static int first_idx = -1, last_idx = -1;
+static int max_idx = sizeof (samples) / sizeof (samples[0]);
+
+static int
+buf_next (int from)
{
- /* NT only allows small host names, so the buffer is
- certainly large enough. */
- return !GetComputerName (buffer, &size);
+ int next_idx = from + 1;
+
+ if (next_idx >= max_idx)
+ next_idx = 0;
+
+ return next_idx;
+}
+
+static int
+buf_prev (int from)
+{
+ int prev_idx = from - 1;
+
+ if (prev_idx < 0)
+ prev_idx = max_idx - 1;
+
+ return prev_idx;
+}
+
+static void
+sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
+{
+ SYSTEM_INFO sysinfo;
+ FILETIME ft_idle, ft_user, ft_kernel;
+
+ /* Initialize the number of processors on this machine. */
+ if (num_of_processors <= 0)
+ {
+ get_native_system_info (&sysinfo);
+ num_of_processors = sysinfo.dwNumberOfProcessors;
+ if (num_of_processors <= 0)
+ {
+ GetSystemInfo (&sysinfo);
+ num_of_processors = sysinfo.dwNumberOfProcessors;
+ }
+ if (num_of_processors <= 0)
+ num_of_processors = 1;
+ }
+
+ /* TODO: Take into account threads that are ready to run, by
+ sampling the "\System\Processor Queue Length" performance
+ counter. The code below accounts only for threads that are
+ actually running. */
+
+ if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
+ {
+ ULARGE_INTEGER uidle, ukernel, uuser;
+
+ memcpy (&uidle, &ft_idle, sizeof (ft_idle));
+ memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
+ memcpy (&uuser, &ft_user, sizeof (ft_user));
+ *idle = uidle.QuadPart;
+ *kernel = ukernel.QuadPart;
+ *user = uuser.QuadPart;
+ }
+ else
+ {
+ *idle = 0;
+ *kernel = 0;
+ *user = 0;
+ }
+}
+
+/* Produce the load average for a given time interval, using the
+ samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
+ 1-minute, 5-minute, or 15-minute average, respectively. */
+static double
+getavg (int which)
+{
+ double retval = -1.0;
+ double tdiff;
+ int idx;
+ double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
+ time_t now = samples[last_idx].sample_time;
+
+ if (first_idx != last_idx)
+ {
+ for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
+ {
+ tdiff = difftime (now, samples[idx].sample_time);
+ if (tdiff >= span - 2*DBL_EPSILON*now)
+ {
+ long double sys =
+ samples[last_idx].kernel + samples[last_idx].user
+ - (samples[idx].kernel + samples[idx].user);
+ long double idl = samples[last_idx].idle - samples[idx].idle;
+
+ retval = (1.0 - idl / sys) * num_of_processors;
+ break;
+ }
+ if (idx == first_idx)
+ break;
+ }
+ }
+
+ return retval;
}
-#endif /* HAVE_SOCKETS */
-/* Emulate getloadavg. */
int
getloadavg (double loadavg[], int nelem)
{
- int i;
+ int elem;
+ ULONGLONG idle, kernel, user;
+ time_t now = time (NULL);
+
+ /* Store another sample. We ignore samples that are less than 1 sec
+ apart. */
+ if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
+ {
+ sample_system_load (&idle, &kernel, &user);
+ last_idx = buf_next (last_idx);
+ samples[last_idx].sample_time = now;
+ samples[last_idx].idle = idle;
+ samples[last_idx].kernel = kernel;
+ samples[last_idx].user = user;
+ /* If the buffer has more that 15 min worth of samples, discard
+ the old ones. */
+ if (first_idx == -1)
+ first_idx = last_idx;
+ while (first_idx != last_idx
+ && (difftime (now, samples[first_idx].sample_time)
+ >= 15.0*60 + 2*DBL_EPSILON*now))
+ first_idx = buf_next (first_idx);
+ }
- /* A faithful emulation is going to have to be saved for a rainy day. */
- for (i = 0; i < nelem; i++)
+ for (elem = 0; elem < nelem; elem++)
{
- loadavg[i] = 0.0;
+ double avg = getavg (elem);
+
+ if (avg < 0)
+ break;
+ loadavg[elem] = avg;
}
- return i;
+
+ return elem;
}
/* Emulate getpwuid, getpwnam and others. */
#define PASSWD_FIELD_SIZE 256
-static char the_passwd_name[PASSWD_FIELD_SIZE];
-static char the_passwd_passwd[PASSWD_FIELD_SIZE];
-static char the_passwd_gecos[PASSWD_FIELD_SIZE];
-static char the_passwd_dir[PASSWD_FIELD_SIZE];
-static char the_passwd_shell[PASSWD_FIELD_SIZE];
+static char dflt_passwd_name[PASSWD_FIELD_SIZE];
+static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
+static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
+static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
+static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
-static struct passwd the_passwd =
+static struct passwd dflt_passwd =
{
- the_passwd_name,
- the_passwd_passwd,
+ dflt_passwd_name,
+ dflt_passwd_passwd,
0,
0,
0,
- the_passwd_gecos,
- the_passwd_dir,
- the_passwd_shell,
+ dflt_passwd_gecos,
+ dflt_passwd_dir,
+ dflt_passwd_shell,
};
-static struct group the_group =
+static char dflt_group_name[GNLEN+1];
+
+static struct group dflt_group =
{
- /* There are no groups on NT, so we just return "root" as the
- group name. */
- "root",
+ /* When group information is not available, we return this as the
+ group for all files. */
+ dflt_group_name,
+ 0,
};
-int
-getuid ()
+unsigned
+getuid (void)
{
- return the_passwd.pw_uid;
+ return dflt_passwd.pw_uid;
}
-int
-geteuid ()
+unsigned
+geteuid (void)
{
/* I could imagine arguing for checking to see whether the user is
in the Administrators group and returning a UID of 0 for that
return getuid ();
}
-int
-getgid ()
+unsigned
+getgid (void)
{
- return the_passwd.pw_gid;
+ return dflt_passwd.pw_gid;
}
-int
-getegid ()
+unsigned
+getegid (void)
{
return getgid ();
}
struct passwd *
-getpwuid (int uid)
+getpwuid (unsigned uid)
{
- if (uid == the_passwd.pw_uid)
- return &the_passwd;
+ if (uid == dflt_passwd.pw_uid)
+ return &dflt_passwd;
return NULL;
}
struct group *
getgrgid (gid_t gid)
{
- return &the_group;
+ return &dflt_group;
}
struct passwd *
if (!pw)
return pw;
- if (stricmp (name, pw->pw_name))
+ if (xstrcasecmp (name, pw->pw_name))
return NULL;
return pw;
}
void
-init_user_info ()
+init_user_info (void)
{
/* Find the user's real name by opening the process token and
looking up the name associated with the user-sid in that token.
the user-sid as the user id value (same for group id using the
primary group sid from the process token). */
- char name[UNLEN+1], domain[1025];
- DWORD length = sizeof (name), dlength = sizeof (domain), trash;
+ char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
+ DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
+ DWORD glength = sizeof (gname);
HANDLE token = NULL;
SID_NAME_USE user_type;
- unsigned char buf[1024];
+ unsigned char *buf = NULL;
+ DWORD blen = 0;
TOKEN_USER user_token;
TOKEN_PRIMARY_GROUP group_token;
+ BOOL result;
- if (open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
- && get_token_information (token, TokenUser,
- (PVOID)buf, sizeof (buf), &trash)
- && (memcpy (&user_token, buf, sizeof (user_token)),
- lookup_account_sid (NULL, user_token.User.Sid, name, &length,
- domain, &dlength, &user_type)))
+ result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
+ if (result)
{
- strcpy (the_passwd.pw_name, name);
+ result = get_token_information (token, TokenUser, NULL, 0, &blen);
+ if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+ {
+ buf = xmalloc (blen);
+ result = get_token_information (token, TokenUser,
+ (LPVOID)buf, blen, &needed);
+ if (result)
+ {
+ memcpy (&user_token, buf, sizeof (user_token));
+ result = lookup_account_sid (NULL, user_token.User.Sid,
+ uname, &ulength,
+ domain, &dlength, &user_type);
+ }
+ }
+ else
+ result = FALSE;
+ }
+ if (result)
+ {
+ strcpy (dflt_passwd.pw_name, uname);
/* Determine a reasonable uid value. */
- if (stricmp ("administrator", name) == 0)
+ if (xstrcasecmp ("administrator", uname) == 0)
{
- the_passwd.pw_uid = 500; /* well-known Administrator uid */
- the_passwd.pw_gid = 513; /* well-known None gid */
+ dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
+ dflt_passwd.pw_gid = 513; /* well-known None gid */
}
else
{
/* Use the last sub-authority value of the RID, the relative
portion of the SID, as user/group ID. */
- DWORD n_subauthorities =
- *get_sid_sub_authority_count (user_token.User.Sid);
+ dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
- if (n_subauthorities < 1)
- the_passwd.pw_uid = 0; /* the "World" RID */
- else
+ /* Get group id and name. */
+ result = get_token_information (token, TokenPrimaryGroup,
+ (LPVOID)buf, blen, &needed);
+ if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
{
- the_passwd.pw_uid =
- *get_sid_sub_authority (user_token.User.Sid,
- n_subauthorities - 1);
+ buf = xrealloc (buf, blen = needed);
+ result = get_token_information (token, TokenPrimaryGroup,
+ (LPVOID)buf, blen, &needed);
}
-
- /* Get group id */
- if (get_token_information (token, TokenPrimaryGroup,
- (PVOID)buf, sizeof (buf), &trash))
+ if (result)
{
memcpy (&group_token, buf, sizeof (group_token));
- n_subauthorities =
- *get_sid_sub_authority_count (group_token.PrimaryGroup);
-
- if (n_subauthorities < 1)
- the_passwd.pw_gid = 0; /* the "World" RID */
- else
- {
- the_passwd.pw_gid =
- *get_sid_sub_authority (group_token.PrimaryGroup,
- n_subauthorities - 1);
- }
+ dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
+ dlength = sizeof (domain);
+ /* If we can get at the real Primary Group name, use that.
+ Otherwise, the default group name was already set to
+ "None" in globals_of_w32. */
+ if (lookup_account_sid (NULL, group_token.PrimaryGroup,
+ gname, &glength, NULL, &dlength,
+ &user_type))
+ strcpy (dflt_group_name, gname);
}
else
- the_passwd.pw_gid = the_passwd.pw_uid;
+ dflt_passwd.pw_gid = dflt_passwd.pw_uid;
}
}
/* If security calls are not supported (presumably because we
- are running under Windows 95), fallback to this. */
- else if (GetUserName (name, &length))
+ are running under Windows 9X), fallback to this: */
+ else if (GetUserName (uname, &ulength))
{
- strcpy (the_passwd.pw_name, name);
- if (stricmp ("administrator", name) == 0)
- the_passwd.pw_uid = 0;
+ strcpy (dflt_passwd.pw_name, uname);
+ if (xstrcasecmp ("administrator", uname) == 0)
+ dflt_passwd.pw_uid = 0;
else
- the_passwd.pw_uid = 123;
- the_passwd.pw_gid = the_passwd.pw_uid;
+ dflt_passwd.pw_uid = 123;
+ dflt_passwd.pw_gid = dflt_passwd.pw_uid;
}
else
{
- strcpy (the_passwd.pw_name, "unknown");
- the_passwd.pw_uid = 123;
- the_passwd.pw_gid = 123;
+ strcpy (dflt_passwd.pw_name, "unknown");
+ dflt_passwd.pw_uid = 123;
+ dflt_passwd.pw_gid = 123;
}
+ dflt_group.gr_gid = dflt_passwd.pw_gid;
/* Ensure HOME and SHELL are defined. */
if (getenv ("HOME") == NULL)
abort ();
/* Set dir and shell from environment variables. */
- strcpy (the_passwd.pw_dir, getenv ("HOME"));
- strcpy (the_passwd.pw_shell, getenv ("SHELL"));
+ strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
+ strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
+ xfree (buf);
if (token)
CloseHandle (token);
}
int
-random ()
+random (void)
{
/* rand () on NT gives us 15 random bits...hack together 30 bits. */
return ((rand () << 15) | rand ());
case path name components to lower case. */
static void
-normalize_filename (fp, path_sep)
- register char *fp;
- char path_sep;
+normalize_filename (register char *fp, char path_sep)
{
char sep;
char *elem;
/* Destructively turn backslashes into slashes. */
void
-dostounix_filename (p)
- register char *p;
+dostounix_filename (register char *p)
{
normalize_filename (p, '/');
}
/* Destructively turn slashes into backslashes. */
void
-unixtodos_filename (p)
- register char *p;
+unixtodos_filename (register char *p)
{
normalize_filename (p, '\\');
}
(From msdos.c...probably should figure out a way to share it,
although this code isn't going to ever change.) */
int
-crlf_to_lf (n, buf)
- register int n;
- register unsigned char *buf;
+crlf_to_lf (register int n, register unsigned char *buf)
{
unsigned char *np = buf;
unsigned char *startp = buf;
return 0;
}
+int
+sigemptyset (sigset_t *set)
+{
+ return 0;
+}
+
+int
+sigaddset (sigset_t *set, int signo)
+{
+ return 0;
+}
+
+int
+sigfillset (sigset_t *set)
+{
+ return 0;
+}
+
+int
+sigprocmask (int how, const sigset_t *set, sigset_t *oset)
+{
+ return 0;
+}
+
int
setpgrp (int pid, int gid)
{
#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
LPBYTE
-w32_get_resource (key, lpdwtype)
- char *key;
- LPDWORD lpdwtype;
+w32_get_resource (char *key, LPDWORD lpdwtype)
{
LPBYTE lpvalue;
HKEY hrootkey = NULL;
return (lpvalue);
}
- if (lpvalue) xfree (lpvalue);
+ xfree (lpvalue);
RegCloseKey (hrootkey);
}
return (lpvalue);
}
- if (lpvalue) xfree (lpvalue);
+ xfree (lpvalue);
RegCloseKey (hrootkey);
}
{"LANG", NULL},
};
-#define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
+#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
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;
+ MSIE 5. */
ShGetFolderPath_fn get_folder_path;
- shell32_dll = GetModuleHandle ("shell32.dll");
get_folder_path = (ShGetFolderPath_fn)
- GetProcAddress (shell32_dll, "SHGetFolderPathA");
+ GetProcAddress (GetModuleHandle ("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 we can't get the appdata dir, revert to old behavior. */
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. */
abort ();
*p = 0;
- if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 0)
+ if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
{
char buf[SET_ENV_BUF_SIZE];
for (p = modname; *p; p++)
if (*p == '\\') *p = '/';
- _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
+ _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)
+ else if (p && xstrcasecmp (p, "\\i386") == 0)
{
*p = 0;
p = strrchr (modname, '\\');
{
*p = 0;
p = strrchr (modname, '\\');
- if (p && stricmp (p, "\\src") == 0)
+ if (p && xstrcasecmp (p, "\\src") == 0)
{
char buf[SET_ENV_BUF_SIZE];
for (p = modname; *p; p++)
if (*p == '\\') *p = '/';
- _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
+ _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
_putenv (strdup (buf));
}
}
/* Also ignore empty environment variables. */
|| *lpval == 0)
{
- if (lpval) xfree (lpval);
+ xfree (lpval);
lpval = env_vars[i].def_value;
dwType = REG_EXPAND_SZ;
dont_free = 1;
char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
if (dwType == REG_EXPAND_SZ)
- ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
+ ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
else if (dwType == REG_SZ)
strcpy (buf1, lpval);
if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
{
- _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name,
+ _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
buf1);
_putenv (strdup (buf2));
}
char *
get_emacs_configuration_options (void)
{
- static char options_buffer[256];
+ static char *options_buffer;
+ char cv[32]; /* Enough for COMPILER_VERSION. */
+ char *options[] = {
+ cv, /* To be filled later. */
+#ifdef EMACSDEBUG
+ " --no-opt",
+#endif
+ /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
+ with a starting space to save work here. */
+#ifdef USER_CFLAGS
+ " --cflags", USER_CFLAGS,
+#endif
+#ifdef USER_LDFLAGS
+ " --ldflags", USER_LDFLAGS,
+#endif
+ NULL
+ };
+ size_t size = 0;
+ int i;
/* Work out the effective configure options for this build. */
#ifdef _MSC_VER
#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
+ if (_snprintf (cv, sizeof (cv), COMPILER_VERSION) < 0)
+ return "Error: not enough space for compiler version";
+
+ for (i = 0; options[i]; i++)
+ size += strlen (options[i]);
+
+ options_buffer = xmalloc (size + 1);
+ options_buffer[0] = '\0';
+
+ for (i = 0; options[i]; i++)
+ strcat (options_buffer, options[i]);
+
return options_buffer;
}
volume_info_data * info;
for (info = volume_cache; info; info = info->next)
- if (stricmp (info->root_dir, root_dir) == 0)
+ if (xstrcasecmp (info->root_dir, root_dir) == 0)
break;
return info;
}
involve network access, and so is extremely quick). */
/* Map drive letter to UNC if remote. */
- if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
+ if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
{
char remote_name[ 256 ];
char drive[3] = { root_dir[0], ':' };
char * p = strrchr (name, '.');
return
(p != NULL
- && (stricmp (p, ".exe") == 0 ||
- stricmp (p, ".com") == 0 ||
- stricmp (p, ".bat") == 0 ||
- stricmp (p, ".cmd") == 0));
+ && (xstrcasecmp (p, ".exe") == 0 ||
+ xstrcasecmp (p, ".com") == 0 ||
+ xstrcasecmp (p, ".bat") == 0 ||
+ xstrcasecmp (p, ".cmd") == 0));
}
/* Emulate the Unix directory procedures opendir, closedir,
nr.lpComment = NULL;
nr.lpProvider = NULL;
- result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
- RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
+ result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
+ RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
if (result == NO_ERROR)
return henum;
char share[MAX_PATH];
int i, n_slashes;
char drive[4];
+ UINT drvtype;
- sprintf (drive, "%c:\\", path[0]);
+ if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
+ drvtype = DRIVE_REMOTE;
+ else if (path[0] == '\0' || path[1] != ':')
+ drvtype = GetDriveType (NULL);
+ else
+ {
+ drive[0] = path[0];
+ drive[1] = ':';
+ drive[2] = '\\';
+ drive[3] = '\0';
+ drvtype = GetDriveType (drive);
+ }
/* Only logon to networked drives. */
- if ((!IS_DIRECTORY_SEP (path[0]) || !IS_DIRECTORY_SEP (path[1]))
- && GetDriveType (drive) != DRIVE_REMOTE)
+ if (drvtype != DRIVE_REMOTE)
return;
n_slashes = 2;
}
FILE *
-sys_fopen(const char * path, const char * mode)
+sys_fopen (const char * path, const char * mode)
{
int fd;
int oflag;
data.wid.dwStreamId = BACKUP_LINK;
data.wid.dwStreamAttributes = 0;
- data.wid.Size.LowPart = wlen * sizeof(WCHAR);
+ data.wid.Size.LowPart = wlen * sizeof (WCHAR);
data.wid.Size.HighPart = 0;
data.wid.dwStreamNameSize = 0;
return -1;
}
- /* Emulate Unix behaviour - newname is deleted if it already exists
+ /* 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
}
static FILETIME utc_base_ft;
-static long double utc_base;
+static ULONGLONG utc_base; /* In 100ns units */
static int init = 0;
+#define FILETIME_TO_U64(result, ft) \
+ do { \
+ ULARGE_INTEGER uiTemp; \
+ uiTemp.LowPart = (ft).dwLowDateTime; \
+ uiTemp.HighPart = (ft).dwHighDateTime; \
+ result = uiTemp.QuadPart; \
+ } while (0)
+
+static void
+initialize_utc_base (void)
+{
+ /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
+ SYSTEMTIME st;
+
+ st.wYear = 1970;
+ st.wMonth = 1;
+ st.wDay = 1;
+ st.wHour = 0;
+ st.wMinute = 0;
+ st.wSecond = 0;
+ st.wMilliseconds = 0;
+
+ SystemTimeToFileTime (&st, &utc_base_ft);
+ FILETIME_TO_U64 (utc_base, utc_base_ft);
+}
+
static time_t
convert_time (FILETIME ft)
{
- long double ret;
+ ULONGLONG tmp;
if (!init)
{
- /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
- SYSTEMTIME st;
-
- st.wYear = 1970;
- st.wMonth = 1;
- st.wDay = 1;
- st.wHour = 0;
- st.wMinute = 0;
- st.wSecond = 0;
- st.wMilliseconds = 0;
-
- SystemTimeToFileTime (&st, &utc_base_ft);
- utc_base = (long double) utc_base_ft.dwHighDateTime
- * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
+ initialize_utc_base();
init = 1;
}
if (CompareFileTime (&ft, &utc_base_ft) < 0)
return 0;
- ret = (long double) ft.dwHighDateTime
- * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
- ret -= utc_base;
- return (time_t) (ret * 1e-7L);
+ FILETIME_TO_U64 (tmp, ft);
+ return (time_t) ((tmp - utc_base) / 10000000L);
}
+
void
convert_from_time_t (time_t time, FILETIME * pft)
{
- long double tmp;
+ ULARGE_INTEGER tmp;
if (!init)
{
- /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
- SYSTEMTIME st;
-
- st.wYear = 1970;
- st.wMonth = 1;
- st.wDay = 1;
- st.wHour = 0;
- st.wMinute = 0;
- st.wSecond = 0;
- st.wMilliseconds = 0;
-
- SystemTimeToFileTime (&st, &utc_base_ft);
- utc_base = (long double) utc_base_ft.dwHighDateTime
- * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
+ initialize_utc_base ();
init = 1;
}
/* time in 100ns units since 1-Jan-1601 */
- tmp = (long double) time * 1e7 + utc_base;
- pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
- pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
+ tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
+ pft->dwHighDateTime = tmp.HighPart;
+ pft->dwLowDateTime = tmp.LowPart;
}
#if 0
#endif
-/* MSVC stat function can't cope with UNC names and has other bugs, so
- replace it with our own. This also allows us to calculate consistent
- inode values without hacks in the main Emacs code. */
-int
-stat (const char * path, struct stat * buf)
+static PSECURITY_DESCRIPTOR
+get_file_security_desc (const char *fname)
{
- char *name, *r;
- WIN32_FIND_DATA wfd;
+ PSECURITY_DESCRIPTOR psd = NULL;
+ DWORD sd_len, err;
+ SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
+ | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
+
+ if (!get_file_security (fname, si, psd, 0, &sd_len))
+ {
+ err = GetLastError ();
+ if (err != ERROR_INSUFFICIENT_BUFFER)
+ return NULL;
+ }
+
+ psd = xmalloc (sd_len);
+ if (!get_file_security (fname, si, psd, sd_len, &sd_len))
+ {
+ xfree (psd);
+ return NULL;
+ }
+
+ return psd;
+}
+
+static DWORD
+get_rid (PSID sid)
+{
+ unsigned n_subauthorities;
+
+ /* Use the last sub-authority value of the RID, the relative
+ portion of the SID, as user/group ID. */
+ n_subauthorities = *get_sid_sub_authority_count (sid);
+ if (n_subauthorities < 1)
+ return 0; /* the "World" RID */
+ return *get_sid_sub_authority (sid, n_subauthorities - 1);
+}
+
+/* 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;
+ char name[GNLEN+1];
+ unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
+};
+
+static struct w32_id *w32_idlist;
+
+static int
+w32_cached_id (PSID sid, unsigned *id, char *name)
+{
+ struct w32_id *tail, *found;
+
+ for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
+ {
+ if (equal_sid ((PSID)tail->sid, sid))
+ {
+ found = tail;
+ break;
+ }
+ }
+ if (found)
+ {
+ *id = found->rid;
+ strcpy (name, found->name);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static void
+w32_add_to_cache (PSID sid, unsigned id, char *name)
+{
+ DWORD sid_len;
+ struct w32_id *new_entry;
+
+ /* We don't want to leave behind stale cache from when Emacs was
+ dumped. */
+ if (initialized)
+ {
+ sid_len = get_length_sid (sid);
+ new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
+ if (new_entry)
+ {
+ new_entry->rid = id;
+ strcpy (new_entry->name, name);
+ copy_sid (sid_len, (PSID)new_entry->sid, sid);
+ new_entry->next = w32_idlist;
+ w32_idlist = new_entry;
+ }
+ }
+}
+
+#define UID 1
+#define GID 2
+
+static int
+get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
+ unsigned *id, char *nm, int what)
+{
+ PSID sid = NULL;
+ char machine[MAX_COMPUTERNAME_LENGTH+1];
+ BOOL dflt;
+ SID_NAME_USE ignore;
+ char name[UNLEN+1];
+ DWORD name_len = sizeof (name);
+ char domain[1024];
+ DWORD domain_len = sizeof (domain);
+ char *mp = NULL;
+ int use_dflt = 0;
+ int result;
+
+ if (what == UID)
+ result = get_security_descriptor_owner (psd, &sid, &dflt);
+ else if (what == GID)
+ result = get_security_descriptor_group (psd, &sid, &dflt);
+ else
+ result = 0;
+
+ if (!result || !is_valid_sid (sid))
+ use_dflt = 1;
+ else if (!w32_cached_id (sid, id, nm))
+ {
+ /* If FNAME is a UNC, we need to lookup account on the
+ specified machine. */
+ if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
+ && fname[2] != '\0')
+ {
+ const char *s;
+ char *p;
+
+ for (s = fname + 2, p = machine;
+ *s && !IS_DIRECTORY_SEP (*s); s++, p++)
+ *p = *s;
+ *p = '\0';
+ mp = machine;
+ }
+
+ if (!lookup_account_sid (mp, sid, name, &name_len,
+ domain, &domain_len, &ignore)
+ || name_len > UNLEN+1)
+ use_dflt = 1;
+ else
+ {
+ *id = get_rid (sid);
+ strcpy (nm, name);
+ w32_add_to_cache (sid, *id, name);
+ }
+ }
+ return use_dflt;
+}
+
+static void
+get_file_owner_and_group (
+ PSECURITY_DESCRIPTOR psd,
+ const char *fname,
+ struct stat *st)
+{
+ int dflt_usr = 0, dflt_grp = 0;
+
+ if (!psd)
+ {
+ dflt_usr = 1;
+ dflt_grp = 1;
+ }
+ else
+ {
+ if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
+ dflt_usr = 1;
+ if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
+ dflt_grp = 1;
+ }
+ /* Consider files to belong to current user/group, if we cannot get
+ more accurate information. */
+ if (dflt_usr)
+ {
+ st->st_uid = dflt_passwd.pw_uid;
+ strcpy (st->st_uname, dflt_passwd.pw_name);
+ }
+ if (dflt_grp)
+ {
+ st->st_gid = dflt_passwd.pw_gid;
+ strcpy (st->st_gname, dflt_group.gr_name);
+ }
+}
+
+/* Return non-zero if NAME is a potentially slow filesystem. */
+int
+is_slow_fs (const char *name)
+{
+ char drive_root[4];
+ UINT devtype;
+
+ if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
+ devtype = DRIVE_REMOTE; /* assume UNC name is remote */
+ else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
+ devtype = GetDriveType (NULL); /* use root of current drive */
+ else
+ {
+ /* GetDriveType needs the root directory of the drive. */
+ strncpy (drive_root, name, 2);
+ drive_root[2] = '\\';
+ drive_root[3] = '\0';
+ devtype = GetDriveType (drive_root);
+ }
+ return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
+}
+
+/* MSVC stat function can't cope with UNC names and has other bugs, so
+ replace it with our own. This also allows us to calculate consistent
+ inode values without hacks in the main Emacs code. */
+int
+stat (const char * path, struct stat * buf)
+{
+ char *name, *r;
+ char drive_root[4];
+ UINT devtype;
+ WIN32_FIND_DATA wfd;
HANDLE fh;
unsigned __int64 fake_inode;
int permission;
int len;
int rootdir = FALSE;
+ PSECURITY_DESCRIPTOR psd = NULL;
if (path == NULL || buf == NULL)
{
if (dir_find_handle != INVALID_HANDLE_VALUE
&& strnicmp (name, dir_pathname, len) == 0
&& IS_DIRECTORY_SEP (name[len])
- && stricmp (name + len + 1, dir_static.d_name) == 0)
+ && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
{
/* This was the last entry returned by readdir. */
wfd = dir_find_data;
}
}
- if (!NILP (Vw32_get_true_file_attributes)
+ if (!(NILP (Vw32_get_true_file_attributes)
+ || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
/* No access rights required to get info. */
&& (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL))
}
}
CloseHandle (fh);
+ psd = get_file_security_desc (name);
+ get_file_owner_and_group (psd, name, buf);
}
else
{
S_IFDIR : S_IFREG;
buf->st_nlink = 1;
fake_inode = 0;
+
+ get_file_owner_and_group (NULL, name, buf);
}
+ xfree (psd);
#if 0
/* Not sure if there is any point in this. */
else
buf->st_ino = fake_inode;
- /* consider files to belong to current user */
- buf->st_uid = the_passwd.pw_uid;
- buf->st_gid = the_passwd.pw_gid;
-
/* volume_info is set indirectly by map_w32_filename */
buf->st_dev = volume_info.serialnum;
buf->st_rdev = volume_info.serialnum;
- buf->st_size = wfd.nFileSizeLow;
+ buf->st_size = wfd.nFileSizeHigh;
+ buf->st_size <<= 32;
+ buf->st_size += wfd.nFileSizeLow;
/* Convert timestamps to Unix format. */
buf->st_mtime = convert_time (wfd.ftLastWriteTime);
else
buf->st_ino = fake_inode;
- /* consider files to belong to current user */
- buf->st_uid = the_passwd.pw_uid;
- buf->st_gid = the_passwd.pw_gid;
+ /* Consider files to belong to current user.
+ FIXME: this should use GetSecurityInfo API, but it is only
+ available for _WIN32_WINNT >= 0x501. */
+ buf->st_uid = dflt_passwd.pw_uid;
+ buf->st_gid = dflt_passwd.pw_gid;
+ strcpy (buf->st_uname, dflt_passwd.pw_name);
+ strcpy (buf->st_gname, dflt_group.gr_name);
buf->st_dev = info.dwVolumeSerialNumber;
buf->st_rdev = info.dwVolumeSerialNumber;
- buf->st_size = info.nFileSizeLow;
+ buf->st_size = info.nFileSizeHigh;
+ buf->st_size <<= 32;
+ buf->st_size += info.nFileSizeLow;
/* Convert timestamps to Unix format. */
buf->st_mtime = convert_time (info.ftLastWriteTime);
#if 0 /* no way of knowing the filename */
char * p = strrchr (name, '.');
if (p != NULL &&
- (stricmp (p, ".exe") == 0 ||
- stricmp (p, ".com") == 0 ||
- stricmp (p, ".bat") == 0 ||
- stricmp (p, ".cmd") == 0))
+ (xstrcasecmp (p, ".exe") == 0 ||
+ xstrcasecmp (p, ".com") == 0 ||
+ xstrcasecmp (p, ".bat") == 0 ||
+ xstrcasecmp (p, ".cmd") == 0))
permission |= S_IEXEC;
#endif
}
return 0;
}
-#ifdef HAVE_SOCKETS
+\f
+/* Support for browsing other processes and their attributes. See
+ process.c for the Lisp bindings. */
+
+/* Helper wrapper functions. */
+
+HANDLE WINAPI create_toolhelp32_snapshot (
+ DWORD Flags,
+ DWORD Ignored)
+{
+ static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
+
+ if (g_b_init_create_toolhelp32_snapshot == 0)
+ {
+ g_b_init_create_toolhelp32_snapshot = 1;
+ s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
+ GetProcAddress (GetModuleHandle ("kernel32.dll"),
+ "CreateToolhelp32Snapshot");
+ }
+ if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
+ {
+ return INVALID_HANDLE_VALUE;
+ }
+ return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
+}
+
+BOOL WINAPI process32_first (
+ HANDLE hSnapshot,
+ LPPROCESSENTRY32 lppe)
+{
+ static Process32First_Proc s_pfn_Process32_First = NULL;
+
+ if (g_b_init_process32_first == 0)
+ {
+ g_b_init_process32_first = 1;
+ s_pfn_Process32_First = (Process32First_Proc)
+ GetProcAddress (GetModuleHandle ("kernel32.dll"),
+ "Process32First");
+ }
+ if (s_pfn_Process32_First == NULL)
+ {
+ return FALSE;
+ }
+ return (s_pfn_Process32_First (hSnapshot, lppe));
+}
+
+BOOL WINAPI process32_next (
+ HANDLE hSnapshot,
+ LPPROCESSENTRY32 lppe)
+{
+ static Process32Next_Proc s_pfn_Process32_Next = NULL;
+
+ if (g_b_init_process32_next == 0)
+ {
+ g_b_init_process32_next = 1;
+ s_pfn_Process32_Next = (Process32Next_Proc)
+ GetProcAddress (GetModuleHandle ("kernel32.dll"),
+ "Process32Next");
+ }
+ if (s_pfn_Process32_Next == NULL)
+ {
+ return FALSE;
+ }
+ return (s_pfn_Process32_Next (hSnapshot, lppe));
+}
+
+BOOL WINAPI open_thread_token (
+ HANDLE ThreadHandle,
+ DWORD DesiredAccess,
+ BOOL OpenAsSelf,
+ PHANDLE TokenHandle)
+{
+ static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ SetLastError (ERROR_NOT_SUPPORTED);
+ return FALSE;
+ }
+ if (g_b_init_open_thread_token == 0)
+ {
+ g_b_init_open_thread_token = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Open_Thread_Token =
+ (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
+ }
+ if (s_pfn_Open_Thread_Token == NULL)
+ {
+ SetLastError (ERROR_NOT_SUPPORTED);
+ return FALSE;
+ }
+ return (
+ s_pfn_Open_Thread_Token (
+ ThreadHandle,
+ DesiredAccess,
+ OpenAsSelf,
+ TokenHandle)
+ );
+}
+
+BOOL WINAPI impersonate_self (
+ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
+{
+ static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_impersonate_self == 0)
+ {
+ g_b_init_impersonate_self = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Impersonate_Self =
+ (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
+ }
+ if (s_pfn_Impersonate_Self == NULL)
+ {
+ return FALSE;
+ }
+ return s_pfn_Impersonate_Self (ImpersonationLevel);
+}
+
+BOOL WINAPI revert_to_self (void)
+{
+ static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_revert_to_self == 0)
+ {
+ g_b_init_revert_to_self = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Revert_To_Self =
+ (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
+ }
+ if (s_pfn_Revert_To_Self == NULL)
+ {
+ return FALSE;
+ }
+ return s_pfn_Revert_To_Self ();
+}
+
+BOOL WINAPI get_process_memory_info (
+ HANDLE h_proc,
+ PPROCESS_MEMORY_COUNTERS mem_counters,
+ DWORD bufsize)
+{
+ static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
+ HMODULE hm_psapi = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_get_process_memory_info == 0)
+ {
+ g_b_init_get_process_memory_info = 1;
+ hm_psapi = LoadLibrary ("Psapi.dll");
+ if (hm_psapi)
+ s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
+ GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
+ }
+ if (s_pfn_Get_Process_Memory_Info == NULL)
+ {
+ return FALSE;
+ }
+ return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
+}
+
+BOOL WINAPI get_process_working_set_size (
+ HANDLE h_proc,
+ DWORD *minrss,
+ DWORD *maxrss)
+{
+ static GetProcessWorkingSetSize_Proc
+ s_pfn_Get_Process_Working_Set_Size = NULL;
+
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_get_process_working_set_size == 0)
+ {
+ g_b_init_get_process_working_set_size = 1;
+ s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
+ GetProcAddress (GetModuleHandle ("kernel32.dll"),
+ "GetProcessWorkingSetSize");
+ }
+ if (s_pfn_Get_Process_Working_Set_Size == NULL)
+ {
+ return FALSE;
+ }
+ return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
+}
+
+BOOL WINAPI global_memory_status (
+ MEMORYSTATUS *buf)
+{
+ static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
+
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_global_memory_status == 0)
+ {
+ g_b_init_global_memory_status = 1;
+ s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
+ GetProcAddress (GetModuleHandle ("kernel32.dll"),
+ "GlobalMemoryStatus");
+ }
+ if (s_pfn_Global_Memory_Status == NULL)
+ {
+ return FALSE;
+ }
+ return s_pfn_Global_Memory_Status (buf);
+}
+
+BOOL WINAPI global_memory_status_ex (
+ MEMORY_STATUS_EX *buf)
+{
+ static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
+
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_global_memory_status_ex == 0)
+ {
+ g_b_init_global_memory_status_ex = 1;
+ s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
+ GetProcAddress (GetModuleHandle ("kernel32.dll"),
+ "GlobalMemoryStatusEx");
+ }
+ if (s_pfn_Global_Memory_Status_Ex == NULL)
+ {
+ return FALSE;
+ }
+ return s_pfn_Global_Memory_Status_Ex (buf);
+}
+
+Lisp_Object
+list_system_processes (void)
+{
+ struct gcpro gcpro1;
+ Lisp_Object proclist = Qnil;
+ HANDLE h_snapshot;
+
+ h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
+
+ if (h_snapshot != INVALID_HANDLE_VALUE)
+ {
+ PROCESSENTRY32 proc_entry;
+ 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))
+ {
+ proc_id = proc_entry.th32ProcessID;
+ proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
+ }
+
+ CloseHandle (h_snapshot);
+ UNGCPRO;
+ proclist = Fnreverse (proclist);
+ }
+
+ return proclist;
+}
+
+static int
+enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
+{
+ TOKEN_PRIVILEGES priv;
+ DWORD priv_size = sizeof (priv);
+ DWORD opriv_size = sizeof (*old_priv);
+ HANDLE h_token = NULL;
+ HANDLE h_thread = GetCurrentThread ();
+ int ret_val = 0;
+ BOOL res;
+
+ res = open_thread_token (h_thread,
+ TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
+ FALSE, &h_token);
+ if (!res && GetLastError () == ERROR_NO_TOKEN)
+ {
+ if (impersonate_self (SecurityImpersonation))
+ res = open_thread_token (h_thread,
+ TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
+ FALSE, &h_token);
+ }
+ if (res)
+ {
+ priv.PrivilegeCount = 1;
+ priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
+ LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
+ if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
+ old_priv, &opriv_size)
+ && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
+ ret_val = 1;
+ }
+ if (h_token)
+ CloseHandle (h_token);
+
+ return ret_val;
+}
+
+static int
+restore_privilege (TOKEN_PRIVILEGES *priv)
+{
+ DWORD priv_size = sizeof (*priv);
+ HANDLE h_token = NULL;
+ int ret_val = 0;
+
+ if (open_thread_token (GetCurrentThread (),
+ TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
+ FALSE, &h_token))
+ {
+ if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
+ && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
+ ret_val = 1;
+ }
+ if (h_token)
+ CloseHandle (h_token);
+
+ return ret_val;
+}
+
+static Lisp_Object
+ltime (long time_sec, long time_usec)
+{
+ return list3 (make_number ((time_sec >> 16) & 0xffff),
+ make_number (time_sec & 0xffff),
+ make_number (time_usec));
+}
+
+#define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
+
+static int
+process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
+ Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
+ double *pcpu)
+{
+ FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
+ ULONGLONG tem1, tem2, tem3, tem;
+
+ if (!h_proc
+ || !get_process_times_fn
+ || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
+ &ft_kernel, &ft_user))
+ return 0;
+
+ GetSystemTimeAsFileTime (&ft_current);
+
+ FILETIME_TO_U64 (tem1, ft_kernel);
+ tem1 /= 10L;
+ *stime = U64_TO_LISP_TIME (tem1);
+
+ FILETIME_TO_U64 (tem2, ft_user);
+ tem2 /= 10L;
+ *utime = U64_TO_LISP_TIME (tem2);
+
+ tem3 = tem1 + tem2;
+ *ttime = U64_TO_LISP_TIME (tem3);
+
+ FILETIME_TO_U64 (tem, ft_creation);
+ /* Process no 4 (System) returns zero creation time. */
+ if (tem)
+ tem = (tem - utc_base) / 10L;
+ *ctime = U64_TO_LISP_TIME (tem);
+
+ if (tem)
+ {
+ FILETIME_TO_U64 (tem3, ft_current);
+ tem = (tem3 - utc_base) / 10L - tem;
+ }
+ *etime = U64_TO_LISP_TIME (tem);
+
+ if (tem)
+ {
+ *pcpu = 100.0 * (tem1 + tem2) / tem;
+ if (*pcpu > 100)
+ *pcpu = 100.0;
+ }
+ else
+ *pcpu = 0;
+
+ return 1;
+}
+
+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;
+ DWORD proc_id;
+ int found_proc = 0;
+ char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
+ DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
+ DWORD glength = sizeof (gname);
+ HANDLE token = NULL;
+ SID_NAME_USE user_type;
+ unsigned char *buf = NULL;
+ DWORD blen = 0;
+ TOKEN_USER user_token;
+ TOKEN_PRIMARY_GROUP group_token;
+ unsigned euid;
+ unsigned egid;
+ DWORD sess;
+ PROCESS_MEMORY_COUNTERS mem;
+ PROCESS_MEMORY_COUNTERS_EX mem_ex;
+ DWORD minrss, maxrss;
+ MEMORYSTATUS memst;
+ MEMORY_STATUS_EX memstex;
+ double totphys = 0.0;
+ Lisp_Object ctime, stime, utime, etime, ttime;
+ double pcpu;
+ BOOL result = FALSE;
+
+ CHECK_NUMBER_OR_FLOAT (pid);
+ proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
+
+ h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
+
+ GCPRO3 (attrs, decoded_cmd, tem);
+
+ if (h_snapshot != INVALID_HANDLE_VALUE)
+ {
+ PROCESSENTRY32 pe;
+ BOOL res;
+
+ pe.dwSize = sizeof (PROCESSENTRY32);
+ for (res = process32_first (h_snapshot, &pe); res;
+ res = process32_next (h_snapshot, &pe))
+ {
+ if (proc_id == pe.th32ProcessID)
+ {
+ if (proc_id == 0)
+ decoded_cmd = build_string ("Idle");
+ else
+ {
+ /* Decode the command name from locale-specific
+ encoding. */
+ cmd_str = make_unibyte_string (pe.szExeFile,
+ strlen (pe.szExeFile));
+ decoded_cmd =
+ code_convert_string_norecord (cmd_str,
+ Vlocale_coding_system, 0);
+ }
+ attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
+ attrs = Fcons (Fcons (Qppid,
+ make_fixnum_or_float (pe.th32ParentProcessID)),
+ attrs);
+ attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
+ attrs);
+ attrs = Fcons (Fcons (Qthcount,
+ make_fixnum_or_float (pe.cntThreads)),
+ attrs);
+ found_proc = 1;
+ break;
+ }
+ }
+
+ CloseHandle (h_snapshot);
+ }
+
+ if (!found_proc)
+ {
+ UNGCPRO;
+ return Qnil;
+ }
+
+ h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+ FALSE, proc_id);
+ /* If we were denied a handle to the process, try again after
+ enabling the SeDebugPrivilege in our process. */
+ if (!h_proc)
+ {
+ TOKEN_PRIVILEGES priv_current;
+
+ if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
+ {
+ h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+ FALSE, proc_id);
+ restore_privilege (&priv_current);
+ revert_to_self ();
+ }
+ }
+ if (h_proc)
+ {
+ result = open_process_token (h_proc, TOKEN_QUERY, &token);
+ if (result)
+ {
+ result = get_token_information (token, TokenUser, NULL, 0, &blen);
+ if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+ {
+ buf = xmalloc (blen);
+ result = get_token_information (token, TokenUser,
+ (LPVOID)buf, blen, &needed);
+ if (result)
+ {
+ memcpy (&user_token, buf, sizeof (user_token));
+ if (!w32_cached_id (user_token.User.Sid, &euid, uname))
+ {
+ euid = get_rid (user_token.User.Sid);
+ result = lookup_account_sid (NULL, user_token.User.Sid,
+ uname, &ulength,
+ domain, &dlength,
+ &user_type);
+ if (result)
+ w32_add_to_cache (user_token.User.Sid, euid, uname);
+ else
+ {
+ strcpy (uname, "unknown");
+ result = TRUE;
+ }
+ }
+ ulength = strlen (uname);
+ }
+ }
+ }
+ if (result)
+ {
+ /* Determine a reasonable euid and gid values. */
+ if (xstrcasecmp ("administrator", uname) == 0)
+ {
+ euid = 500; /* well-known Administrator uid */
+ egid = 513; /* well-known None gid */
+ }
+ else
+ {
+ /* Get group id and name. */
+ result = get_token_information (token, TokenPrimaryGroup,
+ (LPVOID)buf, blen, &needed);
+ if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+ {
+ buf = xrealloc (buf, blen = needed);
+ result = get_token_information (token, TokenPrimaryGroup,
+ (LPVOID)buf, blen, &needed);
+ }
+ if (result)
+ {
+ memcpy (&group_token, buf, sizeof (group_token));
+ if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
+ {
+ egid = get_rid (group_token.PrimaryGroup);
+ dlength = sizeof (domain);
+ result =
+ lookup_account_sid (NULL, group_token.PrimaryGroup,
+ gname, &glength, NULL, &dlength,
+ &user_type);
+ if (result)
+ w32_add_to_cache (group_token.PrimaryGroup,
+ egid, gname);
+ else
+ {
+ strcpy (gname, "None");
+ result = TRUE;
+ }
+ }
+ glength = strlen (gname);
+ }
+ }
+ }
+ xfree (buf);
+ }
+ if (!result)
+ {
+ if (!is_windows_9x ())
+ {
+ /* We couldn't open the process token, presumably because of
+ insufficient access rights. Assume this process is run
+ by the system. */
+ strcpy (uname, "SYSTEM");
+ strcpy (gname, "None");
+ euid = 18; /* SYSTEM */
+ egid = 513; /* None */
+ glength = strlen (gname);
+ ulength = strlen (uname);
+ }
+ /* If we are running under Windows 9X, where security calls are
+ not supported, we assume all processes are run by the current
+ user. */
+ else if (GetUserName (uname, &ulength))
+ {
+ if (xstrcasecmp ("administrator", uname) == 0)
+ euid = 0;
+ else
+ euid = 123;
+ egid = euid;
+ strcpy (gname, "None");
+ glength = strlen (gname);
+ ulength = strlen (uname);
+ }
+ else
+ {
+ euid = 123;
+ egid = 123;
+ strcpy (uname, "administrator");
+ ulength = strlen (uname);
+ strcpy (gname, "None");
+ glength = strlen (gname);
+ }
+ if (token)
+ CloseHandle (token);
+ }
+
+ attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
+ tem = make_unibyte_string (uname, ulength);
+ attrs = Fcons (Fcons (Quser,
+ code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
+ attrs);
+ attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
+ tem = make_unibyte_string (gname, glength);
+ attrs = Fcons (Fcons (Qgroup,
+ code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
+ attrs);
+
+ if (global_memory_status_ex (&memstex))
+#if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
+ totphys = memstex.ullTotalPhys / 1024.0;
+#else
+ /* Visual Studio 6 cannot convert an unsigned __int64 type to
+ double, so we need to do this for it... */
+ {
+ DWORD tot_hi = memstex.ullTotalPhys >> 32;
+ DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
+ DWORD tot_lo = memstex.ullTotalPhys % 1024;
+
+ totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
+ }
+#endif /* __GNUC__ || _MSC_VER >= 1300 */
+ else if (global_memory_status (&memst))
+ totphys = memst.dwTotalPhys / 1024.0;
+ if (h_proc
+ && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
+ sizeof (mem_ex)))
+ {
+ DWORD rss = mem_ex.WorkingSetSize / 1024;
+
+ attrs = Fcons (Fcons (Qmajflt,
+ make_fixnum_or_float (mem_ex.PageFaultCount)),
+ attrs);
+ attrs = Fcons (Fcons (Qvsize,
+ make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
+ attrs);
+ attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
+ if (totphys)
+ attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
+ }
+ else if (h_proc
+ && get_process_memory_info (h_proc, &mem, sizeof (mem)))
+ {
+ DWORD rss = mem_ex.WorkingSetSize / 1024;
+
+ attrs = Fcons (Fcons (Qmajflt,
+ make_fixnum_or_float (mem.PageFaultCount)),
+ attrs);
+ attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
+ if (totphys)
+ attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
+ }
+ else if (h_proc
+ && get_process_working_set_size (h_proc, &minrss, &maxrss))
+ {
+ DWORD rss = maxrss / 1024;
+
+ attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
+ if (totphys)
+ attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
+ }
+
+ if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
+ {
+ attrs = Fcons (Fcons (Qutime, utime), attrs);
+ attrs = Fcons (Fcons (Qstime, stime), attrs);
+ attrs = Fcons (Fcons (Qtime, ttime), attrs);
+ attrs = Fcons (Fcons (Qstart, ctime), attrs);
+ attrs = Fcons (Fcons (Qetime, etime), attrs);
+ attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
+ }
+
+ /* FIXME: Retrieve command line by walking the PEB of the process. */
+
+ if (h_proc)
+ CloseHandle (h_proc);
+ UNGCPRO;
+ return attrs;
+}
+
+\f
/* Wrappers for winsock functions to map between our file descriptors
and winsock's handles; also set h_errno for convenience.
if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
goto fail;
- 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 );
- LOAD_PROC( ioctlsocket );
- LOAD_PROC( recv );
- LOAD_PROC( send );
- LOAD_PROC( closesocket );
- LOAD_PROC( shutdown );
- LOAD_PROC( htons );
- LOAD_PROC( ntohs );
- LOAD_PROC( inet_addr );
- 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 );
+ 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);
+ LOAD_PROC (ioctlsocket);
+ LOAD_PROC (recv);
+ LOAD_PROC (send);
+ LOAD_PROC (closesocket);
+ LOAD_PROC (shutdown);
+ LOAD_PROC (htons);
+ LOAD_PROC (ntohs);
+ LOAD_PROC (inet_addr);
+ 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 */
int h_errno = 0;
-/* function to set h_errno for compatability; map winsock error codes to
+/* function to set h_errno for compatibility; map winsock error codes to
normal system codes where they overlap (non-overlapping definitions
are already in <sys/socket.h> */
static void
-set_errno ()
+set_errno (void)
{
if (winsock_lib == NULL)
h_errno = EINVAL;
}
static void
-check_errno ()
+check_errno (void)
{
if (h_errno == 0 && winsock_lib != NULL)
pfn_WSASetLastError (0);
};
char *
-sys_strerror(int error_no)
+sys_strerror (int error_no)
{
int i;
static char unknown_msg[40];
if (_wsa_errlist[i].errnum == error_no)
return _wsa_errlist[i].msg;
- sprintf(unknown_msg, "Unidentified error: %d", error_no);
+ sprintf (unknown_msg, "Unidentified error: %d", error_no);
return unknown_msg;
}
but I believe the method of keeping the socket handle separate (and
insuring it is not inheritable) is the correct one. */
-//#define SOCK_REPLACE_HANDLE
-
-#ifdef SOCK_REPLACE_HANDLE
-#define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
-#else
#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)
+sys_socket (int af, int type, int protocol)
{
SOCKET s;
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); */
-#else
/* 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
}
}
fd_info[fd].hnd = (HANDLE) s;
-#endif
/* set our own internal flags */
fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
}
struct hostent *
-sys_gethostbyname(const char * name)
+sys_gethostbyname (const char * name)
{
struct hostent * host;
}
struct servent *
-sys_getservbyname(const char * name, const char * proto)
+sys_getservbyname (const char * name, const char * proto)
{
struct servent * serv;
int
sys_recvfrom (int s, char * buf, int len, int flags,
- struct sockaddr * from, int * fromlen)
+ struct sockaddr * from, int * fromlen)
{
if (winsock_lib == NULL)
{
return SOCKET_ERROR;
}
-#endif /* HAVE_SOCKETS */
-
/* Shadow main io functions: we need to handle pipes and sockets more
intelligently, and implement non-blocking mode as well. */
}
if (i == MAXDESC)
{
-#ifdef HAVE_SOCKETS
if (fd_info[fd].flags & FILE_SOCKET)
{
-#ifndef SOCK_REPLACE_HANDLE
if (winsock_lib == NULL) abort ();
pfn_shutdown (SOCK_HANDLE (fd), 2);
rc = pfn_closesocket (SOCK_HANDLE (fd));
-#endif
+
winsock_inuse--; /* count open sockets */
}
-#endif
delete_child (cp);
}
}
if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
return STATUS_READ_ERROR;
- if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
+ if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
|| (fd_info[fd].flags & FILE_READ) == 0)
{
- DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
+ DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
abort ();
}
reporting that input is available; we need this because Windows 95
connects DOS programs to pipes by making the pipe appear to be
the normal console stdout - as a result most DOS programs will
- write to stdout without buffering, ie. one character at a
+ write to stdout without buffering, ie. one character at a
time. Even some W32 programs do this - "dir" in a command
shell on NT is very slow if we don't do this. */
if (rc > 0)
Sleep (0);
}
}
-#ifdef HAVE_SOCKETS
+ else if (fd_info[fd].flags & FILE_SERIAL)
+ {
+ HANDLE hnd = fd_info[fd].hnd;
+ OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
+ COMMTIMEOUTS ct;
+
+ /* Configure timeouts for blocking read. */
+ if (!GetCommTimeouts (hnd, &ct))
+ return STATUS_READ_ERROR;
+ ct.ReadIntervalTimeout = 0;
+ ct.ReadTotalTimeoutMultiplier = 0;
+ ct.ReadTotalTimeoutConstant = 0;
+ if (!SetCommTimeouts (hnd, &ct))
+ return STATUS_READ_ERROR;
+
+ if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
+ {
+ if (GetLastError () != ERROR_IO_PENDING)
+ return STATUS_READ_ERROR;
+ if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
+ return STATUS_READ_ERROR;
+ }
+ }
else if (fd_info[fd].flags & FILE_SOCKET)
{
unsigned long nblock = 0;
pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
}
}
-#endif
if (rc == sizeof (char))
cp->status = STATUS_READ_SUCCEEDED;
return -1;
}
- if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
+ if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
{
child_process *cp = fd_info[fd].cp;
if (to_read > 0)
nchars += _read (fd, buffer, to_read);
}
-#ifdef HAVE_SOCKETS
+ else if (fd_info[fd].flags & FILE_SERIAL)
+ {
+ HANDLE hnd = fd_info[fd].hnd;
+ OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
+ DWORD err = 0;
+ int rc = 0;
+ COMMTIMEOUTS ct;
+
+ if (count > 0)
+ {
+ /* Configure timeouts for non-blocking read. */
+ if (!GetCommTimeouts (hnd, &ct))
+ {
+ errno = EIO;
+ return -1;
+ }
+ ct.ReadIntervalTimeout = MAXDWORD;
+ ct.ReadTotalTimeoutMultiplier = 0;
+ ct.ReadTotalTimeoutConstant = 0;
+ if (!SetCommTimeouts (hnd, &ct))
+ {
+ errno = EIO;
+ return -1;
+ }
+
+ if (!ResetEvent (ovl->hEvent))
+ {
+ errno = EIO;
+ return -1;
+ }
+ if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
+ {
+ if (GetLastError () != ERROR_IO_PENDING)
+ {
+ errno = EIO;
+ return -1;
+ }
+ if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
+ {
+ errno = EIO;
+ return -1;
+ }
+ }
+ nchars += rc;
+ }
+ }
else /* FILE_SOCKET */
{
if (winsock_lib == NULL) abort ();
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)));
+ DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
+ pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
set_errno ();
return -1;
}
nchars += res;
}
}
-#endif
}
else
{
return nchars;
}
+/* From w32xfns.c */
+extern HANDLE interrupt_handle;
+
/* For now, don't bother with a non-blocking mode */
int
sys_write (int fd, const void * buffer, unsigned int count)
return -1;
}
- if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
+ if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
{
if ((fd_info[fd].flags & FILE_WRITE) == 0)
{
}
}
-#ifdef HAVE_SOCKETS
- if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
+ if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
+ {
+ HANDLE hnd = (HANDLE) _get_osfhandle (fd);
+ OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
+ HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
+ DWORD active = 0;
+
+ if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
+ {
+ if (GetLastError () != ERROR_IO_PENDING)
+ {
+ errno = EIO;
+ return -1;
+ }
+ if (detect_input_pending ())
+ active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
+ QS_ALLINPUT);
+ else
+ active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
+ if (active == WAIT_OBJECT_0)
+ { /* User pressed C-g, cancel write, then leave. Don't bother
+ cleaning up as we may only get stuck in buggy drivers. */
+ PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
+ CancelIo (hnd);
+ errno = EIO;
+ return -1;
+ }
+ if (active == WAIT_OBJECT_0 + 1
+ && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
+ {
+ errno = EIO;
+ return -1;
+ }
+ }
+ }
+ else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
{
unsigned long nblock = 0;
if (winsock_lib == NULL) abort ();
if (nchars == SOCKET_ERROR)
{
- DebPrint(("sys_write.send failed with error %d on socket %ld\n",
- pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
+ DebPrint (("sys_write.send failed with error %d on socket %ld\n",
+ pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
set_errno ();
}
}
else
-#endif
- nchars = _write (fd, buffer, count);
+ {
+ /* Some networked filesystems don't like too large writes, so
+ break them into smaller chunks. See the Comments section of
+ the MSDN documentation of WriteFile for details behind the
+ choice of the value of CHUNK below. See also the thread
+ http://thread.gmane.org/gmane.comp.version-control.git/145294
+ in the git mailing list. */
+ const unsigned char *p = buffer;
+ const unsigned chunk = 30 * 1024 * 1024;
+
+ nchars = 0;
+ while (count > 0)
+ {
+ unsigned this_chunk = count < chunk ? count : chunk;
+ int n = _write (fd, p, this_chunk);
+
+ nchars += n;
+ if (n < 0)
+ {
+ nchars = n;
+ break;
+ }
+ else if (n < this_chunk)
+ break;
+ count -= n;
+ p += n;
+ }
+ }
return nchars;
}
static void
-check_windows_init_file ()
+check_windows_init_file (void)
{
extern int noninteractive, inhibit_window_system;
}
void
-term_ntproc ()
+term_ntproc (void)
{
-#ifdef HAVE_SOCKETS
/* shutdown the socket interface if necessary */
term_winsock ();
-#endif
term_w32select ();
}
void
-init_ntproc ()
+init_ntproc (void)
{
-#ifdef HAVE_SOCKETS
/* Initialise the socket interface now if available and requested by
the user by defining PRELOAD_WINSOCK; otherwise loading will be
delayed until open-network-stream is called (w32-has-winsock can
if (getenv ("PRELOAD_WINSOCK") != NULL)
init_winsock (TRUE);
-#endif
/* Initial preparation for subprocess support: replace our standard
handles with non-inheritable versions. */
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)
+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. */
initialized is non zero (see the function main in emacs.c).
*/
void
-globals_of_w32 ()
+globals_of_w32 (void)
{
HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
g_b_init_get_sid_identifier_authority = 0;
g_b_init_get_sid_sub_authority = 0;
g_b_init_get_sid_sub_authority_count = 0;
+ g_b_init_get_file_security = 0;
+ g_b_init_get_security_descriptor_owner = 0;
+ g_b_init_get_security_descriptor_group = 0;
+ g_b_init_is_valid_sid = 0;
+ g_b_init_create_toolhelp32_snapshot = 0;
+ g_b_init_process32_first = 0;
+ g_b_init_process32_next = 0;
+ g_b_init_open_thread_token = 0;
+ g_b_init_impersonate_self = 0;
+ g_b_init_revert_to_self = 0;
+ g_b_init_get_process_memory_info = 0;
+ g_b_init_get_process_working_set_size = 0;
+ g_b_init_global_memory_status = 0;
+ g_b_init_global_memory_status_ex = 0;
+ g_b_init_equal_sid = 0;
+ g_b_init_copy_sid = 0;
+ g_b_init_get_length_sid = 0;
+ g_b_init_get_native_system_info = 0;
+ g_b_init_get_system_times = 0;
+ num_of_processors = 0;
/* The following sets a handler for shutdown notifications for
console apps. This actually applies to Emacs in both console and
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);
+ SetConsoleCtrlHandler (shutdown_handler, TRUE);
+
+ /* "None" is the default group name on standalone workstations. */
+ strcpy (dflt_group_name, "None");
+}
+
+/* For make-serial-process */
+int
+serial_open (char *port)
+{
+ HANDLE hnd;
+ child_process *cp;
+ int fd = -1;
+
+ hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
+ OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+ if (hnd == INVALID_HANDLE_VALUE)
+ error ("Could not open %s", port);
+ fd = (int) _open_osfhandle ((int) hnd, 0);
+ if (fd == -1)
+ error ("Could not open %s", port);
+
+ cp = new_child ();
+ if (!cp)
+ error ("Could not create child process");
+ cp->fd = fd;
+ cp->status = STATUS_READ_ACKNOWLEDGED;
+ fd_info[ fd ].hnd = hnd;
+ fd_info[ fd ].flags |=
+ FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
+ if (fd_info[ fd ].cp != NULL)
+ {
+ error ("fd_info[fd = %d] is already in use", fd);
+ }
+ fd_info[ fd ].cp = cp;
+ cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+ if (cp->ovl_read.hEvent == NULL)
+ error ("Could not create read event");
+ cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+ if (cp->ovl_write.hEvent == NULL)
+ error ("Could not create write event");
+
+ return fd;
+}
+
+/* For serial-process-configure */
+void
+serial_configure (struct Lisp_Process *p,
+ Lisp_Object contact)
+{
+ Lisp_Object childp2 = Qnil;
+ Lisp_Object tem = Qnil;
+ HANDLE hnd;
+ DCB dcb;
+ COMMTIMEOUTS ct;
+ char summary[4] = "???"; /* This usually becomes "8N1". */
+
+ if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
+ error ("Not a serial process");
+ hnd = fd_info[ p->outfd ].hnd;
+
+ childp2 = Fcopy_sequence (p->childp);
+
+ /* Initialize timeouts for blocking read and blocking write. */
+ if (!GetCommTimeouts (hnd, &ct))
+ error ("GetCommTimeouts() failed");
+ ct.ReadIntervalTimeout = 0;
+ ct.ReadTotalTimeoutMultiplier = 0;
+ ct.ReadTotalTimeoutConstant = 0;
+ ct.WriteTotalTimeoutMultiplier = 0;
+ ct.WriteTotalTimeoutConstant = 0;
+ if (!SetCommTimeouts (hnd, &ct))
+ error ("SetCommTimeouts() failed");
+ /* Read port attributes and prepare default configuration. */
+ memset (&dcb, 0, sizeof (dcb));
+ dcb.DCBlength = sizeof (DCB);
+ if (!GetCommState (hnd, &dcb))
+ error ("GetCommState() failed");
+ dcb.fBinary = TRUE;
+ dcb.fNull = FALSE;
+ dcb.fAbortOnError = FALSE;
+ /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
+ dcb.ErrorChar = 0;
+ dcb.EofChar = 0;
+ dcb.EvtChar = 0;
+
+ /* Configure speed. */
+ if (!NILP (Fplist_member (contact, QCspeed)))
+ tem = Fplist_get (contact, QCspeed);
+ else
+ tem = Fplist_get (p->childp, QCspeed);
+ CHECK_NUMBER (tem);
+ dcb.BaudRate = XINT (tem);
+ childp2 = Fplist_put (childp2, QCspeed, tem);
+
+ /* Configure bytesize. */
+ if (!NILP (Fplist_member (contact, QCbytesize)))
+ tem = Fplist_get (contact, QCbytesize);
+ else
+ tem = Fplist_get (p->childp, QCbytesize);
+ if (NILP (tem))
+ tem = make_number (8);
+ CHECK_NUMBER (tem);
+ if (XINT (tem) != 7 && XINT (tem) != 8)
+ error (":bytesize must be nil (8), 7, or 8");
+ dcb.ByteSize = XINT (tem);
+ summary[0] = XINT (tem) + '0';
+ childp2 = Fplist_put (childp2, QCbytesize, tem);
+
+ /* Configure parity. */
+ if (!NILP (Fplist_member (contact, QCparity)))
+ tem = Fplist_get (contact, QCparity);
+ else
+ tem = Fplist_get (p->childp, QCparity);
+ if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
+ error (":parity must be nil (no parity), `even', or `odd'");
+ dcb.fParity = FALSE;
+ dcb.Parity = NOPARITY;
+ dcb.fErrorChar = FALSE;
+ if (NILP (tem))
+ {
+ summary[1] = 'N';
+ }
+ else if (EQ (tem, Qeven))
+ {
+ summary[1] = 'E';
+ dcb.fParity = TRUE;
+ dcb.Parity = EVENPARITY;
+ dcb.fErrorChar = TRUE;
+ }
+ else if (EQ (tem, Qodd))
+ {
+ summary[1] = 'O';
+ dcb.fParity = TRUE;
+ dcb.Parity = ODDPARITY;
+ dcb.fErrorChar = TRUE;
+ }
+ childp2 = Fplist_put (childp2, QCparity, tem);
+
+ /* Configure stopbits. */
+ if (!NILP (Fplist_member (contact, QCstopbits)))
+ tem = Fplist_get (contact, QCstopbits);
+ else
+ tem = Fplist_get (p->childp, QCstopbits);
+ if (NILP (tem))
+ tem = make_number (1);
+ CHECK_NUMBER (tem);
+ if (XINT (tem) != 1 && XINT (tem) != 2)
+ error (":stopbits must be nil (1 stopbit), 1, or 2");
+ summary[2] = XINT (tem) + '0';
+ if (XINT (tem) == 1)
+ dcb.StopBits = ONESTOPBIT;
+ else if (XINT (tem) == 2)
+ dcb.StopBits = TWOSTOPBITS;
+ childp2 = Fplist_put (childp2, QCstopbits, tem);
+
+ /* Configure flowcontrol. */
+ if (!NILP (Fplist_member (contact, QCflowcontrol)))
+ tem = Fplist_get (contact, QCflowcontrol);
+ else
+ tem = Fplist_get (p->childp, QCflowcontrol);
+ if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
+ error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
+ dcb.fOutxCtsFlow = FALSE;
+ dcb.fOutxDsrFlow = FALSE;
+ dcb.fDtrControl = DTR_CONTROL_DISABLE;
+ dcb.fDsrSensitivity = FALSE;
+ dcb.fTXContinueOnXoff = FALSE;
+ dcb.fOutX = FALSE;
+ dcb.fInX = FALSE;
+ dcb.fRtsControl = RTS_CONTROL_DISABLE;
+ dcb.XonChar = 17; /* Control-Q */
+ dcb.XoffChar = 19; /* Control-S */
+ if (NILP (tem))
+ {
+ /* Already configured. */
+ }
+ else if (EQ (tem, Qhw))
+ {
+ dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
+ dcb.fOutxCtsFlow = TRUE;
+ }
+ else if (EQ (tem, Qsw))
+ {
+ dcb.fOutX = TRUE;
+ dcb.fInX = TRUE;
+ }
+ childp2 = Fplist_put (childp2, QCflowcontrol, tem);
+
+ /* Activate configuration. */
+ if (!SetCommState (hnd, &dcb))
+ error ("SetCommState() failed");
+
+ childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
+ p->childp = childp2;
}
/* end of w32.c */