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 */
72 #define _ANONYMOUS_UNION
73 #define _ANONYMOUS_STRUCT
76 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
77 use a different name to avoid compilation problems. */
78 typedef struct _MEMORY_STATUS_EX
{
81 DWORDLONG ullTotalPhys
;
82 DWORDLONG ullAvailPhys
;
83 DWORDLONG ullTotalPageFile
;
84 DWORDLONG ullAvailPageFile
;
85 DWORDLONG ullTotalVirtual
;
86 DWORDLONG ullAvailVirtual
;
87 DWORDLONG ullAvailExtendedVirtual
;
88 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
96 #if !defined(__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
97 /* This either is not in psapi.h or guarded by higher value of
98 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
99 defines it in psapi.h */
100 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
102 DWORD PageFaultCount
;
103 DWORD PeakWorkingSetSize
;
104 DWORD WorkingSetSize
;
105 DWORD QuotaPeakPagedPoolUsage
;
106 DWORD QuotaPagedPoolUsage
;
107 DWORD QuotaPeakNonPagedPoolUsage
;
108 DWORD QuotaNonPagedPoolUsage
;
110 DWORD PeakPagefileUsage
;
112 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
115 /* TCP connection support. */
116 #include <sys/socket.h>
139 #include "dispextern.h" /* for xstrcasecmp */
140 #include "coding.h" /* for Vlocale_coding_system */
142 /* For serial_configure and serial_open. */
145 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
146 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
148 void globals_of_w32 (void);
149 static DWORD
get_rid (PSID
);
151 extern Lisp_Object Vw32_downcase_file_names
;
152 extern Lisp_Object Vw32_generate_fake_inodes
;
153 extern Lisp_Object Vw32_get_true_file_attributes
;
154 /* Defined in process.c for its own purpose. */
155 extern Lisp_Object Qlocal
;
157 extern int w32_num_mouse_buttons
;
160 /* Initialization states.
162 WARNING: If you add any more such variables for additional APIs,
163 you MUST add initialization for them to globals_of_w32
164 below. This is because these variables might get set
165 to non-NULL values during dumping, but the dumped Emacs
166 cannot reuse those values, because it could be run on a
167 different version of the OS, where API addresses are
169 static BOOL g_b_init_is_windows_9x
;
170 static BOOL g_b_init_open_process_token
;
171 static BOOL g_b_init_get_token_information
;
172 static BOOL g_b_init_lookup_account_sid
;
173 static BOOL g_b_init_get_sid_sub_authority
;
174 static BOOL g_b_init_get_sid_sub_authority_count
;
175 static BOOL g_b_init_get_file_security
;
176 static BOOL g_b_init_get_security_descriptor_owner
;
177 static BOOL g_b_init_get_security_descriptor_group
;
178 static BOOL g_b_init_is_valid_sid
;
179 static BOOL g_b_init_create_toolhelp32_snapshot
;
180 static BOOL g_b_init_process32_first
;
181 static BOOL g_b_init_process32_next
;
182 static BOOL g_b_init_open_thread_token
;
183 static BOOL g_b_init_impersonate_self
;
184 static BOOL g_b_init_revert_to_self
;
185 static BOOL g_b_init_get_process_memory_info
;
186 static BOOL g_b_init_get_process_working_set_size
;
187 static BOOL g_b_init_global_memory_status
;
188 static BOOL g_b_init_global_memory_status_ex
;
189 static BOOL g_b_init_get_length_sid
;
190 static BOOL g_b_init_equal_sid
;
191 static BOOL g_b_init_copy_sid
;
192 static BOOL g_b_init_get_native_system_info
;
193 static BOOL g_b_init_get_system_times
;
196 BEGIN: Wrapper functions around OpenProcessToken
197 and other functions in advapi32.dll that are only
198 supported in Windows NT / 2k / XP
200 /* ** Function pointer typedefs ** */
201 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
202 HANDLE ProcessHandle
,
204 PHANDLE TokenHandle
);
205 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
207 TOKEN_INFORMATION_CLASS TokenInformationClass
,
208 LPVOID TokenInformation
,
209 DWORD TokenInformationLength
,
210 PDWORD ReturnLength
);
211 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
212 HANDLE process_handle
,
213 LPFILETIME creation_time
,
214 LPFILETIME exit_time
,
215 LPFILETIME kernel_time
,
216 LPFILETIME user_time
);
218 GetProcessTimes_Proc get_process_times_fn
= NULL
;
221 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
222 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
224 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
225 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
227 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
228 LPCTSTR lpSystemName
,
233 LPDWORD cbDomainName
,
234 PSID_NAME_USE peUse
);
235 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
238 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
240 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
242 SECURITY_INFORMATION RequestedInformation
,
243 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
245 LPDWORD lpnLengthNeeded
);
246 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
247 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
249 LPBOOL lpbOwnerDefaulted
);
250 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
251 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
253 LPBOOL lpbGroupDefaulted
);
254 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
256 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
258 DWORD th32ProcessID
);
259 typedef BOOL (WINAPI
* Process32First_Proc
) (
261 LPPROCESSENTRY32 lppe
);
262 typedef BOOL (WINAPI
* Process32Next_Proc
) (
264 LPPROCESSENTRY32 lppe
);
265 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
269 PHANDLE TokenHandle
);
270 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
271 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
272 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
273 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
275 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
277 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
279 DWORD
* lpMinimumWorkingSetSize
,
280 DWORD
* lpMaximumWorkingSetSize
);
281 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
282 LPMEMORYSTATUS lpBuffer
);
283 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
284 LPMEMORY_STATUS_EX lpBuffer
);
285 typedef BOOL (WINAPI
* CopySid_Proc
) (
286 DWORD nDestinationSidLength
,
287 PSID pDestinationSid
,
289 typedef BOOL (WINAPI
* EqualSid_Proc
) (
292 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
294 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
295 LPSYSTEM_INFO lpSystemInfo
);
296 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
297 LPFILETIME lpIdleTime
,
298 LPFILETIME lpKernelTime
,
299 LPFILETIME lpUserTime
);
301 /* ** A utility function ** */
305 static BOOL s_b_ret
= 0;
306 OSVERSIONINFO os_ver
;
307 if (g_b_init_is_windows_9x
== 0)
309 g_b_init_is_windows_9x
= 1;
310 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
311 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
312 if (GetVersionEx (&os_ver
))
314 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
320 /* Get total user and system times for get-internal-run-time.
321 Returns a list of three integers if the times are provided by the OS
322 (NT derivatives), otherwise it returns the result of current-time. */
324 w32_get_internal_run_time (void)
326 if (get_process_times_fn
)
328 FILETIME create
, exit
, kernel
, user
;
329 HANDLE proc
= GetCurrentProcess ();
330 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
332 LARGE_INTEGER user_int
, kernel_int
, total
;
334 user_int
.LowPart
= user
.dwLowDateTime
;
335 user_int
.HighPart
= user
.dwHighDateTime
;
336 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
337 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
338 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
339 /* FILETIME is 100 nanosecond increments, Emacs only wants
340 microsecond resolution. */
341 total
.QuadPart
/= 10;
342 microseconds
= total
.QuadPart
% 1000000;
343 total
.QuadPart
/= 1000000;
345 /* Sanity check to make sure we can represent the result. */
346 if (total
.HighPart
== 0)
348 int secs
= total
.LowPart
;
350 return list3 (make_number ((secs
>> 16) & 0xffff),
351 make_number (secs
& 0xffff),
352 make_number (microseconds
));
357 return Fcurrent_time ();
360 /* ** The wrapper functions ** */
363 open_process_token (HANDLE ProcessHandle
,
367 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
368 HMODULE hm_advapi32
= NULL
;
369 if (is_windows_9x () == TRUE
)
373 if (g_b_init_open_process_token
== 0)
375 g_b_init_open_process_token
= 1;
376 hm_advapi32
= LoadLibrary ("Advapi32.dll");
377 s_pfn_Open_Process_Token
=
378 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
380 if (s_pfn_Open_Process_Token
== NULL
)
385 s_pfn_Open_Process_Token (
393 get_token_information (HANDLE TokenHandle
,
394 TOKEN_INFORMATION_CLASS TokenInformationClass
,
395 LPVOID TokenInformation
,
396 DWORD TokenInformationLength
,
399 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
400 HMODULE hm_advapi32
= NULL
;
401 if (is_windows_9x () == TRUE
)
405 if (g_b_init_get_token_information
== 0)
407 g_b_init_get_token_information
= 1;
408 hm_advapi32
= LoadLibrary ("Advapi32.dll");
409 s_pfn_Get_Token_Information
=
410 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
412 if (s_pfn_Get_Token_Information
== NULL
)
417 s_pfn_Get_Token_Information (
419 TokenInformationClass
,
421 TokenInformationLength
,
427 lookup_account_sid (LPCTSTR lpSystemName
,
432 LPDWORD cbDomainName
,
435 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
436 HMODULE hm_advapi32
= NULL
;
437 if (is_windows_9x () == TRUE
)
441 if (g_b_init_lookup_account_sid
== 0)
443 g_b_init_lookup_account_sid
= 1;
444 hm_advapi32
= LoadLibrary ("Advapi32.dll");
445 s_pfn_Lookup_Account_Sid
=
446 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
448 if (s_pfn_Lookup_Account_Sid
== NULL
)
453 s_pfn_Lookup_Account_Sid (
465 get_sid_sub_authority (PSID pSid
, DWORD n
)
467 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
468 static DWORD zero
= 0U;
469 HMODULE hm_advapi32
= NULL
;
470 if (is_windows_9x () == TRUE
)
474 if (g_b_init_get_sid_sub_authority
== 0)
476 g_b_init_get_sid_sub_authority
= 1;
477 hm_advapi32
= LoadLibrary ("Advapi32.dll");
478 s_pfn_Get_Sid_Sub_Authority
=
479 (GetSidSubAuthority_Proc
) GetProcAddress (
480 hm_advapi32
, "GetSidSubAuthority");
482 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
486 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
490 get_sid_sub_authority_count (PSID pSid
)
492 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
493 static UCHAR zero
= 0U;
494 HMODULE hm_advapi32
= NULL
;
495 if (is_windows_9x () == TRUE
)
499 if (g_b_init_get_sid_sub_authority_count
== 0)
501 g_b_init_get_sid_sub_authority_count
= 1;
502 hm_advapi32
= LoadLibrary ("Advapi32.dll");
503 s_pfn_Get_Sid_Sub_Authority_Count
=
504 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
505 hm_advapi32
, "GetSidSubAuthorityCount");
507 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
511 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
515 get_file_security (LPCTSTR lpFileName
,
516 SECURITY_INFORMATION RequestedInformation
,
517 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
519 LPDWORD lpnLengthNeeded
)
521 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
522 HMODULE hm_advapi32
= NULL
;
523 if (is_windows_9x () == TRUE
)
527 if (g_b_init_get_file_security
== 0)
529 g_b_init_get_file_security
= 1;
530 hm_advapi32
= LoadLibrary ("Advapi32.dll");
531 s_pfn_Get_File_Security
=
532 (GetFileSecurity_Proc
) GetProcAddress (
533 hm_advapi32
, GetFileSecurity_Name
);
535 if (s_pfn_Get_File_Security
== NULL
)
539 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
540 pSecurityDescriptor
, nLength
,
545 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
547 LPBOOL lpbOwnerDefaulted
)
549 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
550 HMODULE hm_advapi32
= NULL
;
551 if (is_windows_9x () == TRUE
)
555 if (g_b_init_get_security_descriptor_owner
== 0)
557 g_b_init_get_security_descriptor_owner
= 1;
558 hm_advapi32
= LoadLibrary ("Advapi32.dll");
559 s_pfn_Get_Security_Descriptor_Owner
=
560 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
561 hm_advapi32
, "GetSecurityDescriptorOwner");
563 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
567 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
572 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
574 LPBOOL lpbGroupDefaulted
)
576 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
577 HMODULE hm_advapi32
= NULL
;
578 if (is_windows_9x () == TRUE
)
582 if (g_b_init_get_security_descriptor_group
== 0)
584 g_b_init_get_security_descriptor_group
= 1;
585 hm_advapi32
= LoadLibrary ("Advapi32.dll");
586 s_pfn_Get_Security_Descriptor_Group
=
587 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
588 hm_advapi32
, "GetSecurityDescriptorGroup");
590 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
594 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
599 is_valid_sid (PSID sid
)
601 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
602 HMODULE hm_advapi32
= NULL
;
603 if (is_windows_9x () == TRUE
)
607 if (g_b_init_is_valid_sid
== 0)
609 g_b_init_is_valid_sid
= 1;
610 hm_advapi32
= LoadLibrary ("Advapi32.dll");
612 (IsValidSid_Proc
) GetProcAddress (
613 hm_advapi32
, "IsValidSid");
615 if (s_pfn_Is_Valid_Sid
== NULL
)
619 return (s_pfn_Is_Valid_Sid (sid
));
623 equal_sid (PSID sid1
, PSID sid2
)
625 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
626 HMODULE hm_advapi32
= NULL
;
627 if (is_windows_9x () == TRUE
)
631 if (g_b_init_equal_sid
== 0)
633 g_b_init_equal_sid
= 1;
634 hm_advapi32
= LoadLibrary ("Advapi32.dll");
636 (EqualSid_Proc
) GetProcAddress (
637 hm_advapi32
, "EqualSid");
639 if (s_pfn_Equal_Sid
== NULL
)
643 return (s_pfn_Equal_Sid (sid1
, sid2
));
647 get_length_sid (PSID sid
)
649 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
650 HMODULE hm_advapi32
= NULL
;
651 if (is_windows_9x () == TRUE
)
655 if (g_b_init_get_length_sid
== 0)
657 g_b_init_get_length_sid
= 1;
658 hm_advapi32
= LoadLibrary ("Advapi32.dll");
659 s_pfn_Get_Length_Sid
=
660 (GetLengthSid_Proc
) GetProcAddress (
661 hm_advapi32
, "GetLengthSid");
663 if (s_pfn_Get_Length_Sid
== NULL
)
667 return (s_pfn_Get_Length_Sid (sid
));
671 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
673 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
674 HMODULE hm_advapi32
= NULL
;
675 if (is_windows_9x () == TRUE
)
679 if (g_b_init_copy_sid
== 0)
681 g_b_init_copy_sid
= 1;
682 hm_advapi32
= LoadLibrary ("Advapi32.dll");
684 (CopySid_Proc
) GetProcAddress (
685 hm_advapi32
, "CopySid");
687 if (s_pfn_Copy_Sid
== NULL
)
691 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
695 END: Wrapper functions around OpenProcessToken
696 and other functions in advapi32.dll that are only
697 supported in Windows NT / 2k / XP
701 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
703 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
704 if (is_windows_9x () != TRUE
)
706 if (g_b_init_get_native_system_info
== 0)
708 g_b_init_get_native_system_info
= 1;
709 s_pfn_Get_Native_System_Info
=
710 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
711 "GetNativeSystemInfo");
713 if (s_pfn_Get_Native_System_Info
!= NULL
)
714 s_pfn_Get_Native_System_Info (lpSystemInfo
);
717 lpSystemInfo
->dwNumberOfProcessors
= -1;
721 get_system_times (LPFILETIME lpIdleTime
,
722 LPFILETIME lpKernelTime
,
723 LPFILETIME lpUserTime
)
725 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
726 if (is_windows_9x () == TRUE
)
730 if (g_b_init_get_system_times
== 0)
732 g_b_init_get_system_times
= 1;
733 s_pfn_Get_System_times
=
734 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
737 if (s_pfn_Get_System_times
== NULL
)
739 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
742 /* Equivalent of strerror for W32 error codes. */
744 w32_strerror (int error_no
)
746 static char buf
[500];
749 error_no
= GetLastError ();
752 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
754 0, /* choose most suitable language */
755 buf
, sizeof (buf
), NULL
))
756 sprintf (buf
, "w32 error %u", error_no
);
760 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
761 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
763 This is called from alloc.c:valid_pointer_p. */
765 w32_valid_pointer_p (void *p
, int size
)
768 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
772 unsigned char *buf
= alloca (size
);
773 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
782 static char startup_dir
[MAXPATHLEN
];
784 /* Get the current working directory. */
789 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
793 /* Emacs doesn't actually change directory itself, and we want to
794 force our real wd to be where emacs.exe is to avoid unnecessary
795 conflicts when trying to rename or delete directories. */
796 strcpy (dir
, startup_dir
);
801 /* Emulate getloadavg. */
810 /* Number of processors on this machine. */
811 static unsigned num_of_processors
;
813 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
814 static struct load_sample samples
[16*60];
815 static int first_idx
= -1, last_idx
= -1;
816 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
821 int next_idx
= from
+ 1;
823 if (next_idx
>= max_idx
)
832 int prev_idx
= from
- 1;
835 prev_idx
= max_idx
- 1;
841 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
844 FILETIME ft_idle
, ft_user
, ft_kernel
;
846 /* Initialize the number of processors on this machine. */
847 if (num_of_processors
<= 0)
849 get_native_system_info (&sysinfo
);
850 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
851 if (num_of_processors
<= 0)
853 GetSystemInfo (&sysinfo
);
854 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
856 if (num_of_processors
<= 0)
857 num_of_processors
= 1;
860 /* TODO: Take into account threads that are ready to run, by
861 sampling the "\System\Processor Queue Length" performance
862 counter. The code below accounts only for threads that are
865 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
867 ULARGE_INTEGER uidle
, ukernel
, uuser
;
869 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
870 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
871 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
872 *idle
= uidle
.QuadPart
;
873 *kernel
= ukernel
.QuadPart
;
874 *user
= uuser
.QuadPart
;
884 /* Produce the load average for a given time interval, using the
885 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
886 1-minute, 5-minute, or 15-minute average, respectively. */
890 double retval
= -1.0;
893 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
894 time_t now
= samples
[last_idx
].sample_time
;
896 if (first_idx
!= last_idx
)
898 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
900 tdiff
= difftime (now
, samples
[idx
].sample_time
);
901 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
904 samples
[last_idx
].kernel
+ samples
[last_idx
].user
905 - (samples
[idx
].kernel
+ samples
[idx
].user
);
906 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
908 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
911 if (idx
== first_idx
)
920 getloadavg (double loadavg
[], int nelem
)
923 ULONGLONG idle
, kernel
, user
;
924 time_t now
= time (NULL
);
926 /* Store another sample. We ignore samples that are less than 1 sec
928 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
930 sample_system_load (&idle
, &kernel
, &user
);
931 last_idx
= buf_next (last_idx
);
932 samples
[last_idx
].sample_time
= now
;
933 samples
[last_idx
].idle
= idle
;
934 samples
[last_idx
].kernel
= kernel
;
935 samples
[last_idx
].user
= user
;
936 /* If the buffer has more that 15 min worth of samples, discard
939 first_idx
= last_idx
;
940 while (first_idx
!= last_idx
941 && (difftime (now
, samples
[first_idx
].sample_time
)
942 >= 15.0*60 + 2*DBL_EPSILON
*now
))
943 first_idx
= buf_next (first_idx
);
946 for (elem
= 0; elem
< nelem
; elem
++)
948 double avg
= getavg (elem
);
958 /* Emulate getpwuid, getpwnam and others. */
960 #define PASSWD_FIELD_SIZE 256
962 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
963 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
964 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
965 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
966 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
968 static struct passwd dflt_passwd
=
980 static char dflt_group_name
[GNLEN
+1];
982 static struct group dflt_group
=
984 /* When group information is not available, we return this as the
985 group for all files. */
993 return dflt_passwd
.pw_uid
;
999 /* I could imagine arguing for checking to see whether the user is
1000 in the Administrators group and returning a UID of 0 for that
1001 case, but I don't know how wise that would be in the long run. */
1008 return dflt_passwd
.pw_gid
;
1018 getpwuid (unsigned uid
)
1020 if (uid
== dflt_passwd
.pw_uid
)
1021 return &dflt_passwd
;
1026 getgrgid (gid_t gid
)
1032 getpwnam (char *name
)
1036 pw
= getpwuid (getuid ());
1040 if (xstrcasecmp (name
, pw
->pw_name
))
1047 init_user_info (void)
1049 /* Find the user's real name by opening the process token and
1050 looking up the name associated with the user-sid in that token.
1052 Use the relative portion of the identifier authority value from
1053 the user-sid as the user id value (same for group id using the
1054 primary group sid from the process token). */
1056 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1057 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1058 DWORD glength
= sizeof (gname
);
1059 HANDLE token
= NULL
;
1060 SID_NAME_USE user_type
;
1061 unsigned char *buf
= NULL
;
1063 TOKEN_USER user_token
;
1064 TOKEN_PRIMARY_GROUP group_token
;
1067 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1070 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1071 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1073 buf
= xmalloc (blen
);
1074 result
= get_token_information (token
, TokenUser
,
1075 (LPVOID
)buf
, blen
, &needed
);
1078 memcpy (&user_token
, buf
, sizeof (user_token
));
1079 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1081 domain
, &dlength
, &user_type
);
1089 strcpy (dflt_passwd
.pw_name
, uname
);
1090 /* Determine a reasonable uid value. */
1091 if (xstrcasecmp ("administrator", uname
) == 0)
1093 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1094 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1098 /* Use the last sub-authority value of the RID, the relative
1099 portion of the SID, as user/group ID. */
1100 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1102 /* Get group id and name. */
1103 result
= get_token_information (token
, TokenPrimaryGroup
,
1104 (LPVOID
)buf
, blen
, &needed
);
1105 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1107 buf
= xrealloc (buf
, blen
= needed
);
1108 result
= get_token_information (token
, TokenPrimaryGroup
,
1109 (LPVOID
)buf
, blen
, &needed
);
1113 memcpy (&group_token
, buf
, sizeof (group_token
));
1114 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1115 dlength
= sizeof (domain
);
1116 /* If we can get at the real Primary Group name, use that.
1117 Otherwise, the default group name was already set to
1118 "None" in globals_of_w32. */
1119 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1120 gname
, &glength
, NULL
, &dlength
,
1122 strcpy (dflt_group_name
, gname
);
1125 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1128 /* If security calls are not supported (presumably because we
1129 are running under Windows 9X), fallback to this: */
1130 else if (GetUserName (uname
, &ulength
))
1132 strcpy (dflt_passwd
.pw_name
, uname
);
1133 if (xstrcasecmp ("administrator", uname
) == 0)
1134 dflt_passwd
.pw_uid
= 0;
1136 dflt_passwd
.pw_uid
= 123;
1137 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1141 strcpy (dflt_passwd
.pw_name
, "unknown");
1142 dflt_passwd
.pw_uid
= 123;
1143 dflt_passwd
.pw_gid
= 123;
1145 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1147 /* Ensure HOME and SHELL are defined. */
1148 if (getenv ("HOME") == NULL
)
1150 if (getenv ("SHELL") == NULL
)
1153 /* Set dir and shell from environment variables. */
1154 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1155 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1159 CloseHandle (token
);
1165 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1166 return ((rand () << 15) | rand ());
1176 /* Normalize filename by converting all path separators to
1177 the specified separator. Also conditionally convert upper
1178 case path name components to lower case. */
1181 normalize_filename (register char *fp
, char path_sep
)
1186 /* Always lower-case drive letters a-z, even if the filesystem
1187 preserves case in filenames.
1188 This is so filenames can be compared by string comparison
1189 functions that are case-sensitive. Even case-preserving filesystems
1190 do not distinguish case in drive letters. */
1191 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1197 if (NILP (Vw32_downcase_file_names
))
1201 if (*fp
== '/' || *fp
== '\\')
1208 sep
= path_sep
; /* convert to this path separator */
1209 elem
= fp
; /* start of current path element */
1212 if (*fp
>= 'a' && *fp
<= 'z')
1213 elem
= 0; /* don't convert this element */
1215 if (*fp
== 0 || *fp
== ':')
1217 sep
= *fp
; /* restore current separator (or 0) */
1218 *fp
= '/'; /* after conversion of this element */
1221 if (*fp
== '/' || *fp
== '\\')
1223 if (elem
&& elem
!= fp
)
1225 *fp
= 0; /* temporary end of string */
1226 _strlwr (elem
); /* while we convert to lower case */
1228 *fp
= sep
; /* convert (or restore) path separator */
1229 elem
= fp
+ 1; /* next element starts after separator */
1235 /* Destructively turn backslashes into slashes. */
1237 dostounix_filename (register char *p
)
1239 normalize_filename (p
, '/');
1242 /* Destructively turn slashes into backslashes. */
1244 unixtodos_filename (register char *p
)
1246 normalize_filename (p
, '\\');
1249 /* Remove all CR's that are followed by a LF.
1250 (From msdos.c...probably should figure out a way to share it,
1251 although this code isn't going to ever change.) */
1253 crlf_to_lf (register int n
, register unsigned char *buf
)
1255 unsigned char *np
= buf
;
1256 unsigned char *startp
= buf
;
1257 unsigned char *endp
= buf
+ n
;
1261 while (buf
< endp
- 1)
1265 if (*(++buf
) != 0x0a)
1276 /* Parse the root part of file name, if present. Return length and
1277 optionally store pointer to char after root. */
1279 parse_root (char * name
, char ** pPath
)
1281 char * start
= name
;
1286 /* find the root name of the volume if given */
1287 if (isalpha (name
[0]) && name
[1] == ':')
1289 /* skip past drive specifier */
1291 if (IS_DIRECTORY_SEP (name
[0]))
1294 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1300 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1305 if (IS_DIRECTORY_SEP (name
[0]))
1312 return name
- start
;
1315 /* Get long base name for name; name is assumed to be absolute. */
1317 get_long_basename (char * name
, char * buf
, int size
)
1319 WIN32_FIND_DATA find_data
;
1323 /* must be valid filename, no wild cards or other invalid characters */
1324 if (_mbspbrk (name
, "*?|<>\""))
1327 dir_handle
= FindFirstFile (name
, &find_data
);
1328 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1330 if ((len
= strlen (find_data
.cFileName
)) < size
)
1331 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1334 FindClose (dir_handle
);
1339 /* Get long name for file, if possible (assumed to be absolute). */
1341 w32_get_long_filename (char * name
, char * buf
, int size
)
1346 char full
[ MAX_PATH
];
1349 len
= strlen (name
);
1350 if (len
>= MAX_PATH
)
1353 /* Use local copy for destructive modification. */
1354 memcpy (full
, name
, len
+1);
1355 unixtodos_filename (full
);
1357 /* Copy root part verbatim. */
1358 len
= parse_root (full
, &p
);
1359 memcpy (o
, full
, len
);
1364 while (p
!= NULL
&& *p
)
1367 p
= strchr (q
, '\\');
1369 len
= get_long_basename (full
, o
, size
);
1392 is_unc_volume (const char *filename
)
1394 const char *ptr
= filename
;
1396 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1399 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1405 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1408 sigsetmask (int signal_mask
)
1426 sigunblock (int sig
)
1432 sigemptyset (sigset_t
*set
)
1438 sigaddset (sigset_t
*set
, int signo
)
1444 sigfillset (sigset_t
*set
)
1450 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1456 setpgrp (int pid
, int gid
)
1467 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1470 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1473 HKEY hrootkey
= NULL
;
1476 /* Check both the current user and the local machine to see if
1477 we have any resources. */
1479 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1483 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1484 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1485 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1487 RegCloseKey (hrootkey
);
1493 RegCloseKey (hrootkey
);
1496 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1500 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1501 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1502 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1504 RegCloseKey (hrootkey
);
1510 RegCloseKey (hrootkey
);
1516 char *get_emacs_configuration (void);
1517 extern Lisp_Object Vsystem_configuration
;
1520 init_environment (char ** argv
)
1522 static const char * const tempdirs
[] = {
1523 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1528 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1530 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1531 temporary files and assume "/tmp" if $TMPDIR is unset, which
1532 will break on DOS/Windows. Refuse to work if we cannot find
1533 a directory, not even "c:/", usable for that purpose. */
1534 for (i
= 0; i
< imax
; i
++)
1536 const char *tmp
= tempdirs
[i
];
1539 tmp
= getenv (tmp
+ 1);
1540 /* Note that `access' can lie to us if the directory resides on a
1541 read-only filesystem, like CD-ROM or a write-protected floppy.
1542 The only way to be really sure is to actually create a file and
1543 see if it succeeds. But I think that's too much to ask. */
1544 if (tmp
&& _access (tmp
, D_OK
) == 0)
1546 char * var
= alloca (strlen (tmp
) + 8);
1547 sprintf (var
, "TMPDIR=%s", tmp
);
1548 _putenv (strdup (var
));
1555 Fcons (build_string ("no usable temporary directories found!!"),
1557 "While setting TMPDIR: ");
1559 /* Check for environment variables and use registry settings if they
1560 don't exist. Fallback on default values where applicable. */
1565 char locale_name
[32];
1566 struct stat ignored
;
1567 char default_home
[MAX_PATH
];
1569 static const struct env_entry
1576 {"PRELOAD_WINSOCK", NULL
},
1577 {"emacs_dir", "C:/emacs"},
1578 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1579 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1580 {"EMACSDATA", "%emacs_dir%/etc"},
1581 {"EMACSPATH", "%emacs_dir%/bin"},
1582 /* We no longer set INFOPATH because Info-default-directory-list
1584 /* {"INFOPATH", "%emacs_dir%/info"}, */
1585 {"EMACSDOC", "%emacs_dir%/etc"},
1590 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1592 /* We need to copy dflt_envvars[] and work on the copy because we
1593 don't want the dumped Emacs to inherit the values of
1594 environment variables we saw during dumping (which could be on
1595 a different system). The defaults above must be left intact. */
1596 struct env_entry env_vars
[N_ENV_VARS
];
1598 for (i
= 0; i
< N_ENV_VARS
; i
++)
1599 env_vars
[i
] = dflt_envvars
[i
];
1601 /* For backwards compatibility, check if a .emacs file exists in C:/
1602 If not, then we can try to default to the appdata directory under the
1603 user's profile, which is more likely to be writable. */
1604 if (stat ("C:/.emacs", &ignored
) < 0)
1606 HRESULT profile_result
;
1607 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1608 of Windows 95 and NT4 that have not been updated to include
1610 ShGetFolderPath_fn get_folder_path
;
1611 get_folder_path
= (ShGetFolderPath_fn
)
1612 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1614 if (get_folder_path
!= NULL
)
1616 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1619 /* If we can't get the appdata dir, revert to old behavior. */
1620 if (profile_result
== S_OK
)
1621 env_vars
[0].def_value
= default_home
;
1625 /* Get default locale info and use it for LANG. */
1626 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1627 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1628 locale_name
, sizeof (locale_name
)))
1630 for (i
= 0; i
< N_ENV_VARS
; i
++)
1632 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1634 env_vars
[i
].def_value
= locale_name
;
1640 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1642 /* Treat emacs_dir specially: set it unconditionally based on our
1643 location, if it appears that we are running from the bin subdir
1644 of a standard installation. */
1647 char modname
[MAX_PATH
];
1649 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1651 if ((p
= strrchr (modname
, '\\')) == NULL
)
1655 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1657 char buf
[SET_ENV_BUF_SIZE
];
1660 for (p
= modname
; *p
; p
++)
1661 if (*p
== '\\') *p
= '/';
1663 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1664 _putenv (strdup (buf
));
1666 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1668 /* FIXME: should use substring of get_emacs_configuration ().
1669 But I don't think the Windows build supports alpha, mips etc
1670 anymore, so have taken the easy option for now. */
1671 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1674 p
= strrchr (modname
, '\\');
1678 p
= strrchr (modname
, '\\');
1679 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1681 char buf
[SET_ENV_BUF_SIZE
];
1684 for (p
= modname
; *p
; p
++)
1685 if (*p
== '\\') *p
= '/';
1687 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1688 _putenv (strdup (buf
));
1694 for (i
= 0; i
< N_ENV_VARS
; i
++)
1696 if (!getenv (env_vars
[i
].name
))
1700 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1701 /* Also ignore empty environment variables. */
1705 lpval
= env_vars
[i
].def_value
;
1706 dwType
= REG_EXPAND_SZ
;
1712 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1714 if (dwType
== REG_EXPAND_SZ
)
1715 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1716 else if (dwType
== REG_SZ
)
1717 strcpy (buf1
, lpval
);
1718 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1720 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1722 _putenv (strdup (buf2
));
1732 /* Rebuild system configuration to reflect invoking system. */
1733 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1735 /* Another special case: on NT, the PATH variable is actually named
1736 "Path" although cmd.exe (perhaps NT itself) arranges for
1737 environment variable lookup and setting to be case insensitive.
1738 However, Emacs assumes a fully case sensitive environment, so we
1739 need to change "Path" to "PATH" to match the expectations of
1740 various elisp packages. We do this by the sneaky method of
1741 modifying the string in the C runtime environ entry.
1743 The same applies to COMSPEC. */
1747 for (envp
= environ
; *envp
; envp
++)
1748 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1749 memcpy (*envp
, "PATH=", 5);
1750 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1751 memcpy (*envp
, "COMSPEC=", 8);
1754 /* Remember the initial working directory for getwd, then make the
1755 real wd be the location of emacs.exe to avoid conflicts when
1756 renaming or deleting directories. (We also don't call chdir when
1757 running subprocesses for the same reason.) */
1758 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1763 static char modname
[MAX_PATH
];
1765 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1767 if ((p
= strrchr (modname
, '\\')) == NULL
)
1771 SetCurrentDirectory (modname
);
1773 /* Ensure argv[0] has the full path to Emacs. */
1778 /* Determine if there is a middle mouse button, to allow parse_button
1779 to decide whether right mouse events should be mouse-2 or
1781 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1787 emacs_root_dir (void)
1789 static char root_dir
[FILENAME_MAX
];
1792 p
= getenv ("emacs_dir");
1795 strcpy (root_dir
, p
);
1796 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1797 dostounix_filename (root_dir
);
1801 /* We don't have scripts to automatically determine the system configuration
1802 for Emacs before it's compiled, and we don't want to have to make the
1803 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1807 get_emacs_configuration (void)
1809 char *arch
, *oem
, *os
;
1811 static char configuration_buffer
[32];
1813 /* Determine the processor type. */
1814 switch (get_processor_type ())
1817 #ifdef PROCESSOR_INTEL_386
1818 case PROCESSOR_INTEL_386
:
1819 case PROCESSOR_INTEL_486
:
1820 case PROCESSOR_INTEL_PENTIUM
:
1825 #ifdef PROCESSOR_MIPS_R2000
1826 case PROCESSOR_MIPS_R2000
:
1827 case PROCESSOR_MIPS_R3000
:
1828 case PROCESSOR_MIPS_R4000
:
1833 #ifdef PROCESSOR_ALPHA_21064
1834 case PROCESSOR_ALPHA_21064
:
1844 /* Use the OEM field to reflect the compiler/library combination. */
1846 #define COMPILER_NAME "msvc"
1849 #define COMPILER_NAME "mingw"
1851 #define COMPILER_NAME "unknown"
1854 oem
= COMPILER_NAME
;
1856 switch (osinfo_cache
.dwPlatformId
) {
1857 case VER_PLATFORM_WIN32_NT
:
1859 build_num
= osinfo_cache
.dwBuildNumber
;
1861 case VER_PLATFORM_WIN32_WINDOWS
:
1862 if (osinfo_cache
.dwMinorVersion
== 0) {
1867 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1869 case VER_PLATFORM_WIN32s
:
1870 /* Not supported, should not happen. */
1872 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1880 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1881 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1882 get_w32_major_version (), get_w32_minor_version (), build_num
);
1884 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1887 return configuration_buffer
;
1891 get_emacs_configuration_options (void)
1893 static char *options_buffer
;
1894 char cv
[32]; /* Enough for COMPILER_VERSION. */
1896 cv
, /* To be filled later. */
1900 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1901 with a starting space to save work here. */
1903 " --cflags", USER_CFLAGS
,
1906 " --ldflags", USER_LDFLAGS
,
1913 /* Work out the effective configure options for this build. */
1915 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1918 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1920 #define COMPILER_VERSION ""
1924 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
1925 return "Error: not enough space for compiler version";
1926 cv
[sizeof (cv
) - 1] = '\0';
1928 for (i
= 0; options
[i
]; i
++)
1929 size
+= strlen (options
[i
]);
1931 options_buffer
= xmalloc (size
+ 1);
1932 options_buffer
[0] = '\0';
1934 for (i
= 0; options
[i
]; i
++)
1935 strcat (options_buffer
, options
[i
]);
1937 return options_buffer
;
1941 #include <sys/timeb.h>
1943 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1945 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1950 tv
->tv_sec
= tb
.time
;
1951 tv
->tv_usec
= tb
.millitm
* 1000L;
1954 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1955 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1959 /* ------------------------------------------------------------------------- */
1960 /* IO support and wrapper functions for W32 API. */
1961 /* ------------------------------------------------------------------------- */
1963 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1964 on network directories, so we handle that case here.
1965 (Ulrich Leodolter, 1/11/95). */
1967 sys_ctime (const time_t *t
)
1969 char *str
= (char *) ctime (t
);
1970 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1973 /* Emulate sleep...we could have done this with a define, but that
1974 would necessitate including windows.h in the files that used it.
1975 This is much easier. */
1977 sys_sleep (int seconds
)
1979 Sleep (seconds
* 1000);
1982 /* Internal MSVC functions for low-level descriptor munging */
1983 extern int __cdecl
_set_osfhnd (int fd
, long h
);
1984 extern int __cdecl
_free_osfhnd (int fd
);
1986 /* parallel array of private info on file handles */
1987 filedesc fd_info
[ MAXDESC
];
1989 typedef struct volume_info_data
{
1990 struct volume_info_data
* next
;
1992 /* time when info was obtained */
1995 /* actual volume info */
2004 /* Global referenced by various functions. */
2005 static volume_info_data volume_info
;
2007 /* Vector to indicate which drives are local and fixed (for which cached
2008 data never expires). */
2009 static BOOL fixed_drives
[26];
2011 /* Consider cached volume information to be stale if older than 10s,
2012 at least for non-local drives. Info for fixed drives is never stale. */
2013 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2014 #define VOLINFO_STILL_VALID( root_dir, info ) \
2015 ( ( isalpha (root_dir[0]) && \
2016 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2017 || GetTickCount () - info->timestamp < 10000 )
2019 /* Cache support functions. */
2021 /* Simple linked list with linear search is sufficient. */
2022 static volume_info_data
*volume_cache
= NULL
;
2024 static volume_info_data
*
2025 lookup_volume_info (char * root_dir
)
2027 volume_info_data
* info
;
2029 for (info
= volume_cache
; info
; info
= info
->next
)
2030 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2036 add_volume_info (char * root_dir
, volume_info_data
* info
)
2038 info
->root_dir
= xstrdup (root_dir
);
2039 info
->next
= volume_cache
;
2040 volume_cache
= info
;
2044 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2045 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2046 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2047 static volume_info_data
*
2048 GetCachedVolumeInformation (char * root_dir
)
2050 volume_info_data
* info
;
2051 char default_root
[ MAX_PATH
];
2053 /* NULL for root_dir means use root from current directory. */
2054 if (root_dir
== NULL
)
2056 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2058 parse_root (default_root
, &root_dir
);
2060 root_dir
= default_root
;
2063 /* Local fixed drives can be cached permanently. Removable drives
2064 cannot be cached permanently, since the volume name and serial
2065 number (if nothing else) can change. Remote drives should be
2066 treated as if they are removable, since there is no sure way to
2067 tell whether they are or not. Also, the UNC association of drive
2068 letters mapped to remote volumes can be changed at any time (even
2069 by other processes) without notice.
2071 As a compromise, so we can benefit from caching info for remote
2072 volumes, we use a simple expiry mechanism to invalidate cache
2073 entries that are more than ten seconds old. */
2076 /* No point doing this, because WNetGetConnection is even slower than
2077 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2078 GetDriveType is about the only call of this type which does not
2079 involve network access, and so is extremely quick). */
2081 /* Map drive letter to UNC if remote. */
2082 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2084 char remote_name
[ 256 ];
2085 char drive
[3] = { root_dir
[0], ':' };
2087 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2089 /* do something */ ;
2093 info
= lookup_volume_info (root_dir
);
2095 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2103 /* Info is not cached, or is stale. */
2104 if (!GetVolumeInformation (root_dir
,
2105 name
, sizeof (name
),
2109 type
, sizeof (type
)))
2112 /* Cache the volume information for future use, overwriting existing
2113 entry if present. */
2116 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2117 add_volume_info (root_dir
, info
);
2125 info
->name
= xstrdup (name
);
2126 info
->serialnum
= serialnum
;
2127 info
->maxcomp
= maxcomp
;
2128 info
->flags
= flags
;
2129 info
->type
= xstrdup (type
);
2130 info
->timestamp
= GetTickCount ();
2136 /* Get information on the volume where name is held; set path pointer to
2137 start of pathname in name (past UNC header\volume header if present). */
2139 get_volume_info (const char * name
, const char ** pPath
)
2141 char temp
[MAX_PATH
];
2142 char *rootname
= NULL
; /* default to current volume */
2143 volume_info_data
* info
;
2148 /* find the root name of the volume if given */
2149 if (isalpha (name
[0]) && name
[1] == ':')
2157 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2164 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2177 info
= GetCachedVolumeInformation (rootname
);
2180 /* Set global referenced by other functions. */
2181 volume_info
= *info
;
2187 /* Determine if volume is FAT format (ie. only supports short 8.3
2188 names); also set path pointer to start of pathname in name. */
2190 is_fat_volume (const char * name
, const char ** pPath
)
2192 if (get_volume_info (name
, pPath
))
2193 return (volume_info
.maxcomp
== 12);
2197 /* Map filename to a valid 8.3 name if necessary. */
2199 map_w32_filename (const char * name
, const char ** pPath
)
2201 static char shortname
[MAX_PATH
];
2202 char * str
= shortname
;
2205 const char * save_name
= name
;
2207 if (strlen (name
) >= MAX_PATH
)
2209 /* Return a filename which will cause callers to fail. */
2210 strcpy (shortname
, "?");
2214 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2216 register int left
= 8; /* maximum number of chars in part */
2217 register int extn
= 0; /* extension added? */
2218 register int dots
= 2; /* maximum number of dots allowed */
2221 *str
++ = *name
++; /* skip past UNC header */
2223 while ((c
= *name
++))
2230 extn
= 0; /* reset extension flags */
2231 dots
= 2; /* max 2 dots */
2232 left
= 8; /* max length 8 for main part */
2236 extn
= 0; /* reset extension flags */
2237 dots
= 2; /* max 2 dots */
2238 left
= 8; /* max length 8 for main part */
2243 /* Convert path components of the form .xxx to _xxx,
2244 but leave . and .. as they are. This allows .emacs
2245 to be read as _emacs, for example. */
2249 IS_DIRECTORY_SEP (*name
))
2264 extn
= 1; /* we've got an extension */
2265 left
= 3; /* 3 chars in extension */
2269 /* any embedded dots after the first are converted to _ */
2274 case '#': /* don't lose these, they're important */
2276 str
[-1] = c
; /* replace last character of part */
2281 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2283 dots
= 0; /* started a path component */
2292 strcpy (shortname
, name
);
2293 unixtodos_filename (shortname
);
2297 *pPath
= shortname
+ (path
- save_name
);
2303 is_exec (const char * name
)
2305 char * p
= strrchr (name
, '.');
2308 && (xstrcasecmp (p
, ".exe") == 0 ||
2309 xstrcasecmp (p
, ".com") == 0 ||
2310 xstrcasecmp (p
, ".bat") == 0 ||
2311 xstrcasecmp (p
, ".cmd") == 0));
2314 /* Emulate the Unix directory procedures opendir, closedir,
2315 and readdir. We can't use the procedures supplied in sysdep.c,
2316 so we provide them here. */
2318 struct direct dir_static
; /* simulated directory contents */
2319 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2320 static int dir_is_fat
;
2321 static char dir_pathname
[MAXPATHLEN
+1];
2322 static WIN32_FIND_DATA dir_find_data
;
2324 /* Support shares on a network resource as subdirectories of a read-only
2326 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2327 static HANDLE
open_unc_volume (const char *);
2328 static char *read_unc_volume (HANDLE
, char *, int);
2329 static void close_unc_volume (HANDLE
);
2332 opendir (char *filename
)
2336 /* Opening is done by FindFirstFile. However, a read is inherent to
2337 this operation, so we defer the open until read time. */
2339 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2341 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2344 if (is_unc_volume (filename
))
2346 wnet_enum_handle
= open_unc_volume (filename
);
2347 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2351 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2358 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2359 dir_pathname
[MAXPATHLEN
] = '\0';
2360 dir_is_fat
= is_fat_volume (filename
, NULL
);
2366 closedir (DIR *dirp
)
2368 /* If we have a find-handle open, close it. */
2369 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2371 FindClose (dir_find_handle
);
2372 dir_find_handle
= INVALID_HANDLE_VALUE
;
2374 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2376 close_unc_volume (wnet_enum_handle
);
2377 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2379 xfree ((char *) dirp
);
2385 int downcase
= !NILP (Vw32_downcase_file_names
);
2387 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2389 if (!read_unc_volume (wnet_enum_handle
,
2390 dir_find_data
.cFileName
,
2394 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2395 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2397 char filename
[MAXNAMLEN
+ 3];
2400 strcpy (filename
, dir_pathname
);
2401 ln
= strlen (filename
) - 1;
2402 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2403 strcat (filename
, "\\");
2404 strcat (filename
, "*");
2406 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2408 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2413 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2417 /* Emacs never uses this value, so don't bother making it match
2418 value returned by stat(). */
2419 dir_static
.d_ino
= 1;
2421 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2423 /* If the file name in cFileName[] includes `?' characters, it means
2424 the original file name used characters that cannot be represented
2425 by the current ANSI codepage. To avoid total lossage, retrieve
2426 the short 8+3 alias of the long file name. */
2427 if (_mbspbrk (dir_static
.d_name
, "?"))
2429 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2430 downcase
= 1; /* 8+3 aliases are returned in all caps */
2432 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2433 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2434 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2436 /* If the file name in cFileName[] includes `?' characters, it means
2437 the original file name used characters that cannot be represented
2438 by the current ANSI codepage. To avoid total lossage, retrieve
2439 the short 8+3 alias of the long file name. */
2440 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2442 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2443 /* 8+3 aliases are returned in all caps, which could break
2444 various alists that look at filenames' extensions. */
2448 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2449 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2451 _strlwr (dir_static
.d_name
);
2455 for (p
= dir_static
.d_name
; *p
; p
++)
2456 if (*p
>= 'a' && *p
<= 'z')
2459 _strlwr (dir_static
.d_name
);
2466 open_unc_volume (const char *path
)
2472 nr
.dwScope
= RESOURCE_GLOBALNET
;
2473 nr
.dwType
= RESOURCETYPE_DISK
;
2474 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2475 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2476 nr
.lpLocalName
= NULL
;
2477 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2478 nr
.lpComment
= NULL
;
2479 nr
.lpProvider
= NULL
;
2481 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2482 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2484 if (result
== NO_ERROR
)
2487 return INVALID_HANDLE_VALUE
;
2491 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2495 DWORD bufsize
= 512;
2500 buffer
= alloca (bufsize
);
2501 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2502 if (result
!= NO_ERROR
)
2505 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2506 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2508 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2511 strncpy (readbuf
, ptr
, size
);
2516 close_unc_volume (HANDLE henum
)
2518 if (henum
!= INVALID_HANDLE_VALUE
)
2519 WNetCloseEnum (henum
);
2523 unc_volume_file_attributes (const char *path
)
2528 henum
= open_unc_volume (path
);
2529 if (henum
== INVALID_HANDLE_VALUE
)
2532 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2534 close_unc_volume (henum
);
2539 /* Ensure a network connection is authenticated. */
2541 logon_network_drive (const char *path
)
2543 NETRESOURCE resource
;
2544 char share
[MAX_PATH
];
2549 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2550 drvtype
= DRIVE_REMOTE
;
2551 else if (path
[0] == '\0' || path
[1] != ':')
2552 drvtype
= GetDriveType (NULL
);
2559 drvtype
= GetDriveType (drive
);
2562 /* Only logon to networked drives. */
2563 if (drvtype
!= DRIVE_REMOTE
)
2567 strncpy (share
, path
, MAX_PATH
);
2568 /* Truncate to just server and share name. */
2569 for (i
= 2; i
< MAX_PATH
; i
++)
2571 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2578 resource
.dwType
= RESOURCETYPE_DISK
;
2579 resource
.lpLocalName
= NULL
;
2580 resource
.lpRemoteName
= share
;
2581 resource
.lpProvider
= NULL
;
2583 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2586 /* Shadow some MSVC runtime functions to map requests for long filenames
2587 to reasonable short names if necessary. This was originally added to
2588 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2592 sys_access (const char * path
, int mode
)
2596 /* MSVC implementation doesn't recognize D_OK. */
2597 path
= map_w32_filename (path
, NULL
);
2598 if (is_unc_volume (path
))
2600 attributes
= unc_volume_file_attributes (path
);
2601 if (attributes
== -1) {
2606 else if ((attributes
= GetFileAttributes (path
)) == -1)
2608 /* Should try mapping GetLastError to errno; for now just indicate
2609 that path doesn't exist. */
2613 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2618 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2623 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2632 sys_chdir (const char * path
)
2634 return _chdir (map_w32_filename (path
, NULL
));
2638 sys_chmod (const char * path
, int mode
)
2640 return _chmod (map_w32_filename (path
, NULL
), mode
);
2644 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2646 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2652 sys_creat (const char * path
, int mode
)
2654 return _creat (map_w32_filename (path
, NULL
), mode
);
2658 sys_fopen (const char * path
, const char * mode
)
2662 const char * mode_save
= mode
;
2664 /* Force all file handles to be non-inheritable. This is necessary to
2665 ensure child processes don't unwittingly inherit handles that might
2666 prevent future file access. */
2670 else if (mode
[0] == 'w' || mode
[0] == 'a')
2671 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2675 /* Only do simplistic option parsing. */
2679 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2682 else if (mode
[0] == 'b')
2687 else if (mode
[0] == 't')
2694 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2698 return _fdopen (fd
, mode_save
);
2701 /* This only works on NTFS volumes, but is useful to have. */
2703 sys_link (const char * old
, const char * new)
2707 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2709 if (old
== NULL
|| new == NULL
)
2715 strcpy (oldname
, map_w32_filename (old
, NULL
));
2716 strcpy (newname
, map_w32_filename (new, NULL
));
2718 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2719 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2720 if (fileh
!= INVALID_HANDLE_VALUE
)
2724 /* Confusingly, the "alternate" stream name field does not apply
2725 when restoring a hard link, and instead contains the actual
2726 stream data for the link (ie. the name of the link to create).
2727 The WIN32_STREAM_ID structure before the cStreamName field is
2728 the stream header, which is then immediately followed by the
2732 WIN32_STREAM_ID wid
;
2733 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2736 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2737 data
.wid
.cStreamName
, MAX_PATH
);
2740 LPVOID context
= NULL
;
2743 data
.wid
.dwStreamId
= BACKUP_LINK
;
2744 data
.wid
.dwStreamAttributes
= 0;
2745 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2746 data
.wid
.Size
.HighPart
= 0;
2747 data
.wid
.dwStreamNameSize
= 0;
2749 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2750 offsetof (WIN32_STREAM_ID
, cStreamName
)
2751 + data
.wid
.Size
.LowPart
,
2752 &wbytes
, FALSE
, FALSE
, &context
)
2753 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2760 /* Should try mapping GetLastError to errno; for now just
2761 indicate a general error (eg. links not supported). */
2762 errno
= EINVAL
; // perhaps EMLINK?
2766 CloseHandle (fileh
);
2775 sys_mkdir (const char * path
)
2777 return _mkdir (map_w32_filename (path
, NULL
));
2780 /* Because of long name mapping issues, we need to implement this
2781 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2782 a unique name, instead of setting the input template to an empty
2785 Standard algorithm seems to be use pid or tid with a letter on the
2786 front (in place of the 6 X's) and cycle through the letters to find a
2787 unique name. We extend that to allow any reasonable character as the
2788 first of the 6 X's. */
2790 sys_mktemp (char * template)
2794 unsigned uid
= GetCurrentThreadId ();
2795 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2797 if (template == NULL
)
2799 p
= template + strlen (template);
2801 /* replace up to the last 5 X's with uid in decimal */
2802 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2804 p
[0] = '0' + uid
% 10;
2808 if (i
< 0 && p
[0] == 'X')
2813 int save_errno
= errno
;
2814 p
[0] = first_char
[i
];
2815 if (sys_access (template, 0) < 0)
2821 while (++i
< sizeof (first_char
));
2824 /* Template is badly formed or else we can't generate a unique name,
2825 so return empty string */
2831 sys_open (const char * path
, int oflag
, int mode
)
2833 const char* mpath
= map_w32_filename (path
, NULL
);
2834 /* Try to open file without _O_CREAT, to be able to write to hidden
2835 and system files. Force all file handles to be
2837 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2840 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2844 sys_rename (const char * oldname
, const char * newname
)
2847 char temp
[MAX_PATH
];
2849 /* MoveFile on Windows 95 doesn't correctly change the short file name
2850 alias in a number of circumstances (it is not easy to predict when
2851 just by looking at oldname and newname, unfortunately). In these
2852 cases, renaming through a temporary name avoids the problem.
2854 A second problem on Windows 95 is that renaming through a temp name when
2855 newname is uppercase fails (the final long name ends up in
2856 lowercase, although the short alias might be uppercase) UNLESS the
2857 long temp name is not 8.3.
2859 So, on Windows 95 we always rename through a temp name, and we make sure
2860 the temp name has a long extension to ensure correct renaming. */
2862 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2864 if (os_subtype
== OS_WIN95
)
2870 oldname
= map_w32_filename (oldname
, NULL
);
2871 if (o
= strrchr (oldname
, '\\'))
2874 o
= (char *) oldname
;
2876 if (p
= strrchr (temp
, '\\'))
2883 /* Force temp name to require a manufactured 8.3 alias - this
2884 seems to make the second rename work properly. */
2885 sprintf (p
, "_.%s.%u", o
, i
);
2887 result
= rename (oldname
, temp
);
2889 /* This loop must surely terminate! */
2890 while (result
< 0 && errno
== EEXIST
);
2895 /* Emulate Unix behavior - newname is deleted if it already exists
2896 (at least if it is a file; don't do this for directories).
2898 Since we mustn't do this if we are just changing the case of the
2899 file name (we would end up deleting the file we are trying to
2900 rename!), we let rename detect if the destination file already
2901 exists - that way we avoid the possible pitfalls of trying to
2902 determine ourselves whether two names really refer to the same
2903 file, which is not always possible in the general case. (Consider
2904 all the permutations of shared or subst'd drives, etc.) */
2906 newname
= map_w32_filename (newname
, NULL
);
2907 result
= rename (temp
, newname
);
2911 && _chmod (newname
, 0666) == 0
2912 && _unlink (newname
) == 0)
2913 result
= rename (temp
, newname
);
2919 sys_rmdir (const char * path
)
2921 return _rmdir (map_w32_filename (path
, NULL
));
2925 sys_unlink (const char * path
)
2927 path
= map_w32_filename (path
, NULL
);
2929 /* On Unix, unlink works without write permission. */
2930 _chmod (path
, 0666);
2931 return _unlink (path
);
2934 static FILETIME utc_base_ft
;
2935 static ULONGLONG utc_base
; /* In 100ns units */
2936 static int init
= 0;
2938 #define FILETIME_TO_U64(result, ft) \
2940 ULARGE_INTEGER uiTemp; \
2941 uiTemp.LowPart = (ft).dwLowDateTime; \
2942 uiTemp.HighPart = (ft).dwHighDateTime; \
2943 result = uiTemp.QuadPart; \
2947 initialize_utc_base (void)
2949 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2958 st
.wMilliseconds
= 0;
2960 SystemTimeToFileTime (&st
, &utc_base_ft
);
2961 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2965 convert_time (FILETIME ft
)
2971 initialize_utc_base ();
2975 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2978 FILETIME_TO_U64 (tmp
, ft
);
2979 return (time_t) ((tmp
- utc_base
) / 10000000L);
2983 convert_from_time_t (time_t time
, FILETIME
* pft
)
2989 initialize_utc_base ();
2993 /* time in 100ns units since 1-Jan-1601 */
2994 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
2995 pft
->dwHighDateTime
= tmp
.HighPart
;
2996 pft
->dwLowDateTime
= tmp
.LowPart
;
3000 /* No reason to keep this; faking inode values either by hashing or even
3001 using the file index from GetInformationByHandle, is not perfect and
3002 so by default Emacs doesn't use the inode values on Windows.
3003 Instead, we now determine file-truename correctly (except for
3004 possible drive aliasing etc). */
3006 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3008 hashval (const unsigned char * str
)
3013 h
= (h
<< 4) + *str
++;
3019 /* Return the hash value of the canonical pathname, excluding the
3020 drive/UNC header, to get a hopefully unique inode number. */
3022 generate_inode_val (const char * name
)
3024 char fullname
[ MAX_PATH
];
3028 /* Get the truly canonical filename, if it exists. (Note: this
3029 doesn't resolve aliasing due to subst commands, or recognise hard
3031 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3034 parse_root (fullname
, &p
);
3035 /* Normal W32 filesystems are still case insensitive. */
3042 static PSECURITY_DESCRIPTOR
3043 get_file_security_desc (const char *fname
)
3045 PSECURITY_DESCRIPTOR psd
= NULL
;
3047 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3048 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3050 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3052 err
= GetLastError ();
3053 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3057 psd
= xmalloc (sd_len
);
3058 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3070 unsigned n_subauthorities
;
3072 /* Use the last sub-authority value of the RID, the relative
3073 portion of the SID, as user/group ID. */
3074 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3075 if (n_subauthorities
< 1)
3076 return 0; /* the "World" RID */
3077 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3080 /* Caching SID and account values for faster lokup. */
3083 # define FLEXIBLE_ARRAY_MEMBER
3085 # define FLEXIBLE_ARRAY_MEMBER 1
3090 struct w32_id
*next
;
3092 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3095 static struct w32_id
*w32_idlist
;
3098 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3100 struct w32_id
*tail
, *found
;
3102 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3104 if (equal_sid ((PSID
)tail
->sid
, sid
))
3113 strcpy (name
, found
->name
);
3121 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3124 struct w32_id
*new_entry
;
3126 /* We don't want to leave behind stale cache from when Emacs was
3130 sid_len
= get_length_sid (sid
);
3131 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3134 new_entry
->rid
= id
;
3135 strcpy (new_entry
->name
, name
);
3136 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3137 new_entry
->next
= w32_idlist
;
3138 w32_idlist
= new_entry
;
3147 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3148 unsigned *id
, char *nm
, int what
)
3151 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3153 SID_NAME_USE ignore
;
3155 DWORD name_len
= sizeof (name
);
3157 DWORD domain_len
= sizeof (domain
);
3163 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3164 else if (what
== GID
)
3165 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3169 if (!result
|| !is_valid_sid (sid
))
3171 else if (!w32_cached_id (sid
, id
, nm
))
3173 /* If FNAME is a UNC, we need to lookup account on the
3174 specified machine. */
3175 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3176 && fname
[2] != '\0')
3181 for (s
= fname
+ 2, p
= machine
;
3182 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3188 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3189 domain
, &domain_len
, &ignore
)
3190 || name_len
> UNLEN
+1)
3194 *id
= get_rid (sid
);
3196 w32_add_to_cache (sid
, *id
, name
);
3203 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3207 int dflt_usr
= 0, dflt_grp
= 0;
3216 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3218 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3221 /* Consider files to belong to current user/group, if we cannot get
3222 more accurate information. */
3225 st
->st_uid
= dflt_passwd
.pw_uid
;
3226 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3230 st
->st_gid
= dflt_passwd
.pw_gid
;
3231 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3235 /* Return non-zero if NAME is a potentially slow filesystem. */
3237 is_slow_fs (const char *name
)
3242 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3243 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3244 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3245 devtype
= GetDriveType (NULL
); /* use root of current drive */
3248 /* GetDriveType needs the root directory of the drive. */
3249 strncpy (drive_root
, name
, 2);
3250 drive_root
[2] = '\\';
3251 drive_root
[3] = '\0';
3252 devtype
= GetDriveType (drive_root
);
3254 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3257 /* MSVC stat function can't cope with UNC names and has other bugs, so
3258 replace it with our own. This also allows us to calculate consistent
3259 inode values without hacks in the main Emacs code. */
3261 stat (const char * path
, struct stat
* buf
)
3266 WIN32_FIND_DATA wfd
;
3268 unsigned __int64 fake_inode
;
3271 int rootdir
= FALSE
;
3272 PSECURITY_DESCRIPTOR psd
= NULL
;
3274 if (path
== NULL
|| buf
== NULL
)
3280 name
= (char *) map_w32_filename (path
, &path
);
3281 /* Must be valid filename, no wild cards or other invalid
3282 characters. We use _mbspbrk to support multibyte strings that
3283 might look to strpbrk as if they included literal *, ?, and other
3284 characters mentioned below that are disallowed by Windows
3286 if (_mbspbrk (name
, "*?|<>\""))
3292 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3293 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3294 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3299 /* Remove trailing directory separator, unless name is the root
3300 directory of a drive or UNC volume in which case ensure there
3301 is a trailing separator. */
3302 len
= strlen (name
);
3303 rootdir
= (path
>= name
+ len
- 1
3304 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3305 name
= strcpy (alloca (len
+ 2), name
);
3307 if (is_unc_volume (name
))
3309 DWORD attrs
= unc_volume_file_attributes (name
);
3314 memset (&wfd
, 0, sizeof (wfd
));
3315 wfd
.dwFileAttributes
= attrs
;
3316 wfd
.ftCreationTime
= utc_base_ft
;
3317 wfd
.ftLastAccessTime
= utc_base_ft
;
3318 wfd
.ftLastWriteTime
= utc_base_ft
;
3319 strcpy (wfd
.cFileName
, name
);
3323 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3324 strcat (name
, "\\");
3325 if (GetDriveType (name
) < 2)
3330 memset (&wfd
, 0, sizeof (wfd
));
3331 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3332 wfd
.ftCreationTime
= utc_base_ft
;
3333 wfd
.ftLastAccessTime
= utc_base_ft
;
3334 wfd
.ftLastWriteTime
= utc_base_ft
;
3335 strcpy (wfd
.cFileName
, name
);
3339 if (IS_DIRECTORY_SEP (name
[len
-1]))
3342 /* (This is hacky, but helps when doing file completions on
3343 network drives.) Optimize by using information available from
3344 active readdir if possible. */
3345 len
= strlen (dir_pathname
);
3346 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3348 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3349 && strnicmp (name
, dir_pathname
, len
) == 0
3350 && IS_DIRECTORY_SEP (name
[len
])
3351 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3353 /* This was the last entry returned by readdir. */
3354 wfd
= dir_find_data
;
3358 logon_network_drive (name
);
3360 fh
= FindFirstFile (name
, &wfd
);
3361 if (fh
== INVALID_HANDLE_VALUE
)
3370 if (!(NILP (Vw32_get_true_file_attributes
)
3371 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3372 /* No access rights required to get info. */
3373 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3374 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3375 != INVALID_HANDLE_VALUE
)
3377 /* This is more accurate in terms of gettting the correct number
3378 of links, but is quite slow (it is noticeable when Emacs is
3379 making a list of file name completions). */
3380 BY_HANDLE_FILE_INFORMATION info
;
3382 if (GetFileInformationByHandle (fh
, &info
))
3384 buf
->st_nlink
= info
.nNumberOfLinks
;
3385 /* Might as well use file index to fake inode values, but this
3386 is not guaranteed to be unique unless we keep a handle open
3387 all the time (even then there are situations where it is
3388 not unique). Reputedly, there are at most 48 bits of info
3389 (on NTFS, presumably less on FAT). */
3390 fake_inode
= info
.nFileIndexHigh
;
3392 fake_inode
+= info
.nFileIndexLow
;
3400 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3402 buf
->st_mode
= S_IFDIR
;
3406 switch (GetFileType (fh
))
3408 case FILE_TYPE_DISK
:
3409 buf
->st_mode
= S_IFREG
;
3411 case FILE_TYPE_PIPE
:
3412 buf
->st_mode
= S_IFIFO
;
3414 case FILE_TYPE_CHAR
:
3415 case FILE_TYPE_UNKNOWN
:
3417 buf
->st_mode
= S_IFCHR
;
3421 psd
= get_file_security_desc (name
);
3422 get_file_owner_and_group (psd
, name
, buf
);
3426 /* Don't bother to make this information more accurate. */
3427 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3432 get_file_owner_and_group (NULL
, name
, buf
);
3437 /* Not sure if there is any point in this. */
3438 if (!NILP (Vw32_generate_fake_inodes
))
3439 fake_inode
= generate_inode_val (name
);
3440 else if (fake_inode
== 0)
3442 /* For want of something better, try to make everything unique. */
3443 static DWORD gen_num
= 0;
3444 fake_inode
= ++gen_num
;
3448 /* MSVC defines _ino_t to be short; other libc's might not. */
3449 if (sizeof (buf
->st_ino
) == 2)
3450 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3452 buf
->st_ino
= fake_inode
;
3454 /* volume_info is set indirectly by map_w32_filename */
3455 buf
->st_dev
= volume_info
.serialnum
;
3456 buf
->st_rdev
= volume_info
.serialnum
;
3458 buf
->st_size
= wfd
.nFileSizeHigh
;
3459 buf
->st_size
<<= 32;
3460 buf
->st_size
+= wfd
.nFileSizeLow
;
3462 /* Convert timestamps to Unix format. */
3463 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3464 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3465 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3466 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3467 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3469 /* determine rwx permissions */
3470 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3471 permission
= S_IREAD
;
3473 permission
= S_IREAD
| S_IWRITE
;
3475 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3476 permission
|= S_IEXEC
;
3477 else if (is_exec (name
))
3478 permission
|= S_IEXEC
;
3480 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3485 /* Provide fstat and utime as well as stat for consistent handling of
3488 fstat (int desc
, struct stat
* buf
)
3490 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3491 BY_HANDLE_FILE_INFORMATION info
;
3492 unsigned __int64 fake_inode
;
3495 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3497 case FILE_TYPE_DISK
:
3498 buf
->st_mode
= S_IFREG
;
3499 if (!GetFileInformationByHandle (fh
, &info
))
3505 case FILE_TYPE_PIPE
:
3506 buf
->st_mode
= S_IFIFO
;
3508 case FILE_TYPE_CHAR
:
3509 case FILE_TYPE_UNKNOWN
:
3511 buf
->st_mode
= S_IFCHR
;
3513 memset (&info
, 0, sizeof (info
));
3514 info
.dwFileAttributes
= 0;
3515 info
.ftCreationTime
= utc_base_ft
;
3516 info
.ftLastAccessTime
= utc_base_ft
;
3517 info
.ftLastWriteTime
= utc_base_ft
;
3520 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3521 buf
->st_mode
= S_IFDIR
;
3523 buf
->st_nlink
= info
.nNumberOfLinks
;
3524 /* Might as well use file index to fake inode values, but this
3525 is not guaranteed to be unique unless we keep a handle open
3526 all the time (even then there are situations where it is
3527 not unique). Reputedly, there are at most 48 bits of info
3528 (on NTFS, presumably less on FAT). */
3529 fake_inode
= info
.nFileIndexHigh
;
3531 fake_inode
+= info
.nFileIndexLow
;
3533 /* MSVC defines _ino_t to be short; other libc's might not. */
3534 if (sizeof (buf
->st_ino
) == 2)
3535 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3537 buf
->st_ino
= fake_inode
;
3539 /* Consider files to belong to current user.
3540 FIXME: this should use GetSecurityInfo API, but it is only
3541 available for _WIN32_WINNT >= 0x501. */
3542 buf
->st_uid
= dflt_passwd
.pw_uid
;
3543 buf
->st_gid
= dflt_passwd
.pw_gid
;
3544 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3545 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3547 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3548 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3550 buf
->st_size
= info
.nFileSizeHigh
;
3551 buf
->st_size
<<= 32;
3552 buf
->st_size
+= info
.nFileSizeLow
;
3554 /* Convert timestamps to Unix format. */
3555 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3556 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3557 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3558 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3559 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3561 /* determine rwx permissions */
3562 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3563 permission
= S_IREAD
;
3565 permission
= S_IREAD
| S_IWRITE
;
3567 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3568 permission
|= S_IEXEC
;
3571 #if 0 /* no way of knowing the filename */
3572 char * p
= strrchr (name
, '.');
3574 (xstrcasecmp (p
, ".exe") == 0 ||
3575 xstrcasecmp (p
, ".com") == 0 ||
3576 xstrcasecmp (p
, ".bat") == 0 ||
3577 xstrcasecmp (p
, ".cmd") == 0))
3578 permission
|= S_IEXEC
;
3582 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3588 utime (const char *name
, struct utimbuf
*times
)
3590 struct utimbuf deftime
;
3597 deftime
.modtime
= deftime
.actime
= time (NULL
);
3601 /* Need write access to set times. */
3602 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3603 0, OPEN_EXISTING
, 0, NULL
);
3606 convert_from_time_t (times
->actime
, &atime
);
3607 convert_from_time_t (times
->modtime
, &mtime
);
3608 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3625 /* Support for browsing other processes and their attributes. See
3626 process.c for the Lisp bindings. */
3628 /* Helper wrapper functions. */
3630 static HANDLE WINAPI
3631 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
3633 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3635 if (g_b_init_create_toolhelp32_snapshot
== 0)
3637 g_b_init_create_toolhelp32_snapshot
= 1;
3638 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3639 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3640 "CreateToolhelp32Snapshot");
3642 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3644 return INVALID_HANDLE_VALUE
;
3646 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3650 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3652 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3654 if (g_b_init_process32_first
== 0)
3656 g_b_init_process32_first
= 1;
3657 s_pfn_Process32_First
= (Process32First_Proc
)
3658 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3661 if (s_pfn_Process32_First
== NULL
)
3665 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3669 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3671 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3673 if (g_b_init_process32_next
== 0)
3675 g_b_init_process32_next
= 1;
3676 s_pfn_Process32_Next
= (Process32Next_Proc
)
3677 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3680 if (s_pfn_Process32_Next
== NULL
)
3684 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3688 open_thread_token (HANDLE ThreadHandle
,
3689 DWORD DesiredAccess
,
3691 PHANDLE TokenHandle
)
3693 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3694 HMODULE hm_advapi32
= NULL
;
3695 if (is_windows_9x () == TRUE
)
3697 SetLastError (ERROR_NOT_SUPPORTED
);
3700 if (g_b_init_open_thread_token
== 0)
3702 g_b_init_open_thread_token
= 1;
3703 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3704 s_pfn_Open_Thread_Token
=
3705 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3707 if (s_pfn_Open_Thread_Token
== NULL
)
3709 SetLastError (ERROR_NOT_SUPPORTED
);
3713 s_pfn_Open_Thread_Token (
3722 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3724 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3725 HMODULE hm_advapi32
= NULL
;
3726 if (is_windows_9x () == TRUE
)
3730 if (g_b_init_impersonate_self
== 0)
3732 g_b_init_impersonate_self
= 1;
3733 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3734 s_pfn_Impersonate_Self
=
3735 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3737 if (s_pfn_Impersonate_Self
== NULL
)
3741 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3745 revert_to_self (void)
3747 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3748 HMODULE hm_advapi32
= NULL
;
3749 if (is_windows_9x () == TRUE
)
3753 if (g_b_init_revert_to_self
== 0)
3755 g_b_init_revert_to_self
= 1;
3756 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3757 s_pfn_Revert_To_Self
=
3758 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3760 if (s_pfn_Revert_To_Self
== NULL
)
3764 return s_pfn_Revert_To_Self ();
3768 get_process_memory_info (HANDLE h_proc
,
3769 PPROCESS_MEMORY_COUNTERS mem_counters
,
3772 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3773 HMODULE hm_psapi
= NULL
;
3774 if (is_windows_9x () == TRUE
)
3778 if (g_b_init_get_process_memory_info
== 0)
3780 g_b_init_get_process_memory_info
= 1;
3781 hm_psapi
= LoadLibrary ("Psapi.dll");
3783 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3784 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3786 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3790 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3794 get_process_working_set_size (HANDLE h_proc
,
3798 static GetProcessWorkingSetSize_Proc
3799 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3801 if (is_windows_9x () == TRUE
)
3805 if (g_b_init_get_process_working_set_size
== 0)
3807 g_b_init_get_process_working_set_size
= 1;
3808 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3809 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3810 "GetProcessWorkingSetSize");
3812 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3816 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3820 global_memory_status (MEMORYSTATUS
*buf
)
3822 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3824 if (is_windows_9x () == TRUE
)
3828 if (g_b_init_global_memory_status
== 0)
3830 g_b_init_global_memory_status
= 1;
3831 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3832 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3833 "GlobalMemoryStatus");
3835 if (s_pfn_Global_Memory_Status
== NULL
)
3839 return s_pfn_Global_Memory_Status (buf
);
3843 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
3845 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3847 if (is_windows_9x () == TRUE
)
3851 if (g_b_init_global_memory_status_ex
== 0)
3853 g_b_init_global_memory_status_ex
= 1;
3854 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3855 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3856 "GlobalMemoryStatusEx");
3858 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3862 return s_pfn_Global_Memory_Status_Ex (buf
);
3866 list_system_processes (void)
3868 struct gcpro gcpro1
;
3869 Lisp_Object proclist
= Qnil
;
3872 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3874 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3876 PROCESSENTRY32 proc_entry
;
3882 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3883 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3884 res
= process32_next (h_snapshot
, &proc_entry
))
3886 proc_id
= proc_entry
.th32ProcessID
;
3887 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3890 CloseHandle (h_snapshot
);
3892 proclist
= Fnreverse (proclist
);
3899 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3901 TOKEN_PRIVILEGES priv
;
3902 DWORD priv_size
= sizeof (priv
);
3903 DWORD opriv_size
= sizeof (*old_priv
);
3904 HANDLE h_token
= NULL
;
3905 HANDLE h_thread
= GetCurrentThread ();
3909 res
= open_thread_token (h_thread
,
3910 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3912 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3914 if (impersonate_self (SecurityImpersonation
))
3915 res
= open_thread_token (h_thread
,
3916 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3921 priv
.PrivilegeCount
= 1;
3922 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3923 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3924 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3925 old_priv
, &opriv_size
)
3926 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3930 CloseHandle (h_token
);
3936 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3938 DWORD priv_size
= sizeof (*priv
);
3939 HANDLE h_token
= NULL
;
3942 if (open_thread_token (GetCurrentThread (),
3943 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3946 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3947 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3951 CloseHandle (h_token
);
3957 ltime (long time_sec
, long time_usec
)
3959 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3960 make_number (time_sec
& 0xffff),
3961 make_number (time_usec
));
3964 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
3967 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
3968 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
3971 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
3972 ULONGLONG tem1
, tem2
, tem3
, tem
;
3975 || !get_process_times_fn
3976 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
3977 &ft_kernel
, &ft_user
))
3980 GetSystemTimeAsFileTime (&ft_current
);
3982 FILETIME_TO_U64 (tem1
, ft_kernel
);
3984 *stime
= U64_TO_LISP_TIME (tem1
);
3986 FILETIME_TO_U64 (tem2
, ft_user
);
3988 *utime
= U64_TO_LISP_TIME (tem2
);
3991 *ttime
= U64_TO_LISP_TIME (tem3
);
3993 FILETIME_TO_U64 (tem
, ft_creation
);
3994 /* Process no 4 (System) returns zero creation time. */
3996 tem
= (tem
- utc_base
) / 10L;
3997 *ctime
= U64_TO_LISP_TIME (tem
);
4001 FILETIME_TO_U64 (tem3
, ft_current
);
4002 tem
= (tem3
- utc_base
) / 10L - tem
;
4004 *etime
= U64_TO_LISP_TIME (tem
);
4008 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4019 system_process_attributes (Lisp_Object pid
)
4021 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4022 Lisp_Object attrs
= Qnil
;
4023 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4024 HANDLE h_snapshot
, h_proc
;
4027 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4028 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4029 DWORD glength
= sizeof (gname
);
4030 HANDLE token
= NULL
;
4031 SID_NAME_USE user_type
;
4032 unsigned char *buf
= NULL
;
4034 TOKEN_USER user_token
;
4035 TOKEN_PRIMARY_GROUP group_token
;
4039 PROCESS_MEMORY_COUNTERS mem
;
4040 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4041 DWORD minrss
, maxrss
;
4043 MEMORY_STATUS_EX memstex
;
4044 double totphys
= 0.0;
4045 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4047 BOOL result
= FALSE
;
4049 CHECK_NUMBER_OR_FLOAT (pid
);
4050 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4052 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4054 GCPRO3 (attrs
, decoded_cmd
, tem
);
4056 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4061 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4062 for (res
= process32_first (h_snapshot
, &pe
); res
;
4063 res
= process32_next (h_snapshot
, &pe
))
4065 if (proc_id
== pe
.th32ProcessID
)
4068 decoded_cmd
= build_string ("Idle");
4071 /* Decode the command name from locale-specific
4073 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4074 strlen (pe
.szExeFile
));
4076 code_convert_string_norecord (cmd_str
,
4077 Vlocale_coding_system
, 0);
4079 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4080 attrs
= Fcons (Fcons (Qppid
,
4081 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4083 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4085 attrs
= Fcons (Fcons (Qthcount
,
4086 make_fixnum_or_float (pe
.cntThreads
)),
4093 CloseHandle (h_snapshot
);
4102 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4104 /* If we were denied a handle to the process, try again after
4105 enabling the SeDebugPrivilege in our process. */
4108 TOKEN_PRIVILEGES priv_current
;
4110 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4112 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4114 restore_privilege (&priv_current
);
4120 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4123 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4124 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4126 buf
= xmalloc (blen
);
4127 result
= get_token_information (token
, TokenUser
,
4128 (LPVOID
)buf
, blen
, &needed
);
4131 memcpy (&user_token
, buf
, sizeof (user_token
));
4132 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4134 euid
= get_rid (user_token
.User
.Sid
);
4135 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4140 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4143 strcpy (uname
, "unknown");
4147 ulength
= strlen (uname
);
4153 /* Determine a reasonable euid and gid values. */
4154 if (xstrcasecmp ("administrator", uname
) == 0)
4156 euid
= 500; /* well-known Administrator uid */
4157 egid
= 513; /* well-known None gid */
4161 /* Get group id and name. */
4162 result
= get_token_information (token
, TokenPrimaryGroup
,
4163 (LPVOID
)buf
, blen
, &needed
);
4164 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4166 buf
= xrealloc (buf
, blen
= needed
);
4167 result
= get_token_information (token
, TokenPrimaryGroup
,
4168 (LPVOID
)buf
, blen
, &needed
);
4172 memcpy (&group_token
, buf
, sizeof (group_token
));
4173 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4175 egid
= get_rid (group_token
.PrimaryGroup
);
4176 dlength
= sizeof (domain
);
4178 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4179 gname
, &glength
, NULL
, &dlength
,
4182 w32_add_to_cache (group_token
.PrimaryGroup
,
4186 strcpy (gname
, "None");
4190 glength
= strlen (gname
);
4198 if (!is_windows_9x ())
4200 /* We couldn't open the process token, presumably because of
4201 insufficient access rights. Assume this process is run
4203 strcpy (uname
, "SYSTEM");
4204 strcpy (gname
, "None");
4205 euid
= 18; /* SYSTEM */
4206 egid
= 513; /* None */
4207 glength
= strlen (gname
);
4208 ulength
= strlen (uname
);
4210 /* If we are running under Windows 9X, where security calls are
4211 not supported, we assume all processes are run by the current
4213 else if (GetUserName (uname
, &ulength
))
4215 if (xstrcasecmp ("administrator", uname
) == 0)
4220 strcpy (gname
, "None");
4221 glength
= strlen (gname
);
4222 ulength
= strlen (uname
);
4228 strcpy (uname
, "administrator");
4229 ulength
= strlen (uname
);
4230 strcpy (gname
, "None");
4231 glength
= strlen (gname
);
4234 CloseHandle (token
);
4237 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4238 tem
= make_unibyte_string (uname
, ulength
);
4239 attrs
= Fcons (Fcons (Quser
,
4240 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4242 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4243 tem
= make_unibyte_string (gname
, glength
);
4244 attrs
= Fcons (Fcons (Qgroup
,
4245 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4248 if (global_memory_status_ex (&memstex
))
4249 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4250 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4252 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4253 double, so we need to do this for it... */
4255 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4256 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4257 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4259 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4261 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4262 else if (global_memory_status (&memst
))
4263 totphys
= memst
.dwTotalPhys
/ 1024.0;
4266 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4269 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4271 attrs
= Fcons (Fcons (Qmajflt
,
4272 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4274 attrs
= Fcons (Fcons (Qvsize
,
4275 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4277 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4279 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4282 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4284 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4286 attrs
= Fcons (Fcons (Qmajflt
,
4287 make_fixnum_or_float (mem
.PageFaultCount
)),
4289 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4291 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4294 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4296 DWORD rss
= maxrss
/ 1024;
4298 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4300 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4303 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4305 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4306 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4307 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4308 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4309 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4310 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4313 /* FIXME: Retrieve command line by walking the PEB of the process. */
4316 CloseHandle (h_proc
);
4322 /* Wrappers for winsock functions to map between our file descriptors
4323 and winsock's handles; also set h_errno for convenience.
4325 To allow Emacs to run on systems which don't have winsock support
4326 installed, we dynamically link to winsock on startup if present, and
4327 otherwise provide the minimum necessary functionality
4328 (eg. gethostname). */
4330 /* function pointers for relevant socket functions */
4331 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4332 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4333 int (PASCAL
*pfn_WSAGetLastError
) (void);
4334 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4335 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4336 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4337 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4338 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4339 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4340 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4341 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4342 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4343 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4344 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4345 int (PASCAL
*pfn_WSACleanup
) (void);
4347 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4348 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4349 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4350 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4351 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4352 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4353 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4354 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4355 const char * optval
, int optlen
);
4356 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4357 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4359 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4360 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4361 struct sockaddr
* from
, int * fromlen
);
4362 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4363 const struct sockaddr
* to
, int tolen
);
4365 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4366 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4367 #ifndef HANDLE_FLAG_INHERIT
4368 #define HANDLE_FLAG_INHERIT 1
4372 static int winsock_inuse
;
4377 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4379 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4380 after WSAStartup returns successfully, but it seems reasonable
4381 to allow unloading winsock anyway in that case. */
4382 if (pfn_WSACleanup () == 0 ||
4383 pfn_WSAGetLastError () == WSAENETDOWN
)
4385 if (FreeLibrary (winsock_lib
))
4394 init_winsock (int load_now
)
4396 WSADATA winsockData
;
4398 if (winsock_lib
!= NULL
)
4401 pfn_SetHandleInformation
4402 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4403 "SetHandleInformation");
4405 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4407 if (winsock_lib
!= NULL
)
4409 /* dynamically link to socket functions */
4411 #define LOAD_PROC(fn) \
4412 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4415 LOAD_PROC (WSAStartup
);
4416 LOAD_PROC (WSASetLastError
);
4417 LOAD_PROC (WSAGetLastError
);
4418 LOAD_PROC (WSAEventSelect
);
4419 LOAD_PROC (WSACreateEvent
);
4420 LOAD_PROC (WSACloseEvent
);
4423 LOAD_PROC (connect
);
4424 LOAD_PROC (ioctlsocket
);
4427 LOAD_PROC (closesocket
);
4428 LOAD_PROC (shutdown
);
4431 LOAD_PROC (inet_addr
);
4432 LOAD_PROC (gethostname
);
4433 LOAD_PROC (gethostbyname
);
4434 LOAD_PROC (getservbyname
);
4435 LOAD_PROC (getpeername
);
4436 LOAD_PROC (WSACleanup
);
4437 LOAD_PROC (setsockopt
);
4439 LOAD_PROC (getsockname
);
4441 LOAD_PROC (recvfrom
);
4445 /* specify version 1.1 of winsock */
4446 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4448 if (winsockData
.wVersion
!= 0x101)
4453 /* Report that winsock exists and is usable, but leave
4454 socket functions disabled. I am assuming that calling
4455 WSAStartup does not require any network interaction,
4456 and in particular does not cause or require a dial-up
4457 connection to be established. */
4460 FreeLibrary (winsock_lib
);
4468 FreeLibrary (winsock_lib
);
4478 /* function to set h_errno for compatibility; map winsock error codes to
4479 normal system codes where they overlap (non-overlapping definitions
4480 are already in <sys/socket.h> */
4484 if (winsock_lib
== NULL
)
4487 h_errno
= pfn_WSAGetLastError ();
4491 case WSAEACCES
: h_errno
= EACCES
; break;
4492 case WSAEBADF
: h_errno
= EBADF
; break;
4493 case WSAEFAULT
: h_errno
= EFAULT
; break;
4494 case WSAEINTR
: h_errno
= EINTR
; break;
4495 case WSAEINVAL
: h_errno
= EINVAL
; break;
4496 case WSAEMFILE
: h_errno
= EMFILE
; break;
4497 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4498 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4506 if (h_errno
== 0 && winsock_lib
!= NULL
)
4507 pfn_WSASetLastError (0);
4510 /* Extend strerror to handle the winsock-specific error codes. */
4514 } _wsa_errlist
[] = {
4515 WSAEINTR
, "Interrupted function call",
4516 WSAEBADF
, "Bad file descriptor",
4517 WSAEACCES
, "Permission denied",
4518 WSAEFAULT
, "Bad address",
4519 WSAEINVAL
, "Invalid argument",
4520 WSAEMFILE
, "Too many open files",
4522 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4523 WSAEINPROGRESS
, "Operation now in progress",
4524 WSAEALREADY
, "Operation already in progress",
4525 WSAENOTSOCK
, "Socket operation on non-socket",
4526 WSAEDESTADDRREQ
, "Destination address required",
4527 WSAEMSGSIZE
, "Message too long",
4528 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4529 WSAENOPROTOOPT
, "Bad protocol option",
4530 WSAEPROTONOSUPPORT
, "Protocol not supported",
4531 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4532 WSAEOPNOTSUPP
, "Operation not supported",
4533 WSAEPFNOSUPPORT
, "Protocol family not supported",
4534 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4535 WSAEADDRINUSE
, "Address already in use",
4536 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4537 WSAENETDOWN
, "Network is down",
4538 WSAENETUNREACH
, "Network is unreachable",
4539 WSAENETRESET
, "Network dropped connection on reset",
4540 WSAECONNABORTED
, "Software caused connection abort",
4541 WSAECONNRESET
, "Connection reset by peer",
4542 WSAENOBUFS
, "No buffer space available",
4543 WSAEISCONN
, "Socket is already connected",
4544 WSAENOTCONN
, "Socket is not connected",
4545 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4546 WSAETOOMANYREFS
, "Too many references", /* not sure */
4547 WSAETIMEDOUT
, "Connection timed out",
4548 WSAECONNREFUSED
, "Connection refused",
4549 WSAELOOP
, "Network loop", /* not sure */
4550 WSAENAMETOOLONG
, "Name is too long",
4551 WSAEHOSTDOWN
, "Host is down",
4552 WSAEHOSTUNREACH
, "No route to host",
4553 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4554 WSAEPROCLIM
, "Too many processes",
4555 WSAEUSERS
, "Too many users", /* not sure */
4556 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4557 WSAESTALE
, "Data is stale", /* not sure */
4558 WSAEREMOTE
, "Remote error", /* not sure */
4560 WSASYSNOTREADY
, "Network subsystem is unavailable",
4561 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4562 WSANOTINITIALISED
, "Winsock not initialized successfully",
4563 WSAEDISCON
, "Graceful shutdown in progress",
4565 WSAENOMORE
, "No more operations allowed", /* not sure */
4566 WSAECANCELLED
, "Operation cancelled", /* not sure */
4567 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4568 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4569 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4570 WSASYSCALLFAILURE
, "System call failure",
4571 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4572 WSATYPE_NOT_FOUND
, "Class type not found",
4573 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4574 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4575 WSAEREFUSED
, "Operation refused", /* not sure */
4578 WSAHOST_NOT_FOUND
, "Host not found",
4579 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4580 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4581 WSANO_DATA
, "Valid name, no data record of requested type",
4587 sys_strerror (int error_no
)
4590 static char unknown_msg
[40];
4592 if (error_no
>= 0 && error_no
< sys_nerr
)
4593 return sys_errlist
[error_no
];
4595 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4596 if (_wsa_errlist
[i
].errnum
== error_no
)
4597 return _wsa_errlist
[i
].msg
;
4599 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4603 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4604 but I believe the method of keeping the socket handle separate (and
4605 insuring it is not inheritable) is the correct one. */
4607 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4609 static int socket_to_fd (SOCKET s
);
4612 sys_socket (int af
, int type
, int protocol
)
4616 if (winsock_lib
== NULL
)
4619 return INVALID_SOCKET
;
4624 /* call the real socket function */
4625 s
= pfn_socket (af
, type
, protocol
);
4627 if (s
!= INVALID_SOCKET
)
4628 return socket_to_fd (s
);
4634 /* Convert a SOCKET to a file descriptor. */
4636 socket_to_fd (SOCKET s
)
4641 /* Although under NT 3.5 _open_osfhandle will accept a socket
4642 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4643 that does not work under NT 3.1. However, we can get the same
4644 effect by using a backdoor function to replace an existing
4645 descriptor handle with the one we want. */
4647 /* allocate a file descriptor (with appropriate flags) */
4648 fd
= _open ("NUL:", _O_RDWR
);
4651 /* Make a non-inheritable copy of the socket handle. Note
4652 that it is possible that sockets aren't actually kernel
4653 handles, which appears to be the case on Windows 9x when
4654 the MS Proxy winsock client is installed. */
4656 /* Apparently there is a bug in NT 3.51 with some service
4657 packs, which prevents using DuplicateHandle to make a
4658 socket handle non-inheritable (causes WSACleanup to
4659 hang). The work-around is to use SetHandleInformation
4660 instead if it is available and implemented. */
4661 if (pfn_SetHandleInformation
)
4663 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4667 HANDLE parent
= GetCurrentProcess ();
4668 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4670 if (DuplicateHandle (parent
,
4676 DUPLICATE_SAME_ACCESS
))
4678 /* It is possible that DuplicateHandle succeeds even
4679 though the socket wasn't really a kernel handle,
4680 because a real handle has the same value. So
4681 test whether the new handle really is a socket. */
4682 long nonblocking
= 0;
4683 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4685 pfn_closesocket (s
);
4690 CloseHandle (new_s
);
4695 fd_info
[fd
].hnd
= (HANDLE
) s
;
4697 /* set our own internal flags */
4698 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4704 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4706 /* attach child_process to fd_info */
4707 if (fd_info
[ fd
].cp
!= NULL
)
4709 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4713 fd_info
[ fd
].cp
= cp
;
4716 winsock_inuse
++; /* count open sockets */
4723 pfn_closesocket (s
);
4729 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4731 if (winsock_lib
== NULL
)
4734 return SOCKET_ERROR
;
4738 if (fd_info
[s
].flags
& FILE_SOCKET
)
4740 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4741 if (rc
== SOCKET_ERROR
)
4746 return SOCKET_ERROR
;
4750 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4752 if (winsock_lib
== NULL
)
4755 return SOCKET_ERROR
;
4759 if (fd_info
[s
].flags
& FILE_SOCKET
)
4761 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4762 if (rc
== SOCKET_ERROR
)
4767 return SOCKET_ERROR
;
4771 sys_htons (u_short hostshort
)
4773 return (winsock_lib
!= NULL
) ?
4774 pfn_htons (hostshort
) : hostshort
;
4778 sys_ntohs (u_short netshort
)
4780 return (winsock_lib
!= NULL
) ?
4781 pfn_ntohs (netshort
) : netshort
;
4785 sys_inet_addr (const char * cp
)
4787 return (winsock_lib
!= NULL
) ?
4788 pfn_inet_addr (cp
) : INADDR_NONE
;
4792 sys_gethostname (char * name
, int namelen
)
4794 if (winsock_lib
!= NULL
)
4795 return pfn_gethostname (name
, namelen
);
4797 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4798 return !GetComputerName (name
, (DWORD
*)&namelen
);
4801 return SOCKET_ERROR
;
4805 sys_gethostbyname (const char * name
)
4807 struct hostent
* host
;
4809 if (winsock_lib
== NULL
)
4816 host
= pfn_gethostbyname (name
);
4823 sys_getservbyname (const char * name
, const char * proto
)
4825 struct servent
* serv
;
4827 if (winsock_lib
== NULL
)
4834 serv
= pfn_getservbyname (name
, proto
);
4841 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4843 if (winsock_lib
== NULL
)
4846 return SOCKET_ERROR
;
4850 if (fd_info
[s
].flags
& FILE_SOCKET
)
4852 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4853 if (rc
== SOCKET_ERROR
)
4858 return SOCKET_ERROR
;
4862 sys_shutdown (int s
, int how
)
4864 if (winsock_lib
== NULL
)
4867 return SOCKET_ERROR
;
4871 if (fd_info
[s
].flags
& FILE_SOCKET
)
4873 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4874 if (rc
== SOCKET_ERROR
)
4879 return SOCKET_ERROR
;
4883 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4885 if (winsock_lib
== NULL
)
4888 return SOCKET_ERROR
;
4892 if (fd_info
[s
].flags
& FILE_SOCKET
)
4894 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4895 (const char *)optval
, optlen
);
4896 if (rc
== SOCKET_ERROR
)
4901 return SOCKET_ERROR
;
4905 sys_listen (int s
, int backlog
)
4907 if (winsock_lib
== NULL
)
4910 return SOCKET_ERROR
;
4914 if (fd_info
[s
].flags
& FILE_SOCKET
)
4916 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4917 if (rc
== SOCKET_ERROR
)
4920 fd_info
[s
].flags
|= FILE_LISTEN
;
4924 return SOCKET_ERROR
;
4928 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4930 if (winsock_lib
== NULL
)
4933 return SOCKET_ERROR
;
4937 if (fd_info
[s
].flags
& FILE_SOCKET
)
4939 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4940 if (rc
== SOCKET_ERROR
)
4945 return SOCKET_ERROR
;
4949 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
4951 if (winsock_lib
== NULL
)
4958 if (fd_info
[s
].flags
& FILE_LISTEN
)
4960 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
4962 if (t
== INVALID_SOCKET
)
4965 fd
= socket_to_fd (t
);
4967 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4968 ResetEvent (fd_info
[s
].cp
->char_avail
);
4976 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
4977 struct sockaddr
* from
, int * fromlen
)
4979 if (winsock_lib
== NULL
)
4982 return SOCKET_ERROR
;
4986 if (fd_info
[s
].flags
& FILE_SOCKET
)
4988 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
4989 if (rc
== SOCKET_ERROR
)
4994 return SOCKET_ERROR
;
4998 sys_sendto (int s
, const char * buf
, int len
, int flags
,
4999 const struct sockaddr
* to
, int tolen
)
5001 if (winsock_lib
== NULL
)
5004 return SOCKET_ERROR
;
5008 if (fd_info
[s
].flags
& FILE_SOCKET
)
5010 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5011 if (rc
== SOCKET_ERROR
)
5016 return SOCKET_ERROR
;
5019 /* Windows does not have an fcntl function. Provide an implementation
5020 solely for making sockets non-blocking. */
5022 fcntl (int s
, int cmd
, int options
)
5024 if (winsock_lib
== NULL
)
5031 if (fd_info
[s
].flags
& FILE_SOCKET
)
5033 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5035 unsigned long nblock
= 1;
5036 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5037 if (rc
== SOCKET_ERROR
)
5039 /* Keep track of the fact that we set this to non-blocking. */
5040 fd_info
[s
].flags
|= FILE_NDELAY
;
5046 return SOCKET_ERROR
;
5050 return SOCKET_ERROR
;
5054 /* Shadow main io functions: we need to handle pipes and sockets more
5055 intelligently, and implement non-blocking mode as well. */
5068 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5070 child_process
* cp
= fd_info
[fd
].cp
;
5072 fd_info
[fd
].cp
= NULL
;
5074 if (CHILD_ACTIVE (cp
))
5076 /* if last descriptor to active child_process then cleanup */
5078 for (i
= 0; i
< MAXDESC
; i
++)
5082 if (fd_info
[i
].cp
== cp
)
5087 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5089 if (winsock_lib
== NULL
) abort ();
5091 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5092 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5094 winsock_inuse
--; /* count open sockets */
5101 /* Note that sockets do not need special treatment here (at least on
5102 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5103 closesocket is equivalent to CloseHandle, which is to be expected
5104 because socket handles are fully fledged kernel handles. */
5107 if (rc
== 0 && fd
< MAXDESC
)
5108 fd_info
[fd
].flags
= 0;
5119 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5121 /* duplicate our internal info as well */
5122 fd_info
[new_fd
] = fd_info
[fd
];
5128 sys_dup2 (int src
, int dst
)
5132 if (dst
< 0 || dst
>= MAXDESC
)
5138 /* make sure we close the destination first if it's a pipe or socket */
5139 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5142 rc
= _dup2 (src
, dst
);
5145 /* duplicate our internal info as well */
5146 fd_info
[dst
] = fd_info
[src
];
5151 /* Unix pipe() has only one arg */
5153 sys_pipe (int * phandles
)
5158 /* make pipe handles non-inheritable; when we spawn a child, we
5159 replace the relevant handle with an inheritable one. Also put
5160 pipes into binary mode; we will do text mode translation ourselves
5162 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5166 /* Protect against overflow, since Windows can open more handles than
5167 our fd_info array has room for. */
5168 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5170 _close (phandles
[0]);
5171 _close (phandles
[1]);
5176 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5177 fd_info
[phandles
[0]].flags
= flags
;
5179 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5180 fd_info
[phandles
[1]].flags
= flags
;
5188 extern int w32_pipe_read_delay
;
5190 /* Function to do blocking read of one byte, needed to implement
5191 select. It is only allowed on sockets and pipes. */
5193 _sys_read_ahead (int fd
)
5198 if (fd
< 0 || fd
>= MAXDESC
)
5199 return STATUS_READ_ERROR
;
5201 cp
= fd_info
[fd
].cp
;
5203 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5204 return STATUS_READ_ERROR
;
5206 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5207 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5209 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5213 cp
->status
= STATUS_READ_IN_PROGRESS
;
5215 if (fd_info
[fd
].flags
& FILE_PIPE
)
5217 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5219 /* Give subprocess time to buffer some more output for us before
5220 reporting that input is available; we need this because Windows 95
5221 connects DOS programs to pipes by making the pipe appear to be
5222 the normal console stdout - as a result most DOS programs will
5223 write to stdout without buffering, ie. one character at a
5224 time. Even some W32 programs do this - "dir" in a command
5225 shell on NT is very slow if we don't do this. */
5228 int wait
= w32_pipe_read_delay
;
5234 /* Yield remainder of our time slice, effectively giving a
5235 temporary priority boost to the child process. */
5239 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5241 HANDLE hnd
= fd_info
[fd
].hnd
;
5242 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5245 /* Configure timeouts for blocking read. */
5246 if (!GetCommTimeouts (hnd
, &ct
))
5247 return STATUS_READ_ERROR
;
5248 ct
.ReadIntervalTimeout
= 0;
5249 ct
.ReadTotalTimeoutMultiplier
= 0;
5250 ct
.ReadTotalTimeoutConstant
= 0;
5251 if (!SetCommTimeouts (hnd
, &ct
))
5252 return STATUS_READ_ERROR
;
5254 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5256 if (GetLastError () != ERROR_IO_PENDING
)
5257 return STATUS_READ_ERROR
;
5258 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5259 return STATUS_READ_ERROR
;
5262 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5264 unsigned long nblock
= 0;
5265 /* We always want this to block, so temporarily disable NDELAY. */
5266 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5267 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5269 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5271 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5274 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5278 if (rc
== sizeof (char))
5279 cp
->status
= STATUS_READ_SUCCEEDED
;
5281 cp
->status
= STATUS_READ_FAILED
;
5287 _sys_wait_accept (int fd
)
5293 if (fd
< 0 || fd
>= MAXDESC
)
5294 return STATUS_READ_ERROR
;
5296 cp
= fd_info
[fd
].cp
;
5298 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5299 return STATUS_READ_ERROR
;
5301 cp
->status
= STATUS_READ_FAILED
;
5303 hEv
= pfn_WSACreateEvent ();
5304 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5305 if (rc
!= SOCKET_ERROR
)
5307 rc
= WaitForSingleObject (hEv
, INFINITE
);
5308 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5309 if (rc
== WAIT_OBJECT_0
)
5310 cp
->status
= STATUS_READ_SUCCEEDED
;
5312 pfn_WSACloseEvent (hEv
);
5318 sys_read (int fd
, char * buffer
, unsigned int count
)
5323 char * orig_buffer
= buffer
;
5331 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5333 child_process
*cp
= fd_info
[fd
].cp
;
5335 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5343 /* re-read CR carried over from last read */
5344 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5346 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5350 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5353 /* presence of a child_process structure means we are operating in
5354 non-blocking mode - otherwise we just call _read directly.
5355 Note that the child_process structure might be missing because
5356 reap_subprocess has been called; in this case the pipe is
5357 already broken, so calling _read on it is okay. */
5360 int current_status
= cp
->status
;
5362 switch (current_status
)
5364 case STATUS_READ_FAILED
:
5365 case STATUS_READ_ERROR
:
5366 /* report normal EOF if nothing in buffer */
5368 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5371 case STATUS_READ_READY
:
5372 case STATUS_READ_IN_PROGRESS
:
5373 DebPrint (("sys_read called when read is in progress\n"));
5374 errno
= EWOULDBLOCK
;
5377 case STATUS_READ_SUCCEEDED
:
5378 /* consume read-ahead char */
5379 *buffer
++ = cp
->chr
;
5382 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5383 ResetEvent (cp
->char_avail
);
5385 case STATUS_READ_ACKNOWLEDGED
:
5389 DebPrint (("sys_read: bad status %d\n", current_status
));
5394 if (fd_info
[fd
].flags
& FILE_PIPE
)
5396 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5397 to_read
= min (waiting
, (DWORD
) count
);
5400 nchars
+= _read (fd
, buffer
, to_read
);
5402 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5404 HANDLE hnd
= fd_info
[fd
].hnd
;
5405 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5412 /* Configure timeouts for non-blocking read. */
5413 if (!GetCommTimeouts (hnd
, &ct
))
5418 ct
.ReadIntervalTimeout
= MAXDWORD
;
5419 ct
.ReadTotalTimeoutMultiplier
= 0;
5420 ct
.ReadTotalTimeoutConstant
= 0;
5421 if (!SetCommTimeouts (hnd
, &ct
))
5427 if (!ResetEvent (ovl
->hEvent
))
5432 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5434 if (GetLastError () != ERROR_IO_PENDING
)
5439 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5448 else /* FILE_SOCKET */
5450 if (winsock_lib
== NULL
) abort ();
5452 /* do the equivalent of a non-blocking read */
5453 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5454 if (waiting
== 0 && nchars
== 0)
5456 h_errno
= errno
= EWOULDBLOCK
;
5462 /* always use binary mode for sockets */
5463 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5464 if (res
== SOCKET_ERROR
)
5466 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5467 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5477 int nread
= _read (fd
, buffer
, count
);
5480 else if (nchars
== 0)
5485 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5486 /* Perform text mode translation if required. */
5487 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5489 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5490 /* If buffer contains only CR, return that. To be absolutely
5491 sure we should attempt to read the next char, but in
5492 practice a CR to be followed by LF would not appear by
5493 itself in the buffer. */
5494 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5496 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5502 nchars
= _read (fd
, buffer
, count
);
5507 /* From w32xfns.c */
5508 extern HANDLE interrupt_handle
;
5510 /* For now, don't bother with a non-blocking mode */
5512 sys_write (int fd
, const void * buffer
, unsigned int count
)
5522 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5524 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5530 /* Perform text mode translation if required. */
5531 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5533 char * tmpbuf
= alloca (count
* 2);
5534 unsigned char * src
= (void *)buffer
;
5535 unsigned char * dst
= tmpbuf
;
5540 unsigned char *next
;
5541 /* copy next line or remaining bytes */
5542 next
= _memccpy (dst
, src
, '\n', nbytes
);
5545 /* copied one line ending with '\n' */
5546 int copied
= next
- dst
;
5549 /* insert '\r' before '\n' */
5556 /* copied remaining partial line -> now finished */
5563 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5565 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5566 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5567 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5570 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5572 if (GetLastError () != ERROR_IO_PENDING
)
5577 if (detect_input_pending ())
5578 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5581 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5582 if (active
== WAIT_OBJECT_0
)
5583 { /* User pressed C-g, cancel write, then leave. Don't bother
5584 cleaning up as we may only get stuck in buggy drivers. */
5585 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5590 if (active
== WAIT_OBJECT_0
+ 1
5591 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5598 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5600 unsigned long nblock
= 0;
5601 if (winsock_lib
== NULL
) abort ();
5603 /* TODO: implement select() properly so non-blocking I/O works. */
5604 /* For now, make sure the write blocks. */
5605 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5606 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5608 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5610 /* Set the socket back to non-blocking if it was before,
5611 for other operations that support it. */
5612 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5615 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5618 if (nchars
== SOCKET_ERROR
)
5620 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5621 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5627 /* Some networked filesystems don't like too large writes, so
5628 break them into smaller chunks. See the Comments section of
5629 the MSDN documentation of WriteFile for details behind the
5630 choice of the value of CHUNK below. See also the thread
5631 http://thread.gmane.org/gmane.comp.version-control.git/145294
5632 in the git mailing list. */
5633 const unsigned char *p
= buffer
;
5634 const unsigned chunk
= 30 * 1024 * 1024;
5639 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5640 int n
= _write (fd
, p
, this_chunk
);
5648 else if (n
< this_chunk
)
5659 check_windows_init_file (void)
5661 extern int noninteractive
, inhibit_window_system
;
5663 /* A common indication that Emacs is not installed properly is when
5664 it cannot find the Windows installation file. If this file does
5665 not exist in the expected place, tell the user. */
5667 if (!noninteractive
&& !inhibit_window_system
)
5669 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
5670 Lisp_Object objs
[2];
5671 Lisp_Object full_load_path
;
5672 Lisp_Object init_file
;
5675 objs
[0] = Vload_path
;
5676 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5677 full_load_path
= Fappend (2, objs
);
5678 init_file
= build_string ("term/w32-win");
5679 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5682 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5683 char *init_file_name
= SDATA (init_file
);
5684 char *load_path
= SDATA (load_path_print
);
5685 char *buffer
= alloca (1024
5686 + strlen (init_file_name
)
5687 + strlen (load_path
));
5690 "The Emacs Windows initialization file \"%s.el\" "
5691 "could not be found in your Emacs installation. "
5692 "Emacs checked the following directories for this file:\n"
5694 "When Emacs cannot find this file, it usually means that it "
5695 "was not installed properly, or its distribution file was "
5696 "not unpacked properly.\nSee the README.W32 file in the "
5697 "top-level Emacs directory for more information.",
5698 init_file_name
, load_path
);
5701 "Emacs Abort Dialog",
5702 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5703 /* Use the low-level Emacs abort. */
5717 /* shutdown the socket interface if necessary */
5726 /* Initialise the socket interface now if available and requested by
5727 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5728 delayed until open-network-stream is called (w32-has-winsock can
5729 also be used to dynamically load or reload winsock).
5731 Conveniently, init_environment is called before us, so
5732 PRELOAD_WINSOCK can be set in the registry. */
5734 /* Always initialize this correctly. */
5737 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5738 init_winsock (TRUE
);
5740 /* Initial preparation for subprocess support: replace our standard
5741 handles with non-inheritable versions. */
5744 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5745 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5746 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5748 parent
= GetCurrentProcess ();
5750 /* ignore errors when duplicating and closing; typically the
5751 handles will be invalid when running as a gui program. */
5752 DuplicateHandle (parent
,
5753 GetStdHandle (STD_INPUT_HANDLE
),
5758 DUPLICATE_SAME_ACCESS
);
5760 DuplicateHandle (parent
,
5761 GetStdHandle (STD_OUTPUT_HANDLE
),
5766 DUPLICATE_SAME_ACCESS
);
5768 DuplicateHandle (parent
,
5769 GetStdHandle (STD_ERROR_HANDLE
),
5774 DUPLICATE_SAME_ACCESS
);
5780 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5781 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5783 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5786 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5787 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5789 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5792 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5793 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5795 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5799 /* unfortunately, atexit depends on implementation of malloc */
5800 /* atexit (term_ntproc); */
5801 signal (SIGABRT
, term_ntproc
);
5803 /* determine which drives are fixed, for GetCachedVolumeInformation */
5805 /* GetDriveType must have trailing backslash. */
5806 char drive
[] = "A:\\";
5808 /* Loop over all possible drive letters */
5809 while (*drive
<= 'Z')
5811 /* Record if this drive letter refers to a fixed drive. */
5812 fixed_drives
[DRIVE_INDEX (*drive
)] =
5813 (GetDriveType (drive
) == DRIVE_FIXED
);
5818 /* Reset the volume info cache. */
5819 volume_cache
= NULL
;
5822 /* Check to see if Emacs has been installed correctly. */
5823 check_windows_init_file ();
5827 shutdown_handler ensures that buffers' autosave files are
5828 up to date when the user logs off, or the system shuts down.
5831 shutdown_handler (DWORD type
)
5833 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5834 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5835 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5836 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5838 /* Shut down cleanly, making sure autosave files are up to date. */
5839 shut_down_emacs (0, 0, Qnil
);
5842 /* Allow other handlers to handle this signal. */
5847 globals_of_w32 is used to initialize those global variables that
5848 must always be initialized on startup even when the global variable
5849 initialized is non zero (see the function main in emacs.c).
5852 globals_of_w32 (void)
5854 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5856 get_process_times_fn
= (GetProcessTimes_Proc
)
5857 GetProcAddress (kernel32
, "GetProcessTimes");
5859 g_b_init_is_windows_9x
= 0;
5860 g_b_init_open_process_token
= 0;
5861 g_b_init_get_token_information
= 0;
5862 g_b_init_lookup_account_sid
= 0;
5863 g_b_init_get_sid_sub_authority
= 0;
5864 g_b_init_get_sid_sub_authority_count
= 0;
5865 g_b_init_get_file_security
= 0;
5866 g_b_init_get_security_descriptor_owner
= 0;
5867 g_b_init_get_security_descriptor_group
= 0;
5868 g_b_init_is_valid_sid
= 0;
5869 g_b_init_create_toolhelp32_snapshot
= 0;
5870 g_b_init_process32_first
= 0;
5871 g_b_init_process32_next
= 0;
5872 g_b_init_open_thread_token
= 0;
5873 g_b_init_impersonate_self
= 0;
5874 g_b_init_revert_to_self
= 0;
5875 g_b_init_get_process_memory_info
= 0;
5876 g_b_init_get_process_working_set_size
= 0;
5877 g_b_init_global_memory_status
= 0;
5878 g_b_init_global_memory_status_ex
= 0;
5879 g_b_init_equal_sid
= 0;
5880 g_b_init_copy_sid
= 0;
5881 g_b_init_get_length_sid
= 0;
5882 g_b_init_get_native_system_info
= 0;
5883 g_b_init_get_system_times
= 0;
5884 num_of_processors
= 0;
5885 /* The following sets a handler for shutdown notifications for
5886 console apps. This actually applies to Emacs in both console and
5887 GUI modes, since we had to fool windows into thinking emacs is a
5888 console application to get console mode to work. */
5889 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
5891 /* "None" is the default group name on standalone workstations. */
5892 strcpy (dflt_group_name
, "None");
5895 /* For make-serial-process */
5897 serial_open (char *port
)
5903 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5904 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5905 if (hnd
== INVALID_HANDLE_VALUE
)
5906 error ("Could not open %s", port
);
5907 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5909 error ("Could not open %s", port
);
5913 error ("Could not create child process");
5915 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5916 fd_info
[ fd
].hnd
= hnd
;
5917 fd_info
[ fd
].flags
|=
5918 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5919 if (fd_info
[ fd
].cp
!= NULL
)
5921 error ("fd_info[fd = %d] is already in use", fd
);
5923 fd_info
[ fd
].cp
= cp
;
5924 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5925 if (cp
->ovl_read
.hEvent
== NULL
)
5926 error ("Could not create read event");
5927 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5928 if (cp
->ovl_write
.hEvent
== NULL
)
5929 error ("Could not create write event");
5934 /* For serial-process-configure */
5936 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
5938 Lisp_Object childp2
= Qnil
;
5939 Lisp_Object tem
= Qnil
;
5943 char summary
[4] = "???"; /* This usually becomes "8N1". */
5945 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
5946 error ("Not a serial process");
5947 hnd
= fd_info
[ p
->outfd
].hnd
;
5949 childp2
= Fcopy_sequence (p
->childp
);
5951 /* Initialize timeouts for blocking read and blocking write. */
5952 if (!GetCommTimeouts (hnd
, &ct
))
5953 error ("GetCommTimeouts() failed");
5954 ct
.ReadIntervalTimeout
= 0;
5955 ct
.ReadTotalTimeoutMultiplier
= 0;
5956 ct
.ReadTotalTimeoutConstant
= 0;
5957 ct
.WriteTotalTimeoutMultiplier
= 0;
5958 ct
.WriteTotalTimeoutConstant
= 0;
5959 if (!SetCommTimeouts (hnd
, &ct
))
5960 error ("SetCommTimeouts() failed");
5961 /* Read port attributes and prepare default configuration. */
5962 memset (&dcb
, 0, sizeof (dcb
));
5963 dcb
.DCBlength
= sizeof (DCB
);
5964 if (!GetCommState (hnd
, &dcb
))
5965 error ("GetCommState() failed");
5968 dcb
.fAbortOnError
= FALSE
;
5969 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
5974 /* Configure speed. */
5975 if (!NILP (Fplist_member (contact
, QCspeed
)))
5976 tem
= Fplist_get (contact
, QCspeed
);
5978 tem
= Fplist_get (p
->childp
, QCspeed
);
5980 dcb
.BaudRate
= XINT (tem
);
5981 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
5983 /* Configure bytesize. */
5984 if (!NILP (Fplist_member (contact
, QCbytesize
)))
5985 tem
= Fplist_get (contact
, QCbytesize
);
5987 tem
= Fplist_get (p
->childp
, QCbytesize
);
5989 tem
= make_number (8);
5991 if (XINT (tem
) != 7 && XINT (tem
) != 8)
5992 error (":bytesize must be nil (8), 7, or 8");
5993 dcb
.ByteSize
= XINT (tem
);
5994 summary
[0] = XINT (tem
) + '0';
5995 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
5997 /* Configure parity. */
5998 if (!NILP (Fplist_member (contact
, QCparity
)))
5999 tem
= Fplist_get (contact
, QCparity
);
6001 tem
= Fplist_get (p
->childp
, QCparity
);
6002 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6003 error (":parity must be nil (no parity), `even', or `odd'");
6004 dcb
.fParity
= FALSE
;
6005 dcb
.Parity
= NOPARITY
;
6006 dcb
.fErrorChar
= FALSE
;
6011 else if (EQ (tem
, Qeven
))
6015 dcb
.Parity
= EVENPARITY
;
6016 dcb
.fErrorChar
= TRUE
;
6018 else if (EQ (tem
, Qodd
))
6022 dcb
.Parity
= ODDPARITY
;
6023 dcb
.fErrorChar
= TRUE
;
6025 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6027 /* Configure stopbits. */
6028 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6029 tem
= Fplist_get (contact
, QCstopbits
);
6031 tem
= Fplist_get (p
->childp
, QCstopbits
);
6033 tem
= make_number (1);
6035 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6036 error (":stopbits must be nil (1 stopbit), 1, or 2");
6037 summary
[2] = XINT (tem
) + '0';
6038 if (XINT (tem
) == 1)
6039 dcb
.StopBits
= ONESTOPBIT
;
6040 else if (XINT (tem
) == 2)
6041 dcb
.StopBits
= TWOSTOPBITS
;
6042 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6044 /* Configure flowcontrol. */
6045 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6046 tem
= Fplist_get (contact
, QCflowcontrol
);
6048 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6049 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6050 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6051 dcb
.fOutxCtsFlow
= FALSE
;
6052 dcb
.fOutxDsrFlow
= FALSE
;
6053 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6054 dcb
.fDsrSensitivity
= FALSE
;
6055 dcb
.fTXContinueOnXoff
= FALSE
;
6058 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6059 dcb
.XonChar
= 17; /* Control-Q */
6060 dcb
.XoffChar
= 19; /* Control-S */
6063 /* Already configured. */
6065 else if (EQ (tem
, Qhw
))
6067 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6068 dcb
.fOutxCtsFlow
= TRUE
;
6070 else if (EQ (tem
, Qsw
))
6075 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6077 /* Activate configuration. */
6078 if (!SetCommState (hnd
, &dcb
))
6079 error ("SetCommState() failed");
6081 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6082 p
->childp
= childp2
;