1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994-1995, 2000-2012 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
22 #include <stddef.h> /* for offsetof */
25 #include <float.h> /* for DBL_EPSILON */
33 #include <sys/utime.h>
34 #include <mbstring.h> /* for _mbspbrk */
39 /* must include CRT headers *before* config.h */
74 #define _ANONYMOUS_UNION
75 #define _ANONYMOUS_STRUCT
78 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
79 use a different name to avoid compilation problems. */
80 typedef struct _MEMORY_STATUS_EX
{
83 DWORDLONG ullTotalPhys
;
84 DWORDLONG ullAvailPhys
;
85 DWORDLONG ullTotalPageFile
;
86 DWORDLONG ullAvailPageFile
;
87 DWORDLONG ullTotalVirtual
;
88 DWORDLONG ullAvailVirtual
;
89 DWORDLONG ullAvailExtendedVirtual
;
90 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
100 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
101 /* This either is not in psapi.h or guarded by higher value of
102 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
103 defines it in psapi.h */
104 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
106 DWORD PageFaultCount
;
107 DWORD PeakWorkingSetSize
;
108 DWORD WorkingSetSize
;
109 DWORD QuotaPeakPagedPoolUsage
;
110 DWORD QuotaPagedPoolUsage
;
111 DWORD QuotaPeakNonPagedPoolUsage
;
112 DWORD QuotaNonPagedPoolUsage
;
114 DWORD PeakPagefileUsage
;
116 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
119 /* TCP connection support. */
120 #include <sys/socket.h>
143 #include "dispextern.h" /* for xstrcasecmp */
144 #include "coding.h" /* for Vlocale_coding_system */
146 #include "careadlinkat.h"
147 #include "allocator.h"
149 /* For serial_configure and serial_open. */
152 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
153 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
155 Lisp_Object QCloaded_from
;
157 void globals_of_w32 (void);
158 static DWORD
get_rid (PSID
);
161 /* Initialization states.
163 WARNING: If you add any more such variables for additional APIs,
164 you MUST add initialization for them to globals_of_w32
165 below. This is because these variables might get set
166 to non-NULL values during dumping, but the dumped Emacs
167 cannot reuse those values, because it could be run on a
168 different version of the OS, where API addresses are
170 static BOOL g_b_init_is_windows_9x
;
171 static BOOL g_b_init_open_process_token
;
172 static BOOL g_b_init_get_token_information
;
173 static BOOL g_b_init_lookup_account_sid
;
174 static BOOL g_b_init_get_sid_sub_authority
;
175 static BOOL g_b_init_get_sid_sub_authority_count
;
176 static BOOL g_b_init_get_file_security
;
177 static BOOL g_b_init_get_security_descriptor_owner
;
178 static BOOL g_b_init_get_security_descriptor_group
;
179 static BOOL g_b_init_is_valid_sid
;
180 static BOOL g_b_init_create_toolhelp32_snapshot
;
181 static BOOL g_b_init_process32_first
;
182 static BOOL g_b_init_process32_next
;
183 static BOOL g_b_init_open_thread_token
;
184 static BOOL g_b_init_impersonate_self
;
185 static BOOL g_b_init_revert_to_self
;
186 static BOOL g_b_init_get_process_memory_info
;
187 static BOOL g_b_init_get_process_working_set_size
;
188 static BOOL g_b_init_global_memory_status
;
189 static BOOL g_b_init_global_memory_status_ex
;
190 static BOOL g_b_init_get_length_sid
;
191 static BOOL g_b_init_equal_sid
;
192 static BOOL g_b_init_copy_sid
;
193 static BOOL g_b_init_get_native_system_info
;
194 static BOOL g_b_init_get_system_times
;
197 BEGIN: Wrapper functions around OpenProcessToken
198 and other functions in advapi32.dll that are only
199 supported in Windows NT / 2k / XP
201 /* ** Function pointer typedefs ** */
202 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
203 HANDLE ProcessHandle
,
205 PHANDLE TokenHandle
);
206 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
208 TOKEN_INFORMATION_CLASS TokenInformationClass
,
209 LPVOID TokenInformation
,
210 DWORD TokenInformationLength
,
211 PDWORD ReturnLength
);
212 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
213 HANDLE process_handle
,
214 LPFILETIME creation_time
,
215 LPFILETIME exit_time
,
216 LPFILETIME kernel_time
,
217 LPFILETIME user_time
);
219 GetProcessTimes_Proc get_process_times_fn
= NULL
;
222 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
223 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
225 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
226 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
228 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
229 LPCTSTR lpSystemName
,
234 LPDWORD cbDomainName
,
235 PSID_NAME_USE peUse
);
236 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
239 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
241 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
243 SECURITY_INFORMATION RequestedInformation
,
244 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
246 LPDWORD lpnLengthNeeded
);
247 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
248 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
250 LPBOOL lpbOwnerDefaulted
);
251 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
252 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
254 LPBOOL lpbGroupDefaulted
);
255 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
257 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
259 DWORD th32ProcessID
);
260 typedef BOOL (WINAPI
* Process32First_Proc
) (
262 LPPROCESSENTRY32 lppe
);
263 typedef BOOL (WINAPI
* Process32Next_Proc
) (
265 LPPROCESSENTRY32 lppe
);
266 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
270 PHANDLE TokenHandle
);
271 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
272 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
273 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
274 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
276 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
278 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
280 DWORD
* lpMinimumWorkingSetSize
,
281 DWORD
* lpMaximumWorkingSetSize
);
282 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
283 LPMEMORYSTATUS lpBuffer
);
284 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
285 LPMEMORY_STATUS_EX lpBuffer
);
286 typedef BOOL (WINAPI
* CopySid_Proc
) (
287 DWORD nDestinationSidLength
,
288 PSID pDestinationSid
,
290 typedef BOOL (WINAPI
* EqualSid_Proc
) (
293 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
295 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
296 LPSYSTEM_INFO lpSystemInfo
);
297 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
298 LPFILETIME lpIdleTime
,
299 LPFILETIME lpKernelTime
,
300 LPFILETIME lpUserTime
);
302 /* ** A utility function ** */
306 static BOOL s_b_ret
= 0;
307 OSVERSIONINFO os_ver
;
308 if (g_b_init_is_windows_9x
== 0)
310 g_b_init_is_windows_9x
= 1;
311 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
312 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
313 if (GetVersionEx (&os_ver
))
315 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
321 /* Get total user and system times for get-internal-run-time.
322 Returns a list of three integers if the times are provided by the OS
323 (NT derivatives), otherwise it returns the result of current-time. */
325 w32_get_internal_run_time (void)
327 if (get_process_times_fn
)
329 FILETIME create
, exit
, kernel
, user
;
330 HANDLE proc
= GetCurrentProcess ();
331 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
333 LARGE_INTEGER user_int
, kernel_int
, total
;
335 user_int
.LowPart
= user
.dwLowDateTime
;
336 user_int
.HighPart
= user
.dwHighDateTime
;
337 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
338 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
339 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
340 /* FILETIME is 100 nanosecond increments, Emacs only wants
341 microsecond resolution. */
342 total
.QuadPart
/= 10;
343 microseconds
= total
.QuadPart
% 1000000;
344 total
.QuadPart
/= 1000000;
346 /* Sanity check to make sure we can represent the result. */
347 if (total
.HighPart
== 0)
349 int secs
= total
.LowPart
;
351 return list3 (make_number ((secs
>> 16) & 0xffff),
352 make_number (secs
& 0xffff),
353 make_number (microseconds
));
358 return Fcurrent_time ();
361 /* ** The wrapper functions ** */
364 open_process_token (HANDLE ProcessHandle
,
368 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
369 HMODULE hm_advapi32
= NULL
;
370 if (is_windows_9x () == TRUE
)
374 if (g_b_init_open_process_token
== 0)
376 g_b_init_open_process_token
= 1;
377 hm_advapi32
= LoadLibrary ("Advapi32.dll");
378 s_pfn_Open_Process_Token
=
379 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
381 if (s_pfn_Open_Process_Token
== NULL
)
386 s_pfn_Open_Process_Token (
394 get_token_information (HANDLE TokenHandle
,
395 TOKEN_INFORMATION_CLASS TokenInformationClass
,
396 LPVOID TokenInformation
,
397 DWORD TokenInformationLength
,
400 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
401 HMODULE hm_advapi32
= NULL
;
402 if (is_windows_9x () == TRUE
)
406 if (g_b_init_get_token_information
== 0)
408 g_b_init_get_token_information
= 1;
409 hm_advapi32
= LoadLibrary ("Advapi32.dll");
410 s_pfn_Get_Token_Information
=
411 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
413 if (s_pfn_Get_Token_Information
== NULL
)
418 s_pfn_Get_Token_Information (
420 TokenInformationClass
,
422 TokenInformationLength
,
428 lookup_account_sid (LPCTSTR lpSystemName
,
433 LPDWORD cbDomainName
,
436 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
437 HMODULE hm_advapi32
= NULL
;
438 if (is_windows_9x () == TRUE
)
442 if (g_b_init_lookup_account_sid
== 0)
444 g_b_init_lookup_account_sid
= 1;
445 hm_advapi32
= LoadLibrary ("Advapi32.dll");
446 s_pfn_Lookup_Account_Sid
=
447 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
449 if (s_pfn_Lookup_Account_Sid
== NULL
)
454 s_pfn_Lookup_Account_Sid (
466 get_sid_sub_authority (PSID pSid
, DWORD n
)
468 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
469 static DWORD zero
= 0U;
470 HMODULE hm_advapi32
= NULL
;
471 if (is_windows_9x () == TRUE
)
475 if (g_b_init_get_sid_sub_authority
== 0)
477 g_b_init_get_sid_sub_authority
= 1;
478 hm_advapi32
= LoadLibrary ("Advapi32.dll");
479 s_pfn_Get_Sid_Sub_Authority
=
480 (GetSidSubAuthority_Proc
) GetProcAddress (
481 hm_advapi32
, "GetSidSubAuthority");
483 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
487 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
491 get_sid_sub_authority_count (PSID pSid
)
493 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
494 static UCHAR zero
= 0U;
495 HMODULE hm_advapi32
= NULL
;
496 if (is_windows_9x () == TRUE
)
500 if (g_b_init_get_sid_sub_authority_count
== 0)
502 g_b_init_get_sid_sub_authority_count
= 1;
503 hm_advapi32
= LoadLibrary ("Advapi32.dll");
504 s_pfn_Get_Sid_Sub_Authority_Count
=
505 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
506 hm_advapi32
, "GetSidSubAuthorityCount");
508 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
512 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
516 get_file_security (LPCTSTR lpFileName
,
517 SECURITY_INFORMATION RequestedInformation
,
518 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
520 LPDWORD lpnLengthNeeded
)
522 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
523 HMODULE hm_advapi32
= NULL
;
524 if (is_windows_9x () == TRUE
)
528 if (g_b_init_get_file_security
== 0)
530 g_b_init_get_file_security
= 1;
531 hm_advapi32
= LoadLibrary ("Advapi32.dll");
532 s_pfn_Get_File_Security
=
533 (GetFileSecurity_Proc
) GetProcAddress (
534 hm_advapi32
, GetFileSecurity_Name
);
536 if (s_pfn_Get_File_Security
== NULL
)
540 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
541 pSecurityDescriptor
, nLength
,
546 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
548 LPBOOL lpbOwnerDefaulted
)
550 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
551 HMODULE hm_advapi32
= NULL
;
552 if (is_windows_9x () == TRUE
)
556 if (g_b_init_get_security_descriptor_owner
== 0)
558 g_b_init_get_security_descriptor_owner
= 1;
559 hm_advapi32
= LoadLibrary ("Advapi32.dll");
560 s_pfn_Get_Security_Descriptor_Owner
=
561 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
562 hm_advapi32
, "GetSecurityDescriptorOwner");
564 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
568 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
573 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
575 LPBOOL lpbGroupDefaulted
)
577 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
578 HMODULE hm_advapi32
= NULL
;
579 if (is_windows_9x () == TRUE
)
583 if (g_b_init_get_security_descriptor_group
== 0)
585 g_b_init_get_security_descriptor_group
= 1;
586 hm_advapi32
= LoadLibrary ("Advapi32.dll");
587 s_pfn_Get_Security_Descriptor_Group
=
588 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
589 hm_advapi32
, "GetSecurityDescriptorGroup");
591 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
595 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
600 is_valid_sid (PSID sid
)
602 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
603 HMODULE hm_advapi32
= NULL
;
604 if (is_windows_9x () == TRUE
)
608 if (g_b_init_is_valid_sid
== 0)
610 g_b_init_is_valid_sid
= 1;
611 hm_advapi32
= LoadLibrary ("Advapi32.dll");
613 (IsValidSid_Proc
) GetProcAddress (
614 hm_advapi32
, "IsValidSid");
616 if (s_pfn_Is_Valid_Sid
== NULL
)
620 return (s_pfn_Is_Valid_Sid (sid
));
624 equal_sid (PSID sid1
, PSID sid2
)
626 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
627 HMODULE hm_advapi32
= NULL
;
628 if (is_windows_9x () == TRUE
)
632 if (g_b_init_equal_sid
== 0)
634 g_b_init_equal_sid
= 1;
635 hm_advapi32
= LoadLibrary ("Advapi32.dll");
637 (EqualSid_Proc
) GetProcAddress (
638 hm_advapi32
, "EqualSid");
640 if (s_pfn_Equal_Sid
== NULL
)
644 return (s_pfn_Equal_Sid (sid1
, sid2
));
648 get_length_sid (PSID sid
)
650 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
651 HMODULE hm_advapi32
= NULL
;
652 if (is_windows_9x () == TRUE
)
656 if (g_b_init_get_length_sid
== 0)
658 g_b_init_get_length_sid
= 1;
659 hm_advapi32
= LoadLibrary ("Advapi32.dll");
660 s_pfn_Get_Length_Sid
=
661 (GetLengthSid_Proc
) GetProcAddress (
662 hm_advapi32
, "GetLengthSid");
664 if (s_pfn_Get_Length_Sid
== NULL
)
668 return (s_pfn_Get_Length_Sid (sid
));
672 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
674 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
675 HMODULE hm_advapi32
= NULL
;
676 if (is_windows_9x () == TRUE
)
680 if (g_b_init_copy_sid
== 0)
682 g_b_init_copy_sid
= 1;
683 hm_advapi32
= LoadLibrary ("Advapi32.dll");
685 (CopySid_Proc
) GetProcAddress (
686 hm_advapi32
, "CopySid");
688 if (s_pfn_Copy_Sid
== NULL
)
692 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
696 END: Wrapper functions around OpenProcessToken
697 and other functions in advapi32.dll that are only
698 supported in Windows NT / 2k / XP
702 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
704 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
705 if (is_windows_9x () != TRUE
)
707 if (g_b_init_get_native_system_info
== 0)
709 g_b_init_get_native_system_info
= 1;
710 s_pfn_Get_Native_System_Info
=
711 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
712 "GetNativeSystemInfo");
714 if (s_pfn_Get_Native_System_Info
!= NULL
)
715 s_pfn_Get_Native_System_Info (lpSystemInfo
);
718 lpSystemInfo
->dwNumberOfProcessors
= -1;
722 get_system_times (LPFILETIME lpIdleTime
,
723 LPFILETIME lpKernelTime
,
724 LPFILETIME lpUserTime
)
726 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
727 if (is_windows_9x () == TRUE
)
731 if (g_b_init_get_system_times
== 0)
733 g_b_init_get_system_times
= 1;
734 s_pfn_Get_System_times
=
735 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
738 if (s_pfn_Get_System_times
== NULL
)
740 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
743 /* Equivalent of strerror for W32 error codes. */
745 w32_strerror (int error_no
)
747 static char buf
[500];
750 error_no
= GetLastError ();
753 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
755 0, /* choose most suitable language */
756 buf
, sizeof (buf
), NULL
))
757 sprintf (buf
, "w32 error %u", error_no
);
761 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
762 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
764 This is called from alloc.c:valid_pointer_p. */
766 w32_valid_pointer_p (void *p
, int size
)
769 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
773 unsigned char *buf
= alloca (size
);
774 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
783 static char startup_dir
[MAXPATHLEN
];
785 /* Get the current working directory. */
790 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
794 /* Emacs doesn't actually change directory itself, and we want to
795 force our real wd to be where emacs.exe is to avoid unnecessary
796 conflicts when trying to rename or delete directories. */
797 strcpy (dir
, startup_dir
);
802 /* Emulate getloadavg. */
811 /* Number of processors on this machine. */
812 static unsigned num_of_processors
;
814 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
815 static struct load_sample samples
[16*60];
816 static int first_idx
= -1, last_idx
= -1;
817 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
822 int next_idx
= from
+ 1;
824 if (next_idx
>= max_idx
)
833 int prev_idx
= from
- 1;
836 prev_idx
= max_idx
- 1;
842 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
845 FILETIME ft_idle
, ft_user
, ft_kernel
;
847 /* Initialize the number of processors on this machine. */
848 if (num_of_processors
<= 0)
850 get_native_system_info (&sysinfo
);
851 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
852 if (num_of_processors
<= 0)
854 GetSystemInfo (&sysinfo
);
855 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
857 if (num_of_processors
<= 0)
858 num_of_processors
= 1;
861 /* TODO: Take into account threads that are ready to run, by
862 sampling the "\System\Processor Queue Length" performance
863 counter. The code below accounts only for threads that are
866 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
868 ULARGE_INTEGER uidle
, ukernel
, uuser
;
870 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
871 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
872 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
873 *idle
= uidle
.QuadPart
;
874 *kernel
= ukernel
.QuadPart
;
875 *user
= uuser
.QuadPart
;
885 /* Produce the load average for a given time interval, using the
886 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
887 1-minute, 5-minute, or 15-minute average, respectively. */
891 double retval
= -1.0;
894 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
895 time_t now
= samples
[last_idx
].sample_time
;
897 if (first_idx
!= last_idx
)
899 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
901 tdiff
= difftime (now
, samples
[idx
].sample_time
);
902 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
905 samples
[last_idx
].kernel
+ samples
[last_idx
].user
906 - (samples
[idx
].kernel
+ samples
[idx
].user
);
907 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
909 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
912 if (idx
== first_idx
)
921 getloadavg (double loadavg
[], int nelem
)
924 ULONGLONG idle
, kernel
, user
;
925 time_t now
= time (NULL
);
927 /* Store another sample. We ignore samples that are less than 1 sec
929 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
931 sample_system_load (&idle
, &kernel
, &user
);
932 last_idx
= buf_next (last_idx
);
933 samples
[last_idx
].sample_time
= now
;
934 samples
[last_idx
].idle
= idle
;
935 samples
[last_idx
].kernel
= kernel
;
936 samples
[last_idx
].user
= user
;
937 /* If the buffer has more that 15 min worth of samples, discard
940 first_idx
= last_idx
;
941 while (first_idx
!= last_idx
942 && (difftime (now
, samples
[first_idx
].sample_time
)
943 >= 15.0*60 + 2*DBL_EPSILON
*now
))
944 first_idx
= buf_next (first_idx
);
947 for (elem
= 0; elem
< nelem
; elem
++)
949 double avg
= getavg (elem
);
959 /* Emulate getpwuid, getpwnam and others. */
961 #define PASSWD_FIELD_SIZE 256
963 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
964 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
965 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
966 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
967 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
969 static struct passwd dflt_passwd
=
981 static char dflt_group_name
[GNLEN
+1];
983 static struct group dflt_group
=
985 /* When group information is not available, we return this as the
986 group for all files. */
994 return dflt_passwd
.pw_uid
;
1000 /* I could imagine arguing for checking to see whether the user is
1001 in the Administrators group and returning a UID of 0 for that
1002 case, but I don't know how wise that would be in the long run. */
1009 return dflt_passwd
.pw_gid
;
1019 getpwuid (unsigned uid
)
1021 if (uid
== dflt_passwd
.pw_uid
)
1022 return &dflt_passwd
;
1027 getgrgid (gid_t gid
)
1033 getpwnam (char *name
)
1037 pw
= getpwuid (getuid ());
1041 if (xstrcasecmp (name
, pw
->pw_name
))
1048 init_user_info (void)
1050 /* Find the user's real name by opening the process token and
1051 looking up the name associated with the user-sid in that token.
1053 Use the relative portion of the identifier authority value from
1054 the user-sid as the user id value (same for group id using the
1055 primary group sid from the process token). */
1057 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1058 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1059 DWORD glength
= sizeof (gname
);
1060 HANDLE token
= NULL
;
1061 SID_NAME_USE user_type
;
1062 unsigned char *buf
= NULL
;
1064 TOKEN_USER user_token
;
1065 TOKEN_PRIMARY_GROUP group_token
;
1068 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1071 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1072 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1074 buf
= xmalloc (blen
);
1075 result
= get_token_information (token
, TokenUser
,
1076 (LPVOID
)buf
, blen
, &needed
);
1079 memcpy (&user_token
, buf
, sizeof (user_token
));
1080 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1082 domain
, &dlength
, &user_type
);
1090 strcpy (dflt_passwd
.pw_name
, uname
);
1091 /* Determine a reasonable uid value. */
1092 if (xstrcasecmp ("administrator", uname
) == 0)
1094 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1095 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1099 /* Use the last sub-authority value of the RID, the relative
1100 portion of the SID, as user/group ID. */
1101 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1103 /* Get group id and name. */
1104 result
= get_token_information (token
, TokenPrimaryGroup
,
1105 (LPVOID
)buf
, blen
, &needed
);
1106 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1108 buf
= xrealloc (buf
, blen
= needed
);
1109 result
= get_token_information (token
, TokenPrimaryGroup
,
1110 (LPVOID
)buf
, blen
, &needed
);
1114 memcpy (&group_token
, buf
, sizeof (group_token
));
1115 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1116 dlength
= sizeof (domain
);
1117 /* If we can get at the real Primary Group name, use that.
1118 Otherwise, the default group name was already set to
1119 "None" in globals_of_w32. */
1120 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1121 gname
, &glength
, NULL
, &dlength
,
1123 strcpy (dflt_group_name
, gname
);
1126 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1129 /* If security calls are not supported (presumably because we
1130 are running under Windows 9X), fallback to this: */
1131 else if (GetUserName (uname
, &ulength
))
1133 strcpy (dflt_passwd
.pw_name
, uname
);
1134 if (xstrcasecmp ("administrator", uname
) == 0)
1135 dflt_passwd
.pw_uid
= 0;
1137 dflt_passwd
.pw_uid
= 123;
1138 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1142 strcpy (dflt_passwd
.pw_name
, "unknown");
1143 dflt_passwd
.pw_uid
= 123;
1144 dflt_passwd
.pw_gid
= 123;
1146 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1148 /* Ensure HOME and SHELL are defined. */
1149 if (getenv ("HOME") == NULL
)
1151 if (getenv ("SHELL") == NULL
)
1154 /* Set dir and shell from environment variables. */
1155 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1156 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1160 CloseHandle (token
);
1166 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1167 return ((rand () << 15) | rand ());
1177 /* Normalize filename by converting all path separators to
1178 the specified separator. Also conditionally convert upper
1179 case path name components to lower case. */
1182 normalize_filename (register char *fp
, char path_sep
)
1187 /* Always lower-case drive letters a-z, even if the filesystem
1188 preserves case in filenames.
1189 This is so filenames can be compared by string comparison
1190 functions that are case-sensitive. Even case-preserving filesystems
1191 do not distinguish case in drive letters. */
1192 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1198 if (NILP (Vw32_downcase_file_names
))
1202 if (*fp
== '/' || *fp
== '\\')
1209 sep
= path_sep
; /* convert to this path separator */
1210 elem
= fp
; /* start of current path element */
1213 if (*fp
>= 'a' && *fp
<= 'z')
1214 elem
= 0; /* don't convert this element */
1216 if (*fp
== 0 || *fp
== ':')
1218 sep
= *fp
; /* restore current separator (or 0) */
1219 *fp
= '/'; /* after conversion of this element */
1222 if (*fp
== '/' || *fp
== '\\')
1224 if (elem
&& elem
!= fp
)
1226 *fp
= 0; /* temporary end of string */
1227 _strlwr (elem
); /* while we convert to lower case */
1229 *fp
= sep
; /* convert (or restore) path separator */
1230 elem
= fp
+ 1; /* next element starts after separator */
1236 /* Destructively turn backslashes into slashes. */
1238 dostounix_filename (register char *p
)
1240 normalize_filename (p
, '/');
1243 /* Destructively turn slashes into backslashes. */
1245 unixtodos_filename (register char *p
)
1247 normalize_filename (p
, '\\');
1250 /* Remove all CR's that are followed by a LF.
1251 (From msdos.c...probably should figure out a way to share it,
1252 although this code isn't going to ever change.) */
1254 crlf_to_lf (register int n
, register unsigned char *buf
)
1256 unsigned char *np
= buf
;
1257 unsigned char *startp
= buf
;
1258 unsigned char *endp
= buf
+ n
;
1262 while (buf
< endp
- 1)
1266 if (*(++buf
) != 0x0a)
1277 /* Parse the root part of file name, if present. Return length and
1278 optionally store pointer to char after root. */
1280 parse_root (char * name
, char ** pPath
)
1282 char * start
= name
;
1287 /* find the root name of the volume if given */
1288 if (isalpha (name
[0]) && name
[1] == ':')
1290 /* skip past drive specifier */
1292 if (IS_DIRECTORY_SEP (name
[0]))
1295 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1301 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1306 if (IS_DIRECTORY_SEP (name
[0]))
1313 return name
- start
;
1316 /* Get long base name for name; name is assumed to be absolute. */
1318 get_long_basename (char * name
, char * buf
, int size
)
1320 WIN32_FIND_DATA find_data
;
1324 /* must be valid filename, no wild cards or other invalid characters */
1325 if (_mbspbrk (name
, "*?|<>\""))
1328 dir_handle
= FindFirstFile (name
, &find_data
);
1329 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1331 if ((len
= strlen (find_data
.cFileName
)) < size
)
1332 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1335 FindClose (dir_handle
);
1340 /* Get long name for file, if possible (assumed to be absolute). */
1342 w32_get_long_filename (char * name
, char * buf
, int size
)
1347 char full
[ MAX_PATH
];
1350 len
= strlen (name
);
1351 if (len
>= MAX_PATH
)
1354 /* Use local copy for destructive modification. */
1355 memcpy (full
, name
, len
+1);
1356 unixtodos_filename (full
);
1358 /* Copy root part verbatim. */
1359 len
= parse_root (full
, &p
);
1360 memcpy (o
, full
, len
);
1365 while (p
!= NULL
&& *p
)
1368 p
= strchr (q
, '\\');
1370 len
= get_long_basename (full
, o
, size
);
1393 is_unc_volume (const char *filename
)
1395 const char *ptr
= filename
;
1397 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1400 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1406 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1409 sigsetmask (int signal_mask
)
1427 sigunblock (int sig
)
1433 sigemptyset (sigset_t
*set
)
1439 sigaddset (sigset_t
*set
, int signo
)
1445 sigfillset (sigset_t
*set
)
1451 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1457 pthread_sigmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1459 if (sigprocmask (how
, set
, oset
) == -1)
1465 setpgrp (int pid
, int gid
)
1476 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1479 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1482 HKEY hrootkey
= NULL
;
1485 /* Check both the current user and the local machine to see if
1486 we have any resources. */
1488 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1492 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1493 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1494 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1496 RegCloseKey (hrootkey
);
1502 RegCloseKey (hrootkey
);
1505 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1509 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1510 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1511 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1513 RegCloseKey (hrootkey
);
1519 RegCloseKey (hrootkey
);
1525 char *get_emacs_configuration (void);
1528 init_environment (char ** argv
)
1530 static const char * const tempdirs
[] = {
1531 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1536 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1538 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1539 temporary files and assume "/tmp" if $TMPDIR is unset, which
1540 will break on DOS/Windows. Refuse to work if we cannot find
1541 a directory, not even "c:/", usable for that purpose. */
1542 for (i
= 0; i
< imax
; i
++)
1544 const char *tmp
= tempdirs
[i
];
1547 tmp
= getenv (tmp
+ 1);
1548 /* Note that `access' can lie to us if the directory resides on a
1549 read-only filesystem, like CD-ROM or a write-protected floppy.
1550 The only way to be really sure is to actually create a file and
1551 see if it succeeds. But I think that's too much to ask. */
1553 /* MSVC's _access crashes with D_OK. */
1554 if (tmp
&& sys_access (tmp
, D_OK
) == 0)
1556 if (tmp
&& _access (tmp
, D_OK
) == 0)
1559 char * var
= alloca (strlen (tmp
) + 8);
1560 sprintf (var
, "TMPDIR=%s", tmp
);
1561 _putenv (strdup (var
));
1568 Fcons (build_string ("no usable temporary directories found!!"),
1570 "While setting TMPDIR: ");
1572 /* Check for environment variables and use registry settings if they
1573 don't exist. Fallback on default values where applicable. */
1578 char locale_name
[32];
1579 struct stat ignored
;
1580 char default_home
[MAX_PATH
];
1583 static const struct env_entry
1590 {"PRELOAD_WINSOCK", NULL
},
1591 {"emacs_dir", "C:/emacs"},
1592 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1593 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1594 {"EMACSDATA", "%emacs_dir%/etc"},
1595 {"EMACSPATH", "%emacs_dir%/bin"},
1596 /* We no longer set INFOPATH because Info-default-directory-list
1598 /* {"INFOPATH", "%emacs_dir%/info"}, */
1599 {"EMACSDOC", "%emacs_dir%/etc"},
1604 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1606 /* We need to copy dflt_envvars[] and work on the copy because we
1607 don't want the dumped Emacs to inherit the values of
1608 environment variables we saw during dumping (which could be on
1609 a different system). The defaults above must be left intact. */
1610 struct env_entry env_vars
[N_ENV_VARS
];
1612 for (i
= 0; i
< N_ENV_VARS
; i
++)
1613 env_vars
[i
] = dflt_envvars
[i
];
1615 /* For backwards compatibility, check if a .emacs file exists in C:/
1616 If not, then we can try to default to the appdata directory under the
1617 user's profile, which is more likely to be writable. */
1618 if (stat ("C:/.emacs", &ignored
) < 0)
1620 HRESULT profile_result
;
1621 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1622 of Windows 95 and NT4 that have not been updated to include
1624 ShGetFolderPath_fn get_folder_path
;
1625 get_folder_path
= (ShGetFolderPath_fn
)
1626 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1628 if (get_folder_path
!= NULL
)
1630 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1633 /* If we can't get the appdata dir, revert to old behavior. */
1634 if (profile_result
== S_OK
)
1636 env_vars
[0].def_value
= default_home
;
1642 /* Get default locale info and use it for LANG. */
1643 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1644 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1645 locale_name
, sizeof (locale_name
)))
1647 for (i
= 0; i
< N_ENV_VARS
; i
++)
1649 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1651 env_vars
[i
].def_value
= locale_name
;
1657 /* When Emacs is invoked with --no-site-lisp, we must remove the
1658 site-lisp directories from the default value of EMACSLOADPATH.
1659 This assumes that the site-lisp entries are at the front, and
1660 that additional entries do exist. */
1663 for (i
= 0; i
< N_ENV_VARS
; i
++)
1665 if (strcmp (env_vars
[i
].name
, "EMACSLOADPATH") == 0)
1668 while ((site
= strstr (env_vars
[i
].def_value
, "site-lisp")))
1669 env_vars
[i
].def_value
= strchr (site
, ';') + 1;
1675 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1677 /* Treat emacs_dir specially: set it unconditionally based on our
1678 location, if it appears that we are running from the bin subdir
1679 of a standard installation. */
1682 char modname
[MAX_PATH
];
1684 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1686 if ((p
= strrchr (modname
, '\\')) == NULL
)
1690 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1692 char buf
[SET_ENV_BUF_SIZE
];
1695 for (p
= modname
; *p
; p
++)
1696 if (*p
== '\\') *p
= '/';
1698 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1699 _putenv (strdup (buf
));
1701 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1703 /* FIXME: should use substring of get_emacs_configuration ().
1704 But I don't think the Windows build supports alpha, mips etc
1705 anymore, so have taken the easy option for now. */
1706 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1709 p
= strrchr (modname
, '\\');
1713 p
= strrchr (modname
, '\\');
1714 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1716 char buf
[SET_ENV_BUF_SIZE
];
1719 for (p
= modname
; *p
; p
++)
1720 if (*p
== '\\') *p
= '/';
1722 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1723 _putenv (strdup (buf
));
1729 for (i
= 0; i
< N_ENV_VARS
; i
++)
1731 if (!getenv (env_vars
[i
].name
))
1735 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1736 /* Also ignore empty environment variables. */
1740 lpval
= env_vars
[i
].def_value
;
1741 dwType
= REG_EXPAND_SZ
;
1743 if (!strcmp (env_vars
[i
].name
, "HOME") && !appdata
)
1745 Lisp_Object warning
[2];
1746 warning
[0] = intern ("initialization");
1747 warning
[1] = build_string ("Setting HOME to C:\\ by default is deprecated");
1748 Vdelayed_warnings_list
= Fcons (Flist (2, warning
),
1749 Vdelayed_warnings_list
);
1755 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1757 if (dwType
== REG_EXPAND_SZ
)
1758 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1759 else if (dwType
== REG_SZ
)
1760 strcpy (buf1
, lpval
);
1761 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1763 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1765 _putenv (strdup (buf2
));
1775 /* Rebuild system configuration to reflect invoking system. */
1776 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1778 /* Another special case: on NT, the PATH variable is actually named
1779 "Path" although cmd.exe (perhaps NT itself) arranges for
1780 environment variable lookup and setting to be case insensitive.
1781 However, Emacs assumes a fully case sensitive environment, so we
1782 need to change "Path" to "PATH" to match the expectations of
1783 various elisp packages. We do this by the sneaky method of
1784 modifying the string in the C runtime environ entry.
1786 The same applies to COMSPEC. */
1790 for (envp
= environ
; *envp
; envp
++)
1791 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1792 memcpy (*envp
, "PATH=", 5);
1793 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1794 memcpy (*envp
, "COMSPEC=", 8);
1797 /* Remember the initial working directory for getwd, then make the
1798 real wd be the location of emacs.exe to avoid conflicts when
1799 renaming or deleting directories. (We also don't call chdir when
1800 running subprocesses for the same reason.) */
1801 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1806 static char modname
[MAX_PATH
];
1808 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1810 if ((p
= strrchr (modname
, '\\')) == NULL
)
1814 SetCurrentDirectory (modname
);
1816 /* Ensure argv[0] has the full path to Emacs. */
1821 /* Determine if there is a middle mouse button, to allow parse_button
1822 to decide whether right mouse events should be mouse-2 or
1824 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1830 emacs_root_dir (void)
1832 static char root_dir
[FILENAME_MAX
];
1835 p
= getenv ("emacs_dir");
1838 strcpy (root_dir
, p
);
1839 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1840 dostounix_filename (root_dir
);
1844 /* We don't have scripts to automatically determine the system configuration
1845 for Emacs before it's compiled, and we don't want to have to make the
1846 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1850 get_emacs_configuration (void)
1852 char *arch
, *oem
, *os
;
1854 static char configuration_buffer
[32];
1856 /* Determine the processor type. */
1857 switch (get_processor_type ())
1860 #ifdef PROCESSOR_INTEL_386
1861 case PROCESSOR_INTEL_386
:
1862 case PROCESSOR_INTEL_486
:
1863 case PROCESSOR_INTEL_PENTIUM
:
1868 #ifdef PROCESSOR_MIPS_R2000
1869 case PROCESSOR_MIPS_R2000
:
1870 case PROCESSOR_MIPS_R3000
:
1871 case PROCESSOR_MIPS_R4000
:
1876 #ifdef PROCESSOR_ALPHA_21064
1877 case PROCESSOR_ALPHA_21064
:
1887 /* Use the OEM field to reflect the compiler/library combination. */
1889 #define COMPILER_NAME "msvc"
1892 #define COMPILER_NAME "mingw"
1894 #define COMPILER_NAME "unknown"
1897 oem
= COMPILER_NAME
;
1899 switch (osinfo_cache
.dwPlatformId
) {
1900 case VER_PLATFORM_WIN32_NT
:
1902 build_num
= osinfo_cache
.dwBuildNumber
;
1904 case VER_PLATFORM_WIN32_WINDOWS
:
1905 if (osinfo_cache
.dwMinorVersion
== 0) {
1910 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1912 case VER_PLATFORM_WIN32s
:
1913 /* Not supported, should not happen. */
1915 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1923 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1924 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1925 get_w32_major_version (), get_w32_minor_version (), build_num
);
1927 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1930 return configuration_buffer
;
1934 get_emacs_configuration_options (void)
1936 static char *options_buffer
;
1937 char cv
[32]; /* Enough for COMPILER_VERSION. */
1939 cv
, /* To be filled later. */
1943 #ifdef ENABLE_CHECKING
1944 " --enable-checking",
1946 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1947 with a starting space to save work here. */
1949 " --cflags", USER_CFLAGS
,
1952 " --ldflags", USER_LDFLAGS
,
1959 /* Work out the effective configure options for this build. */
1961 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1964 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1966 #define COMPILER_VERSION ""
1970 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
1971 return "Error: not enough space for compiler version";
1972 cv
[sizeof (cv
) - 1] = '\0';
1974 for (i
= 0; options
[i
]; i
++)
1975 size
+= strlen (options
[i
]);
1977 options_buffer
= xmalloc (size
+ 1);
1978 options_buffer
[0] = '\0';
1980 for (i
= 0; options
[i
]; i
++)
1981 strcat (options_buffer
, options
[i
]);
1983 return options_buffer
;
1987 #include <sys/timeb.h>
1989 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1991 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1996 tv
->tv_sec
= tb
.time
;
1997 tv
->tv_usec
= tb
.millitm
* 1000L;
1998 /* Implementation note: _ftime sometimes doesn't update the dstflag
1999 according to the new timezone when the system timezone is
2000 changed. We could fix that by using GetSystemTime and
2001 GetTimeZoneInformation, but that doesn't seem necessary, since
2002 Emacs always calls gettimeofday with the 2nd argument NULL (see
2006 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
2007 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
2011 /* ------------------------------------------------------------------------- */
2012 /* IO support and wrapper functions for W32 API. */
2013 /* ------------------------------------------------------------------------- */
2015 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2016 on network directories, so we handle that case here.
2017 (Ulrich Leodolter, 1/11/95). */
2019 sys_ctime (const time_t *t
)
2021 char *str
= (char *) ctime (t
);
2022 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2025 /* Emulate sleep...we could have done this with a define, but that
2026 would necessitate including windows.h in the files that used it.
2027 This is much easier. */
2029 sys_sleep (int seconds
)
2031 Sleep (seconds
* 1000);
2034 /* Internal MSVC functions for low-level descriptor munging */
2035 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2036 extern int __cdecl
_free_osfhnd (int fd
);
2038 /* parallel array of private info on file handles */
2039 filedesc fd_info
[ MAXDESC
];
2041 typedef struct volume_info_data
{
2042 struct volume_info_data
* next
;
2044 /* time when info was obtained */
2047 /* actual volume info */
2056 /* Global referenced by various functions. */
2057 static volume_info_data volume_info
;
2059 /* Vector to indicate which drives are local and fixed (for which cached
2060 data never expires). */
2061 static BOOL fixed_drives
[26];
2063 /* Consider cached volume information to be stale if older than 10s,
2064 at least for non-local drives. Info for fixed drives is never stale. */
2065 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2066 #define VOLINFO_STILL_VALID( root_dir, info ) \
2067 ( ( isalpha (root_dir[0]) && \
2068 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2069 || GetTickCount () - info->timestamp < 10000 )
2071 /* Cache support functions. */
2073 /* Simple linked list with linear search is sufficient. */
2074 static volume_info_data
*volume_cache
= NULL
;
2076 static volume_info_data
*
2077 lookup_volume_info (char * root_dir
)
2079 volume_info_data
* info
;
2081 for (info
= volume_cache
; info
; info
= info
->next
)
2082 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2088 add_volume_info (char * root_dir
, volume_info_data
* info
)
2090 info
->root_dir
= xstrdup (root_dir
);
2091 info
->next
= volume_cache
;
2092 volume_cache
= info
;
2096 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2097 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2098 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2099 static volume_info_data
*
2100 GetCachedVolumeInformation (char * root_dir
)
2102 volume_info_data
* info
;
2103 char default_root
[ MAX_PATH
];
2105 /* NULL for root_dir means use root from current directory. */
2106 if (root_dir
== NULL
)
2108 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2110 parse_root (default_root
, &root_dir
);
2112 root_dir
= default_root
;
2115 /* Local fixed drives can be cached permanently. Removable drives
2116 cannot be cached permanently, since the volume name and serial
2117 number (if nothing else) can change. Remote drives should be
2118 treated as if they are removable, since there is no sure way to
2119 tell whether they are or not. Also, the UNC association of drive
2120 letters mapped to remote volumes can be changed at any time (even
2121 by other processes) without notice.
2123 As a compromise, so we can benefit from caching info for remote
2124 volumes, we use a simple expiry mechanism to invalidate cache
2125 entries that are more than ten seconds old. */
2128 /* No point doing this, because WNetGetConnection is even slower than
2129 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2130 GetDriveType is about the only call of this type which does not
2131 involve network access, and so is extremely quick). */
2133 /* Map drive letter to UNC if remote. */
2134 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2136 char remote_name
[ 256 ];
2137 char drive
[3] = { root_dir
[0], ':' };
2139 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2141 /* do something */ ;
2145 info
= lookup_volume_info (root_dir
);
2147 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2155 /* Info is not cached, or is stale. */
2156 if (!GetVolumeInformation (root_dir
,
2157 name
, sizeof (name
),
2161 type
, sizeof (type
)))
2164 /* Cache the volume information for future use, overwriting existing
2165 entry if present. */
2168 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2169 add_volume_info (root_dir
, info
);
2177 info
->name
= xstrdup (name
);
2178 info
->serialnum
= serialnum
;
2179 info
->maxcomp
= maxcomp
;
2180 info
->flags
= flags
;
2181 info
->type
= xstrdup (type
);
2182 info
->timestamp
= GetTickCount ();
2188 /* Get information on the volume where name is held; set path pointer to
2189 start of pathname in name (past UNC header\volume header if present). */
2191 get_volume_info (const char * name
, const char ** pPath
)
2193 char temp
[MAX_PATH
];
2194 char *rootname
= NULL
; /* default to current volume */
2195 volume_info_data
* info
;
2200 /* find the root name of the volume if given */
2201 if (isalpha (name
[0]) && name
[1] == ':')
2209 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2216 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2229 info
= GetCachedVolumeInformation (rootname
);
2232 /* Set global referenced by other functions. */
2233 volume_info
= *info
;
2239 /* Determine if volume is FAT format (ie. only supports short 8.3
2240 names); also set path pointer to start of pathname in name. */
2242 is_fat_volume (const char * name
, const char ** pPath
)
2244 if (get_volume_info (name
, pPath
))
2245 return (volume_info
.maxcomp
== 12);
2249 /* Map filename to a valid 8.3 name if necessary. */
2251 map_w32_filename (const char * name
, const char ** pPath
)
2253 static char shortname
[MAX_PATH
];
2254 char * str
= shortname
;
2257 const char * save_name
= name
;
2259 if (strlen (name
) >= MAX_PATH
)
2261 /* Return a filename which will cause callers to fail. */
2262 strcpy (shortname
, "?");
2266 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2268 register int left
= 8; /* maximum number of chars in part */
2269 register int extn
= 0; /* extension added? */
2270 register int dots
= 2; /* maximum number of dots allowed */
2273 *str
++ = *name
++; /* skip past UNC header */
2275 while ((c
= *name
++))
2282 extn
= 0; /* reset extension flags */
2283 dots
= 2; /* max 2 dots */
2284 left
= 8; /* max length 8 for main part */
2288 extn
= 0; /* reset extension flags */
2289 dots
= 2; /* max 2 dots */
2290 left
= 8; /* max length 8 for main part */
2295 /* Convert path components of the form .xxx to _xxx,
2296 but leave . and .. as they are. This allows .emacs
2297 to be read as _emacs, for example. */
2301 IS_DIRECTORY_SEP (*name
))
2316 extn
= 1; /* we've got an extension */
2317 left
= 3; /* 3 chars in extension */
2321 /* any embedded dots after the first are converted to _ */
2326 case '#': /* don't lose these, they're important */
2328 str
[-1] = c
; /* replace last character of part */
2333 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2335 dots
= 0; /* started a path component */
2344 strcpy (shortname
, name
);
2345 unixtodos_filename (shortname
);
2349 *pPath
= shortname
+ (path
- save_name
);
2355 is_exec (const char * name
)
2357 char * p
= strrchr (name
, '.');
2360 && (xstrcasecmp (p
, ".exe") == 0 ||
2361 xstrcasecmp (p
, ".com") == 0 ||
2362 xstrcasecmp (p
, ".bat") == 0 ||
2363 xstrcasecmp (p
, ".cmd") == 0));
2366 /* Emulate the Unix directory procedures opendir, closedir,
2367 and readdir. We can't use the procedures supplied in sysdep.c,
2368 so we provide them here. */
2370 struct direct dir_static
; /* simulated directory contents */
2371 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2372 static int dir_is_fat
;
2373 static char dir_pathname
[MAXPATHLEN
+1];
2374 static WIN32_FIND_DATA dir_find_data
;
2376 /* Support shares on a network resource as subdirectories of a read-only
2378 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2379 static HANDLE
open_unc_volume (const char *);
2380 static char *read_unc_volume (HANDLE
, char *, int);
2381 static void close_unc_volume (HANDLE
);
2384 opendir (char *filename
)
2388 /* Opening is done by FindFirstFile. However, a read is inherent to
2389 this operation, so we defer the open until read time. */
2391 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2393 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2396 if (is_unc_volume (filename
))
2398 wnet_enum_handle
= open_unc_volume (filename
);
2399 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2403 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2410 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2411 dir_pathname
[MAXPATHLEN
] = '\0';
2412 dir_is_fat
= is_fat_volume (filename
, NULL
);
2418 closedir (DIR *dirp
)
2420 /* If we have a find-handle open, close it. */
2421 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2423 FindClose (dir_find_handle
);
2424 dir_find_handle
= INVALID_HANDLE_VALUE
;
2426 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2428 close_unc_volume (wnet_enum_handle
);
2429 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2431 xfree ((char *) dirp
);
2437 int downcase
= !NILP (Vw32_downcase_file_names
);
2439 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2441 if (!read_unc_volume (wnet_enum_handle
,
2442 dir_find_data
.cFileName
,
2446 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2447 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2449 char filename
[MAXNAMLEN
+ 3];
2452 strcpy (filename
, dir_pathname
);
2453 ln
= strlen (filename
) - 1;
2454 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2455 strcat (filename
, "\\");
2456 strcat (filename
, "*");
2458 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2460 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2465 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2469 /* Emacs never uses this value, so don't bother making it match
2470 value returned by stat(). */
2471 dir_static
.d_ino
= 1;
2473 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2475 /* If the file name in cFileName[] includes `?' characters, it means
2476 the original file name used characters that cannot be represented
2477 by the current ANSI codepage. To avoid total lossage, retrieve
2478 the short 8+3 alias of the long file name. */
2479 if (_mbspbrk (dir_static
.d_name
, "?"))
2481 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2482 downcase
= 1; /* 8+3 aliases are returned in all caps */
2484 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2485 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2486 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2488 /* If the file name in cFileName[] includes `?' characters, it means
2489 the original file name used characters that cannot be represented
2490 by the current ANSI codepage. To avoid total lossage, retrieve
2491 the short 8+3 alias of the long file name. */
2492 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2494 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2495 /* 8+3 aliases are returned in all caps, which could break
2496 various alists that look at filenames' extensions. */
2500 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2501 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2503 _strlwr (dir_static
.d_name
);
2507 for (p
= dir_static
.d_name
; *p
; p
++)
2508 if (*p
>= 'a' && *p
<= 'z')
2511 _strlwr (dir_static
.d_name
);
2518 open_unc_volume (const char *path
)
2524 nr
.dwScope
= RESOURCE_GLOBALNET
;
2525 nr
.dwType
= RESOURCETYPE_DISK
;
2526 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2527 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2528 nr
.lpLocalName
= NULL
;
2529 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2530 nr
.lpComment
= NULL
;
2531 nr
.lpProvider
= NULL
;
2533 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2534 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2536 if (result
== NO_ERROR
)
2539 return INVALID_HANDLE_VALUE
;
2543 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2547 DWORD bufsize
= 512;
2552 buffer
= alloca (bufsize
);
2553 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
2554 if (result
!= NO_ERROR
)
2557 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2558 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2560 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2563 strncpy (readbuf
, ptr
, size
);
2568 close_unc_volume (HANDLE henum
)
2570 if (henum
!= INVALID_HANDLE_VALUE
)
2571 WNetCloseEnum (henum
);
2575 unc_volume_file_attributes (const char *path
)
2580 henum
= open_unc_volume (path
);
2581 if (henum
== INVALID_HANDLE_VALUE
)
2584 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2586 close_unc_volume (henum
);
2591 /* Ensure a network connection is authenticated. */
2593 logon_network_drive (const char *path
)
2595 NETRESOURCE resource
;
2596 char share
[MAX_PATH
];
2601 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2602 drvtype
= DRIVE_REMOTE
;
2603 else if (path
[0] == '\0' || path
[1] != ':')
2604 drvtype
= GetDriveType (NULL
);
2611 drvtype
= GetDriveType (drive
);
2614 /* Only logon to networked drives. */
2615 if (drvtype
!= DRIVE_REMOTE
)
2619 strncpy (share
, path
, MAX_PATH
);
2620 /* Truncate to just server and share name. */
2621 for (i
= 2; i
< MAX_PATH
; i
++)
2623 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2630 resource
.dwType
= RESOURCETYPE_DISK
;
2631 resource
.lpLocalName
= NULL
;
2632 resource
.lpRemoteName
= share
;
2633 resource
.lpProvider
= NULL
;
2635 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2638 /* Shadow some MSVC runtime functions to map requests for long filenames
2639 to reasonable short names if necessary. This was originally added to
2640 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2644 sys_access (const char * path
, int mode
)
2648 /* MSVC implementation doesn't recognize D_OK. */
2649 path
= map_w32_filename (path
, NULL
);
2650 if (is_unc_volume (path
))
2652 attributes
= unc_volume_file_attributes (path
);
2653 if (attributes
== -1) {
2658 else if ((attributes
= GetFileAttributes (path
)) == -1)
2660 /* Should try mapping GetLastError to errno; for now just indicate
2661 that path doesn't exist. */
2665 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2670 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2675 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2684 sys_chdir (const char * path
)
2686 return _chdir (map_w32_filename (path
, NULL
));
2690 sys_chmod (const char * path
, int mode
)
2692 return _chmod (map_w32_filename (path
, NULL
), mode
);
2696 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2698 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2704 sys_creat (const char * path
, int mode
)
2706 return _creat (map_w32_filename (path
, NULL
), mode
);
2710 sys_fopen (const char * path
, const char * mode
)
2714 const char * mode_save
= mode
;
2716 /* Force all file handles to be non-inheritable. This is necessary to
2717 ensure child processes don't unwittingly inherit handles that might
2718 prevent future file access. */
2722 else if (mode
[0] == 'w' || mode
[0] == 'a')
2723 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2727 /* Only do simplistic option parsing. */
2731 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2734 else if (mode
[0] == 'b')
2739 else if (mode
[0] == 't')
2746 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2750 return _fdopen (fd
, mode_save
);
2753 /* This only works on NTFS volumes, but is useful to have. */
2755 sys_link (const char * old
, const char * new)
2759 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2761 if (old
== NULL
|| new == NULL
)
2767 strcpy (oldname
, map_w32_filename (old
, NULL
));
2768 strcpy (newname
, map_w32_filename (new, NULL
));
2770 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2771 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2772 if (fileh
!= INVALID_HANDLE_VALUE
)
2776 /* Confusingly, the "alternate" stream name field does not apply
2777 when restoring a hard link, and instead contains the actual
2778 stream data for the link (ie. the name of the link to create).
2779 The WIN32_STREAM_ID structure before the cStreamName field is
2780 the stream header, which is then immediately followed by the
2784 WIN32_STREAM_ID wid
;
2785 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2788 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2789 data
.wid
.cStreamName
, MAX_PATH
);
2792 LPVOID context
= NULL
;
2795 data
.wid
.dwStreamId
= BACKUP_LINK
;
2796 data
.wid
.dwStreamAttributes
= 0;
2797 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2798 data
.wid
.Size
.HighPart
= 0;
2799 data
.wid
.dwStreamNameSize
= 0;
2801 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2802 offsetof (WIN32_STREAM_ID
, cStreamName
)
2803 + data
.wid
.Size
.LowPart
,
2804 &wbytes
, FALSE
, FALSE
, &context
)
2805 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2812 /* Should try mapping GetLastError to errno; for now just
2813 indicate a general error (eg. links not supported). */
2814 errno
= EINVAL
; // perhaps EMLINK?
2818 CloseHandle (fileh
);
2827 sys_mkdir (const char * path
)
2829 return _mkdir (map_w32_filename (path
, NULL
));
2832 /* Because of long name mapping issues, we need to implement this
2833 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2834 a unique name, instead of setting the input template to an empty
2837 Standard algorithm seems to be use pid or tid with a letter on the
2838 front (in place of the 6 X's) and cycle through the letters to find a
2839 unique name. We extend that to allow any reasonable character as the
2840 first of the 6 X's. */
2842 sys_mktemp (char * template)
2846 unsigned uid
= GetCurrentThreadId ();
2847 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2849 if (template == NULL
)
2851 p
= template + strlen (template);
2853 /* replace up to the last 5 X's with uid in decimal */
2854 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2856 p
[0] = '0' + uid
% 10;
2860 if (i
< 0 && p
[0] == 'X')
2865 int save_errno
= errno
;
2866 p
[0] = first_char
[i
];
2867 if (sys_access (template, 0) < 0)
2873 while (++i
< sizeof (first_char
));
2876 /* Template is badly formed or else we can't generate a unique name,
2877 so return empty string */
2883 sys_open (const char * path
, int oflag
, int mode
)
2885 const char* mpath
= map_w32_filename (path
, NULL
);
2886 /* Try to open file without _O_CREAT, to be able to write to hidden
2887 and system files. Force all file handles to be
2889 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2892 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2896 sys_rename (const char * oldname
, const char * newname
)
2899 char temp
[MAX_PATH
];
2903 /* MoveFile on Windows 95 doesn't correctly change the short file name
2904 alias in a number of circumstances (it is not easy to predict when
2905 just by looking at oldname and newname, unfortunately). In these
2906 cases, renaming through a temporary name avoids the problem.
2908 A second problem on Windows 95 is that renaming through a temp name when
2909 newname is uppercase fails (the final long name ends up in
2910 lowercase, although the short alias might be uppercase) UNLESS the
2911 long temp name is not 8.3.
2913 So, on Windows 95 we always rename through a temp name, and we make sure
2914 the temp name has a long extension to ensure correct renaming. */
2916 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2918 /* volume_info is set indirectly by map_w32_filename. */
2919 oldname_dev
= volume_info
.serialnum
;
2921 if (os_subtype
== OS_WIN95
)
2927 oldname
= map_w32_filename (oldname
, NULL
);
2928 if ((o
= strrchr (oldname
, '\\')))
2931 o
= (char *) oldname
;
2933 if ((p
= strrchr (temp
, '\\')))
2940 /* Force temp name to require a manufactured 8.3 alias - this
2941 seems to make the second rename work properly. */
2942 sprintf (p
, "_.%s.%u", o
, i
);
2944 result
= rename (oldname
, temp
);
2946 /* This loop must surely terminate! */
2947 while (result
< 0 && errno
== EEXIST
);
2952 /* Emulate Unix behavior - newname is deleted if it already exists
2953 (at least if it is a file; don't do this for directories).
2955 Since we mustn't do this if we are just changing the case of the
2956 file name (we would end up deleting the file we are trying to
2957 rename!), we let rename detect if the destination file already
2958 exists - that way we avoid the possible pitfalls of trying to
2959 determine ourselves whether two names really refer to the same
2960 file, which is not always possible in the general case. (Consider
2961 all the permutations of shared or subst'd drives, etc.) */
2963 newname
= map_w32_filename (newname
, NULL
);
2965 /* volume_info is set indirectly by map_w32_filename. */
2966 newname_dev
= volume_info
.serialnum
;
2968 result
= rename (temp
, newname
);
2974 && newname_dev
!= oldname_dev
)
2976 /* The implementation of `rename' on Windows does not return
2977 errno = EXDEV when you are moving a directory to a
2978 different storage device (ex. logical disk). It returns
2979 EACCES instead. So here we handle such situations and
2983 if ((attributes
= GetFileAttributes (temp
)) != -1
2984 && attributes
& FILE_ATTRIBUTE_DIRECTORY
)
2987 else if (errno
== EEXIST
)
2989 if (_chmod (newname
, 0666) != 0)
2991 if (_unlink (newname
) != 0)
2993 result
= rename (temp
, newname
);
3001 sys_rmdir (const char * path
)
3003 return _rmdir (map_w32_filename (path
, NULL
));
3007 sys_unlink (const char * path
)
3009 path
= map_w32_filename (path
, NULL
);
3011 /* On Unix, unlink works without write permission. */
3012 _chmod (path
, 0666);
3013 return _unlink (path
);
3016 static FILETIME utc_base_ft
;
3017 static ULONGLONG utc_base
; /* In 100ns units */
3018 static int init
= 0;
3020 #define FILETIME_TO_U64(result, ft) \
3022 ULARGE_INTEGER uiTemp; \
3023 uiTemp.LowPart = (ft).dwLowDateTime; \
3024 uiTemp.HighPart = (ft).dwHighDateTime; \
3025 result = uiTemp.QuadPart; \
3029 initialize_utc_base (void)
3031 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3040 st
.wMilliseconds
= 0;
3042 SystemTimeToFileTime (&st
, &utc_base_ft
);
3043 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3047 convert_time (FILETIME ft
)
3053 initialize_utc_base ();
3057 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3060 FILETIME_TO_U64 (tmp
, ft
);
3061 return (time_t) ((tmp
- utc_base
) / 10000000L);
3065 convert_from_time_t (time_t time
, FILETIME
* pft
)
3071 initialize_utc_base ();
3075 /* time in 100ns units since 1-Jan-1601 */
3076 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3077 pft
->dwHighDateTime
= tmp
.HighPart
;
3078 pft
->dwLowDateTime
= tmp
.LowPart
;
3082 /* No reason to keep this; faking inode values either by hashing or even
3083 using the file index from GetInformationByHandle, is not perfect and
3084 so by default Emacs doesn't use the inode values on Windows.
3085 Instead, we now determine file-truename correctly (except for
3086 possible drive aliasing etc). */
3088 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3090 hashval (const unsigned char * str
)
3095 h
= (h
<< 4) + *str
++;
3101 /* Return the hash value of the canonical pathname, excluding the
3102 drive/UNC header, to get a hopefully unique inode number. */
3104 generate_inode_val (const char * name
)
3106 char fullname
[ MAX_PATH
];
3110 /* Get the truly canonical filename, if it exists. (Note: this
3111 doesn't resolve aliasing due to subst commands, or recognize hard
3113 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3116 parse_root (fullname
, &p
);
3117 /* Normal W32 filesystems are still case insensitive. */
3124 static PSECURITY_DESCRIPTOR
3125 get_file_security_desc (const char *fname
)
3127 PSECURITY_DESCRIPTOR psd
= NULL
;
3129 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3130 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3132 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3134 err
= GetLastError ();
3135 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3139 psd
= xmalloc (sd_len
);
3140 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3152 unsigned n_subauthorities
;
3154 /* Use the last sub-authority value of the RID, the relative
3155 portion of the SID, as user/group ID. */
3156 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3157 if (n_subauthorities
< 1)
3158 return 0; /* the "World" RID */
3159 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3162 /* Caching SID and account values for faster lokup. */
3165 # define FLEXIBLE_ARRAY_MEMBER
3167 # define FLEXIBLE_ARRAY_MEMBER 1
3172 struct w32_id
*next
;
3174 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3177 static struct w32_id
*w32_idlist
;
3180 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3182 struct w32_id
*tail
, *found
;
3184 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3186 if (equal_sid ((PSID
)tail
->sid
, sid
))
3195 strcpy (name
, found
->name
);
3203 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3206 struct w32_id
*new_entry
;
3208 /* We don't want to leave behind stale cache from when Emacs was
3212 sid_len
= get_length_sid (sid
);
3213 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3216 new_entry
->rid
= id
;
3217 strcpy (new_entry
->name
, name
);
3218 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3219 new_entry
->next
= w32_idlist
;
3220 w32_idlist
= new_entry
;
3229 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3230 unsigned *id
, char *nm
, int what
)
3233 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3235 SID_NAME_USE ignore
;
3237 DWORD name_len
= sizeof (name
);
3239 DWORD domain_len
= sizeof (domain
);
3245 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3246 else if (what
== GID
)
3247 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3251 if (!result
|| !is_valid_sid (sid
))
3253 else if (!w32_cached_id (sid
, id
, nm
))
3255 /* If FNAME is a UNC, we need to lookup account on the
3256 specified machine. */
3257 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3258 && fname
[2] != '\0')
3263 for (s
= fname
+ 2, p
= machine
;
3264 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3270 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3271 domain
, &domain_len
, &ignore
)
3272 || name_len
> UNLEN
+1)
3276 *id
= get_rid (sid
);
3278 w32_add_to_cache (sid
, *id
, name
);
3285 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3289 int dflt_usr
= 0, dflt_grp
= 0;
3298 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3300 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3303 /* Consider files to belong to current user/group, if we cannot get
3304 more accurate information. */
3307 st
->st_uid
= dflt_passwd
.pw_uid
;
3308 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3312 st
->st_gid
= dflt_passwd
.pw_gid
;
3313 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3317 /* Return non-zero if NAME is a potentially slow filesystem. */
3319 is_slow_fs (const char *name
)
3324 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3325 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3326 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3327 devtype
= GetDriveType (NULL
); /* use root of current drive */
3330 /* GetDriveType needs the root directory of the drive. */
3331 strncpy (drive_root
, name
, 2);
3332 drive_root
[2] = '\\';
3333 drive_root
[3] = '\0';
3334 devtype
= GetDriveType (drive_root
);
3336 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3339 /* MSVC stat function can't cope with UNC names and has other bugs, so
3340 replace it with our own. This also allows us to calculate consistent
3341 inode values without hacks in the main Emacs code. */
3343 stat (const char * path
, struct stat
* buf
)
3346 WIN32_FIND_DATA wfd
;
3348 unsigned __int64 fake_inode
;
3351 int rootdir
= FALSE
;
3352 PSECURITY_DESCRIPTOR psd
= NULL
;
3354 if (path
== NULL
|| buf
== NULL
)
3360 name
= (char *) map_w32_filename (path
, &path
);
3361 /* Must be valid filename, no wild cards or other invalid
3362 characters. We use _mbspbrk to support multibyte strings that
3363 might look to strpbrk as if they included literal *, ?, and other
3364 characters mentioned below that are disallowed by Windows
3366 if (_mbspbrk (name
, "*?|<>\""))
3372 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3373 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3374 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3379 /* Remove trailing directory separator, unless name is the root
3380 directory of a drive or UNC volume in which case ensure there
3381 is a trailing separator. */
3382 len
= strlen (name
);
3383 rootdir
= (path
>= name
+ len
- 1
3384 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3385 name
= strcpy (alloca (len
+ 2), name
);
3387 if (is_unc_volume (name
))
3389 DWORD attrs
= unc_volume_file_attributes (name
);
3394 memset (&wfd
, 0, sizeof (wfd
));
3395 wfd
.dwFileAttributes
= attrs
;
3396 wfd
.ftCreationTime
= utc_base_ft
;
3397 wfd
.ftLastAccessTime
= utc_base_ft
;
3398 wfd
.ftLastWriteTime
= utc_base_ft
;
3399 strcpy (wfd
.cFileName
, name
);
3403 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3404 strcat (name
, "\\");
3405 if (GetDriveType (name
) < 2)
3410 memset (&wfd
, 0, sizeof (wfd
));
3411 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3412 wfd
.ftCreationTime
= utc_base_ft
;
3413 wfd
.ftLastAccessTime
= utc_base_ft
;
3414 wfd
.ftLastWriteTime
= utc_base_ft
;
3415 strcpy (wfd
.cFileName
, name
);
3419 if (IS_DIRECTORY_SEP (name
[len
-1]))
3422 /* (This is hacky, but helps when doing file completions on
3423 network drives.) Optimize by using information available from
3424 active readdir if possible. */
3425 len
= strlen (dir_pathname
);
3426 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3428 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3429 && strnicmp (name
, dir_pathname
, len
) == 0
3430 && IS_DIRECTORY_SEP (name
[len
])
3431 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3433 /* This was the last entry returned by readdir. */
3434 wfd
= dir_find_data
;
3438 logon_network_drive (name
);
3440 fh
= FindFirstFile (name
, &wfd
);
3441 if (fh
== INVALID_HANDLE_VALUE
)
3450 if (!(NILP (Vw32_get_true_file_attributes
)
3451 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3452 /* No access rights required to get info. */
3453 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3454 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3455 != INVALID_HANDLE_VALUE
)
3457 /* This is more accurate in terms of getting the correct number
3458 of links, but is quite slow (it is noticeable when Emacs is
3459 making a list of file name completions). */
3460 BY_HANDLE_FILE_INFORMATION info
;
3462 if (GetFileInformationByHandle (fh
, &info
))
3464 buf
->st_nlink
= info
.nNumberOfLinks
;
3465 /* Might as well use file index to fake inode values, but this
3466 is not guaranteed to be unique unless we keep a handle open
3467 all the time (even then there are situations where it is
3468 not unique). Reputedly, there are at most 48 bits of info
3469 (on NTFS, presumably less on FAT). */
3470 fake_inode
= info
.nFileIndexHigh
;
3472 fake_inode
+= info
.nFileIndexLow
;
3480 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3482 buf
->st_mode
= S_IFDIR
;
3486 switch (GetFileType (fh
))
3488 case FILE_TYPE_DISK
:
3489 buf
->st_mode
= S_IFREG
;
3491 case FILE_TYPE_PIPE
:
3492 buf
->st_mode
= S_IFIFO
;
3494 case FILE_TYPE_CHAR
:
3495 case FILE_TYPE_UNKNOWN
:
3497 buf
->st_mode
= S_IFCHR
;
3501 psd
= get_file_security_desc (name
);
3502 get_file_owner_and_group (psd
, name
, buf
);
3506 /* Don't bother to make this information more accurate. */
3507 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3512 get_file_owner_and_group (NULL
, name
, buf
);
3517 /* Not sure if there is any point in this. */
3518 if (!NILP (Vw32_generate_fake_inodes
))
3519 fake_inode
= generate_inode_val (name
);
3520 else if (fake_inode
== 0)
3522 /* For want of something better, try to make everything unique. */
3523 static DWORD gen_num
= 0;
3524 fake_inode
= ++gen_num
;
3528 /* MSVC defines _ino_t to be short; other libc's might not. */
3529 if (sizeof (buf
->st_ino
) == 2)
3530 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3532 buf
->st_ino
= fake_inode
;
3534 /* volume_info is set indirectly by map_w32_filename */
3535 buf
->st_dev
= volume_info
.serialnum
;
3536 buf
->st_rdev
= volume_info
.serialnum
;
3538 buf
->st_size
= wfd
.nFileSizeHigh
;
3539 buf
->st_size
<<= 32;
3540 buf
->st_size
+= wfd
.nFileSizeLow
;
3542 /* Convert timestamps to Unix format. */
3543 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3544 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3545 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3546 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3547 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3549 /* determine rwx permissions */
3550 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3551 permission
= S_IREAD
;
3553 permission
= S_IREAD
| S_IWRITE
;
3555 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3556 permission
|= S_IEXEC
;
3557 else if (is_exec (name
))
3558 permission
|= S_IEXEC
;
3560 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3565 /* Provide fstat and utime as well as stat for consistent handling of
3568 fstat (int desc
, struct stat
* buf
)
3570 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3571 BY_HANDLE_FILE_INFORMATION info
;
3572 unsigned __int64 fake_inode
;
3575 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3577 case FILE_TYPE_DISK
:
3578 buf
->st_mode
= S_IFREG
;
3579 if (!GetFileInformationByHandle (fh
, &info
))
3585 case FILE_TYPE_PIPE
:
3586 buf
->st_mode
= S_IFIFO
;
3588 case FILE_TYPE_CHAR
:
3589 case FILE_TYPE_UNKNOWN
:
3591 buf
->st_mode
= S_IFCHR
;
3593 memset (&info
, 0, sizeof (info
));
3594 info
.dwFileAttributes
= 0;
3595 info
.ftCreationTime
= utc_base_ft
;
3596 info
.ftLastAccessTime
= utc_base_ft
;
3597 info
.ftLastWriteTime
= utc_base_ft
;
3600 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3601 buf
->st_mode
= S_IFDIR
;
3603 buf
->st_nlink
= info
.nNumberOfLinks
;
3604 /* Might as well use file index to fake inode values, but this
3605 is not guaranteed to be unique unless we keep a handle open
3606 all the time (even then there are situations where it is
3607 not unique). Reputedly, there are at most 48 bits of info
3608 (on NTFS, presumably less on FAT). */
3609 fake_inode
= info
.nFileIndexHigh
;
3611 fake_inode
+= info
.nFileIndexLow
;
3613 /* MSVC defines _ino_t to be short; other libc's might not. */
3614 if (sizeof (buf
->st_ino
) == 2)
3615 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3617 buf
->st_ino
= fake_inode
;
3619 /* Consider files to belong to current user.
3620 FIXME: this should use GetSecurityInfo API, but it is only
3621 available for _WIN32_WINNT >= 0x501. */
3622 buf
->st_uid
= dflt_passwd
.pw_uid
;
3623 buf
->st_gid
= dflt_passwd
.pw_gid
;
3624 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3625 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3627 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3628 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3630 buf
->st_size
= info
.nFileSizeHigh
;
3631 buf
->st_size
<<= 32;
3632 buf
->st_size
+= info
.nFileSizeLow
;
3634 /* Convert timestamps to Unix format. */
3635 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3636 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3637 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3638 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3639 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3641 /* determine rwx permissions */
3642 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3643 permission
= S_IREAD
;
3645 permission
= S_IREAD
| S_IWRITE
;
3647 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3648 permission
|= S_IEXEC
;
3651 #if 0 /* no way of knowing the filename */
3652 char * p
= strrchr (name
, '.');
3654 (xstrcasecmp (p
, ".exe") == 0 ||
3655 xstrcasecmp (p
, ".com") == 0 ||
3656 xstrcasecmp (p
, ".bat") == 0 ||
3657 xstrcasecmp (p
, ".cmd") == 0))
3658 permission
|= S_IEXEC
;
3662 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3668 utime (const char *name
, struct utimbuf
*times
)
3670 struct utimbuf deftime
;
3677 deftime
.modtime
= deftime
.actime
= time (NULL
);
3681 /* Need write access to set times. */
3682 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3683 0, OPEN_EXISTING
, 0, NULL
);
3686 convert_from_time_t (times
->actime
, &atime
);
3687 convert_from_time_t (times
->modtime
, &mtime
);
3688 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3705 /* Symlink-related functions that always fail. Used in fileio.c and in
3706 sysdep.c to avoid #ifdef's. */
3708 symlink (char const *dummy1
, char const *dummy2
)
3715 readlink (const char *name
, char *dummy1
, size_t dummy2
)
3717 /* `access' is much faster than `stat' on MS-Windows. */
3718 if (sys_access (name
, 0) == 0)
3724 careadlinkat (int fd
, char const *filename
,
3725 char *buffer
, size_t buffer_size
,
3726 struct allocator
const *alloc
,
3727 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
3734 careadlinkatcwd (int fd
, char const *filename
, char *buffer
,
3738 return readlink (filename
, buffer
, buffer_size
);
3742 /* Support for browsing other processes and their attributes. See
3743 process.c for the Lisp bindings. */
3745 /* Helper wrapper functions. */
3747 static HANDLE WINAPI
3748 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
3750 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3752 if (g_b_init_create_toolhelp32_snapshot
== 0)
3754 g_b_init_create_toolhelp32_snapshot
= 1;
3755 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3756 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3757 "CreateToolhelp32Snapshot");
3759 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3761 return INVALID_HANDLE_VALUE
;
3763 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3767 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3769 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3771 if (g_b_init_process32_first
== 0)
3773 g_b_init_process32_first
= 1;
3774 s_pfn_Process32_First
= (Process32First_Proc
)
3775 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3778 if (s_pfn_Process32_First
== NULL
)
3782 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3786 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3788 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3790 if (g_b_init_process32_next
== 0)
3792 g_b_init_process32_next
= 1;
3793 s_pfn_Process32_Next
= (Process32Next_Proc
)
3794 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3797 if (s_pfn_Process32_Next
== NULL
)
3801 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3805 open_thread_token (HANDLE ThreadHandle
,
3806 DWORD DesiredAccess
,
3808 PHANDLE TokenHandle
)
3810 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3811 HMODULE hm_advapi32
= NULL
;
3812 if (is_windows_9x () == TRUE
)
3814 SetLastError (ERROR_NOT_SUPPORTED
);
3817 if (g_b_init_open_thread_token
== 0)
3819 g_b_init_open_thread_token
= 1;
3820 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3821 s_pfn_Open_Thread_Token
=
3822 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3824 if (s_pfn_Open_Thread_Token
== NULL
)
3826 SetLastError (ERROR_NOT_SUPPORTED
);
3830 s_pfn_Open_Thread_Token (
3839 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3841 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3842 HMODULE hm_advapi32
= NULL
;
3843 if (is_windows_9x () == TRUE
)
3847 if (g_b_init_impersonate_self
== 0)
3849 g_b_init_impersonate_self
= 1;
3850 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3851 s_pfn_Impersonate_Self
=
3852 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3854 if (s_pfn_Impersonate_Self
== NULL
)
3858 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3862 revert_to_self (void)
3864 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3865 HMODULE hm_advapi32
= NULL
;
3866 if (is_windows_9x () == TRUE
)
3870 if (g_b_init_revert_to_self
== 0)
3872 g_b_init_revert_to_self
= 1;
3873 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3874 s_pfn_Revert_To_Self
=
3875 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3877 if (s_pfn_Revert_To_Self
== NULL
)
3881 return s_pfn_Revert_To_Self ();
3885 get_process_memory_info (HANDLE h_proc
,
3886 PPROCESS_MEMORY_COUNTERS mem_counters
,
3889 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3890 HMODULE hm_psapi
= NULL
;
3891 if (is_windows_9x () == TRUE
)
3895 if (g_b_init_get_process_memory_info
== 0)
3897 g_b_init_get_process_memory_info
= 1;
3898 hm_psapi
= LoadLibrary ("Psapi.dll");
3900 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3901 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3903 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3907 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3911 get_process_working_set_size (HANDLE h_proc
,
3915 static GetProcessWorkingSetSize_Proc
3916 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3918 if (is_windows_9x () == TRUE
)
3922 if (g_b_init_get_process_working_set_size
== 0)
3924 g_b_init_get_process_working_set_size
= 1;
3925 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3926 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3927 "GetProcessWorkingSetSize");
3929 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3933 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3937 global_memory_status (MEMORYSTATUS
*buf
)
3939 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3941 if (is_windows_9x () == TRUE
)
3945 if (g_b_init_global_memory_status
== 0)
3947 g_b_init_global_memory_status
= 1;
3948 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3949 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3950 "GlobalMemoryStatus");
3952 if (s_pfn_Global_Memory_Status
== NULL
)
3956 return s_pfn_Global_Memory_Status (buf
);
3960 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
3962 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3964 if (is_windows_9x () == TRUE
)
3968 if (g_b_init_global_memory_status_ex
== 0)
3970 g_b_init_global_memory_status_ex
= 1;
3971 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3972 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3973 "GlobalMemoryStatusEx");
3975 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3979 return s_pfn_Global_Memory_Status_Ex (buf
);
3983 list_system_processes (void)
3985 struct gcpro gcpro1
;
3986 Lisp_Object proclist
= Qnil
;
3989 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3991 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3993 PROCESSENTRY32 proc_entry
;
3999 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
4000 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
4001 res
= process32_next (h_snapshot
, &proc_entry
))
4003 proc_id
= proc_entry
.th32ProcessID
;
4004 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
4007 CloseHandle (h_snapshot
);
4009 proclist
= Fnreverse (proclist
);
4016 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
4018 TOKEN_PRIVILEGES priv
;
4019 DWORD priv_size
= sizeof (priv
);
4020 DWORD opriv_size
= sizeof (*old_priv
);
4021 HANDLE h_token
= NULL
;
4022 HANDLE h_thread
= GetCurrentThread ();
4026 res
= open_thread_token (h_thread
,
4027 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4029 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
4031 if (impersonate_self (SecurityImpersonation
))
4032 res
= open_thread_token (h_thread
,
4033 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4038 priv
.PrivilegeCount
= 1;
4039 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
4040 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
4041 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
4042 old_priv
, &opriv_size
)
4043 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4047 CloseHandle (h_token
);
4053 restore_privilege (TOKEN_PRIVILEGES
*priv
)
4055 DWORD priv_size
= sizeof (*priv
);
4056 HANDLE h_token
= NULL
;
4059 if (open_thread_token (GetCurrentThread (),
4060 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4063 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
4064 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4068 CloseHandle (h_token
);
4074 ltime (long time_sec
, long time_usec
)
4076 return list3 (make_number ((time_sec
>> 16) & 0xffff),
4077 make_number (time_sec
& 0xffff),
4078 make_number (time_usec
));
4081 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
4084 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4085 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4088 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4089 ULONGLONG tem1
, tem2
, tem3
, tem
;
4092 || !get_process_times_fn
4093 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4094 &ft_kernel
, &ft_user
))
4097 GetSystemTimeAsFileTime (&ft_current
);
4099 FILETIME_TO_U64 (tem1
, ft_kernel
);
4101 *stime
= U64_TO_LISP_TIME (tem1
);
4103 FILETIME_TO_U64 (tem2
, ft_user
);
4105 *utime
= U64_TO_LISP_TIME (tem2
);
4108 *ttime
= U64_TO_LISP_TIME (tem3
);
4110 FILETIME_TO_U64 (tem
, ft_creation
);
4111 /* Process no 4 (System) returns zero creation time. */
4113 tem
= (tem
- utc_base
) / 10L;
4114 *ctime
= U64_TO_LISP_TIME (tem
);
4118 FILETIME_TO_U64 (tem3
, ft_current
);
4119 tem
= (tem3
- utc_base
) / 10L - tem
;
4121 *etime
= U64_TO_LISP_TIME (tem
);
4125 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4136 system_process_attributes (Lisp_Object pid
)
4138 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4139 Lisp_Object attrs
= Qnil
;
4140 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4141 HANDLE h_snapshot
, h_proc
;
4144 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4145 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4146 DWORD glength
= sizeof (gname
);
4147 HANDLE token
= NULL
;
4148 SID_NAME_USE user_type
;
4149 unsigned char *buf
= NULL
;
4151 TOKEN_USER user_token
;
4152 TOKEN_PRIMARY_GROUP group_token
;
4155 PROCESS_MEMORY_COUNTERS mem
;
4156 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4157 DWORD minrss
, maxrss
;
4159 MEMORY_STATUS_EX memstex
;
4160 double totphys
= 0.0;
4161 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4163 BOOL result
= FALSE
;
4165 CHECK_NUMBER_OR_FLOAT (pid
);
4166 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4168 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4170 GCPRO3 (attrs
, decoded_cmd
, tem
);
4172 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4177 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4178 for (res
= process32_first (h_snapshot
, &pe
); res
;
4179 res
= process32_next (h_snapshot
, &pe
))
4181 if (proc_id
== pe
.th32ProcessID
)
4184 decoded_cmd
= build_string ("Idle");
4187 /* Decode the command name from locale-specific
4189 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4190 strlen (pe
.szExeFile
));
4192 code_convert_string_norecord (cmd_str
,
4193 Vlocale_coding_system
, 0);
4195 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4196 attrs
= Fcons (Fcons (Qppid
,
4197 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4199 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4201 attrs
= Fcons (Fcons (Qthcount
,
4202 make_fixnum_or_float (pe
.cntThreads
)),
4209 CloseHandle (h_snapshot
);
4218 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4220 /* If we were denied a handle to the process, try again after
4221 enabling the SeDebugPrivilege in our process. */
4224 TOKEN_PRIVILEGES priv_current
;
4226 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4228 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4230 restore_privilege (&priv_current
);
4236 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4239 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4240 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4242 buf
= xmalloc (blen
);
4243 result
= get_token_information (token
, TokenUser
,
4244 (LPVOID
)buf
, blen
, &needed
);
4247 memcpy (&user_token
, buf
, sizeof (user_token
));
4248 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4250 euid
= get_rid (user_token
.User
.Sid
);
4251 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4256 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4259 strcpy (uname
, "unknown");
4263 ulength
= strlen (uname
);
4269 /* Determine a reasonable euid and gid values. */
4270 if (xstrcasecmp ("administrator", uname
) == 0)
4272 euid
= 500; /* well-known Administrator uid */
4273 egid
= 513; /* well-known None gid */
4277 /* Get group id and name. */
4278 result
= get_token_information (token
, TokenPrimaryGroup
,
4279 (LPVOID
)buf
, blen
, &needed
);
4280 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4282 buf
= xrealloc (buf
, blen
= needed
);
4283 result
= get_token_information (token
, TokenPrimaryGroup
,
4284 (LPVOID
)buf
, blen
, &needed
);
4288 memcpy (&group_token
, buf
, sizeof (group_token
));
4289 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4291 egid
= get_rid (group_token
.PrimaryGroup
);
4292 dlength
= sizeof (domain
);
4294 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4295 gname
, &glength
, NULL
, &dlength
,
4298 w32_add_to_cache (group_token
.PrimaryGroup
,
4302 strcpy (gname
, "None");
4306 glength
= strlen (gname
);
4314 if (!is_windows_9x ())
4316 /* We couldn't open the process token, presumably because of
4317 insufficient access rights. Assume this process is run
4319 strcpy (uname
, "SYSTEM");
4320 strcpy (gname
, "None");
4321 euid
= 18; /* SYSTEM */
4322 egid
= 513; /* None */
4323 glength
= strlen (gname
);
4324 ulength
= strlen (uname
);
4326 /* If we are running under Windows 9X, where security calls are
4327 not supported, we assume all processes are run by the current
4329 else if (GetUserName (uname
, &ulength
))
4331 if (xstrcasecmp ("administrator", uname
) == 0)
4336 strcpy (gname
, "None");
4337 glength
= strlen (gname
);
4338 ulength
= strlen (uname
);
4344 strcpy (uname
, "administrator");
4345 ulength
= strlen (uname
);
4346 strcpy (gname
, "None");
4347 glength
= strlen (gname
);
4350 CloseHandle (token
);
4353 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4354 tem
= make_unibyte_string (uname
, ulength
);
4355 attrs
= Fcons (Fcons (Quser
,
4356 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4358 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4359 tem
= make_unibyte_string (gname
, glength
);
4360 attrs
= Fcons (Fcons (Qgroup
,
4361 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4364 if (global_memory_status_ex (&memstex
))
4365 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4366 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4368 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4369 double, so we need to do this for it... */
4371 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4372 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4373 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4375 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4377 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4378 else if (global_memory_status (&memst
))
4379 totphys
= memst
.dwTotalPhys
/ 1024.0;
4382 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4385 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4387 attrs
= Fcons (Fcons (Qmajflt
,
4388 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4390 attrs
= Fcons (Fcons (Qvsize
,
4391 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4393 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4395 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4398 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4400 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4402 attrs
= Fcons (Fcons (Qmajflt
,
4403 make_fixnum_or_float (mem
.PageFaultCount
)),
4405 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4407 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4410 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4412 DWORD rss
= maxrss
/ 1024;
4414 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4416 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4419 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4421 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4422 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4423 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4424 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4425 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4426 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4429 /* FIXME: Retrieve command line by walking the PEB of the process. */
4432 CloseHandle (h_proc
);
4438 /* Wrappers for winsock functions to map between our file descriptors
4439 and winsock's handles; also set h_errno for convenience.
4441 To allow Emacs to run on systems which don't have winsock support
4442 installed, we dynamically link to winsock on startup if present, and
4443 otherwise provide the minimum necessary functionality
4444 (eg. gethostname). */
4446 /* function pointers for relevant socket functions */
4447 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4448 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4449 int (PASCAL
*pfn_WSAGetLastError
) (void);
4450 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4451 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4452 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4453 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4454 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4455 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4456 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4457 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4458 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4459 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4460 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4461 int (PASCAL
*pfn_WSACleanup
) (void);
4463 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4464 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4465 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4466 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4467 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4468 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4469 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4470 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4471 const char * optval
, int optlen
);
4472 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4473 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4475 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4476 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4477 struct sockaddr
* from
, int * fromlen
);
4478 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4479 const struct sockaddr
* to
, int tolen
);
4481 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4482 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4483 #ifndef HANDLE_FLAG_INHERIT
4484 #define HANDLE_FLAG_INHERIT 1
4488 static int winsock_inuse
;
4493 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4495 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4496 after WSAStartup returns successfully, but it seems reasonable
4497 to allow unloading winsock anyway in that case. */
4498 if (pfn_WSACleanup () == 0 ||
4499 pfn_WSAGetLastError () == WSAENETDOWN
)
4501 if (FreeLibrary (winsock_lib
))
4510 init_winsock (int load_now
)
4512 WSADATA winsockData
;
4514 if (winsock_lib
!= NULL
)
4517 pfn_SetHandleInformation
4518 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4519 "SetHandleInformation");
4521 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4523 if (winsock_lib
!= NULL
)
4525 /* dynamically link to socket functions */
4527 #define LOAD_PROC(fn) \
4528 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4531 LOAD_PROC (WSAStartup
);
4532 LOAD_PROC (WSASetLastError
);
4533 LOAD_PROC (WSAGetLastError
);
4534 LOAD_PROC (WSAEventSelect
);
4535 LOAD_PROC (WSACreateEvent
);
4536 LOAD_PROC (WSACloseEvent
);
4539 LOAD_PROC (connect
);
4540 LOAD_PROC (ioctlsocket
);
4543 LOAD_PROC (closesocket
);
4544 LOAD_PROC (shutdown
);
4547 LOAD_PROC (inet_addr
);
4548 LOAD_PROC (gethostname
);
4549 LOAD_PROC (gethostbyname
);
4550 LOAD_PROC (getservbyname
);
4551 LOAD_PROC (getpeername
);
4552 LOAD_PROC (WSACleanup
);
4553 LOAD_PROC (setsockopt
);
4555 LOAD_PROC (getsockname
);
4557 LOAD_PROC (recvfrom
);
4561 /* specify version 1.1 of winsock */
4562 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4564 if (winsockData
.wVersion
!= 0x101)
4569 /* Report that winsock exists and is usable, but leave
4570 socket functions disabled. I am assuming that calling
4571 WSAStartup does not require any network interaction,
4572 and in particular does not cause or require a dial-up
4573 connection to be established. */
4576 FreeLibrary (winsock_lib
);
4584 FreeLibrary (winsock_lib
);
4594 /* function to set h_errno for compatibility; map winsock error codes to
4595 normal system codes where they overlap (non-overlapping definitions
4596 are already in <sys/socket.h> */
4600 if (winsock_lib
== NULL
)
4603 h_errno
= pfn_WSAGetLastError ();
4607 case WSAEACCES
: h_errno
= EACCES
; break;
4608 case WSAEBADF
: h_errno
= EBADF
; break;
4609 case WSAEFAULT
: h_errno
= EFAULT
; break;
4610 case WSAEINTR
: h_errno
= EINTR
; break;
4611 case WSAEINVAL
: h_errno
= EINVAL
; break;
4612 case WSAEMFILE
: h_errno
= EMFILE
; break;
4613 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4614 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4622 if (h_errno
== 0 && winsock_lib
!= NULL
)
4623 pfn_WSASetLastError (0);
4626 /* Extend strerror to handle the winsock-specific error codes. */
4630 } _wsa_errlist
[] = {
4631 {WSAEINTR
, "Interrupted function call"},
4632 {WSAEBADF
, "Bad file descriptor"},
4633 {WSAEACCES
, "Permission denied"},
4634 {WSAEFAULT
, "Bad address"},
4635 {WSAEINVAL
, "Invalid argument"},
4636 {WSAEMFILE
, "Too many open files"},
4638 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
4639 {WSAEINPROGRESS
, "Operation now in progress"},
4640 {WSAEALREADY
, "Operation already in progress"},
4641 {WSAENOTSOCK
, "Socket operation on non-socket"},
4642 {WSAEDESTADDRREQ
, "Destination address required"},
4643 {WSAEMSGSIZE
, "Message too long"},
4644 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
4645 {WSAENOPROTOOPT
, "Bad protocol option"},
4646 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
4647 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
4648 {WSAEOPNOTSUPP
, "Operation not supported"},
4649 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
4650 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
4651 {WSAEADDRINUSE
, "Address already in use"},
4652 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
4653 {WSAENETDOWN
, "Network is down"},
4654 {WSAENETUNREACH
, "Network is unreachable"},
4655 {WSAENETRESET
, "Network dropped connection on reset"},
4656 {WSAECONNABORTED
, "Software caused connection abort"},
4657 {WSAECONNRESET
, "Connection reset by peer"},
4658 {WSAENOBUFS
, "No buffer space available"},
4659 {WSAEISCONN
, "Socket is already connected"},
4660 {WSAENOTCONN
, "Socket is not connected"},
4661 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
4662 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
4663 {WSAETIMEDOUT
, "Connection timed out"},
4664 {WSAECONNREFUSED
, "Connection refused"},
4665 {WSAELOOP
, "Network loop"}, /* not sure */
4666 {WSAENAMETOOLONG
, "Name is too long"},
4667 {WSAEHOSTDOWN
, "Host is down"},
4668 {WSAEHOSTUNREACH
, "No route to host"},
4669 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
4670 {WSAEPROCLIM
, "Too many processes"},
4671 {WSAEUSERS
, "Too many users"}, /* not sure */
4672 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
4673 {WSAESTALE
, "Data is stale"}, /* not sure */
4674 {WSAEREMOTE
, "Remote error"}, /* not sure */
4676 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
4677 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
4678 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
4679 {WSAEDISCON
, "Graceful shutdown in progress"},
4681 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
4682 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
4683 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
4684 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
4685 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
4686 {WSASYSCALLFAILURE
, "System call failure"},
4687 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
4688 {WSATYPE_NOT_FOUND
, "Class type not found"},
4689 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
4690 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
4691 {WSAEREFUSED
, "Operation refused"}, /* not sure */
4694 {WSAHOST_NOT_FOUND
, "Host not found"},
4695 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
4696 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
4697 {WSANO_DATA
, "Valid name, no data record of requested type"},
4703 sys_strerror (int error_no
)
4706 static char unknown_msg
[40];
4708 if (error_no
>= 0 && error_no
< sys_nerr
)
4709 return sys_errlist
[error_no
];
4711 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4712 if (_wsa_errlist
[i
].errnum
== error_no
)
4713 return _wsa_errlist
[i
].msg
;
4715 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4719 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4720 but I believe the method of keeping the socket handle separate (and
4721 insuring it is not inheritable) is the correct one. */
4723 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4725 static int socket_to_fd (SOCKET s
);
4728 sys_socket (int af
, int type
, int protocol
)
4732 if (winsock_lib
== NULL
)
4735 return INVALID_SOCKET
;
4740 /* call the real socket function */
4741 s
= pfn_socket (af
, type
, protocol
);
4743 if (s
!= INVALID_SOCKET
)
4744 return socket_to_fd (s
);
4750 /* Convert a SOCKET to a file descriptor. */
4752 socket_to_fd (SOCKET s
)
4757 /* Although under NT 3.5 _open_osfhandle will accept a socket
4758 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4759 that does not work under NT 3.1. However, we can get the same
4760 effect by using a backdoor function to replace an existing
4761 descriptor handle with the one we want. */
4763 /* allocate a file descriptor (with appropriate flags) */
4764 fd
= _open ("NUL:", _O_RDWR
);
4767 /* Make a non-inheritable copy of the socket handle. Note
4768 that it is possible that sockets aren't actually kernel
4769 handles, which appears to be the case on Windows 9x when
4770 the MS Proxy winsock client is installed. */
4772 /* Apparently there is a bug in NT 3.51 with some service
4773 packs, which prevents using DuplicateHandle to make a
4774 socket handle non-inheritable (causes WSACleanup to
4775 hang). The work-around is to use SetHandleInformation
4776 instead if it is available and implemented. */
4777 if (pfn_SetHandleInformation
)
4779 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4783 HANDLE parent
= GetCurrentProcess ();
4784 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4786 if (DuplicateHandle (parent
,
4792 DUPLICATE_SAME_ACCESS
))
4794 /* It is possible that DuplicateHandle succeeds even
4795 though the socket wasn't really a kernel handle,
4796 because a real handle has the same value. So
4797 test whether the new handle really is a socket. */
4798 long nonblocking
= 0;
4799 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4801 pfn_closesocket (s
);
4806 CloseHandle (new_s
);
4811 fd_info
[fd
].hnd
= (HANDLE
) s
;
4813 /* set our own internal flags */
4814 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4820 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4822 /* attach child_process to fd_info */
4823 if (fd_info
[ fd
].cp
!= NULL
)
4825 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4829 fd_info
[ fd
].cp
= cp
;
4832 winsock_inuse
++; /* count open sockets */
4839 pfn_closesocket (s
);
4845 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4847 if (winsock_lib
== NULL
)
4850 return SOCKET_ERROR
;
4854 if (fd_info
[s
].flags
& FILE_SOCKET
)
4856 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4857 if (rc
== SOCKET_ERROR
)
4862 return SOCKET_ERROR
;
4866 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4868 if (winsock_lib
== NULL
)
4871 return SOCKET_ERROR
;
4875 if (fd_info
[s
].flags
& FILE_SOCKET
)
4877 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4878 if (rc
== SOCKET_ERROR
)
4883 return SOCKET_ERROR
;
4887 sys_htons (u_short hostshort
)
4889 return (winsock_lib
!= NULL
) ?
4890 pfn_htons (hostshort
) : hostshort
;
4894 sys_ntohs (u_short netshort
)
4896 return (winsock_lib
!= NULL
) ?
4897 pfn_ntohs (netshort
) : netshort
;
4901 sys_inet_addr (const char * cp
)
4903 return (winsock_lib
!= NULL
) ?
4904 pfn_inet_addr (cp
) : INADDR_NONE
;
4908 sys_gethostname (char * name
, int namelen
)
4910 if (winsock_lib
!= NULL
)
4911 return pfn_gethostname (name
, namelen
);
4913 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4914 return !GetComputerName (name
, (DWORD
*)&namelen
);
4917 return SOCKET_ERROR
;
4921 sys_gethostbyname (const char * name
)
4923 struct hostent
* host
;
4925 if (winsock_lib
== NULL
)
4932 host
= pfn_gethostbyname (name
);
4939 sys_getservbyname (const char * name
, const char * proto
)
4941 struct servent
* serv
;
4943 if (winsock_lib
== NULL
)
4950 serv
= pfn_getservbyname (name
, proto
);
4957 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4959 if (winsock_lib
== NULL
)
4962 return SOCKET_ERROR
;
4966 if (fd_info
[s
].flags
& FILE_SOCKET
)
4968 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4969 if (rc
== SOCKET_ERROR
)
4974 return SOCKET_ERROR
;
4978 sys_shutdown (int s
, int how
)
4980 if (winsock_lib
== NULL
)
4983 return SOCKET_ERROR
;
4987 if (fd_info
[s
].flags
& FILE_SOCKET
)
4989 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4990 if (rc
== SOCKET_ERROR
)
4995 return SOCKET_ERROR
;
4999 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
5001 if (winsock_lib
== NULL
)
5004 return SOCKET_ERROR
;
5008 if (fd_info
[s
].flags
& FILE_SOCKET
)
5010 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
5011 (const char *)optval
, optlen
);
5012 if (rc
== SOCKET_ERROR
)
5017 return SOCKET_ERROR
;
5021 sys_listen (int s
, int backlog
)
5023 if (winsock_lib
== NULL
)
5026 return SOCKET_ERROR
;
5030 if (fd_info
[s
].flags
& FILE_SOCKET
)
5032 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
5033 if (rc
== SOCKET_ERROR
)
5036 fd_info
[s
].flags
|= FILE_LISTEN
;
5040 return SOCKET_ERROR
;
5044 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
5046 if (winsock_lib
== NULL
)
5049 return SOCKET_ERROR
;
5053 if (fd_info
[s
].flags
& FILE_SOCKET
)
5055 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
5056 if (rc
== SOCKET_ERROR
)
5061 return SOCKET_ERROR
;
5065 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
5067 if (winsock_lib
== NULL
)
5074 if (fd_info
[s
].flags
& FILE_LISTEN
)
5076 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5078 if (t
== INVALID_SOCKET
)
5081 fd
= socket_to_fd (t
);
5083 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5084 ResetEvent (fd_info
[s
].cp
->char_avail
);
5092 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5093 struct sockaddr
* from
, int * fromlen
)
5095 if (winsock_lib
== NULL
)
5098 return SOCKET_ERROR
;
5102 if (fd_info
[s
].flags
& FILE_SOCKET
)
5104 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5105 if (rc
== SOCKET_ERROR
)
5110 return SOCKET_ERROR
;
5114 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5115 const struct sockaddr
* to
, int tolen
)
5117 if (winsock_lib
== NULL
)
5120 return SOCKET_ERROR
;
5124 if (fd_info
[s
].flags
& FILE_SOCKET
)
5126 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5127 if (rc
== SOCKET_ERROR
)
5132 return SOCKET_ERROR
;
5135 /* Windows does not have an fcntl function. Provide an implementation
5136 solely for making sockets non-blocking. */
5138 fcntl (int s
, int cmd
, int options
)
5140 if (winsock_lib
== NULL
)
5147 if (fd_info
[s
].flags
& FILE_SOCKET
)
5149 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5151 unsigned long nblock
= 1;
5152 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5153 if (rc
== SOCKET_ERROR
)
5155 /* Keep track of the fact that we set this to non-blocking. */
5156 fd_info
[s
].flags
|= FILE_NDELAY
;
5162 return SOCKET_ERROR
;
5166 return SOCKET_ERROR
;
5170 /* Shadow main io functions: we need to handle pipes and sockets more
5171 intelligently, and implement non-blocking mode as well. */
5184 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5186 child_process
* cp
= fd_info
[fd
].cp
;
5188 fd_info
[fd
].cp
= NULL
;
5190 if (CHILD_ACTIVE (cp
))
5192 /* if last descriptor to active child_process then cleanup */
5194 for (i
= 0; i
< MAXDESC
; i
++)
5198 if (fd_info
[i
].cp
== cp
)
5203 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5205 if (winsock_lib
== NULL
) abort ();
5207 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5208 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5210 winsock_inuse
--; /* count open sockets */
5217 /* Note that sockets do not need special treatment here (at least on
5218 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5219 closesocket is equivalent to CloseHandle, which is to be expected
5220 because socket handles are fully fledged kernel handles. */
5223 if (rc
== 0 && fd
< MAXDESC
)
5224 fd_info
[fd
].flags
= 0;
5235 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5237 /* duplicate our internal info as well */
5238 fd_info
[new_fd
] = fd_info
[fd
];
5244 sys_dup2 (int src
, int dst
)
5248 if (dst
< 0 || dst
>= MAXDESC
)
5254 /* make sure we close the destination first if it's a pipe or socket */
5255 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5258 rc
= _dup2 (src
, dst
);
5261 /* duplicate our internal info as well */
5262 fd_info
[dst
] = fd_info
[src
];
5267 /* Unix pipe() has only one arg */
5269 sys_pipe (int * phandles
)
5274 /* make pipe handles non-inheritable; when we spawn a child, we
5275 replace the relevant handle with an inheritable one. Also put
5276 pipes into binary mode; we will do text mode translation ourselves
5278 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5282 /* Protect against overflow, since Windows can open more handles than
5283 our fd_info array has room for. */
5284 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5286 _close (phandles
[0]);
5287 _close (phandles
[1]);
5292 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5293 fd_info
[phandles
[0]].flags
= flags
;
5295 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5296 fd_info
[phandles
[1]].flags
= flags
;
5303 /* Function to do blocking read of one byte, needed to implement
5304 select. It is only allowed on sockets and pipes. */
5306 _sys_read_ahead (int fd
)
5311 if (fd
< 0 || fd
>= MAXDESC
)
5312 return STATUS_READ_ERROR
;
5314 cp
= fd_info
[fd
].cp
;
5316 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5317 return STATUS_READ_ERROR
;
5319 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5320 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5322 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5326 cp
->status
= STATUS_READ_IN_PROGRESS
;
5328 if (fd_info
[fd
].flags
& FILE_PIPE
)
5330 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5332 /* Give subprocess time to buffer some more output for us before
5333 reporting that input is available; we need this because Windows 95
5334 connects DOS programs to pipes by making the pipe appear to be
5335 the normal console stdout - as a result most DOS programs will
5336 write to stdout without buffering, ie. one character at a
5337 time. Even some W32 programs do this - "dir" in a command
5338 shell on NT is very slow if we don't do this. */
5341 int wait
= w32_pipe_read_delay
;
5347 /* Yield remainder of our time slice, effectively giving a
5348 temporary priority boost to the child process. */
5352 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5354 HANDLE hnd
= fd_info
[fd
].hnd
;
5355 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5358 /* Configure timeouts for blocking read. */
5359 if (!GetCommTimeouts (hnd
, &ct
))
5360 return STATUS_READ_ERROR
;
5361 ct
.ReadIntervalTimeout
= 0;
5362 ct
.ReadTotalTimeoutMultiplier
= 0;
5363 ct
.ReadTotalTimeoutConstant
= 0;
5364 if (!SetCommTimeouts (hnd
, &ct
))
5365 return STATUS_READ_ERROR
;
5367 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5369 if (GetLastError () != ERROR_IO_PENDING
)
5370 return STATUS_READ_ERROR
;
5371 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5372 return STATUS_READ_ERROR
;
5375 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5377 unsigned long nblock
= 0;
5378 /* We always want this to block, so temporarily disable NDELAY. */
5379 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5380 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5382 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5384 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5387 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5391 if (rc
== sizeof (char))
5392 cp
->status
= STATUS_READ_SUCCEEDED
;
5394 cp
->status
= STATUS_READ_FAILED
;
5400 _sys_wait_accept (int fd
)
5406 if (fd
< 0 || fd
>= MAXDESC
)
5407 return STATUS_READ_ERROR
;
5409 cp
= fd_info
[fd
].cp
;
5411 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5412 return STATUS_READ_ERROR
;
5414 cp
->status
= STATUS_READ_FAILED
;
5416 hEv
= pfn_WSACreateEvent ();
5417 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5418 if (rc
!= SOCKET_ERROR
)
5420 rc
= WaitForSingleObject (hEv
, INFINITE
);
5421 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5422 if (rc
== WAIT_OBJECT_0
)
5423 cp
->status
= STATUS_READ_SUCCEEDED
;
5425 pfn_WSACloseEvent (hEv
);
5431 sys_read (int fd
, char * buffer
, unsigned int count
)
5436 char * orig_buffer
= buffer
;
5444 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5446 child_process
*cp
= fd_info
[fd
].cp
;
5448 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5456 /* re-read CR carried over from last read */
5457 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5459 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5463 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5466 /* presence of a child_process structure means we are operating in
5467 non-blocking mode - otherwise we just call _read directly.
5468 Note that the child_process structure might be missing because
5469 reap_subprocess has been called; in this case the pipe is
5470 already broken, so calling _read on it is okay. */
5473 int current_status
= cp
->status
;
5475 switch (current_status
)
5477 case STATUS_READ_FAILED
:
5478 case STATUS_READ_ERROR
:
5479 /* report normal EOF if nothing in buffer */
5481 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5484 case STATUS_READ_READY
:
5485 case STATUS_READ_IN_PROGRESS
:
5486 DebPrint (("sys_read called when read is in progress\n"));
5487 errno
= EWOULDBLOCK
;
5490 case STATUS_READ_SUCCEEDED
:
5491 /* consume read-ahead char */
5492 *buffer
++ = cp
->chr
;
5495 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5496 ResetEvent (cp
->char_avail
);
5498 case STATUS_READ_ACKNOWLEDGED
:
5502 DebPrint (("sys_read: bad status %d\n", current_status
));
5507 if (fd_info
[fd
].flags
& FILE_PIPE
)
5509 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5510 to_read
= min (waiting
, (DWORD
) count
);
5513 nchars
+= _read (fd
, buffer
, to_read
);
5515 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5517 HANDLE hnd
= fd_info
[fd
].hnd
;
5518 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5524 /* Configure timeouts for non-blocking read. */
5525 if (!GetCommTimeouts (hnd
, &ct
))
5530 ct
.ReadIntervalTimeout
= MAXDWORD
;
5531 ct
.ReadTotalTimeoutMultiplier
= 0;
5532 ct
.ReadTotalTimeoutConstant
= 0;
5533 if (!SetCommTimeouts (hnd
, &ct
))
5539 if (!ResetEvent (ovl
->hEvent
))
5544 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5546 if (GetLastError () != ERROR_IO_PENDING
)
5551 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5560 else /* FILE_SOCKET */
5562 if (winsock_lib
== NULL
) abort ();
5564 /* do the equivalent of a non-blocking read */
5565 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5566 if (waiting
== 0 && nchars
== 0)
5568 h_errno
= errno
= EWOULDBLOCK
;
5574 /* always use binary mode for sockets */
5575 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5576 if (res
== SOCKET_ERROR
)
5578 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5579 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5589 int nread
= _read (fd
, buffer
, count
);
5592 else if (nchars
== 0)
5597 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5598 /* Perform text mode translation if required. */
5599 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5601 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5602 /* If buffer contains only CR, return that. To be absolutely
5603 sure we should attempt to read the next char, but in
5604 practice a CR to be followed by LF would not appear by
5605 itself in the buffer. */
5606 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5608 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5614 nchars
= _read (fd
, buffer
, count
);
5619 /* From w32xfns.c */
5620 extern HANDLE interrupt_handle
;
5622 /* For now, don't bother with a non-blocking mode */
5624 sys_write (int fd
, const void * buffer
, unsigned int count
)
5634 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5636 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5642 /* Perform text mode translation if required. */
5643 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5645 char * tmpbuf
= alloca (count
* 2);
5646 unsigned char * src
= (void *)buffer
;
5647 unsigned char * dst
= tmpbuf
;
5652 unsigned char *next
;
5653 /* copy next line or remaining bytes */
5654 next
= _memccpy (dst
, src
, '\n', nbytes
);
5657 /* copied one line ending with '\n' */
5658 int copied
= next
- dst
;
5661 /* insert '\r' before '\n' */
5668 /* copied remaining partial line -> now finished */
5675 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5677 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5678 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5679 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5682 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5684 if (GetLastError () != ERROR_IO_PENDING
)
5689 if (detect_input_pending ())
5690 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5693 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5694 if (active
== WAIT_OBJECT_0
)
5695 { /* User pressed C-g, cancel write, then leave. Don't bother
5696 cleaning up as we may only get stuck in buggy drivers. */
5697 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5702 if (active
== WAIT_OBJECT_0
+ 1
5703 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5710 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5712 unsigned long nblock
= 0;
5713 if (winsock_lib
== NULL
) abort ();
5715 /* TODO: implement select() properly so non-blocking I/O works. */
5716 /* For now, make sure the write blocks. */
5717 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5718 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5720 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5722 /* Set the socket back to non-blocking if it was before,
5723 for other operations that support it. */
5724 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5727 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5730 if (nchars
== SOCKET_ERROR
)
5732 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5733 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5739 /* Some networked filesystems don't like too large writes, so
5740 break them into smaller chunks. See the Comments section of
5741 the MSDN documentation of WriteFile for details behind the
5742 choice of the value of CHUNK below. See also the thread
5743 http://thread.gmane.org/gmane.comp.version-control.git/145294
5744 in the git mailing list. */
5745 const unsigned char *p
= buffer
;
5746 const unsigned chunk
= 30 * 1024 * 1024;
5751 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5752 int n
= _write (fd
, p
, this_chunk
);
5760 else if (n
< this_chunk
)
5770 /* The Windows CRT functions are "optimized for speed", so they don't
5771 check for timezone and DST changes if they were last called less
5772 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
5773 all Emacs features that repeatedly call time functions (e.g.,
5774 display-time) are in real danger of missing timezone and DST
5775 changes. Calling tzset before each localtime call fixes that. */
5777 sys_localtime (const time_t *t
)
5780 return localtime (t
);
5785 /* Delayed loading of libraries. */
5787 Lisp_Object Vlibrary_cache
;
5789 /* The argument LIBRARIES is an alist that associates a symbol
5790 LIBRARY_ID, identifying an external DLL library known to Emacs, to
5791 a list of filenames under which the library is usually found. In
5792 most cases, the argument passed as LIBRARIES is the variable
5793 `dynamic-library-alist', which is initialized to a list of common
5794 library names. If the function loads the library successfully, it
5795 returns the handle of the DLL, and records the filename in the
5796 property :loaded-from of LIBRARY_ID; it returns NULL if the library
5797 could not be found, or when it was already loaded (because the
5798 handle is not recorded anywhere, and so is lost after use). It
5799 would be trivial to save the handle too in :loaded-from, but
5800 currently there's no use case for it. */
5802 w32_delayed_load (Lisp_Object libraries
, Lisp_Object library_id
)
5804 HMODULE library_dll
= NULL
;
5806 CHECK_SYMBOL (library_id
);
5808 if (CONSP (libraries
) && NILP (Fassq (library_id
, Vlibrary_cache
)))
5810 Lisp_Object found
= Qnil
;
5811 Lisp_Object dlls
= Fassq (library_id
, libraries
);
5814 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
5816 CHECK_STRING_CAR (dlls
);
5817 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
5819 found
= XCAR (dlls
);
5824 Fput (library_id
, QCloaded_from
, found
);
5832 check_windows_init_file (void)
5834 /* A common indication that Emacs is not installed properly is when
5835 it cannot find the Windows installation file. If this file does
5836 not exist in the expected place, tell the user. */
5838 if (!noninteractive
&& !inhibit_window_system
5839 /* Vload_path is not yet initialized when we are loading
5841 && NILP (Vpurify_flag
))
5843 Lisp_Object objs
[2];
5844 Lisp_Object full_load_path
;
5845 Lisp_Object init_file
;
5848 objs
[0] = Vload_path
;
5849 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5850 full_load_path
= Fappend (2, objs
);
5851 init_file
= build_string ("term/w32-win");
5852 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5855 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5856 char *init_file_name
= SDATA (init_file
);
5857 char *load_path
= SDATA (load_path_print
);
5858 char *buffer
= alloca (1024
5859 + strlen (init_file_name
)
5860 + strlen (load_path
));
5863 "The Emacs Windows initialization file \"%s.el\" "
5864 "could not be found in your Emacs installation. "
5865 "Emacs checked the following directories for this file:\n"
5867 "When Emacs cannot find this file, it usually means that it "
5868 "was not installed properly, or its distribution file was "
5869 "not unpacked properly.\nSee the README.W32 file in the "
5870 "top-level Emacs directory for more information.",
5871 init_file_name
, load_path
);
5874 "Emacs Abort Dialog",
5875 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5876 /* Use the low-level Emacs abort. */
5890 /* shutdown the socket interface if necessary */
5899 /* Initialize the socket interface now if available and requested by
5900 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5901 delayed until open-network-stream is called (w32-has-winsock can
5902 also be used to dynamically load or reload winsock).
5904 Conveniently, init_environment is called before us, so
5905 PRELOAD_WINSOCK can be set in the registry. */
5907 /* Always initialize this correctly. */
5910 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5911 init_winsock (TRUE
);
5913 /* Initial preparation for subprocess support: replace our standard
5914 handles with non-inheritable versions. */
5917 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5918 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5919 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5921 parent
= GetCurrentProcess ();
5923 /* ignore errors when duplicating and closing; typically the
5924 handles will be invalid when running as a gui program. */
5925 DuplicateHandle (parent
,
5926 GetStdHandle (STD_INPUT_HANDLE
),
5931 DUPLICATE_SAME_ACCESS
);
5933 DuplicateHandle (parent
,
5934 GetStdHandle (STD_OUTPUT_HANDLE
),
5939 DUPLICATE_SAME_ACCESS
);
5941 DuplicateHandle (parent
,
5942 GetStdHandle (STD_ERROR_HANDLE
),
5947 DUPLICATE_SAME_ACCESS
);
5953 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5954 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5956 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5959 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5960 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5962 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5965 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5966 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5968 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5972 /* unfortunately, atexit depends on implementation of malloc */
5973 /* atexit (term_ntproc); */
5974 signal (SIGABRT
, term_ntproc
);
5976 /* determine which drives are fixed, for GetCachedVolumeInformation */
5978 /* GetDriveType must have trailing backslash. */
5979 char drive
[] = "A:\\";
5981 /* Loop over all possible drive letters */
5982 while (*drive
<= 'Z')
5984 /* Record if this drive letter refers to a fixed drive. */
5985 fixed_drives
[DRIVE_INDEX (*drive
)] =
5986 (GetDriveType (drive
) == DRIVE_FIXED
);
5991 /* Reset the volume info cache. */
5992 volume_cache
= NULL
;
5995 /* Check to see if Emacs has been installed correctly. */
5996 check_windows_init_file ();
6000 shutdown_handler ensures that buffers' autosave files are
6001 up to date when the user logs off, or the system shuts down.
6004 shutdown_handler (DWORD type
)
6006 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
6007 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
6008 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
6009 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
6011 /* Shut down cleanly, making sure autosave files are up to date. */
6012 shut_down_emacs (0, 0, Qnil
);
6015 /* Allow other handlers to handle this signal. */
6020 globals_of_w32 is used to initialize those global variables that
6021 must always be initialized on startup even when the global variable
6022 initialized is non zero (see the function main in emacs.c).
6025 globals_of_w32 (void)
6027 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
6029 get_process_times_fn
= (GetProcessTimes_Proc
)
6030 GetProcAddress (kernel32
, "GetProcessTimes");
6032 DEFSYM (QCloaded_from
, ":loaded-from");
6034 Vlibrary_cache
= Qnil
;
6035 staticpro (&Vlibrary_cache
);
6037 g_b_init_is_windows_9x
= 0;
6038 g_b_init_open_process_token
= 0;
6039 g_b_init_get_token_information
= 0;
6040 g_b_init_lookup_account_sid
= 0;
6041 g_b_init_get_sid_sub_authority
= 0;
6042 g_b_init_get_sid_sub_authority_count
= 0;
6043 g_b_init_get_file_security
= 0;
6044 g_b_init_get_security_descriptor_owner
= 0;
6045 g_b_init_get_security_descriptor_group
= 0;
6046 g_b_init_is_valid_sid
= 0;
6047 g_b_init_create_toolhelp32_snapshot
= 0;
6048 g_b_init_process32_first
= 0;
6049 g_b_init_process32_next
= 0;
6050 g_b_init_open_thread_token
= 0;
6051 g_b_init_impersonate_self
= 0;
6052 g_b_init_revert_to_self
= 0;
6053 g_b_init_get_process_memory_info
= 0;
6054 g_b_init_get_process_working_set_size
= 0;
6055 g_b_init_global_memory_status
= 0;
6056 g_b_init_global_memory_status_ex
= 0;
6057 g_b_init_equal_sid
= 0;
6058 g_b_init_copy_sid
= 0;
6059 g_b_init_get_length_sid
= 0;
6060 g_b_init_get_native_system_info
= 0;
6061 g_b_init_get_system_times
= 0;
6062 num_of_processors
= 0;
6063 /* The following sets a handler for shutdown notifications for
6064 console apps. This actually applies to Emacs in both console and
6065 GUI modes, since we had to fool windows into thinking emacs is a
6066 console application to get console mode to work. */
6067 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
6069 /* "None" is the default group name on standalone workstations. */
6070 strcpy (dflt_group_name
, "None");
6073 /* For make-serial-process */
6075 serial_open (char *port
)
6081 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
6082 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
6083 if (hnd
== INVALID_HANDLE_VALUE
)
6084 error ("Could not open %s", port
);
6085 fd
= (int) _open_osfhandle ((int) hnd
, 0);
6087 error ("Could not open %s", port
);
6091 error ("Could not create child process");
6093 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6094 fd_info
[ fd
].hnd
= hnd
;
6095 fd_info
[ fd
].flags
|=
6096 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
6097 if (fd_info
[ fd
].cp
!= NULL
)
6099 error ("fd_info[fd = %d] is already in use", fd
);
6101 fd_info
[ fd
].cp
= cp
;
6102 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6103 if (cp
->ovl_read
.hEvent
== NULL
)
6104 error ("Could not create read event");
6105 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6106 if (cp
->ovl_write
.hEvent
== NULL
)
6107 error ("Could not create write event");
6112 /* For serial-process-configure */
6114 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
6116 Lisp_Object childp2
= Qnil
;
6117 Lisp_Object tem
= Qnil
;
6121 char summary
[4] = "???"; /* This usually becomes "8N1". */
6123 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6124 error ("Not a serial process");
6125 hnd
= fd_info
[ p
->outfd
].hnd
;
6127 childp2
= Fcopy_sequence (p
->childp
);
6129 /* Initialize timeouts for blocking read and blocking write. */
6130 if (!GetCommTimeouts (hnd
, &ct
))
6131 error ("GetCommTimeouts() failed");
6132 ct
.ReadIntervalTimeout
= 0;
6133 ct
.ReadTotalTimeoutMultiplier
= 0;
6134 ct
.ReadTotalTimeoutConstant
= 0;
6135 ct
.WriteTotalTimeoutMultiplier
= 0;
6136 ct
.WriteTotalTimeoutConstant
= 0;
6137 if (!SetCommTimeouts (hnd
, &ct
))
6138 error ("SetCommTimeouts() failed");
6139 /* Read port attributes and prepare default configuration. */
6140 memset (&dcb
, 0, sizeof (dcb
));
6141 dcb
.DCBlength
= sizeof (DCB
);
6142 if (!GetCommState (hnd
, &dcb
))
6143 error ("GetCommState() failed");
6146 dcb
.fAbortOnError
= FALSE
;
6147 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6152 /* Configure speed. */
6153 if (!NILP (Fplist_member (contact
, QCspeed
)))
6154 tem
= Fplist_get (contact
, QCspeed
);
6156 tem
= Fplist_get (p
->childp
, QCspeed
);
6158 dcb
.BaudRate
= XINT (tem
);
6159 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6161 /* Configure bytesize. */
6162 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6163 tem
= Fplist_get (contact
, QCbytesize
);
6165 tem
= Fplist_get (p
->childp
, QCbytesize
);
6167 tem
= make_number (8);
6169 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6170 error (":bytesize must be nil (8), 7, or 8");
6171 dcb
.ByteSize
= XINT (tem
);
6172 summary
[0] = XINT (tem
) + '0';
6173 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6175 /* Configure parity. */
6176 if (!NILP (Fplist_member (contact
, QCparity
)))
6177 tem
= Fplist_get (contact
, QCparity
);
6179 tem
= Fplist_get (p
->childp
, QCparity
);
6180 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6181 error (":parity must be nil (no parity), `even', or `odd'");
6182 dcb
.fParity
= FALSE
;
6183 dcb
.Parity
= NOPARITY
;
6184 dcb
.fErrorChar
= FALSE
;
6189 else if (EQ (tem
, Qeven
))
6193 dcb
.Parity
= EVENPARITY
;
6194 dcb
.fErrorChar
= TRUE
;
6196 else if (EQ (tem
, Qodd
))
6200 dcb
.Parity
= ODDPARITY
;
6201 dcb
.fErrorChar
= TRUE
;
6203 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6205 /* Configure stopbits. */
6206 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6207 tem
= Fplist_get (contact
, QCstopbits
);
6209 tem
= Fplist_get (p
->childp
, QCstopbits
);
6211 tem
= make_number (1);
6213 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6214 error (":stopbits must be nil (1 stopbit), 1, or 2");
6215 summary
[2] = XINT (tem
) + '0';
6216 if (XINT (tem
) == 1)
6217 dcb
.StopBits
= ONESTOPBIT
;
6218 else if (XINT (tem
) == 2)
6219 dcb
.StopBits
= TWOSTOPBITS
;
6220 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6222 /* Configure flowcontrol. */
6223 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6224 tem
= Fplist_get (contact
, QCflowcontrol
);
6226 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6227 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6228 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6229 dcb
.fOutxCtsFlow
= FALSE
;
6230 dcb
.fOutxDsrFlow
= FALSE
;
6231 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6232 dcb
.fDsrSensitivity
= FALSE
;
6233 dcb
.fTXContinueOnXoff
= FALSE
;
6236 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6237 dcb
.XonChar
= 17; /* Control-Q */
6238 dcb
.XoffChar
= 19; /* Control-S */
6241 /* Already configured. */
6243 else if (EQ (tem
, Qhw
))
6245 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6246 dcb
.fOutxCtsFlow
= TRUE
;
6248 else if (EQ (tem
, Qsw
))
6253 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6255 /* Activate configuration. */
6256 if (!SetCommState (hnd
, &dcb
))
6257 error ("SetCommState() failed");
6259 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6260 p
->childp
= childp2
;
6266 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
6271 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
6272 int fd
= process
->infd
;
6276 n
= sys_read (fd
, (char*)buf
, sz
);
6283 if (err
== EWOULDBLOCK
)
6285 /* Set a small timeout. */
6286 EMACS_SET_SECS_USECS (timeout
, 1, 0);
6288 FD_SET ((int)fd
, &fdset
);
6290 /* Use select with the timeout to poll the selector. */
6291 sc
= select (fd
+ 1, &fdset
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0,
6295 continue; /* Try again. */
6297 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
6298 Also accept select return 0 as an indicator to EAGAIN. */
6299 if (sc
== 0 || errno
== EWOULDBLOCK
)
6302 err
= errno
; /* Other errors are just passed on. */
6305 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
6312 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
6314 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
6315 int fd
= process
->outfd
;
6316 ssize_t n
= sys_write (fd
, buf
, sz
);
6318 /* 0 or more bytes written means everything went fine. */
6322 /* Negative bytes written means we got an error in errno.
6323 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
6324 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
6325 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
6329 #endif /* HAVE_GNUTLS */