1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994-1995, 2000-2011 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 */
38 /* must include CRT headers *before* config.h */
71 #define _ANONYMOUS_UNION
72 #define _ANONYMOUS_STRUCT
75 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
76 use a different name to avoid compilation problems. */
77 typedef struct _MEMORY_STATUS_EX
{
80 DWORDLONG ullTotalPhys
;
81 DWORDLONG ullAvailPhys
;
82 DWORDLONG ullTotalPageFile
;
83 DWORDLONG ullAvailPageFile
;
84 DWORDLONG ullTotalVirtual
;
85 DWORDLONG ullAvailVirtual
;
86 DWORDLONG ullAvailExtendedVirtual
;
87 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
95 #if !defined(__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
96 /* This either is not in psapi.h or guarded by higher value of
97 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
98 defines it in psapi.h */
99 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
101 DWORD PageFaultCount
;
102 DWORD PeakWorkingSetSize
;
103 DWORD WorkingSetSize
;
104 DWORD QuotaPeakPagedPoolUsage
;
105 DWORD QuotaPagedPoolUsage
;
106 DWORD QuotaPeakNonPagedPoolUsage
;
107 DWORD QuotaNonPagedPoolUsage
;
109 DWORD PeakPagefileUsage
;
111 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
114 /* TCP connection support. */
115 #include <sys/socket.h>
138 #include "dispextern.h" /* for xstrcasecmp */
139 #include "coding.h" /* for Vlocale_coding_system */
141 /* For serial_configure and serial_open. */
144 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
145 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
147 void globals_of_w32 (void);
148 static DWORD
get_rid (PSID
);
150 /* Defined in process.c for its own purpose. */
151 extern Lisp_Object Qlocal
;
154 /* Initialization states.
156 WARNING: If you add any more such variables for additional APIs,
157 you MUST add initialization for them to globals_of_w32
158 below. This is because these variables might get set
159 to non-NULL values during dumping, but the dumped Emacs
160 cannot reuse those values, because it could be run on a
161 different version of the OS, where API addresses are
163 static BOOL g_b_init_is_windows_9x
;
164 static BOOL g_b_init_open_process_token
;
165 static BOOL g_b_init_get_token_information
;
166 static BOOL g_b_init_lookup_account_sid
;
167 static BOOL g_b_init_get_sid_sub_authority
;
168 static BOOL g_b_init_get_sid_sub_authority_count
;
169 static BOOL g_b_init_get_file_security
;
170 static BOOL g_b_init_get_security_descriptor_owner
;
171 static BOOL g_b_init_get_security_descriptor_group
;
172 static BOOL g_b_init_is_valid_sid
;
173 static BOOL g_b_init_create_toolhelp32_snapshot
;
174 static BOOL g_b_init_process32_first
;
175 static BOOL g_b_init_process32_next
;
176 static BOOL g_b_init_open_thread_token
;
177 static BOOL g_b_init_impersonate_self
;
178 static BOOL g_b_init_revert_to_self
;
179 static BOOL g_b_init_get_process_memory_info
;
180 static BOOL g_b_init_get_process_working_set_size
;
181 static BOOL g_b_init_global_memory_status
;
182 static BOOL g_b_init_global_memory_status_ex
;
183 static BOOL g_b_init_get_length_sid
;
184 static BOOL g_b_init_equal_sid
;
185 static BOOL g_b_init_copy_sid
;
186 static BOOL g_b_init_get_native_system_info
;
187 static BOOL g_b_init_get_system_times
;
190 BEGIN: Wrapper functions around OpenProcessToken
191 and other functions in advapi32.dll that are only
192 supported in Windows NT / 2k / XP
194 /* ** Function pointer typedefs ** */
195 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
196 HANDLE ProcessHandle
,
198 PHANDLE TokenHandle
);
199 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
201 TOKEN_INFORMATION_CLASS TokenInformationClass
,
202 LPVOID TokenInformation
,
203 DWORD TokenInformationLength
,
204 PDWORD ReturnLength
);
205 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
206 HANDLE process_handle
,
207 LPFILETIME creation_time
,
208 LPFILETIME exit_time
,
209 LPFILETIME kernel_time
,
210 LPFILETIME user_time
);
212 GetProcessTimes_Proc get_process_times_fn
= NULL
;
215 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
216 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
218 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
219 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
221 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
222 LPCTSTR lpSystemName
,
227 LPDWORD cbDomainName
,
228 PSID_NAME_USE peUse
);
229 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
232 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
234 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
236 SECURITY_INFORMATION RequestedInformation
,
237 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
239 LPDWORD lpnLengthNeeded
);
240 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
241 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
243 LPBOOL lpbOwnerDefaulted
);
244 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
245 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
247 LPBOOL lpbGroupDefaulted
);
248 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
250 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
252 DWORD th32ProcessID
);
253 typedef BOOL (WINAPI
* Process32First_Proc
) (
255 LPPROCESSENTRY32 lppe
);
256 typedef BOOL (WINAPI
* Process32Next_Proc
) (
258 LPPROCESSENTRY32 lppe
);
259 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
263 PHANDLE TokenHandle
);
264 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
265 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
266 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
267 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
269 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
271 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
273 DWORD
* lpMinimumWorkingSetSize
,
274 DWORD
* lpMaximumWorkingSetSize
);
275 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
276 LPMEMORYSTATUS lpBuffer
);
277 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
278 LPMEMORY_STATUS_EX lpBuffer
);
279 typedef BOOL (WINAPI
* CopySid_Proc
) (
280 DWORD nDestinationSidLength
,
281 PSID pDestinationSid
,
283 typedef BOOL (WINAPI
* EqualSid_Proc
) (
286 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
288 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
289 LPSYSTEM_INFO lpSystemInfo
);
290 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
291 LPFILETIME lpIdleTime
,
292 LPFILETIME lpKernelTime
,
293 LPFILETIME lpUserTime
);
295 /* ** A utility function ** */
299 static BOOL s_b_ret
= 0;
300 OSVERSIONINFO os_ver
;
301 if (g_b_init_is_windows_9x
== 0)
303 g_b_init_is_windows_9x
= 1;
304 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
305 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
306 if (GetVersionEx (&os_ver
))
308 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
314 /* Get total user and system times for get-internal-run-time.
315 Returns a list of three integers if the times are provided by the OS
316 (NT derivatives), otherwise it returns the result of current-time. */
318 w32_get_internal_run_time (void)
320 if (get_process_times_fn
)
322 FILETIME create
, exit
, kernel
, user
;
323 HANDLE proc
= GetCurrentProcess ();
324 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
326 LARGE_INTEGER user_int
, kernel_int
, total
;
328 user_int
.LowPart
= user
.dwLowDateTime
;
329 user_int
.HighPart
= user
.dwHighDateTime
;
330 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
331 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
332 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
333 /* FILETIME is 100 nanosecond increments, Emacs only wants
334 microsecond resolution. */
335 total
.QuadPart
/= 10;
336 microseconds
= total
.QuadPart
% 1000000;
337 total
.QuadPart
/= 1000000;
339 /* Sanity check to make sure we can represent the result. */
340 if (total
.HighPart
== 0)
342 int secs
= total
.LowPart
;
344 return list3 (make_number ((secs
>> 16) & 0xffff),
345 make_number (secs
& 0xffff),
346 make_number (microseconds
));
351 return Fcurrent_time ();
354 /* ** The wrapper functions ** */
357 open_process_token (HANDLE ProcessHandle
,
361 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
362 HMODULE hm_advapi32
= NULL
;
363 if (is_windows_9x () == TRUE
)
367 if (g_b_init_open_process_token
== 0)
369 g_b_init_open_process_token
= 1;
370 hm_advapi32
= LoadLibrary ("Advapi32.dll");
371 s_pfn_Open_Process_Token
=
372 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
374 if (s_pfn_Open_Process_Token
== NULL
)
379 s_pfn_Open_Process_Token (
387 get_token_information (HANDLE TokenHandle
,
388 TOKEN_INFORMATION_CLASS TokenInformationClass
,
389 LPVOID TokenInformation
,
390 DWORD TokenInformationLength
,
393 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
394 HMODULE hm_advapi32
= NULL
;
395 if (is_windows_9x () == TRUE
)
399 if (g_b_init_get_token_information
== 0)
401 g_b_init_get_token_information
= 1;
402 hm_advapi32
= LoadLibrary ("Advapi32.dll");
403 s_pfn_Get_Token_Information
=
404 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
406 if (s_pfn_Get_Token_Information
== NULL
)
411 s_pfn_Get_Token_Information (
413 TokenInformationClass
,
415 TokenInformationLength
,
421 lookup_account_sid (LPCTSTR lpSystemName
,
426 LPDWORD cbDomainName
,
429 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
430 HMODULE hm_advapi32
= NULL
;
431 if (is_windows_9x () == TRUE
)
435 if (g_b_init_lookup_account_sid
== 0)
437 g_b_init_lookup_account_sid
= 1;
438 hm_advapi32
= LoadLibrary ("Advapi32.dll");
439 s_pfn_Lookup_Account_Sid
=
440 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
442 if (s_pfn_Lookup_Account_Sid
== NULL
)
447 s_pfn_Lookup_Account_Sid (
459 get_sid_sub_authority (PSID pSid
, DWORD n
)
461 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
462 static DWORD zero
= 0U;
463 HMODULE hm_advapi32
= NULL
;
464 if (is_windows_9x () == TRUE
)
468 if (g_b_init_get_sid_sub_authority
== 0)
470 g_b_init_get_sid_sub_authority
= 1;
471 hm_advapi32
= LoadLibrary ("Advapi32.dll");
472 s_pfn_Get_Sid_Sub_Authority
=
473 (GetSidSubAuthority_Proc
) GetProcAddress (
474 hm_advapi32
, "GetSidSubAuthority");
476 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
480 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
484 get_sid_sub_authority_count (PSID pSid
)
486 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
487 static UCHAR zero
= 0U;
488 HMODULE hm_advapi32
= NULL
;
489 if (is_windows_9x () == TRUE
)
493 if (g_b_init_get_sid_sub_authority_count
== 0)
495 g_b_init_get_sid_sub_authority_count
= 1;
496 hm_advapi32
= LoadLibrary ("Advapi32.dll");
497 s_pfn_Get_Sid_Sub_Authority_Count
=
498 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
499 hm_advapi32
, "GetSidSubAuthorityCount");
501 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
505 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
509 get_file_security (LPCTSTR lpFileName
,
510 SECURITY_INFORMATION RequestedInformation
,
511 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
513 LPDWORD lpnLengthNeeded
)
515 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
516 HMODULE hm_advapi32
= NULL
;
517 if (is_windows_9x () == TRUE
)
521 if (g_b_init_get_file_security
== 0)
523 g_b_init_get_file_security
= 1;
524 hm_advapi32
= LoadLibrary ("Advapi32.dll");
525 s_pfn_Get_File_Security
=
526 (GetFileSecurity_Proc
) GetProcAddress (
527 hm_advapi32
, GetFileSecurity_Name
);
529 if (s_pfn_Get_File_Security
== NULL
)
533 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
534 pSecurityDescriptor
, nLength
,
539 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
541 LPBOOL lpbOwnerDefaulted
)
543 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
544 HMODULE hm_advapi32
= NULL
;
545 if (is_windows_9x () == TRUE
)
549 if (g_b_init_get_security_descriptor_owner
== 0)
551 g_b_init_get_security_descriptor_owner
= 1;
552 hm_advapi32
= LoadLibrary ("Advapi32.dll");
553 s_pfn_Get_Security_Descriptor_Owner
=
554 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
555 hm_advapi32
, "GetSecurityDescriptorOwner");
557 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
561 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
566 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
568 LPBOOL lpbGroupDefaulted
)
570 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
571 HMODULE hm_advapi32
= NULL
;
572 if (is_windows_9x () == TRUE
)
576 if (g_b_init_get_security_descriptor_group
== 0)
578 g_b_init_get_security_descriptor_group
= 1;
579 hm_advapi32
= LoadLibrary ("Advapi32.dll");
580 s_pfn_Get_Security_Descriptor_Group
=
581 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
582 hm_advapi32
, "GetSecurityDescriptorGroup");
584 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
588 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
593 is_valid_sid (PSID sid
)
595 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
596 HMODULE hm_advapi32
= NULL
;
597 if (is_windows_9x () == TRUE
)
601 if (g_b_init_is_valid_sid
== 0)
603 g_b_init_is_valid_sid
= 1;
604 hm_advapi32
= LoadLibrary ("Advapi32.dll");
606 (IsValidSid_Proc
) GetProcAddress (
607 hm_advapi32
, "IsValidSid");
609 if (s_pfn_Is_Valid_Sid
== NULL
)
613 return (s_pfn_Is_Valid_Sid (sid
));
617 equal_sid (PSID sid1
, PSID sid2
)
619 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
620 HMODULE hm_advapi32
= NULL
;
621 if (is_windows_9x () == TRUE
)
625 if (g_b_init_equal_sid
== 0)
627 g_b_init_equal_sid
= 1;
628 hm_advapi32
= LoadLibrary ("Advapi32.dll");
630 (EqualSid_Proc
) GetProcAddress (
631 hm_advapi32
, "EqualSid");
633 if (s_pfn_Equal_Sid
== NULL
)
637 return (s_pfn_Equal_Sid (sid1
, sid2
));
641 get_length_sid (PSID sid
)
643 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
644 HMODULE hm_advapi32
= NULL
;
645 if (is_windows_9x () == TRUE
)
649 if (g_b_init_get_length_sid
== 0)
651 g_b_init_get_length_sid
= 1;
652 hm_advapi32
= LoadLibrary ("Advapi32.dll");
653 s_pfn_Get_Length_Sid
=
654 (GetLengthSid_Proc
) GetProcAddress (
655 hm_advapi32
, "GetLengthSid");
657 if (s_pfn_Get_Length_Sid
== NULL
)
661 return (s_pfn_Get_Length_Sid (sid
));
665 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
667 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
668 HMODULE hm_advapi32
= NULL
;
669 if (is_windows_9x () == TRUE
)
673 if (g_b_init_copy_sid
== 0)
675 g_b_init_copy_sid
= 1;
676 hm_advapi32
= LoadLibrary ("Advapi32.dll");
678 (CopySid_Proc
) GetProcAddress (
679 hm_advapi32
, "CopySid");
681 if (s_pfn_Copy_Sid
== NULL
)
685 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
689 END: Wrapper functions around OpenProcessToken
690 and other functions in advapi32.dll that are only
691 supported in Windows NT / 2k / XP
695 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
697 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
698 if (is_windows_9x () != TRUE
)
700 if (g_b_init_get_native_system_info
== 0)
702 g_b_init_get_native_system_info
= 1;
703 s_pfn_Get_Native_System_Info
=
704 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
705 "GetNativeSystemInfo");
707 if (s_pfn_Get_Native_System_Info
!= NULL
)
708 s_pfn_Get_Native_System_Info (lpSystemInfo
);
711 lpSystemInfo
->dwNumberOfProcessors
= -1;
715 get_system_times (LPFILETIME lpIdleTime
,
716 LPFILETIME lpKernelTime
,
717 LPFILETIME lpUserTime
)
719 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
720 if (is_windows_9x () == TRUE
)
724 if (g_b_init_get_system_times
== 0)
726 g_b_init_get_system_times
= 1;
727 s_pfn_Get_System_times
=
728 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
731 if (s_pfn_Get_System_times
== NULL
)
733 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
736 /* Equivalent of strerror for W32 error codes. */
738 w32_strerror (int error_no
)
740 static char buf
[500];
743 error_no
= GetLastError ();
746 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
748 0, /* choose most suitable language */
749 buf
, sizeof (buf
), NULL
))
750 sprintf (buf
, "w32 error %u", error_no
);
754 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
755 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
757 This is called from alloc.c:valid_pointer_p. */
759 w32_valid_pointer_p (void *p
, int size
)
762 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
766 unsigned char *buf
= alloca (size
);
767 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
776 static char startup_dir
[MAXPATHLEN
];
778 /* Get the current working directory. */
783 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
787 /* Emacs doesn't actually change directory itself, and we want to
788 force our real wd to be where emacs.exe is to avoid unnecessary
789 conflicts when trying to rename or delete directories. */
790 strcpy (dir
, startup_dir
);
795 /* Emulate getloadavg. */
804 /* Number of processors on this machine. */
805 static unsigned num_of_processors
;
807 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
808 static struct load_sample samples
[16*60];
809 static int first_idx
= -1, last_idx
= -1;
810 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
815 int next_idx
= from
+ 1;
817 if (next_idx
>= max_idx
)
826 int prev_idx
= from
- 1;
829 prev_idx
= max_idx
- 1;
835 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
838 FILETIME ft_idle
, ft_user
, ft_kernel
;
840 /* Initialize the number of processors on this machine. */
841 if (num_of_processors
<= 0)
843 get_native_system_info (&sysinfo
);
844 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
845 if (num_of_processors
<= 0)
847 GetSystemInfo (&sysinfo
);
848 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
850 if (num_of_processors
<= 0)
851 num_of_processors
= 1;
854 /* TODO: Take into account threads that are ready to run, by
855 sampling the "\System\Processor Queue Length" performance
856 counter. The code below accounts only for threads that are
859 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
861 ULARGE_INTEGER uidle
, ukernel
, uuser
;
863 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
864 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
865 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
866 *idle
= uidle
.QuadPart
;
867 *kernel
= ukernel
.QuadPart
;
868 *user
= uuser
.QuadPart
;
878 /* Produce the load average for a given time interval, using the
879 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
880 1-minute, 5-minute, or 15-minute average, respectively. */
884 double retval
= -1.0;
887 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
888 time_t now
= samples
[last_idx
].sample_time
;
890 if (first_idx
!= last_idx
)
892 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
894 tdiff
= difftime (now
, samples
[idx
].sample_time
);
895 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
898 samples
[last_idx
].kernel
+ samples
[last_idx
].user
899 - (samples
[idx
].kernel
+ samples
[idx
].user
);
900 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
902 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
905 if (idx
== first_idx
)
914 getloadavg (double loadavg
[], int nelem
)
917 ULONGLONG idle
, kernel
, user
;
918 time_t now
= time (NULL
);
920 /* Store another sample. We ignore samples that are less than 1 sec
922 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
924 sample_system_load (&idle
, &kernel
, &user
);
925 last_idx
= buf_next (last_idx
);
926 samples
[last_idx
].sample_time
= now
;
927 samples
[last_idx
].idle
= idle
;
928 samples
[last_idx
].kernel
= kernel
;
929 samples
[last_idx
].user
= user
;
930 /* If the buffer has more that 15 min worth of samples, discard
933 first_idx
= last_idx
;
934 while (first_idx
!= last_idx
935 && (difftime (now
, samples
[first_idx
].sample_time
)
936 >= 15.0*60 + 2*DBL_EPSILON
*now
))
937 first_idx
= buf_next (first_idx
);
940 for (elem
= 0; elem
< nelem
; elem
++)
942 double avg
= getavg (elem
);
952 /* Emulate getpwuid, getpwnam and others. */
954 #define PASSWD_FIELD_SIZE 256
956 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
957 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
958 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
959 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
960 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
962 static struct passwd dflt_passwd
=
974 static char dflt_group_name
[GNLEN
+1];
976 static struct group dflt_group
=
978 /* When group information is not available, we return this as the
979 group for all files. */
987 return dflt_passwd
.pw_uid
;
993 /* I could imagine arguing for checking to see whether the user is
994 in the Administrators group and returning a UID of 0 for that
995 case, but I don't know how wise that would be in the long run. */
1002 return dflt_passwd
.pw_gid
;
1012 getpwuid (unsigned uid
)
1014 if (uid
== dflt_passwd
.pw_uid
)
1015 return &dflt_passwd
;
1020 getgrgid (gid_t gid
)
1026 getpwnam (char *name
)
1030 pw
= getpwuid (getuid ());
1034 if (xstrcasecmp (name
, pw
->pw_name
))
1041 init_user_info (void)
1043 /* Find the user's real name by opening the process token and
1044 looking up the name associated with the user-sid in that token.
1046 Use the relative portion of the identifier authority value from
1047 the user-sid as the user id value (same for group id using the
1048 primary group sid from the process token). */
1050 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1051 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1052 DWORD glength
= sizeof (gname
);
1053 HANDLE token
= NULL
;
1054 SID_NAME_USE user_type
;
1055 unsigned char *buf
= NULL
;
1057 TOKEN_USER user_token
;
1058 TOKEN_PRIMARY_GROUP group_token
;
1061 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1064 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1065 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1067 buf
= xmalloc (blen
);
1068 result
= get_token_information (token
, TokenUser
,
1069 (LPVOID
)buf
, blen
, &needed
);
1072 memcpy (&user_token
, buf
, sizeof (user_token
));
1073 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1075 domain
, &dlength
, &user_type
);
1083 strcpy (dflt_passwd
.pw_name
, uname
);
1084 /* Determine a reasonable uid value. */
1085 if (xstrcasecmp ("administrator", uname
) == 0)
1087 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1088 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1092 /* Use the last sub-authority value of the RID, the relative
1093 portion of the SID, as user/group ID. */
1094 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1096 /* Get group id and name. */
1097 result
= get_token_information (token
, TokenPrimaryGroup
,
1098 (LPVOID
)buf
, blen
, &needed
);
1099 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1101 buf
= xrealloc (buf
, blen
= needed
);
1102 result
= get_token_information (token
, TokenPrimaryGroup
,
1103 (LPVOID
)buf
, blen
, &needed
);
1107 memcpy (&group_token
, buf
, sizeof (group_token
));
1108 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1109 dlength
= sizeof (domain
);
1110 /* If we can get at the real Primary Group name, use that.
1111 Otherwise, the default group name was already set to
1112 "None" in globals_of_w32. */
1113 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1114 gname
, &glength
, NULL
, &dlength
,
1116 strcpy (dflt_group_name
, gname
);
1119 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1122 /* If security calls are not supported (presumably because we
1123 are running under Windows 9X), fallback to this: */
1124 else if (GetUserName (uname
, &ulength
))
1126 strcpy (dflt_passwd
.pw_name
, uname
);
1127 if (xstrcasecmp ("administrator", uname
) == 0)
1128 dflt_passwd
.pw_uid
= 0;
1130 dflt_passwd
.pw_uid
= 123;
1131 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1135 strcpy (dflt_passwd
.pw_name
, "unknown");
1136 dflt_passwd
.pw_uid
= 123;
1137 dflt_passwd
.pw_gid
= 123;
1139 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1141 /* Ensure HOME and SHELL are defined. */
1142 if (getenv ("HOME") == NULL
)
1144 if (getenv ("SHELL") == NULL
)
1147 /* Set dir and shell from environment variables. */
1148 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1149 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1153 CloseHandle (token
);
1159 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1160 return ((rand () << 15) | rand ());
1170 /* Normalize filename by converting all path separators to
1171 the specified separator. Also conditionally convert upper
1172 case path name components to lower case. */
1175 normalize_filename (register char *fp
, char path_sep
)
1180 /* Always lower-case drive letters a-z, even if the filesystem
1181 preserves case in filenames.
1182 This is so filenames can be compared by string comparison
1183 functions that are case-sensitive. Even case-preserving filesystems
1184 do not distinguish case in drive letters. */
1185 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1191 if (NILP (Vw32_downcase_file_names
))
1195 if (*fp
== '/' || *fp
== '\\')
1202 sep
= path_sep
; /* convert to this path separator */
1203 elem
= fp
; /* start of current path element */
1206 if (*fp
>= 'a' && *fp
<= 'z')
1207 elem
= 0; /* don't convert this element */
1209 if (*fp
== 0 || *fp
== ':')
1211 sep
= *fp
; /* restore current separator (or 0) */
1212 *fp
= '/'; /* after conversion of this element */
1215 if (*fp
== '/' || *fp
== '\\')
1217 if (elem
&& elem
!= fp
)
1219 *fp
= 0; /* temporary end of string */
1220 _strlwr (elem
); /* while we convert to lower case */
1222 *fp
= sep
; /* convert (or restore) path separator */
1223 elem
= fp
+ 1; /* next element starts after separator */
1229 /* Destructively turn backslashes into slashes. */
1231 dostounix_filename (register char *p
)
1233 normalize_filename (p
, '/');
1236 /* Destructively turn slashes into backslashes. */
1238 unixtodos_filename (register char *p
)
1240 normalize_filename (p
, '\\');
1243 /* Remove all CR's that are followed by a LF.
1244 (From msdos.c...probably should figure out a way to share it,
1245 although this code isn't going to ever change.) */
1247 crlf_to_lf (register int n
, register unsigned char *buf
)
1249 unsigned char *np
= buf
;
1250 unsigned char *startp
= buf
;
1251 unsigned char *endp
= buf
+ n
;
1255 while (buf
< endp
- 1)
1259 if (*(++buf
) != 0x0a)
1270 /* Parse the root part of file name, if present. Return length and
1271 optionally store pointer to char after root. */
1273 parse_root (char * name
, char ** pPath
)
1275 char * start
= name
;
1280 /* find the root name of the volume if given */
1281 if (isalpha (name
[0]) && name
[1] == ':')
1283 /* skip past drive specifier */
1285 if (IS_DIRECTORY_SEP (name
[0]))
1288 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1294 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1299 if (IS_DIRECTORY_SEP (name
[0]))
1306 return name
- start
;
1309 /* Get long base name for name; name is assumed to be absolute. */
1311 get_long_basename (char * name
, char * buf
, int size
)
1313 WIN32_FIND_DATA find_data
;
1317 /* must be valid filename, no wild cards or other invalid characters */
1318 if (_mbspbrk (name
, "*?|<>\""))
1321 dir_handle
= FindFirstFile (name
, &find_data
);
1322 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1324 if ((len
= strlen (find_data
.cFileName
)) < size
)
1325 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1328 FindClose (dir_handle
);
1333 /* Get long name for file, if possible (assumed to be absolute). */
1335 w32_get_long_filename (char * name
, char * buf
, int size
)
1340 char full
[ MAX_PATH
];
1343 len
= strlen (name
);
1344 if (len
>= MAX_PATH
)
1347 /* Use local copy for destructive modification. */
1348 memcpy (full
, name
, len
+1);
1349 unixtodos_filename (full
);
1351 /* Copy root part verbatim. */
1352 len
= parse_root (full
, &p
);
1353 memcpy (o
, full
, len
);
1358 while (p
!= NULL
&& *p
)
1361 p
= strchr (q
, '\\');
1363 len
= get_long_basename (full
, o
, size
);
1386 is_unc_volume (const char *filename
)
1388 const char *ptr
= filename
;
1390 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1393 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1399 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1402 sigsetmask (int signal_mask
)
1420 sigunblock (int sig
)
1426 sigemptyset (sigset_t
*set
)
1432 sigaddset (sigset_t
*set
, int signo
)
1438 sigfillset (sigset_t
*set
)
1444 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1450 setpgrp (int pid
, int gid
)
1461 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1464 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1467 HKEY hrootkey
= NULL
;
1470 /* Check both the current user and the local machine to see if
1471 we have any resources. */
1473 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1477 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1478 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1479 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1481 RegCloseKey (hrootkey
);
1487 RegCloseKey (hrootkey
);
1490 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1494 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1495 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1496 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1498 RegCloseKey (hrootkey
);
1504 RegCloseKey (hrootkey
);
1510 char *get_emacs_configuration (void);
1512 init_environment (char ** argv
)
1514 static const char * const tempdirs
[] = {
1515 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1520 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1522 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1523 temporary files and assume "/tmp" if $TMPDIR is unset, which
1524 will break on DOS/Windows. Refuse to work if we cannot find
1525 a directory, not even "c:/", usable for that purpose. */
1526 for (i
= 0; i
< imax
; i
++)
1528 const char *tmp
= tempdirs
[i
];
1531 tmp
= getenv (tmp
+ 1);
1532 /* Note that `access' can lie to us if the directory resides on a
1533 read-only filesystem, like CD-ROM or a write-protected floppy.
1534 The only way to be really sure is to actually create a file and
1535 see if it succeeds. But I think that's too much to ask. */
1536 if (tmp
&& _access (tmp
, D_OK
) == 0)
1538 char * var
= alloca (strlen (tmp
) + 8);
1539 sprintf (var
, "TMPDIR=%s", tmp
);
1540 _putenv (strdup (var
));
1547 Fcons (build_string ("no usable temporary directories found!!"),
1549 "While setting TMPDIR: ");
1551 /* Check for environment variables and use registry settings if they
1552 don't exist. Fallback on default values where applicable. */
1557 char locale_name
[32];
1558 struct stat ignored
;
1559 char default_home
[MAX_PATH
];
1561 static const struct env_entry
1568 {"PRELOAD_WINSOCK", NULL
},
1569 {"emacs_dir", "C:/emacs"},
1570 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1571 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1572 {"EMACSDATA", "%emacs_dir%/etc"},
1573 {"EMACSPATH", "%emacs_dir%/bin"},
1574 /* We no longer set INFOPATH because Info-default-directory-list
1576 /* {"INFOPATH", "%emacs_dir%/info"}, */
1577 {"EMACSDOC", "%emacs_dir%/etc"},
1582 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1584 /* We need to copy dflt_envvars[] and work on the copy because we
1585 don't want the dumped Emacs to inherit the values of
1586 environment variables we saw during dumping (which could be on
1587 a different system). The defaults above must be left intact. */
1588 struct env_entry env_vars
[N_ENV_VARS
];
1590 for (i
= 0; i
< N_ENV_VARS
; i
++)
1591 env_vars
[i
] = dflt_envvars
[i
];
1593 /* For backwards compatibility, check if a .emacs file exists in C:/
1594 If not, then we can try to default to the appdata directory under the
1595 user's profile, which is more likely to be writable. */
1596 if (stat ("C:/.emacs", &ignored
) < 0)
1598 HRESULT profile_result
;
1599 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1600 of Windows 95 and NT4 that have not been updated to include
1602 ShGetFolderPath_fn get_folder_path
;
1603 get_folder_path
= (ShGetFolderPath_fn
)
1604 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1606 if (get_folder_path
!= NULL
)
1608 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1611 /* If we can't get the appdata dir, revert to old behavior. */
1612 if (profile_result
== S_OK
)
1613 env_vars
[0].def_value
= default_home
;
1617 /* Get default locale info and use it for LANG. */
1618 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1619 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1620 locale_name
, sizeof (locale_name
)))
1622 for (i
= 0; i
< N_ENV_VARS
; i
++)
1624 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1626 env_vars
[i
].def_value
= locale_name
;
1632 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1634 /* Treat emacs_dir specially: set it unconditionally based on our
1635 location, if it appears that we are running from the bin subdir
1636 of a standard installation. */
1639 char modname
[MAX_PATH
];
1641 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1643 if ((p
= strrchr (modname
, '\\')) == NULL
)
1647 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1649 char buf
[SET_ENV_BUF_SIZE
];
1652 for (p
= modname
; *p
; p
++)
1653 if (*p
== '\\') *p
= '/';
1655 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1656 _putenv (strdup (buf
));
1658 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1660 /* FIXME: should use substring of get_emacs_configuration ().
1661 But I don't think the Windows build supports alpha, mips etc
1662 anymore, so have taken the easy option for now. */
1663 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1666 p
= strrchr (modname
, '\\');
1670 p
= strrchr (modname
, '\\');
1671 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1673 char buf
[SET_ENV_BUF_SIZE
];
1676 for (p
= modname
; *p
; p
++)
1677 if (*p
== '\\') *p
= '/';
1679 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1680 _putenv (strdup (buf
));
1686 for (i
= 0; i
< N_ENV_VARS
; i
++)
1688 if (!getenv (env_vars
[i
].name
))
1692 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1693 /* Also ignore empty environment variables. */
1697 lpval
= env_vars
[i
].def_value
;
1698 dwType
= REG_EXPAND_SZ
;
1704 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1706 if (dwType
== REG_EXPAND_SZ
)
1707 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1708 else if (dwType
== REG_SZ
)
1709 strcpy (buf1
, lpval
);
1710 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1712 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1714 _putenv (strdup (buf2
));
1724 /* Rebuild system configuration to reflect invoking system. */
1725 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1727 /* Another special case: on NT, the PATH variable is actually named
1728 "Path" although cmd.exe (perhaps NT itself) arranges for
1729 environment variable lookup and setting to be case insensitive.
1730 However, Emacs assumes a fully case sensitive environment, so we
1731 need to change "Path" to "PATH" to match the expectations of
1732 various elisp packages. We do this by the sneaky method of
1733 modifying the string in the C runtime environ entry.
1735 The same applies to COMSPEC. */
1739 for (envp
= environ
; *envp
; envp
++)
1740 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1741 memcpy (*envp
, "PATH=", 5);
1742 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1743 memcpy (*envp
, "COMSPEC=", 8);
1746 /* Remember the initial working directory for getwd, then make the
1747 real wd be the location of emacs.exe to avoid conflicts when
1748 renaming or deleting directories. (We also don't call chdir when
1749 running subprocesses for the same reason.) */
1750 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1755 static char modname
[MAX_PATH
];
1757 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1759 if ((p
= strrchr (modname
, '\\')) == NULL
)
1763 SetCurrentDirectory (modname
);
1765 /* Ensure argv[0] has the full path to Emacs. */
1770 /* Determine if there is a middle mouse button, to allow parse_button
1771 to decide whether right mouse events should be mouse-2 or
1773 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1779 emacs_root_dir (void)
1781 static char root_dir
[FILENAME_MAX
];
1784 p
= getenv ("emacs_dir");
1787 strcpy (root_dir
, p
);
1788 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1789 dostounix_filename (root_dir
);
1793 /* We don't have scripts to automatically determine the system configuration
1794 for Emacs before it's compiled, and we don't want to have to make the
1795 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1799 get_emacs_configuration (void)
1801 char *arch
, *oem
, *os
;
1803 static char configuration_buffer
[32];
1805 /* Determine the processor type. */
1806 switch (get_processor_type ())
1809 #ifdef PROCESSOR_INTEL_386
1810 case PROCESSOR_INTEL_386
:
1811 case PROCESSOR_INTEL_486
:
1812 case PROCESSOR_INTEL_PENTIUM
:
1817 #ifdef PROCESSOR_MIPS_R2000
1818 case PROCESSOR_MIPS_R2000
:
1819 case PROCESSOR_MIPS_R3000
:
1820 case PROCESSOR_MIPS_R4000
:
1825 #ifdef PROCESSOR_ALPHA_21064
1826 case PROCESSOR_ALPHA_21064
:
1836 /* Use the OEM field to reflect the compiler/library combination. */
1838 #define COMPILER_NAME "msvc"
1841 #define COMPILER_NAME "mingw"
1843 #define COMPILER_NAME "unknown"
1846 oem
= COMPILER_NAME
;
1848 switch (osinfo_cache
.dwPlatformId
) {
1849 case VER_PLATFORM_WIN32_NT
:
1851 build_num
= osinfo_cache
.dwBuildNumber
;
1853 case VER_PLATFORM_WIN32_WINDOWS
:
1854 if (osinfo_cache
.dwMinorVersion
== 0) {
1859 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1861 case VER_PLATFORM_WIN32s
:
1862 /* Not supported, should not happen. */
1864 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1872 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1873 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1874 get_w32_major_version (), get_w32_minor_version (), build_num
);
1876 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1879 return configuration_buffer
;
1883 get_emacs_configuration_options (void)
1885 static char *options_buffer
;
1886 char cv
[32]; /* Enough for COMPILER_VERSION. */
1888 cv
, /* To be filled later. */
1892 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1893 with a starting space to save work here. */
1895 " --cflags", USER_CFLAGS
,
1898 " --ldflags", USER_LDFLAGS
,
1905 /* Work out the effective configure options for this build. */
1907 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1910 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1912 #define COMPILER_VERSION ""
1916 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
1917 return "Error: not enough space for compiler version";
1918 cv
[sizeof (cv
) - 1] = '\0';
1920 for (i
= 0; options
[i
]; i
++)
1921 size
+= strlen (options
[i
]);
1923 options_buffer
= xmalloc (size
+ 1);
1924 options_buffer
[0] = '\0';
1926 for (i
= 0; options
[i
]; i
++)
1927 strcat (options_buffer
, options
[i
]);
1929 return options_buffer
;
1933 #include <sys/timeb.h>
1935 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1937 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1942 tv
->tv_sec
= tb
.time
;
1943 tv
->tv_usec
= tb
.millitm
* 1000L;
1946 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1947 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1951 /* ------------------------------------------------------------------------- */
1952 /* IO support and wrapper functions for W32 API. */
1953 /* ------------------------------------------------------------------------- */
1955 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1956 on network directories, so we handle that case here.
1957 (Ulrich Leodolter, 1/11/95). */
1959 sys_ctime (const time_t *t
)
1961 char *str
= (char *) ctime (t
);
1962 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1965 /* Emulate sleep...we could have done this with a define, but that
1966 would necessitate including windows.h in the files that used it.
1967 This is much easier. */
1969 sys_sleep (int seconds
)
1971 Sleep (seconds
* 1000);
1974 /* Internal MSVC functions for low-level descriptor munging */
1975 extern int __cdecl
_set_osfhnd (int fd
, long h
);
1976 extern int __cdecl
_free_osfhnd (int fd
);
1978 /* parallel array of private info on file handles */
1979 filedesc fd_info
[ MAXDESC
];
1981 typedef struct volume_info_data
{
1982 struct volume_info_data
* next
;
1984 /* time when info was obtained */
1987 /* actual volume info */
1996 /* Global referenced by various functions. */
1997 static volume_info_data volume_info
;
1999 /* Vector to indicate which drives are local and fixed (for which cached
2000 data never expires). */
2001 static BOOL fixed_drives
[26];
2003 /* Consider cached volume information to be stale if older than 10s,
2004 at least for non-local drives. Info for fixed drives is never stale. */
2005 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2006 #define VOLINFO_STILL_VALID( root_dir, info ) \
2007 ( ( isalpha (root_dir[0]) && \
2008 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2009 || GetTickCount () - info->timestamp < 10000 )
2011 /* Cache support functions. */
2013 /* Simple linked list with linear search is sufficient. */
2014 static volume_info_data
*volume_cache
= NULL
;
2016 static volume_info_data
*
2017 lookup_volume_info (char * root_dir
)
2019 volume_info_data
* info
;
2021 for (info
= volume_cache
; info
; info
= info
->next
)
2022 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2028 add_volume_info (char * root_dir
, volume_info_data
* info
)
2030 info
->root_dir
= xstrdup (root_dir
);
2031 info
->next
= volume_cache
;
2032 volume_cache
= info
;
2036 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2037 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2038 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2039 static volume_info_data
*
2040 GetCachedVolumeInformation (char * root_dir
)
2042 volume_info_data
* info
;
2043 char default_root
[ MAX_PATH
];
2045 /* NULL for root_dir means use root from current directory. */
2046 if (root_dir
== NULL
)
2048 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2050 parse_root (default_root
, &root_dir
);
2052 root_dir
= default_root
;
2055 /* Local fixed drives can be cached permanently. Removable drives
2056 cannot be cached permanently, since the volume name and serial
2057 number (if nothing else) can change. Remote drives should be
2058 treated as if they are removable, since there is no sure way to
2059 tell whether they are or not. Also, the UNC association of drive
2060 letters mapped to remote volumes can be changed at any time (even
2061 by other processes) without notice.
2063 As a compromise, so we can benefit from caching info for remote
2064 volumes, we use a simple expiry mechanism to invalidate cache
2065 entries that are more than ten seconds old. */
2068 /* No point doing this, because WNetGetConnection is even slower than
2069 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2070 GetDriveType is about the only call of this type which does not
2071 involve network access, and so is extremely quick). */
2073 /* Map drive letter to UNC if remote. */
2074 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2076 char remote_name
[ 256 ];
2077 char drive
[3] = { root_dir
[0], ':' };
2079 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2081 /* do something */ ;
2085 info
= lookup_volume_info (root_dir
);
2087 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2095 /* Info is not cached, or is stale. */
2096 if (!GetVolumeInformation (root_dir
,
2097 name
, sizeof (name
),
2101 type
, sizeof (type
)))
2104 /* Cache the volume information for future use, overwriting existing
2105 entry if present. */
2108 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2109 add_volume_info (root_dir
, info
);
2117 info
->name
= xstrdup (name
);
2118 info
->serialnum
= serialnum
;
2119 info
->maxcomp
= maxcomp
;
2120 info
->flags
= flags
;
2121 info
->type
= xstrdup (type
);
2122 info
->timestamp
= GetTickCount ();
2128 /* Get information on the volume where name is held; set path pointer to
2129 start of pathname in name (past UNC header\volume header if present). */
2131 get_volume_info (const char * name
, const char ** pPath
)
2133 char temp
[MAX_PATH
];
2134 char *rootname
= NULL
; /* default to current volume */
2135 volume_info_data
* info
;
2140 /* find the root name of the volume if given */
2141 if (isalpha (name
[0]) && name
[1] == ':')
2149 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2156 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2169 info
= GetCachedVolumeInformation (rootname
);
2172 /* Set global referenced by other functions. */
2173 volume_info
= *info
;
2179 /* Determine if volume is FAT format (ie. only supports short 8.3
2180 names); also set path pointer to start of pathname in name. */
2182 is_fat_volume (const char * name
, const char ** pPath
)
2184 if (get_volume_info (name
, pPath
))
2185 return (volume_info
.maxcomp
== 12);
2189 /* Map filename to a valid 8.3 name if necessary. */
2191 map_w32_filename (const char * name
, const char ** pPath
)
2193 static char shortname
[MAX_PATH
];
2194 char * str
= shortname
;
2197 const char * save_name
= name
;
2199 if (strlen (name
) >= MAX_PATH
)
2201 /* Return a filename which will cause callers to fail. */
2202 strcpy (shortname
, "?");
2206 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2208 register int left
= 8; /* maximum number of chars in part */
2209 register int extn
= 0; /* extension added? */
2210 register int dots
= 2; /* maximum number of dots allowed */
2213 *str
++ = *name
++; /* skip past UNC header */
2215 while ((c
= *name
++))
2222 extn
= 0; /* reset extension flags */
2223 dots
= 2; /* max 2 dots */
2224 left
= 8; /* max length 8 for main part */
2228 extn
= 0; /* reset extension flags */
2229 dots
= 2; /* max 2 dots */
2230 left
= 8; /* max length 8 for main part */
2235 /* Convert path components of the form .xxx to _xxx,
2236 but leave . and .. as they are. This allows .emacs
2237 to be read as _emacs, for example. */
2241 IS_DIRECTORY_SEP (*name
))
2256 extn
= 1; /* we've got an extension */
2257 left
= 3; /* 3 chars in extension */
2261 /* any embedded dots after the first are converted to _ */
2266 case '#': /* don't lose these, they're important */
2268 str
[-1] = c
; /* replace last character of part */
2273 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2275 dots
= 0; /* started a path component */
2284 strcpy (shortname
, name
);
2285 unixtodos_filename (shortname
);
2289 *pPath
= shortname
+ (path
- save_name
);
2295 is_exec (const char * name
)
2297 char * p
= strrchr (name
, '.');
2300 && (xstrcasecmp (p
, ".exe") == 0 ||
2301 xstrcasecmp (p
, ".com") == 0 ||
2302 xstrcasecmp (p
, ".bat") == 0 ||
2303 xstrcasecmp (p
, ".cmd") == 0));
2306 /* Emulate the Unix directory procedures opendir, closedir,
2307 and readdir. We can't use the procedures supplied in sysdep.c,
2308 so we provide them here. */
2310 struct direct dir_static
; /* simulated directory contents */
2311 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2312 static int dir_is_fat
;
2313 static char dir_pathname
[MAXPATHLEN
+1];
2314 static WIN32_FIND_DATA dir_find_data
;
2316 /* Support shares on a network resource as subdirectories of a read-only
2318 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2319 static HANDLE
open_unc_volume (const char *);
2320 static char *read_unc_volume (HANDLE
, char *, int);
2321 static void close_unc_volume (HANDLE
);
2324 opendir (char *filename
)
2328 /* Opening is done by FindFirstFile. However, a read is inherent to
2329 this operation, so we defer the open until read time. */
2331 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2333 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2336 if (is_unc_volume (filename
))
2338 wnet_enum_handle
= open_unc_volume (filename
);
2339 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2343 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2350 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2351 dir_pathname
[MAXPATHLEN
] = '\0';
2352 dir_is_fat
= is_fat_volume (filename
, NULL
);
2358 closedir (DIR *dirp
)
2360 /* If we have a find-handle open, close it. */
2361 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2363 FindClose (dir_find_handle
);
2364 dir_find_handle
= INVALID_HANDLE_VALUE
;
2366 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2368 close_unc_volume (wnet_enum_handle
);
2369 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2371 xfree ((char *) dirp
);
2377 int downcase
= !NILP (Vw32_downcase_file_names
);
2379 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2381 if (!read_unc_volume (wnet_enum_handle
,
2382 dir_find_data
.cFileName
,
2386 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2387 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2389 char filename
[MAXNAMLEN
+ 3];
2392 strcpy (filename
, dir_pathname
);
2393 ln
= strlen (filename
) - 1;
2394 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2395 strcat (filename
, "\\");
2396 strcat (filename
, "*");
2398 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2400 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2405 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2409 /* Emacs never uses this value, so don't bother making it match
2410 value returned by stat(). */
2411 dir_static
.d_ino
= 1;
2413 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2415 /* If the file name in cFileName[] includes `?' characters, it means
2416 the original file name used characters that cannot be represented
2417 by the current ANSI codepage. To avoid total lossage, retrieve
2418 the short 8+3 alias of the long file name. */
2419 if (_mbspbrk (dir_static
.d_name
, "?"))
2421 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2422 downcase
= 1; /* 8+3 aliases are returned in all caps */
2424 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2425 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2426 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2428 /* If the file name in cFileName[] includes `?' characters, it means
2429 the original file name used characters that cannot be represented
2430 by the current ANSI codepage. To avoid total lossage, retrieve
2431 the short 8+3 alias of the long file name. */
2432 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2434 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2435 /* 8+3 aliases are returned in all caps, which could break
2436 various alists that look at filenames' extensions. */
2440 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2441 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2443 _strlwr (dir_static
.d_name
);
2447 for (p
= dir_static
.d_name
; *p
; p
++)
2448 if (*p
>= 'a' && *p
<= 'z')
2451 _strlwr (dir_static
.d_name
);
2458 open_unc_volume (const char *path
)
2464 nr
.dwScope
= RESOURCE_GLOBALNET
;
2465 nr
.dwType
= RESOURCETYPE_DISK
;
2466 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2467 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2468 nr
.lpLocalName
= NULL
;
2469 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2470 nr
.lpComment
= NULL
;
2471 nr
.lpProvider
= NULL
;
2473 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2474 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2476 if (result
== NO_ERROR
)
2479 return INVALID_HANDLE_VALUE
;
2483 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2487 DWORD bufsize
= 512;
2492 buffer
= alloca (bufsize
);
2493 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2494 if (result
!= NO_ERROR
)
2497 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2498 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2500 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2503 strncpy (readbuf
, ptr
, size
);
2508 close_unc_volume (HANDLE henum
)
2510 if (henum
!= INVALID_HANDLE_VALUE
)
2511 WNetCloseEnum (henum
);
2515 unc_volume_file_attributes (const char *path
)
2520 henum
= open_unc_volume (path
);
2521 if (henum
== INVALID_HANDLE_VALUE
)
2524 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2526 close_unc_volume (henum
);
2531 /* Ensure a network connection is authenticated. */
2533 logon_network_drive (const char *path
)
2535 NETRESOURCE resource
;
2536 char share
[MAX_PATH
];
2541 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2542 drvtype
= DRIVE_REMOTE
;
2543 else if (path
[0] == '\0' || path
[1] != ':')
2544 drvtype
= GetDriveType (NULL
);
2551 drvtype
= GetDriveType (drive
);
2554 /* Only logon to networked drives. */
2555 if (drvtype
!= DRIVE_REMOTE
)
2559 strncpy (share
, path
, MAX_PATH
);
2560 /* Truncate to just server and share name. */
2561 for (i
= 2; i
< MAX_PATH
; i
++)
2563 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2570 resource
.dwType
= RESOURCETYPE_DISK
;
2571 resource
.lpLocalName
= NULL
;
2572 resource
.lpRemoteName
= share
;
2573 resource
.lpProvider
= NULL
;
2575 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2578 /* Shadow some MSVC runtime functions to map requests for long filenames
2579 to reasonable short names if necessary. This was originally added to
2580 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2584 sys_access (const char * path
, int mode
)
2588 /* MSVC implementation doesn't recognize D_OK. */
2589 path
= map_w32_filename (path
, NULL
);
2590 if (is_unc_volume (path
))
2592 attributes
= unc_volume_file_attributes (path
);
2593 if (attributes
== -1) {
2598 else if ((attributes
= GetFileAttributes (path
)) == -1)
2600 /* Should try mapping GetLastError to errno; for now just indicate
2601 that path doesn't exist. */
2605 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2610 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2615 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2624 sys_chdir (const char * path
)
2626 return _chdir (map_w32_filename (path
, NULL
));
2630 sys_chmod (const char * path
, int mode
)
2632 return _chmod (map_w32_filename (path
, NULL
), mode
);
2636 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2638 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2644 sys_creat (const char * path
, int mode
)
2646 return _creat (map_w32_filename (path
, NULL
), mode
);
2650 sys_fopen (const char * path
, const char * mode
)
2654 const char * mode_save
= mode
;
2656 /* Force all file handles to be non-inheritable. This is necessary to
2657 ensure child processes don't unwittingly inherit handles that might
2658 prevent future file access. */
2662 else if (mode
[0] == 'w' || mode
[0] == 'a')
2663 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2667 /* Only do simplistic option parsing. */
2671 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2674 else if (mode
[0] == 'b')
2679 else if (mode
[0] == 't')
2686 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2690 return _fdopen (fd
, mode_save
);
2693 /* This only works on NTFS volumes, but is useful to have. */
2695 sys_link (const char * old
, const char * new)
2699 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2701 if (old
== NULL
|| new == NULL
)
2707 strcpy (oldname
, map_w32_filename (old
, NULL
));
2708 strcpy (newname
, map_w32_filename (new, NULL
));
2710 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2711 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2712 if (fileh
!= INVALID_HANDLE_VALUE
)
2716 /* Confusingly, the "alternate" stream name field does not apply
2717 when restoring a hard link, and instead contains the actual
2718 stream data for the link (ie. the name of the link to create).
2719 The WIN32_STREAM_ID structure before the cStreamName field is
2720 the stream header, which is then immediately followed by the
2724 WIN32_STREAM_ID wid
;
2725 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2728 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2729 data
.wid
.cStreamName
, MAX_PATH
);
2732 LPVOID context
= NULL
;
2735 data
.wid
.dwStreamId
= BACKUP_LINK
;
2736 data
.wid
.dwStreamAttributes
= 0;
2737 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2738 data
.wid
.Size
.HighPart
= 0;
2739 data
.wid
.dwStreamNameSize
= 0;
2741 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2742 offsetof (WIN32_STREAM_ID
, cStreamName
)
2743 + data
.wid
.Size
.LowPart
,
2744 &wbytes
, FALSE
, FALSE
, &context
)
2745 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2752 /* Should try mapping GetLastError to errno; for now just
2753 indicate a general error (eg. links not supported). */
2754 errno
= EINVAL
; // perhaps EMLINK?
2758 CloseHandle (fileh
);
2767 sys_mkdir (const char * path
)
2769 return _mkdir (map_w32_filename (path
, NULL
));
2772 /* Because of long name mapping issues, we need to implement this
2773 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2774 a unique name, instead of setting the input template to an empty
2777 Standard algorithm seems to be use pid or tid with a letter on the
2778 front (in place of the 6 X's) and cycle through the letters to find a
2779 unique name. We extend that to allow any reasonable character as the
2780 first of the 6 X's. */
2782 sys_mktemp (char * template)
2786 unsigned uid
= GetCurrentThreadId ();
2787 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2789 if (template == NULL
)
2791 p
= template + strlen (template);
2793 /* replace up to the last 5 X's with uid in decimal */
2794 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2796 p
[0] = '0' + uid
% 10;
2800 if (i
< 0 && p
[0] == 'X')
2805 int save_errno
= errno
;
2806 p
[0] = first_char
[i
];
2807 if (sys_access (template, 0) < 0)
2813 while (++i
< sizeof (first_char
));
2816 /* Template is badly formed or else we can't generate a unique name,
2817 so return empty string */
2823 sys_open (const char * path
, int oflag
, int mode
)
2825 const char* mpath
= map_w32_filename (path
, NULL
);
2826 /* Try to open file without _O_CREAT, to be able to write to hidden
2827 and system files. Force all file handles to be
2829 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2832 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2836 sys_rename (const char * oldname
, const char * newname
)
2839 char temp
[MAX_PATH
];
2841 /* MoveFile on Windows 95 doesn't correctly change the short file name
2842 alias in a number of circumstances (it is not easy to predict when
2843 just by looking at oldname and newname, unfortunately). In these
2844 cases, renaming through a temporary name avoids the problem.
2846 A second problem on Windows 95 is that renaming through a temp name when
2847 newname is uppercase fails (the final long name ends up in
2848 lowercase, although the short alias might be uppercase) UNLESS the
2849 long temp name is not 8.3.
2851 So, on Windows 95 we always rename through a temp name, and we make sure
2852 the temp name has a long extension to ensure correct renaming. */
2854 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2856 if (os_subtype
== OS_WIN95
)
2862 oldname
= map_w32_filename (oldname
, NULL
);
2863 if (o
= strrchr (oldname
, '\\'))
2866 o
= (char *) oldname
;
2868 if (p
= strrchr (temp
, '\\'))
2875 /* Force temp name to require a manufactured 8.3 alias - this
2876 seems to make the second rename work properly. */
2877 sprintf (p
, "_.%s.%u", o
, i
);
2879 result
= rename (oldname
, temp
);
2881 /* This loop must surely terminate! */
2882 while (result
< 0 && errno
== EEXIST
);
2887 /* Emulate Unix behavior - newname is deleted if it already exists
2888 (at least if it is a file; don't do this for directories).
2890 Since we mustn't do this if we are just changing the case of the
2891 file name (we would end up deleting the file we are trying to
2892 rename!), we let rename detect if the destination file already
2893 exists - that way we avoid the possible pitfalls of trying to
2894 determine ourselves whether two names really refer to the same
2895 file, which is not always possible in the general case. (Consider
2896 all the permutations of shared or subst'd drives, etc.) */
2898 newname
= map_w32_filename (newname
, NULL
);
2899 result
= rename (temp
, newname
);
2903 && _chmod (newname
, 0666) == 0
2904 && _unlink (newname
) == 0)
2905 result
= rename (temp
, newname
);
2911 sys_rmdir (const char * path
)
2913 return _rmdir (map_w32_filename (path
, NULL
));
2917 sys_unlink (const char * path
)
2919 path
= map_w32_filename (path
, NULL
);
2921 /* On Unix, unlink works without write permission. */
2922 _chmod (path
, 0666);
2923 return _unlink (path
);
2926 static FILETIME utc_base_ft
;
2927 static ULONGLONG utc_base
; /* In 100ns units */
2928 static int init
= 0;
2930 #define FILETIME_TO_U64(result, ft) \
2932 ULARGE_INTEGER uiTemp; \
2933 uiTemp.LowPart = (ft).dwLowDateTime; \
2934 uiTemp.HighPart = (ft).dwHighDateTime; \
2935 result = uiTemp.QuadPart; \
2939 initialize_utc_base (void)
2941 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2950 st
.wMilliseconds
= 0;
2952 SystemTimeToFileTime (&st
, &utc_base_ft
);
2953 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2957 convert_time (FILETIME ft
)
2963 initialize_utc_base ();
2967 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2970 FILETIME_TO_U64 (tmp
, ft
);
2971 return (time_t) ((tmp
- utc_base
) / 10000000L);
2975 convert_from_time_t (time_t time
, FILETIME
* pft
)
2981 initialize_utc_base ();
2985 /* time in 100ns units since 1-Jan-1601 */
2986 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
2987 pft
->dwHighDateTime
= tmp
.HighPart
;
2988 pft
->dwLowDateTime
= tmp
.LowPart
;
2992 /* No reason to keep this; faking inode values either by hashing or even
2993 using the file index from GetInformationByHandle, is not perfect and
2994 so by default Emacs doesn't use the inode values on Windows.
2995 Instead, we now determine file-truename correctly (except for
2996 possible drive aliasing etc). */
2998 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3000 hashval (const unsigned char * str
)
3005 h
= (h
<< 4) + *str
++;
3011 /* Return the hash value of the canonical pathname, excluding the
3012 drive/UNC header, to get a hopefully unique inode number. */
3014 generate_inode_val (const char * name
)
3016 char fullname
[ MAX_PATH
];
3020 /* Get the truly canonical filename, if it exists. (Note: this
3021 doesn't resolve aliasing due to subst commands, or recognise hard
3023 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3026 parse_root (fullname
, &p
);
3027 /* Normal W32 filesystems are still case insensitive. */
3034 static PSECURITY_DESCRIPTOR
3035 get_file_security_desc (const char *fname
)
3037 PSECURITY_DESCRIPTOR psd
= NULL
;
3039 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3040 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3042 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3044 err
= GetLastError ();
3045 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3049 psd
= xmalloc (sd_len
);
3050 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3062 unsigned n_subauthorities
;
3064 /* Use the last sub-authority value of the RID, the relative
3065 portion of the SID, as user/group ID. */
3066 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3067 if (n_subauthorities
< 1)
3068 return 0; /* the "World" RID */
3069 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3072 /* Caching SID and account values for faster lokup. */
3075 # define FLEXIBLE_ARRAY_MEMBER
3077 # define FLEXIBLE_ARRAY_MEMBER 1
3082 struct w32_id
*next
;
3084 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3087 static struct w32_id
*w32_idlist
;
3090 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3092 struct w32_id
*tail
, *found
;
3094 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3096 if (equal_sid ((PSID
)tail
->sid
, sid
))
3105 strcpy (name
, found
->name
);
3113 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3116 struct w32_id
*new_entry
;
3118 /* We don't want to leave behind stale cache from when Emacs was
3122 sid_len
= get_length_sid (sid
);
3123 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3126 new_entry
->rid
= id
;
3127 strcpy (new_entry
->name
, name
);
3128 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3129 new_entry
->next
= w32_idlist
;
3130 w32_idlist
= new_entry
;
3139 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3140 unsigned *id
, char *nm
, int what
)
3143 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3145 SID_NAME_USE ignore
;
3147 DWORD name_len
= sizeof (name
);
3149 DWORD domain_len
= sizeof (domain
);
3155 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3156 else if (what
== GID
)
3157 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3161 if (!result
|| !is_valid_sid (sid
))
3163 else if (!w32_cached_id (sid
, id
, nm
))
3165 /* If FNAME is a UNC, we need to lookup account on the
3166 specified machine. */
3167 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3168 && fname
[2] != '\0')
3173 for (s
= fname
+ 2, p
= machine
;
3174 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3180 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3181 domain
, &domain_len
, &ignore
)
3182 || name_len
> UNLEN
+1)
3186 *id
= get_rid (sid
);
3188 w32_add_to_cache (sid
, *id
, name
);
3195 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3199 int dflt_usr
= 0, dflt_grp
= 0;
3208 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3210 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3213 /* Consider files to belong to current user/group, if we cannot get
3214 more accurate information. */
3217 st
->st_uid
= dflt_passwd
.pw_uid
;
3218 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3222 st
->st_gid
= dflt_passwd
.pw_gid
;
3223 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3227 /* Return non-zero if NAME is a potentially slow filesystem. */
3229 is_slow_fs (const char *name
)
3234 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3235 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3236 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3237 devtype
= GetDriveType (NULL
); /* use root of current drive */
3240 /* GetDriveType needs the root directory of the drive. */
3241 strncpy (drive_root
, name
, 2);
3242 drive_root
[2] = '\\';
3243 drive_root
[3] = '\0';
3244 devtype
= GetDriveType (drive_root
);
3246 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3249 /* MSVC stat function can't cope with UNC names and has other bugs, so
3250 replace it with our own. This also allows us to calculate consistent
3251 inode values without hacks in the main Emacs code. */
3253 stat (const char * path
, struct stat
* buf
)
3258 WIN32_FIND_DATA wfd
;
3260 unsigned __int64 fake_inode
;
3263 int rootdir
= FALSE
;
3264 PSECURITY_DESCRIPTOR psd
= NULL
;
3266 if (path
== NULL
|| buf
== NULL
)
3272 name
= (char *) map_w32_filename (path
, &path
);
3273 /* Must be valid filename, no wild cards or other invalid
3274 characters. We use _mbspbrk to support multibyte strings that
3275 might look to strpbrk as if they included literal *, ?, and other
3276 characters mentioned below that are disallowed by Windows
3278 if (_mbspbrk (name
, "*?|<>\""))
3284 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3285 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3286 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3291 /* Remove trailing directory separator, unless name is the root
3292 directory of a drive or UNC volume in which case ensure there
3293 is a trailing separator. */
3294 len
= strlen (name
);
3295 rootdir
= (path
>= name
+ len
- 1
3296 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3297 name
= strcpy (alloca (len
+ 2), name
);
3299 if (is_unc_volume (name
))
3301 DWORD attrs
= unc_volume_file_attributes (name
);
3306 memset (&wfd
, 0, sizeof (wfd
));
3307 wfd
.dwFileAttributes
= attrs
;
3308 wfd
.ftCreationTime
= utc_base_ft
;
3309 wfd
.ftLastAccessTime
= utc_base_ft
;
3310 wfd
.ftLastWriteTime
= utc_base_ft
;
3311 strcpy (wfd
.cFileName
, name
);
3315 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3316 strcat (name
, "\\");
3317 if (GetDriveType (name
) < 2)
3322 memset (&wfd
, 0, sizeof (wfd
));
3323 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3324 wfd
.ftCreationTime
= utc_base_ft
;
3325 wfd
.ftLastAccessTime
= utc_base_ft
;
3326 wfd
.ftLastWriteTime
= utc_base_ft
;
3327 strcpy (wfd
.cFileName
, name
);
3331 if (IS_DIRECTORY_SEP (name
[len
-1]))
3334 /* (This is hacky, but helps when doing file completions on
3335 network drives.) Optimize by using information available from
3336 active readdir if possible. */
3337 len
= strlen (dir_pathname
);
3338 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3340 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3341 && strnicmp (name
, dir_pathname
, len
) == 0
3342 && IS_DIRECTORY_SEP (name
[len
])
3343 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3345 /* This was the last entry returned by readdir. */
3346 wfd
= dir_find_data
;
3350 logon_network_drive (name
);
3352 fh
= FindFirstFile (name
, &wfd
);
3353 if (fh
== INVALID_HANDLE_VALUE
)
3362 if (!(NILP (Vw32_get_true_file_attributes
)
3363 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3364 /* No access rights required to get info. */
3365 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3366 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3367 != INVALID_HANDLE_VALUE
)
3369 /* This is more accurate in terms of gettting the correct number
3370 of links, but is quite slow (it is noticeable when Emacs is
3371 making a list of file name completions). */
3372 BY_HANDLE_FILE_INFORMATION info
;
3374 if (GetFileInformationByHandle (fh
, &info
))
3376 buf
->st_nlink
= info
.nNumberOfLinks
;
3377 /* Might as well use file index to fake inode values, but this
3378 is not guaranteed to be unique unless we keep a handle open
3379 all the time (even then there are situations where it is
3380 not unique). Reputedly, there are at most 48 bits of info
3381 (on NTFS, presumably less on FAT). */
3382 fake_inode
= info
.nFileIndexHigh
;
3384 fake_inode
+= info
.nFileIndexLow
;
3392 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3394 buf
->st_mode
= S_IFDIR
;
3398 switch (GetFileType (fh
))
3400 case FILE_TYPE_DISK
:
3401 buf
->st_mode
= S_IFREG
;
3403 case FILE_TYPE_PIPE
:
3404 buf
->st_mode
= S_IFIFO
;
3406 case FILE_TYPE_CHAR
:
3407 case FILE_TYPE_UNKNOWN
:
3409 buf
->st_mode
= S_IFCHR
;
3413 psd
= get_file_security_desc (name
);
3414 get_file_owner_and_group (psd
, name
, buf
);
3418 /* Don't bother to make this information more accurate. */
3419 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3424 get_file_owner_and_group (NULL
, name
, buf
);
3429 /* Not sure if there is any point in this. */
3430 if (!NILP (Vw32_generate_fake_inodes
))
3431 fake_inode
= generate_inode_val (name
);
3432 else if (fake_inode
== 0)
3434 /* For want of something better, try to make everything unique. */
3435 static DWORD gen_num
= 0;
3436 fake_inode
= ++gen_num
;
3440 /* MSVC defines _ino_t to be short; other libc's might not. */
3441 if (sizeof (buf
->st_ino
) == 2)
3442 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3444 buf
->st_ino
= fake_inode
;
3446 /* volume_info is set indirectly by map_w32_filename */
3447 buf
->st_dev
= volume_info
.serialnum
;
3448 buf
->st_rdev
= volume_info
.serialnum
;
3450 buf
->st_size
= wfd
.nFileSizeHigh
;
3451 buf
->st_size
<<= 32;
3452 buf
->st_size
+= wfd
.nFileSizeLow
;
3454 /* Convert timestamps to Unix format. */
3455 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3456 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3457 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3458 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3459 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3461 /* determine rwx permissions */
3462 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3463 permission
= S_IREAD
;
3465 permission
= S_IREAD
| S_IWRITE
;
3467 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3468 permission
|= S_IEXEC
;
3469 else if (is_exec (name
))
3470 permission
|= S_IEXEC
;
3472 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3477 /* Provide fstat and utime as well as stat for consistent handling of
3480 fstat (int desc
, struct stat
* buf
)
3482 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3483 BY_HANDLE_FILE_INFORMATION info
;
3484 unsigned __int64 fake_inode
;
3487 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3489 case FILE_TYPE_DISK
:
3490 buf
->st_mode
= S_IFREG
;
3491 if (!GetFileInformationByHandle (fh
, &info
))
3497 case FILE_TYPE_PIPE
:
3498 buf
->st_mode
= S_IFIFO
;
3500 case FILE_TYPE_CHAR
:
3501 case FILE_TYPE_UNKNOWN
:
3503 buf
->st_mode
= S_IFCHR
;
3505 memset (&info
, 0, sizeof (info
));
3506 info
.dwFileAttributes
= 0;
3507 info
.ftCreationTime
= utc_base_ft
;
3508 info
.ftLastAccessTime
= utc_base_ft
;
3509 info
.ftLastWriteTime
= utc_base_ft
;
3512 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3513 buf
->st_mode
= S_IFDIR
;
3515 buf
->st_nlink
= info
.nNumberOfLinks
;
3516 /* Might as well use file index to fake inode values, but this
3517 is not guaranteed to be unique unless we keep a handle open
3518 all the time (even then there are situations where it is
3519 not unique). Reputedly, there are at most 48 bits of info
3520 (on NTFS, presumably less on FAT). */
3521 fake_inode
= info
.nFileIndexHigh
;
3523 fake_inode
+= info
.nFileIndexLow
;
3525 /* MSVC defines _ino_t to be short; other libc's might not. */
3526 if (sizeof (buf
->st_ino
) == 2)
3527 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3529 buf
->st_ino
= fake_inode
;
3531 /* Consider files to belong to current user.
3532 FIXME: this should use GetSecurityInfo API, but it is only
3533 available for _WIN32_WINNT >= 0x501. */
3534 buf
->st_uid
= dflt_passwd
.pw_uid
;
3535 buf
->st_gid
= dflt_passwd
.pw_gid
;
3536 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3537 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3539 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3540 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3542 buf
->st_size
= info
.nFileSizeHigh
;
3543 buf
->st_size
<<= 32;
3544 buf
->st_size
+= info
.nFileSizeLow
;
3546 /* Convert timestamps to Unix format. */
3547 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3548 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3549 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3550 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3551 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3553 /* determine rwx permissions */
3554 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3555 permission
= S_IREAD
;
3557 permission
= S_IREAD
| S_IWRITE
;
3559 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3560 permission
|= S_IEXEC
;
3563 #if 0 /* no way of knowing the filename */
3564 char * p
= strrchr (name
, '.');
3566 (xstrcasecmp (p
, ".exe") == 0 ||
3567 xstrcasecmp (p
, ".com") == 0 ||
3568 xstrcasecmp (p
, ".bat") == 0 ||
3569 xstrcasecmp (p
, ".cmd") == 0))
3570 permission
|= S_IEXEC
;
3574 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3580 utime (const char *name
, struct utimbuf
*times
)
3582 struct utimbuf deftime
;
3589 deftime
.modtime
= deftime
.actime
= time (NULL
);
3593 /* Need write access to set times. */
3594 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3595 0, OPEN_EXISTING
, 0, NULL
);
3598 convert_from_time_t (times
->actime
, &atime
);
3599 convert_from_time_t (times
->modtime
, &mtime
);
3600 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3617 /* Symlink-related functions that always fail. Used in fileio.c to
3620 symlink (char const *dummy1
, char const *dummy2
)
3627 readlink (const char *name
, char *dummy1
, size_t dummy2
)
3629 /* `access' is much faster than `stat' on MS-Windows. */
3630 if (sys_access (name
, 0) == 0)
3636 /* Support for browsing other processes and their attributes. See
3637 process.c for the Lisp bindings. */
3639 /* Helper wrapper functions. */
3641 static HANDLE WINAPI
3642 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
3644 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3646 if (g_b_init_create_toolhelp32_snapshot
== 0)
3648 g_b_init_create_toolhelp32_snapshot
= 1;
3649 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3650 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3651 "CreateToolhelp32Snapshot");
3653 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3655 return INVALID_HANDLE_VALUE
;
3657 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3661 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3663 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3665 if (g_b_init_process32_first
== 0)
3667 g_b_init_process32_first
= 1;
3668 s_pfn_Process32_First
= (Process32First_Proc
)
3669 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3672 if (s_pfn_Process32_First
== NULL
)
3676 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3680 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3682 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3684 if (g_b_init_process32_next
== 0)
3686 g_b_init_process32_next
= 1;
3687 s_pfn_Process32_Next
= (Process32Next_Proc
)
3688 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3691 if (s_pfn_Process32_Next
== NULL
)
3695 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3699 open_thread_token (HANDLE ThreadHandle
,
3700 DWORD DesiredAccess
,
3702 PHANDLE TokenHandle
)
3704 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3705 HMODULE hm_advapi32
= NULL
;
3706 if (is_windows_9x () == TRUE
)
3708 SetLastError (ERROR_NOT_SUPPORTED
);
3711 if (g_b_init_open_thread_token
== 0)
3713 g_b_init_open_thread_token
= 1;
3714 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3715 s_pfn_Open_Thread_Token
=
3716 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3718 if (s_pfn_Open_Thread_Token
== NULL
)
3720 SetLastError (ERROR_NOT_SUPPORTED
);
3724 s_pfn_Open_Thread_Token (
3733 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3735 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3736 HMODULE hm_advapi32
= NULL
;
3737 if (is_windows_9x () == TRUE
)
3741 if (g_b_init_impersonate_self
== 0)
3743 g_b_init_impersonate_self
= 1;
3744 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3745 s_pfn_Impersonate_Self
=
3746 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3748 if (s_pfn_Impersonate_Self
== NULL
)
3752 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3756 revert_to_self (void)
3758 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3759 HMODULE hm_advapi32
= NULL
;
3760 if (is_windows_9x () == TRUE
)
3764 if (g_b_init_revert_to_self
== 0)
3766 g_b_init_revert_to_self
= 1;
3767 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3768 s_pfn_Revert_To_Self
=
3769 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3771 if (s_pfn_Revert_To_Self
== NULL
)
3775 return s_pfn_Revert_To_Self ();
3779 get_process_memory_info (HANDLE h_proc
,
3780 PPROCESS_MEMORY_COUNTERS mem_counters
,
3783 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3784 HMODULE hm_psapi
= NULL
;
3785 if (is_windows_9x () == TRUE
)
3789 if (g_b_init_get_process_memory_info
== 0)
3791 g_b_init_get_process_memory_info
= 1;
3792 hm_psapi
= LoadLibrary ("Psapi.dll");
3794 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3795 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3797 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3801 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3805 get_process_working_set_size (HANDLE h_proc
,
3809 static GetProcessWorkingSetSize_Proc
3810 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3812 if (is_windows_9x () == TRUE
)
3816 if (g_b_init_get_process_working_set_size
== 0)
3818 g_b_init_get_process_working_set_size
= 1;
3819 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3820 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3821 "GetProcessWorkingSetSize");
3823 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3827 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3831 global_memory_status (MEMORYSTATUS
*buf
)
3833 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3835 if (is_windows_9x () == TRUE
)
3839 if (g_b_init_global_memory_status
== 0)
3841 g_b_init_global_memory_status
= 1;
3842 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3843 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3844 "GlobalMemoryStatus");
3846 if (s_pfn_Global_Memory_Status
== NULL
)
3850 return s_pfn_Global_Memory_Status (buf
);
3854 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
3856 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3858 if (is_windows_9x () == TRUE
)
3862 if (g_b_init_global_memory_status_ex
== 0)
3864 g_b_init_global_memory_status_ex
= 1;
3865 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3866 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3867 "GlobalMemoryStatusEx");
3869 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3873 return s_pfn_Global_Memory_Status_Ex (buf
);
3877 list_system_processes (void)
3879 struct gcpro gcpro1
;
3880 Lisp_Object proclist
= Qnil
;
3883 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3885 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3887 PROCESSENTRY32 proc_entry
;
3893 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3894 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3895 res
= process32_next (h_snapshot
, &proc_entry
))
3897 proc_id
= proc_entry
.th32ProcessID
;
3898 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3901 CloseHandle (h_snapshot
);
3903 proclist
= Fnreverse (proclist
);
3910 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3912 TOKEN_PRIVILEGES priv
;
3913 DWORD priv_size
= sizeof (priv
);
3914 DWORD opriv_size
= sizeof (*old_priv
);
3915 HANDLE h_token
= NULL
;
3916 HANDLE h_thread
= GetCurrentThread ();
3920 res
= open_thread_token (h_thread
,
3921 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3923 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3925 if (impersonate_self (SecurityImpersonation
))
3926 res
= open_thread_token (h_thread
,
3927 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3932 priv
.PrivilegeCount
= 1;
3933 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3934 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3935 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3936 old_priv
, &opriv_size
)
3937 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3941 CloseHandle (h_token
);
3947 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3949 DWORD priv_size
= sizeof (*priv
);
3950 HANDLE h_token
= NULL
;
3953 if (open_thread_token (GetCurrentThread (),
3954 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3957 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3958 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3962 CloseHandle (h_token
);
3968 ltime (long time_sec
, long time_usec
)
3970 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3971 make_number (time_sec
& 0xffff),
3972 make_number (time_usec
));
3975 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
3978 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
3979 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
3982 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
3983 ULONGLONG tem1
, tem2
, tem3
, tem
;
3986 || !get_process_times_fn
3987 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
3988 &ft_kernel
, &ft_user
))
3991 GetSystemTimeAsFileTime (&ft_current
);
3993 FILETIME_TO_U64 (tem1
, ft_kernel
);
3995 *stime
= U64_TO_LISP_TIME (tem1
);
3997 FILETIME_TO_U64 (tem2
, ft_user
);
3999 *utime
= U64_TO_LISP_TIME (tem2
);
4002 *ttime
= U64_TO_LISP_TIME (tem3
);
4004 FILETIME_TO_U64 (tem
, ft_creation
);
4005 /* Process no 4 (System) returns zero creation time. */
4007 tem
= (tem
- utc_base
) / 10L;
4008 *ctime
= U64_TO_LISP_TIME (tem
);
4012 FILETIME_TO_U64 (tem3
, ft_current
);
4013 tem
= (tem3
- utc_base
) / 10L - tem
;
4015 *etime
= U64_TO_LISP_TIME (tem
);
4019 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4030 system_process_attributes (Lisp_Object pid
)
4032 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4033 Lisp_Object attrs
= Qnil
;
4034 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4035 HANDLE h_snapshot
, h_proc
;
4038 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4039 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4040 DWORD glength
= sizeof (gname
);
4041 HANDLE token
= NULL
;
4042 SID_NAME_USE user_type
;
4043 unsigned char *buf
= NULL
;
4045 TOKEN_USER user_token
;
4046 TOKEN_PRIMARY_GROUP group_token
;
4050 PROCESS_MEMORY_COUNTERS mem
;
4051 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4052 DWORD minrss
, maxrss
;
4054 MEMORY_STATUS_EX memstex
;
4055 double totphys
= 0.0;
4056 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4058 BOOL result
= FALSE
;
4060 CHECK_NUMBER_OR_FLOAT (pid
);
4061 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4063 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4065 GCPRO3 (attrs
, decoded_cmd
, tem
);
4067 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4072 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4073 for (res
= process32_first (h_snapshot
, &pe
); res
;
4074 res
= process32_next (h_snapshot
, &pe
))
4076 if (proc_id
== pe
.th32ProcessID
)
4079 decoded_cmd
= build_string ("Idle");
4082 /* Decode the command name from locale-specific
4084 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4085 strlen (pe
.szExeFile
));
4087 code_convert_string_norecord (cmd_str
,
4088 Vlocale_coding_system
, 0);
4090 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4091 attrs
= Fcons (Fcons (Qppid
,
4092 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4094 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4096 attrs
= Fcons (Fcons (Qthcount
,
4097 make_fixnum_or_float (pe
.cntThreads
)),
4104 CloseHandle (h_snapshot
);
4113 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4115 /* If we were denied a handle to the process, try again after
4116 enabling the SeDebugPrivilege in our process. */
4119 TOKEN_PRIVILEGES priv_current
;
4121 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4123 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4125 restore_privilege (&priv_current
);
4131 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4134 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4135 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4137 buf
= xmalloc (blen
);
4138 result
= get_token_information (token
, TokenUser
,
4139 (LPVOID
)buf
, blen
, &needed
);
4142 memcpy (&user_token
, buf
, sizeof (user_token
));
4143 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4145 euid
= get_rid (user_token
.User
.Sid
);
4146 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4151 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4154 strcpy (uname
, "unknown");
4158 ulength
= strlen (uname
);
4164 /* Determine a reasonable euid and gid values. */
4165 if (xstrcasecmp ("administrator", uname
) == 0)
4167 euid
= 500; /* well-known Administrator uid */
4168 egid
= 513; /* well-known None gid */
4172 /* Get group id and name. */
4173 result
= get_token_information (token
, TokenPrimaryGroup
,
4174 (LPVOID
)buf
, blen
, &needed
);
4175 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4177 buf
= xrealloc (buf
, blen
= needed
);
4178 result
= get_token_information (token
, TokenPrimaryGroup
,
4179 (LPVOID
)buf
, blen
, &needed
);
4183 memcpy (&group_token
, buf
, sizeof (group_token
));
4184 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4186 egid
= get_rid (group_token
.PrimaryGroup
);
4187 dlength
= sizeof (domain
);
4189 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4190 gname
, &glength
, NULL
, &dlength
,
4193 w32_add_to_cache (group_token
.PrimaryGroup
,
4197 strcpy (gname
, "None");
4201 glength
= strlen (gname
);
4209 if (!is_windows_9x ())
4211 /* We couldn't open the process token, presumably because of
4212 insufficient access rights. Assume this process is run
4214 strcpy (uname
, "SYSTEM");
4215 strcpy (gname
, "None");
4216 euid
= 18; /* SYSTEM */
4217 egid
= 513; /* None */
4218 glength
= strlen (gname
);
4219 ulength
= strlen (uname
);
4221 /* If we are running under Windows 9X, where security calls are
4222 not supported, we assume all processes are run by the current
4224 else if (GetUserName (uname
, &ulength
))
4226 if (xstrcasecmp ("administrator", uname
) == 0)
4231 strcpy (gname
, "None");
4232 glength
= strlen (gname
);
4233 ulength
= strlen (uname
);
4239 strcpy (uname
, "administrator");
4240 ulength
= strlen (uname
);
4241 strcpy (gname
, "None");
4242 glength
= strlen (gname
);
4245 CloseHandle (token
);
4248 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4249 tem
= make_unibyte_string (uname
, ulength
);
4250 attrs
= Fcons (Fcons (Quser
,
4251 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4253 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4254 tem
= make_unibyte_string (gname
, glength
);
4255 attrs
= Fcons (Fcons (Qgroup
,
4256 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4259 if (global_memory_status_ex (&memstex
))
4260 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4261 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4263 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4264 double, so we need to do this for it... */
4266 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4267 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4268 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4270 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4272 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4273 else if (global_memory_status (&memst
))
4274 totphys
= memst
.dwTotalPhys
/ 1024.0;
4277 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4280 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4282 attrs
= Fcons (Fcons (Qmajflt
,
4283 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4285 attrs
= Fcons (Fcons (Qvsize
,
4286 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4288 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4290 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4293 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4295 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4297 attrs
= Fcons (Fcons (Qmajflt
,
4298 make_fixnum_or_float (mem
.PageFaultCount
)),
4300 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4302 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4305 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4307 DWORD rss
= maxrss
/ 1024;
4309 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4311 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4314 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4316 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4317 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4318 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4319 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4320 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4321 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4324 /* FIXME: Retrieve command line by walking the PEB of the process. */
4327 CloseHandle (h_proc
);
4333 /* Wrappers for winsock functions to map between our file descriptors
4334 and winsock's handles; also set h_errno for convenience.
4336 To allow Emacs to run on systems which don't have winsock support
4337 installed, we dynamically link to winsock on startup if present, and
4338 otherwise provide the minimum necessary functionality
4339 (eg. gethostname). */
4341 /* function pointers for relevant socket functions */
4342 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4343 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4344 int (PASCAL
*pfn_WSAGetLastError
) (void);
4345 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4346 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4347 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4348 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4349 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4350 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4351 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4352 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4353 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4354 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4355 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4356 int (PASCAL
*pfn_WSACleanup
) (void);
4358 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4359 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4360 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4361 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4362 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4363 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4364 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4365 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4366 const char * optval
, int optlen
);
4367 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4368 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4370 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4371 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4372 struct sockaddr
* from
, int * fromlen
);
4373 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4374 const struct sockaddr
* to
, int tolen
);
4376 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4377 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4378 #ifndef HANDLE_FLAG_INHERIT
4379 #define HANDLE_FLAG_INHERIT 1
4383 static int winsock_inuse
;
4388 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4390 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4391 after WSAStartup returns successfully, but it seems reasonable
4392 to allow unloading winsock anyway in that case. */
4393 if (pfn_WSACleanup () == 0 ||
4394 pfn_WSAGetLastError () == WSAENETDOWN
)
4396 if (FreeLibrary (winsock_lib
))
4405 init_winsock (int load_now
)
4407 WSADATA winsockData
;
4409 if (winsock_lib
!= NULL
)
4412 pfn_SetHandleInformation
4413 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4414 "SetHandleInformation");
4416 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4418 if (winsock_lib
!= NULL
)
4420 /* dynamically link to socket functions */
4422 #define LOAD_PROC(fn) \
4423 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4426 LOAD_PROC (WSAStartup
);
4427 LOAD_PROC (WSASetLastError
);
4428 LOAD_PROC (WSAGetLastError
);
4429 LOAD_PROC (WSAEventSelect
);
4430 LOAD_PROC (WSACreateEvent
);
4431 LOAD_PROC (WSACloseEvent
);
4434 LOAD_PROC (connect
);
4435 LOAD_PROC (ioctlsocket
);
4438 LOAD_PROC (closesocket
);
4439 LOAD_PROC (shutdown
);
4442 LOAD_PROC (inet_addr
);
4443 LOAD_PROC (gethostname
);
4444 LOAD_PROC (gethostbyname
);
4445 LOAD_PROC (getservbyname
);
4446 LOAD_PROC (getpeername
);
4447 LOAD_PROC (WSACleanup
);
4448 LOAD_PROC (setsockopt
);
4450 LOAD_PROC (getsockname
);
4452 LOAD_PROC (recvfrom
);
4456 /* specify version 1.1 of winsock */
4457 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4459 if (winsockData
.wVersion
!= 0x101)
4464 /* Report that winsock exists and is usable, but leave
4465 socket functions disabled. I am assuming that calling
4466 WSAStartup does not require any network interaction,
4467 and in particular does not cause or require a dial-up
4468 connection to be established. */
4471 FreeLibrary (winsock_lib
);
4479 FreeLibrary (winsock_lib
);
4489 /* function to set h_errno for compatibility; map winsock error codes to
4490 normal system codes where they overlap (non-overlapping definitions
4491 are already in <sys/socket.h> */
4495 if (winsock_lib
== NULL
)
4498 h_errno
= pfn_WSAGetLastError ();
4502 case WSAEACCES
: h_errno
= EACCES
; break;
4503 case WSAEBADF
: h_errno
= EBADF
; break;
4504 case WSAEFAULT
: h_errno
= EFAULT
; break;
4505 case WSAEINTR
: h_errno
= EINTR
; break;
4506 case WSAEINVAL
: h_errno
= EINVAL
; break;
4507 case WSAEMFILE
: h_errno
= EMFILE
; break;
4508 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4509 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4517 if (h_errno
== 0 && winsock_lib
!= NULL
)
4518 pfn_WSASetLastError (0);
4521 /* Extend strerror to handle the winsock-specific error codes. */
4525 } _wsa_errlist
[] = {
4526 WSAEINTR
, "Interrupted function call",
4527 WSAEBADF
, "Bad file descriptor",
4528 WSAEACCES
, "Permission denied",
4529 WSAEFAULT
, "Bad address",
4530 WSAEINVAL
, "Invalid argument",
4531 WSAEMFILE
, "Too many open files",
4533 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4534 WSAEINPROGRESS
, "Operation now in progress",
4535 WSAEALREADY
, "Operation already in progress",
4536 WSAENOTSOCK
, "Socket operation on non-socket",
4537 WSAEDESTADDRREQ
, "Destination address required",
4538 WSAEMSGSIZE
, "Message too long",
4539 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4540 WSAENOPROTOOPT
, "Bad protocol option",
4541 WSAEPROTONOSUPPORT
, "Protocol not supported",
4542 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4543 WSAEOPNOTSUPP
, "Operation not supported",
4544 WSAEPFNOSUPPORT
, "Protocol family not supported",
4545 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4546 WSAEADDRINUSE
, "Address already in use",
4547 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4548 WSAENETDOWN
, "Network is down",
4549 WSAENETUNREACH
, "Network is unreachable",
4550 WSAENETRESET
, "Network dropped connection on reset",
4551 WSAECONNABORTED
, "Software caused connection abort",
4552 WSAECONNRESET
, "Connection reset by peer",
4553 WSAENOBUFS
, "No buffer space available",
4554 WSAEISCONN
, "Socket is already connected",
4555 WSAENOTCONN
, "Socket is not connected",
4556 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4557 WSAETOOMANYREFS
, "Too many references", /* not sure */
4558 WSAETIMEDOUT
, "Connection timed out",
4559 WSAECONNREFUSED
, "Connection refused",
4560 WSAELOOP
, "Network loop", /* not sure */
4561 WSAENAMETOOLONG
, "Name is too long",
4562 WSAEHOSTDOWN
, "Host is down",
4563 WSAEHOSTUNREACH
, "No route to host",
4564 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4565 WSAEPROCLIM
, "Too many processes",
4566 WSAEUSERS
, "Too many users", /* not sure */
4567 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4568 WSAESTALE
, "Data is stale", /* not sure */
4569 WSAEREMOTE
, "Remote error", /* not sure */
4571 WSASYSNOTREADY
, "Network subsystem is unavailable",
4572 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4573 WSANOTINITIALISED
, "Winsock not initialized successfully",
4574 WSAEDISCON
, "Graceful shutdown in progress",
4576 WSAENOMORE
, "No more operations allowed", /* not sure */
4577 WSAECANCELLED
, "Operation cancelled", /* not sure */
4578 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4579 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4580 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4581 WSASYSCALLFAILURE
, "System call failure",
4582 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4583 WSATYPE_NOT_FOUND
, "Class type not found",
4584 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4585 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4586 WSAEREFUSED
, "Operation refused", /* not sure */
4589 WSAHOST_NOT_FOUND
, "Host not found",
4590 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4591 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4592 WSANO_DATA
, "Valid name, no data record of requested type",
4598 sys_strerror (int error_no
)
4601 static char unknown_msg
[40];
4603 if (error_no
>= 0 && error_no
< sys_nerr
)
4604 return sys_errlist
[error_no
];
4606 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4607 if (_wsa_errlist
[i
].errnum
== error_no
)
4608 return _wsa_errlist
[i
].msg
;
4610 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4614 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4615 but I believe the method of keeping the socket handle separate (and
4616 insuring it is not inheritable) is the correct one. */
4618 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4620 static int socket_to_fd (SOCKET s
);
4623 sys_socket (int af
, int type
, int protocol
)
4627 if (winsock_lib
== NULL
)
4630 return INVALID_SOCKET
;
4635 /* call the real socket function */
4636 s
= pfn_socket (af
, type
, protocol
);
4638 if (s
!= INVALID_SOCKET
)
4639 return socket_to_fd (s
);
4645 /* Convert a SOCKET to a file descriptor. */
4647 socket_to_fd (SOCKET s
)
4652 /* Although under NT 3.5 _open_osfhandle will accept a socket
4653 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4654 that does not work under NT 3.1. However, we can get the same
4655 effect by using a backdoor function to replace an existing
4656 descriptor handle with the one we want. */
4658 /* allocate a file descriptor (with appropriate flags) */
4659 fd
= _open ("NUL:", _O_RDWR
);
4662 /* Make a non-inheritable copy of the socket handle. Note
4663 that it is possible that sockets aren't actually kernel
4664 handles, which appears to be the case on Windows 9x when
4665 the MS Proxy winsock client is installed. */
4667 /* Apparently there is a bug in NT 3.51 with some service
4668 packs, which prevents using DuplicateHandle to make a
4669 socket handle non-inheritable (causes WSACleanup to
4670 hang). The work-around is to use SetHandleInformation
4671 instead if it is available and implemented. */
4672 if (pfn_SetHandleInformation
)
4674 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4678 HANDLE parent
= GetCurrentProcess ();
4679 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4681 if (DuplicateHandle (parent
,
4687 DUPLICATE_SAME_ACCESS
))
4689 /* It is possible that DuplicateHandle succeeds even
4690 though the socket wasn't really a kernel handle,
4691 because a real handle has the same value. So
4692 test whether the new handle really is a socket. */
4693 long nonblocking
= 0;
4694 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4696 pfn_closesocket (s
);
4701 CloseHandle (new_s
);
4706 fd_info
[fd
].hnd
= (HANDLE
) s
;
4708 /* set our own internal flags */
4709 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4715 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4717 /* attach child_process to fd_info */
4718 if (fd_info
[ fd
].cp
!= NULL
)
4720 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4724 fd_info
[ fd
].cp
= cp
;
4727 winsock_inuse
++; /* count open sockets */
4734 pfn_closesocket (s
);
4740 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4742 if (winsock_lib
== NULL
)
4745 return SOCKET_ERROR
;
4749 if (fd_info
[s
].flags
& FILE_SOCKET
)
4751 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4752 if (rc
== SOCKET_ERROR
)
4757 return SOCKET_ERROR
;
4761 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4763 if (winsock_lib
== NULL
)
4766 return SOCKET_ERROR
;
4770 if (fd_info
[s
].flags
& FILE_SOCKET
)
4772 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4773 if (rc
== SOCKET_ERROR
)
4778 return SOCKET_ERROR
;
4782 sys_htons (u_short hostshort
)
4784 return (winsock_lib
!= NULL
) ?
4785 pfn_htons (hostshort
) : hostshort
;
4789 sys_ntohs (u_short netshort
)
4791 return (winsock_lib
!= NULL
) ?
4792 pfn_ntohs (netshort
) : netshort
;
4796 sys_inet_addr (const char * cp
)
4798 return (winsock_lib
!= NULL
) ?
4799 pfn_inet_addr (cp
) : INADDR_NONE
;
4803 sys_gethostname (char * name
, int namelen
)
4805 if (winsock_lib
!= NULL
)
4806 return pfn_gethostname (name
, namelen
);
4808 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4809 return !GetComputerName (name
, (DWORD
*)&namelen
);
4812 return SOCKET_ERROR
;
4816 sys_gethostbyname (const char * name
)
4818 struct hostent
* host
;
4820 if (winsock_lib
== NULL
)
4827 host
= pfn_gethostbyname (name
);
4834 sys_getservbyname (const char * name
, const char * proto
)
4836 struct servent
* serv
;
4838 if (winsock_lib
== NULL
)
4845 serv
= pfn_getservbyname (name
, proto
);
4852 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4854 if (winsock_lib
== NULL
)
4857 return SOCKET_ERROR
;
4861 if (fd_info
[s
].flags
& FILE_SOCKET
)
4863 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4864 if (rc
== SOCKET_ERROR
)
4869 return SOCKET_ERROR
;
4873 sys_shutdown (int s
, int how
)
4875 if (winsock_lib
== NULL
)
4878 return SOCKET_ERROR
;
4882 if (fd_info
[s
].flags
& FILE_SOCKET
)
4884 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4885 if (rc
== SOCKET_ERROR
)
4890 return SOCKET_ERROR
;
4894 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4896 if (winsock_lib
== NULL
)
4899 return SOCKET_ERROR
;
4903 if (fd_info
[s
].flags
& FILE_SOCKET
)
4905 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4906 (const char *)optval
, optlen
);
4907 if (rc
== SOCKET_ERROR
)
4912 return SOCKET_ERROR
;
4916 sys_listen (int s
, int backlog
)
4918 if (winsock_lib
== NULL
)
4921 return SOCKET_ERROR
;
4925 if (fd_info
[s
].flags
& FILE_SOCKET
)
4927 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4928 if (rc
== SOCKET_ERROR
)
4931 fd_info
[s
].flags
|= FILE_LISTEN
;
4935 return SOCKET_ERROR
;
4939 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4941 if (winsock_lib
== NULL
)
4944 return SOCKET_ERROR
;
4948 if (fd_info
[s
].flags
& FILE_SOCKET
)
4950 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4951 if (rc
== SOCKET_ERROR
)
4956 return SOCKET_ERROR
;
4960 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
4962 if (winsock_lib
== NULL
)
4969 if (fd_info
[s
].flags
& FILE_LISTEN
)
4971 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
4973 if (t
== INVALID_SOCKET
)
4976 fd
= socket_to_fd (t
);
4978 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4979 ResetEvent (fd_info
[s
].cp
->char_avail
);
4987 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
4988 struct sockaddr
* from
, int * fromlen
)
4990 if (winsock_lib
== NULL
)
4993 return SOCKET_ERROR
;
4997 if (fd_info
[s
].flags
& FILE_SOCKET
)
4999 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5000 if (rc
== SOCKET_ERROR
)
5005 return SOCKET_ERROR
;
5009 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5010 const struct sockaddr
* to
, int tolen
)
5012 if (winsock_lib
== NULL
)
5015 return SOCKET_ERROR
;
5019 if (fd_info
[s
].flags
& FILE_SOCKET
)
5021 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5022 if (rc
== SOCKET_ERROR
)
5027 return SOCKET_ERROR
;
5030 /* Windows does not have an fcntl function. Provide an implementation
5031 solely for making sockets non-blocking. */
5033 fcntl (int s
, int cmd
, int options
)
5035 if (winsock_lib
== NULL
)
5042 if (fd_info
[s
].flags
& FILE_SOCKET
)
5044 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5046 unsigned long nblock
= 1;
5047 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5048 if (rc
== SOCKET_ERROR
)
5050 /* Keep track of the fact that we set this to non-blocking. */
5051 fd_info
[s
].flags
|= FILE_NDELAY
;
5057 return SOCKET_ERROR
;
5061 return SOCKET_ERROR
;
5065 /* Shadow main io functions: we need to handle pipes and sockets more
5066 intelligently, and implement non-blocking mode as well. */
5079 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5081 child_process
* cp
= fd_info
[fd
].cp
;
5083 fd_info
[fd
].cp
= NULL
;
5085 if (CHILD_ACTIVE (cp
))
5087 /* if last descriptor to active child_process then cleanup */
5089 for (i
= 0; i
< MAXDESC
; i
++)
5093 if (fd_info
[i
].cp
== cp
)
5098 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5100 if (winsock_lib
== NULL
) abort ();
5102 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5103 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5105 winsock_inuse
--; /* count open sockets */
5112 /* Note that sockets do not need special treatment here (at least on
5113 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5114 closesocket is equivalent to CloseHandle, which is to be expected
5115 because socket handles are fully fledged kernel handles. */
5118 if (rc
== 0 && fd
< MAXDESC
)
5119 fd_info
[fd
].flags
= 0;
5130 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5132 /* duplicate our internal info as well */
5133 fd_info
[new_fd
] = fd_info
[fd
];
5139 sys_dup2 (int src
, int dst
)
5143 if (dst
< 0 || dst
>= MAXDESC
)
5149 /* make sure we close the destination first if it's a pipe or socket */
5150 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5153 rc
= _dup2 (src
, dst
);
5156 /* duplicate our internal info as well */
5157 fd_info
[dst
] = fd_info
[src
];
5162 /* Unix pipe() has only one arg */
5164 sys_pipe (int * phandles
)
5169 /* make pipe handles non-inheritable; when we spawn a child, we
5170 replace the relevant handle with an inheritable one. Also put
5171 pipes into binary mode; we will do text mode translation ourselves
5173 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5177 /* Protect against overflow, since Windows can open more handles than
5178 our fd_info array has room for. */
5179 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5181 _close (phandles
[0]);
5182 _close (phandles
[1]);
5187 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5188 fd_info
[phandles
[0]].flags
= flags
;
5190 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5191 fd_info
[phandles
[1]].flags
= flags
;
5198 /* Function to do blocking read of one byte, needed to implement
5199 select. It is only allowed on sockets and pipes. */
5201 _sys_read_ahead (int fd
)
5206 if (fd
< 0 || fd
>= MAXDESC
)
5207 return STATUS_READ_ERROR
;
5209 cp
= fd_info
[fd
].cp
;
5211 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5212 return STATUS_READ_ERROR
;
5214 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5215 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5217 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5221 cp
->status
= STATUS_READ_IN_PROGRESS
;
5223 if (fd_info
[fd
].flags
& FILE_PIPE
)
5225 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5227 /* Give subprocess time to buffer some more output for us before
5228 reporting that input is available; we need this because Windows 95
5229 connects DOS programs to pipes by making the pipe appear to be
5230 the normal console stdout - as a result most DOS programs will
5231 write to stdout without buffering, ie. one character at a
5232 time. Even some W32 programs do this - "dir" in a command
5233 shell on NT is very slow if we don't do this. */
5236 int wait
= w32_pipe_read_delay
;
5242 /* Yield remainder of our time slice, effectively giving a
5243 temporary priority boost to the child process. */
5247 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5249 HANDLE hnd
= fd_info
[fd
].hnd
;
5250 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5253 /* Configure timeouts for blocking read. */
5254 if (!GetCommTimeouts (hnd
, &ct
))
5255 return STATUS_READ_ERROR
;
5256 ct
.ReadIntervalTimeout
= 0;
5257 ct
.ReadTotalTimeoutMultiplier
= 0;
5258 ct
.ReadTotalTimeoutConstant
= 0;
5259 if (!SetCommTimeouts (hnd
, &ct
))
5260 return STATUS_READ_ERROR
;
5262 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5264 if (GetLastError () != ERROR_IO_PENDING
)
5265 return STATUS_READ_ERROR
;
5266 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5267 return STATUS_READ_ERROR
;
5270 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5272 unsigned long nblock
= 0;
5273 /* We always want this to block, so temporarily disable NDELAY. */
5274 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5275 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5277 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5279 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5282 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5286 if (rc
== sizeof (char))
5287 cp
->status
= STATUS_READ_SUCCEEDED
;
5289 cp
->status
= STATUS_READ_FAILED
;
5295 _sys_wait_accept (int fd
)
5301 if (fd
< 0 || fd
>= MAXDESC
)
5302 return STATUS_READ_ERROR
;
5304 cp
= fd_info
[fd
].cp
;
5306 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5307 return STATUS_READ_ERROR
;
5309 cp
->status
= STATUS_READ_FAILED
;
5311 hEv
= pfn_WSACreateEvent ();
5312 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5313 if (rc
!= SOCKET_ERROR
)
5315 rc
= WaitForSingleObject (hEv
, INFINITE
);
5316 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5317 if (rc
== WAIT_OBJECT_0
)
5318 cp
->status
= STATUS_READ_SUCCEEDED
;
5320 pfn_WSACloseEvent (hEv
);
5326 sys_read (int fd
, char * buffer
, unsigned int count
)
5331 char * orig_buffer
= buffer
;
5339 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5341 child_process
*cp
= fd_info
[fd
].cp
;
5343 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5351 /* re-read CR carried over from last read */
5352 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5354 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5358 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5361 /* presence of a child_process structure means we are operating in
5362 non-blocking mode - otherwise we just call _read directly.
5363 Note that the child_process structure might be missing because
5364 reap_subprocess has been called; in this case the pipe is
5365 already broken, so calling _read on it is okay. */
5368 int current_status
= cp
->status
;
5370 switch (current_status
)
5372 case STATUS_READ_FAILED
:
5373 case STATUS_READ_ERROR
:
5374 /* report normal EOF if nothing in buffer */
5376 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5379 case STATUS_READ_READY
:
5380 case STATUS_READ_IN_PROGRESS
:
5381 DebPrint (("sys_read called when read is in progress\n"));
5382 errno
= EWOULDBLOCK
;
5385 case STATUS_READ_SUCCEEDED
:
5386 /* consume read-ahead char */
5387 *buffer
++ = cp
->chr
;
5390 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5391 ResetEvent (cp
->char_avail
);
5393 case STATUS_READ_ACKNOWLEDGED
:
5397 DebPrint (("sys_read: bad status %d\n", current_status
));
5402 if (fd_info
[fd
].flags
& FILE_PIPE
)
5404 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5405 to_read
= min (waiting
, (DWORD
) count
);
5408 nchars
+= _read (fd
, buffer
, to_read
);
5410 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5412 HANDLE hnd
= fd_info
[fd
].hnd
;
5413 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5420 /* Configure timeouts for non-blocking read. */
5421 if (!GetCommTimeouts (hnd
, &ct
))
5426 ct
.ReadIntervalTimeout
= MAXDWORD
;
5427 ct
.ReadTotalTimeoutMultiplier
= 0;
5428 ct
.ReadTotalTimeoutConstant
= 0;
5429 if (!SetCommTimeouts (hnd
, &ct
))
5435 if (!ResetEvent (ovl
->hEvent
))
5440 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5442 if (GetLastError () != ERROR_IO_PENDING
)
5447 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5456 else /* FILE_SOCKET */
5458 if (winsock_lib
== NULL
) abort ();
5460 /* do the equivalent of a non-blocking read */
5461 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5462 if (waiting
== 0 && nchars
== 0)
5464 h_errno
= errno
= EWOULDBLOCK
;
5470 /* always use binary mode for sockets */
5471 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5472 if (res
== SOCKET_ERROR
)
5474 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5475 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5485 int nread
= _read (fd
, buffer
, count
);
5488 else if (nchars
== 0)
5493 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5494 /* Perform text mode translation if required. */
5495 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5497 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5498 /* If buffer contains only CR, return that. To be absolutely
5499 sure we should attempt to read the next char, but in
5500 practice a CR to be followed by LF would not appear by
5501 itself in the buffer. */
5502 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5504 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5510 nchars
= _read (fd
, buffer
, count
);
5515 /* From w32xfns.c */
5516 extern HANDLE interrupt_handle
;
5518 /* For now, don't bother with a non-blocking mode */
5520 sys_write (int fd
, const void * buffer
, unsigned int count
)
5530 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5532 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5538 /* Perform text mode translation if required. */
5539 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5541 char * tmpbuf
= alloca (count
* 2);
5542 unsigned char * src
= (void *)buffer
;
5543 unsigned char * dst
= tmpbuf
;
5548 unsigned char *next
;
5549 /* copy next line or remaining bytes */
5550 next
= _memccpy (dst
, src
, '\n', nbytes
);
5553 /* copied one line ending with '\n' */
5554 int copied
= next
- dst
;
5557 /* insert '\r' before '\n' */
5564 /* copied remaining partial line -> now finished */
5571 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5573 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5574 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5575 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5578 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5580 if (GetLastError () != ERROR_IO_PENDING
)
5585 if (detect_input_pending ())
5586 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5589 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5590 if (active
== WAIT_OBJECT_0
)
5591 { /* User pressed C-g, cancel write, then leave. Don't bother
5592 cleaning up as we may only get stuck in buggy drivers. */
5593 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5598 if (active
== WAIT_OBJECT_0
+ 1
5599 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5606 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5608 unsigned long nblock
= 0;
5609 if (winsock_lib
== NULL
) abort ();
5611 /* TODO: implement select() properly so non-blocking I/O works. */
5612 /* For now, make sure the write blocks. */
5613 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5614 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5616 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5618 /* Set the socket back to non-blocking if it was before,
5619 for other operations that support it. */
5620 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5623 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5626 if (nchars
== SOCKET_ERROR
)
5628 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5629 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5635 /* Some networked filesystems don't like too large writes, so
5636 break them into smaller chunks. See the Comments section of
5637 the MSDN documentation of WriteFile for details behind the
5638 choice of the value of CHUNK below. See also the thread
5639 http://thread.gmane.org/gmane.comp.version-control.git/145294
5640 in the git mailing list. */
5641 const unsigned char *p
= buffer
;
5642 const unsigned chunk
= 30 * 1024 * 1024;
5647 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5648 int n
= _write (fd
, p
, this_chunk
);
5656 else if (n
< this_chunk
)
5667 check_windows_init_file (void)
5669 extern int noninteractive
, inhibit_window_system
;
5671 /* A common indication that Emacs is not installed properly is when
5672 it cannot find the Windows installation file. If this file does
5673 not exist in the expected place, tell the user. */
5675 if (!noninteractive
&& !inhibit_window_system
)
5677 Lisp_Object objs
[2];
5678 Lisp_Object full_load_path
;
5679 Lisp_Object init_file
;
5682 objs
[0] = Vload_path
;
5683 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5684 full_load_path
= Fappend (2, objs
);
5685 init_file
= build_string ("term/w32-win");
5686 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5689 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5690 char *init_file_name
= SDATA (init_file
);
5691 char *load_path
= SDATA (load_path_print
);
5692 char *buffer
= alloca (1024
5693 + strlen (init_file_name
)
5694 + strlen (load_path
));
5697 "The Emacs Windows initialization file \"%s.el\" "
5698 "could not be found in your Emacs installation. "
5699 "Emacs checked the following directories for this file:\n"
5701 "When Emacs cannot find this file, it usually means that it "
5702 "was not installed properly, or its distribution file was "
5703 "not unpacked properly.\nSee the README.W32 file in the "
5704 "top-level Emacs directory for more information.",
5705 init_file_name
, load_path
);
5708 "Emacs Abort Dialog",
5709 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5710 /* Use the low-level Emacs abort. */
5724 /* shutdown the socket interface if necessary */
5733 /* Initialise the socket interface now if available and requested by
5734 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5735 delayed until open-network-stream is called (w32-has-winsock can
5736 also be used to dynamically load or reload winsock).
5738 Conveniently, init_environment is called before us, so
5739 PRELOAD_WINSOCK can be set in the registry. */
5741 /* Always initialize this correctly. */
5744 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5745 init_winsock (TRUE
);
5747 /* Initial preparation for subprocess support: replace our standard
5748 handles with non-inheritable versions. */
5751 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5752 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5753 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5755 parent
= GetCurrentProcess ();
5757 /* ignore errors when duplicating and closing; typically the
5758 handles will be invalid when running as a gui program. */
5759 DuplicateHandle (parent
,
5760 GetStdHandle (STD_INPUT_HANDLE
),
5765 DUPLICATE_SAME_ACCESS
);
5767 DuplicateHandle (parent
,
5768 GetStdHandle (STD_OUTPUT_HANDLE
),
5773 DUPLICATE_SAME_ACCESS
);
5775 DuplicateHandle (parent
,
5776 GetStdHandle (STD_ERROR_HANDLE
),
5781 DUPLICATE_SAME_ACCESS
);
5787 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5788 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5790 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5793 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5794 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5796 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5799 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5800 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5802 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5806 /* unfortunately, atexit depends on implementation of malloc */
5807 /* atexit (term_ntproc); */
5808 signal (SIGABRT
, term_ntproc
);
5810 /* determine which drives are fixed, for GetCachedVolumeInformation */
5812 /* GetDriveType must have trailing backslash. */
5813 char drive
[] = "A:\\";
5815 /* Loop over all possible drive letters */
5816 while (*drive
<= 'Z')
5818 /* Record if this drive letter refers to a fixed drive. */
5819 fixed_drives
[DRIVE_INDEX (*drive
)] =
5820 (GetDriveType (drive
) == DRIVE_FIXED
);
5825 /* Reset the volume info cache. */
5826 volume_cache
= NULL
;
5829 /* Check to see if Emacs has been installed correctly. */
5830 check_windows_init_file ();
5834 shutdown_handler ensures that buffers' autosave files are
5835 up to date when the user logs off, or the system shuts down.
5838 shutdown_handler (DWORD type
)
5840 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5841 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5842 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5843 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5845 /* Shut down cleanly, making sure autosave files are up to date. */
5846 shut_down_emacs (0, 0, Qnil
);
5849 /* Allow other handlers to handle this signal. */
5854 globals_of_w32 is used to initialize those global variables that
5855 must always be initialized on startup even when the global variable
5856 initialized is non zero (see the function main in emacs.c).
5859 globals_of_w32 (void)
5861 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5863 get_process_times_fn
= (GetProcessTimes_Proc
)
5864 GetProcAddress (kernel32
, "GetProcessTimes");
5866 g_b_init_is_windows_9x
= 0;
5867 g_b_init_open_process_token
= 0;
5868 g_b_init_get_token_information
= 0;
5869 g_b_init_lookup_account_sid
= 0;
5870 g_b_init_get_sid_sub_authority
= 0;
5871 g_b_init_get_sid_sub_authority_count
= 0;
5872 g_b_init_get_file_security
= 0;
5873 g_b_init_get_security_descriptor_owner
= 0;
5874 g_b_init_get_security_descriptor_group
= 0;
5875 g_b_init_is_valid_sid
= 0;
5876 g_b_init_create_toolhelp32_snapshot
= 0;
5877 g_b_init_process32_first
= 0;
5878 g_b_init_process32_next
= 0;
5879 g_b_init_open_thread_token
= 0;
5880 g_b_init_impersonate_self
= 0;
5881 g_b_init_revert_to_self
= 0;
5882 g_b_init_get_process_memory_info
= 0;
5883 g_b_init_get_process_working_set_size
= 0;
5884 g_b_init_global_memory_status
= 0;
5885 g_b_init_global_memory_status_ex
= 0;
5886 g_b_init_equal_sid
= 0;
5887 g_b_init_copy_sid
= 0;
5888 g_b_init_get_length_sid
= 0;
5889 g_b_init_get_native_system_info
= 0;
5890 g_b_init_get_system_times
= 0;
5891 num_of_processors
= 0;
5892 /* The following sets a handler for shutdown notifications for
5893 console apps. This actually applies to Emacs in both console and
5894 GUI modes, since we had to fool windows into thinking emacs is a
5895 console application to get console mode to work. */
5896 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
5898 /* "None" is the default group name on standalone workstations. */
5899 strcpy (dflt_group_name
, "None");
5902 /* For make-serial-process */
5904 serial_open (char *port
)
5910 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5911 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5912 if (hnd
== INVALID_HANDLE_VALUE
)
5913 error ("Could not open %s", port
);
5914 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5916 error ("Could not open %s", port
);
5920 error ("Could not create child process");
5922 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5923 fd_info
[ fd
].hnd
= hnd
;
5924 fd_info
[ fd
].flags
|=
5925 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5926 if (fd_info
[ fd
].cp
!= NULL
)
5928 error ("fd_info[fd = %d] is already in use", fd
);
5930 fd_info
[ fd
].cp
= cp
;
5931 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5932 if (cp
->ovl_read
.hEvent
== NULL
)
5933 error ("Could not create read event");
5934 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5935 if (cp
->ovl_write
.hEvent
== NULL
)
5936 error ("Could not create write event");
5941 /* For serial-process-configure */
5943 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
5945 Lisp_Object childp2
= Qnil
;
5946 Lisp_Object tem
= Qnil
;
5950 char summary
[4] = "???"; /* This usually becomes "8N1". */
5952 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
5953 error ("Not a serial process");
5954 hnd
= fd_info
[ p
->outfd
].hnd
;
5956 childp2
= Fcopy_sequence (p
->childp
);
5958 /* Initialize timeouts for blocking read and blocking write. */
5959 if (!GetCommTimeouts (hnd
, &ct
))
5960 error ("GetCommTimeouts() failed");
5961 ct
.ReadIntervalTimeout
= 0;
5962 ct
.ReadTotalTimeoutMultiplier
= 0;
5963 ct
.ReadTotalTimeoutConstant
= 0;
5964 ct
.WriteTotalTimeoutMultiplier
= 0;
5965 ct
.WriteTotalTimeoutConstant
= 0;
5966 if (!SetCommTimeouts (hnd
, &ct
))
5967 error ("SetCommTimeouts() failed");
5968 /* Read port attributes and prepare default configuration. */
5969 memset (&dcb
, 0, sizeof (dcb
));
5970 dcb
.DCBlength
= sizeof (DCB
);
5971 if (!GetCommState (hnd
, &dcb
))
5972 error ("GetCommState() failed");
5975 dcb
.fAbortOnError
= FALSE
;
5976 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
5981 /* Configure speed. */
5982 if (!NILP (Fplist_member (contact
, QCspeed
)))
5983 tem
= Fplist_get (contact
, QCspeed
);
5985 tem
= Fplist_get (p
->childp
, QCspeed
);
5987 dcb
.BaudRate
= XINT (tem
);
5988 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
5990 /* Configure bytesize. */
5991 if (!NILP (Fplist_member (contact
, QCbytesize
)))
5992 tem
= Fplist_get (contact
, QCbytesize
);
5994 tem
= Fplist_get (p
->childp
, QCbytesize
);
5996 tem
= make_number (8);
5998 if (XINT (tem
) != 7 && XINT (tem
) != 8)
5999 error (":bytesize must be nil (8), 7, or 8");
6000 dcb
.ByteSize
= XINT (tem
);
6001 summary
[0] = XINT (tem
) + '0';
6002 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6004 /* Configure parity. */
6005 if (!NILP (Fplist_member (contact
, QCparity
)))
6006 tem
= Fplist_get (contact
, QCparity
);
6008 tem
= Fplist_get (p
->childp
, QCparity
);
6009 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6010 error (":parity must be nil (no parity), `even', or `odd'");
6011 dcb
.fParity
= FALSE
;
6012 dcb
.Parity
= NOPARITY
;
6013 dcb
.fErrorChar
= FALSE
;
6018 else if (EQ (tem
, Qeven
))
6022 dcb
.Parity
= EVENPARITY
;
6023 dcb
.fErrorChar
= TRUE
;
6025 else if (EQ (tem
, Qodd
))
6029 dcb
.Parity
= ODDPARITY
;
6030 dcb
.fErrorChar
= TRUE
;
6032 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6034 /* Configure stopbits. */
6035 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6036 tem
= Fplist_get (contact
, QCstopbits
);
6038 tem
= Fplist_get (p
->childp
, QCstopbits
);
6040 tem
= make_number (1);
6042 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6043 error (":stopbits must be nil (1 stopbit), 1, or 2");
6044 summary
[2] = XINT (tem
) + '0';
6045 if (XINT (tem
) == 1)
6046 dcb
.StopBits
= ONESTOPBIT
;
6047 else if (XINT (tem
) == 2)
6048 dcb
.StopBits
= TWOSTOPBITS
;
6049 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6051 /* Configure flowcontrol. */
6052 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6053 tem
= Fplist_get (contact
, QCflowcontrol
);
6055 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6056 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6057 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6058 dcb
.fOutxCtsFlow
= FALSE
;
6059 dcb
.fOutxDsrFlow
= FALSE
;
6060 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6061 dcb
.fDsrSensitivity
= FALSE
;
6062 dcb
.fTXContinueOnXoff
= FALSE
;
6065 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6066 dcb
.XonChar
= 17; /* Control-Q */
6067 dcb
.XoffChar
= 19; /* Control-S */
6070 /* Already configured. */
6072 else if (EQ (tem
, Qhw
))
6074 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6075 dcb
.fOutxCtsFlow
= TRUE
;
6077 else if (EQ (tem
, Qsw
))
6082 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6084 /* Activate configuration. */
6085 if (!SetCommState (hnd
, &dcb
))
6086 error ("SetCommState() failed");
6088 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6089 p
->childp
= childp2
;