#include <sys/time.h>
#include <sys/utime.h>
#include <mbstring.h> /* for _mbspbrk */
+#include <math.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>
+#include <tlhelp32.h>
+#include <psapi.h>
+/* This either is not in psapi.h or guarded by higher value of
+ _WIN32_WINNT than what we use. */
+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;
+
#ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
#include <sys/socket.h>
#undef socket
#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"
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;
/*
BEGIN: Wrapper functions around OpenProcessToken
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);
+
+
/* ** A utility function ** */
static BOOL
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
primary group sid from the process token). */
char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
- DWORD ulength = sizeof (uname), dlength = sizeof (domain), trash;
+ 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, uname, &ulength,
- domain, &dlength, &user_type)))
+ result = open_process_token (GetCurrentProcess (), 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));
+ 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. */
dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
/* Get group id and name. */
- if (get_token_information (token, TokenPrimaryGroup,
- (PVOID)buf, sizeof (buf), &trash))
+ 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));
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))
}
}
/* If security calls are not supported (presumably because we
- are running under Windows 95), fallback to this. */
+ are running under Windows 9X), fallback to this: */
else if (GetUserName (uname, &ulength))
{
strcpy (dflt_passwd.pw_name, uname);
strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
+ xfree (buf);
if (token)
CloseHandle (token);
}
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)
{
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. */
static long double utc_base;
static int init = 0;
+static long double
+convert_time_raw (FILETIME ft)
+{
+ return
+ (long double) ft.dwHighDateTime
+ * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
+}
+
static time_t
convert_time (FILETIME ft)
{
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);
+ return (time_t) ((convert_time_raw (ft) - utc_base) * 1e-7L);
}
+
void
convert_from_time_t (time_t time, FILETIME * pft)
{
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 {
+ int 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, int *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, int 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
if (!result || !is_valid_sid (sid))
use_dflt = 1;
- else
+ else if (!w32_cached_id (sid, id, nm))
{
/* If FNAME is a UNC, we need to lookup account on the
specified machine. */
{
*id = get_rid (sid);
strcpy (nm, name);
+ w32_add_to_cache (sid, *id, name);
}
}
return use_dflt;
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;
}
}
+ /* GetDriveType needs the root directory of NAME's drive. */
+ if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
+ devtype = GetDriveType (NULL); /* use root of current diectory */
+ else
+ {
+ strncpy (drive_root, name, 3);
+ drive_root[3] = '\0';
+ devtype = GetDriveType (drive_root);
+ }
+
if (!(NILP (Vw32_get_true_file_attributes)
- || (EQ (Vw32_get_true_file_attributes, Qlocal) &&
- GetDriveType (name) != DRIVE_FIXED))
+ || (EQ (Vw32_get_true_file_attributes, Qlocal)
+ && devtype != DRIVE_FIXED && devtype != DRIVE_RAMDISK))
/* No access rights required to get info. */
&& (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL))
return 0;
}
+\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
+w32_list_system_processes ()
+{
+ 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 (time_sec, time_usec)
+ long time_sec, time_usec;
+{
+ return list3 (make_number ((time_sec >> 16) & 0xffff),
+ make_number (time_sec & 0xffff),
+ make_number (time_usec));
+}
+
+static int
+process_times (h_proc, ctime, etime, stime, utime, pcpu)
+ HANDLE h_proc;
+ Lisp_Object *ctime, *etime, *stime, *utime;
+ double *pcpu;
+{
+ FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
+ long ctime_sec, ctime_usec, stime_sec, stime_usec, utime_sec, utime_usec;
+ long etime_sec, etime_usec;
+ long double tem1, tem2, 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);
+
+ tem1 = convert_time_raw (ft_kernel) * 0.1L;
+ stime_usec = fmodl (tem1, 1000000.0L);
+ stime_sec = tem1 * 0.000001L;
+ *stime = ltime (stime_sec, stime_usec);
+ tem2 = convert_time_raw (ft_user) * 0.1L;
+ utime_usec = fmodl (tem2, 1000000.0L);
+ utime_sec = tem2 * 0.000001L;
+ *utime = ltime (utime_sec, utime_usec);
+ tem = convert_time_raw (ft_creation);
+ /* Process no 4 (System) returns zero creation time. */
+ if (tem)
+ tem = (tem - utc_base) * 0.1;
+ ctime_usec = fmodl (tem, 1000000.0L);
+ ctime_sec = tem * 0.000001L;
+ *ctime = ltime (ctime_sec, ctime_usec);
+ if (tem)
+ tem = (convert_time_raw (ft_current) - utc_base) * 0.1L - tem;
+ etime_usec = fmodl (tem, 1000000.0L);
+ etime_sec = tem * 0.000001L;
+ *etime = ltime (etime_sec, etime_usec);
+
+ if (tem)
+ {
+ *pcpu = 100.0 * (tem1 + tem2) / tem;
+ if (*pcpu > 100)
+ *pcpu = 100.0;
+ }
+ else
+ *pcpu = 0;
+
+ return 1;
+}
+
+Lisp_Object
+w32_system_process_attributes (pid)
+ 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;
+ int euid;
+ int 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;
+ 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);
+ }
+ }
+ }
+ if (buf)
+ 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, &pcpu))
+ {
+ attrs = Fcons (Fcons (Qutime, utime), attrs);
+ attrs = Fcons (Fcons (Qstime, stime), 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
#ifdef HAVE_SOCKETS
/* Wrappers for winsock functions to map between our file descriptors
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;
/* 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