1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23 #include <stddef.h> /* for offsetof */
26 #include <float.h> /* for DBL_EPSILON */
34 #include <sys/utime.h>
35 #include <mbstring.h> /* for _mbspbrk */
39 /* must include CRT headers *before* config.h */
74 #define _ANONYMOUS_UNION
75 #define _ANONYMOUS_STRUCT
78 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
79 use a different name to avoid compilation problems. */
80 typedef struct _MEMORY_STATUS_EX
{
83 DWORDLONG ullTotalPhys
;
84 DWORDLONG ullAvailPhys
;
85 DWORDLONG ullTotalPageFile
;
86 DWORDLONG ullAvailPageFile
;
87 DWORDLONG ullTotalVirtual
;
88 DWORDLONG ullAvailVirtual
;
89 DWORDLONG ullAvailExtendedVirtual
;
90 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
98 #if !defined(__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
99 /* This either is not in psapi.h or guarded by higher value of
100 _WIN32_WINNT than what we use. w32api suplied with MinGW 3.15
101 defines it in psapi.h */
102 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
104 DWORD PageFaultCount
;
105 DWORD PeakWorkingSetSize
;
106 DWORD WorkingSetSize
;
107 DWORD QuotaPeakPagedPoolUsage
;
108 DWORD QuotaPagedPoolUsage
;
109 DWORD QuotaPeakNonPagedPoolUsage
;
110 DWORD QuotaNonPagedPoolUsage
;
112 DWORD PeakPagefileUsage
;
114 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
117 /* TCP connection support. */
118 #include <sys/socket.h>
141 #include "dispextern.h" /* for xstrcasecmp */
142 #include "coding.h" /* for Vlocale_coding_system */
144 /* For serial_configure and serial_open. */
147 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
148 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
150 void globals_of_w32 (void);
151 static DWORD
get_rid (PSID
);
153 extern Lisp_Object Vw32_downcase_file_names
;
154 extern Lisp_Object Vw32_generate_fake_inodes
;
155 extern Lisp_Object Vw32_get_true_file_attributes
;
156 /* Defined in process.c for its own purpose. */
157 extern Lisp_Object Qlocal
;
159 extern int w32_num_mouse_buttons
;
162 /* Initialization states.
164 WARNING: If you add any more such variables for additional APIs,
165 you MUST add initialization for them to globals_of_w32
166 below. This is because these variables might get set
167 to non-NULL values during dumping, but the dumped Emacs
168 cannot reuse those values, because it could be run on a
169 different version of the OS, where API addresses are
171 static BOOL g_b_init_is_windows_9x
;
172 static BOOL g_b_init_open_process_token
;
173 static BOOL g_b_init_get_token_information
;
174 static BOOL g_b_init_lookup_account_sid
;
175 static BOOL g_b_init_get_sid_sub_authority
;
176 static BOOL g_b_init_get_sid_sub_authority_count
;
177 static BOOL g_b_init_get_file_security
;
178 static BOOL g_b_init_get_security_descriptor_owner
;
179 static BOOL g_b_init_get_security_descriptor_group
;
180 static BOOL g_b_init_is_valid_sid
;
181 static BOOL g_b_init_create_toolhelp32_snapshot
;
182 static BOOL g_b_init_process32_first
;
183 static BOOL g_b_init_process32_next
;
184 static BOOL g_b_init_open_thread_token
;
185 static BOOL g_b_init_impersonate_self
;
186 static BOOL g_b_init_revert_to_self
;
187 static BOOL g_b_init_get_process_memory_info
;
188 static BOOL g_b_init_get_process_working_set_size
;
189 static BOOL g_b_init_global_memory_status
;
190 static BOOL g_b_init_global_memory_status_ex
;
191 static BOOL g_b_init_get_length_sid
;
192 static BOOL g_b_init_equal_sid
;
193 static BOOL g_b_init_copy_sid
;
194 static BOOL g_b_init_get_native_system_info
;
195 static BOOL g_b_init_get_system_times
;
198 BEGIN: Wrapper functions around OpenProcessToken
199 and other functions in advapi32.dll that are only
200 supported in Windows NT / 2k / XP
202 /* ** Function pointer typedefs ** */
203 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
204 HANDLE ProcessHandle
,
206 PHANDLE TokenHandle
);
207 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
209 TOKEN_INFORMATION_CLASS TokenInformationClass
,
210 LPVOID TokenInformation
,
211 DWORD TokenInformationLength
,
212 PDWORD ReturnLength
);
213 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
214 HANDLE process_handle
,
215 LPFILETIME creation_time
,
216 LPFILETIME exit_time
,
217 LPFILETIME kernel_time
,
218 LPFILETIME user_time
);
220 GetProcessTimes_Proc get_process_times_fn
= NULL
;
223 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
224 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
226 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
227 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
229 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
230 LPCTSTR lpSystemName
,
235 LPDWORD cbDomainName
,
236 PSID_NAME_USE peUse
);
237 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
240 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
242 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
244 SECURITY_INFORMATION RequestedInformation
,
245 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
247 LPDWORD lpnLengthNeeded
);
248 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
249 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
251 LPBOOL lpbOwnerDefaulted
);
252 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
253 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
255 LPBOOL lpbGroupDefaulted
);
256 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
258 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
260 DWORD th32ProcessID
);
261 typedef BOOL (WINAPI
* Process32First_Proc
) (
263 LPPROCESSENTRY32 lppe
);
264 typedef BOOL (WINAPI
* Process32Next_Proc
) (
266 LPPROCESSENTRY32 lppe
);
267 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
271 PHANDLE TokenHandle
);
272 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
273 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
274 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
275 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
277 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
279 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
281 DWORD
* lpMinimumWorkingSetSize
,
282 DWORD
* lpMaximumWorkingSetSize
);
283 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
284 LPMEMORYSTATUS lpBuffer
);
285 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
286 LPMEMORY_STATUS_EX lpBuffer
);
287 typedef BOOL (WINAPI
* CopySid_Proc
) (
288 DWORD nDestinationSidLength
,
289 PSID pDestinationSid
,
291 typedef BOOL (WINAPI
* EqualSid_Proc
) (
294 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
296 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
297 LPSYSTEM_INFO lpSystemInfo
);
298 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
299 LPFILETIME lpIdleTime
,
300 LPFILETIME lpKernelTime
,
301 LPFILETIME lpUserTime
);
303 /* ** A utility function ** */
307 static BOOL s_b_ret
= 0;
308 OSVERSIONINFO os_ver
;
309 if (g_b_init_is_windows_9x
== 0)
311 g_b_init_is_windows_9x
= 1;
312 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
313 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
314 if (GetVersionEx (&os_ver
))
316 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
322 /* Get total user and system times for get-internal-run-time.
323 Returns a list of three integers if the times are provided by the OS
324 (NT derivatives), otherwise it returns the result of current-time. */
326 w32_get_internal_run_time (void)
328 if (get_process_times_fn
)
330 FILETIME create
, exit
, kernel
, user
;
331 HANDLE proc
= GetCurrentProcess ();
332 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
334 LARGE_INTEGER user_int
, kernel_int
, total
;
336 user_int
.LowPart
= user
.dwLowDateTime
;
337 user_int
.HighPart
= user
.dwHighDateTime
;
338 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
339 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
340 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
341 /* FILETIME is 100 nanosecond increments, Emacs only wants
342 microsecond resolution. */
343 total
.QuadPart
/= 10;
344 microseconds
= total
.QuadPart
% 1000000;
345 total
.QuadPart
/= 1000000;
347 /* Sanity check to make sure we can represent the result. */
348 if (total
.HighPart
== 0)
350 int secs
= total
.LowPart
;
352 return list3 (make_number ((secs
>> 16) & 0xffff),
353 make_number (secs
& 0xffff),
354 make_number (microseconds
));
359 return Fcurrent_time ();
362 /* ** The wrapper functions ** */
365 open_process_token (HANDLE ProcessHandle
,
369 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
370 HMODULE hm_advapi32
= NULL
;
371 if (is_windows_9x () == TRUE
)
375 if (g_b_init_open_process_token
== 0)
377 g_b_init_open_process_token
= 1;
378 hm_advapi32
= LoadLibrary ("Advapi32.dll");
379 s_pfn_Open_Process_Token
=
380 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
382 if (s_pfn_Open_Process_Token
== NULL
)
387 s_pfn_Open_Process_Token (
395 get_token_information (HANDLE TokenHandle
,
396 TOKEN_INFORMATION_CLASS TokenInformationClass
,
397 LPVOID TokenInformation
,
398 DWORD TokenInformationLength
,
401 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
402 HMODULE hm_advapi32
= NULL
;
403 if (is_windows_9x () == TRUE
)
407 if (g_b_init_get_token_information
== 0)
409 g_b_init_get_token_information
= 1;
410 hm_advapi32
= LoadLibrary ("Advapi32.dll");
411 s_pfn_Get_Token_Information
=
412 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
414 if (s_pfn_Get_Token_Information
== NULL
)
419 s_pfn_Get_Token_Information (
421 TokenInformationClass
,
423 TokenInformationLength
,
429 lookup_account_sid (LPCTSTR lpSystemName
,
434 LPDWORD cbDomainName
,
437 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
438 HMODULE hm_advapi32
= NULL
;
439 if (is_windows_9x () == TRUE
)
443 if (g_b_init_lookup_account_sid
== 0)
445 g_b_init_lookup_account_sid
= 1;
446 hm_advapi32
= LoadLibrary ("Advapi32.dll");
447 s_pfn_Lookup_Account_Sid
=
448 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
450 if (s_pfn_Lookup_Account_Sid
== NULL
)
455 s_pfn_Lookup_Account_Sid (
467 get_sid_sub_authority (PSID pSid
, DWORD n
)
469 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
470 static DWORD zero
= 0U;
471 HMODULE hm_advapi32
= NULL
;
472 if (is_windows_9x () == TRUE
)
476 if (g_b_init_get_sid_sub_authority
== 0)
478 g_b_init_get_sid_sub_authority
= 1;
479 hm_advapi32
= LoadLibrary ("Advapi32.dll");
480 s_pfn_Get_Sid_Sub_Authority
=
481 (GetSidSubAuthority_Proc
) GetProcAddress (
482 hm_advapi32
, "GetSidSubAuthority");
484 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
488 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
492 get_sid_sub_authority_count (PSID pSid
)
494 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
495 static UCHAR zero
= 0U;
496 HMODULE hm_advapi32
= NULL
;
497 if (is_windows_9x () == TRUE
)
501 if (g_b_init_get_sid_sub_authority_count
== 0)
503 g_b_init_get_sid_sub_authority_count
= 1;
504 hm_advapi32
= LoadLibrary ("Advapi32.dll");
505 s_pfn_Get_Sid_Sub_Authority_Count
=
506 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
507 hm_advapi32
, "GetSidSubAuthorityCount");
509 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
513 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
517 get_file_security (LPCTSTR lpFileName
,
518 SECURITY_INFORMATION RequestedInformation
,
519 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
521 LPDWORD lpnLengthNeeded
)
523 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
524 HMODULE hm_advapi32
= NULL
;
525 if (is_windows_9x () == TRUE
)
529 if (g_b_init_get_file_security
== 0)
531 g_b_init_get_file_security
= 1;
532 hm_advapi32
= LoadLibrary ("Advapi32.dll");
533 s_pfn_Get_File_Security
=
534 (GetFileSecurity_Proc
) GetProcAddress (
535 hm_advapi32
, GetFileSecurity_Name
);
537 if (s_pfn_Get_File_Security
== NULL
)
541 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
542 pSecurityDescriptor
, nLength
,
547 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
549 LPBOOL lpbOwnerDefaulted
)
551 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
552 HMODULE hm_advapi32
= NULL
;
553 if (is_windows_9x () == TRUE
)
557 if (g_b_init_get_security_descriptor_owner
== 0)
559 g_b_init_get_security_descriptor_owner
= 1;
560 hm_advapi32
= LoadLibrary ("Advapi32.dll");
561 s_pfn_Get_Security_Descriptor_Owner
=
562 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
563 hm_advapi32
, "GetSecurityDescriptorOwner");
565 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
569 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
574 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
576 LPBOOL lpbGroupDefaulted
)
578 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
579 HMODULE hm_advapi32
= NULL
;
580 if (is_windows_9x () == TRUE
)
584 if (g_b_init_get_security_descriptor_group
== 0)
586 g_b_init_get_security_descriptor_group
= 1;
587 hm_advapi32
= LoadLibrary ("Advapi32.dll");
588 s_pfn_Get_Security_Descriptor_Group
=
589 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
590 hm_advapi32
, "GetSecurityDescriptorGroup");
592 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
596 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
601 is_valid_sid (PSID sid
)
603 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
604 HMODULE hm_advapi32
= NULL
;
605 if (is_windows_9x () == TRUE
)
609 if (g_b_init_is_valid_sid
== 0)
611 g_b_init_is_valid_sid
= 1;
612 hm_advapi32
= LoadLibrary ("Advapi32.dll");
614 (IsValidSid_Proc
) GetProcAddress (
615 hm_advapi32
, "IsValidSid");
617 if (s_pfn_Is_Valid_Sid
== NULL
)
621 return (s_pfn_Is_Valid_Sid (sid
));
625 equal_sid (PSID sid1
, PSID sid2
)
627 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
628 HMODULE hm_advapi32
= NULL
;
629 if (is_windows_9x () == TRUE
)
633 if (g_b_init_equal_sid
== 0)
635 g_b_init_equal_sid
= 1;
636 hm_advapi32
= LoadLibrary ("Advapi32.dll");
638 (EqualSid_Proc
) GetProcAddress (
639 hm_advapi32
, "EqualSid");
641 if (s_pfn_Equal_Sid
== NULL
)
645 return (s_pfn_Equal_Sid (sid1
, sid2
));
649 get_length_sid (PSID sid
)
651 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
652 HMODULE hm_advapi32
= NULL
;
653 if (is_windows_9x () == TRUE
)
657 if (g_b_init_get_length_sid
== 0)
659 g_b_init_get_length_sid
= 1;
660 hm_advapi32
= LoadLibrary ("Advapi32.dll");
661 s_pfn_Get_Length_Sid
=
662 (GetLengthSid_Proc
) GetProcAddress (
663 hm_advapi32
, "GetLengthSid");
665 if (s_pfn_Get_Length_Sid
== NULL
)
669 return (s_pfn_Get_Length_Sid (sid
));
673 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
675 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
676 HMODULE hm_advapi32
= NULL
;
677 if (is_windows_9x () == TRUE
)
681 if (g_b_init_copy_sid
== 0)
683 g_b_init_copy_sid
= 1;
684 hm_advapi32
= LoadLibrary ("Advapi32.dll");
686 (CopySid_Proc
) GetProcAddress (
687 hm_advapi32
, "CopySid");
689 if (s_pfn_Copy_Sid
== NULL
)
693 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
697 END: Wrapper functions around OpenProcessToken
698 and other functions in advapi32.dll that are only
699 supported in Windows NT / 2k / XP
703 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
705 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
706 if (is_windows_9x () != TRUE
)
708 if (g_b_init_get_native_system_info
== 0)
710 g_b_init_get_native_system_info
= 1;
711 s_pfn_Get_Native_System_Info
=
712 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
713 "GetNativeSystemInfo");
715 if (s_pfn_Get_Native_System_Info
!= NULL
)
716 s_pfn_Get_Native_System_Info (lpSystemInfo
);
719 lpSystemInfo
->dwNumberOfProcessors
= -1;
723 get_system_times (LPFILETIME lpIdleTime
,
724 LPFILETIME lpKernelTime
,
725 LPFILETIME lpUserTime
)
727 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
728 if (is_windows_9x () == TRUE
)
732 if (g_b_init_get_system_times
== 0)
734 g_b_init_get_system_times
= 1;
735 s_pfn_Get_System_times
=
736 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
739 if (s_pfn_Get_System_times
== NULL
)
741 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
744 /* Equivalent of strerror for W32 error codes. */
746 w32_strerror (int error_no
)
748 static char buf
[500];
751 error_no
= GetLastError ();
754 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
756 0, /* choose most suitable language */
757 buf
, sizeof (buf
), NULL
))
758 sprintf (buf
, "w32 error %u", error_no
);
762 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
763 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
765 This is called from alloc.c:valid_pointer_p. */
767 w32_valid_pointer_p (void *p
, int size
)
770 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
774 unsigned char *buf
= alloca (size
);
775 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
784 static char startup_dir
[MAXPATHLEN
];
786 /* Get the current working directory. */
791 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
795 /* Emacs doesn't actually change directory itself, and we want to
796 force our real wd to be where emacs.exe is to avoid unnecessary
797 conflicts when trying to rename or delete directories. */
798 strcpy (dir
, startup_dir
);
803 /* Emulate getloadavg. */
812 /* Number of processors on this machine. */
813 static unsigned num_of_processors
;
815 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
816 static struct load_sample samples
[16*60];
817 static int first_idx
= -1, last_idx
= -1;
818 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
823 int next_idx
= from
+ 1;
825 if (next_idx
>= max_idx
)
834 int prev_idx
= from
- 1;
837 prev_idx
= max_idx
- 1;
843 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
846 FILETIME ft_idle
, ft_user
, ft_kernel
;
848 /* Initialize the number of processors on this machine. */
849 if (num_of_processors
<= 0)
851 get_native_system_info (&sysinfo
);
852 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
853 if (num_of_processors
<= 0)
855 GetSystemInfo (&sysinfo
);
856 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
858 if (num_of_processors
<= 0)
859 num_of_processors
= 1;
862 /* TODO: Take into account threads that are ready to run, by
863 sampling the "\System\Processor Queue Length" performance
864 counter. The code below accounts only for threads that are
867 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
869 ULARGE_INTEGER uidle
, ukernel
, uuser
;
871 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
872 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
873 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
874 *idle
= uidle
.QuadPart
;
875 *kernel
= ukernel
.QuadPart
;
876 *user
= uuser
.QuadPart
;
886 /* Produce the load average for a given time interval, using the
887 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
888 1-minute, 5-minute, or 15-minute average, respectively. */
892 double retval
= -1.0;
895 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
896 time_t now
= samples
[last_idx
].sample_time
;
898 if (first_idx
!= last_idx
)
900 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
902 tdiff
= difftime (now
, samples
[idx
].sample_time
);
903 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
906 samples
[last_idx
].kernel
+ samples
[last_idx
].user
907 - (samples
[idx
].kernel
+ samples
[idx
].user
);
908 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
910 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
913 if (idx
== first_idx
)
922 getloadavg (double loadavg
[], int nelem
)
925 ULONGLONG idle
, kernel
, user
;
926 time_t now
= time (NULL
);
928 /* Store another sample. We ignore samples that are less than 1 sec
930 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
932 sample_system_load (&idle
, &kernel
, &user
);
933 last_idx
= buf_next (last_idx
);
934 samples
[last_idx
].sample_time
= now
;
935 samples
[last_idx
].idle
= idle
;
936 samples
[last_idx
].kernel
= kernel
;
937 samples
[last_idx
].user
= user
;
938 /* If the buffer has more that 15 min worth of samples, discard
941 first_idx
= last_idx
;
942 while (first_idx
!= last_idx
943 && (difftime (now
, samples
[first_idx
].sample_time
)
944 >= 15.0*60 + 2*DBL_EPSILON
*now
))
945 first_idx
= buf_next (first_idx
);
948 for (elem
= 0; elem
< nelem
; elem
++)
950 double avg
= getavg (elem
);
960 /* Emulate getpwuid, getpwnam and others. */
962 #define PASSWD_FIELD_SIZE 256
964 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
965 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
966 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
967 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
968 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
970 static struct passwd dflt_passwd
=
982 static char dflt_group_name
[GNLEN
+1];
984 static struct group dflt_group
=
986 /* When group information is not available, we return this as the
987 group for all files. */
995 return dflt_passwd
.pw_uid
;
1001 /* I could imagine arguing for checking to see whether the user is
1002 in the Administrators group and returning a UID of 0 for that
1003 case, but I don't know how wise that would be in the long run. */
1010 return dflt_passwd
.pw_gid
;
1020 getpwuid (unsigned uid
)
1022 if (uid
== dflt_passwd
.pw_uid
)
1023 return &dflt_passwd
;
1028 getgrgid (gid_t gid
)
1034 getpwnam (char *name
)
1038 pw
= getpwuid (getuid ());
1042 if (xstrcasecmp (name
, pw
->pw_name
))
1049 init_user_info (void)
1051 /* Find the user's real name by opening the process token and
1052 looking up the name associated with the user-sid in that token.
1054 Use the relative portion of the identifier authority value from
1055 the user-sid as the user id value (same for group id using the
1056 primary group sid from the process token). */
1058 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1059 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1060 DWORD glength
= sizeof (gname
);
1061 HANDLE token
= NULL
;
1062 SID_NAME_USE user_type
;
1063 unsigned char *buf
= NULL
;
1065 TOKEN_USER user_token
;
1066 TOKEN_PRIMARY_GROUP group_token
;
1069 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1072 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1073 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1075 buf
= xmalloc (blen
);
1076 result
= get_token_information (token
, TokenUser
,
1077 (LPVOID
)buf
, blen
, &needed
);
1080 memcpy (&user_token
, buf
, sizeof (user_token
));
1081 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1083 domain
, &dlength
, &user_type
);
1091 strcpy (dflt_passwd
.pw_name
, uname
);
1092 /* Determine a reasonable uid value. */
1093 if (xstrcasecmp ("administrator", uname
) == 0)
1095 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1096 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1100 /* Use the last sub-authority value of the RID, the relative
1101 portion of the SID, as user/group ID. */
1102 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1104 /* Get group id and name. */
1105 result
= get_token_information (token
, TokenPrimaryGroup
,
1106 (LPVOID
)buf
, blen
, &needed
);
1107 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1109 buf
= xrealloc (buf
, blen
= needed
);
1110 result
= get_token_information (token
, TokenPrimaryGroup
,
1111 (LPVOID
)buf
, blen
, &needed
);
1115 memcpy (&group_token
, buf
, sizeof (group_token
));
1116 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1117 dlength
= sizeof (domain
);
1118 /* If we can get at the real Primary Group name, use that.
1119 Otherwise, the default group name was already set to
1120 "None" in globals_of_w32. */
1121 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1122 gname
, &glength
, NULL
, &dlength
,
1124 strcpy (dflt_group_name
, gname
);
1127 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1130 /* If security calls are not supported (presumably because we
1131 are running under Windows 9X), fallback to this: */
1132 else if (GetUserName (uname
, &ulength
))
1134 strcpy (dflt_passwd
.pw_name
, uname
);
1135 if (xstrcasecmp ("administrator", uname
) == 0)
1136 dflt_passwd
.pw_uid
= 0;
1138 dflt_passwd
.pw_uid
= 123;
1139 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1143 strcpy (dflt_passwd
.pw_name
, "unknown");
1144 dflt_passwd
.pw_uid
= 123;
1145 dflt_passwd
.pw_gid
= 123;
1147 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1149 /* Ensure HOME and SHELL are defined. */
1150 if (getenv ("HOME") == NULL
)
1152 if (getenv ("SHELL") == NULL
)
1155 /* Set dir and shell from environment variables. */
1156 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1157 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1161 CloseHandle (token
);
1167 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1168 return ((rand () << 15) | rand ());
1178 /* Normalize filename by converting all path separators to
1179 the specified separator. Also conditionally convert upper
1180 case path name components to lower case. */
1183 normalize_filename (register char *fp
, char path_sep
)
1188 /* Always lower-case drive letters a-z, even if the filesystem
1189 preserves case in filenames.
1190 This is so filenames can be compared by string comparison
1191 functions that are case-sensitive. Even case-preserving filesystems
1192 do not distinguish case in drive letters. */
1193 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1199 if (NILP (Vw32_downcase_file_names
))
1203 if (*fp
== '/' || *fp
== '\\')
1210 sep
= path_sep
; /* convert to this path separator */
1211 elem
= fp
; /* start of current path element */
1214 if (*fp
>= 'a' && *fp
<= 'z')
1215 elem
= 0; /* don't convert this element */
1217 if (*fp
== 0 || *fp
== ':')
1219 sep
= *fp
; /* restore current separator (or 0) */
1220 *fp
= '/'; /* after conversion of this element */
1223 if (*fp
== '/' || *fp
== '\\')
1225 if (elem
&& elem
!= fp
)
1227 *fp
= 0; /* temporary end of string */
1228 _strlwr (elem
); /* while we convert to lower case */
1230 *fp
= sep
; /* convert (or restore) path separator */
1231 elem
= fp
+ 1; /* next element starts after separator */
1237 /* Destructively turn backslashes into slashes. */
1239 dostounix_filename (register char *p
)
1241 normalize_filename (p
, '/');
1244 /* Destructively turn slashes into backslashes. */
1246 unixtodos_filename (register char *p
)
1248 normalize_filename (p
, '\\');
1251 /* Remove all CR's that are followed by a LF.
1252 (From msdos.c...probably should figure out a way to share it,
1253 although this code isn't going to ever change.) */
1255 crlf_to_lf (register int n
, register unsigned char *buf
)
1257 unsigned char *np
= buf
;
1258 unsigned char *startp
= buf
;
1259 unsigned char *endp
= buf
+ n
;
1263 while (buf
< endp
- 1)
1267 if (*(++buf
) != 0x0a)
1278 /* Parse the root part of file name, if present. Return length and
1279 optionally store pointer to char after root. */
1281 parse_root (char * name
, char ** pPath
)
1283 char * start
= name
;
1288 /* find the root name of the volume if given */
1289 if (isalpha (name
[0]) && name
[1] == ':')
1291 /* skip past drive specifier */
1293 if (IS_DIRECTORY_SEP (name
[0]))
1296 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1302 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1307 if (IS_DIRECTORY_SEP (name
[0]))
1314 return name
- start
;
1317 /* Get long base name for name; name is assumed to be absolute. */
1319 get_long_basename (char * name
, char * buf
, int size
)
1321 WIN32_FIND_DATA find_data
;
1325 /* must be valid filename, no wild cards or other invalid characters */
1326 if (_mbspbrk (name
, "*?|<>\""))
1329 dir_handle
= FindFirstFile (name
, &find_data
);
1330 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1332 if ((len
= strlen (find_data
.cFileName
)) < size
)
1333 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1336 FindClose (dir_handle
);
1341 /* Get long name for file, if possible (assumed to be absolute). */
1343 w32_get_long_filename (char * name
, char * buf
, int size
)
1348 char full
[ MAX_PATH
];
1351 len
= strlen (name
);
1352 if (len
>= MAX_PATH
)
1355 /* Use local copy for destructive modification. */
1356 memcpy (full
, name
, len
+1);
1357 unixtodos_filename (full
);
1359 /* Copy root part verbatim. */
1360 len
= parse_root (full
, &p
);
1361 memcpy (o
, full
, len
);
1366 while (p
!= NULL
&& *p
)
1369 p
= strchr (q
, '\\');
1371 len
= get_long_basename (full
, o
, size
);
1394 is_unc_volume (const char *filename
)
1396 const char *ptr
= filename
;
1398 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1401 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1407 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1410 sigsetmask (int signal_mask
)
1428 sigunblock (int sig
)
1434 sigemptyset (sigset_t
*set
)
1440 sigaddset (sigset_t
*set
, int signo
)
1446 sigfillset (sigset_t
*set
)
1452 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1458 setpgrp (int pid
, int gid
)
1469 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1472 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1475 HKEY hrootkey
= NULL
;
1478 /* Check both the current user and the local machine to see if
1479 we have any resources. */
1481 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1485 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1486 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1487 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1489 RegCloseKey (hrootkey
);
1495 RegCloseKey (hrootkey
);
1498 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1502 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1503 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1504 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1506 RegCloseKey (hrootkey
);
1512 RegCloseKey (hrootkey
);
1518 char *get_emacs_configuration (void);
1519 extern Lisp_Object Vsystem_configuration
;
1522 init_environment (char ** argv
)
1524 static const char * const tempdirs
[] = {
1525 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1530 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1532 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1533 temporary files and assume "/tmp" if $TMPDIR is unset, which
1534 will break on DOS/Windows. Refuse to work if we cannot find
1535 a directory, not even "c:/", usable for that purpose. */
1536 for (i
= 0; i
< imax
; i
++)
1538 const char *tmp
= tempdirs
[i
];
1541 tmp
= getenv (tmp
+ 1);
1542 /* Note that `access' can lie to us if the directory resides on a
1543 read-only filesystem, like CD-ROM or a write-protected floppy.
1544 The only way to be really sure is to actually create a file and
1545 see if it succeeds. But I think that's too much to ask. */
1546 if (tmp
&& _access (tmp
, D_OK
) == 0)
1548 char * var
= alloca (strlen (tmp
) + 8);
1549 sprintf (var
, "TMPDIR=%s", tmp
);
1550 _putenv (strdup (var
));
1557 Fcons (build_string ("no usable temporary directories found!!"),
1559 "While setting TMPDIR: ");
1561 /* Check for environment variables and use registry settings if they
1562 don't exist. Fallback on default values where applicable. */
1567 char locale_name
[32];
1568 struct stat ignored
;
1569 char default_home
[MAX_PATH
];
1571 static const struct env_entry
1578 {"PRELOAD_WINSOCK", NULL
},
1579 {"emacs_dir", "C:/emacs"},
1580 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1581 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1582 {"EMACSDATA", "%emacs_dir%/etc"},
1583 {"EMACSPATH", "%emacs_dir%/bin"},
1584 /* We no longer set INFOPATH because Info-default-directory-list
1586 /* {"INFOPATH", "%emacs_dir%/info"}, */
1587 {"EMACSDOC", "%emacs_dir%/etc"},
1592 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1594 /* We need to copy dflt_envvars[] and work on the copy because we
1595 don't want the dumped Emacs to inherit the values of
1596 environment variables we saw during dumping (which could be on
1597 a different system). The defaults above must be left intact. */
1598 struct env_entry env_vars
[N_ENV_VARS
];
1600 for (i
= 0; i
< N_ENV_VARS
; i
++)
1601 env_vars
[i
] = dflt_envvars
[i
];
1603 /* For backwards compatibility, check if a .emacs file exists in C:/
1604 If not, then we can try to default to the appdata directory under the
1605 user's profile, which is more likely to be writable. */
1606 if (stat ("C:/.emacs", &ignored
) < 0)
1608 HRESULT profile_result
;
1609 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1610 of Windows 95 and NT4 that have not been updated to include
1612 ShGetFolderPath_fn get_folder_path
;
1613 get_folder_path
= (ShGetFolderPath_fn
)
1614 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1616 if (get_folder_path
!= NULL
)
1618 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1621 /* If we can't get the appdata dir, revert to old behavior. */
1622 if (profile_result
== S_OK
)
1623 env_vars
[0].def_value
= default_home
;
1627 /* Get default locale info and use it for LANG. */
1628 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1629 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1630 locale_name
, sizeof (locale_name
)))
1632 for (i
= 0; i
< N_ENV_VARS
; i
++)
1634 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1636 env_vars
[i
].def_value
= locale_name
;
1642 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1644 /* Treat emacs_dir specially: set it unconditionally based on our
1645 location, if it appears that we are running from the bin subdir
1646 of a standard installation. */
1649 char modname
[MAX_PATH
];
1651 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1653 if ((p
= strrchr (modname
, '\\')) == NULL
)
1657 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1659 char buf
[SET_ENV_BUF_SIZE
];
1662 for (p
= modname
; *p
; p
++)
1663 if (*p
== '\\') *p
= '/';
1665 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1666 _putenv (strdup (buf
));
1668 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1670 /* FIXME: should use substring of get_emacs_configuration ().
1671 But I don't think the Windows build supports alpha, mips etc
1672 anymore, so have taken the easy option for now. */
1673 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1676 p
= strrchr (modname
, '\\');
1680 p
= strrchr (modname
, '\\');
1681 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1683 char buf
[SET_ENV_BUF_SIZE
];
1686 for (p
= modname
; *p
; p
++)
1687 if (*p
== '\\') *p
= '/';
1689 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1690 _putenv (strdup (buf
));
1696 for (i
= 0; i
< N_ENV_VARS
; i
++)
1698 if (!getenv (env_vars
[i
].name
))
1702 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1703 /* Also ignore empty environment variables. */
1707 lpval
= env_vars
[i
].def_value
;
1708 dwType
= REG_EXPAND_SZ
;
1714 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1716 if (dwType
== REG_EXPAND_SZ
)
1717 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1718 else if (dwType
== REG_SZ
)
1719 strcpy (buf1
, lpval
);
1720 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1722 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1724 _putenv (strdup (buf2
));
1734 /* Rebuild system configuration to reflect invoking system. */
1735 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1737 /* Another special case: on NT, the PATH variable is actually named
1738 "Path" although cmd.exe (perhaps NT itself) arranges for
1739 environment variable lookup and setting to be case insensitive.
1740 However, Emacs assumes a fully case sensitive environment, so we
1741 need to change "Path" to "PATH" to match the expectations of
1742 various elisp packages. We do this by the sneaky method of
1743 modifying the string in the C runtime environ entry.
1745 The same applies to COMSPEC. */
1749 for (envp
= environ
; *envp
; envp
++)
1750 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1751 memcpy (*envp
, "PATH=", 5);
1752 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1753 memcpy (*envp
, "COMSPEC=", 8);
1756 /* Remember the initial working directory for getwd, then make the
1757 real wd be the location of emacs.exe to avoid conflicts when
1758 renaming or deleting directories. (We also don't call chdir when
1759 running subprocesses for the same reason.) */
1760 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1765 static char modname
[MAX_PATH
];
1767 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1769 if ((p
= strrchr (modname
, '\\')) == NULL
)
1773 SetCurrentDirectory (modname
);
1775 /* Ensure argv[0] has the full path to Emacs. */
1780 /* Determine if there is a middle mouse button, to allow parse_button
1781 to decide whether right mouse events should be mouse-2 or
1783 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1789 emacs_root_dir (void)
1791 static char root_dir
[FILENAME_MAX
];
1794 p
= getenv ("emacs_dir");
1797 strcpy (root_dir
, p
);
1798 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1799 dostounix_filename (root_dir
);
1803 /* We don't have scripts to automatically determine the system configuration
1804 for Emacs before it's compiled, and we don't want to have to make the
1805 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1809 get_emacs_configuration (void)
1811 char *arch
, *oem
, *os
;
1813 static char configuration_buffer
[32];
1815 /* Determine the processor type. */
1816 switch (get_processor_type ())
1819 #ifdef PROCESSOR_INTEL_386
1820 case PROCESSOR_INTEL_386
:
1821 case PROCESSOR_INTEL_486
:
1822 case PROCESSOR_INTEL_PENTIUM
:
1827 #ifdef PROCESSOR_MIPS_R2000
1828 case PROCESSOR_MIPS_R2000
:
1829 case PROCESSOR_MIPS_R3000
:
1830 case PROCESSOR_MIPS_R4000
:
1835 #ifdef PROCESSOR_ALPHA_21064
1836 case PROCESSOR_ALPHA_21064
:
1846 /* Use the OEM field to reflect the compiler/library combination. */
1848 #define COMPILER_NAME "msvc"
1851 #define COMPILER_NAME "mingw"
1853 #define COMPILER_NAME "unknown"
1856 oem
= COMPILER_NAME
;
1858 switch (osinfo_cache
.dwPlatformId
) {
1859 case VER_PLATFORM_WIN32_NT
:
1861 build_num
= osinfo_cache
.dwBuildNumber
;
1863 case VER_PLATFORM_WIN32_WINDOWS
:
1864 if (osinfo_cache
.dwMinorVersion
== 0) {
1869 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1871 case VER_PLATFORM_WIN32s
:
1872 /* Not supported, should not happen. */
1874 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1882 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1883 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1884 get_w32_major_version (), get_w32_minor_version (), build_num
);
1886 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1889 return configuration_buffer
;
1893 get_emacs_configuration_options (void)
1895 static char *options_buffer
;
1896 char cv
[32]; /* Enough for COMPILER_VERSION. */
1898 cv
, /* To be filled later. */
1902 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1903 with a starting space to save work here. */
1905 " --cflags", USER_CFLAGS
,
1908 " --ldflags", USER_LDFLAGS
,
1915 /* Work out the effective configure options for this build. */
1917 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1920 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1922 #define COMPILER_VERSION ""
1926 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
1927 return "Error: not enough space for compiler version";
1928 cv
[sizeof (cv
) - 1] = '\0';
1930 for (i
= 0; options
[i
]; i
++)
1931 size
+= strlen (options
[i
]);
1933 options_buffer
= xmalloc (size
+ 1);
1934 options_buffer
[0] = '\0';
1936 for (i
= 0; options
[i
]; i
++)
1937 strcat (options_buffer
, options
[i
]);
1939 return options_buffer
;
1943 #include <sys/timeb.h>
1945 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1947 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1952 tv
->tv_sec
= tb
.time
;
1953 tv
->tv_usec
= tb
.millitm
* 1000L;
1956 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1957 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1961 /* ------------------------------------------------------------------------- */
1962 /* IO support and wrapper functions for W32 API. */
1963 /* ------------------------------------------------------------------------- */
1965 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1966 on network directories, so we handle that case here.
1967 (Ulrich Leodolter, 1/11/95). */
1969 sys_ctime (const time_t *t
)
1971 char *str
= (char *) ctime (t
);
1972 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1975 /* Emulate sleep...we could have done this with a define, but that
1976 would necessitate including windows.h in the files that used it.
1977 This is much easier. */
1979 sys_sleep (int seconds
)
1981 Sleep (seconds
* 1000);
1984 /* Internal MSVC functions for low-level descriptor munging */
1985 extern int __cdecl
_set_osfhnd (int fd
, long h
);
1986 extern int __cdecl
_free_osfhnd (int fd
);
1988 /* parallel array of private info on file handles */
1989 filedesc fd_info
[ MAXDESC
];
1991 typedef struct volume_info_data
{
1992 struct volume_info_data
* next
;
1994 /* time when info was obtained */
1997 /* actual volume info */
2006 /* Global referenced by various functions. */
2007 static volume_info_data volume_info
;
2009 /* Vector to indicate which drives are local and fixed (for which cached
2010 data never expires). */
2011 static BOOL fixed_drives
[26];
2013 /* Consider cached volume information to be stale if older than 10s,
2014 at least for non-local drives. Info for fixed drives is never stale. */
2015 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2016 #define VOLINFO_STILL_VALID( root_dir, info ) \
2017 ( ( isalpha (root_dir[0]) && \
2018 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2019 || GetTickCount () - info->timestamp < 10000 )
2021 /* Cache support functions. */
2023 /* Simple linked list with linear search is sufficient. */
2024 static volume_info_data
*volume_cache
= NULL
;
2026 static volume_info_data
*
2027 lookup_volume_info (char * root_dir
)
2029 volume_info_data
* info
;
2031 for (info
= volume_cache
; info
; info
= info
->next
)
2032 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2038 add_volume_info (char * root_dir
, volume_info_data
* info
)
2040 info
->root_dir
= xstrdup (root_dir
);
2041 info
->next
= volume_cache
;
2042 volume_cache
= info
;
2046 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2047 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2048 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2049 static volume_info_data
*
2050 GetCachedVolumeInformation (char * root_dir
)
2052 volume_info_data
* info
;
2053 char default_root
[ MAX_PATH
];
2055 /* NULL for root_dir means use root from current directory. */
2056 if (root_dir
== NULL
)
2058 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2060 parse_root (default_root
, &root_dir
);
2062 root_dir
= default_root
;
2065 /* Local fixed drives can be cached permanently. Removable drives
2066 cannot be cached permanently, since the volume name and serial
2067 number (if nothing else) can change. Remote drives should be
2068 treated as if they are removable, since there is no sure way to
2069 tell whether they are or not. Also, the UNC association of drive
2070 letters mapped to remote volumes can be changed at any time (even
2071 by other processes) without notice.
2073 As a compromise, so we can benefit from caching info for remote
2074 volumes, we use a simple expiry mechanism to invalidate cache
2075 entries that are more than ten seconds old. */
2078 /* No point doing this, because WNetGetConnection is even slower than
2079 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2080 GetDriveType is about the only call of this type which does not
2081 involve network access, and so is extremely quick). */
2083 /* Map drive letter to UNC if remote. */
2084 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2086 char remote_name
[ 256 ];
2087 char drive
[3] = { root_dir
[0], ':' };
2089 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2091 /* do something */ ;
2095 info
= lookup_volume_info (root_dir
);
2097 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2105 /* Info is not cached, or is stale. */
2106 if (!GetVolumeInformation (root_dir
,
2107 name
, sizeof (name
),
2111 type
, sizeof (type
)))
2114 /* Cache the volume information for future use, overwriting existing
2115 entry if present. */
2118 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2119 add_volume_info (root_dir
, info
);
2127 info
->name
= xstrdup (name
);
2128 info
->serialnum
= serialnum
;
2129 info
->maxcomp
= maxcomp
;
2130 info
->flags
= flags
;
2131 info
->type
= xstrdup (type
);
2132 info
->timestamp
= GetTickCount ();
2138 /* Get information on the volume where name is held; set path pointer to
2139 start of pathname in name (past UNC header\volume header if present). */
2141 get_volume_info (const char * name
, const char ** pPath
)
2143 char temp
[MAX_PATH
];
2144 char *rootname
= NULL
; /* default to current volume */
2145 volume_info_data
* info
;
2150 /* find the root name of the volume if given */
2151 if (isalpha (name
[0]) && name
[1] == ':')
2159 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2166 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2179 info
= GetCachedVolumeInformation (rootname
);
2182 /* Set global referenced by other functions. */
2183 volume_info
= *info
;
2189 /* Determine if volume is FAT format (ie. only supports short 8.3
2190 names); also set path pointer to start of pathname in name. */
2192 is_fat_volume (const char * name
, const char ** pPath
)
2194 if (get_volume_info (name
, pPath
))
2195 return (volume_info
.maxcomp
== 12);
2199 /* Map filename to a valid 8.3 name if necessary. */
2201 map_w32_filename (const char * name
, const char ** pPath
)
2203 static char shortname
[MAX_PATH
];
2204 char * str
= shortname
;
2207 const char * save_name
= name
;
2209 if (strlen (name
) >= MAX_PATH
)
2211 /* Return a filename which will cause callers to fail. */
2212 strcpy (shortname
, "?");
2216 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2218 register int left
= 8; /* maximum number of chars in part */
2219 register int extn
= 0; /* extension added? */
2220 register int dots
= 2; /* maximum number of dots allowed */
2223 *str
++ = *name
++; /* skip past UNC header */
2225 while ((c
= *name
++))
2232 extn
= 0; /* reset extension flags */
2233 dots
= 2; /* max 2 dots */
2234 left
= 8; /* max length 8 for main part */
2238 extn
= 0; /* reset extension flags */
2239 dots
= 2; /* max 2 dots */
2240 left
= 8; /* max length 8 for main part */
2245 /* Convert path components of the form .xxx to _xxx,
2246 but leave . and .. as they are. This allows .emacs
2247 to be read as _emacs, for example. */
2251 IS_DIRECTORY_SEP (*name
))
2266 extn
= 1; /* we've got an extension */
2267 left
= 3; /* 3 chars in extension */
2271 /* any embedded dots after the first are converted to _ */
2276 case '#': /* don't lose these, they're important */
2278 str
[-1] = c
; /* replace last character of part */
2283 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2285 dots
= 0; /* started a path component */
2294 strcpy (shortname
, name
);
2295 unixtodos_filename (shortname
);
2299 *pPath
= shortname
+ (path
- save_name
);
2305 is_exec (const char * name
)
2307 char * p
= strrchr (name
, '.');
2310 && (xstrcasecmp (p
, ".exe") == 0 ||
2311 xstrcasecmp (p
, ".com") == 0 ||
2312 xstrcasecmp (p
, ".bat") == 0 ||
2313 xstrcasecmp (p
, ".cmd") == 0));
2316 /* Emulate the Unix directory procedures opendir, closedir,
2317 and readdir. We can't use the procedures supplied in sysdep.c,
2318 so we provide them here. */
2320 struct direct dir_static
; /* simulated directory contents */
2321 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2322 static int dir_is_fat
;
2323 static char dir_pathname
[MAXPATHLEN
+1];
2324 static WIN32_FIND_DATA dir_find_data
;
2326 /* Support shares on a network resource as subdirectories of a read-only
2328 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2329 static HANDLE
open_unc_volume (const char *);
2330 static char *read_unc_volume (HANDLE
, char *, int);
2331 static void close_unc_volume (HANDLE
);
2334 opendir (char *filename
)
2338 /* Opening is done by FindFirstFile. However, a read is inherent to
2339 this operation, so we defer the open until read time. */
2341 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2343 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2346 if (is_unc_volume (filename
))
2348 wnet_enum_handle
= open_unc_volume (filename
);
2349 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2353 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2360 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2361 dir_pathname
[MAXPATHLEN
] = '\0';
2362 dir_is_fat
= is_fat_volume (filename
, NULL
);
2368 closedir (DIR *dirp
)
2370 /* If we have a find-handle open, close it. */
2371 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2373 FindClose (dir_find_handle
);
2374 dir_find_handle
= INVALID_HANDLE_VALUE
;
2376 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2378 close_unc_volume (wnet_enum_handle
);
2379 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2381 xfree ((char *) dirp
);
2387 int downcase
= !NILP (Vw32_downcase_file_names
);
2389 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2391 if (!read_unc_volume (wnet_enum_handle
,
2392 dir_find_data
.cFileName
,
2396 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2397 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2399 char filename
[MAXNAMLEN
+ 3];
2402 strcpy (filename
, dir_pathname
);
2403 ln
= strlen (filename
) - 1;
2404 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2405 strcat (filename
, "\\");
2406 strcat (filename
, "*");
2408 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2410 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2415 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2419 /* Emacs never uses this value, so don't bother making it match
2420 value returned by stat(). */
2421 dir_static
.d_ino
= 1;
2423 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2425 /* If the file name in cFileName[] includes `?' characters, it means
2426 the original file name used characters that cannot be represented
2427 by the current ANSI codepage. To avoid total lossage, retrieve
2428 the short 8+3 alias of the long file name. */
2429 if (_mbspbrk (dir_static
.d_name
, "?"))
2431 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2432 downcase
= 1; /* 8+3 aliases are returned in all caps */
2434 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2435 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2436 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2438 /* If the file name in cFileName[] includes `?' characters, it means
2439 the original file name used characters that cannot be represented
2440 by the current ANSI codepage. To avoid total lossage, retrieve
2441 the short 8+3 alias of the long file name. */
2442 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2444 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2445 /* 8+3 aliases are returned in all caps, which could break
2446 various alists that look at filenames' extensions. */
2450 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2451 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2453 _strlwr (dir_static
.d_name
);
2457 for (p
= dir_static
.d_name
; *p
; p
++)
2458 if (*p
>= 'a' && *p
<= 'z')
2461 _strlwr (dir_static
.d_name
);
2468 open_unc_volume (const char *path
)
2474 nr
.dwScope
= RESOURCE_GLOBALNET
;
2475 nr
.dwType
= RESOURCETYPE_DISK
;
2476 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2477 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2478 nr
.lpLocalName
= NULL
;
2479 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2480 nr
.lpComment
= NULL
;
2481 nr
.lpProvider
= NULL
;
2483 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2484 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2486 if (result
== NO_ERROR
)
2489 return INVALID_HANDLE_VALUE
;
2493 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2497 DWORD bufsize
= 512;
2502 buffer
= alloca (bufsize
);
2503 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2504 if (result
!= NO_ERROR
)
2507 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2508 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2510 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2513 strncpy (readbuf
, ptr
, size
);
2518 close_unc_volume (HANDLE henum
)
2520 if (henum
!= INVALID_HANDLE_VALUE
)
2521 WNetCloseEnum (henum
);
2525 unc_volume_file_attributes (const char *path
)
2530 henum
= open_unc_volume (path
);
2531 if (henum
== INVALID_HANDLE_VALUE
)
2534 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2536 close_unc_volume (henum
);
2541 /* Ensure a network connection is authenticated. */
2543 logon_network_drive (const char *path
)
2545 NETRESOURCE resource
;
2546 char share
[MAX_PATH
];
2551 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2552 drvtype
= DRIVE_REMOTE
;
2553 else if (path
[0] == '\0' || path
[1] != ':')
2554 drvtype
= GetDriveType (NULL
);
2561 drvtype
= GetDriveType (drive
);
2564 /* Only logon to networked drives. */
2565 if (drvtype
!= DRIVE_REMOTE
)
2569 strncpy (share
, path
, MAX_PATH
);
2570 /* Truncate to just server and share name. */
2571 for (i
= 2; i
< MAX_PATH
; i
++)
2573 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2580 resource
.dwType
= RESOURCETYPE_DISK
;
2581 resource
.lpLocalName
= NULL
;
2582 resource
.lpRemoteName
= share
;
2583 resource
.lpProvider
= NULL
;
2585 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2588 /* Shadow some MSVC runtime functions to map requests for long filenames
2589 to reasonable short names if necessary. This was originally added to
2590 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2594 sys_access (const char * path
, int mode
)
2598 /* MSVC implementation doesn't recognize D_OK. */
2599 path
= map_w32_filename (path
, NULL
);
2600 if (is_unc_volume (path
))
2602 attributes
= unc_volume_file_attributes (path
);
2603 if (attributes
== -1) {
2608 else if ((attributes
= GetFileAttributes (path
)) == -1)
2610 /* Should try mapping GetLastError to errno; for now just indicate
2611 that path doesn't exist. */
2615 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2620 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2625 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2634 sys_chdir (const char * path
)
2636 return _chdir (map_w32_filename (path
, NULL
));
2640 sys_chmod (const char * path
, int mode
)
2642 return _chmod (map_w32_filename (path
, NULL
), mode
);
2646 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2648 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2654 sys_creat (const char * path
, int mode
)
2656 return _creat (map_w32_filename (path
, NULL
), mode
);
2660 sys_fopen (const char * path
, const char * mode
)
2664 const char * mode_save
= mode
;
2666 /* Force all file handles to be non-inheritable. This is necessary to
2667 ensure child processes don't unwittingly inherit handles that might
2668 prevent future file access. */
2672 else if (mode
[0] == 'w' || mode
[0] == 'a')
2673 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2677 /* Only do simplistic option parsing. */
2681 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2684 else if (mode
[0] == 'b')
2689 else if (mode
[0] == 't')
2696 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2700 return _fdopen (fd
, mode_save
);
2703 /* This only works on NTFS volumes, but is useful to have. */
2705 sys_link (const char * old
, const char * new)
2709 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2711 if (old
== NULL
|| new == NULL
)
2717 strcpy (oldname
, map_w32_filename (old
, NULL
));
2718 strcpy (newname
, map_w32_filename (new, NULL
));
2720 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2721 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2722 if (fileh
!= INVALID_HANDLE_VALUE
)
2726 /* Confusingly, the "alternate" stream name field does not apply
2727 when restoring a hard link, and instead contains the actual
2728 stream data for the link (ie. the name of the link to create).
2729 The WIN32_STREAM_ID structure before the cStreamName field is
2730 the stream header, which is then immediately followed by the
2734 WIN32_STREAM_ID wid
;
2735 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2738 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2739 data
.wid
.cStreamName
, MAX_PATH
);
2742 LPVOID context
= NULL
;
2745 data
.wid
.dwStreamId
= BACKUP_LINK
;
2746 data
.wid
.dwStreamAttributes
= 0;
2747 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2748 data
.wid
.Size
.HighPart
= 0;
2749 data
.wid
.dwStreamNameSize
= 0;
2751 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2752 offsetof (WIN32_STREAM_ID
, cStreamName
)
2753 + data
.wid
.Size
.LowPart
,
2754 &wbytes
, FALSE
, FALSE
, &context
)
2755 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2762 /* Should try mapping GetLastError to errno; for now just
2763 indicate a general error (eg. links not supported). */
2764 errno
= EINVAL
; // perhaps EMLINK?
2768 CloseHandle (fileh
);
2777 sys_mkdir (const char * path
)
2779 return _mkdir (map_w32_filename (path
, NULL
));
2782 /* Because of long name mapping issues, we need to implement this
2783 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2784 a unique name, instead of setting the input template to an empty
2787 Standard algorithm seems to be use pid or tid with a letter on the
2788 front (in place of the 6 X's) and cycle through the letters to find a
2789 unique name. We extend that to allow any reasonable character as the
2790 first of the 6 X's. */
2792 sys_mktemp (char * template)
2796 unsigned uid
= GetCurrentThreadId ();
2797 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2799 if (template == NULL
)
2801 p
= template + strlen (template);
2803 /* replace up to the last 5 X's with uid in decimal */
2804 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2806 p
[0] = '0' + uid
% 10;
2810 if (i
< 0 && p
[0] == 'X')
2815 int save_errno
= errno
;
2816 p
[0] = first_char
[i
];
2817 if (sys_access (template, 0) < 0)
2823 while (++i
< sizeof (first_char
));
2826 /* Template is badly formed or else we can't generate a unique name,
2827 so return empty string */
2833 sys_open (const char * path
, int oflag
, int mode
)
2835 const char* mpath
= map_w32_filename (path
, NULL
);
2836 /* Try to open file without _O_CREAT, to be able to write to hidden
2837 and system files. Force all file handles to be
2839 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2842 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2846 sys_rename (const char * oldname
, const char * newname
)
2849 char temp
[MAX_PATH
];
2851 /* MoveFile on Windows 95 doesn't correctly change the short file name
2852 alias in a number of circumstances (it is not easy to predict when
2853 just by looking at oldname and newname, unfortunately). In these
2854 cases, renaming through a temporary name avoids the problem.
2856 A second problem on Windows 95 is that renaming through a temp name when
2857 newname is uppercase fails (the final long name ends up in
2858 lowercase, although the short alias might be uppercase) UNLESS the
2859 long temp name is not 8.3.
2861 So, on Windows 95 we always rename through a temp name, and we make sure
2862 the temp name has a long extension to ensure correct renaming. */
2864 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2866 if (os_subtype
== OS_WIN95
)
2872 oldname
= map_w32_filename (oldname
, NULL
);
2873 if (o
= strrchr (oldname
, '\\'))
2876 o
= (char *) oldname
;
2878 if (p
= strrchr (temp
, '\\'))
2885 /* Force temp name to require a manufactured 8.3 alias - this
2886 seems to make the second rename work properly. */
2887 sprintf (p
, "_.%s.%u", o
, i
);
2889 result
= rename (oldname
, temp
);
2891 /* This loop must surely terminate! */
2892 while (result
< 0 && errno
== EEXIST
);
2897 /* Emulate Unix behavior - newname is deleted if it already exists
2898 (at least if it is a file; don't do this for directories).
2900 Since we mustn't do this if we are just changing the case of the
2901 file name (we would end up deleting the file we are trying to
2902 rename!), we let rename detect if the destination file already
2903 exists - that way we avoid the possible pitfalls of trying to
2904 determine ourselves whether two names really refer to the same
2905 file, which is not always possible in the general case. (Consider
2906 all the permutations of shared or subst'd drives, etc.) */
2908 newname
= map_w32_filename (newname
, NULL
);
2909 result
= rename (temp
, newname
);
2913 && _chmod (newname
, 0666) == 0
2914 && _unlink (newname
) == 0)
2915 result
= rename (temp
, newname
);
2921 sys_rmdir (const char * path
)
2923 return _rmdir (map_w32_filename (path
, NULL
));
2927 sys_unlink (const char * path
)
2929 path
= map_w32_filename (path
, NULL
);
2931 /* On Unix, unlink works without write permission. */
2932 _chmod (path
, 0666);
2933 return _unlink (path
);
2936 static FILETIME utc_base_ft
;
2937 static ULONGLONG utc_base
; /* In 100ns units */
2938 static int init
= 0;
2940 #define FILETIME_TO_U64(result, ft) \
2942 ULARGE_INTEGER uiTemp; \
2943 uiTemp.LowPart = (ft).dwLowDateTime; \
2944 uiTemp.HighPart = (ft).dwHighDateTime; \
2945 result = uiTemp.QuadPart; \
2949 initialize_utc_base (void)
2951 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2960 st
.wMilliseconds
= 0;
2962 SystemTimeToFileTime (&st
, &utc_base_ft
);
2963 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2967 convert_time (FILETIME ft
)
2973 initialize_utc_base();
2977 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2980 FILETIME_TO_U64 (tmp
, ft
);
2981 return (time_t) ((tmp
- utc_base
) / 10000000L);
2985 convert_from_time_t (time_t time
, FILETIME
* pft
)
2991 initialize_utc_base ();
2995 /* time in 100ns units since 1-Jan-1601 */
2996 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
2997 pft
->dwHighDateTime
= tmp
.HighPart
;
2998 pft
->dwLowDateTime
= tmp
.LowPart
;
3002 /* No reason to keep this; faking inode values either by hashing or even
3003 using the file index from GetInformationByHandle, is not perfect and
3004 so by default Emacs doesn't use the inode values on Windows.
3005 Instead, we now determine file-truename correctly (except for
3006 possible drive aliasing etc). */
3008 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3010 hashval (const unsigned char * str
)
3015 h
= (h
<< 4) + *str
++;
3021 /* Return the hash value of the canonical pathname, excluding the
3022 drive/UNC header, to get a hopefully unique inode number. */
3024 generate_inode_val (const char * name
)
3026 char fullname
[ MAX_PATH
];
3030 /* Get the truly canonical filename, if it exists. (Note: this
3031 doesn't resolve aliasing due to subst commands, or recognise hard
3033 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3036 parse_root (fullname
, &p
);
3037 /* Normal W32 filesystems are still case insensitive. */
3044 static PSECURITY_DESCRIPTOR
3045 get_file_security_desc (const char *fname
)
3047 PSECURITY_DESCRIPTOR psd
= NULL
;
3049 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3050 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3052 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3054 err
= GetLastError ();
3055 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3059 psd
= xmalloc (sd_len
);
3060 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3072 unsigned n_subauthorities
;
3074 /* Use the last sub-authority value of the RID, the relative
3075 portion of the SID, as user/group ID. */
3076 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3077 if (n_subauthorities
< 1)
3078 return 0; /* the "World" RID */
3079 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3082 /* Caching SID and account values for faster lokup. */
3085 # define FLEXIBLE_ARRAY_MEMBER
3087 # define FLEXIBLE_ARRAY_MEMBER 1
3092 struct w32_id
*next
;
3094 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3097 static struct w32_id
*w32_idlist
;
3100 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3102 struct w32_id
*tail
, *found
;
3104 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3106 if (equal_sid ((PSID
)tail
->sid
, sid
))
3115 strcpy (name
, found
->name
);
3123 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3126 struct w32_id
*new_entry
;
3128 /* We don't want to leave behind stale cache from when Emacs was
3132 sid_len
= get_length_sid (sid
);
3133 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3136 new_entry
->rid
= id
;
3137 strcpy (new_entry
->name
, name
);
3138 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3139 new_entry
->next
= w32_idlist
;
3140 w32_idlist
= new_entry
;
3149 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3150 unsigned *id
, char *nm
, int what
)
3153 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3155 SID_NAME_USE ignore
;
3157 DWORD name_len
= sizeof (name
);
3159 DWORD domain_len
= sizeof (domain
);
3165 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3166 else if (what
== GID
)
3167 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3171 if (!result
|| !is_valid_sid (sid
))
3173 else if (!w32_cached_id (sid
, id
, nm
))
3175 /* If FNAME is a UNC, we need to lookup account on the
3176 specified machine. */
3177 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3178 && fname
[2] != '\0')
3183 for (s
= fname
+ 2, p
= machine
;
3184 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3190 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3191 domain
, &domain_len
, &ignore
)
3192 || name_len
> UNLEN
+1)
3196 *id
= get_rid (sid
);
3198 w32_add_to_cache (sid
, *id
, name
);
3205 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3209 int dflt_usr
= 0, dflt_grp
= 0;
3218 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3220 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3223 /* Consider files to belong to current user/group, if we cannot get
3224 more accurate information. */
3227 st
->st_uid
= dflt_passwd
.pw_uid
;
3228 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3232 st
->st_gid
= dflt_passwd
.pw_gid
;
3233 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3237 /* Return non-zero if NAME is a potentially slow filesystem. */
3239 is_slow_fs (const char *name
)
3244 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3245 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3246 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3247 devtype
= GetDriveType (NULL
); /* use root of current drive */
3250 /* GetDriveType needs the root directory of the drive. */
3251 strncpy (drive_root
, name
, 2);
3252 drive_root
[2] = '\\';
3253 drive_root
[3] = '\0';
3254 devtype
= GetDriveType (drive_root
);
3256 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3259 /* MSVC stat function can't cope with UNC names and has other bugs, so
3260 replace it with our own. This also allows us to calculate consistent
3261 inode values without hacks in the main Emacs code. */
3263 stat (const char * path
, struct stat
* buf
)
3268 WIN32_FIND_DATA wfd
;
3270 unsigned __int64 fake_inode
;
3273 int rootdir
= FALSE
;
3274 PSECURITY_DESCRIPTOR psd
= NULL
;
3276 if (path
== NULL
|| buf
== NULL
)
3282 name
= (char *) map_w32_filename (path
, &path
);
3283 /* Must be valid filename, no wild cards or other invalid
3284 characters. We use _mbspbrk to support multibyte strings that
3285 might look to strpbrk as if they included literal *, ?, and other
3286 characters mentioned below that are disallowed by Windows
3288 if (_mbspbrk (name
, "*?|<>\""))
3294 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3295 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3296 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3301 /* Remove trailing directory separator, unless name is the root
3302 directory of a drive or UNC volume in which case ensure there
3303 is a trailing separator. */
3304 len
= strlen (name
);
3305 rootdir
= (path
>= name
+ len
- 1
3306 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3307 name
= strcpy (alloca (len
+ 2), name
);
3309 if (is_unc_volume (name
))
3311 DWORD attrs
= unc_volume_file_attributes (name
);
3316 memset (&wfd
, 0, sizeof (wfd
));
3317 wfd
.dwFileAttributes
= attrs
;
3318 wfd
.ftCreationTime
= utc_base_ft
;
3319 wfd
.ftLastAccessTime
= utc_base_ft
;
3320 wfd
.ftLastWriteTime
= utc_base_ft
;
3321 strcpy (wfd
.cFileName
, name
);
3325 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3326 strcat (name
, "\\");
3327 if (GetDriveType (name
) < 2)
3332 memset (&wfd
, 0, sizeof (wfd
));
3333 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3334 wfd
.ftCreationTime
= utc_base_ft
;
3335 wfd
.ftLastAccessTime
= utc_base_ft
;
3336 wfd
.ftLastWriteTime
= utc_base_ft
;
3337 strcpy (wfd
.cFileName
, name
);
3341 if (IS_DIRECTORY_SEP (name
[len
-1]))
3344 /* (This is hacky, but helps when doing file completions on
3345 network drives.) Optimize by using information available from
3346 active readdir if possible. */
3347 len
= strlen (dir_pathname
);
3348 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3350 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3351 && strnicmp (name
, dir_pathname
, len
) == 0
3352 && IS_DIRECTORY_SEP (name
[len
])
3353 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3355 /* This was the last entry returned by readdir. */
3356 wfd
= dir_find_data
;
3360 logon_network_drive (name
);
3362 fh
= FindFirstFile (name
, &wfd
);
3363 if (fh
== INVALID_HANDLE_VALUE
)
3372 if (!(NILP (Vw32_get_true_file_attributes
)
3373 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3374 /* No access rights required to get info. */
3375 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3376 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3377 != INVALID_HANDLE_VALUE
)
3379 /* This is more accurate in terms of gettting the correct number
3380 of links, but is quite slow (it is noticeable when Emacs is
3381 making a list of file name completions). */
3382 BY_HANDLE_FILE_INFORMATION info
;
3384 if (GetFileInformationByHandle (fh
, &info
))
3386 buf
->st_nlink
= info
.nNumberOfLinks
;
3387 /* Might as well use file index to fake inode values, but this
3388 is not guaranteed to be unique unless we keep a handle open
3389 all the time (even then there are situations where it is
3390 not unique). Reputedly, there are at most 48 bits of info
3391 (on NTFS, presumably less on FAT). */
3392 fake_inode
= info
.nFileIndexHigh
;
3394 fake_inode
+= info
.nFileIndexLow
;
3402 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3404 buf
->st_mode
= S_IFDIR
;
3408 switch (GetFileType (fh
))
3410 case FILE_TYPE_DISK
:
3411 buf
->st_mode
= S_IFREG
;
3413 case FILE_TYPE_PIPE
:
3414 buf
->st_mode
= S_IFIFO
;
3416 case FILE_TYPE_CHAR
:
3417 case FILE_TYPE_UNKNOWN
:
3419 buf
->st_mode
= S_IFCHR
;
3423 psd
= get_file_security_desc (name
);
3424 get_file_owner_and_group (psd
, name
, buf
);
3428 /* Don't bother to make this information more accurate. */
3429 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3434 get_file_owner_and_group (NULL
, name
, buf
);
3439 /* Not sure if there is any point in this. */
3440 if (!NILP (Vw32_generate_fake_inodes
))
3441 fake_inode
= generate_inode_val (name
);
3442 else if (fake_inode
== 0)
3444 /* For want of something better, try to make everything unique. */
3445 static DWORD gen_num
= 0;
3446 fake_inode
= ++gen_num
;
3450 /* MSVC defines _ino_t to be short; other libc's might not. */
3451 if (sizeof (buf
->st_ino
) == 2)
3452 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3454 buf
->st_ino
= fake_inode
;
3456 /* volume_info is set indirectly by map_w32_filename */
3457 buf
->st_dev
= volume_info
.serialnum
;
3458 buf
->st_rdev
= volume_info
.serialnum
;
3460 buf
->st_size
= wfd
.nFileSizeHigh
;
3461 buf
->st_size
<<= 32;
3462 buf
->st_size
+= wfd
.nFileSizeLow
;
3464 /* Convert timestamps to Unix format. */
3465 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3466 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3467 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3468 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3469 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3471 /* determine rwx permissions */
3472 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3473 permission
= S_IREAD
;
3475 permission
= S_IREAD
| S_IWRITE
;
3477 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3478 permission
|= S_IEXEC
;
3479 else if (is_exec (name
))
3480 permission
|= S_IEXEC
;
3482 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3487 /* Provide fstat and utime as well as stat for consistent handling of
3490 fstat (int desc
, struct stat
* buf
)
3492 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3493 BY_HANDLE_FILE_INFORMATION info
;
3494 unsigned __int64 fake_inode
;
3497 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3499 case FILE_TYPE_DISK
:
3500 buf
->st_mode
= S_IFREG
;
3501 if (!GetFileInformationByHandle (fh
, &info
))
3507 case FILE_TYPE_PIPE
:
3508 buf
->st_mode
= S_IFIFO
;
3510 case FILE_TYPE_CHAR
:
3511 case FILE_TYPE_UNKNOWN
:
3513 buf
->st_mode
= S_IFCHR
;
3515 memset (&info
, 0, sizeof (info
));
3516 info
.dwFileAttributes
= 0;
3517 info
.ftCreationTime
= utc_base_ft
;
3518 info
.ftLastAccessTime
= utc_base_ft
;
3519 info
.ftLastWriteTime
= utc_base_ft
;
3522 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3523 buf
->st_mode
= S_IFDIR
;
3525 buf
->st_nlink
= info
.nNumberOfLinks
;
3526 /* Might as well use file index to fake inode values, but this
3527 is not guaranteed to be unique unless we keep a handle open
3528 all the time (even then there are situations where it is
3529 not unique). Reputedly, there are at most 48 bits of info
3530 (on NTFS, presumably less on FAT). */
3531 fake_inode
= info
.nFileIndexHigh
;
3533 fake_inode
+= info
.nFileIndexLow
;
3535 /* MSVC defines _ino_t to be short; other libc's might not. */
3536 if (sizeof (buf
->st_ino
) == 2)
3537 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3539 buf
->st_ino
= fake_inode
;
3541 /* Consider files to belong to current user.
3542 FIXME: this should use GetSecurityInfo API, but it is only
3543 available for _WIN32_WINNT >= 0x501. */
3544 buf
->st_uid
= dflt_passwd
.pw_uid
;
3545 buf
->st_gid
= dflt_passwd
.pw_gid
;
3546 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3547 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3549 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3550 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3552 buf
->st_size
= info
.nFileSizeHigh
;
3553 buf
->st_size
<<= 32;
3554 buf
->st_size
+= info
.nFileSizeLow
;
3556 /* Convert timestamps to Unix format. */
3557 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3558 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3559 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3560 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3561 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3563 /* determine rwx permissions */
3564 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3565 permission
= S_IREAD
;
3567 permission
= S_IREAD
| S_IWRITE
;
3569 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3570 permission
|= S_IEXEC
;
3573 #if 0 /* no way of knowing the filename */
3574 char * p
= strrchr (name
, '.');
3576 (xstrcasecmp (p
, ".exe") == 0 ||
3577 xstrcasecmp (p
, ".com") == 0 ||
3578 xstrcasecmp (p
, ".bat") == 0 ||
3579 xstrcasecmp (p
, ".cmd") == 0))
3580 permission
|= S_IEXEC
;
3584 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3590 utime (const char *name
, struct utimbuf
*times
)
3592 struct utimbuf deftime
;
3599 deftime
.modtime
= deftime
.actime
= time (NULL
);
3603 /* Need write access to set times. */
3604 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3605 0, OPEN_EXISTING
, 0, NULL
);
3608 convert_from_time_t (times
->actime
, &atime
);
3609 convert_from_time_t (times
->modtime
, &mtime
);
3610 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3627 /* Support for browsing other processes and their attributes. See
3628 process.c for the Lisp bindings. */
3630 /* Helper wrapper functions. */
3632 static HANDLE WINAPI
3633 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
3635 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3637 if (g_b_init_create_toolhelp32_snapshot
== 0)
3639 g_b_init_create_toolhelp32_snapshot
= 1;
3640 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3641 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3642 "CreateToolhelp32Snapshot");
3644 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3646 return INVALID_HANDLE_VALUE
;
3648 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3652 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3654 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3656 if (g_b_init_process32_first
== 0)
3658 g_b_init_process32_first
= 1;
3659 s_pfn_Process32_First
= (Process32First_Proc
)
3660 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3663 if (s_pfn_Process32_First
== NULL
)
3667 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3671 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3673 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3675 if (g_b_init_process32_next
== 0)
3677 g_b_init_process32_next
= 1;
3678 s_pfn_Process32_Next
= (Process32Next_Proc
)
3679 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3682 if (s_pfn_Process32_Next
== NULL
)
3686 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3690 open_thread_token (HANDLE ThreadHandle
,
3691 DWORD DesiredAccess
,
3693 PHANDLE TokenHandle
)
3695 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3696 HMODULE hm_advapi32
= NULL
;
3697 if (is_windows_9x () == TRUE
)
3699 SetLastError (ERROR_NOT_SUPPORTED
);
3702 if (g_b_init_open_thread_token
== 0)
3704 g_b_init_open_thread_token
= 1;
3705 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3706 s_pfn_Open_Thread_Token
=
3707 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3709 if (s_pfn_Open_Thread_Token
== NULL
)
3711 SetLastError (ERROR_NOT_SUPPORTED
);
3715 s_pfn_Open_Thread_Token (
3724 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3726 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3727 HMODULE hm_advapi32
= NULL
;
3728 if (is_windows_9x () == TRUE
)
3732 if (g_b_init_impersonate_self
== 0)
3734 g_b_init_impersonate_self
= 1;
3735 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3736 s_pfn_Impersonate_Self
=
3737 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3739 if (s_pfn_Impersonate_Self
== NULL
)
3743 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3747 revert_to_self (void)
3749 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3750 HMODULE hm_advapi32
= NULL
;
3751 if (is_windows_9x () == TRUE
)
3755 if (g_b_init_revert_to_self
== 0)
3757 g_b_init_revert_to_self
= 1;
3758 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3759 s_pfn_Revert_To_Self
=
3760 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3762 if (s_pfn_Revert_To_Self
== NULL
)
3766 return s_pfn_Revert_To_Self ();
3770 get_process_memory_info (HANDLE h_proc
,
3771 PPROCESS_MEMORY_COUNTERS mem_counters
,
3774 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3775 HMODULE hm_psapi
= NULL
;
3776 if (is_windows_9x () == TRUE
)
3780 if (g_b_init_get_process_memory_info
== 0)
3782 g_b_init_get_process_memory_info
= 1;
3783 hm_psapi
= LoadLibrary ("Psapi.dll");
3785 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3786 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3788 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3792 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3796 get_process_working_set_size (HANDLE h_proc
,
3800 static GetProcessWorkingSetSize_Proc
3801 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3803 if (is_windows_9x () == TRUE
)
3807 if (g_b_init_get_process_working_set_size
== 0)
3809 g_b_init_get_process_working_set_size
= 1;
3810 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3811 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3812 "GetProcessWorkingSetSize");
3814 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3818 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3822 global_memory_status (MEMORYSTATUS
*buf
)
3824 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3826 if (is_windows_9x () == TRUE
)
3830 if (g_b_init_global_memory_status
== 0)
3832 g_b_init_global_memory_status
= 1;
3833 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3834 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3835 "GlobalMemoryStatus");
3837 if (s_pfn_Global_Memory_Status
== NULL
)
3841 return s_pfn_Global_Memory_Status (buf
);
3845 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
3847 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3849 if (is_windows_9x () == TRUE
)
3853 if (g_b_init_global_memory_status_ex
== 0)
3855 g_b_init_global_memory_status_ex
= 1;
3856 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3857 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3858 "GlobalMemoryStatusEx");
3860 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3864 return s_pfn_Global_Memory_Status_Ex (buf
);
3868 list_system_processes (void)
3870 struct gcpro gcpro1
;
3871 Lisp_Object proclist
= Qnil
;
3874 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3876 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3878 PROCESSENTRY32 proc_entry
;
3884 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3885 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3886 res
= process32_next (h_snapshot
, &proc_entry
))
3888 proc_id
= proc_entry
.th32ProcessID
;
3889 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3892 CloseHandle (h_snapshot
);
3894 proclist
= Fnreverse (proclist
);
3901 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3903 TOKEN_PRIVILEGES priv
;
3904 DWORD priv_size
= sizeof (priv
);
3905 DWORD opriv_size
= sizeof (*old_priv
);
3906 HANDLE h_token
= NULL
;
3907 HANDLE h_thread
= GetCurrentThread ();
3911 res
= open_thread_token (h_thread
,
3912 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3914 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3916 if (impersonate_self (SecurityImpersonation
))
3917 res
= open_thread_token (h_thread
,
3918 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3923 priv
.PrivilegeCount
= 1;
3924 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3925 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3926 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3927 old_priv
, &opriv_size
)
3928 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3932 CloseHandle (h_token
);
3938 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3940 DWORD priv_size
= sizeof (*priv
);
3941 HANDLE h_token
= NULL
;
3944 if (open_thread_token (GetCurrentThread (),
3945 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3948 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3949 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3953 CloseHandle (h_token
);
3959 ltime (long time_sec
, long time_usec
)
3961 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3962 make_number (time_sec
& 0xffff),
3963 make_number (time_usec
));
3966 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
3969 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
3970 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
3973 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
3974 ULONGLONG tem1
, tem2
, tem3
, tem
;
3977 || !get_process_times_fn
3978 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
3979 &ft_kernel
, &ft_user
))
3982 GetSystemTimeAsFileTime (&ft_current
);
3984 FILETIME_TO_U64 (tem1
, ft_kernel
);
3986 *stime
= U64_TO_LISP_TIME (tem1
);
3988 FILETIME_TO_U64 (tem2
, ft_user
);
3990 *utime
= U64_TO_LISP_TIME (tem2
);
3993 *ttime
= U64_TO_LISP_TIME (tem3
);
3995 FILETIME_TO_U64 (tem
, ft_creation
);
3996 /* Process no 4 (System) returns zero creation time. */
3998 tem
= (tem
- utc_base
) / 10L;
3999 *ctime
= U64_TO_LISP_TIME (tem
);
4003 FILETIME_TO_U64 (tem3
, ft_current
);
4004 tem
= (tem3
- utc_base
) / 10L - tem
;
4006 *etime
= U64_TO_LISP_TIME (tem
);
4010 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4021 system_process_attributes (Lisp_Object pid
)
4023 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4024 Lisp_Object attrs
= Qnil
;
4025 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4026 HANDLE h_snapshot
, h_proc
;
4029 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4030 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4031 DWORD glength
= sizeof (gname
);
4032 HANDLE token
= NULL
;
4033 SID_NAME_USE user_type
;
4034 unsigned char *buf
= NULL
;
4036 TOKEN_USER user_token
;
4037 TOKEN_PRIMARY_GROUP group_token
;
4041 PROCESS_MEMORY_COUNTERS mem
;
4042 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4043 DWORD minrss
, maxrss
;
4045 MEMORY_STATUS_EX memstex
;
4046 double totphys
= 0.0;
4047 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4049 BOOL result
= FALSE
;
4051 CHECK_NUMBER_OR_FLOAT (pid
);
4052 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4054 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4056 GCPRO3 (attrs
, decoded_cmd
, tem
);
4058 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4063 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4064 for (res
= process32_first (h_snapshot
, &pe
); res
;
4065 res
= process32_next (h_snapshot
, &pe
))
4067 if (proc_id
== pe
.th32ProcessID
)
4070 decoded_cmd
= build_string ("Idle");
4073 /* Decode the command name from locale-specific
4075 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4076 strlen (pe
.szExeFile
));
4078 code_convert_string_norecord (cmd_str
,
4079 Vlocale_coding_system
, 0);
4081 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4082 attrs
= Fcons (Fcons (Qppid
,
4083 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4085 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4087 attrs
= Fcons (Fcons (Qthcount
,
4088 make_fixnum_or_float (pe
.cntThreads
)),
4095 CloseHandle (h_snapshot
);
4104 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4106 /* If we were denied a handle to the process, try again after
4107 enabling the SeDebugPrivilege in our process. */
4110 TOKEN_PRIVILEGES priv_current
;
4112 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4114 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4116 restore_privilege (&priv_current
);
4122 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4125 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4126 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4128 buf
= xmalloc (blen
);
4129 result
= get_token_information (token
, TokenUser
,
4130 (LPVOID
)buf
, blen
, &needed
);
4133 memcpy (&user_token
, buf
, sizeof (user_token
));
4134 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4136 euid
= get_rid (user_token
.User
.Sid
);
4137 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4142 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4145 strcpy (uname
, "unknown");
4149 ulength
= strlen (uname
);
4155 /* Determine a reasonable euid and gid values. */
4156 if (xstrcasecmp ("administrator", uname
) == 0)
4158 euid
= 500; /* well-known Administrator uid */
4159 egid
= 513; /* well-known None gid */
4163 /* Get group id and name. */
4164 result
= get_token_information (token
, TokenPrimaryGroup
,
4165 (LPVOID
)buf
, blen
, &needed
);
4166 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4168 buf
= xrealloc (buf
, blen
= needed
);
4169 result
= get_token_information (token
, TokenPrimaryGroup
,
4170 (LPVOID
)buf
, blen
, &needed
);
4174 memcpy (&group_token
, buf
, sizeof (group_token
));
4175 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4177 egid
= get_rid (group_token
.PrimaryGroup
);
4178 dlength
= sizeof (domain
);
4180 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4181 gname
, &glength
, NULL
, &dlength
,
4184 w32_add_to_cache (group_token
.PrimaryGroup
,
4188 strcpy (gname
, "None");
4192 glength
= strlen (gname
);
4200 if (!is_windows_9x ())
4202 /* We couldn't open the process token, presumably because of
4203 insufficient access rights. Assume this process is run
4205 strcpy (uname
, "SYSTEM");
4206 strcpy (gname
, "None");
4207 euid
= 18; /* SYSTEM */
4208 egid
= 513; /* None */
4209 glength
= strlen (gname
);
4210 ulength
= strlen (uname
);
4212 /* If we are running under Windows 9X, where security calls are
4213 not supported, we assume all processes are run by the current
4215 else if (GetUserName (uname
, &ulength
))
4217 if (xstrcasecmp ("administrator", uname
) == 0)
4222 strcpy (gname
, "None");
4223 glength
= strlen (gname
);
4224 ulength
= strlen (uname
);
4230 strcpy (uname
, "administrator");
4231 ulength
= strlen (uname
);
4232 strcpy (gname
, "None");
4233 glength
= strlen (gname
);
4236 CloseHandle (token
);
4239 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4240 tem
= make_unibyte_string (uname
, ulength
);
4241 attrs
= Fcons (Fcons (Quser
,
4242 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4244 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4245 tem
= make_unibyte_string (gname
, glength
);
4246 attrs
= Fcons (Fcons (Qgroup
,
4247 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4250 if (global_memory_status_ex (&memstex
))
4251 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4252 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4254 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4255 double, so we need to do this for it... */
4257 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4258 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4259 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4261 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4263 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4264 else if (global_memory_status (&memst
))
4265 totphys
= memst
.dwTotalPhys
/ 1024.0;
4268 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4271 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4273 attrs
= Fcons (Fcons (Qmajflt
,
4274 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4276 attrs
= Fcons (Fcons (Qvsize
,
4277 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4279 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4281 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4284 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4286 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4288 attrs
= Fcons (Fcons (Qmajflt
,
4289 make_fixnum_or_float (mem
.PageFaultCount
)),
4291 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4293 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4296 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4298 DWORD rss
= maxrss
/ 1024;
4300 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4302 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4305 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4307 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4308 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4309 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4310 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4311 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4312 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4315 /* FIXME: Retrieve command line by walking the PEB of the process. */
4318 CloseHandle (h_proc
);
4324 /* Wrappers for winsock functions to map between our file descriptors
4325 and winsock's handles; also set h_errno for convenience.
4327 To allow Emacs to run on systems which don't have winsock support
4328 installed, we dynamically link to winsock on startup if present, and
4329 otherwise provide the minimum necessary functionality
4330 (eg. gethostname). */
4332 /* function pointers for relevant socket functions */
4333 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4334 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4335 int (PASCAL
*pfn_WSAGetLastError
) (void);
4336 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4337 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4338 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4339 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4340 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4341 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4342 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4343 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4344 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4345 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4346 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4347 int (PASCAL
*pfn_WSACleanup
) (void);
4349 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4350 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4351 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4352 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4353 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4354 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4355 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4356 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4357 const char * optval
, int optlen
);
4358 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4359 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4361 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4362 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4363 struct sockaddr
* from
, int * fromlen
);
4364 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4365 const struct sockaddr
* to
, int tolen
);
4367 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4368 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4369 #ifndef HANDLE_FLAG_INHERIT
4370 #define HANDLE_FLAG_INHERIT 1
4374 static int winsock_inuse
;
4379 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4381 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4382 after WSAStartup returns successfully, but it seems reasonable
4383 to allow unloading winsock anyway in that case. */
4384 if (pfn_WSACleanup () == 0 ||
4385 pfn_WSAGetLastError () == WSAENETDOWN
)
4387 if (FreeLibrary (winsock_lib
))
4396 init_winsock (int load_now
)
4398 WSADATA winsockData
;
4400 if (winsock_lib
!= NULL
)
4403 pfn_SetHandleInformation
4404 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4405 "SetHandleInformation");
4407 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4409 if (winsock_lib
!= NULL
)
4411 /* dynamically link to socket functions */
4413 #define LOAD_PROC(fn) \
4414 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4417 LOAD_PROC (WSAStartup
);
4418 LOAD_PROC (WSASetLastError
);
4419 LOAD_PROC (WSAGetLastError
);
4420 LOAD_PROC (WSAEventSelect
);
4421 LOAD_PROC (WSACreateEvent
);
4422 LOAD_PROC (WSACloseEvent
);
4425 LOAD_PROC (connect
);
4426 LOAD_PROC (ioctlsocket
);
4429 LOAD_PROC (closesocket
);
4430 LOAD_PROC (shutdown
);
4433 LOAD_PROC (inet_addr
);
4434 LOAD_PROC (gethostname
);
4435 LOAD_PROC (gethostbyname
);
4436 LOAD_PROC (getservbyname
);
4437 LOAD_PROC (getpeername
);
4438 LOAD_PROC (WSACleanup
);
4439 LOAD_PROC (setsockopt
);
4441 LOAD_PROC (getsockname
);
4443 LOAD_PROC (recvfrom
);
4447 /* specify version 1.1 of winsock */
4448 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4450 if (winsockData
.wVersion
!= 0x101)
4455 /* Report that winsock exists and is usable, but leave
4456 socket functions disabled. I am assuming that calling
4457 WSAStartup does not require any network interaction,
4458 and in particular does not cause or require a dial-up
4459 connection to be established. */
4462 FreeLibrary (winsock_lib
);
4470 FreeLibrary (winsock_lib
);
4480 /* function to set h_errno for compatibility; map winsock error codes to
4481 normal system codes where they overlap (non-overlapping definitions
4482 are already in <sys/socket.h> */
4486 if (winsock_lib
== NULL
)
4489 h_errno
= pfn_WSAGetLastError ();
4493 case WSAEACCES
: h_errno
= EACCES
; break;
4494 case WSAEBADF
: h_errno
= EBADF
; break;
4495 case WSAEFAULT
: h_errno
= EFAULT
; break;
4496 case WSAEINTR
: h_errno
= EINTR
; break;
4497 case WSAEINVAL
: h_errno
= EINVAL
; break;
4498 case WSAEMFILE
: h_errno
= EMFILE
; break;
4499 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4500 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4508 if (h_errno
== 0 && winsock_lib
!= NULL
)
4509 pfn_WSASetLastError (0);
4512 /* Extend strerror to handle the winsock-specific error codes. */
4516 } _wsa_errlist
[] = {
4517 WSAEINTR
, "Interrupted function call",
4518 WSAEBADF
, "Bad file descriptor",
4519 WSAEACCES
, "Permission denied",
4520 WSAEFAULT
, "Bad address",
4521 WSAEINVAL
, "Invalid argument",
4522 WSAEMFILE
, "Too many open files",
4524 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4525 WSAEINPROGRESS
, "Operation now in progress",
4526 WSAEALREADY
, "Operation already in progress",
4527 WSAENOTSOCK
, "Socket operation on non-socket",
4528 WSAEDESTADDRREQ
, "Destination address required",
4529 WSAEMSGSIZE
, "Message too long",
4530 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4531 WSAENOPROTOOPT
, "Bad protocol option",
4532 WSAEPROTONOSUPPORT
, "Protocol not supported",
4533 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4534 WSAEOPNOTSUPP
, "Operation not supported",
4535 WSAEPFNOSUPPORT
, "Protocol family not supported",
4536 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4537 WSAEADDRINUSE
, "Address already in use",
4538 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4539 WSAENETDOWN
, "Network is down",
4540 WSAENETUNREACH
, "Network is unreachable",
4541 WSAENETRESET
, "Network dropped connection on reset",
4542 WSAECONNABORTED
, "Software caused connection abort",
4543 WSAECONNRESET
, "Connection reset by peer",
4544 WSAENOBUFS
, "No buffer space available",
4545 WSAEISCONN
, "Socket is already connected",
4546 WSAENOTCONN
, "Socket is not connected",
4547 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4548 WSAETOOMANYREFS
, "Too many references", /* not sure */
4549 WSAETIMEDOUT
, "Connection timed out",
4550 WSAECONNREFUSED
, "Connection refused",
4551 WSAELOOP
, "Network loop", /* not sure */
4552 WSAENAMETOOLONG
, "Name is too long",
4553 WSAEHOSTDOWN
, "Host is down",
4554 WSAEHOSTUNREACH
, "No route to host",
4555 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4556 WSAEPROCLIM
, "Too many processes",
4557 WSAEUSERS
, "Too many users", /* not sure */
4558 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4559 WSAESTALE
, "Data is stale", /* not sure */
4560 WSAEREMOTE
, "Remote error", /* not sure */
4562 WSASYSNOTREADY
, "Network subsystem is unavailable",
4563 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4564 WSANOTINITIALISED
, "Winsock not initialized successfully",
4565 WSAEDISCON
, "Graceful shutdown in progress",
4567 WSAENOMORE
, "No more operations allowed", /* not sure */
4568 WSAECANCELLED
, "Operation cancelled", /* not sure */
4569 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4570 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4571 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4572 WSASYSCALLFAILURE
, "System call failure",
4573 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4574 WSATYPE_NOT_FOUND
, "Class type not found",
4575 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4576 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4577 WSAEREFUSED
, "Operation refused", /* not sure */
4580 WSAHOST_NOT_FOUND
, "Host not found",
4581 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4582 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4583 WSANO_DATA
, "Valid name, no data record of requested type",
4589 sys_strerror (int error_no
)
4592 static char unknown_msg
[40];
4594 if (error_no
>= 0 && error_no
< sys_nerr
)
4595 return sys_errlist
[error_no
];
4597 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4598 if (_wsa_errlist
[i
].errnum
== error_no
)
4599 return _wsa_errlist
[i
].msg
;
4601 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4605 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4606 but I believe the method of keeping the socket handle separate (and
4607 insuring it is not inheritable) is the correct one. */
4609 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4611 static int socket_to_fd (SOCKET s
);
4614 sys_socket (int af
, int type
, int protocol
)
4618 if (winsock_lib
== NULL
)
4621 return INVALID_SOCKET
;
4626 /* call the real socket function */
4627 s
= pfn_socket (af
, type
, protocol
);
4629 if (s
!= INVALID_SOCKET
)
4630 return socket_to_fd (s
);
4636 /* Convert a SOCKET to a file descriptor. */
4638 socket_to_fd (SOCKET s
)
4643 /* Although under NT 3.5 _open_osfhandle will accept a socket
4644 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4645 that does not work under NT 3.1. However, we can get the same
4646 effect by using a backdoor function to replace an existing
4647 descriptor handle with the one we want. */
4649 /* allocate a file descriptor (with appropriate flags) */
4650 fd
= _open ("NUL:", _O_RDWR
);
4653 /* Make a non-inheritable copy of the socket handle. Note
4654 that it is possible that sockets aren't actually kernel
4655 handles, which appears to be the case on Windows 9x when
4656 the MS Proxy winsock client is installed. */
4658 /* Apparently there is a bug in NT 3.51 with some service
4659 packs, which prevents using DuplicateHandle to make a
4660 socket handle non-inheritable (causes WSACleanup to
4661 hang). The work-around is to use SetHandleInformation
4662 instead if it is available and implemented. */
4663 if (pfn_SetHandleInformation
)
4665 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4669 HANDLE parent
= GetCurrentProcess ();
4670 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4672 if (DuplicateHandle (parent
,
4678 DUPLICATE_SAME_ACCESS
))
4680 /* It is possible that DuplicateHandle succeeds even
4681 though the socket wasn't really a kernel handle,
4682 because a real handle has the same value. So
4683 test whether the new handle really is a socket. */
4684 long nonblocking
= 0;
4685 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4687 pfn_closesocket (s
);
4692 CloseHandle (new_s
);
4697 fd_info
[fd
].hnd
= (HANDLE
) s
;
4699 /* set our own internal flags */
4700 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4706 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4708 /* attach child_process to fd_info */
4709 if (fd_info
[ fd
].cp
!= NULL
)
4711 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4715 fd_info
[ fd
].cp
= cp
;
4718 winsock_inuse
++; /* count open sockets */
4725 pfn_closesocket (s
);
4731 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4733 if (winsock_lib
== NULL
)
4736 return SOCKET_ERROR
;
4740 if (fd_info
[s
].flags
& FILE_SOCKET
)
4742 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4743 if (rc
== SOCKET_ERROR
)
4748 return SOCKET_ERROR
;
4752 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4754 if (winsock_lib
== NULL
)
4757 return SOCKET_ERROR
;
4761 if (fd_info
[s
].flags
& FILE_SOCKET
)
4763 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4764 if (rc
== SOCKET_ERROR
)
4769 return SOCKET_ERROR
;
4773 sys_htons (u_short hostshort
)
4775 return (winsock_lib
!= NULL
) ?
4776 pfn_htons (hostshort
) : hostshort
;
4780 sys_ntohs (u_short netshort
)
4782 return (winsock_lib
!= NULL
) ?
4783 pfn_ntohs (netshort
) : netshort
;
4787 sys_inet_addr (const char * cp
)
4789 return (winsock_lib
!= NULL
) ?
4790 pfn_inet_addr (cp
) : INADDR_NONE
;
4794 sys_gethostname (char * name
, int namelen
)
4796 if (winsock_lib
!= NULL
)
4797 return pfn_gethostname (name
, namelen
);
4799 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4800 return !GetComputerName (name
, (DWORD
*)&namelen
);
4803 return SOCKET_ERROR
;
4807 sys_gethostbyname (const char * name
)
4809 struct hostent
* host
;
4811 if (winsock_lib
== NULL
)
4818 host
= pfn_gethostbyname (name
);
4825 sys_getservbyname (const char * name
, const char * proto
)
4827 struct servent
* serv
;
4829 if (winsock_lib
== NULL
)
4836 serv
= pfn_getservbyname (name
, proto
);
4843 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4845 if (winsock_lib
== NULL
)
4848 return SOCKET_ERROR
;
4852 if (fd_info
[s
].flags
& FILE_SOCKET
)
4854 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4855 if (rc
== SOCKET_ERROR
)
4860 return SOCKET_ERROR
;
4864 sys_shutdown (int s
, int how
)
4866 if (winsock_lib
== NULL
)
4869 return SOCKET_ERROR
;
4873 if (fd_info
[s
].flags
& FILE_SOCKET
)
4875 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4876 if (rc
== SOCKET_ERROR
)
4881 return SOCKET_ERROR
;
4885 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4887 if (winsock_lib
== NULL
)
4890 return SOCKET_ERROR
;
4894 if (fd_info
[s
].flags
& FILE_SOCKET
)
4896 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4897 (const char *)optval
, optlen
);
4898 if (rc
== SOCKET_ERROR
)
4903 return SOCKET_ERROR
;
4907 sys_listen (int s
, int backlog
)
4909 if (winsock_lib
== NULL
)
4912 return SOCKET_ERROR
;
4916 if (fd_info
[s
].flags
& FILE_SOCKET
)
4918 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4919 if (rc
== SOCKET_ERROR
)
4922 fd_info
[s
].flags
|= FILE_LISTEN
;
4926 return SOCKET_ERROR
;
4930 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4932 if (winsock_lib
== NULL
)
4935 return SOCKET_ERROR
;
4939 if (fd_info
[s
].flags
& FILE_SOCKET
)
4941 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4942 if (rc
== SOCKET_ERROR
)
4947 return SOCKET_ERROR
;
4951 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
4953 if (winsock_lib
== NULL
)
4960 if (fd_info
[s
].flags
& FILE_LISTEN
)
4962 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
4964 if (t
== INVALID_SOCKET
)
4967 fd
= socket_to_fd (t
);
4969 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4970 ResetEvent (fd_info
[s
].cp
->char_avail
);
4978 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
4979 struct sockaddr
* from
, int * fromlen
)
4981 if (winsock_lib
== NULL
)
4984 return SOCKET_ERROR
;
4988 if (fd_info
[s
].flags
& FILE_SOCKET
)
4990 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
4991 if (rc
== SOCKET_ERROR
)
4996 return SOCKET_ERROR
;
5000 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5001 const struct sockaddr
* to
, int tolen
)
5003 if (winsock_lib
== NULL
)
5006 return SOCKET_ERROR
;
5010 if (fd_info
[s
].flags
& FILE_SOCKET
)
5012 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5013 if (rc
== SOCKET_ERROR
)
5018 return SOCKET_ERROR
;
5021 /* Windows does not have an fcntl function. Provide an implementation
5022 solely for making sockets non-blocking. */
5024 fcntl (int s
, int cmd
, int options
)
5026 if (winsock_lib
== NULL
)
5033 if (fd_info
[s
].flags
& FILE_SOCKET
)
5035 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5037 unsigned long nblock
= 1;
5038 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5039 if (rc
== SOCKET_ERROR
)
5041 /* Keep track of the fact that we set this to non-blocking. */
5042 fd_info
[s
].flags
|= FILE_NDELAY
;
5048 return SOCKET_ERROR
;
5052 return SOCKET_ERROR
;
5056 /* Shadow main io functions: we need to handle pipes and sockets more
5057 intelligently, and implement non-blocking mode as well. */
5070 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5072 child_process
* cp
= fd_info
[fd
].cp
;
5074 fd_info
[fd
].cp
= NULL
;
5076 if (CHILD_ACTIVE (cp
))
5078 /* if last descriptor to active child_process then cleanup */
5080 for (i
= 0; i
< MAXDESC
; i
++)
5084 if (fd_info
[i
].cp
== cp
)
5089 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5091 if (winsock_lib
== NULL
) abort ();
5093 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5094 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5096 winsock_inuse
--; /* count open sockets */
5103 /* Note that sockets do not need special treatment here (at least on
5104 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5105 closesocket is equivalent to CloseHandle, which is to be expected
5106 because socket handles are fully fledged kernel handles. */
5109 if (rc
== 0 && fd
< MAXDESC
)
5110 fd_info
[fd
].flags
= 0;
5121 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5123 /* duplicate our internal info as well */
5124 fd_info
[new_fd
] = fd_info
[fd
];
5130 sys_dup2 (int src
, int dst
)
5134 if (dst
< 0 || dst
>= MAXDESC
)
5140 /* make sure we close the destination first if it's a pipe or socket */
5141 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5144 rc
= _dup2 (src
, dst
);
5147 /* duplicate our internal info as well */
5148 fd_info
[dst
] = fd_info
[src
];
5153 /* Unix pipe() has only one arg */
5155 sys_pipe (int * phandles
)
5160 /* make pipe handles non-inheritable; when we spawn a child, we
5161 replace the relevant handle with an inheritable one. Also put
5162 pipes into binary mode; we will do text mode translation ourselves
5164 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5168 /* Protect against overflow, since Windows can open more handles than
5169 our fd_info array has room for. */
5170 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5172 _close (phandles
[0]);
5173 _close (phandles
[1]);
5178 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5179 fd_info
[phandles
[0]].flags
= flags
;
5181 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5182 fd_info
[phandles
[1]].flags
= flags
;
5190 extern int w32_pipe_read_delay
;
5192 /* Function to do blocking read of one byte, needed to implement
5193 select. It is only allowed on sockets and pipes. */
5195 _sys_read_ahead (int fd
)
5200 if (fd
< 0 || fd
>= MAXDESC
)
5201 return STATUS_READ_ERROR
;
5203 cp
= fd_info
[fd
].cp
;
5205 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5206 return STATUS_READ_ERROR
;
5208 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5209 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5211 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5215 cp
->status
= STATUS_READ_IN_PROGRESS
;
5217 if (fd_info
[fd
].flags
& FILE_PIPE
)
5219 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5221 /* Give subprocess time to buffer some more output for us before
5222 reporting that input is available; we need this because Windows 95
5223 connects DOS programs to pipes by making the pipe appear to be
5224 the normal console stdout - as a result most DOS programs will
5225 write to stdout without buffering, ie. one character at a
5226 time. Even some W32 programs do this - "dir" in a command
5227 shell on NT is very slow if we don't do this. */
5230 int wait
= w32_pipe_read_delay
;
5236 /* Yield remainder of our time slice, effectively giving a
5237 temporary priority boost to the child process. */
5241 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5243 HANDLE hnd
= fd_info
[fd
].hnd
;
5244 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5247 /* Configure timeouts for blocking read. */
5248 if (!GetCommTimeouts (hnd
, &ct
))
5249 return STATUS_READ_ERROR
;
5250 ct
.ReadIntervalTimeout
= 0;
5251 ct
.ReadTotalTimeoutMultiplier
= 0;
5252 ct
.ReadTotalTimeoutConstant
= 0;
5253 if (!SetCommTimeouts (hnd
, &ct
))
5254 return STATUS_READ_ERROR
;
5256 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5258 if (GetLastError () != ERROR_IO_PENDING
)
5259 return STATUS_READ_ERROR
;
5260 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5261 return STATUS_READ_ERROR
;
5264 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5266 unsigned long nblock
= 0;
5267 /* We always want this to block, so temporarily disable NDELAY. */
5268 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5269 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5271 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5273 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5276 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5280 if (rc
== sizeof (char))
5281 cp
->status
= STATUS_READ_SUCCEEDED
;
5283 cp
->status
= STATUS_READ_FAILED
;
5289 _sys_wait_accept (int fd
)
5295 if (fd
< 0 || fd
>= MAXDESC
)
5296 return STATUS_READ_ERROR
;
5298 cp
= fd_info
[fd
].cp
;
5300 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5301 return STATUS_READ_ERROR
;
5303 cp
->status
= STATUS_READ_FAILED
;
5305 hEv
= pfn_WSACreateEvent ();
5306 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5307 if (rc
!= SOCKET_ERROR
)
5309 rc
= WaitForSingleObject (hEv
, INFINITE
);
5310 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5311 if (rc
== WAIT_OBJECT_0
)
5312 cp
->status
= STATUS_READ_SUCCEEDED
;
5314 pfn_WSACloseEvent (hEv
);
5320 sys_read (int fd
, char * buffer
, unsigned int count
)
5325 char * orig_buffer
= buffer
;
5333 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5335 child_process
*cp
= fd_info
[fd
].cp
;
5337 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5345 /* re-read CR carried over from last read */
5346 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5348 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5352 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5355 /* presence of a child_process structure means we are operating in
5356 non-blocking mode - otherwise we just call _read directly.
5357 Note that the child_process structure might be missing because
5358 reap_subprocess has been called; in this case the pipe is
5359 already broken, so calling _read on it is okay. */
5362 int current_status
= cp
->status
;
5364 switch (current_status
)
5366 case STATUS_READ_FAILED
:
5367 case STATUS_READ_ERROR
:
5368 /* report normal EOF if nothing in buffer */
5370 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5373 case STATUS_READ_READY
:
5374 case STATUS_READ_IN_PROGRESS
:
5375 DebPrint (("sys_read called when read is in progress\n"));
5376 errno
= EWOULDBLOCK
;
5379 case STATUS_READ_SUCCEEDED
:
5380 /* consume read-ahead char */
5381 *buffer
++ = cp
->chr
;
5384 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5385 ResetEvent (cp
->char_avail
);
5387 case STATUS_READ_ACKNOWLEDGED
:
5391 DebPrint (("sys_read: bad status %d\n", current_status
));
5396 if (fd_info
[fd
].flags
& FILE_PIPE
)
5398 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5399 to_read
= min (waiting
, (DWORD
) count
);
5402 nchars
+= _read (fd
, buffer
, to_read
);
5404 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5406 HANDLE hnd
= fd_info
[fd
].hnd
;
5407 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5414 /* Configure timeouts for non-blocking read. */
5415 if (!GetCommTimeouts (hnd
, &ct
))
5420 ct
.ReadIntervalTimeout
= MAXDWORD
;
5421 ct
.ReadTotalTimeoutMultiplier
= 0;
5422 ct
.ReadTotalTimeoutConstant
= 0;
5423 if (!SetCommTimeouts (hnd
, &ct
))
5429 if (!ResetEvent (ovl
->hEvent
))
5434 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5436 if (GetLastError () != ERROR_IO_PENDING
)
5441 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5450 else /* FILE_SOCKET */
5452 if (winsock_lib
== NULL
) abort ();
5454 /* do the equivalent of a non-blocking read */
5455 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5456 if (waiting
== 0 && nchars
== 0)
5458 h_errno
= errno
= EWOULDBLOCK
;
5464 /* always use binary mode for sockets */
5465 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5466 if (res
== SOCKET_ERROR
)
5468 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5469 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5479 int nread
= _read (fd
, buffer
, count
);
5482 else if (nchars
== 0)
5487 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5488 /* Perform text mode translation if required. */
5489 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5491 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5492 /* If buffer contains only CR, return that. To be absolutely
5493 sure we should attempt to read the next char, but in
5494 practice a CR to be followed by LF would not appear by
5495 itself in the buffer. */
5496 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5498 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5504 nchars
= _read (fd
, buffer
, count
);
5509 /* From w32xfns.c */
5510 extern HANDLE interrupt_handle
;
5512 /* For now, don't bother with a non-blocking mode */
5514 sys_write (int fd
, const void * buffer
, unsigned int count
)
5524 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5526 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5532 /* Perform text mode translation if required. */
5533 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5535 char * tmpbuf
= alloca (count
* 2);
5536 unsigned char * src
= (void *)buffer
;
5537 unsigned char * dst
= tmpbuf
;
5542 unsigned char *next
;
5543 /* copy next line or remaining bytes */
5544 next
= _memccpy (dst
, src
, '\n', nbytes
);
5547 /* copied one line ending with '\n' */
5548 int copied
= next
- dst
;
5551 /* insert '\r' before '\n' */
5558 /* copied remaining partial line -> now finished */
5565 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5567 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5568 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5569 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5572 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5574 if (GetLastError () != ERROR_IO_PENDING
)
5579 if (detect_input_pending ())
5580 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5583 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5584 if (active
== WAIT_OBJECT_0
)
5585 { /* User pressed C-g, cancel write, then leave. Don't bother
5586 cleaning up as we may only get stuck in buggy drivers. */
5587 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5592 if (active
== WAIT_OBJECT_0
+ 1
5593 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5600 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5602 unsigned long nblock
= 0;
5603 if (winsock_lib
== NULL
) abort ();
5605 /* TODO: implement select() properly so non-blocking I/O works. */
5606 /* For now, make sure the write blocks. */
5607 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5608 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5610 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5612 /* Set the socket back to non-blocking if it was before,
5613 for other operations that support it. */
5614 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5617 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5620 if (nchars
== SOCKET_ERROR
)
5622 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5623 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5629 /* Some networked filesystems don't like too large writes, so
5630 break them into smaller chunks. See the Comments section of
5631 the MSDN documentation of WriteFile for details behind the
5632 choice of the value of CHUNK below. See also the thread
5633 http://thread.gmane.org/gmane.comp.version-control.git/145294
5634 in the git mailing list. */
5635 const unsigned char *p
= buffer
;
5636 const unsigned chunk
= 30 * 1024 * 1024;
5641 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5642 int n
= _write (fd
, p
, this_chunk
);
5650 else if (n
< this_chunk
)
5661 check_windows_init_file (void)
5663 extern int noninteractive
, inhibit_window_system
;
5665 /* A common indication that Emacs is not installed properly is when
5666 it cannot find the Windows installation file. If this file does
5667 not exist in the expected place, tell the user. */
5669 if (!noninteractive
&& !inhibit_window_system
)
5671 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
5672 Lisp_Object objs
[2];
5673 Lisp_Object full_load_path
;
5674 Lisp_Object init_file
;
5677 objs
[0] = Vload_path
;
5678 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5679 full_load_path
= Fappend (2, objs
);
5680 init_file
= build_string ("term/w32-win");
5681 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5684 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5685 char *init_file_name
= SDATA (init_file
);
5686 char *load_path
= SDATA (load_path_print
);
5687 char *buffer
= alloca (1024
5688 + strlen (init_file_name
)
5689 + strlen (load_path
));
5692 "The Emacs Windows initialization file \"%s.el\" "
5693 "could not be found in your Emacs installation. "
5694 "Emacs checked the following directories for this file:\n"
5696 "When Emacs cannot find this file, it usually means that it "
5697 "was not installed properly, or its distribution file was "
5698 "not unpacked properly.\nSee the README.W32 file in the "
5699 "top-level Emacs directory for more information.",
5700 init_file_name
, load_path
);
5703 "Emacs Abort Dialog",
5704 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5705 /* Use the low-level Emacs abort. */
5719 /* shutdown the socket interface if necessary */
5728 /* Initialise the socket interface now if available and requested by
5729 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5730 delayed until open-network-stream is called (w32-has-winsock can
5731 also be used to dynamically load or reload winsock).
5733 Conveniently, init_environment is called before us, so
5734 PRELOAD_WINSOCK can be set in the registry. */
5736 /* Always initialize this correctly. */
5739 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5740 init_winsock (TRUE
);
5742 /* Initial preparation for subprocess support: replace our standard
5743 handles with non-inheritable versions. */
5746 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5747 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5748 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5750 parent
= GetCurrentProcess ();
5752 /* ignore errors when duplicating and closing; typically the
5753 handles will be invalid when running as a gui program. */
5754 DuplicateHandle (parent
,
5755 GetStdHandle (STD_INPUT_HANDLE
),
5760 DUPLICATE_SAME_ACCESS
);
5762 DuplicateHandle (parent
,
5763 GetStdHandle (STD_OUTPUT_HANDLE
),
5768 DUPLICATE_SAME_ACCESS
);
5770 DuplicateHandle (parent
,
5771 GetStdHandle (STD_ERROR_HANDLE
),
5776 DUPLICATE_SAME_ACCESS
);
5782 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5783 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5785 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5788 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5789 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5791 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5794 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5795 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5797 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5801 /* unfortunately, atexit depends on implementation of malloc */
5802 /* atexit (term_ntproc); */
5803 signal (SIGABRT
, term_ntproc
);
5805 /* determine which drives are fixed, for GetCachedVolumeInformation */
5807 /* GetDriveType must have trailing backslash. */
5808 char drive
[] = "A:\\";
5810 /* Loop over all possible drive letters */
5811 while (*drive
<= 'Z')
5813 /* Record if this drive letter refers to a fixed drive. */
5814 fixed_drives
[DRIVE_INDEX (*drive
)] =
5815 (GetDriveType (drive
) == DRIVE_FIXED
);
5820 /* Reset the volume info cache. */
5821 volume_cache
= NULL
;
5824 /* Check to see if Emacs has been installed correctly. */
5825 check_windows_init_file ();
5829 shutdown_handler ensures that buffers' autosave files are
5830 up to date when the user logs off, or the system shuts down.
5833 shutdown_handler (DWORD type
)
5835 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5836 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5837 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5838 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5840 /* Shut down cleanly, making sure autosave files are up to date. */
5841 shut_down_emacs (0, 0, Qnil
);
5844 /* Allow other handlers to handle this signal. */
5849 globals_of_w32 is used to initialize those global variables that
5850 must always be initialized on startup even when the global variable
5851 initialized is non zero (see the function main in emacs.c).
5854 globals_of_w32 (void)
5856 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5858 get_process_times_fn
= (GetProcessTimes_Proc
)
5859 GetProcAddress (kernel32
, "GetProcessTimes");
5861 g_b_init_is_windows_9x
= 0;
5862 g_b_init_open_process_token
= 0;
5863 g_b_init_get_token_information
= 0;
5864 g_b_init_lookup_account_sid
= 0;
5865 g_b_init_get_sid_sub_authority
= 0;
5866 g_b_init_get_sid_sub_authority_count
= 0;
5867 g_b_init_get_file_security
= 0;
5868 g_b_init_get_security_descriptor_owner
= 0;
5869 g_b_init_get_security_descriptor_group
= 0;
5870 g_b_init_is_valid_sid
= 0;
5871 g_b_init_create_toolhelp32_snapshot
= 0;
5872 g_b_init_process32_first
= 0;
5873 g_b_init_process32_next
= 0;
5874 g_b_init_open_thread_token
= 0;
5875 g_b_init_impersonate_self
= 0;
5876 g_b_init_revert_to_self
= 0;
5877 g_b_init_get_process_memory_info
= 0;
5878 g_b_init_get_process_working_set_size
= 0;
5879 g_b_init_global_memory_status
= 0;
5880 g_b_init_global_memory_status_ex
= 0;
5881 g_b_init_equal_sid
= 0;
5882 g_b_init_copy_sid
= 0;
5883 g_b_init_get_length_sid
= 0;
5884 g_b_init_get_native_system_info
= 0;
5885 g_b_init_get_system_times
= 0;
5886 num_of_processors
= 0;
5887 /* The following sets a handler for shutdown notifications for
5888 console apps. This actually applies to Emacs in both console and
5889 GUI modes, since we had to fool windows into thinking emacs is a
5890 console application to get console mode to work. */
5891 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
5893 /* "None" is the default group name on standalone workstations. */
5894 strcpy (dflt_group_name
, "None");
5897 /* For make-serial-process */
5899 serial_open (char *port
)
5905 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5906 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5907 if (hnd
== INVALID_HANDLE_VALUE
)
5908 error ("Could not open %s", port
);
5909 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5911 error ("Could not open %s", port
);
5915 error ("Could not create child process");
5917 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5918 fd_info
[ fd
].hnd
= hnd
;
5919 fd_info
[ fd
].flags
|=
5920 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5921 if (fd_info
[ fd
].cp
!= NULL
)
5923 error ("fd_info[fd = %d] is already in use", fd
);
5925 fd_info
[ fd
].cp
= cp
;
5926 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5927 if (cp
->ovl_read
.hEvent
== NULL
)
5928 error ("Could not create read event");
5929 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5930 if (cp
->ovl_write
.hEvent
== NULL
)
5931 error ("Could not create write event");
5936 /* For serial-process-configure */
5938 serial_configure (struct Lisp_Process
*p
,
5939 Lisp_Object contact
)
5941 Lisp_Object childp2
= Qnil
;
5942 Lisp_Object tem
= Qnil
;
5946 char summary
[4] = "???"; /* This usually becomes "8N1". */
5948 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
5949 error ("Not a serial process");
5950 hnd
= fd_info
[ p
->outfd
].hnd
;
5952 childp2
= Fcopy_sequence (p
->childp
);
5954 /* Initialize timeouts for blocking read and blocking write. */
5955 if (!GetCommTimeouts (hnd
, &ct
))
5956 error ("GetCommTimeouts() failed");
5957 ct
.ReadIntervalTimeout
= 0;
5958 ct
.ReadTotalTimeoutMultiplier
= 0;
5959 ct
.ReadTotalTimeoutConstant
= 0;
5960 ct
.WriteTotalTimeoutMultiplier
= 0;
5961 ct
.WriteTotalTimeoutConstant
= 0;
5962 if (!SetCommTimeouts (hnd
, &ct
))
5963 error ("SetCommTimeouts() failed");
5964 /* Read port attributes and prepare default configuration. */
5965 memset (&dcb
, 0, sizeof (dcb
));
5966 dcb
.DCBlength
= sizeof (DCB
);
5967 if (!GetCommState (hnd
, &dcb
))
5968 error ("GetCommState() failed");
5971 dcb
.fAbortOnError
= FALSE
;
5972 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
5977 /* Configure speed. */
5978 if (!NILP (Fplist_member (contact
, QCspeed
)))
5979 tem
= Fplist_get (contact
, QCspeed
);
5981 tem
= Fplist_get (p
->childp
, QCspeed
);
5983 dcb
.BaudRate
= XINT (tem
);
5984 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
5986 /* Configure bytesize. */
5987 if (!NILP (Fplist_member (contact
, QCbytesize
)))
5988 tem
= Fplist_get (contact
, QCbytesize
);
5990 tem
= Fplist_get (p
->childp
, QCbytesize
);
5992 tem
= make_number (8);
5994 if (XINT (tem
) != 7 && XINT (tem
) != 8)
5995 error (":bytesize must be nil (8), 7, or 8");
5996 dcb
.ByteSize
= XINT (tem
);
5997 summary
[0] = XINT (tem
) + '0';
5998 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6000 /* Configure parity. */
6001 if (!NILP (Fplist_member (contact
, QCparity
)))
6002 tem
= Fplist_get (contact
, QCparity
);
6004 tem
= Fplist_get (p
->childp
, QCparity
);
6005 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6006 error (":parity must be nil (no parity), `even', or `odd'");
6007 dcb
.fParity
= FALSE
;
6008 dcb
.Parity
= NOPARITY
;
6009 dcb
.fErrorChar
= FALSE
;
6014 else if (EQ (tem
, Qeven
))
6018 dcb
.Parity
= EVENPARITY
;
6019 dcb
.fErrorChar
= TRUE
;
6021 else if (EQ (tem
, Qodd
))
6025 dcb
.Parity
= ODDPARITY
;
6026 dcb
.fErrorChar
= TRUE
;
6028 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6030 /* Configure stopbits. */
6031 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6032 tem
= Fplist_get (contact
, QCstopbits
);
6034 tem
= Fplist_get (p
->childp
, QCstopbits
);
6036 tem
= make_number (1);
6038 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6039 error (":stopbits must be nil (1 stopbit), 1, or 2");
6040 summary
[2] = XINT (tem
) + '0';
6041 if (XINT (tem
) == 1)
6042 dcb
.StopBits
= ONESTOPBIT
;
6043 else if (XINT (tem
) == 2)
6044 dcb
.StopBits
= TWOSTOPBITS
;
6045 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6047 /* Configure flowcontrol. */
6048 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6049 tem
= Fplist_get (contact
, QCflowcontrol
);
6051 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6052 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6053 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6054 dcb
.fOutxCtsFlow
= FALSE
;
6055 dcb
.fOutxDsrFlow
= FALSE
;
6056 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6057 dcb
.fDsrSensitivity
= FALSE
;
6058 dcb
.fTXContinueOnXoff
= FALSE
;
6061 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6062 dcb
.XonChar
= 17; /* Control-Q */
6063 dcb
.XoffChar
= 19; /* Control-S */
6066 /* Already configured. */
6068 else if (EQ (tem
, Qhw
))
6070 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6071 dcb
.fOutxCtsFlow
= TRUE
;
6073 else if (EQ (tem
, Qsw
))
6078 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6080 /* Activate configuration. */
6081 if (!SetCommState (hnd
, &dcb
))
6082 error ("SetCommState() failed");
6084 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6085 p
->childp
= childp2
;
6090 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6091 (do not change this comment) */