1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23 #include <stddef.h> /* for offsetof */
26 #include <float.h> /* for DBL_EPSILON */
34 #include <sys/utime.h>
35 #include <mbstring.h> /* for _mbspbrk */
39 /* must include CRT headers *before* config.h */
74 #define _ANONYMOUS_UNION
75 #define _ANONYMOUS_STRUCT
78 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
79 use a different name to avoid compilation problems. */
80 typedef struct _MEMORY_STATUS_EX
{
83 DWORDLONG ullTotalPhys
;
84 DWORDLONG ullAvailPhys
;
85 DWORDLONG ullTotalPageFile
;
86 DWORDLONG ullAvailPageFile
;
87 DWORDLONG ullTotalVirtual
;
88 DWORDLONG ullAvailVirtual
;
89 DWORDLONG ullAvailExtendedVirtual
;
90 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
97 /* This either is not in psapi.h or guarded by higher value of
98 _WIN32_WINNT than what we use. */
99 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
101 DWORD PageFaultCount
;
102 DWORD PeakWorkingSetSize
;
103 DWORD WorkingSetSize
;
104 DWORD QuotaPeakPagedPoolUsage
;
105 DWORD QuotaPagedPoolUsage
;
106 DWORD QuotaPeakNonPagedPoolUsage
;
107 DWORD QuotaNonPagedPoolUsage
;
109 DWORD PeakPagefileUsage
;
111 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
113 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
114 #include <sys/socket.h>
138 #include "dispextern.h" /* for xstrcasecmp */
139 #include "coding.h" /* for Vlocale_coding_system */
141 /* For serial_configure and serial_open. */
144 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
145 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
147 void globals_of_w32 (void);
148 static DWORD
get_rid (PSID
);
150 extern Lisp_Object Vw32_downcase_file_names
;
151 extern Lisp_Object Vw32_generate_fake_inodes
;
152 extern Lisp_Object Vw32_get_true_file_attributes
;
153 /* Defined in process.c for its own purpose. */
154 extern Lisp_Object Qlocal
;
156 extern int w32_num_mouse_buttons
;
159 /* Initialization states.
161 WARNING: If you add any more such variables for additional APIs,
162 you MUST add initialization for them to globals_of_w32
163 below. This is because these variables might get set
164 to non-NULL values during dumping, but the dumped Emacs
165 cannot reuse those values, because it could be run on a
166 different version of the OS, where API addresses are
168 static BOOL g_b_init_is_windows_9x
;
169 static BOOL g_b_init_open_process_token
;
170 static BOOL g_b_init_get_token_information
;
171 static BOOL g_b_init_lookup_account_sid
;
172 static BOOL g_b_init_get_sid_identifier_authority
;
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 PSID_IDENTIFIER_AUTHORITY (WINAPI
* GetSidIdentifierAuthority_Proc
) (
237 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
240 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
242 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
244 SECURITY_INFORMATION RequestedInformation
,
245 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
247 LPDWORD lpnLengthNeeded
);
248 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
249 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
251 LPBOOL lpbOwnerDefaulted
);
252 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
253 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
255 LPBOOL lpbGroupDefaulted
);
256 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
258 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
260 DWORD th32ProcessID
);
261 typedef BOOL (WINAPI
* Process32First_Proc
) (
263 LPPROCESSENTRY32 lppe
);
264 typedef BOOL (WINAPI
* Process32Next_Proc
) (
266 LPPROCESSENTRY32 lppe
);
267 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
271 PHANDLE TokenHandle
);
272 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
273 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
274 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
275 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
277 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
279 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
281 DWORD
* lpMinimumWorkingSetSize
,
282 DWORD
* lpMaximumWorkingSetSize
);
283 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
284 LPMEMORYSTATUS lpBuffer
);
285 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
286 LPMEMORY_STATUS_EX lpBuffer
);
287 typedef BOOL (WINAPI
* CopySid_Proc
) (
288 DWORD nDestinationSidLength
,
289 PSID pDestinationSid
,
291 typedef BOOL (WINAPI
* EqualSid_Proc
) (
294 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
296 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
297 LPSYSTEM_INFO lpSystemInfo
);
298 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
299 LPFILETIME lpIdleTime
,
300 LPFILETIME lpKernelTime
,
301 LPFILETIME lpUserTime
);
305 /* ** A utility function ** */
309 static BOOL s_b_ret
=0;
310 OSVERSIONINFO os_ver
;
311 if (g_b_init_is_windows_9x
== 0)
313 g_b_init_is_windows_9x
= 1;
314 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
315 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
316 if (GetVersionEx (&os_ver
))
318 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
324 /* Get total user and system times for get-internal-run-time.
325 Returns a list of three integers if the times are provided by the OS
326 (NT derivatives), otherwise it returns the result of current-time. */
328 w32_get_internal_run_time (void)
330 if (get_process_times_fn
)
332 FILETIME create
, exit
, kernel
, user
;
333 HANDLE proc
= GetCurrentProcess ();
334 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
336 LARGE_INTEGER user_int
, kernel_int
, total
;
338 user_int
.LowPart
= user
.dwLowDateTime
;
339 user_int
.HighPart
= user
.dwHighDateTime
;
340 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
341 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
342 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
343 /* FILETIME is 100 nanosecond increments, Emacs only wants
344 microsecond resolution. */
345 total
.QuadPart
/= 10;
346 microseconds
= total
.QuadPart
% 1000000;
347 total
.QuadPart
/= 1000000;
349 /* Sanity check to make sure we can represent the result. */
350 if (total
.HighPart
== 0)
352 int secs
= total
.LowPart
;
354 return list3 (make_number ((secs
>> 16) & 0xffff),
355 make_number (secs
& 0xffff),
356 make_number (microseconds
));
361 return Fcurrent_time ();
364 /* ** The wrapper functions ** */
366 BOOL WINAPI
open_process_token (
367 HANDLE ProcessHandle
,
371 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
372 HMODULE hm_advapi32
= NULL
;
373 if (is_windows_9x () == TRUE
)
377 if (g_b_init_open_process_token
== 0)
379 g_b_init_open_process_token
= 1;
380 hm_advapi32
= LoadLibrary ("Advapi32.dll");
381 s_pfn_Open_Process_Token
=
382 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
384 if (s_pfn_Open_Process_Token
== NULL
)
389 s_pfn_Open_Process_Token (
396 BOOL WINAPI
get_token_information (
398 TOKEN_INFORMATION_CLASS TokenInformationClass
,
399 LPVOID TokenInformation
,
400 DWORD TokenInformationLength
,
403 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
404 HMODULE hm_advapi32
= NULL
;
405 if (is_windows_9x () == TRUE
)
409 if (g_b_init_get_token_information
== 0)
411 g_b_init_get_token_information
= 1;
412 hm_advapi32
= LoadLibrary ("Advapi32.dll");
413 s_pfn_Get_Token_Information
=
414 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
416 if (s_pfn_Get_Token_Information
== NULL
)
421 s_pfn_Get_Token_Information (
423 TokenInformationClass
,
425 TokenInformationLength
,
430 BOOL WINAPI
lookup_account_sid (
431 LPCTSTR lpSystemName
,
436 LPDWORD cbDomainName
,
439 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
440 HMODULE hm_advapi32
= NULL
;
441 if (is_windows_9x () == TRUE
)
445 if (g_b_init_lookup_account_sid
== 0)
447 g_b_init_lookup_account_sid
= 1;
448 hm_advapi32
= LoadLibrary ("Advapi32.dll");
449 s_pfn_Lookup_Account_Sid
=
450 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
452 if (s_pfn_Lookup_Account_Sid
== NULL
)
457 s_pfn_Lookup_Account_Sid (
468 PSID_IDENTIFIER_AUTHORITY WINAPI
get_sid_identifier_authority (
471 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority
= NULL
;
472 HMODULE hm_advapi32
= NULL
;
473 if (is_windows_9x () == TRUE
)
477 if (g_b_init_get_sid_identifier_authority
== 0)
479 g_b_init_get_sid_identifier_authority
= 1;
480 hm_advapi32
= LoadLibrary ("Advapi32.dll");
481 s_pfn_Get_Sid_Identifier_Authority
=
482 (GetSidIdentifierAuthority_Proc
) GetProcAddress (
483 hm_advapi32
, "GetSidIdentifierAuthority");
485 if (s_pfn_Get_Sid_Identifier_Authority
== NULL
)
489 return (s_pfn_Get_Sid_Identifier_Authority (pSid
));
492 PDWORD WINAPI
get_sid_sub_authority (
496 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
497 static DWORD zero
= 0U;
498 HMODULE hm_advapi32
= NULL
;
499 if (is_windows_9x () == TRUE
)
503 if (g_b_init_get_sid_sub_authority
== 0)
505 g_b_init_get_sid_sub_authority
= 1;
506 hm_advapi32
= LoadLibrary ("Advapi32.dll");
507 s_pfn_Get_Sid_Sub_Authority
=
508 (GetSidSubAuthority_Proc
) GetProcAddress (
509 hm_advapi32
, "GetSidSubAuthority");
511 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
515 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
518 PUCHAR WINAPI
get_sid_sub_authority_count (
521 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
522 static UCHAR zero
= 0U;
523 HMODULE hm_advapi32
= NULL
;
524 if (is_windows_9x () == TRUE
)
528 if (g_b_init_get_sid_sub_authority_count
== 0)
530 g_b_init_get_sid_sub_authority_count
= 1;
531 hm_advapi32
= LoadLibrary ("Advapi32.dll");
532 s_pfn_Get_Sid_Sub_Authority_Count
=
533 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
534 hm_advapi32
, "GetSidSubAuthorityCount");
536 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
540 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
543 BOOL WINAPI
get_file_security (
545 SECURITY_INFORMATION RequestedInformation
,
546 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
548 LPDWORD lpnLengthNeeded
)
550 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
551 HMODULE hm_advapi32
= NULL
;
552 if (is_windows_9x () == TRUE
)
556 if (g_b_init_get_file_security
== 0)
558 g_b_init_get_file_security
= 1;
559 hm_advapi32
= LoadLibrary ("Advapi32.dll");
560 s_pfn_Get_File_Security
=
561 (GetFileSecurity_Proc
) GetProcAddress (
562 hm_advapi32
, GetFileSecurity_Name
);
564 if (s_pfn_Get_File_Security
== NULL
)
568 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
569 pSecurityDescriptor
, nLength
,
573 BOOL WINAPI
get_security_descriptor_owner (
574 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
576 LPBOOL lpbOwnerDefaulted
)
578 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
579 HMODULE hm_advapi32
= NULL
;
580 if (is_windows_9x () == TRUE
)
584 if (g_b_init_get_security_descriptor_owner
== 0)
586 g_b_init_get_security_descriptor_owner
= 1;
587 hm_advapi32
= LoadLibrary ("Advapi32.dll");
588 s_pfn_Get_Security_Descriptor_Owner
=
589 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
590 hm_advapi32
, "GetSecurityDescriptorOwner");
592 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
596 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
600 BOOL WINAPI
get_security_descriptor_group (
601 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
603 LPBOOL lpbGroupDefaulted
)
605 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
606 HMODULE hm_advapi32
= NULL
;
607 if (is_windows_9x () == TRUE
)
611 if (g_b_init_get_security_descriptor_group
== 0)
613 g_b_init_get_security_descriptor_group
= 1;
614 hm_advapi32
= LoadLibrary ("Advapi32.dll");
615 s_pfn_Get_Security_Descriptor_Group
=
616 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
617 hm_advapi32
, "GetSecurityDescriptorGroup");
619 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
623 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
627 BOOL WINAPI
is_valid_sid (
630 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
631 HMODULE hm_advapi32
= NULL
;
632 if (is_windows_9x () == TRUE
)
636 if (g_b_init_is_valid_sid
== 0)
638 g_b_init_is_valid_sid
= 1;
639 hm_advapi32
= LoadLibrary ("Advapi32.dll");
641 (IsValidSid_Proc
) GetProcAddress (
642 hm_advapi32
, "IsValidSid");
644 if (s_pfn_Is_Valid_Sid
== NULL
)
648 return (s_pfn_Is_Valid_Sid (sid
));
651 BOOL WINAPI
equal_sid (
655 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
656 HMODULE hm_advapi32
= NULL
;
657 if (is_windows_9x () == TRUE
)
661 if (g_b_init_equal_sid
== 0)
663 g_b_init_equal_sid
= 1;
664 hm_advapi32
= LoadLibrary ("Advapi32.dll");
666 (EqualSid_Proc
) GetProcAddress (
667 hm_advapi32
, "EqualSid");
669 if (s_pfn_Equal_Sid
== NULL
)
673 return (s_pfn_Equal_Sid (sid1
, sid2
));
676 DWORD WINAPI
get_length_sid (
679 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
680 HMODULE hm_advapi32
= NULL
;
681 if (is_windows_9x () == TRUE
)
685 if (g_b_init_get_length_sid
== 0)
687 g_b_init_get_length_sid
= 1;
688 hm_advapi32
= LoadLibrary ("Advapi32.dll");
689 s_pfn_Get_Length_Sid
=
690 (GetLengthSid_Proc
) GetProcAddress (
691 hm_advapi32
, "GetLengthSid");
693 if (s_pfn_Get_Length_Sid
== NULL
)
697 return (s_pfn_Get_Length_Sid (sid
));
700 BOOL WINAPI
copy_sid (
705 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
706 HMODULE hm_advapi32
= NULL
;
707 if (is_windows_9x () == TRUE
)
711 if (g_b_init_copy_sid
== 0)
713 g_b_init_copy_sid
= 1;
714 hm_advapi32
= LoadLibrary ("Advapi32.dll");
716 (CopySid_Proc
) GetProcAddress (
717 hm_advapi32
, "CopySid");
719 if (s_pfn_Copy_Sid
== NULL
)
723 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
727 END: Wrapper functions around OpenProcessToken
728 and other functions in advapi32.dll that are only
729 supported in Windows NT / 2k / XP
732 void WINAPI
get_native_system_info (
733 LPSYSTEM_INFO lpSystemInfo
)
735 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
736 if (is_windows_9x () != TRUE
)
738 if (g_b_init_get_native_system_info
== 0)
740 g_b_init_get_native_system_info
= 1;
741 s_pfn_Get_Native_System_Info
=
742 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
743 "GetNativeSystemInfo");
745 if (s_pfn_Get_Native_System_Info
!= NULL
)
746 s_pfn_Get_Native_System_Info (lpSystemInfo
);
749 lpSystemInfo
->dwNumberOfProcessors
= -1;
752 BOOL WINAPI
get_system_times (
753 LPFILETIME lpIdleTime
,
754 LPFILETIME lpKernelTime
,
755 LPFILETIME lpUserTime
)
757 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
758 if (is_windows_9x () == TRUE
)
762 if (g_b_init_get_system_times
== 0)
764 g_b_init_get_system_times
= 1;
765 s_pfn_Get_System_times
=
766 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
769 if (s_pfn_Get_System_times
== NULL
)
771 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
774 /* Equivalent of strerror for W32 error codes. */
776 w32_strerror (int error_no
)
778 static char buf
[500];
781 error_no
= GetLastError ();
784 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
786 0, /* choose most suitable language */
787 buf
, sizeof (buf
), NULL
))
788 sprintf (buf
, "w32 error %u", error_no
);
792 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
793 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
795 This is called from alloc.c:valid_pointer_p. */
797 w32_valid_pointer_p (void *p
, int size
)
800 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
804 unsigned char *buf
= alloca (size
);
805 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
814 static char startup_dir
[MAXPATHLEN
];
816 /* Get the current working directory. */
821 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
825 /* Emacs doesn't actually change directory itself, and we want to
826 force our real wd to be where emacs.exe is to avoid unnecessary
827 conflicts when trying to rename or delete directories. */
828 strcpy (dir
, startup_dir
);
834 /* Emulate gethostname. */
836 gethostname (char *buffer
, int size
)
838 /* NT only allows small host names, so the buffer is
839 certainly large enough. */
840 return !GetComputerName (buffer
, &size
);
842 #endif /* HAVE_SOCKETS */
844 /* Emulate getloadavg. */
853 /* Number of processors on this machine. */
854 static unsigned num_of_processors
;
856 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
857 static struct load_sample samples
[16*60];
858 static int first_idx
= -1, last_idx
= -1;
859 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
864 int next_idx
= from
+ 1;
866 if (next_idx
>= max_idx
)
875 int prev_idx
= from
- 1;
878 prev_idx
= max_idx
- 1;
884 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
887 FILETIME ft_idle
, ft_user
, ft_kernel
;
889 /* Initialize the number of processors on this machine. */
890 if (num_of_processors
<= 0)
892 get_native_system_info (&sysinfo
);
893 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
894 if (num_of_processors
<= 0)
896 GetSystemInfo (&sysinfo
);
897 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
899 if (num_of_processors
<= 0)
900 num_of_processors
= 1;
903 /* TODO: Take into account threads that are ready to run, by
904 sampling the "\System\Processor Queue Length" performance
905 counter. The code below accounts only for threads that are
908 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
910 ULARGE_INTEGER uidle
, ukernel
, uuser
;
912 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
913 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
914 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
915 *idle
= uidle
.QuadPart
;
916 *kernel
= ukernel
.QuadPart
;
917 *user
= uuser
.QuadPart
;
927 /* Produce the load average for a given time interval, using the
928 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
929 1-minute, 5-minute, or 15-minute average, respectively. */
933 double retval
= -1.0;
936 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
937 time_t now
= samples
[last_idx
].sample_time
;
939 if (first_idx
!= last_idx
)
941 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
943 tdiff
= difftime (now
, samples
[idx
].sample_time
);
944 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
947 samples
[last_idx
].kernel
+ samples
[last_idx
].user
948 - (samples
[idx
].kernel
+ samples
[idx
].user
);
949 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
951 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
954 if (idx
== first_idx
)
963 getloadavg (double loadavg
[], int nelem
)
966 ULONGLONG idle
, kernel
, user
;
967 time_t now
= time (NULL
);
969 /* Store another sample. We ignore samples that are less than 1 sec
971 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
973 sample_system_load (&idle
, &kernel
, &user
);
974 last_idx
= buf_next (last_idx
);
975 samples
[last_idx
].sample_time
= now
;
976 samples
[last_idx
].idle
= idle
;
977 samples
[last_idx
].kernel
= kernel
;
978 samples
[last_idx
].user
= user
;
979 /* If the buffer has more that 15 min worth of samples, discard
982 first_idx
= last_idx
;
983 while (first_idx
!= last_idx
984 && (difftime (now
, samples
[first_idx
].sample_time
)
985 >= 15.0*60 + 2*DBL_EPSILON
*now
))
986 first_idx
= buf_next (first_idx
);
989 for (elem
= 0; elem
< nelem
; elem
++)
991 double avg
= getavg (elem
);
1001 /* Emulate getpwuid, getpwnam and others. */
1003 #define PASSWD_FIELD_SIZE 256
1005 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1006 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1007 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1008 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
1009 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
1011 static struct passwd dflt_passwd
=
1023 static char dflt_group_name
[GNLEN
+1];
1025 static struct group dflt_group
=
1027 /* When group information is not available, we return this as the
1028 group for all files. */
1036 return dflt_passwd
.pw_uid
;
1042 /* I could imagine arguing for checking to see whether the user is
1043 in the Administrators group and returning a UID of 0 for that
1044 case, but I don't know how wise that would be in the long run. */
1051 return dflt_passwd
.pw_gid
;
1061 getpwuid (unsigned uid
)
1063 if (uid
== dflt_passwd
.pw_uid
)
1064 return &dflt_passwd
;
1069 getgrgid (gid_t gid
)
1075 getpwnam (char *name
)
1079 pw
= getpwuid (getuid ());
1083 if (xstrcasecmp (name
, pw
->pw_name
))
1090 init_user_info (void)
1092 /* Find the user's real name by opening the process token and
1093 looking up the name associated with the user-sid in that token.
1095 Use the relative portion of the identifier authority value from
1096 the user-sid as the user id value (same for group id using the
1097 primary group sid from the process token). */
1099 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1100 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1101 DWORD glength
= sizeof (gname
);
1102 HANDLE token
= NULL
;
1103 SID_NAME_USE user_type
;
1104 unsigned char *buf
= NULL
;
1106 TOKEN_USER user_token
;
1107 TOKEN_PRIMARY_GROUP group_token
;
1110 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1113 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1114 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1116 buf
= xmalloc (blen
);
1117 result
= get_token_information (token
, TokenUser
,
1118 (LPVOID
)buf
, blen
, &needed
);
1121 memcpy (&user_token
, buf
, sizeof (user_token
));
1122 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1124 domain
, &dlength
, &user_type
);
1132 strcpy (dflt_passwd
.pw_name
, uname
);
1133 /* Determine a reasonable uid value. */
1134 if (xstrcasecmp ("administrator", uname
) == 0)
1136 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1137 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1141 /* Use the last sub-authority value of the RID, the relative
1142 portion of the SID, as user/group ID. */
1143 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1145 /* Get group id and name. */
1146 result
= get_token_information (token
, TokenPrimaryGroup
,
1147 (LPVOID
)buf
, blen
, &needed
);
1148 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1150 buf
= xrealloc (buf
, blen
= needed
);
1151 result
= get_token_information (token
, TokenPrimaryGroup
,
1152 (LPVOID
)buf
, blen
, &needed
);
1156 memcpy (&group_token
, buf
, sizeof (group_token
));
1157 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1158 dlength
= sizeof (domain
);
1159 /* If we can get at the real Primary Group name, use that.
1160 Otherwise, the default group name was already set to
1161 "None" in globals_of_w32. */
1162 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1163 gname
, &glength
, NULL
, &dlength
,
1165 strcpy (dflt_group_name
, gname
);
1168 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1171 /* If security calls are not supported (presumably because we
1172 are running under Windows 9X), fallback to this: */
1173 else if (GetUserName (uname
, &ulength
))
1175 strcpy (dflt_passwd
.pw_name
, uname
);
1176 if (xstrcasecmp ("administrator", uname
) == 0)
1177 dflt_passwd
.pw_uid
= 0;
1179 dflt_passwd
.pw_uid
= 123;
1180 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1184 strcpy (dflt_passwd
.pw_name
, "unknown");
1185 dflt_passwd
.pw_uid
= 123;
1186 dflt_passwd
.pw_gid
= 123;
1188 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1190 /* Ensure HOME and SHELL are defined. */
1191 if (getenv ("HOME") == NULL
)
1193 if (getenv ("SHELL") == NULL
)
1196 /* Set dir and shell from environment variables. */
1197 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1198 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1202 CloseHandle (token
);
1208 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1209 return ((rand () << 15) | rand ());
1219 /* Normalize filename by converting all path separators to
1220 the specified separator. Also conditionally convert upper
1221 case path name components to lower case. */
1224 normalize_filename (register char *fp
, char path_sep
)
1229 /* Always lower-case drive letters a-z, even if the filesystem
1230 preserves case in filenames.
1231 This is so filenames can be compared by string comparison
1232 functions that are case-sensitive. Even case-preserving filesystems
1233 do not distinguish case in drive letters. */
1234 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1240 if (NILP (Vw32_downcase_file_names
))
1244 if (*fp
== '/' || *fp
== '\\')
1251 sep
= path_sep
; /* convert to this path separator */
1252 elem
= fp
; /* start of current path element */
1255 if (*fp
>= 'a' && *fp
<= 'z')
1256 elem
= 0; /* don't convert this element */
1258 if (*fp
== 0 || *fp
== ':')
1260 sep
= *fp
; /* restore current separator (or 0) */
1261 *fp
= '/'; /* after conversion of this element */
1264 if (*fp
== '/' || *fp
== '\\')
1266 if (elem
&& elem
!= fp
)
1268 *fp
= 0; /* temporary end of string */
1269 _strlwr (elem
); /* while we convert to lower case */
1271 *fp
= sep
; /* convert (or restore) path separator */
1272 elem
= fp
+ 1; /* next element starts after separator */
1278 /* Destructively turn backslashes into slashes. */
1280 dostounix_filename (register char *p
)
1282 normalize_filename (p
, '/');
1285 /* Destructively turn slashes into backslashes. */
1287 unixtodos_filename (register char *p
)
1289 normalize_filename (p
, '\\');
1292 /* Remove all CR's that are followed by a LF.
1293 (From msdos.c...probably should figure out a way to share it,
1294 although this code isn't going to ever change.) */
1296 crlf_to_lf (register int n
, register unsigned char *buf
)
1298 unsigned char *np
= buf
;
1299 unsigned char *startp
= buf
;
1300 unsigned char *endp
= buf
+ n
;
1304 while (buf
< endp
- 1)
1308 if (*(++buf
) != 0x0a)
1319 /* Parse the root part of file name, if present. Return length and
1320 optionally store pointer to char after root. */
1322 parse_root (char * name
, char ** pPath
)
1324 char * start
= name
;
1329 /* find the root name of the volume if given */
1330 if (isalpha (name
[0]) && name
[1] == ':')
1332 /* skip past drive specifier */
1334 if (IS_DIRECTORY_SEP (name
[0]))
1337 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1343 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1348 if (IS_DIRECTORY_SEP (name
[0]))
1355 return name
- start
;
1358 /* Get long base name for name; name is assumed to be absolute. */
1360 get_long_basename (char * name
, char * buf
, int size
)
1362 WIN32_FIND_DATA find_data
;
1366 /* must be valid filename, no wild cards or other invalid characters */
1367 if (_mbspbrk (name
, "*?|<>\""))
1370 dir_handle
= FindFirstFile (name
, &find_data
);
1371 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1373 if ((len
= strlen (find_data
.cFileName
)) < size
)
1374 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1377 FindClose (dir_handle
);
1382 /* Get long name for file, if possible (assumed to be absolute). */
1384 w32_get_long_filename (char * name
, char * buf
, int size
)
1389 char full
[ MAX_PATH
];
1392 len
= strlen (name
);
1393 if (len
>= MAX_PATH
)
1396 /* Use local copy for destructive modification. */
1397 memcpy (full
, name
, len
+1);
1398 unixtodos_filename (full
);
1400 /* Copy root part verbatim. */
1401 len
= parse_root (full
, &p
);
1402 memcpy (o
, full
, len
);
1407 while (p
!= NULL
&& *p
)
1410 p
= strchr (q
, '\\');
1412 len
= get_long_basename (full
, o
, size
);
1435 is_unc_volume (const char *filename
)
1437 const char *ptr
= filename
;
1439 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1442 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1448 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1451 sigsetmask (int signal_mask
)
1469 sigunblock (int sig
)
1475 sigemptyset (sigset_t
*set
)
1481 sigaddset (sigset_t
*set
, int signo
)
1487 sigfillset (sigset_t
*set
)
1493 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1499 setpgrp (int pid
, int gid
)
1510 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1513 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1516 HKEY hrootkey
= NULL
;
1519 /* Check both the current user and the local machine to see if
1520 we have any resources. */
1522 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1526 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1527 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1528 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1530 RegCloseKey (hrootkey
);
1536 RegCloseKey (hrootkey
);
1539 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1543 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1544 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1545 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1547 RegCloseKey (hrootkey
);
1553 RegCloseKey (hrootkey
);
1559 char *get_emacs_configuration (void);
1560 extern Lisp_Object Vsystem_configuration
;
1563 init_environment (char ** argv
)
1565 static const char * const tempdirs
[] = {
1566 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1571 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1573 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1574 temporary files and assume "/tmp" if $TMPDIR is unset, which
1575 will break on DOS/Windows. Refuse to work if we cannot find
1576 a directory, not even "c:/", usable for that purpose. */
1577 for (i
= 0; i
< imax
; i
++)
1579 const char *tmp
= tempdirs
[i
];
1582 tmp
= getenv (tmp
+ 1);
1583 /* Note that `access' can lie to us if the directory resides on a
1584 read-only filesystem, like CD-ROM or a write-protected floppy.
1585 The only way to be really sure is to actually create a file and
1586 see if it succeeds. But I think that's too much to ask. */
1587 if (tmp
&& _access (tmp
, D_OK
) == 0)
1589 char * var
= alloca (strlen (tmp
) + 8);
1590 sprintf (var
, "TMPDIR=%s", tmp
);
1591 _putenv (strdup (var
));
1598 Fcons (build_string ("no usable temporary directories found!!"),
1600 "While setting TMPDIR: ");
1602 /* Check for environment variables and use registry settings if they
1603 don't exist. Fallback on default values where applicable. */
1608 char locale_name
[32];
1609 struct stat ignored
;
1610 char default_home
[MAX_PATH
];
1612 static const struct env_entry
1619 {"PRELOAD_WINSOCK", NULL
},
1620 {"emacs_dir", "C:/emacs"},
1621 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1622 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1623 {"EMACSDATA", "%emacs_dir%/etc"},
1624 {"EMACSPATH", "%emacs_dir%/bin"},
1625 /* We no longer set INFOPATH because Info-default-directory-list
1627 /* {"INFOPATH", "%emacs_dir%/info"}, */
1628 {"EMACSDOC", "%emacs_dir%/etc"},
1633 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1635 /* We need to copy dflt_envvars[] and work on the copy because we
1636 don't want the dumped Emacs to inherit the values of
1637 environment variables we saw during dumping (which could be on
1638 a different system). The defaults above must be left intact. */
1639 struct env_entry env_vars
[N_ENV_VARS
];
1641 for (i
= 0; i
< N_ENV_VARS
; i
++)
1642 env_vars
[i
] = dflt_envvars
[i
];
1644 /* For backwards compatibility, check if a .emacs file exists in C:/
1645 If not, then we can try to default to the appdata directory under the
1646 user's profile, which is more likely to be writable. */
1647 if (stat ("C:/.emacs", &ignored
) < 0)
1649 HRESULT profile_result
;
1650 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1651 of Windows 95 and NT4 that have not been updated to include
1653 ShGetFolderPath_fn get_folder_path
;
1654 get_folder_path
= (ShGetFolderPath_fn
)
1655 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1657 if (get_folder_path
!= NULL
)
1659 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1662 /* If we can't get the appdata dir, revert to old behavior. */
1663 if (profile_result
== S_OK
)
1664 env_vars
[0].def_value
= default_home
;
1668 /* Get default locale info and use it for LANG. */
1669 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1670 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1671 locale_name
, sizeof (locale_name
)))
1673 for (i
= 0; i
< N_ENV_VARS
; i
++)
1675 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1677 env_vars
[i
].def_value
= locale_name
;
1683 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1685 /* Treat emacs_dir specially: set it unconditionally based on our
1686 location, if it appears that we are running from the bin subdir
1687 of a standard installation. */
1690 char modname
[MAX_PATH
];
1692 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1694 if ((p
= strrchr (modname
, '\\')) == NULL
)
1698 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1700 char buf
[SET_ENV_BUF_SIZE
];
1703 for (p
= modname
; *p
; p
++)
1704 if (*p
== '\\') *p
= '/';
1706 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1707 _putenv (strdup (buf
));
1709 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1711 /* FIXME: should use substring of get_emacs_configuration ().
1712 But I don't think the Windows build supports alpha, mips etc
1713 anymore, so have taken the easy option for now. */
1714 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1717 p
= strrchr (modname
, '\\');
1721 p
= strrchr (modname
, '\\');
1722 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1724 char buf
[SET_ENV_BUF_SIZE
];
1727 for (p
= modname
; *p
; p
++)
1728 if (*p
== '\\') *p
= '/';
1730 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1731 _putenv (strdup (buf
));
1737 for (i
= 0; i
< N_ENV_VARS
; i
++)
1739 if (!getenv (env_vars
[i
].name
))
1743 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1744 /* Also ignore empty environment variables. */
1748 lpval
= env_vars
[i
].def_value
;
1749 dwType
= REG_EXPAND_SZ
;
1755 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1757 if (dwType
== REG_EXPAND_SZ
)
1758 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1759 else if (dwType
== REG_SZ
)
1760 strcpy (buf1
, lpval
);
1761 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1763 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1765 _putenv (strdup (buf2
));
1775 /* Rebuild system configuration to reflect invoking system. */
1776 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1778 /* Another special case: on NT, the PATH variable is actually named
1779 "Path" although cmd.exe (perhaps NT itself) arranges for
1780 environment variable lookup and setting to be case insensitive.
1781 However, Emacs assumes a fully case sensitive environment, so we
1782 need to change "Path" to "PATH" to match the expectations of
1783 various elisp packages. We do this by the sneaky method of
1784 modifying the string in the C runtime environ entry.
1786 The same applies to COMSPEC. */
1790 for (envp
= environ
; *envp
; envp
++)
1791 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1792 memcpy (*envp
, "PATH=", 5);
1793 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1794 memcpy (*envp
, "COMSPEC=", 8);
1797 /* Remember the initial working directory for getwd, then make the
1798 real wd be the location of emacs.exe to avoid conflicts when
1799 renaming or deleting directories. (We also don't call chdir when
1800 running subprocesses for the same reason.) */
1801 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1806 static char modname
[MAX_PATH
];
1808 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1810 if ((p
= strrchr (modname
, '\\')) == NULL
)
1814 SetCurrentDirectory (modname
);
1816 /* Ensure argv[0] has the full path to Emacs. */
1821 /* Determine if there is a middle mouse button, to allow parse_button
1822 to decide whether right mouse events should be mouse-2 or
1824 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1830 emacs_root_dir (void)
1832 static char root_dir
[FILENAME_MAX
];
1835 p
= getenv ("emacs_dir");
1838 strcpy (root_dir
, p
);
1839 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1840 dostounix_filename (root_dir
);
1844 /* We don't have scripts to automatically determine the system configuration
1845 for Emacs before it's compiled, and we don't want to have to make the
1846 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1850 get_emacs_configuration (void)
1852 char *arch
, *oem
, *os
;
1854 static char configuration_buffer
[32];
1856 /* Determine the processor type. */
1857 switch (get_processor_type ())
1860 #ifdef PROCESSOR_INTEL_386
1861 case PROCESSOR_INTEL_386
:
1862 case PROCESSOR_INTEL_486
:
1863 case PROCESSOR_INTEL_PENTIUM
:
1868 #ifdef PROCESSOR_MIPS_R2000
1869 case PROCESSOR_MIPS_R2000
:
1870 case PROCESSOR_MIPS_R3000
:
1871 case PROCESSOR_MIPS_R4000
:
1876 #ifdef PROCESSOR_ALPHA_21064
1877 case PROCESSOR_ALPHA_21064
:
1887 /* Use the OEM field to reflect the compiler/library combination. */
1889 #define COMPILER_NAME "msvc"
1892 #define COMPILER_NAME "mingw"
1894 #define COMPILER_NAME "unknown"
1897 oem
= COMPILER_NAME
;
1899 switch (osinfo_cache
.dwPlatformId
) {
1900 case VER_PLATFORM_WIN32_NT
:
1902 build_num
= osinfo_cache
.dwBuildNumber
;
1904 case VER_PLATFORM_WIN32_WINDOWS
:
1905 if (osinfo_cache
.dwMinorVersion
== 0) {
1910 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1912 case VER_PLATFORM_WIN32s
:
1913 /* Not supported, should not happen. */
1915 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1923 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1924 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1925 get_w32_major_version (), get_w32_minor_version (), build_num
);
1927 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1930 return configuration_buffer
;
1934 get_emacs_configuration_options (void)
1936 static char options_buffer
[256];
1938 /* Work out the effective configure options for this build. */
1940 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1943 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1945 #define COMPILER_VERSION ""
1949 sprintf (options_buffer
, COMPILER_VERSION
);
1951 strcat (options_buffer
, " --no-opt");
1954 strcat (options_buffer
, " --cflags");
1955 strcat (options_buffer
, USER_CFLAGS
);
1958 strcat (options_buffer
, " --ldflags");
1959 strcat (options_buffer
, USER_LDFLAGS
);
1961 return options_buffer
;
1965 #include <sys/timeb.h>
1967 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1969 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1974 tv
->tv_sec
= tb
.time
;
1975 tv
->tv_usec
= tb
.millitm
* 1000L;
1978 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1979 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1983 /* ------------------------------------------------------------------------- */
1984 /* IO support and wrapper functions for W32 API. */
1985 /* ------------------------------------------------------------------------- */
1987 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1988 on network directories, so we handle that case here.
1989 (Ulrich Leodolter, 1/11/95). */
1991 sys_ctime (const time_t *t
)
1993 char *str
= (char *) ctime (t
);
1994 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1997 /* Emulate sleep...we could have done this with a define, but that
1998 would necessitate including windows.h in the files that used it.
1999 This is much easier. */
2001 sys_sleep (int seconds
)
2003 Sleep (seconds
* 1000);
2006 /* Internal MSVC functions for low-level descriptor munging */
2007 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2008 extern int __cdecl
_free_osfhnd (int fd
);
2010 /* parallel array of private info on file handles */
2011 filedesc fd_info
[ MAXDESC
];
2013 typedef struct volume_info_data
{
2014 struct volume_info_data
* next
;
2016 /* time when info was obtained */
2019 /* actual volume info */
2028 /* Global referenced by various functions. */
2029 static volume_info_data volume_info
;
2031 /* Vector to indicate which drives are local and fixed (for which cached
2032 data never expires). */
2033 static BOOL fixed_drives
[26];
2035 /* Consider cached volume information to be stale if older than 10s,
2036 at least for non-local drives. Info for fixed drives is never stale. */
2037 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2038 #define VOLINFO_STILL_VALID( root_dir, info ) \
2039 ( ( isalpha (root_dir[0]) && \
2040 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2041 || GetTickCount () - info->timestamp < 10000 )
2043 /* Cache support functions. */
2045 /* Simple linked list with linear search is sufficient. */
2046 static volume_info_data
*volume_cache
= NULL
;
2048 static volume_info_data
*
2049 lookup_volume_info (char * root_dir
)
2051 volume_info_data
* info
;
2053 for (info
= volume_cache
; info
; info
= info
->next
)
2054 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2060 add_volume_info (char * root_dir
, volume_info_data
* info
)
2062 info
->root_dir
= xstrdup (root_dir
);
2063 info
->next
= volume_cache
;
2064 volume_cache
= info
;
2068 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2069 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2070 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2072 GetCachedVolumeInformation (char * root_dir
)
2074 volume_info_data
* info
;
2075 char default_root
[ MAX_PATH
];
2077 /* NULL for root_dir means use root from current directory. */
2078 if (root_dir
== NULL
)
2080 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2082 parse_root (default_root
, &root_dir
);
2084 root_dir
= default_root
;
2087 /* Local fixed drives can be cached permanently. Removable drives
2088 cannot be cached permanently, since the volume name and serial
2089 number (if nothing else) can change. Remote drives should be
2090 treated as if they are removable, since there is no sure way to
2091 tell whether they are or not. Also, the UNC association of drive
2092 letters mapped to remote volumes can be changed at any time (even
2093 by other processes) without notice.
2095 As a compromise, so we can benefit from caching info for remote
2096 volumes, we use a simple expiry mechanism to invalidate cache
2097 entries that are more than ten seconds old. */
2100 /* No point doing this, because WNetGetConnection is even slower than
2101 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2102 GetDriveType is about the only call of this type which does not
2103 involve network access, and so is extremely quick). */
2105 /* Map drive letter to UNC if remote. */
2106 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2108 char remote_name
[ 256 ];
2109 char drive
[3] = { root_dir
[0], ':' };
2111 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2113 /* do something */ ;
2117 info
= lookup_volume_info (root_dir
);
2119 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2127 /* Info is not cached, or is stale. */
2128 if (!GetVolumeInformation (root_dir
,
2129 name
, sizeof (name
),
2133 type
, sizeof (type
)))
2136 /* Cache the volume information for future use, overwriting existing
2137 entry if present. */
2140 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2141 add_volume_info (root_dir
, info
);
2149 info
->name
= xstrdup (name
);
2150 info
->serialnum
= serialnum
;
2151 info
->maxcomp
= maxcomp
;
2152 info
->flags
= flags
;
2153 info
->type
= xstrdup (type
);
2154 info
->timestamp
= GetTickCount ();
2160 /* Get information on the volume where name is held; set path pointer to
2161 start of pathname in name (past UNC header\volume header if present). */
2163 get_volume_info (const char * name
, const char ** pPath
)
2165 char temp
[MAX_PATH
];
2166 char *rootname
= NULL
; /* default to current volume */
2167 volume_info_data
* info
;
2172 /* find the root name of the volume if given */
2173 if (isalpha (name
[0]) && name
[1] == ':')
2181 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2188 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2201 info
= GetCachedVolumeInformation (rootname
);
2204 /* Set global referenced by other functions. */
2205 volume_info
= *info
;
2211 /* Determine if volume is FAT format (ie. only supports short 8.3
2212 names); also set path pointer to start of pathname in name. */
2214 is_fat_volume (const char * name
, const char ** pPath
)
2216 if (get_volume_info (name
, pPath
))
2217 return (volume_info
.maxcomp
== 12);
2221 /* Map filename to a valid 8.3 name if necessary. */
2223 map_w32_filename (const char * name
, const char ** pPath
)
2225 static char shortname
[MAX_PATH
];
2226 char * str
= shortname
;
2229 const char * save_name
= name
;
2231 if (strlen (name
) >= MAX_PATH
)
2233 /* Return a filename which will cause callers to fail. */
2234 strcpy (shortname
, "?");
2238 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2240 register int left
= 8; /* maximum number of chars in part */
2241 register int extn
= 0; /* extension added? */
2242 register int dots
= 2; /* maximum number of dots allowed */
2245 *str
++ = *name
++; /* skip past UNC header */
2247 while ((c
= *name
++))
2254 extn
= 0; /* reset extension flags */
2255 dots
= 2; /* max 2 dots */
2256 left
= 8; /* max length 8 for main part */
2260 extn
= 0; /* reset extension flags */
2261 dots
= 2; /* max 2 dots */
2262 left
= 8; /* max length 8 for main part */
2267 /* Convert path components of the form .xxx to _xxx,
2268 but leave . and .. as they are. This allows .emacs
2269 to be read as _emacs, for example. */
2273 IS_DIRECTORY_SEP (*name
))
2288 extn
= 1; /* we've got an extension */
2289 left
= 3; /* 3 chars in extension */
2293 /* any embedded dots after the first are converted to _ */
2298 case '#': /* don't lose these, they're important */
2300 str
[-1] = c
; /* replace last character of part */
2305 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2307 dots
= 0; /* started a path component */
2316 strcpy (shortname
, name
);
2317 unixtodos_filename (shortname
);
2321 *pPath
= shortname
+ (path
- save_name
);
2327 is_exec (const char * name
)
2329 char * p
= strrchr (name
, '.');
2332 && (xstrcasecmp (p
, ".exe") == 0 ||
2333 xstrcasecmp (p
, ".com") == 0 ||
2334 xstrcasecmp (p
, ".bat") == 0 ||
2335 xstrcasecmp (p
, ".cmd") == 0));
2338 /* Emulate the Unix directory procedures opendir, closedir,
2339 and readdir. We can't use the procedures supplied in sysdep.c,
2340 so we provide them here. */
2342 struct direct dir_static
; /* simulated directory contents */
2343 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2344 static int dir_is_fat
;
2345 static char dir_pathname
[MAXPATHLEN
+1];
2346 static WIN32_FIND_DATA dir_find_data
;
2348 /* Support shares on a network resource as subdirectories of a read-only
2350 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2351 HANDLE
open_unc_volume (const char *);
2352 char *read_unc_volume (HANDLE
, char *, int);
2353 void close_unc_volume (HANDLE
);
2356 opendir (char *filename
)
2360 /* Opening is done by FindFirstFile. However, a read is inherent to
2361 this operation, so we defer the open until read time. */
2363 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2365 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2368 if (is_unc_volume (filename
))
2370 wnet_enum_handle
= open_unc_volume (filename
);
2371 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2375 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2382 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2383 dir_pathname
[MAXPATHLEN
] = '\0';
2384 dir_is_fat
= is_fat_volume (filename
, NULL
);
2390 closedir (DIR *dirp
)
2392 /* If we have a find-handle open, close it. */
2393 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2395 FindClose (dir_find_handle
);
2396 dir_find_handle
= INVALID_HANDLE_VALUE
;
2398 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2400 close_unc_volume (wnet_enum_handle
);
2401 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2403 xfree ((char *) dirp
);
2409 int downcase
= !NILP (Vw32_downcase_file_names
);
2411 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2413 if (!read_unc_volume (wnet_enum_handle
,
2414 dir_find_data
.cFileName
,
2418 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2419 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2421 char filename
[MAXNAMLEN
+ 3];
2424 strcpy (filename
, dir_pathname
);
2425 ln
= strlen (filename
) - 1;
2426 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2427 strcat (filename
, "\\");
2428 strcat (filename
, "*");
2430 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2432 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2437 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2441 /* Emacs never uses this value, so don't bother making it match
2442 value returned by stat(). */
2443 dir_static
.d_ino
= 1;
2445 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2447 /* If the file name in cFileName[] includes `?' characters, it means
2448 the original file name used characters that cannot be represented
2449 by the current ANSI codepage. To avoid total lossage, retrieve
2450 the short 8+3 alias of the long file name. */
2451 if (_mbspbrk (dir_static
.d_name
, "?"))
2453 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2454 downcase
= 1; /* 8+3 aliases are returned in all caps */
2456 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2457 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2458 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2460 /* If the file name in cFileName[] includes `?' characters, it means
2461 the original file name used characters that cannot be represented
2462 by the current ANSI codepage. To avoid total lossage, retrieve
2463 the short 8+3 alias of the long file name. */
2464 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2466 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2467 /* 8+3 aliases are returned in all caps, which could break
2468 various alists that look at filenames' extensions. */
2472 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2473 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2475 _strlwr (dir_static
.d_name
);
2479 for (p
= dir_static
.d_name
; *p
; p
++)
2480 if (*p
>= 'a' && *p
<= 'z')
2483 _strlwr (dir_static
.d_name
);
2490 open_unc_volume (const char *path
)
2496 nr
.dwScope
= RESOURCE_GLOBALNET
;
2497 nr
.dwType
= RESOURCETYPE_DISK
;
2498 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2499 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2500 nr
.lpLocalName
= NULL
;
2501 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2502 nr
.lpComment
= NULL
;
2503 nr
.lpProvider
= NULL
;
2505 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2506 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2508 if (result
== NO_ERROR
)
2511 return INVALID_HANDLE_VALUE
;
2515 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2519 DWORD bufsize
= 512;
2524 buffer
= alloca (bufsize
);
2525 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2526 if (result
!= NO_ERROR
)
2529 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2530 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2532 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2535 strncpy (readbuf
, ptr
, size
);
2540 close_unc_volume (HANDLE henum
)
2542 if (henum
!= INVALID_HANDLE_VALUE
)
2543 WNetCloseEnum (henum
);
2547 unc_volume_file_attributes (const char *path
)
2552 henum
= open_unc_volume (path
);
2553 if (henum
== INVALID_HANDLE_VALUE
)
2556 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2558 close_unc_volume (henum
);
2563 /* Ensure a network connection is authenticated. */
2565 logon_network_drive (const char *path
)
2567 NETRESOURCE resource
;
2568 char share
[MAX_PATH
];
2573 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2574 drvtype
= DRIVE_REMOTE
;
2575 else if (path
[0] == '\0' || path
[1] != ':')
2576 drvtype
= GetDriveType (NULL
);
2583 drvtype
= GetDriveType (drive
);
2586 /* Only logon to networked drives. */
2587 if (drvtype
!= DRIVE_REMOTE
)
2591 strncpy (share
, path
, MAX_PATH
);
2592 /* Truncate to just server and share name. */
2593 for (i
= 2; i
< MAX_PATH
; i
++)
2595 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2602 resource
.dwType
= RESOURCETYPE_DISK
;
2603 resource
.lpLocalName
= NULL
;
2604 resource
.lpRemoteName
= share
;
2605 resource
.lpProvider
= NULL
;
2607 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2610 /* Shadow some MSVC runtime functions to map requests for long filenames
2611 to reasonable short names if necessary. This was originally added to
2612 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2616 sys_access (const char * path
, int mode
)
2620 /* MSVC implementation doesn't recognize D_OK. */
2621 path
= map_w32_filename (path
, NULL
);
2622 if (is_unc_volume (path
))
2624 attributes
= unc_volume_file_attributes (path
);
2625 if (attributes
== -1) {
2630 else if ((attributes
= GetFileAttributes (path
)) == -1)
2632 /* Should try mapping GetLastError to errno; for now just indicate
2633 that path doesn't exist. */
2637 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2642 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2647 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2656 sys_chdir (const char * path
)
2658 return _chdir (map_w32_filename (path
, NULL
));
2662 sys_chmod (const char * path
, int mode
)
2664 return _chmod (map_w32_filename (path
, NULL
), mode
);
2668 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2670 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2676 sys_creat (const char * path
, int mode
)
2678 return _creat (map_w32_filename (path
, NULL
), mode
);
2682 sys_fopen (const char * path
, const char * mode
)
2686 const char * mode_save
= mode
;
2688 /* Force all file handles to be non-inheritable. This is necessary to
2689 ensure child processes don't unwittingly inherit handles that might
2690 prevent future file access. */
2694 else if (mode
[0] == 'w' || mode
[0] == 'a')
2695 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2699 /* Only do simplistic option parsing. */
2703 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2706 else if (mode
[0] == 'b')
2711 else if (mode
[0] == 't')
2718 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2722 return _fdopen (fd
, mode_save
);
2725 /* This only works on NTFS volumes, but is useful to have. */
2727 sys_link (const char * old
, const char * new)
2731 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2733 if (old
== NULL
|| new == NULL
)
2739 strcpy (oldname
, map_w32_filename (old
, NULL
));
2740 strcpy (newname
, map_w32_filename (new, NULL
));
2742 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2743 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2744 if (fileh
!= INVALID_HANDLE_VALUE
)
2748 /* Confusingly, the "alternate" stream name field does not apply
2749 when restoring a hard link, and instead contains the actual
2750 stream data for the link (ie. the name of the link to create).
2751 The WIN32_STREAM_ID structure before the cStreamName field is
2752 the stream header, which is then immediately followed by the
2756 WIN32_STREAM_ID wid
;
2757 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2760 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2761 data
.wid
.cStreamName
, MAX_PATH
);
2764 LPVOID context
= NULL
;
2767 data
.wid
.dwStreamId
= BACKUP_LINK
;
2768 data
.wid
.dwStreamAttributes
= 0;
2769 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2770 data
.wid
.Size
.HighPart
= 0;
2771 data
.wid
.dwStreamNameSize
= 0;
2773 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2774 offsetof (WIN32_STREAM_ID
, cStreamName
)
2775 + data
.wid
.Size
.LowPart
,
2776 &wbytes
, FALSE
, FALSE
, &context
)
2777 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2784 /* Should try mapping GetLastError to errno; for now just
2785 indicate a general error (eg. links not supported). */
2786 errno
= EINVAL
; // perhaps EMLINK?
2790 CloseHandle (fileh
);
2799 sys_mkdir (const char * path
)
2801 return _mkdir (map_w32_filename (path
, NULL
));
2804 /* Because of long name mapping issues, we need to implement this
2805 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2806 a unique name, instead of setting the input template to an empty
2809 Standard algorithm seems to be use pid or tid with a letter on the
2810 front (in place of the 6 X's) and cycle through the letters to find a
2811 unique name. We extend that to allow any reasonable character as the
2812 first of the 6 X's. */
2814 sys_mktemp (char * template)
2818 unsigned uid
= GetCurrentThreadId ();
2819 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2821 if (template == NULL
)
2823 p
= template + strlen (template);
2825 /* replace up to the last 5 X's with uid in decimal */
2826 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2828 p
[0] = '0' + uid
% 10;
2832 if (i
< 0 && p
[0] == 'X')
2837 int save_errno
= errno
;
2838 p
[0] = first_char
[i
];
2839 if (sys_access (template, 0) < 0)
2845 while (++i
< sizeof (first_char
));
2848 /* Template is badly formed or else we can't generate a unique name,
2849 so return empty string */
2855 sys_open (const char * path
, int oflag
, int mode
)
2857 const char* mpath
= map_w32_filename (path
, NULL
);
2858 /* Try to open file without _O_CREAT, to be able to write to hidden
2859 and system files. Force all file handles to be
2861 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2864 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2868 sys_rename (const char * oldname
, const char * newname
)
2871 char temp
[MAX_PATH
];
2873 /* MoveFile on Windows 95 doesn't correctly change the short file name
2874 alias in a number of circumstances (it is not easy to predict when
2875 just by looking at oldname and newname, unfortunately). In these
2876 cases, renaming through a temporary name avoids the problem.
2878 A second problem on Windows 95 is that renaming through a temp name when
2879 newname is uppercase fails (the final long name ends up in
2880 lowercase, although the short alias might be uppercase) UNLESS the
2881 long temp name is not 8.3.
2883 So, on Windows 95 we always rename through a temp name, and we make sure
2884 the temp name has a long extension to ensure correct renaming. */
2886 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2888 if (os_subtype
== OS_WIN95
)
2894 oldname
= map_w32_filename (oldname
, NULL
);
2895 if (o
= strrchr (oldname
, '\\'))
2898 o
= (char *) oldname
;
2900 if (p
= strrchr (temp
, '\\'))
2907 /* Force temp name to require a manufactured 8.3 alias - this
2908 seems to make the second rename work properly. */
2909 sprintf (p
, "_.%s.%u", o
, i
);
2911 result
= rename (oldname
, temp
);
2913 /* This loop must surely terminate! */
2914 while (result
< 0 && errno
== EEXIST
);
2919 /* Emulate Unix behavior - newname is deleted if it already exists
2920 (at least if it is a file; don't do this for directories).
2922 Since we mustn't do this if we are just changing the case of the
2923 file name (we would end up deleting the file we are trying to
2924 rename!), we let rename detect if the destination file already
2925 exists - that way we avoid the possible pitfalls of trying to
2926 determine ourselves whether two names really refer to the same
2927 file, which is not always possible in the general case. (Consider
2928 all the permutations of shared or subst'd drives, etc.) */
2930 newname
= map_w32_filename (newname
, NULL
);
2931 result
= rename (temp
, newname
);
2935 && _chmod (newname
, 0666) == 0
2936 && _unlink (newname
) == 0)
2937 result
= rename (temp
, newname
);
2943 sys_rmdir (const char * path
)
2945 return _rmdir (map_w32_filename (path
, NULL
));
2949 sys_unlink (const char * path
)
2951 path
= map_w32_filename (path
, NULL
);
2953 /* On Unix, unlink works without write permission. */
2954 _chmod (path
, 0666);
2955 return _unlink (path
);
2958 static FILETIME utc_base_ft
;
2959 static ULONGLONG utc_base
; /* In 100ns units */
2960 static int init
= 0;
2962 #define FILETIME_TO_U64(result, ft) \
2964 ULARGE_INTEGER uiTemp; \
2965 uiTemp.LowPart = (ft).dwLowDateTime; \
2966 uiTemp.HighPart = (ft).dwHighDateTime; \
2967 result = uiTemp.QuadPart; \
2971 initialize_utc_base (void)
2973 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2982 st
.wMilliseconds
= 0;
2984 SystemTimeToFileTime (&st
, &utc_base_ft
);
2985 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2989 convert_time (FILETIME ft
)
2995 initialize_utc_base();
2999 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3002 FILETIME_TO_U64 (tmp
, ft
);
3003 return (time_t) ((tmp
- utc_base
) / 10000000L);
3008 convert_from_time_t (time_t time
, FILETIME
* pft
)
3014 initialize_utc_base ();
3018 /* time in 100ns units since 1-Jan-1601 */
3019 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3020 pft
->dwHighDateTime
= tmp
.HighPart
;
3021 pft
->dwLowDateTime
= tmp
.LowPart
;
3025 /* No reason to keep this; faking inode values either by hashing or even
3026 using the file index from GetInformationByHandle, is not perfect and
3027 so by default Emacs doesn't use the inode values on Windows.
3028 Instead, we now determine file-truename correctly (except for
3029 possible drive aliasing etc). */
3031 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3033 hashval (const unsigned char * str
)
3038 h
= (h
<< 4) + *str
++;
3044 /* Return the hash value of the canonical pathname, excluding the
3045 drive/UNC header, to get a hopefully unique inode number. */
3047 generate_inode_val (const char * name
)
3049 char fullname
[ MAX_PATH
];
3053 /* Get the truly canonical filename, if it exists. (Note: this
3054 doesn't resolve aliasing due to subst commands, or recognise hard
3056 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3059 parse_root (fullname
, &p
);
3060 /* Normal W32 filesystems are still case insensitive. */
3067 static PSECURITY_DESCRIPTOR
3068 get_file_security_desc (const char *fname
)
3070 PSECURITY_DESCRIPTOR psd
= NULL
;
3072 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3073 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3075 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3077 err
= GetLastError ();
3078 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3082 psd
= xmalloc (sd_len
);
3083 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3095 unsigned n_subauthorities
;
3097 /* Use the last sub-authority value of the RID, the relative
3098 portion of the SID, as user/group ID. */
3099 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3100 if (n_subauthorities
< 1)
3101 return 0; /* the "World" RID */
3102 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3105 /* Caching SID and account values for faster lokup. */
3108 # define FLEXIBLE_ARRAY_MEMBER
3110 # define FLEXIBLE_ARRAY_MEMBER 1
3115 struct w32_id
*next
;
3117 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3120 static struct w32_id
*w32_idlist
;
3123 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3125 struct w32_id
*tail
, *found
;
3127 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3129 if (equal_sid ((PSID
)tail
->sid
, sid
))
3138 strcpy (name
, found
->name
);
3146 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3149 struct w32_id
*new_entry
;
3151 /* We don't want to leave behind stale cache from when Emacs was
3155 sid_len
= get_length_sid (sid
);
3156 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3159 new_entry
->rid
= id
;
3160 strcpy (new_entry
->name
, name
);
3161 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3162 new_entry
->next
= w32_idlist
;
3163 w32_idlist
= new_entry
;
3172 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3173 unsigned *id
, char *nm
, int what
)
3176 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3178 SID_NAME_USE ignore
;
3180 DWORD name_len
= sizeof (name
);
3182 DWORD domain_len
= sizeof (domain
);
3188 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3189 else if (what
== GID
)
3190 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3194 if (!result
|| !is_valid_sid (sid
))
3196 else if (!w32_cached_id (sid
, id
, nm
))
3198 /* If FNAME is a UNC, we need to lookup account on the
3199 specified machine. */
3200 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3201 && fname
[2] != '\0')
3206 for (s
= fname
+ 2, p
= machine
;
3207 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3213 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3214 domain
, &domain_len
, &ignore
)
3215 || name_len
> UNLEN
+1)
3219 *id
= get_rid (sid
);
3221 w32_add_to_cache (sid
, *id
, name
);
3228 get_file_owner_and_group (
3229 PSECURITY_DESCRIPTOR psd
,
3233 int dflt_usr
= 0, dflt_grp
= 0;
3242 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3244 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3247 /* Consider files to belong to current user/group, if we cannot get
3248 more accurate information. */
3251 st
->st_uid
= dflt_passwd
.pw_uid
;
3252 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3256 st
->st_gid
= dflt_passwd
.pw_gid
;
3257 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3261 /* Return non-zero if NAME is a potentially slow filesystem. */
3263 is_slow_fs (const char *name
)
3268 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3269 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3270 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3271 devtype
= GetDriveType (NULL
); /* use root of current drive */
3274 /* GetDriveType needs the root directory of the drive. */
3275 strncpy (drive_root
, name
, 2);
3276 drive_root
[2] = '\\';
3277 drive_root
[3] = '\0';
3278 devtype
= GetDriveType (drive_root
);
3280 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3283 /* MSVC stat function can't cope with UNC names and has other bugs, so
3284 replace it with our own. This also allows us to calculate consistent
3285 inode values without hacks in the main Emacs code. */
3287 stat (const char * path
, struct stat
* buf
)
3292 WIN32_FIND_DATA wfd
;
3294 unsigned __int64 fake_inode
;
3297 int rootdir
= FALSE
;
3298 PSECURITY_DESCRIPTOR psd
= NULL
;
3300 if (path
== NULL
|| buf
== NULL
)
3306 name
= (char *) map_w32_filename (path
, &path
);
3307 /* Must be valid filename, no wild cards or other invalid
3308 characters. We use _mbspbrk to support multibyte strings that
3309 might look to strpbrk as if they included literal *, ?, and other
3310 characters mentioned below that are disallowed by Windows
3312 if (_mbspbrk (name
, "*?|<>\""))
3318 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3319 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3320 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3325 /* Remove trailing directory separator, unless name is the root
3326 directory of a drive or UNC volume in which case ensure there
3327 is a trailing separator. */
3328 len
= strlen (name
);
3329 rootdir
= (path
>= name
+ len
- 1
3330 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3331 name
= strcpy (alloca (len
+ 2), name
);
3333 if (is_unc_volume (name
))
3335 DWORD attrs
= unc_volume_file_attributes (name
);
3340 memset (&wfd
, 0, sizeof (wfd
));
3341 wfd
.dwFileAttributes
= attrs
;
3342 wfd
.ftCreationTime
= utc_base_ft
;
3343 wfd
.ftLastAccessTime
= utc_base_ft
;
3344 wfd
.ftLastWriteTime
= utc_base_ft
;
3345 strcpy (wfd
.cFileName
, name
);
3349 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3350 strcat (name
, "\\");
3351 if (GetDriveType (name
) < 2)
3356 memset (&wfd
, 0, sizeof (wfd
));
3357 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3358 wfd
.ftCreationTime
= utc_base_ft
;
3359 wfd
.ftLastAccessTime
= utc_base_ft
;
3360 wfd
.ftLastWriteTime
= utc_base_ft
;
3361 strcpy (wfd
.cFileName
, name
);
3365 if (IS_DIRECTORY_SEP (name
[len
-1]))
3368 /* (This is hacky, but helps when doing file completions on
3369 network drives.) Optimize by using information available from
3370 active readdir if possible. */
3371 len
= strlen (dir_pathname
);
3372 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3374 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3375 && strnicmp (name
, dir_pathname
, len
) == 0
3376 && IS_DIRECTORY_SEP (name
[len
])
3377 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3379 /* This was the last entry returned by readdir. */
3380 wfd
= dir_find_data
;
3384 logon_network_drive (name
);
3386 fh
= FindFirstFile (name
, &wfd
);
3387 if (fh
== INVALID_HANDLE_VALUE
)
3396 if (!(NILP (Vw32_get_true_file_attributes
)
3397 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3398 /* No access rights required to get info. */
3399 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3400 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3401 != INVALID_HANDLE_VALUE
)
3403 /* This is more accurate in terms of gettting the correct number
3404 of links, but is quite slow (it is noticeable when Emacs is
3405 making a list of file name completions). */
3406 BY_HANDLE_FILE_INFORMATION info
;
3408 if (GetFileInformationByHandle (fh
, &info
))
3410 buf
->st_nlink
= info
.nNumberOfLinks
;
3411 /* Might as well use file index to fake inode values, but this
3412 is not guaranteed to be unique unless we keep a handle open
3413 all the time (even then there are situations where it is
3414 not unique). Reputedly, there are at most 48 bits of info
3415 (on NTFS, presumably less on FAT). */
3416 fake_inode
= info
.nFileIndexHigh
;
3418 fake_inode
+= info
.nFileIndexLow
;
3426 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3428 buf
->st_mode
= S_IFDIR
;
3432 switch (GetFileType (fh
))
3434 case FILE_TYPE_DISK
:
3435 buf
->st_mode
= S_IFREG
;
3437 case FILE_TYPE_PIPE
:
3438 buf
->st_mode
= S_IFIFO
;
3440 case FILE_TYPE_CHAR
:
3441 case FILE_TYPE_UNKNOWN
:
3443 buf
->st_mode
= S_IFCHR
;
3447 psd
= get_file_security_desc (name
);
3448 get_file_owner_and_group (psd
, name
, buf
);
3452 /* Don't bother to make this information more accurate. */
3453 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3458 get_file_owner_and_group (NULL
, name
, buf
);
3463 /* Not sure if there is any point in this. */
3464 if (!NILP (Vw32_generate_fake_inodes
))
3465 fake_inode
= generate_inode_val (name
);
3466 else if (fake_inode
== 0)
3468 /* For want of something better, try to make everything unique. */
3469 static DWORD gen_num
= 0;
3470 fake_inode
= ++gen_num
;
3474 /* MSVC defines _ino_t to be short; other libc's might not. */
3475 if (sizeof (buf
->st_ino
) == 2)
3476 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3478 buf
->st_ino
= fake_inode
;
3480 /* volume_info is set indirectly by map_w32_filename */
3481 buf
->st_dev
= volume_info
.serialnum
;
3482 buf
->st_rdev
= volume_info
.serialnum
;
3485 buf
->st_size
= wfd
.nFileSizeHigh
;
3486 buf
->st_size
<<= 32;
3487 buf
->st_size
+= wfd
.nFileSizeLow
;
3489 /* Convert timestamps to Unix format. */
3490 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3491 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3492 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3493 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3494 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3496 /* determine rwx permissions */
3497 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3498 permission
= S_IREAD
;
3500 permission
= S_IREAD
| S_IWRITE
;
3502 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3503 permission
|= S_IEXEC
;
3504 else if (is_exec (name
))
3505 permission
|= S_IEXEC
;
3507 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3512 /* Provide fstat and utime as well as stat for consistent handling of
3515 fstat (int desc
, struct stat
* buf
)
3517 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3518 BY_HANDLE_FILE_INFORMATION info
;
3519 unsigned __int64 fake_inode
;
3522 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3524 case FILE_TYPE_DISK
:
3525 buf
->st_mode
= S_IFREG
;
3526 if (!GetFileInformationByHandle (fh
, &info
))
3532 case FILE_TYPE_PIPE
:
3533 buf
->st_mode
= S_IFIFO
;
3535 case FILE_TYPE_CHAR
:
3536 case FILE_TYPE_UNKNOWN
:
3538 buf
->st_mode
= S_IFCHR
;
3540 memset (&info
, 0, sizeof (info
));
3541 info
.dwFileAttributes
= 0;
3542 info
.ftCreationTime
= utc_base_ft
;
3543 info
.ftLastAccessTime
= utc_base_ft
;
3544 info
.ftLastWriteTime
= utc_base_ft
;
3547 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3548 buf
->st_mode
= S_IFDIR
;
3550 buf
->st_nlink
= info
.nNumberOfLinks
;
3551 /* Might as well use file index to fake inode values, but this
3552 is not guaranteed to be unique unless we keep a handle open
3553 all the time (even then there are situations where it is
3554 not unique). Reputedly, there are at most 48 bits of info
3555 (on NTFS, presumably less on FAT). */
3556 fake_inode
= info
.nFileIndexHigh
;
3558 fake_inode
+= info
.nFileIndexLow
;
3560 /* MSVC defines _ino_t to be short; other libc's might not. */
3561 if (sizeof (buf
->st_ino
) == 2)
3562 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3564 buf
->st_ino
= fake_inode
;
3566 /* Consider files to belong to current user.
3567 FIXME: this should use GetSecurityInfo API, but it is only
3568 available for _WIN32_WINNT >= 0x501. */
3569 buf
->st_uid
= dflt_passwd
.pw_uid
;
3570 buf
->st_gid
= dflt_passwd
.pw_gid
;
3571 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3572 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3574 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3575 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3577 buf
->st_size
= info
.nFileSizeHigh
;
3578 buf
->st_size
<<= 32;
3579 buf
->st_size
+= info
.nFileSizeLow
;
3581 /* Convert timestamps to Unix format. */
3582 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3583 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3584 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3585 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3586 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3588 /* determine rwx permissions */
3589 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3590 permission
= S_IREAD
;
3592 permission
= S_IREAD
| S_IWRITE
;
3594 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3595 permission
|= S_IEXEC
;
3598 #if 0 /* no way of knowing the filename */
3599 char * p
= strrchr (name
, '.');
3601 (xstrcasecmp (p
, ".exe") == 0 ||
3602 xstrcasecmp (p
, ".com") == 0 ||
3603 xstrcasecmp (p
, ".bat") == 0 ||
3604 xstrcasecmp (p
, ".cmd") == 0))
3605 permission
|= S_IEXEC
;
3609 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3615 utime (const char *name
, struct utimbuf
*times
)
3617 struct utimbuf deftime
;
3624 deftime
.modtime
= deftime
.actime
= time (NULL
);
3628 /* Need write access to set times. */
3629 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3630 0, OPEN_EXISTING
, 0, NULL
);
3633 convert_from_time_t (times
->actime
, &atime
);
3634 convert_from_time_t (times
->modtime
, &mtime
);
3635 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3652 /* Support for browsing other processes and their attributes. See
3653 process.c for the Lisp bindings. */
3655 /* Helper wrapper functions. */
3657 HANDLE WINAPI
create_toolhelp32_snapshot (
3661 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3663 if (g_b_init_create_toolhelp32_snapshot
== 0)
3665 g_b_init_create_toolhelp32_snapshot
= 1;
3666 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3667 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3668 "CreateToolhelp32Snapshot");
3670 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3672 return INVALID_HANDLE_VALUE
;
3674 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3677 BOOL WINAPI
process32_first (
3679 LPPROCESSENTRY32 lppe
)
3681 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3683 if (g_b_init_process32_first
== 0)
3685 g_b_init_process32_first
= 1;
3686 s_pfn_Process32_First
= (Process32First_Proc
)
3687 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3690 if (s_pfn_Process32_First
== NULL
)
3694 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3697 BOOL WINAPI
process32_next (
3699 LPPROCESSENTRY32 lppe
)
3701 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3703 if (g_b_init_process32_next
== 0)
3705 g_b_init_process32_next
= 1;
3706 s_pfn_Process32_Next
= (Process32Next_Proc
)
3707 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3710 if (s_pfn_Process32_Next
== NULL
)
3714 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3717 BOOL WINAPI
open_thread_token (
3718 HANDLE ThreadHandle
,
3719 DWORD DesiredAccess
,
3721 PHANDLE TokenHandle
)
3723 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3724 HMODULE hm_advapi32
= NULL
;
3725 if (is_windows_9x () == TRUE
)
3727 SetLastError (ERROR_NOT_SUPPORTED
);
3730 if (g_b_init_open_thread_token
== 0)
3732 g_b_init_open_thread_token
= 1;
3733 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3734 s_pfn_Open_Thread_Token
=
3735 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3737 if (s_pfn_Open_Thread_Token
== NULL
)
3739 SetLastError (ERROR_NOT_SUPPORTED
);
3743 s_pfn_Open_Thread_Token (
3751 BOOL WINAPI
impersonate_self (
3752 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3754 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3755 HMODULE hm_advapi32
= NULL
;
3756 if (is_windows_9x () == TRUE
)
3760 if (g_b_init_impersonate_self
== 0)
3762 g_b_init_impersonate_self
= 1;
3763 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3764 s_pfn_Impersonate_Self
=
3765 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3767 if (s_pfn_Impersonate_Self
== NULL
)
3771 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3774 BOOL WINAPI
revert_to_self (void)
3776 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3777 HMODULE hm_advapi32
= NULL
;
3778 if (is_windows_9x () == TRUE
)
3782 if (g_b_init_revert_to_self
== 0)
3784 g_b_init_revert_to_self
= 1;
3785 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3786 s_pfn_Revert_To_Self
=
3787 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3789 if (s_pfn_Revert_To_Self
== NULL
)
3793 return s_pfn_Revert_To_Self ();
3796 BOOL WINAPI
get_process_memory_info (
3798 PPROCESS_MEMORY_COUNTERS mem_counters
,
3801 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3802 HMODULE hm_psapi
= NULL
;
3803 if (is_windows_9x () == TRUE
)
3807 if (g_b_init_get_process_memory_info
== 0)
3809 g_b_init_get_process_memory_info
= 1;
3810 hm_psapi
= LoadLibrary ("Psapi.dll");
3812 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3813 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3815 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3819 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3822 BOOL WINAPI
get_process_working_set_size (
3827 static GetProcessWorkingSetSize_Proc
3828 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3830 if (is_windows_9x () == TRUE
)
3834 if (g_b_init_get_process_working_set_size
== 0)
3836 g_b_init_get_process_working_set_size
= 1;
3837 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3838 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3839 "GetProcessWorkingSetSize");
3841 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3845 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3848 BOOL WINAPI
global_memory_status (
3851 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3853 if (is_windows_9x () == TRUE
)
3857 if (g_b_init_global_memory_status
== 0)
3859 g_b_init_global_memory_status
= 1;
3860 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3861 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3862 "GlobalMemoryStatus");
3864 if (s_pfn_Global_Memory_Status
== NULL
)
3868 return s_pfn_Global_Memory_Status (buf
);
3871 BOOL WINAPI
global_memory_status_ex (
3872 MEMORY_STATUS_EX
*buf
)
3874 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3876 if (is_windows_9x () == TRUE
)
3880 if (g_b_init_global_memory_status_ex
== 0)
3882 g_b_init_global_memory_status_ex
= 1;
3883 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3884 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3885 "GlobalMemoryStatusEx");
3887 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3891 return s_pfn_Global_Memory_Status_Ex (buf
);
3895 list_system_processes (void)
3897 struct gcpro gcpro1
;
3898 Lisp_Object proclist
= Qnil
;
3901 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3903 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3905 PROCESSENTRY32 proc_entry
;
3911 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3912 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3913 res
= process32_next (h_snapshot
, &proc_entry
))
3915 proc_id
= proc_entry
.th32ProcessID
;
3916 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3919 CloseHandle (h_snapshot
);
3921 proclist
= Fnreverse (proclist
);
3928 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3930 TOKEN_PRIVILEGES priv
;
3931 DWORD priv_size
= sizeof (priv
);
3932 DWORD opriv_size
= sizeof (*old_priv
);
3933 HANDLE h_token
= NULL
;
3934 HANDLE h_thread
= GetCurrentThread ();
3938 res
= open_thread_token (h_thread
,
3939 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3941 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3943 if (impersonate_self (SecurityImpersonation
))
3944 res
= open_thread_token (h_thread
,
3945 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3950 priv
.PrivilegeCount
= 1;
3951 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3952 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3953 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3954 old_priv
, &opriv_size
)
3955 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3959 CloseHandle (h_token
);
3965 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3967 DWORD priv_size
= sizeof (*priv
);
3968 HANDLE h_token
= NULL
;
3971 if (open_thread_token (GetCurrentThread (),
3972 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3975 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3976 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3980 CloseHandle (h_token
);
3986 ltime (long time_sec
, long time_usec
)
3988 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3989 make_number (time_sec
& 0xffff),
3990 make_number (time_usec
));
3993 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
3996 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
3997 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4000 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4001 ULONGLONG tem1
, tem2
, tem3
, tem
;
4004 || !get_process_times_fn
4005 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4006 &ft_kernel
, &ft_user
))
4009 GetSystemTimeAsFileTime (&ft_current
);
4011 FILETIME_TO_U64 (tem1
, ft_kernel
);
4013 *stime
= U64_TO_LISP_TIME (tem1
);
4015 FILETIME_TO_U64 (tem2
, ft_user
);
4017 *utime
= U64_TO_LISP_TIME (tem2
);
4020 *ttime
= U64_TO_LISP_TIME (tem3
);
4022 FILETIME_TO_U64 (tem
, ft_creation
);
4023 /* Process no 4 (System) returns zero creation time. */
4025 tem
= (tem
- utc_base
) / 10L;
4026 *ctime
= U64_TO_LISP_TIME (tem
);
4030 FILETIME_TO_U64 (tem3
, ft_current
);
4031 tem
= (tem3
- utc_base
) / 10L - tem
;
4033 *etime
= U64_TO_LISP_TIME (tem
);
4037 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4048 system_process_attributes (Lisp_Object pid
)
4050 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4051 Lisp_Object attrs
= Qnil
;
4052 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4053 HANDLE h_snapshot
, h_proc
;
4056 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4057 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4058 DWORD glength
= sizeof (gname
);
4059 HANDLE token
= NULL
;
4060 SID_NAME_USE user_type
;
4061 unsigned char *buf
= NULL
;
4063 TOKEN_USER user_token
;
4064 TOKEN_PRIMARY_GROUP group_token
;
4068 PROCESS_MEMORY_COUNTERS mem
;
4069 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4070 DWORD minrss
, maxrss
;
4072 MEMORY_STATUS_EX memstex
;
4073 double totphys
= 0.0;
4074 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4076 BOOL result
= FALSE
;
4078 CHECK_NUMBER_OR_FLOAT (pid
);
4079 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4081 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4083 GCPRO3 (attrs
, decoded_cmd
, tem
);
4085 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4090 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4091 for (res
= process32_first (h_snapshot
, &pe
); res
;
4092 res
= process32_next (h_snapshot
, &pe
))
4094 if (proc_id
== pe
.th32ProcessID
)
4097 decoded_cmd
= build_string ("Idle");
4100 /* Decode the command name from locale-specific
4102 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4103 strlen (pe
.szExeFile
));
4105 code_convert_string_norecord (cmd_str
,
4106 Vlocale_coding_system
, 0);
4108 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4109 attrs
= Fcons (Fcons (Qppid
,
4110 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4112 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4114 attrs
= Fcons (Fcons (Qthcount
,
4115 make_fixnum_or_float (pe
.cntThreads
)),
4122 CloseHandle (h_snapshot
);
4131 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4133 /* If we were denied a handle to the process, try again after
4134 enabling the SeDebugPrivilege in our process. */
4137 TOKEN_PRIVILEGES priv_current
;
4139 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4141 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4143 restore_privilege (&priv_current
);
4149 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4152 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4153 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4155 buf
= xmalloc (blen
);
4156 result
= get_token_information (token
, TokenUser
,
4157 (LPVOID
)buf
, blen
, &needed
);
4160 memcpy (&user_token
, buf
, sizeof (user_token
));
4161 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4163 euid
= get_rid (user_token
.User
.Sid
);
4164 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4169 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4172 strcpy (uname
, "unknown");
4176 ulength
= strlen (uname
);
4182 /* Determine a reasonable euid and gid values. */
4183 if (xstrcasecmp ("administrator", uname
) == 0)
4185 euid
= 500; /* well-known Administrator uid */
4186 egid
= 513; /* well-known None gid */
4190 /* Get group id and name. */
4191 result
= get_token_information (token
, TokenPrimaryGroup
,
4192 (LPVOID
)buf
, blen
, &needed
);
4193 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4195 buf
= xrealloc (buf
, blen
= needed
);
4196 result
= get_token_information (token
, TokenPrimaryGroup
,
4197 (LPVOID
)buf
, blen
, &needed
);
4201 memcpy (&group_token
, buf
, sizeof (group_token
));
4202 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4204 egid
= get_rid (group_token
.PrimaryGroup
);
4205 dlength
= sizeof (domain
);
4207 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4208 gname
, &glength
, NULL
, &dlength
,
4211 w32_add_to_cache (group_token
.PrimaryGroup
,
4215 strcpy (gname
, "None");
4219 glength
= strlen (gname
);
4227 if (!is_windows_9x ())
4229 /* We couldn't open the process token, presumably because of
4230 insufficient access rights. Assume this process is run
4232 strcpy (uname
, "SYSTEM");
4233 strcpy (gname
, "None");
4234 euid
= 18; /* SYSTEM */
4235 egid
= 513; /* None */
4236 glength
= strlen (gname
);
4237 ulength
= strlen (uname
);
4239 /* If we are running under Windows 9X, where security calls are
4240 not supported, we assume all processes are run by the current
4242 else if (GetUserName (uname
, &ulength
))
4244 if (xstrcasecmp ("administrator", uname
) == 0)
4249 strcpy (gname
, "None");
4250 glength
= strlen (gname
);
4251 ulength
= strlen (uname
);
4257 strcpy (uname
, "administrator");
4258 ulength
= strlen (uname
);
4259 strcpy (gname
, "None");
4260 glength
= strlen (gname
);
4263 CloseHandle (token
);
4266 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4267 tem
= make_unibyte_string (uname
, ulength
);
4268 attrs
= Fcons (Fcons (Quser
,
4269 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4271 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4272 tem
= make_unibyte_string (gname
, glength
);
4273 attrs
= Fcons (Fcons (Qgroup
,
4274 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4277 if (global_memory_status_ex (&memstex
))
4278 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4279 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4281 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4282 double, so we need to do this for it... */
4284 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4285 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4286 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4288 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4290 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4291 else if (global_memory_status (&memst
))
4292 totphys
= memst
.dwTotalPhys
/ 1024.0;
4295 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4298 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4300 attrs
= Fcons (Fcons (Qmajflt
,
4301 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4303 attrs
= Fcons (Fcons (Qvsize
,
4304 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4306 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4308 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4311 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4313 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4315 attrs
= Fcons (Fcons (Qmajflt
,
4316 make_fixnum_or_float (mem
.PageFaultCount
)),
4318 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4320 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4323 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4325 DWORD rss
= maxrss
/ 1024;
4327 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4329 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4332 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4334 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4335 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4336 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4337 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4338 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4339 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4342 /* FIXME: Retrieve command line by walking the PEB of the process. */
4345 CloseHandle (h_proc
);
4353 /* Wrappers for winsock functions to map between our file descriptors
4354 and winsock's handles; also set h_errno for convenience.
4356 To allow Emacs to run on systems which don't have winsock support
4357 installed, we dynamically link to winsock on startup if present, and
4358 otherwise provide the minimum necessary functionality
4359 (eg. gethostname). */
4361 /* function pointers for relevant socket functions */
4362 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4363 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4364 int (PASCAL
*pfn_WSAGetLastError
) (void);
4365 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4366 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4367 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4368 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4369 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4370 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4371 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4372 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4373 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4374 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4375 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4376 int (PASCAL
*pfn_WSACleanup
) (void);
4378 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4379 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4380 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4381 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4382 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4383 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4384 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4385 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4386 const char * optval
, int optlen
);
4387 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4388 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4390 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4391 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4392 struct sockaddr
* from
, int * fromlen
);
4393 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4394 const struct sockaddr
* to
, int tolen
);
4396 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4397 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4398 #ifndef HANDLE_FLAG_INHERIT
4399 #define HANDLE_FLAG_INHERIT 1
4403 static int winsock_inuse
;
4408 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4410 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4411 after WSAStartup returns successfully, but it seems reasonable
4412 to allow unloading winsock anyway in that case. */
4413 if (pfn_WSACleanup () == 0 ||
4414 pfn_WSAGetLastError () == WSAENETDOWN
)
4416 if (FreeLibrary (winsock_lib
))
4425 init_winsock (int load_now
)
4427 WSADATA winsockData
;
4429 if (winsock_lib
!= NULL
)
4432 pfn_SetHandleInformation
= NULL
;
4433 pfn_SetHandleInformation
4434 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4435 "SetHandleInformation");
4437 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4439 if (winsock_lib
!= NULL
)
4441 /* dynamically link to socket functions */
4443 #define LOAD_PROC(fn) \
4444 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4447 LOAD_PROC (WSAStartup
);
4448 LOAD_PROC (WSASetLastError
);
4449 LOAD_PROC (WSAGetLastError
);
4450 LOAD_PROC (WSAEventSelect
);
4451 LOAD_PROC (WSACreateEvent
);
4452 LOAD_PROC (WSACloseEvent
);
4455 LOAD_PROC (connect
);
4456 LOAD_PROC (ioctlsocket
);
4459 LOAD_PROC (closesocket
);
4460 LOAD_PROC (shutdown
);
4463 LOAD_PROC (inet_addr
);
4464 LOAD_PROC (gethostname
);
4465 LOAD_PROC (gethostbyname
);
4466 LOAD_PROC (getservbyname
);
4467 LOAD_PROC (getpeername
);
4468 LOAD_PROC (WSACleanup
);
4469 LOAD_PROC (setsockopt
);
4471 LOAD_PROC (getsockname
);
4473 LOAD_PROC (recvfrom
);
4477 /* specify version 1.1 of winsock */
4478 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4480 if (winsockData
.wVersion
!= 0x101)
4485 /* Report that winsock exists and is usable, but leave
4486 socket functions disabled. I am assuming that calling
4487 WSAStartup does not require any network interaction,
4488 and in particular does not cause or require a dial-up
4489 connection to be established. */
4492 FreeLibrary (winsock_lib
);
4500 FreeLibrary (winsock_lib
);
4510 /* function to set h_errno for compatibility; map winsock error codes to
4511 normal system codes where they overlap (non-overlapping definitions
4512 are already in <sys/socket.h> */
4516 if (winsock_lib
== NULL
)
4519 h_errno
= pfn_WSAGetLastError ();
4523 case WSAEACCES
: h_errno
= EACCES
; break;
4524 case WSAEBADF
: h_errno
= EBADF
; break;
4525 case WSAEFAULT
: h_errno
= EFAULT
; break;
4526 case WSAEINTR
: h_errno
= EINTR
; break;
4527 case WSAEINVAL
: h_errno
= EINVAL
; break;
4528 case WSAEMFILE
: h_errno
= EMFILE
; break;
4529 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4530 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4538 if (h_errno
== 0 && winsock_lib
!= NULL
)
4539 pfn_WSASetLastError (0);
4542 /* Extend strerror to handle the winsock-specific error codes. */
4546 } _wsa_errlist
[] = {
4547 WSAEINTR
, "Interrupted function call",
4548 WSAEBADF
, "Bad file descriptor",
4549 WSAEACCES
, "Permission denied",
4550 WSAEFAULT
, "Bad address",
4551 WSAEINVAL
, "Invalid argument",
4552 WSAEMFILE
, "Too many open files",
4554 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4555 WSAEINPROGRESS
, "Operation now in progress",
4556 WSAEALREADY
, "Operation already in progress",
4557 WSAENOTSOCK
, "Socket operation on non-socket",
4558 WSAEDESTADDRREQ
, "Destination address required",
4559 WSAEMSGSIZE
, "Message too long",
4560 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4561 WSAENOPROTOOPT
, "Bad protocol option",
4562 WSAEPROTONOSUPPORT
, "Protocol not supported",
4563 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4564 WSAEOPNOTSUPP
, "Operation not supported",
4565 WSAEPFNOSUPPORT
, "Protocol family not supported",
4566 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4567 WSAEADDRINUSE
, "Address already in use",
4568 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4569 WSAENETDOWN
, "Network is down",
4570 WSAENETUNREACH
, "Network is unreachable",
4571 WSAENETRESET
, "Network dropped connection on reset",
4572 WSAECONNABORTED
, "Software caused connection abort",
4573 WSAECONNRESET
, "Connection reset by peer",
4574 WSAENOBUFS
, "No buffer space available",
4575 WSAEISCONN
, "Socket is already connected",
4576 WSAENOTCONN
, "Socket is not connected",
4577 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4578 WSAETOOMANYREFS
, "Too many references", /* not sure */
4579 WSAETIMEDOUT
, "Connection timed out",
4580 WSAECONNREFUSED
, "Connection refused",
4581 WSAELOOP
, "Network loop", /* not sure */
4582 WSAENAMETOOLONG
, "Name is too long",
4583 WSAEHOSTDOWN
, "Host is down",
4584 WSAEHOSTUNREACH
, "No route to host",
4585 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4586 WSAEPROCLIM
, "Too many processes",
4587 WSAEUSERS
, "Too many users", /* not sure */
4588 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4589 WSAESTALE
, "Data is stale", /* not sure */
4590 WSAEREMOTE
, "Remote error", /* not sure */
4592 WSASYSNOTREADY
, "Network subsystem is unavailable",
4593 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4594 WSANOTINITIALISED
, "Winsock not initialized successfully",
4595 WSAEDISCON
, "Graceful shutdown in progress",
4597 WSAENOMORE
, "No more operations allowed", /* not sure */
4598 WSAECANCELLED
, "Operation cancelled", /* not sure */
4599 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4600 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4601 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4602 WSASYSCALLFAILURE
, "System call failure",
4603 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4604 WSATYPE_NOT_FOUND
, "Class type not found",
4605 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4606 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4607 WSAEREFUSED
, "Operation refused", /* not sure */
4610 WSAHOST_NOT_FOUND
, "Host not found",
4611 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4612 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4613 WSANO_DATA
, "Valid name, no data record of requested type",
4619 sys_strerror (int error_no
)
4622 static char unknown_msg
[40];
4624 if (error_no
>= 0 && error_no
< sys_nerr
)
4625 return sys_errlist
[error_no
];
4627 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4628 if (_wsa_errlist
[i
].errnum
== error_no
)
4629 return _wsa_errlist
[i
].msg
;
4631 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4635 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4636 but I believe the method of keeping the socket handle separate (and
4637 insuring it is not inheritable) is the correct one. */
4639 //#define SOCK_REPLACE_HANDLE
4641 #ifdef SOCK_REPLACE_HANDLE
4642 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4644 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4647 int socket_to_fd (SOCKET s
);
4650 sys_socket (int af
, int type
, int protocol
)
4654 if (winsock_lib
== NULL
)
4657 return INVALID_SOCKET
;
4662 /* call the real socket function */
4663 s
= pfn_socket (af
, type
, protocol
);
4665 if (s
!= INVALID_SOCKET
)
4666 return socket_to_fd (s
);
4672 /* Convert a SOCKET to a file descriptor. */
4674 socket_to_fd (SOCKET s
)
4679 /* Although under NT 3.5 _open_osfhandle will accept a socket
4680 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4681 that does not work under NT 3.1. However, we can get the same
4682 effect by using a backdoor function to replace an existing
4683 descriptor handle with the one we want. */
4685 /* allocate a file descriptor (with appropriate flags) */
4686 fd
= _open ("NUL:", _O_RDWR
);
4689 #ifdef SOCK_REPLACE_HANDLE
4690 /* now replace handle to NUL with our socket handle */
4691 CloseHandle ((HANDLE
) _get_osfhandle (fd
));
4693 _set_osfhnd (fd
, s
);
4694 /* setmode (fd, _O_BINARY); */
4696 /* Make a non-inheritable copy of the socket handle. Note
4697 that it is possible that sockets aren't actually kernel
4698 handles, which appears to be the case on Windows 9x when
4699 the MS Proxy winsock client is installed. */
4701 /* Apparently there is a bug in NT 3.51 with some service
4702 packs, which prevents using DuplicateHandle to make a
4703 socket handle non-inheritable (causes WSACleanup to
4704 hang). The work-around is to use SetHandleInformation
4705 instead if it is available and implemented. */
4706 if (pfn_SetHandleInformation
)
4708 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4712 HANDLE parent
= GetCurrentProcess ();
4713 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4715 if (DuplicateHandle (parent
,
4721 DUPLICATE_SAME_ACCESS
))
4723 /* It is possible that DuplicateHandle succeeds even
4724 though the socket wasn't really a kernel handle,
4725 because a real handle has the same value. So
4726 test whether the new handle really is a socket. */
4727 long nonblocking
= 0;
4728 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4730 pfn_closesocket (s
);
4735 CloseHandle (new_s
);
4740 fd_info
[fd
].hnd
= (HANDLE
) s
;
4743 /* set our own internal flags */
4744 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4750 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4752 /* attach child_process to fd_info */
4753 if (fd_info
[ fd
].cp
!= NULL
)
4755 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4759 fd_info
[ fd
].cp
= cp
;
4762 winsock_inuse
++; /* count open sockets */
4769 pfn_closesocket (s
);
4776 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4778 if (winsock_lib
== NULL
)
4781 return SOCKET_ERROR
;
4785 if (fd_info
[s
].flags
& FILE_SOCKET
)
4787 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4788 if (rc
== SOCKET_ERROR
)
4793 return SOCKET_ERROR
;
4798 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4800 if (winsock_lib
== NULL
)
4803 return SOCKET_ERROR
;
4807 if (fd_info
[s
].flags
& FILE_SOCKET
)
4809 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4810 if (rc
== SOCKET_ERROR
)
4815 return SOCKET_ERROR
;
4819 sys_htons (u_short hostshort
)
4821 return (winsock_lib
!= NULL
) ?
4822 pfn_htons (hostshort
) : hostshort
;
4826 sys_ntohs (u_short netshort
)
4828 return (winsock_lib
!= NULL
) ?
4829 pfn_ntohs (netshort
) : netshort
;
4833 sys_inet_addr (const char * cp
)
4835 return (winsock_lib
!= NULL
) ?
4836 pfn_inet_addr (cp
) : INADDR_NONE
;
4840 sys_gethostname (char * name
, int namelen
)
4842 if (winsock_lib
!= NULL
)
4843 return pfn_gethostname (name
, namelen
);
4845 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4846 return !GetComputerName (name
, (DWORD
*)&namelen
);
4849 return SOCKET_ERROR
;
4853 sys_gethostbyname (const char * name
)
4855 struct hostent
* host
;
4857 if (winsock_lib
== NULL
)
4864 host
= pfn_gethostbyname (name
);
4871 sys_getservbyname (const char * name
, const char * proto
)
4873 struct servent
* serv
;
4875 if (winsock_lib
== NULL
)
4882 serv
= pfn_getservbyname (name
, proto
);
4889 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4891 if (winsock_lib
== NULL
)
4894 return SOCKET_ERROR
;
4898 if (fd_info
[s
].flags
& FILE_SOCKET
)
4900 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4901 if (rc
== SOCKET_ERROR
)
4906 return SOCKET_ERROR
;
4911 sys_shutdown (int s
, int how
)
4913 if (winsock_lib
== NULL
)
4916 return SOCKET_ERROR
;
4920 if (fd_info
[s
].flags
& FILE_SOCKET
)
4922 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4923 if (rc
== SOCKET_ERROR
)
4928 return SOCKET_ERROR
;
4932 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4934 if (winsock_lib
== NULL
)
4937 return SOCKET_ERROR
;
4941 if (fd_info
[s
].flags
& FILE_SOCKET
)
4943 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4944 (const char *)optval
, optlen
);
4945 if (rc
== SOCKET_ERROR
)
4950 return SOCKET_ERROR
;
4954 sys_listen (int s
, int backlog
)
4956 if (winsock_lib
== NULL
)
4959 return SOCKET_ERROR
;
4963 if (fd_info
[s
].flags
& FILE_SOCKET
)
4965 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4966 if (rc
== SOCKET_ERROR
)
4969 fd_info
[s
].flags
|= FILE_LISTEN
;
4973 return SOCKET_ERROR
;
4977 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4979 if (winsock_lib
== NULL
)
4982 return SOCKET_ERROR
;
4986 if (fd_info
[s
].flags
& FILE_SOCKET
)
4988 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4989 if (rc
== SOCKET_ERROR
)
4994 return SOCKET_ERROR
;
4998 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
5000 if (winsock_lib
== NULL
)
5007 if (fd_info
[s
].flags
& FILE_LISTEN
)
5009 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5011 if (t
== INVALID_SOCKET
)
5014 fd
= socket_to_fd (t
);
5016 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5017 ResetEvent (fd_info
[s
].cp
->char_avail
);
5025 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5026 struct sockaddr
* from
, int * fromlen
)
5028 if (winsock_lib
== NULL
)
5031 return SOCKET_ERROR
;
5035 if (fd_info
[s
].flags
& FILE_SOCKET
)
5037 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5038 if (rc
== SOCKET_ERROR
)
5043 return SOCKET_ERROR
;
5047 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5048 const struct sockaddr
* to
, int tolen
)
5050 if (winsock_lib
== NULL
)
5053 return SOCKET_ERROR
;
5057 if (fd_info
[s
].flags
& FILE_SOCKET
)
5059 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5060 if (rc
== SOCKET_ERROR
)
5065 return SOCKET_ERROR
;
5068 /* Windows does not have an fcntl function. Provide an implementation
5069 solely for making sockets non-blocking. */
5071 fcntl (int s
, int cmd
, int options
)
5073 if (winsock_lib
== NULL
)
5080 if (fd_info
[s
].flags
& FILE_SOCKET
)
5082 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5084 unsigned long nblock
= 1;
5085 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5086 if (rc
== SOCKET_ERROR
)
5088 /* Keep track of the fact that we set this to non-blocking. */
5089 fd_info
[s
].flags
|= FILE_NDELAY
;
5095 return SOCKET_ERROR
;
5099 return SOCKET_ERROR
;
5102 #endif /* HAVE_SOCKETS */
5105 /* Shadow main io functions: we need to handle pipes and sockets more
5106 intelligently, and implement non-blocking mode as well. */
5119 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5121 child_process
* cp
= fd_info
[fd
].cp
;
5123 fd_info
[fd
].cp
= NULL
;
5125 if (CHILD_ACTIVE (cp
))
5127 /* if last descriptor to active child_process then cleanup */
5129 for (i
= 0; i
< MAXDESC
; i
++)
5133 if (fd_info
[i
].cp
== cp
)
5139 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5141 #ifndef SOCK_REPLACE_HANDLE
5142 if (winsock_lib
== NULL
) abort ();
5144 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5145 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5147 winsock_inuse
--; /* count open sockets */
5155 /* Note that sockets do not need special treatment here (at least on
5156 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5157 closesocket is equivalent to CloseHandle, which is to be expected
5158 because socket handles are fully fledged kernel handles. */
5161 if (rc
== 0 && fd
< MAXDESC
)
5162 fd_info
[fd
].flags
= 0;
5173 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5175 /* duplicate our internal info as well */
5176 fd_info
[new_fd
] = fd_info
[fd
];
5183 sys_dup2 (int src
, int dst
)
5187 if (dst
< 0 || dst
>= MAXDESC
)
5193 /* make sure we close the destination first if it's a pipe or socket */
5194 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5197 rc
= _dup2 (src
, dst
);
5200 /* duplicate our internal info as well */
5201 fd_info
[dst
] = fd_info
[src
];
5206 /* Unix pipe() has only one arg */
5208 sys_pipe (int * phandles
)
5213 /* make pipe handles non-inheritable; when we spawn a child, we
5214 replace the relevant handle with an inheritable one. Also put
5215 pipes into binary mode; we will do text mode translation ourselves
5217 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5221 /* Protect against overflow, since Windows can open more handles than
5222 our fd_info array has room for. */
5223 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5225 _close (phandles
[0]);
5226 _close (phandles
[1]);
5231 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5232 fd_info
[phandles
[0]].flags
= flags
;
5234 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5235 fd_info
[phandles
[1]].flags
= flags
;
5243 extern int w32_pipe_read_delay
;
5245 /* Function to do blocking read of one byte, needed to implement
5246 select. It is only allowed on sockets and pipes. */
5248 _sys_read_ahead (int fd
)
5253 if (fd
< 0 || fd
>= MAXDESC
)
5254 return STATUS_READ_ERROR
;
5256 cp
= fd_info
[fd
].cp
;
5258 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5259 return STATUS_READ_ERROR
;
5261 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5262 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5264 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5268 cp
->status
= STATUS_READ_IN_PROGRESS
;
5270 if (fd_info
[fd
].flags
& FILE_PIPE
)
5272 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5274 /* Give subprocess time to buffer some more output for us before
5275 reporting that input is available; we need this because Windows 95
5276 connects DOS programs to pipes by making the pipe appear to be
5277 the normal console stdout - as a result most DOS programs will
5278 write to stdout without buffering, ie. one character at a
5279 time. Even some W32 programs do this - "dir" in a command
5280 shell on NT is very slow if we don't do this. */
5283 int wait
= w32_pipe_read_delay
;
5289 /* Yield remainder of our time slice, effectively giving a
5290 temporary priority boost to the child process. */
5294 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5296 HANDLE hnd
= fd_info
[fd
].hnd
;
5297 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5300 /* Configure timeouts for blocking read. */
5301 if (!GetCommTimeouts (hnd
, &ct
))
5302 return STATUS_READ_ERROR
;
5303 ct
.ReadIntervalTimeout
= 0;
5304 ct
.ReadTotalTimeoutMultiplier
= 0;
5305 ct
.ReadTotalTimeoutConstant
= 0;
5306 if (!SetCommTimeouts (hnd
, &ct
))
5307 return STATUS_READ_ERROR
;
5309 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5311 if (GetLastError () != ERROR_IO_PENDING
)
5312 return STATUS_READ_ERROR
;
5313 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5314 return STATUS_READ_ERROR
;
5318 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5320 unsigned long nblock
= 0;
5321 /* We always want this to block, so temporarily disable NDELAY. */
5322 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5323 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5325 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5327 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5330 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5335 if (rc
== sizeof (char))
5336 cp
->status
= STATUS_READ_SUCCEEDED
;
5338 cp
->status
= STATUS_READ_FAILED
;
5344 _sys_wait_accept (int fd
)
5350 if (fd
< 0 || fd
>= MAXDESC
)
5351 return STATUS_READ_ERROR
;
5353 cp
= fd_info
[fd
].cp
;
5355 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5356 return STATUS_READ_ERROR
;
5358 cp
->status
= STATUS_READ_FAILED
;
5360 hEv
= pfn_WSACreateEvent ();
5361 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5362 if (rc
!= SOCKET_ERROR
)
5364 rc
= WaitForSingleObject (hEv
, INFINITE
);
5365 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5366 if (rc
== WAIT_OBJECT_0
)
5367 cp
->status
= STATUS_READ_SUCCEEDED
;
5369 pfn_WSACloseEvent (hEv
);
5375 sys_read (int fd
, char * buffer
, unsigned int count
)
5380 char * orig_buffer
= buffer
;
5388 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5390 child_process
*cp
= fd_info
[fd
].cp
;
5392 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5400 /* re-read CR carried over from last read */
5401 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5403 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5407 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5410 /* presence of a child_process structure means we are operating in
5411 non-blocking mode - otherwise we just call _read directly.
5412 Note that the child_process structure might be missing because
5413 reap_subprocess has been called; in this case the pipe is
5414 already broken, so calling _read on it is okay. */
5417 int current_status
= cp
->status
;
5419 switch (current_status
)
5421 case STATUS_READ_FAILED
:
5422 case STATUS_READ_ERROR
:
5423 /* report normal EOF if nothing in buffer */
5425 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5428 case STATUS_READ_READY
:
5429 case STATUS_READ_IN_PROGRESS
:
5430 DebPrint (("sys_read called when read is in progress\n"));
5431 errno
= EWOULDBLOCK
;
5434 case STATUS_READ_SUCCEEDED
:
5435 /* consume read-ahead char */
5436 *buffer
++ = cp
->chr
;
5439 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5440 ResetEvent (cp
->char_avail
);
5442 case STATUS_READ_ACKNOWLEDGED
:
5446 DebPrint (("sys_read: bad status %d\n", current_status
));
5451 if (fd_info
[fd
].flags
& FILE_PIPE
)
5453 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5454 to_read
= min (waiting
, (DWORD
) count
);
5457 nchars
+= _read (fd
, buffer
, to_read
);
5459 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5461 HANDLE hnd
= fd_info
[fd
].hnd
;
5462 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5469 /* Configure timeouts for non-blocking read. */
5470 if (!GetCommTimeouts (hnd
, &ct
))
5475 ct
.ReadIntervalTimeout
= MAXDWORD
;
5476 ct
.ReadTotalTimeoutMultiplier
= 0;
5477 ct
.ReadTotalTimeoutConstant
= 0;
5478 if (!SetCommTimeouts (hnd
, &ct
))
5484 if (!ResetEvent (ovl
->hEvent
))
5489 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5491 if (GetLastError () != ERROR_IO_PENDING
)
5496 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5506 else /* FILE_SOCKET */
5508 if (winsock_lib
== NULL
) abort ();
5510 /* do the equivalent of a non-blocking read */
5511 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5512 if (waiting
== 0 && nchars
== 0)
5514 h_errno
= errno
= EWOULDBLOCK
;
5520 /* always use binary mode for sockets */
5521 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5522 if (res
== SOCKET_ERROR
)
5524 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5525 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5536 int nread
= _read (fd
, buffer
, count
);
5539 else if (nchars
== 0)
5544 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5545 /* Perform text mode translation if required. */
5546 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5548 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5549 /* If buffer contains only CR, return that. To be absolutely
5550 sure we should attempt to read the next char, but in
5551 practice a CR to be followed by LF would not appear by
5552 itself in the buffer. */
5553 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5555 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5561 nchars
= _read (fd
, buffer
, count
);
5566 /* From w32xfns.c */
5567 extern HANDLE interrupt_handle
;
5569 /* For now, don't bother with a non-blocking mode */
5571 sys_write (int fd
, const void * buffer
, unsigned int count
)
5581 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5583 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5589 /* Perform text mode translation if required. */
5590 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5592 char * tmpbuf
= alloca (count
* 2);
5593 unsigned char * src
= (void *)buffer
;
5594 unsigned char * dst
= tmpbuf
;
5599 unsigned char *next
;
5600 /* copy next line or remaining bytes */
5601 next
= _memccpy (dst
, src
, '\n', nbytes
);
5604 /* copied one line ending with '\n' */
5605 int copied
= next
- dst
;
5608 /* insert '\r' before '\n' */
5615 /* copied remaining partial line -> now finished */
5622 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5624 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5625 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5626 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5629 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5631 if (GetLastError () != ERROR_IO_PENDING
)
5636 if (detect_input_pending ())
5637 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5640 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5641 if (active
== WAIT_OBJECT_0
)
5642 { /* User pressed C-g, cancel write, then leave. Don't bother
5643 cleaning up as we may only get stuck in buggy drivers. */
5644 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5649 if (active
== WAIT_OBJECT_0
+ 1
5650 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5659 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5661 unsigned long nblock
= 0;
5662 if (winsock_lib
== NULL
) abort ();
5664 /* TODO: implement select() properly so non-blocking I/O works. */
5665 /* For now, make sure the write blocks. */
5666 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5667 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5669 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5671 /* Set the socket back to non-blocking if it was before,
5672 for other operations that support it. */
5673 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5676 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5679 if (nchars
== SOCKET_ERROR
)
5681 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5682 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5689 /* Some networked filesystems don't like too large writes, so
5690 break them into smaller chunks. See the Comments section of
5691 the MSDN documentation of WriteFile for details behind the
5692 choice of the value of CHUNK below. See also the thread
5693 http://thread.gmane.org/gmane.comp.version-control.git/145294
5694 in the git mailing list. */
5695 const unsigned char *p
= buffer
;
5696 const unsigned chunk
= 30 * 1024 * 1024;
5701 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5702 int n
= _write (fd
, p
, this_chunk
);
5710 else if (n
< this_chunk
)
5721 check_windows_init_file (void)
5723 extern int noninteractive
, inhibit_window_system
;
5725 /* A common indication that Emacs is not installed properly is when
5726 it cannot find the Windows installation file. If this file does
5727 not exist in the expected place, tell the user. */
5729 if (!noninteractive
&& !inhibit_window_system
)
5731 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
5732 Lisp_Object objs
[2];
5733 Lisp_Object full_load_path
;
5734 Lisp_Object init_file
;
5737 objs
[0] = Vload_path
;
5738 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5739 full_load_path
= Fappend (2, objs
);
5740 init_file
= build_string ("term/w32-win");
5741 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5744 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5745 char *init_file_name
= SDATA (init_file
);
5746 char *load_path
= SDATA (load_path_print
);
5747 char *buffer
= alloca (1024
5748 + strlen (init_file_name
)
5749 + strlen (load_path
));
5752 "The Emacs Windows initialization file \"%s.el\" "
5753 "could not be found in your Emacs installation. "
5754 "Emacs checked the following directories for this file:\n"
5756 "When Emacs cannot find this file, it usually means that it "
5757 "was not installed properly, or its distribution file was "
5758 "not unpacked properly.\nSee the README.W32 file in the "
5759 "top-level Emacs directory for more information.",
5760 init_file_name
, load_path
);
5763 "Emacs Abort Dialog",
5764 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5765 /* Use the low-level Emacs abort. */
5780 /* shutdown the socket interface if necessary */
5791 /* Initialise the socket interface now if available and requested by
5792 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5793 delayed until open-network-stream is called (w32-has-winsock can
5794 also be used to dynamically load or reload winsock).
5796 Conveniently, init_environment is called before us, so
5797 PRELOAD_WINSOCK can be set in the registry. */
5799 /* Always initialize this correctly. */
5802 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5803 init_winsock (TRUE
);
5806 /* Initial preparation for subprocess support: replace our standard
5807 handles with non-inheritable versions. */
5810 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5811 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5812 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5814 parent
= GetCurrentProcess ();
5816 /* ignore errors when duplicating and closing; typically the
5817 handles will be invalid when running as a gui program. */
5818 DuplicateHandle (parent
,
5819 GetStdHandle (STD_INPUT_HANDLE
),
5824 DUPLICATE_SAME_ACCESS
);
5826 DuplicateHandle (parent
,
5827 GetStdHandle (STD_OUTPUT_HANDLE
),
5832 DUPLICATE_SAME_ACCESS
);
5834 DuplicateHandle (parent
,
5835 GetStdHandle (STD_ERROR_HANDLE
),
5840 DUPLICATE_SAME_ACCESS
);
5846 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5847 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5849 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5852 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5853 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5855 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5858 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5859 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5861 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5865 /* unfortunately, atexit depends on implementation of malloc */
5866 /* atexit (term_ntproc); */
5867 signal (SIGABRT
, term_ntproc
);
5869 /* determine which drives are fixed, for GetCachedVolumeInformation */
5871 /* GetDriveType must have trailing backslash. */
5872 char drive
[] = "A:\\";
5874 /* Loop over all possible drive letters */
5875 while (*drive
<= 'Z')
5877 /* Record if this drive letter refers to a fixed drive. */
5878 fixed_drives
[DRIVE_INDEX (*drive
)] =
5879 (GetDriveType (drive
) == DRIVE_FIXED
);
5884 /* Reset the volume info cache. */
5885 volume_cache
= NULL
;
5888 /* Check to see if Emacs has been installed correctly. */
5889 check_windows_init_file ();
5893 shutdown_handler ensures that buffers' autosave files are
5894 up to date when the user logs off, or the system shuts down.
5897 shutdown_handler (DWORD type
)
5899 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5900 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5901 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5902 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5904 /* Shut down cleanly, making sure autosave files are up to date. */
5905 shut_down_emacs (0, 0, Qnil
);
5908 /* Allow other handlers to handle this signal. */
5913 globals_of_w32 is used to initialize those global variables that
5914 must always be initialized on startup even when the global variable
5915 initialized is non zero (see the function main in emacs.c).
5918 globals_of_w32 (void)
5920 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5922 get_process_times_fn
= (GetProcessTimes_Proc
)
5923 GetProcAddress (kernel32
, "GetProcessTimes");
5925 g_b_init_is_windows_9x
= 0;
5926 g_b_init_open_process_token
= 0;
5927 g_b_init_get_token_information
= 0;
5928 g_b_init_lookup_account_sid
= 0;
5929 g_b_init_get_sid_identifier_authority
= 0;
5930 g_b_init_get_sid_sub_authority
= 0;
5931 g_b_init_get_sid_sub_authority_count
= 0;
5932 g_b_init_get_file_security
= 0;
5933 g_b_init_get_security_descriptor_owner
= 0;
5934 g_b_init_get_security_descriptor_group
= 0;
5935 g_b_init_is_valid_sid
= 0;
5936 g_b_init_create_toolhelp32_snapshot
= 0;
5937 g_b_init_process32_first
= 0;
5938 g_b_init_process32_next
= 0;
5939 g_b_init_open_thread_token
= 0;
5940 g_b_init_impersonate_self
= 0;
5941 g_b_init_revert_to_self
= 0;
5942 g_b_init_get_process_memory_info
= 0;
5943 g_b_init_get_process_working_set_size
= 0;
5944 g_b_init_global_memory_status
= 0;
5945 g_b_init_global_memory_status_ex
= 0;
5946 g_b_init_equal_sid
= 0;
5947 g_b_init_copy_sid
= 0;
5948 g_b_init_get_length_sid
= 0;
5949 g_b_init_get_native_system_info
= 0;
5950 g_b_init_get_system_times
= 0;
5951 num_of_processors
= 0;
5952 /* The following sets a handler for shutdown notifications for
5953 console apps. This actually applies to Emacs in both console and
5954 GUI modes, since we had to fool windows into thinking emacs is a
5955 console application to get console mode to work. */
5956 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
5958 /* "None" is the default group name on standalone workstations. */
5959 strcpy (dflt_group_name
, "None");
5962 /* For make-serial-process */
5964 serial_open (char *port
)
5970 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5971 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5972 if (hnd
== INVALID_HANDLE_VALUE
)
5973 error ("Could not open %s", port
);
5974 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5976 error ("Could not open %s", port
);
5980 error ("Could not create child process");
5982 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5983 fd_info
[ fd
].hnd
= hnd
;
5984 fd_info
[ fd
].flags
|=
5985 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5986 if (fd_info
[ fd
].cp
!= NULL
)
5988 error ("fd_info[fd = %d] is already in use", fd
);
5990 fd_info
[ fd
].cp
= cp
;
5991 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5992 if (cp
->ovl_read
.hEvent
== NULL
)
5993 error ("Could not create read event");
5994 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5995 if (cp
->ovl_write
.hEvent
== NULL
)
5996 error ("Could not create write event");
6001 /* For serial-process-configure */
6003 serial_configure (struct Lisp_Process
*p
,
6004 Lisp_Object contact
)
6006 Lisp_Object childp2
= Qnil
;
6007 Lisp_Object tem
= Qnil
;
6011 char summary
[4] = "???"; /* This usually becomes "8N1". */
6013 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6014 error ("Not a serial process");
6015 hnd
= fd_info
[ p
->outfd
].hnd
;
6017 childp2
= Fcopy_sequence (p
->childp
);
6019 /* Initialize timeouts for blocking read and blocking write. */
6020 if (!GetCommTimeouts (hnd
, &ct
))
6021 error ("GetCommTimeouts() failed");
6022 ct
.ReadIntervalTimeout
= 0;
6023 ct
.ReadTotalTimeoutMultiplier
= 0;
6024 ct
.ReadTotalTimeoutConstant
= 0;
6025 ct
.WriteTotalTimeoutMultiplier
= 0;
6026 ct
.WriteTotalTimeoutConstant
= 0;
6027 if (!SetCommTimeouts (hnd
, &ct
))
6028 error ("SetCommTimeouts() failed");
6029 /* Read port attributes and prepare default configuration. */
6030 memset (&dcb
, 0, sizeof (dcb
));
6031 dcb
.DCBlength
= sizeof (DCB
);
6032 if (!GetCommState (hnd
, &dcb
))
6033 error ("GetCommState() failed");
6036 dcb
.fAbortOnError
= FALSE
;
6037 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6042 /* Configure speed. */
6043 if (!NILP (Fplist_member (contact
, QCspeed
)))
6044 tem
= Fplist_get (contact
, QCspeed
);
6046 tem
= Fplist_get (p
->childp
, QCspeed
);
6048 dcb
.BaudRate
= XINT (tem
);
6049 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6051 /* Configure bytesize. */
6052 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6053 tem
= Fplist_get (contact
, QCbytesize
);
6055 tem
= Fplist_get (p
->childp
, QCbytesize
);
6057 tem
= make_number (8);
6059 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6060 error (":bytesize must be nil (8), 7, or 8");
6061 dcb
.ByteSize
= XINT (tem
);
6062 summary
[0] = XINT (tem
) + '0';
6063 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6065 /* Configure parity. */
6066 if (!NILP (Fplist_member (contact
, QCparity
)))
6067 tem
= Fplist_get (contact
, QCparity
);
6069 tem
= Fplist_get (p
->childp
, QCparity
);
6070 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6071 error (":parity must be nil (no parity), `even', or `odd'");
6072 dcb
.fParity
= FALSE
;
6073 dcb
.Parity
= NOPARITY
;
6074 dcb
.fErrorChar
= FALSE
;
6079 else if (EQ (tem
, Qeven
))
6083 dcb
.Parity
= EVENPARITY
;
6084 dcb
.fErrorChar
= TRUE
;
6086 else if (EQ (tem
, Qodd
))
6090 dcb
.Parity
= ODDPARITY
;
6091 dcb
.fErrorChar
= TRUE
;
6093 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6095 /* Configure stopbits. */
6096 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6097 tem
= Fplist_get (contact
, QCstopbits
);
6099 tem
= Fplist_get (p
->childp
, QCstopbits
);
6101 tem
= make_number (1);
6103 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6104 error (":stopbits must be nil (1 stopbit), 1, or 2");
6105 summary
[2] = XINT (tem
) + '0';
6106 if (XINT (tem
) == 1)
6107 dcb
.StopBits
= ONESTOPBIT
;
6108 else if (XINT (tem
) == 2)
6109 dcb
.StopBits
= TWOSTOPBITS
;
6110 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6112 /* Configure flowcontrol. */
6113 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6114 tem
= Fplist_get (contact
, QCflowcontrol
);
6116 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6117 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6118 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6119 dcb
.fOutxCtsFlow
= FALSE
;
6120 dcb
.fOutxDsrFlow
= FALSE
;
6121 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6122 dcb
.fDsrSensitivity
= FALSE
;
6123 dcb
.fTXContinueOnXoff
= FALSE
;
6126 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6127 dcb
.XonChar
= 17; /* Control-Q */
6128 dcb
.XoffChar
= 19; /* Control-S */
6131 /* Already configured. */
6133 else if (EQ (tem
, Qhw
))
6135 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6136 dcb
.fOutxCtsFlow
= TRUE
;
6138 else if (EQ (tem
, Qsw
))
6143 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6145 /* Activate configuration. */
6146 if (!SetCommState (hnd
, &dcb
))
6147 error ("SetCommState() failed");
6149 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6150 p
->childp
= childp2
;
6155 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6156 (do not change this comment) */