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 extern Lisp_Object QCport
, QCspeed
, QCprocess
;
145 extern Lisp_Object QCbytesize
, QCstopbits
, QCparity
, Qodd
, Qeven
;
146 extern Lisp_Object QCflowcontrol
, Qhw
, Qsw
, QCsummary
;
148 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
149 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
151 void globals_of_w32 (void);
152 static DWORD
get_rid (PSID
);
154 extern Lisp_Object Vw32_downcase_file_names
;
155 extern Lisp_Object Vw32_generate_fake_inodes
;
156 extern Lisp_Object Vw32_get_true_file_attributes
;
157 /* Defined in process.c for its own purpose. */
158 extern Lisp_Object Qlocal
;
160 extern int w32_num_mouse_buttons
;
163 /* Initialization states.
165 WARNING: If you add any more such variables for additional APIs,
166 you MUST add initialization for them to globals_of_w32
167 below. This is because these variables might get set
168 to non-NULL values during dumping, but the dumped Emacs
169 cannot reuse those values, because it could be run on a
170 different version of the OS, where API addresses are
172 static BOOL g_b_init_is_windows_9x
;
173 static BOOL g_b_init_open_process_token
;
174 static BOOL g_b_init_get_token_information
;
175 static BOOL g_b_init_lookup_account_sid
;
176 static BOOL g_b_init_get_sid_identifier_authority
;
177 static BOOL g_b_init_get_sid_sub_authority
;
178 static BOOL g_b_init_get_sid_sub_authority_count
;
179 static BOOL g_b_init_get_file_security
;
180 static BOOL g_b_init_get_security_descriptor_owner
;
181 static BOOL g_b_init_get_security_descriptor_group
;
182 static BOOL g_b_init_is_valid_sid
;
183 static BOOL g_b_init_create_toolhelp32_snapshot
;
184 static BOOL g_b_init_process32_first
;
185 static BOOL g_b_init_process32_next
;
186 static BOOL g_b_init_open_thread_token
;
187 static BOOL g_b_init_impersonate_self
;
188 static BOOL g_b_init_revert_to_self
;
189 static BOOL g_b_init_get_process_memory_info
;
190 static BOOL g_b_init_get_process_working_set_size
;
191 static BOOL g_b_init_global_memory_status
;
192 static BOOL g_b_init_global_memory_status_ex
;
193 static BOOL g_b_init_get_length_sid
;
194 static BOOL g_b_init_equal_sid
;
195 static BOOL g_b_init_copy_sid
;
196 static BOOL g_b_init_get_native_system_info
;
197 static BOOL g_b_init_get_system_times
;
200 BEGIN: Wrapper functions around OpenProcessToken
201 and other functions in advapi32.dll that are only
202 supported in Windows NT / 2k / XP
204 /* ** Function pointer typedefs ** */
205 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
206 HANDLE ProcessHandle
,
208 PHANDLE TokenHandle
);
209 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
211 TOKEN_INFORMATION_CLASS TokenInformationClass
,
212 LPVOID TokenInformation
,
213 DWORD TokenInformationLength
,
214 PDWORD ReturnLength
);
215 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
216 HANDLE process_handle
,
217 LPFILETIME creation_time
,
218 LPFILETIME exit_time
,
219 LPFILETIME kernel_time
,
220 LPFILETIME user_time
);
222 GetProcessTimes_Proc get_process_times_fn
= NULL
;
225 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
226 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
228 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
229 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
231 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
232 LPCTSTR lpSystemName
,
237 LPDWORD cbDomainName
,
238 PSID_NAME_USE peUse
);
239 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI
* GetSidIdentifierAuthority_Proc
) (
241 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
244 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
246 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
248 SECURITY_INFORMATION RequestedInformation
,
249 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
251 LPDWORD lpnLengthNeeded
);
252 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
253 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
255 LPBOOL lpbOwnerDefaulted
);
256 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
257 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
259 LPBOOL lpbGroupDefaulted
);
260 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
262 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
264 DWORD th32ProcessID
);
265 typedef BOOL (WINAPI
* Process32First_Proc
) (
267 LPPROCESSENTRY32 lppe
);
268 typedef BOOL (WINAPI
* Process32Next_Proc
) (
270 LPPROCESSENTRY32 lppe
);
271 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
275 PHANDLE TokenHandle
);
276 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
277 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
278 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
279 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
281 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
283 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
285 DWORD
* lpMinimumWorkingSetSize
,
286 DWORD
* lpMaximumWorkingSetSize
);
287 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
288 LPMEMORYSTATUS lpBuffer
);
289 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
290 LPMEMORY_STATUS_EX lpBuffer
);
291 typedef BOOL (WINAPI
* CopySid_Proc
) (
292 DWORD nDestinationSidLength
,
293 PSID pDestinationSid
,
295 typedef BOOL (WINAPI
* EqualSid_Proc
) (
298 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
300 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
301 LPSYSTEM_INFO lpSystemInfo
);
302 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
303 LPFILETIME lpIdleTime
,
304 LPFILETIME lpKernelTime
,
305 LPFILETIME lpUserTime
);
309 /* ** A utility function ** */
313 static BOOL s_b_ret
=0;
314 OSVERSIONINFO os_ver
;
315 if (g_b_init_is_windows_9x
== 0)
317 g_b_init_is_windows_9x
= 1;
318 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
319 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
320 if (GetVersionEx (&os_ver
))
322 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
328 /* Get total user and system times for get-internal-run-time.
329 Returns a list of three integers if the times are provided by the OS
330 (NT derivatives), otherwise it returns the result of current-time. */
332 w32_get_internal_run_time (void)
334 if (get_process_times_fn
)
336 FILETIME create
, exit
, kernel
, user
;
337 HANDLE proc
= GetCurrentProcess ();
338 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
340 LARGE_INTEGER user_int
, kernel_int
, total
;
342 user_int
.LowPart
= user
.dwLowDateTime
;
343 user_int
.HighPart
= user
.dwHighDateTime
;
344 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
345 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
346 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
347 /* FILETIME is 100 nanosecond increments, Emacs only wants
348 microsecond resolution. */
349 total
.QuadPart
/= 10;
350 microseconds
= total
.QuadPart
% 1000000;
351 total
.QuadPart
/= 1000000;
353 /* Sanity check to make sure we can represent the result. */
354 if (total
.HighPart
== 0)
356 int secs
= total
.LowPart
;
358 return list3 (make_number ((secs
>> 16) & 0xffff),
359 make_number (secs
& 0xffff),
360 make_number (microseconds
));
365 return Fcurrent_time ();
368 /* ** The wrapper functions ** */
370 BOOL WINAPI
open_process_token (
371 HANDLE ProcessHandle
,
375 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
376 HMODULE hm_advapi32
= NULL
;
377 if (is_windows_9x () == TRUE
)
381 if (g_b_init_open_process_token
== 0)
383 g_b_init_open_process_token
= 1;
384 hm_advapi32
= LoadLibrary ("Advapi32.dll");
385 s_pfn_Open_Process_Token
=
386 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
388 if (s_pfn_Open_Process_Token
== NULL
)
393 s_pfn_Open_Process_Token (
400 BOOL WINAPI
get_token_information (
402 TOKEN_INFORMATION_CLASS TokenInformationClass
,
403 LPVOID TokenInformation
,
404 DWORD TokenInformationLength
,
407 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
408 HMODULE hm_advapi32
= NULL
;
409 if (is_windows_9x () == TRUE
)
413 if (g_b_init_get_token_information
== 0)
415 g_b_init_get_token_information
= 1;
416 hm_advapi32
= LoadLibrary ("Advapi32.dll");
417 s_pfn_Get_Token_Information
=
418 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
420 if (s_pfn_Get_Token_Information
== NULL
)
425 s_pfn_Get_Token_Information (
427 TokenInformationClass
,
429 TokenInformationLength
,
434 BOOL WINAPI
lookup_account_sid (
435 LPCTSTR lpSystemName
,
440 LPDWORD cbDomainName
,
443 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
444 HMODULE hm_advapi32
= NULL
;
445 if (is_windows_9x () == TRUE
)
449 if (g_b_init_lookup_account_sid
== 0)
451 g_b_init_lookup_account_sid
= 1;
452 hm_advapi32
= LoadLibrary ("Advapi32.dll");
453 s_pfn_Lookup_Account_Sid
=
454 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
456 if (s_pfn_Lookup_Account_Sid
== NULL
)
461 s_pfn_Lookup_Account_Sid (
472 PSID_IDENTIFIER_AUTHORITY WINAPI
get_sid_identifier_authority (
475 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority
= NULL
;
476 HMODULE hm_advapi32
= NULL
;
477 if (is_windows_9x () == TRUE
)
481 if (g_b_init_get_sid_identifier_authority
== 0)
483 g_b_init_get_sid_identifier_authority
= 1;
484 hm_advapi32
= LoadLibrary ("Advapi32.dll");
485 s_pfn_Get_Sid_Identifier_Authority
=
486 (GetSidIdentifierAuthority_Proc
) GetProcAddress (
487 hm_advapi32
, "GetSidIdentifierAuthority");
489 if (s_pfn_Get_Sid_Identifier_Authority
== NULL
)
493 return (s_pfn_Get_Sid_Identifier_Authority (pSid
));
496 PDWORD WINAPI
get_sid_sub_authority (
500 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
501 static DWORD zero
= 0U;
502 HMODULE hm_advapi32
= NULL
;
503 if (is_windows_9x () == TRUE
)
507 if (g_b_init_get_sid_sub_authority
== 0)
509 g_b_init_get_sid_sub_authority
= 1;
510 hm_advapi32
= LoadLibrary ("Advapi32.dll");
511 s_pfn_Get_Sid_Sub_Authority
=
512 (GetSidSubAuthority_Proc
) GetProcAddress (
513 hm_advapi32
, "GetSidSubAuthority");
515 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
519 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
522 PUCHAR WINAPI
get_sid_sub_authority_count (
525 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
526 static UCHAR zero
= 0U;
527 HMODULE hm_advapi32
= NULL
;
528 if (is_windows_9x () == TRUE
)
532 if (g_b_init_get_sid_sub_authority_count
== 0)
534 g_b_init_get_sid_sub_authority_count
= 1;
535 hm_advapi32
= LoadLibrary ("Advapi32.dll");
536 s_pfn_Get_Sid_Sub_Authority_Count
=
537 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
538 hm_advapi32
, "GetSidSubAuthorityCount");
540 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
544 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
547 BOOL WINAPI
get_file_security (
549 SECURITY_INFORMATION RequestedInformation
,
550 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
552 LPDWORD lpnLengthNeeded
)
554 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
555 HMODULE hm_advapi32
= NULL
;
556 if (is_windows_9x () == TRUE
)
560 if (g_b_init_get_file_security
== 0)
562 g_b_init_get_file_security
= 1;
563 hm_advapi32
= LoadLibrary ("Advapi32.dll");
564 s_pfn_Get_File_Security
=
565 (GetFileSecurity_Proc
) GetProcAddress (
566 hm_advapi32
, GetFileSecurity_Name
);
568 if (s_pfn_Get_File_Security
== NULL
)
572 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
573 pSecurityDescriptor
, nLength
,
577 BOOL WINAPI
get_security_descriptor_owner (
578 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
580 LPBOOL lpbOwnerDefaulted
)
582 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
583 HMODULE hm_advapi32
= NULL
;
584 if (is_windows_9x () == TRUE
)
588 if (g_b_init_get_security_descriptor_owner
== 0)
590 g_b_init_get_security_descriptor_owner
= 1;
591 hm_advapi32
= LoadLibrary ("Advapi32.dll");
592 s_pfn_Get_Security_Descriptor_Owner
=
593 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
594 hm_advapi32
, "GetSecurityDescriptorOwner");
596 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
600 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
604 BOOL WINAPI
get_security_descriptor_group (
605 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
607 LPBOOL lpbGroupDefaulted
)
609 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
610 HMODULE hm_advapi32
= NULL
;
611 if (is_windows_9x () == TRUE
)
615 if (g_b_init_get_security_descriptor_group
== 0)
617 g_b_init_get_security_descriptor_group
= 1;
618 hm_advapi32
= LoadLibrary ("Advapi32.dll");
619 s_pfn_Get_Security_Descriptor_Group
=
620 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
621 hm_advapi32
, "GetSecurityDescriptorGroup");
623 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
627 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
631 BOOL WINAPI
is_valid_sid (
634 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
635 HMODULE hm_advapi32
= NULL
;
636 if (is_windows_9x () == TRUE
)
640 if (g_b_init_is_valid_sid
== 0)
642 g_b_init_is_valid_sid
= 1;
643 hm_advapi32
= LoadLibrary ("Advapi32.dll");
645 (IsValidSid_Proc
) GetProcAddress (
646 hm_advapi32
, "IsValidSid");
648 if (s_pfn_Is_Valid_Sid
== NULL
)
652 return (s_pfn_Is_Valid_Sid (sid
));
655 BOOL WINAPI
equal_sid (
659 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
660 HMODULE hm_advapi32
= NULL
;
661 if (is_windows_9x () == TRUE
)
665 if (g_b_init_equal_sid
== 0)
667 g_b_init_equal_sid
= 1;
668 hm_advapi32
= LoadLibrary ("Advapi32.dll");
670 (EqualSid_Proc
) GetProcAddress (
671 hm_advapi32
, "EqualSid");
673 if (s_pfn_Equal_Sid
== NULL
)
677 return (s_pfn_Equal_Sid (sid1
, sid2
));
680 DWORD WINAPI
get_length_sid (
683 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
684 HMODULE hm_advapi32
= NULL
;
685 if (is_windows_9x () == TRUE
)
689 if (g_b_init_get_length_sid
== 0)
691 g_b_init_get_length_sid
= 1;
692 hm_advapi32
= LoadLibrary ("Advapi32.dll");
693 s_pfn_Get_Length_Sid
=
694 (GetLengthSid_Proc
) GetProcAddress (
695 hm_advapi32
, "GetLengthSid");
697 if (s_pfn_Get_Length_Sid
== NULL
)
701 return (s_pfn_Get_Length_Sid (sid
));
704 BOOL WINAPI
copy_sid (
709 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
710 HMODULE hm_advapi32
= NULL
;
711 if (is_windows_9x () == TRUE
)
715 if (g_b_init_copy_sid
== 0)
717 g_b_init_copy_sid
= 1;
718 hm_advapi32
= LoadLibrary ("Advapi32.dll");
720 (CopySid_Proc
) GetProcAddress (
721 hm_advapi32
, "CopySid");
723 if (s_pfn_Copy_Sid
== NULL
)
727 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
731 END: Wrapper functions around OpenProcessToken
732 and other functions in advapi32.dll that are only
733 supported in Windows NT / 2k / XP
736 void WINAPI
get_native_system_info (
737 LPSYSTEM_INFO lpSystemInfo
)
739 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
740 if (is_windows_9x () != TRUE
)
742 if (g_b_init_get_native_system_info
== 0)
744 g_b_init_get_native_system_info
= 1;
745 s_pfn_Get_Native_System_Info
=
746 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
747 "GetNativeSystemInfo");
749 if (s_pfn_Get_Native_System_Info
!= NULL
)
750 s_pfn_Get_Native_System_Info (lpSystemInfo
);
753 lpSystemInfo
->dwNumberOfProcessors
= -1;
756 BOOL WINAPI
get_system_times (
757 LPFILETIME lpIdleTime
,
758 LPFILETIME lpKernelTime
,
759 LPFILETIME lpUserTime
)
761 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
762 if (is_windows_9x () == TRUE
)
766 if (g_b_init_get_system_times
== 0)
768 g_b_init_get_system_times
= 1;
769 s_pfn_Get_System_times
=
770 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
773 if (s_pfn_Get_System_times
== NULL
)
775 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
778 /* Equivalent of strerror for W32 error codes. */
780 w32_strerror (int error_no
)
782 static char buf
[500];
785 error_no
= GetLastError ();
788 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
790 0, /* choose most suitable language */
791 buf
, sizeof (buf
), NULL
))
792 sprintf (buf
, "w32 error %u", error_no
);
796 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
797 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
799 This is called from alloc.c:valid_pointer_p. */
801 w32_valid_pointer_p (void *p
, int size
)
804 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
808 unsigned char *buf
= alloca (size
);
809 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
818 static char startup_dir
[MAXPATHLEN
];
820 /* Get the current working directory. */
825 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
829 /* Emacs doesn't actually change directory itself, and we want to
830 force our real wd to be where emacs.exe is to avoid unnecessary
831 conflicts when trying to rename or delete directories. */
832 strcpy (dir
, startup_dir
);
838 /* Emulate gethostname. */
840 gethostname (char *buffer
, int size
)
842 /* NT only allows small host names, so the buffer is
843 certainly large enough. */
844 return !GetComputerName (buffer
, &size
);
846 #endif /* HAVE_SOCKETS */
848 /* Emulate getloadavg. */
857 /* Number of processors on this machine. */
858 static unsigned num_of_processors
;
860 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
861 static struct load_sample samples
[16*60];
862 static int first_idx
= -1, last_idx
= -1;
863 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
868 int next_idx
= from
+ 1;
870 if (next_idx
>= max_idx
)
879 int prev_idx
= from
- 1;
882 prev_idx
= max_idx
- 1;
888 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
891 FILETIME ft_idle
, ft_user
, ft_kernel
;
893 /* Initialize the number of processors on this machine. */
894 if (num_of_processors
<= 0)
896 get_native_system_info (&sysinfo
);
897 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
898 if (num_of_processors
<= 0)
900 GetSystemInfo (&sysinfo
);
901 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
903 if (num_of_processors
<= 0)
904 num_of_processors
= 1;
907 /* TODO: Take into account threads that are ready to run, by
908 sampling the "\System\Processor Queue Length" performance
909 counter. The code below accounts only for threads that are
912 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
914 ULARGE_INTEGER uidle
, ukernel
, uuser
;
916 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
917 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
918 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
919 *idle
= uidle
.QuadPart
;
920 *kernel
= ukernel
.QuadPart
;
921 *user
= uuser
.QuadPart
;
931 /* Produce the load average for a given time interval, using the
932 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
933 1-minute, 5-minute, or 15-minute average, respectively. */
937 double retval
= -1.0;
940 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
941 time_t now
= samples
[last_idx
].sample_time
;
943 if (first_idx
!= last_idx
)
945 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
947 tdiff
= difftime (now
, samples
[idx
].sample_time
);
948 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
951 samples
[last_idx
].kernel
+ samples
[last_idx
].user
952 - (samples
[idx
].kernel
+ samples
[idx
].user
);
953 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
955 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
958 if (idx
== first_idx
)
967 getloadavg (double loadavg
[], int nelem
)
970 ULONGLONG idle
, kernel
, user
;
971 time_t now
= time (NULL
);
973 /* Store another sample. We ignore samples that are less than 1 sec
975 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
977 sample_system_load (&idle
, &kernel
, &user
);
978 last_idx
= buf_next (last_idx
);
979 samples
[last_idx
].sample_time
= now
;
980 samples
[last_idx
].idle
= idle
;
981 samples
[last_idx
].kernel
= kernel
;
982 samples
[last_idx
].user
= user
;
983 /* If the buffer has more that 15 min worth of samples, discard
986 first_idx
= last_idx
;
987 while (first_idx
!= last_idx
988 && (difftime (now
, samples
[first_idx
].sample_time
)
989 >= 15.0*60 + 2*DBL_EPSILON
*now
))
990 first_idx
= buf_next (first_idx
);
993 for (elem
= 0; elem
< nelem
; elem
++)
995 double avg
= getavg (elem
);
1005 /* Emulate getpwuid, getpwnam and others. */
1007 #define PASSWD_FIELD_SIZE 256
1009 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1010 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1011 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1012 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
1013 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
1015 static struct passwd dflt_passwd
=
1027 static char dflt_group_name
[GNLEN
+1];
1029 static struct group dflt_group
=
1031 /* When group information is not available, we return this as the
1032 group for all files. */
1040 return dflt_passwd
.pw_uid
;
1046 /* I could imagine arguing for checking to see whether the user is
1047 in the Administrators group and returning a UID of 0 for that
1048 case, but I don't know how wise that would be in the long run. */
1055 return dflt_passwd
.pw_gid
;
1065 getpwuid (unsigned uid
)
1067 if (uid
== dflt_passwd
.pw_uid
)
1068 return &dflt_passwd
;
1073 getgrgid (gid_t gid
)
1079 getpwnam (char *name
)
1083 pw
= getpwuid (getuid ());
1087 if (xstrcasecmp (name
, pw
->pw_name
))
1094 init_user_info (void)
1096 /* Find the user's real name by opening the process token and
1097 looking up the name associated with the user-sid in that token.
1099 Use the relative portion of the identifier authority value from
1100 the user-sid as the user id value (same for group id using the
1101 primary group sid from the process token). */
1103 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1104 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1105 DWORD glength
= sizeof (gname
);
1106 HANDLE token
= NULL
;
1107 SID_NAME_USE user_type
;
1108 unsigned char *buf
= NULL
;
1110 TOKEN_USER user_token
;
1111 TOKEN_PRIMARY_GROUP group_token
;
1114 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1117 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1118 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1120 buf
= xmalloc (blen
);
1121 result
= get_token_information (token
, TokenUser
,
1122 (LPVOID
)buf
, blen
, &needed
);
1125 memcpy (&user_token
, buf
, sizeof (user_token
));
1126 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1128 domain
, &dlength
, &user_type
);
1136 strcpy (dflt_passwd
.pw_name
, uname
);
1137 /* Determine a reasonable uid value. */
1138 if (xstrcasecmp ("administrator", uname
) == 0)
1140 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1141 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1145 /* Use the last sub-authority value of the RID, the relative
1146 portion of the SID, as user/group ID. */
1147 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1149 /* Get group id and name. */
1150 result
= get_token_information (token
, TokenPrimaryGroup
,
1151 (LPVOID
)buf
, blen
, &needed
);
1152 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1154 buf
= xrealloc (buf
, blen
= needed
);
1155 result
= get_token_information (token
, TokenPrimaryGroup
,
1156 (LPVOID
)buf
, blen
, &needed
);
1160 memcpy (&group_token
, buf
, sizeof (group_token
));
1161 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1162 dlength
= sizeof (domain
);
1163 /* If we can get at the real Primary Group name, use that.
1164 Otherwise, the default group name was already set to
1165 "None" in globals_of_w32. */
1166 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1167 gname
, &glength
, NULL
, &dlength
,
1169 strcpy (dflt_group_name
, gname
);
1172 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1175 /* If security calls are not supported (presumably because we
1176 are running under Windows 9X), fallback to this: */
1177 else if (GetUserName (uname
, &ulength
))
1179 strcpy (dflt_passwd
.pw_name
, uname
);
1180 if (xstrcasecmp ("administrator", uname
) == 0)
1181 dflt_passwd
.pw_uid
= 0;
1183 dflt_passwd
.pw_uid
= 123;
1184 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1188 strcpy (dflt_passwd
.pw_name
, "unknown");
1189 dflt_passwd
.pw_uid
= 123;
1190 dflt_passwd
.pw_gid
= 123;
1192 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1194 /* Ensure HOME and SHELL are defined. */
1195 if (getenv ("HOME") == NULL
)
1197 if (getenv ("SHELL") == NULL
)
1200 /* Set dir and shell from environment variables. */
1201 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1202 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1206 CloseHandle (token
);
1212 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1213 return ((rand () << 15) | rand ());
1223 /* Normalize filename by converting all path separators to
1224 the specified separator. Also conditionally convert upper
1225 case path name components to lower case. */
1228 normalize_filename (register char *fp
, char path_sep
)
1233 /* Always lower-case drive letters a-z, even if the filesystem
1234 preserves case in filenames.
1235 This is so filenames can be compared by string comparison
1236 functions that are case-sensitive. Even case-preserving filesystems
1237 do not distinguish case in drive letters. */
1238 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1244 if (NILP (Vw32_downcase_file_names
))
1248 if (*fp
== '/' || *fp
== '\\')
1255 sep
= path_sep
; /* convert to this path separator */
1256 elem
= fp
; /* start of current path element */
1259 if (*fp
>= 'a' && *fp
<= 'z')
1260 elem
= 0; /* don't convert this element */
1262 if (*fp
== 0 || *fp
== ':')
1264 sep
= *fp
; /* restore current separator (or 0) */
1265 *fp
= '/'; /* after conversion of this element */
1268 if (*fp
== '/' || *fp
== '\\')
1270 if (elem
&& elem
!= fp
)
1272 *fp
= 0; /* temporary end of string */
1273 _strlwr (elem
); /* while we convert to lower case */
1275 *fp
= sep
; /* convert (or restore) path separator */
1276 elem
= fp
+ 1; /* next element starts after separator */
1282 /* Destructively turn backslashes into slashes. */
1284 dostounix_filename (register char *p
)
1286 normalize_filename (p
, '/');
1289 /* Destructively turn slashes into backslashes. */
1291 unixtodos_filename (register char *p
)
1293 normalize_filename (p
, '\\');
1296 /* Remove all CR's that are followed by a LF.
1297 (From msdos.c...probably should figure out a way to share it,
1298 although this code isn't going to ever change.) */
1300 crlf_to_lf (register int n
, register unsigned char *buf
)
1302 unsigned char *np
= buf
;
1303 unsigned char *startp
= buf
;
1304 unsigned char *endp
= buf
+ n
;
1308 while (buf
< endp
- 1)
1312 if (*(++buf
) != 0x0a)
1323 /* Parse the root part of file name, if present. Return length and
1324 optionally store pointer to char after root. */
1326 parse_root (char * name
, char ** pPath
)
1328 char * start
= name
;
1333 /* find the root name of the volume if given */
1334 if (isalpha (name
[0]) && name
[1] == ':')
1336 /* skip past drive specifier */
1338 if (IS_DIRECTORY_SEP (name
[0]))
1341 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1347 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1352 if (IS_DIRECTORY_SEP (name
[0]))
1359 return name
- start
;
1362 /* Get long base name for name; name is assumed to be absolute. */
1364 get_long_basename (char * name
, char * buf
, int size
)
1366 WIN32_FIND_DATA find_data
;
1370 /* must be valid filename, no wild cards or other invalid characters */
1371 if (_mbspbrk (name
, "*?|<>\""))
1374 dir_handle
= FindFirstFile (name
, &find_data
);
1375 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1377 if ((len
= strlen (find_data
.cFileName
)) < size
)
1378 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1381 FindClose (dir_handle
);
1386 /* Get long name for file, if possible (assumed to be absolute). */
1388 w32_get_long_filename (char * name
, char * buf
, int size
)
1393 char full
[ MAX_PATH
];
1396 len
= strlen (name
);
1397 if (len
>= MAX_PATH
)
1400 /* Use local copy for destructive modification. */
1401 memcpy (full
, name
, len
+1);
1402 unixtodos_filename (full
);
1404 /* Copy root part verbatim. */
1405 len
= parse_root (full
, &p
);
1406 memcpy (o
, full
, len
);
1411 while (p
!= NULL
&& *p
)
1414 p
= strchr (q
, '\\');
1416 len
= get_long_basename (full
, o
, size
);
1439 is_unc_volume (const char *filename
)
1441 const char *ptr
= filename
;
1443 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1446 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1452 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1455 sigsetmask (int signal_mask
)
1473 sigunblock (int sig
)
1479 sigemptyset (sigset_t
*set
)
1485 sigaddset (sigset_t
*set
, int signo
)
1491 sigfillset (sigset_t
*set
)
1497 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1503 setpgrp (int pid
, int gid
)
1514 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1517 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1520 HKEY hrootkey
= NULL
;
1523 /* Check both the current user and the local machine to see if
1524 we have any resources. */
1526 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1530 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1531 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1532 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1534 RegCloseKey (hrootkey
);
1540 RegCloseKey (hrootkey
);
1543 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1547 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1548 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1549 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1551 RegCloseKey (hrootkey
);
1557 RegCloseKey (hrootkey
);
1563 char *get_emacs_configuration (void);
1564 extern Lisp_Object Vsystem_configuration
;
1567 init_environment (char ** argv
)
1569 static const char * const tempdirs
[] = {
1570 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1575 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1577 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1578 temporary files and assume "/tmp" if $TMPDIR is unset, which
1579 will break on DOS/Windows. Refuse to work if we cannot find
1580 a directory, not even "c:/", usable for that purpose. */
1581 for (i
= 0; i
< imax
; i
++)
1583 const char *tmp
= tempdirs
[i
];
1586 tmp
= getenv (tmp
+ 1);
1587 /* Note that `access' can lie to us if the directory resides on a
1588 read-only filesystem, like CD-ROM or a write-protected floppy.
1589 The only way to be really sure is to actually create a file and
1590 see if it succeeds. But I think that's too much to ask. */
1591 if (tmp
&& _access (tmp
, D_OK
) == 0)
1593 char * var
= alloca (strlen (tmp
) + 8);
1594 sprintf (var
, "TMPDIR=%s", tmp
);
1595 _putenv (strdup (var
));
1602 Fcons (build_string ("no usable temporary directories found!!"),
1604 "While setting TMPDIR: ");
1606 /* Check for environment variables and use registry settings if they
1607 don't exist. Fallback on default values where applicable. */
1612 char locale_name
[32];
1613 struct stat ignored
;
1614 char default_home
[MAX_PATH
];
1616 static const struct env_entry
1623 {"PRELOAD_WINSOCK", NULL
},
1624 {"emacs_dir", "C:/emacs"},
1625 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1626 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1627 {"EMACSDATA", "%emacs_dir%/etc"},
1628 {"EMACSPATH", "%emacs_dir%/bin"},
1629 /* We no longer set INFOPATH because Info-default-directory-list
1631 /* {"INFOPATH", "%emacs_dir%/info"}, */
1632 {"EMACSDOC", "%emacs_dir%/etc"},
1637 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1639 /* We need to copy dflt_envvars[] and work on the copy because we
1640 don't want the dumped Emacs to inherit the values of
1641 environment variables we saw during dumping (which could be on
1642 a different system). The defaults above must be left intact. */
1643 struct env_entry env_vars
[N_ENV_VARS
];
1645 for (i
= 0; i
< N_ENV_VARS
; i
++)
1646 env_vars
[i
] = dflt_envvars
[i
];
1648 /* For backwards compatibility, check if a .emacs file exists in C:/
1649 If not, then we can try to default to the appdata directory under the
1650 user's profile, which is more likely to be writable. */
1651 if (stat ("C:/.emacs", &ignored
) < 0)
1653 HRESULT profile_result
;
1654 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1655 of Windows 95 and NT4 that have not been updated to include
1657 ShGetFolderPath_fn get_folder_path
;
1658 get_folder_path
= (ShGetFolderPath_fn
)
1659 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1661 if (get_folder_path
!= NULL
)
1663 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1666 /* If we can't get the appdata dir, revert to old behavior. */
1667 if (profile_result
== S_OK
)
1668 env_vars
[0].def_value
= default_home
;
1672 /* Get default locale info and use it for LANG. */
1673 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1674 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1675 locale_name
, sizeof (locale_name
)))
1677 for (i
= 0; i
< N_ENV_VARS
; i
++)
1679 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1681 env_vars
[i
].def_value
= locale_name
;
1687 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1689 /* Treat emacs_dir specially: set it unconditionally based on our
1690 location, if it appears that we are running from the bin subdir
1691 of a standard installation. */
1694 char modname
[MAX_PATH
];
1696 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1698 if ((p
= strrchr (modname
, '\\')) == NULL
)
1702 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1704 char buf
[SET_ENV_BUF_SIZE
];
1707 for (p
= modname
; *p
; p
++)
1708 if (*p
== '\\') *p
= '/';
1710 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1711 _putenv (strdup (buf
));
1713 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1715 /* FIXME: should use substring of get_emacs_configuration ().
1716 But I don't think the Windows build supports alpha, mips etc
1717 anymore, so have taken the easy option for now. */
1718 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1721 p
= strrchr (modname
, '\\');
1725 p
= strrchr (modname
, '\\');
1726 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1728 char buf
[SET_ENV_BUF_SIZE
];
1731 for (p
= modname
; *p
; p
++)
1732 if (*p
== '\\') *p
= '/';
1734 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1735 _putenv (strdup (buf
));
1741 for (i
= 0; i
< N_ENV_VARS
; i
++)
1743 if (!getenv (env_vars
[i
].name
))
1747 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1748 /* Also ignore empty environment variables. */
1752 lpval
= env_vars
[i
].def_value
;
1753 dwType
= REG_EXPAND_SZ
;
1759 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1761 if (dwType
== REG_EXPAND_SZ
)
1762 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1763 else if (dwType
== REG_SZ
)
1764 strcpy (buf1
, lpval
);
1765 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1767 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1769 _putenv (strdup (buf2
));
1779 /* Rebuild system configuration to reflect invoking system. */
1780 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1782 /* Another special case: on NT, the PATH variable is actually named
1783 "Path" although cmd.exe (perhaps NT itself) arranges for
1784 environment variable lookup and setting to be case insensitive.
1785 However, Emacs assumes a fully case sensitive environment, so we
1786 need to change "Path" to "PATH" to match the expectations of
1787 various elisp packages. We do this by the sneaky method of
1788 modifying the string in the C runtime environ entry.
1790 The same applies to COMSPEC. */
1794 for (envp
= environ
; *envp
; envp
++)
1795 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1796 memcpy (*envp
, "PATH=", 5);
1797 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1798 memcpy (*envp
, "COMSPEC=", 8);
1801 /* Remember the initial working directory for getwd, then make the
1802 real wd be the location of emacs.exe to avoid conflicts when
1803 renaming or deleting directories. (We also don't call chdir when
1804 running subprocesses for the same reason.) */
1805 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1810 static char modname
[MAX_PATH
];
1812 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1814 if ((p
= strrchr (modname
, '\\')) == NULL
)
1818 SetCurrentDirectory (modname
);
1820 /* Ensure argv[0] has the full path to Emacs. */
1825 /* Determine if there is a middle mouse button, to allow parse_button
1826 to decide whether right mouse events should be mouse-2 or
1828 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1834 emacs_root_dir (void)
1836 static char root_dir
[FILENAME_MAX
];
1839 p
= getenv ("emacs_dir");
1842 strcpy (root_dir
, p
);
1843 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1844 dostounix_filename (root_dir
);
1848 /* We don't have scripts to automatically determine the system configuration
1849 for Emacs before it's compiled, and we don't want to have to make the
1850 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1854 get_emacs_configuration (void)
1856 char *arch
, *oem
, *os
;
1858 static char configuration_buffer
[32];
1860 /* Determine the processor type. */
1861 switch (get_processor_type ())
1864 #ifdef PROCESSOR_INTEL_386
1865 case PROCESSOR_INTEL_386
:
1866 case PROCESSOR_INTEL_486
:
1867 case PROCESSOR_INTEL_PENTIUM
:
1872 #ifdef PROCESSOR_MIPS_R2000
1873 case PROCESSOR_MIPS_R2000
:
1874 case PROCESSOR_MIPS_R3000
:
1875 case PROCESSOR_MIPS_R4000
:
1880 #ifdef PROCESSOR_ALPHA_21064
1881 case PROCESSOR_ALPHA_21064
:
1891 /* Use the OEM field to reflect the compiler/library combination. */
1893 #define COMPILER_NAME "msvc"
1896 #define COMPILER_NAME "mingw"
1898 #define COMPILER_NAME "unknown"
1901 oem
= COMPILER_NAME
;
1903 switch (osinfo_cache
.dwPlatformId
) {
1904 case VER_PLATFORM_WIN32_NT
:
1906 build_num
= osinfo_cache
.dwBuildNumber
;
1908 case VER_PLATFORM_WIN32_WINDOWS
:
1909 if (osinfo_cache
.dwMinorVersion
== 0) {
1914 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1916 case VER_PLATFORM_WIN32s
:
1917 /* Not supported, should not happen. */
1919 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1927 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1928 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1929 get_w32_major_version (), get_w32_minor_version (), build_num
);
1931 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1934 return configuration_buffer
;
1938 get_emacs_configuration_options (void)
1940 static char options_buffer
[256];
1942 /* Work out the effective configure options for this build. */
1944 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1947 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1949 #define COMPILER_VERSION ""
1953 sprintf (options_buffer
, COMPILER_VERSION
);
1955 strcat (options_buffer
, " --no-opt");
1958 strcat (options_buffer
, " --cflags");
1959 strcat (options_buffer
, USER_CFLAGS
);
1962 strcat (options_buffer
, " --ldflags");
1963 strcat (options_buffer
, USER_LDFLAGS
);
1965 return options_buffer
;
1969 #include <sys/timeb.h>
1971 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1973 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1978 tv
->tv_sec
= tb
.time
;
1979 tv
->tv_usec
= tb
.millitm
* 1000L;
1982 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1983 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1987 /* ------------------------------------------------------------------------- */
1988 /* IO support and wrapper functions for W32 API. */
1989 /* ------------------------------------------------------------------------- */
1991 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1992 on network directories, so we handle that case here.
1993 (Ulrich Leodolter, 1/11/95). */
1995 sys_ctime (const time_t *t
)
1997 char *str
= (char *) ctime (t
);
1998 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2001 /* Emulate sleep...we could have done this with a define, but that
2002 would necessitate including windows.h in the files that used it.
2003 This is much easier. */
2005 sys_sleep (int seconds
)
2007 Sleep (seconds
* 1000);
2010 /* Internal MSVC functions for low-level descriptor munging */
2011 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2012 extern int __cdecl
_free_osfhnd (int fd
);
2014 /* parallel array of private info on file handles */
2015 filedesc fd_info
[ MAXDESC
];
2017 typedef struct volume_info_data
{
2018 struct volume_info_data
* next
;
2020 /* time when info was obtained */
2023 /* actual volume info */
2032 /* Global referenced by various functions. */
2033 static volume_info_data volume_info
;
2035 /* Vector to indicate which drives are local and fixed (for which cached
2036 data never expires). */
2037 static BOOL fixed_drives
[26];
2039 /* Consider cached volume information to be stale if older than 10s,
2040 at least for non-local drives. Info for fixed drives is never stale. */
2041 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2042 #define VOLINFO_STILL_VALID( root_dir, info ) \
2043 ( ( isalpha (root_dir[0]) && \
2044 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2045 || GetTickCount () - info->timestamp < 10000 )
2047 /* Cache support functions. */
2049 /* Simple linked list with linear search is sufficient. */
2050 static volume_info_data
*volume_cache
= NULL
;
2052 static volume_info_data
*
2053 lookup_volume_info (char * root_dir
)
2055 volume_info_data
* info
;
2057 for (info
= volume_cache
; info
; info
= info
->next
)
2058 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2064 add_volume_info (char * root_dir
, volume_info_data
* info
)
2066 info
->root_dir
= xstrdup (root_dir
);
2067 info
->next
= volume_cache
;
2068 volume_cache
= info
;
2072 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2073 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2074 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2076 GetCachedVolumeInformation (char * root_dir
)
2078 volume_info_data
* info
;
2079 char default_root
[ MAX_PATH
];
2081 /* NULL for root_dir means use root from current directory. */
2082 if (root_dir
== NULL
)
2084 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2086 parse_root (default_root
, &root_dir
);
2088 root_dir
= default_root
;
2091 /* Local fixed drives can be cached permanently. Removable drives
2092 cannot be cached permanently, since the volume name and serial
2093 number (if nothing else) can change. Remote drives should be
2094 treated as if they are removable, since there is no sure way to
2095 tell whether they are or not. Also, the UNC association of drive
2096 letters mapped to remote volumes can be changed at any time (even
2097 by other processes) without notice.
2099 As a compromise, so we can benefit from caching info for remote
2100 volumes, we use a simple expiry mechanism to invalidate cache
2101 entries that are more than ten seconds old. */
2104 /* No point doing this, because WNetGetConnection is even slower than
2105 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2106 GetDriveType is about the only call of this type which does not
2107 involve network access, and so is extremely quick). */
2109 /* Map drive letter to UNC if remote. */
2110 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2112 char remote_name
[ 256 ];
2113 char drive
[3] = { root_dir
[0], ':' };
2115 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2117 /* do something */ ;
2121 info
= lookup_volume_info (root_dir
);
2123 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2131 /* Info is not cached, or is stale. */
2132 if (!GetVolumeInformation (root_dir
,
2133 name
, sizeof (name
),
2137 type
, sizeof (type
)))
2140 /* Cache the volume information for future use, overwriting existing
2141 entry if present. */
2144 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2145 add_volume_info (root_dir
, info
);
2153 info
->name
= xstrdup (name
);
2154 info
->serialnum
= serialnum
;
2155 info
->maxcomp
= maxcomp
;
2156 info
->flags
= flags
;
2157 info
->type
= xstrdup (type
);
2158 info
->timestamp
= GetTickCount ();
2164 /* Get information on the volume where name is held; set path pointer to
2165 start of pathname in name (past UNC header\volume header if present). */
2167 get_volume_info (const char * name
, const char ** pPath
)
2169 char temp
[MAX_PATH
];
2170 char *rootname
= NULL
; /* default to current volume */
2171 volume_info_data
* info
;
2176 /* find the root name of the volume if given */
2177 if (isalpha (name
[0]) && name
[1] == ':')
2185 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2192 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2205 info
= GetCachedVolumeInformation (rootname
);
2208 /* Set global referenced by other functions. */
2209 volume_info
= *info
;
2215 /* Determine if volume is FAT format (ie. only supports short 8.3
2216 names); also set path pointer to start of pathname in name. */
2218 is_fat_volume (const char * name
, const char ** pPath
)
2220 if (get_volume_info (name
, pPath
))
2221 return (volume_info
.maxcomp
== 12);
2225 /* Map filename to a valid 8.3 name if necessary. */
2227 map_w32_filename (const char * name
, const char ** pPath
)
2229 static char shortname
[MAX_PATH
];
2230 char * str
= shortname
;
2233 const char * save_name
= name
;
2235 if (strlen (name
) >= MAX_PATH
)
2237 /* Return a filename which will cause callers to fail. */
2238 strcpy (shortname
, "?");
2242 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2244 register int left
= 8; /* maximum number of chars in part */
2245 register int extn
= 0; /* extension added? */
2246 register int dots
= 2; /* maximum number of dots allowed */
2249 *str
++ = *name
++; /* skip past UNC header */
2251 while ((c
= *name
++))
2258 extn
= 0; /* reset extension flags */
2259 dots
= 2; /* max 2 dots */
2260 left
= 8; /* max length 8 for main part */
2264 extn
= 0; /* reset extension flags */
2265 dots
= 2; /* max 2 dots */
2266 left
= 8; /* max length 8 for main part */
2271 /* Convert path components of the form .xxx to _xxx,
2272 but leave . and .. as they are. This allows .emacs
2273 to be read as _emacs, for example. */
2277 IS_DIRECTORY_SEP (*name
))
2292 extn
= 1; /* we've got an extension */
2293 left
= 3; /* 3 chars in extension */
2297 /* any embedded dots after the first are converted to _ */
2302 case '#': /* don't lose these, they're important */
2304 str
[-1] = c
; /* replace last character of part */
2309 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2311 dots
= 0; /* started a path component */
2320 strcpy (shortname
, name
);
2321 unixtodos_filename (shortname
);
2325 *pPath
= shortname
+ (path
- save_name
);
2331 is_exec (const char * name
)
2333 char * p
= strrchr (name
, '.');
2336 && (xstrcasecmp (p
, ".exe") == 0 ||
2337 xstrcasecmp (p
, ".com") == 0 ||
2338 xstrcasecmp (p
, ".bat") == 0 ||
2339 xstrcasecmp (p
, ".cmd") == 0));
2342 /* Emulate the Unix directory procedures opendir, closedir,
2343 and readdir. We can't use the procedures supplied in sysdep.c,
2344 so we provide them here. */
2346 struct direct dir_static
; /* simulated directory contents */
2347 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2348 static int dir_is_fat
;
2349 static char dir_pathname
[MAXPATHLEN
+1];
2350 static WIN32_FIND_DATA dir_find_data
;
2352 /* Support shares on a network resource as subdirectories of a read-only
2354 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2355 HANDLE
open_unc_volume (const char *);
2356 char *read_unc_volume (HANDLE
, char *, int);
2357 void close_unc_volume (HANDLE
);
2360 opendir (char *filename
)
2364 /* Opening is done by FindFirstFile. However, a read is inherent to
2365 this operation, so we defer the open until read time. */
2367 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2369 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2372 if (is_unc_volume (filename
))
2374 wnet_enum_handle
= open_unc_volume (filename
);
2375 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2379 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2386 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2387 dir_pathname
[MAXPATHLEN
] = '\0';
2388 dir_is_fat
= is_fat_volume (filename
, NULL
);
2394 closedir (DIR *dirp
)
2396 /* If we have a find-handle open, close it. */
2397 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2399 FindClose (dir_find_handle
);
2400 dir_find_handle
= INVALID_HANDLE_VALUE
;
2402 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2404 close_unc_volume (wnet_enum_handle
);
2405 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2407 xfree ((char *) dirp
);
2413 int downcase
= !NILP (Vw32_downcase_file_names
);
2415 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2417 if (!read_unc_volume (wnet_enum_handle
,
2418 dir_find_data
.cFileName
,
2422 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2423 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2425 char filename
[MAXNAMLEN
+ 3];
2428 strcpy (filename
, dir_pathname
);
2429 ln
= strlen (filename
) - 1;
2430 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2431 strcat (filename
, "\\");
2432 strcat (filename
, "*");
2434 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2436 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2441 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2445 /* Emacs never uses this value, so don't bother making it match
2446 value returned by stat(). */
2447 dir_static
.d_ino
= 1;
2449 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2451 /* If the file name in cFileName[] includes `?' characters, it means
2452 the original file name used characters that cannot be represented
2453 by the current ANSI codepage. To avoid total lossage, retrieve
2454 the short 8+3 alias of the long file name. */
2455 if (_mbspbrk (dir_static
.d_name
, "?"))
2457 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2458 downcase
= 1; /* 8+3 aliases are returned in all caps */
2460 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2461 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2462 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2464 /* If the file name in cFileName[] includes `?' characters, it means
2465 the original file name used characters that cannot be represented
2466 by the current ANSI codepage. To avoid total lossage, retrieve
2467 the short 8+3 alias of the long file name. */
2468 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2470 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2471 /* 8+3 aliases are returned in all caps, which could break
2472 various alists that look at filenames' extensions. */
2476 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2477 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2479 _strlwr (dir_static
.d_name
);
2483 for (p
= dir_static
.d_name
; *p
; p
++)
2484 if (*p
>= 'a' && *p
<= 'z')
2487 _strlwr (dir_static
.d_name
);
2494 open_unc_volume (const char *path
)
2500 nr
.dwScope
= RESOURCE_GLOBALNET
;
2501 nr
.dwType
= RESOURCETYPE_DISK
;
2502 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2503 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2504 nr
.lpLocalName
= NULL
;
2505 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2506 nr
.lpComment
= NULL
;
2507 nr
.lpProvider
= NULL
;
2509 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2510 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2512 if (result
== NO_ERROR
)
2515 return INVALID_HANDLE_VALUE
;
2519 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2523 DWORD bufsize
= 512;
2528 buffer
= alloca (bufsize
);
2529 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2530 if (result
!= NO_ERROR
)
2533 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2534 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2536 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2539 strncpy (readbuf
, ptr
, size
);
2544 close_unc_volume (HANDLE henum
)
2546 if (henum
!= INVALID_HANDLE_VALUE
)
2547 WNetCloseEnum (henum
);
2551 unc_volume_file_attributes (const char *path
)
2556 henum
= open_unc_volume (path
);
2557 if (henum
== INVALID_HANDLE_VALUE
)
2560 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2562 close_unc_volume (henum
);
2567 /* Ensure a network connection is authenticated. */
2569 logon_network_drive (const char *path
)
2571 NETRESOURCE resource
;
2572 char share
[MAX_PATH
];
2577 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2578 drvtype
= DRIVE_REMOTE
;
2579 else if (path
[0] == '\0' || path
[1] != ':')
2580 drvtype
= GetDriveType (NULL
);
2587 drvtype
= GetDriveType (drive
);
2590 /* Only logon to networked drives. */
2591 if (drvtype
!= DRIVE_REMOTE
)
2595 strncpy (share
, path
, MAX_PATH
);
2596 /* Truncate to just server and share name. */
2597 for (i
= 2; i
< MAX_PATH
; i
++)
2599 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2606 resource
.dwType
= RESOURCETYPE_DISK
;
2607 resource
.lpLocalName
= NULL
;
2608 resource
.lpRemoteName
= share
;
2609 resource
.lpProvider
= NULL
;
2611 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2614 /* Shadow some MSVC runtime functions to map requests for long filenames
2615 to reasonable short names if necessary. This was originally added to
2616 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2620 sys_access (const char * path
, int mode
)
2624 /* MSVC implementation doesn't recognize D_OK. */
2625 path
= map_w32_filename (path
, NULL
);
2626 if (is_unc_volume (path
))
2628 attributes
= unc_volume_file_attributes (path
);
2629 if (attributes
== -1) {
2634 else if ((attributes
= GetFileAttributes (path
)) == -1)
2636 /* Should try mapping GetLastError to errno; for now just indicate
2637 that path doesn't exist. */
2641 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2646 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2651 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2660 sys_chdir (const char * path
)
2662 return _chdir (map_w32_filename (path
, NULL
));
2666 sys_chmod (const char * path
, int mode
)
2668 return _chmod (map_w32_filename (path
, NULL
), mode
);
2672 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2674 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2680 sys_creat (const char * path
, int mode
)
2682 return _creat (map_w32_filename (path
, NULL
), mode
);
2686 sys_fopen (const char * path
, const char * mode
)
2690 const char * mode_save
= mode
;
2692 /* Force all file handles to be non-inheritable. This is necessary to
2693 ensure child processes don't unwittingly inherit handles that might
2694 prevent future file access. */
2698 else if (mode
[0] == 'w' || mode
[0] == 'a')
2699 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2703 /* Only do simplistic option parsing. */
2707 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2710 else if (mode
[0] == 'b')
2715 else if (mode
[0] == 't')
2722 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2726 return _fdopen (fd
, mode_save
);
2729 /* This only works on NTFS volumes, but is useful to have. */
2731 sys_link (const char * old
, const char * new)
2735 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2737 if (old
== NULL
|| new == NULL
)
2743 strcpy (oldname
, map_w32_filename (old
, NULL
));
2744 strcpy (newname
, map_w32_filename (new, NULL
));
2746 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2747 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2748 if (fileh
!= INVALID_HANDLE_VALUE
)
2752 /* Confusingly, the "alternate" stream name field does not apply
2753 when restoring a hard link, and instead contains the actual
2754 stream data for the link (ie. the name of the link to create).
2755 The WIN32_STREAM_ID structure before the cStreamName field is
2756 the stream header, which is then immediately followed by the
2760 WIN32_STREAM_ID wid
;
2761 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2764 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2765 data
.wid
.cStreamName
, MAX_PATH
);
2768 LPVOID context
= NULL
;
2771 data
.wid
.dwStreamId
= BACKUP_LINK
;
2772 data
.wid
.dwStreamAttributes
= 0;
2773 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2774 data
.wid
.Size
.HighPart
= 0;
2775 data
.wid
.dwStreamNameSize
= 0;
2777 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2778 offsetof (WIN32_STREAM_ID
, cStreamName
)
2779 + data
.wid
.Size
.LowPart
,
2780 &wbytes
, FALSE
, FALSE
, &context
)
2781 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2788 /* Should try mapping GetLastError to errno; for now just
2789 indicate a general error (eg. links not supported). */
2790 errno
= EINVAL
; // perhaps EMLINK?
2794 CloseHandle (fileh
);
2803 sys_mkdir (const char * path
)
2805 return _mkdir (map_w32_filename (path
, NULL
));
2808 /* Because of long name mapping issues, we need to implement this
2809 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2810 a unique name, instead of setting the input template to an empty
2813 Standard algorithm seems to be use pid or tid with a letter on the
2814 front (in place of the 6 X's) and cycle through the letters to find a
2815 unique name. We extend that to allow any reasonable character as the
2816 first of the 6 X's. */
2818 sys_mktemp (char * template)
2822 unsigned uid
= GetCurrentThreadId ();
2823 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2825 if (template == NULL
)
2827 p
= template + strlen (template);
2829 /* replace up to the last 5 X's with uid in decimal */
2830 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2832 p
[0] = '0' + uid
% 10;
2836 if (i
< 0 && p
[0] == 'X')
2841 int save_errno
= errno
;
2842 p
[0] = first_char
[i
];
2843 if (sys_access (template, 0) < 0)
2849 while (++i
< sizeof (first_char
));
2852 /* Template is badly formed or else we can't generate a unique name,
2853 so return empty string */
2859 sys_open (const char * path
, int oflag
, int mode
)
2861 const char* mpath
= map_w32_filename (path
, NULL
);
2862 /* Try to open file without _O_CREAT, to be able to write to hidden
2863 and system files. Force all file handles to be
2865 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2868 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2872 sys_rename (const char * oldname
, const char * newname
)
2875 char temp
[MAX_PATH
];
2877 /* MoveFile on Windows 95 doesn't correctly change the short file name
2878 alias in a number of circumstances (it is not easy to predict when
2879 just by looking at oldname and newname, unfortunately). In these
2880 cases, renaming through a temporary name avoids the problem.
2882 A second problem on Windows 95 is that renaming through a temp name when
2883 newname is uppercase fails (the final long name ends up in
2884 lowercase, although the short alias might be uppercase) UNLESS the
2885 long temp name is not 8.3.
2887 So, on Windows 95 we always rename through a temp name, and we make sure
2888 the temp name has a long extension to ensure correct renaming. */
2890 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2892 if (os_subtype
== OS_WIN95
)
2898 oldname
= map_w32_filename (oldname
, NULL
);
2899 if (o
= strrchr (oldname
, '\\'))
2902 o
= (char *) oldname
;
2904 if (p
= strrchr (temp
, '\\'))
2911 /* Force temp name to require a manufactured 8.3 alias - this
2912 seems to make the second rename work properly. */
2913 sprintf (p
, "_.%s.%u", o
, i
);
2915 result
= rename (oldname
, temp
);
2917 /* This loop must surely terminate! */
2918 while (result
< 0 && errno
== EEXIST
);
2923 /* Emulate Unix behavior - newname is deleted if it already exists
2924 (at least if it is a file; don't do this for directories).
2926 Since we mustn't do this if we are just changing the case of the
2927 file name (we would end up deleting the file we are trying to
2928 rename!), we let rename detect if the destination file already
2929 exists - that way we avoid the possible pitfalls of trying to
2930 determine ourselves whether two names really refer to the same
2931 file, which is not always possible in the general case. (Consider
2932 all the permutations of shared or subst'd drives, etc.) */
2934 newname
= map_w32_filename (newname
, NULL
);
2935 result
= rename (temp
, newname
);
2939 && _chmod (newname
, 0666) == 0
2940 && _unlink (newname
) == 0)
2941 result
= rename (temp
, newname
);
2947 sys_rmdir (const char * path
)
2949 return _rmdir (map_w32_filename (path
, NULL
));
2953 sys_unlink (const char * path
)
2955 path
= map_w32_filename (path
, NULL
);
2957 /* On Unix, unlink works without write permission. */
2958 _chmod (path
, 0666);
2959 return _unlink (path
);
2962 static FILETIME utc_base_ft
;
2963 static ULONGLONG utc_base
; /* In 100ns units */
2964 static int init
= 0;
2966 #define FILETIME_TO_U64(result, ft) \
2968 ULARGE_INTEGER uiTemp; \
2969 uiTemp.LowPart = (ft).dwLowDateTime; \
2970 uiTemp.HighPart = (ft).dwHighDateTime; \
2971 result = uiTemp.QuadPart; \
2975 initialize_utc_base (void)
2977 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2986 st
.wMilliseconds
= 0;
2988 SystemTimeToFileTime (&st
, &utc_base_ft
);
2989 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2993 convert_time (FILETIME ft
)
2999 initialize_utc_base();
3003 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3006 FILETIME_TO_U64 (tmp
, ft
);
3007 return (time_t) ((tmp
- utc_base
) / 10000000L);
3012 convert_from_time_t (time_t time
, FILETIME
* pft
)
3018 initialize_utc_base ();
3022 /* time in 100ns units since 1-Jan-1601 */
3023 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3024 pft
->dwHighDateTime
= tmp
.HighPart
;
3025 pft
->dwLowDateTime
= tmp
.LowPart
;
3029 /* No reason to keep this; faking inode values either by hashing or even
3030 using the file index from GetInformationByHandle, is not perfect and
3031 so by default Emacs doesn't use the inode values on Windows.
3032 Instead, we now determine file-truename correctly (except for
3033 possible drive aliasing etc). */
3035 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3037 hashval (const unsigned char * str
)
3042 h
= (h
<< 4) + *str
++;
3048 /* Return the hash value of the canonical pathname, excluding the
3049 drive/UNC header, to get a hopefully unique inode number. */
3051 generate_inode_val (const char * name
)
3053 char fullname
[ MAX_PATH
];
3057 /* Get the truly canonical filename, if it exists. (Note: this
3058 doesn't resolve aliasing due to subst commands, or recognise hard
3060 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3063 parse_root (fullname
, &p
);
3064 /* Normal W32 filesystems are still case insensitive. */
3071 static PSECURITY_DESCRIPTOR
3072 get_file_security_desc (const char *fname
)
3074 PSECURITY_DESCRIPTOR psd
= NULL
;
3076 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3077 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3079 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3081 err
= GetLastError ();
3082 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3086 psd
= xmalloc (sd_len
);
3087 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3099 unsigned n_subauthorities
;
3101 /* Use the last sub-authority value of the RID, the relative
3102 portion of the SID, as user/group ID. */
3103 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3104 if (n_subauthorities
< 1)
3105 return 0; /* the "World" RID */
3106 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3109 /* Caching SID and account values for faster lokup. */
3112 # define FLEXIBLE_ARRAY_MEMBER
3114 # define FLEXIBLE_ARRAY_MEMBER 1
3119 struct w32_id
*next
;
3121 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3124 static struct w32_id
*w32_idlist
;
3127 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3129 struct w32_id
*tail
, *found
;
3131 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3133 if (equal_sid ((PSID
)tail
->sid
, sid
))
3142 strcpy (name
, found
->name
);
3150 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3153 struct w32_id
*new_entry
;
3155 /* We don't want to leave behind stale cache from when Emacs was
3159 sid_len
= get_length_sid (sid
);
3160 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3163 new_entry
->rid
= id
;
3164 strcpy (new_entry
->name
, name
);
3165 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3166 new_entry
->next
= w32_idlist
;
3167 w32_idlist
= new_entry
;
3176 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3177 unsigned *id
, char *nm
, int what
)
3180 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3182 SID_NAME_USE ignore
;
3184 DWORD name_len
= sizeof (name
);
3186 DWORD domain_len
= sizeof (domain
);
3192 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3193 else if (what
== GID
)
3194 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3198 if (!result
|| !is_valid_sid (sid
))
3200 else if (!w32_cached_id (sid
, id
, nm
))
3202 /* If FNAME is a UNC, we need to lookup account on the
3203 specified machine. */
3204 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3205 && fname
[2] != '\0')
3210 for (s
= fname
+ 2, p
= machine
;
3211 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3217 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3218 domain
, &domain_len
, &ignore
)
3219 || name_len
> UNLEN
+1)
3223 *id
= get_rid (sid
);
3225 w32_add_to_cache (sid
, *id
, name
);
3232 get_file_owner_and_group (
3233 PSECURITY_DESCRIPTOR psd
,
3237 int dflt_usr
= 0, dflt_grp
= 0;
3246 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3248 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3251 /* Consider files to belong to current user/group, if we cannot get
3252 more accurate information. */
3255 st
->st_uid
= dflt_passwd
.pw_uid
;
3256 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3260 st
->st_gid
= dflt_passwd
.pw_gid
;
3261 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3265 /* Return non-zero if NAME is a potentially slow filesystem. */
3267 is_slow_fs (const char *name
)
3272 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3273 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3274 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3275 devtype
= GetDriveType (NULL
); /* use root of current drive */
3278 /* GetDriveType needs the root directory of the drive. */
3279 strncpy (drive_root
, name
, 2);
3280 drive_root
[2] = '\\';
3281 drive_root
[3] = '\0';
3282 devtype
= GetDriveType (drive_root
);
3284 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3287 /* MSVC stat function can't cope with UNC names and has other bugs, so
3288 replace it with our own. This also allows us to calculate consistent
3289 inode values without hacks in the main Emacs code. */
3291 stat (const char * path
, struct stat
* buf
)
3296 WIN32_FIND_DATA wfd
;
3298 unsigned __int64 fake_inode
;
3301 int rootdir
= FALSE
;
3302 PSECURITY_DESCRIPTOR psd
= NULL
;
3304 if (path
== NULL
|| buf
== NULL
)
3310 name
= (char *) map_w32_filename (path
, &path
);
3311 /* Must be valid filename, no wild cards or other invalid
3312 characters. We use _mbspbrk to support multibyte strings that
3313 might look to strpbrk as if they included literal *, ?, and other
3314 characters mentioned below that are disallowed by Windows
3316 if (_mbspbrk (name
, "*?|<>\""))
3322 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3323 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3324 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3329 /* Remove trailing directory separator, unless name is the root
3330 directory of a drive or UNC volume in which case ensure there
3331 is a trailing separator. */
3332 len
= strlen (name
);
3333 rootdir
= (path
>= name
+ len
- 1
3334 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3335 name
= strcpy (alloca (len
+ 2), name
);
3337 if (is_unc_volume (name
))
3339 DWORD attrs
= unc_volume_file_attributes (name
);
3344 memset (&wfd
, 0, sizeof (wfd
));
3345 wfd
.dwFileAttributes
= attrs
;
3346 wfd
.ftCreationTime
= utc_base_ft
;
3347 wfd
.ftLastAccessTime
= utc_base_ft
;
3348 wfd
.ftLastWriteTime
= utc_base_ft
;
3349 strcpy (wfd
.cFileName
, name
);
3353 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3354 strcat (name
, "\\");
3355 if (GetDriveType (name
) < 2)
3360 memset (&wfd
, 0, sizeof (wfd
));
3361 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3362 wfd
.ftCreationTime
= utc_base_ft
;
3363 wfd
.ftLastAccessTime
= utc_base_ft
;
3364 wfd
.ftLastWriteTime
= utc_base_ft
;
3365 strcpy (wfd
.cFileName
, name
);
3369 if (IS_DIRECTORY_SEP (name
[len
-1]))
3372 /* (This is hacky, but helps when doing file completions on
3373 network drives.) Optimize by using information available from
3374 active readdir if possible. */
3375 len
= strlen (dir_pathname
);
3376 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3378 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3379 && strnicmp (name
, dir_pathname
, len
) == 0
3380 && IS_DIRECTORY_SEP (name
[len
])
3381 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3383 /* This was the last entry returned by readdir. */
3384 wfd
= dir_find_data
;
3388 logon_network_drive (name
);
3390 fh
= FindFirstFile (name
, &wfd
);
3391 if (fh
== INVALID_HANDLE_VALUE
)
3400 if (!(NILP (Vw32_get_true_file_attributes
)
3401 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3402 /* No access rights required to get info. */
3403 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3404 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3405 != INVALID_HANDLE_VALUE
)
3407 /* This is more accurate in terms of gettting the correct number
3408 of links, but is quite slow (it is noticeable when Emacs is
3409 making a list of file name completions). */
3410 BY_HANDLE_FILE_INFORMATION info
;
3412 if (GetFileInformationByHandle (fh
, &info
))
3414 buf
->st_nlink
= info
.nNumberOfLinks
;
3415 /* Might as well use file index to fake inode values, but this
3416 is not guaranteed to be unique unless we keep a handle open
3417 all the time (even then there are situations where it is
3418 not unique). Reputedly, there are at most 48 bits of info
3419 (on NTFS, presumably less on FAT). */
3420 fake_inode
= info
.nFileIndexHigh
;
3422 fake_inode
+= info
.nFileIndexLow
;
3430 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3432 buf
->st_mode
= S_IFDIR
;
3436 switch (GetFileType (fh
))
3438 case FILE_TYPE_DISK
:
3439 buf
->st_mode
= S_IFREG
;
3441 case FILE_TYPE_PIPE
:
3442 buf
->st_mode
= S_IFIFO
;
3444 case FILE_TYPE_CHAR
:
3445 case FILE_TYPE_UNKNOWN
:
3447 buf
->st_mode
= S_IFCHR
;
3451 psd
= get_file_security_desc (name
);
3452 get_file_owner_and_group (psd
, name
, buf
);
3456 /* Don't bother to make this information more accurate. */
3457 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3462 get_file_owner_and_group (NULL
, name
, buf
);
3467 /* Not sure if there is any point in this. */
3468 if (!NILP (Vw32_generate_fake_inodes
))
3469 fake_inode
= generate_inode_val (name
);
3470 else if (fake_inode
== 0)
3472 /* For want of something better, try to make everything unique. */
3473 static DWORD gen_num
= 0;
3474 fake_inode
= ++gen_num
;
3478 /* MSVC defines _ino_t to be short; other libc's might not. */
3479 if (sizeof (buf
->st_ino
) == 2)
3480 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3482 buf
->st_ino
= fake_inode
;
3484 /* volume_info is set indirectly by map_w32_filename */
3485 buf
->st_dev
= volume_info
.serialnum
;
3486 buf
->st_rdev
= volume_info
.serialnum
;
3489 buf
->st_size
= wfd
.nFileSizeHigh
;
3490 buf
->st_size
<<= 32;
3491 buf
->st_size
+= wfd
.nFileSizeLow
;
3493 /* Convert timestamps to Unix format. */
3494 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3495 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3496 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3497 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3498 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3500 /* determine rwx permissions */
3501 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3502 permission
= S_IREAD
;
3504 permission
= S_IREAD
| S_IWRITE
;
3506 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3507 permission
|= S_IEXEC
;
3508 else if (is_exec (name
))
3509 permission
|= S_IEXEC
;
3511 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3516 /* Provide fstat and utime as well as stat for consistent handling of
3519 fstat (int desc
, struct stat
* buf
)
3521 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3522 BY_HANDLE_FILE_INFORMATION info
;
3523 unsigned __int64 fake_inode
;
3526 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3528 case FILE_TYPE_DISK
:
3529 buf
->st_mode
= S_IFREG
;
3530 if (!GetFileInformationByHandle (fh
, &info
))
3536 case FILE_TYPE_PIPE
:
3537 buf
->st_mode
= S_IFIFO
;
3539 case FILE_TYPE_CHAR
:
3540 case FILE_TYPE_UNKNOWN
:
3542 buf
->st_mode
= S_IFCHR
;
3544 memset (&info
, 0, sizeof (info
));
3545 info
.dwFileAttributes
= 0;
3546 info
.ftCreationTime
= utc_base_ft
;
3547 info
.ftLastAccessTime
= utc_base_ft
;
3548 info
.ftLastWriteTime
= utc_base_ft
;
3551 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3552 buf
->st_mode
= S_IFDIR
;
3554 buf
->st_nlink
= info
.nNumberOfLinks
;
3555 /* Might as well use file index to fake inode values, but this
3556 is not guaranteed to be unique unless we keep a handle open
3557 all the time (even then there are situations where it is
3558 not unique). Reputedly, there are at most 48 bits of info
3559 (on NTFS, presumably less on FAT). */
3560 fake_inode
= info
.nFileIndexHigh
;
3562 fake_inode
+= info
.nFileIndexLow
;
3564 /* MSVC defines _ino_t to be short; other libc's might not. */
3565 if (sizeof (buf
->st_ino
) == 2)
3566 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3568 buf
->st_ino
= fake_inode
;
3570 /* Consider files to belong to current user.
3571 FIXME: this should use GetSecurityInfo API, but it is only
3572 available for _WIN32_WINNT >= 0x501. */
3573 buf
->st_uid
= dflt_passwd
.pw_uid
;
3574 buf
->st_gid
= dflt_passwd
.pw_gid
;
3575 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3576 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3578 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3579 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3581 buf
->st_size
= info
.nFileSizeHigh
;
3582 buf
->st_size
<<= 32;
3583 buf
->st_size
+= info
.nFileSizeLow
;
3585 /* Convert timestamps to Unix format. */
3586 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3587 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3588 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3589 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3590 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3592 /* determine rwx permissions */
3593 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3594 permission
= S_IREAD
;
3596 permission
= S_IREAD
| S_IWRITE
;
3598 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3599 permission
|= S_IEXEC
;
3602 #if 0 /* no way of knowing the filename */
3603 char * p
= strrchr (name
, '.');
3605 (xstrcasecmp (p
, ".exe") == 0 ||
3606 xstrcasecmp (p
, ".com") == 0 ||
3607 xstrcasecmp (p
, ".bat") == 0 ||
3608 xstrcasecmp (p
, ".cmd") == 0))
3609 permission
|= S_IEXEC
;
3613 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3619 utime (const char *name
, struct utimbuf
*times
)
3621 struct utimbuf deftime
;
3628 deftime
.modtime
= deftime
.actime
= time (NULL
);
3632 /* Need write access to set times. */
3633 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3634 0, OPEN_EXISTING
, 0, NULL
);
3637 convert_from_time_t (times
->actime
, &atime
);
3638 convert_from_time_t (times
->modtime
, &mtime
);
3639 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3656 /* Support for browsing other processes and their attributes. See
3657 process.c for the Lisp bindings. */
3659 /* Helper wrapper functions. */
3661 HANDLE WINAPI
create_toolhelp32_snapshot (
3665 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3667 if (g_b_init_create_toolhelp32_snapshot
== 0)
3669 g_b_init_create_toolhelp32_snapshot
= 1;
3670 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3671 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3672 "CreateToolhelp32Snapshot");
3674 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3676 return INVALID_HANDLE_VALUE
;
3678 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3681 BOOL WINAPI
process32_first (
3683 LPPROCESSENTRY32 lppe
)
3685 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3687 if (g_b_init_process32_first
== 0)
3689 g_b_init_process32_first
= 1;
3690 s_pfn_Process32_First
= (Process32First_Proc
)
3691 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3694 if (s_pfn_Process32_First
== NULL
)
3698 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3701 BOOL WINAPI
process32_next (
3703 LPPROCESSENTRY32 lppe
)
3705 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3707 if (g_b_init_process32_next
== 0)
3709 g_b_init_process32_next
= 1;
3710 s_pfn_Process32_Next
= (Process32Next_Proc
)
3711 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3714 if (s_pfn_Process32_Next
== NULL
)
3718 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3721 BOOL WINAPI
open_thread_token (
3722 HANDLE ThreadHandle
,
3723 DWORD DesiredAccess
,
3725 PHANDLE TokenHandle
)
3727 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3728 HMODULE hm_advapi32
= NULL
;
3729 if (is_windows_9x () == TRUE
)
3731 SetLastError (ERROR_NOT_SUPPORTED
);
3734 if (g_b_init_open_thread_token
== 0)
3736 g_b_init_open_thread_token
= 1;
3737 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3738 s_pfn_Open_Thread_Token
=
3739 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3741 if (s_pfn_Open_Thread_Token
== NULL
)
3743 SetLastError (ERROR_NOT_SUPPORTED
);
3747 s_pfn_Open_Thread_Token (
3755 BOOL WINAPI
impersonate_self (
3756 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3758 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3759 HMODULE hm_advapi32
= NULL
;
3760 if (is_windows_9x () == TRUE
)
3764 if (g_b_init_impersonate_self
== 0)
3766 g_b_init_impersonate_self
= 1;
3767 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3768 s_pfn_Impersonate_Self
=
3769 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3771 if (s_pfn_Impersonate_Self
== NULL
)
3775 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3778 BOOL WINAPI
revert_to_self (void)
3780 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3781 HMODULE hm_advapi32
= NULL
;
3782 if (is_windows_9x () == TRUE
)
3786 if (g_b_init_revert_to_self
== 0)
3788 g_b_init_revert_to_self
= 1;
3789 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3790 s_pfn_Revert_To_Self
=
3791 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3793 if (s_pfn_Revert_To_Self
== NULL
)
3797 return s_pfn_Revert_To_Self ();
3800 BOOL WINAPI
get_process_memory_info (
3802 PPROCESS_MEMORY_COUNTERS mem_counters
,
3805 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3806 HMODULE hm_psapi
= NULL
;
3807 if (is_windows_9x () == TRUE
)
3811 if (g_b_init_get_process_memory_info
== 0)
3813 g_b_init_get_process_memory_info
= 1;
3814 hm_psapi
= LoadLibrary ("Psapi.dll");
3816 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3817 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3819 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3823 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3826 BOOL WINAPI
get_process_working_set_size (
3831 static GetProcessWorkingSetSize_Proc
3832 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3834 if (is_windows_9x () == TRUE
)
3838 if (g_b_init_get_process_working_set_size
== 0)
3840 g_b_init_get_process_working_set_size
= 1;
3841 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3842 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3843 "GetProcessWorkingSetSize");
3845 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3849 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3852 BOOL WINAPI
global_memory_status (
3855 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3857 if (is_windows_9x () == TRUE
)
3861 if (g_b_init_global_memory_status
== 0)
3863 g_b_init_global_memory_status
= 1;
3864 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3865 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3866 "GlobalMemoryStatus");
3868 if (s_pfn_Global_Memory_Status
== NULL
)
3872 return s_pfn_Global_Memory_Status (buf
);
3875 BOOL WINAPI
global_memory_status_ex (
3876 MEMORY_STATUS_EX
*buf
)
3878 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3880 if (is_windows_9x () == TRUE
)
3884 if (g_b_init_global_memory_status_ex
== 0)
3886 g_b_init_global_memory_status_ex
= 1;
3887 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3888 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3889 "GlobalMemoryStatusEx");
3891 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3895 return s_pfn_Global_Memory_Status_Ex (buf
);
3899 list_system_processes (void)
3901 struct gcpro gcpro1
;
3902 Lisp_Object proclist
= Qnil
;
3905 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3907 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3909 PROCESSENTRY32 proc_entry
;
3915 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3916 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3917 res
= process32_next (h_snapshot
, &proc_entry
))
3919 proc_id
= proc_entry
.th32ProcessID
;
3920 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3923 CloseHandle (h_snapshot
);
3925 proclist
= Fnreverse (proclist
);
3932 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3934 TOKEN_PRIVILEGES priv
;
3935 DWORD priv_size
= sizeof (priv
);
3936 DWORD opriv_size
= sizeof (*old_priv
);
3937 HANDLE h_token
= NULL
;
3938 HANDLE h_thread
= GetCurrentThread ();
3942 res
= open_thread_token (h_thread
,
3943 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3945 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3947 if (impersonate_self (SecurityImpersonation
))
3948 res
= open_thread_token (h_thread
,
3949 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3954 priv
.PrivilegeCount
= 1;
3955 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3956 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3957 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3958 old_priv
, &opriv_size
)
3959 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3963 CloseHandle (h_token
);
3969 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3971 DWORD priv_size
= sizeof (*priv
);
3972 HANDLE h_token
= NULL
;
3975 if (open_thread_token (GetCurrentThread (),
3976 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3979 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3980 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3984 CloseHandle (h_token
);
3990 ltime (long time_sec
, long time_usec
)
3992 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3993 make_number (time_sec
& 0xffff),
3994 make_number (time_usec
));
3997 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
4000 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4001 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4004 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4005 ULONGLONG tem1
, tem2
, tem3
, tem
;
4008 || !get_process_times_fn
4009 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4010 &ft_kernel
, &ft_user
))
4013 GetSystemTimeAsFileTime (&ft_current
);
4015 FILETIME_TO_U64 (tem1
, ft_kernel
);
4017 *stime
= U64_TO_LISP_TIME (tem1
);
4019 FILETIME_TO_U64 (tem2
, ft_user
);
4021 *utime
= U64_TO_LISP_TIME (tem2
);
4024 *ttime
= U64_TO_LISP_TIME (tem3
);
4026 FILETIME_TO_U64 (tem
, ft_creation
);
4027 /* Process no 4 (System) returns zero creation time. */
4029 tem
= (tem
- utc_base
) / 10L;
4030 *ctime
= U64_TO_LISP_TIME (tem
);
4034 FILETIME_TO_U64 (tem3
, ft_current
);
4035 tem
= (tem3
- utc_base
) / 10L - tem
;
4037 *etime
= U64_TO_LISP_TIME (tem
);
4041 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4052 system_process_attributes (Lisp_Object pid
)
4054 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4055 Lisp_Object attrs
= Qnil
;
4056 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4057 HANDLE h_snapshot
, h_proc
;
4060 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4061 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4062 DWORD glength
= sizeof (gname
);
4063 HANDLE token
= NULL
;
4064 SID_NAME_USE user_type
;
4065 unsigned char *buf
= NULL
;
4067 TOKEN_USER user_token
;
4068 TOKEN_PRIMARY_GROUP group_token
;
4072 PROCESS_MEMORY_COUNTERS mem
;
4073 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4074 DWORD minrss
, maxrss
;
4076 MEMORY_STATUS_EX memstex
;
4077 double totphys
= 0.0;
4078 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4080 BOOL result
= FALSE
;
4082 CHECK_NUMBER_OR_FLOAT (pid
);
4083 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4085 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4087 GCPRO3 (attrs
, decoded_cmd
, tem
);
4089 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4094 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4095 for (res
= process32_first (h_snapshot
, &pe
); res
;
4096 res
= process32_next (h_snapshot
, &pe
))
4098 if (proc_id
== pe
.th32ProcessID
)
4101 decoded_cmd
= build_string ("Idle");
4104 /* Decode the command name from locale-specific
4106 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4107 strlen (pe
.szExeFile
));
4109 code_convert_string_norecord (cmd_str
,
4110 Vlocale_coding_system
, 0);
4112 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4113 attrs
= Fcons (Fcons (Qppid
,
4114 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4116 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4118 attrs
= Fcons (Fcons (Qthcount
,
4119 make_fixnum_or_float (pe
.cntThreads
)),
4126 CloseHandle (h_snapshot
);
4135 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4137 /* If we were denied a handle to the process, try again after
4138 enabling the SeDebugPrivilege in our process. */
4141 TOKEN_PRIVILEGES priv_current
;
4143 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4145 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4147 restore_privilege (&priv_current
);
4153 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4156 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4157 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4159 buf
= xmalloc (blen
);
4160 result
= get_token_information (token
, TokenUser
,
4161 (LPVOID
)buf
, blen
, &needed
);
4164 memcpy (&user_token
, buf
, sizeof (user_token
));
4165 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4167 euid
= get_rid (user_token
.User
.Sid
);
4168 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4173 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4176 strcpy (uname
, "unknown");
4180 ulength
= strlen (uname
);
4186 /* Determine a reasonable euid and gid values. */
4187 if (xstrcasecmp ("administrator", uname
) == 0)
4189 euid
= 500; /* well-known Administrator uid */
4190 egid
= 513; /* well-known None gid */
4194 /* Get group id and name. */
4195 result
= get_token_information (token
, TokenPrimaryGroup
,
4196 (LPVOID
)buf
, blen
, &needed
);
4197 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4199 buf
= xrealloc (buf
, blen
= needed
);
4200 result
= get_token_information (token
, TokenPrimaryGroup
,
4201 (LPVOID
)buf
, blen
, &needed
);
4205 memcpy (&group_token
, buf
, sizeof (group_token
));
4206 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4208 egid
= get_rid (group_token
.PrimaryGroup
);
4209 dlength
= sizeof (domain
);
4211 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4212 gname
, &glength
, NULL
, &dlength
,
4215 w32_add_to_cache (group_token
.PrimaryGroup
,
4219 strcpy (gname
, "None");
4223 glength
= strlen (gname
);
4231 if (!is_windows_9x ())
4233 /* We couldn't open the process token, presumably because of
4234 insufficient access rights. Assume this process is run
4236 strcpy (uname
, "SYSTEM");
4237 strcpy (gname
, "None");
4238 euid
= 18; /* SYSTEM */
4239 egid
= 513; /* None */
4240 glength
= strlen (gname
);
4241 ulength
= strlen (uname
);
4243 /* If we are running under Windows 9X, where security calls are
4244 not supported, we assume all processes are run by the current
4246 else if (GetUserName (uname
, &ulength
))
4248 if (xstrcasecmp ("administrator", uname
) == 0)
4253 strcpy (gname
, "None");
4254 glength
= strlen (gname
);
4255 ulength
= strlen (uname
);
4261 strcpy (uname
, "administrator");
4262 ulength
= strlen (uname
);
4263 strcpy (gname
, "None");
4264 glength
= strlen (gname
);
4267 CloseHandle (token
);
4270 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4271 tem
= make_unibyte_string (uname
, ulength
);
4272 attrs
= Fcons (Fcons (Quser
,
4273 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4275 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4276 tem
= make_unibyte_string (gname
, glength
);
4277 attrs
= Fcons (Fcons (Qgroup
,
4278 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4281 if (global_memory_status_ex (&memstex
))
4282 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4283 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4285 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4286 double, so we need to do this for it... */
4288 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4289 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4290 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4292 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4294 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4295 else if (global_memory_status (&memst
))
4296 totphys
= memst
.dwTotalPhys
/ 1024.0;
4299 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4302 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4304 attrs
= Fcons (Fcons (Qmajflt
,
4305 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4307 attrs
= Fcons (Fcons (Qvsize
,
4308 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4310 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4312 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4315 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4317 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4319 attrs
= Fcons (Fcons (Qmajflt
,
4320 make_fixnum_or_float (mem
.PageFaultCount
)),
4322 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4324 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4327 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4329 DWORD rss
= maxrss
/ 1024;
4331 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4333 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4336 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4338 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4339 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4340 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4341 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4342 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4343 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4346 /* FIXME: Retrieve command line by walking the PEB of the process. */
4349 CloseHandle (h_proc
);
4357 /* Wrappers for winsock functions to map between our file descriptors
4358 and winsock's handles; also set h_errno for convenience.
4360 To allow Emacs to run on systems which don't have winsock support
4361 installed, we dynamically link to winsock on startup if present, and
4362 otherwise provide the minimum necessary functionality
4363 (eg. gethostname). */
4365 /* function pointers for relevant socket functions */
4366 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4367 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4368 int (PASCAL
*pfn_WSAGetLastError
) (void);
4369 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4370 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4371 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4372 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4373 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4374 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4375 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4376 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4377 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4378 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4379 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4380 int (PASCAL
*pfn_WSACleanup
) (void);
4382 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4383 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4384 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4385 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4386 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4387 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4388 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4389 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4390 const char * optval
, int optlen
);
4391 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4392 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4394 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4395 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4396 struct sockaddr
* from
, int * fromlen
);
4397 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4398 const struct sockaddr
* to
, int tolen
);
4400 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4401 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4402 #ifndef HANDLE_FLAG_INHERIT
4403 #define HANDLE_FLAG_INHERIT 1
4407 static int winsock_inuse
;
4412 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4414 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4415 after WSAStartup returns successfully, but it seems reasonable
4416 to allow unloading winsock anyway in that case. */
4417 if (pfn_WSACleanup () == 0 ||
4418 pfn_WSAGetLastError () == WSAENETDOWN
)
4420 if (FreeLibrary (winsock_lib
))
4429 init_winsock (int load_now
)
4431 WSADATA winsockData
;
4433 if (winsock_lib
!= NULL
)
4436 pfn_SetHandleInformation
= NULL
;
4437 pfn_SetHandleInformation
4438 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4439 "SetHandleInformation");
4441 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4443 if (winsock_lib
!= NULL
)
4445 /* dynamically link to socket functions */
4447 #define LOAD_PROC(fn) \
4448 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4451 LOAD_PROC (WSAStartup
);
4452 LOAD_PROC (WSASetLastError
);
4453 LOAD_PROC (WSAGetLastError
);
4454 LOAD_PROC (WSAEventSelect
);
4455 LOAD_PROC (WSACreateEvent
);
4456 LOAD_PROC (WSACloseEvent
);
4459 LOAD_PROC (connect
);
4460 LOAD_PROC (ioctlsocket
);
4463 LOAD_PROC (closesocket
);
4464 LOAD_PROC (shutdown
);
4467 LOAD_PROC (inet_addr
);
4468 LOAD_PROC (gethostname
);
4469 LOAD_PROC (gethostbyname
);
4470 LOAD_PROC (getservbyname
);
4471 LOAD_PROC (getpeername
);
4472 LOAD_PROC (WSACleanup
);
4473 LOAD_PROC (setsockopt
);
4475 LOAD_PROC (getsockname
);
4477 LOAD_PROC (recvfrom
);
4481 /* specify version 1.1 of winsock */
4482 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4484 if (winsockData
.wVersion
!= 0x101)
4489 /* Report that winsock exists and is usable, but leave
4490 socket functions disabled. I am assuming that calling
4491 WSAStartup does not require any network interaction,
4492 and in particular does not cause or require a dial-up
4493 connection to be established. */
4496 FreeLibrary (winsock_lib
);
4504 FreeLibrary (winsock_lib
);
4514 /* function to set h_errno for compatibility; map winsock error codes to
4515 normal system codes where they overlap (non-overlapping definitions
4516 are already in <sys/socket.h> */
4520 if (winsock_lib
== NULL
)
4523 h_errno
= pfn_WSAGetLastError ();
4527 case WSAEACCES
: h_errno
= EACCES
; break;
4528 case WSAEBADF
: h_errno
= EBADF
; break;
4529 case WSAEFAULT
: h_errno
= EFAULT
; break;
4530 case WSAEINTR
: h_errno
= EINTR
; break;
4531 case WSAEINVAL
: h_errno
= EINVAL
; break;
4532 case WSAEMFILE
: h_errno
= EMFILE
; break;
4533 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4534 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4542 if (h_errno
== 0 && winsock_lib
!= NULL
)
4543 pfn_WSASetLastError (0);
4546 /* Extend strerror to handle the winsock-specific error codes. */
4550 } _wsa_errlist
[] = {
4551 WSAEINTR
, "Interrupted function call",
4552 WSAEBADF
, "Bad file descriptor",
4553 WSAEACCES
, "Permission denied",
4554 WSAEFAULT
, "Bad address",
4555 WSAEINVAL
, "Invalid argument",
4556 WSAEMFILE
, "Too many open files",
4558 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4559 WSAEINPROGRESS
, "Operation now in progress",
4560 WSAEALREADY
, "Operation already in progress",
4561 WSAENOTSOCK
, "Socket operation on non-socket",
4562 WSAEDESTADDRREQ
, "Destination address required",
4563 WSAEMSGSIZE
, "Message too long",
4564 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4565 WSAENOPROTOOPT
, "Bad protocol option",
4566 WSAEPROTONOSUPPORT
, "Protocol not supported",
4567 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4568 WSAEOPNOTSUPP
, "Operation not supported",
4569 WSAEPFNOSUPPORT
, "Protocol family not supported",
4570 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4571 WSAEADDRINUSE
, "Address already in use",
4572 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4573 WSAENETDOWN
, "Network is down",
4574 WSAENETUNREACH
, "Network is unreachable",
4575 WSAENETRESET
, "Network dropped connection on reset",
4576 WSAECONNABORTED
, "Software caused connection abort",
4577 WSAECONNRESET
, "Connection reset by peer",
4578 WSAENOBUFS
, "No buffer space available",
4579 WSAEISCONN
, "Socket is already connected",
4580 WSAENOTCONN
, "Socket is not connected",
4581 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4582 WSAETOOMANYREFS
, "Too many references", /* not sure */
4583 WSAETIMEDOUT
, "Connection timed out",
4584 WSAECONNREFUSED
, "Connection refused",
4585 WSAELOOP
, "Network loop", /* not sure */
4586 WSAENAMETOOLONG
, "Name is too long",
4587 WSAEHOSTDOWN
, "Host is down",
4588 WSAEHOSTUNREACH
, "No route to host",
4589 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4590 WSAEPROCLIM
, "Too many processes",
4591 WSAEUSERS
, "Too many users", /* not sure */
4592 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4593 WSAESTALE
, "Data is stale", /* not sure */
4594 WSAEREMOTE
, "Remote error", /* not sure */
4596 WSASYSNOTREADY
, "Network subsystem is unavailable",
4597 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4598 WSANOTINITIALISED
, "Winsock not initialized successfully",
4599 WSAEDISCON
, "Graceful shutdown in progress",
4601 WSAENOMORE
, "No more operations allowed", /* not sure */
4602 WSAECANCELLED
, "Operation cancelled", /* not sure */
4603 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4604 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4605 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4606 WSASYSCALLFAILURE
, "System call failure",
4607 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4608 WSATYPE_NOT_FOUND
, "Class type not found",
4609 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4610 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4611 WSAEREFUSED
, "Operation refused", /* not sure */
4614 WSAHOST_NOT_FOUND
, "Host not found",
4615 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4616 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4617 WSANO_DATA
, "Valid name, no data record of requested type",
4623 sys_strerror (int error_no
)
4626 static char unknown_msg
[40];
4628 if (error_no
>= 0 && error_no
< sys_nerr
)
4629 return sys_errlist
[error_no
];
4631 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4632 if (_wsa_errlist
[i
].errnum
== error_no
)
4633 return _wsa_errlist
[i
].msg
;
4635 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4639 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4640 but I believe the method of keeping the socket handle separate (and
4641 insuring it is not inheritable) is the correct one. */
4643 //#define SOCK_REPLACE_HANDLE
4645 #ifdef SOCK_REPLACE_HANDLE
4646 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4648 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4651 int socket_to_fd (SOCKET s
);
4654 sys_socket (int af
, int type
, int protocol
)
4658 if (winsock_lib
== NULL
)
4661 return INVALID_SOCKET
;
4666 /* call the real socket function */
4667 s
= pfn_socket (af
, type
, protocol
);
4669 if (s
!= INVALID_SOCKET
)
4670 return socket_to_fd (s
);
4676 /* Convert a SOCKET to a file descriptor. */
4678 socket_to_fd (SOCKET s
)
4683 /* Although under NT 3.5 _open_osfhandle will accept a socket
4684 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4685 that does not work under NT 3.1. However, we can get the same
4686 effect by using a backdoor function to replace an existing
4687 descriptor handle with the one we want. */
4689 /* allocate a file descriptor (with appropriate flags) */
4690 fd
= _open ("NUL:", _O_RDWR
);
4693 #ifdef SOCK_REPLACE_HANDLE
4694 /* now replace handle to NUL with our socket handle */
4695 CloseHandle ((HANDLE
) _get_osfhandle (fd
));
4697 _set_osfhnd (fd
, s
);
4698 /* setmode (fd, _O_BINARY); */
4700 /* Make a non-inheritable copy of the socket handle. Note
4701 that it is possible that sockets aren't actually kernel
4702 handles, which appears to be the case on Windows 9x when
4703 the MS Proxy winsock client is installed. */
4705 /* Apparently there is a bug in NT 3.51 with some service
4706 packs, which prevents using DuplicateHandle to make a
4707 socket handle non-inheritable (causes WSACleanup to
4708 hang). The work-around is to use SetHandleInformation
4709 instead if it is available and implemented. */
4710 if (pfn_SetHandleInformation
)
4712 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4716 HANDLE parent
= GetCurrentProcess ();
4717 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4719 if (DuplicateHandle (parent
,
4725 DUPLICATE_SAME_ACCESS
))
4727 /* It is possible that DuplicateHandle succeeds even
4728 though the socket wasn't really a kernel handle,
4729 because a real handle has the same value. So
4730 test whether the new handle really is a socket. */
4731 long nonblocking
= 0;
4732 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4734 pfn_closesocket (s
);
4739 CloseHandle (new_s
);
4744 fd_info
[fd
].hnd
= (HANDLE
) s
;
4747 /* set our own internal flags */
4748 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4754 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4756 /* attach child_process to fd_info */
4757 if (fd_info
[ fd
].cp
!= NULL
)
4759 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4763 fd_info
[ fd
].cp
= cp
;
4766 winsock_inuse
++; /* count open sockets */
4773 pfn_closesocket (s
);
4780 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4782 if (winsock_lib
== NULL
)
4785 return SOCKET_ERROR
;
4789 if (fd_info
[s
].flags
& FILE_SOCKET
)
4791 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4792 if (rc
== SOCKET_ERROR
)
4797 return SOCKET_ERROR
;
4802 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4804 if (winsock_lib
== NULL
)
4807 return SOCKET_ERROR
;
4811 if (fd_info
[s
].flags
& FILE_SOCKET
)
4813 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4814 if (rc
== SOCKET_ERROR
)
4819 return SOCKET_ERROR
;
4823 sys_htons (u_short hostshort
)
4825 return (winsock_lib
!= NULL
) ?
4826 pfn_htons (hostshort
) : hostshort
;
4830 sys_ntohs (u_short netshort
)
4832 return (winsock_lib
!= NULL
) ?
4833 pfn_ntohs (netshort
) : netshort
;
4837 sys_inet_addr (const char * cp
)
4839 return (winsock_lib
!= NULL
) ?
4840 pfn_inet_addr (cp
) : INADDR_NONE
;
4844 sys_gethostname (char * name
, int namelen
)
4846 if (winsock_lib
!= NULL
)
4847 return pfn_gethostname (name
, namelen
);
4849 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4850 return !GetComputerName (name
, (DWORD
*)&namelen
);
4853 return SOCKET_ERROR
;
4857 sys_gethostbyname (const char * name
)
4859 struct hostent
* host
;
4861 if (winsock_lib
== NULL
)
4868 host
= pfn_gethostbyname (name
);
4875 sys_getservbyname (const char * name
, const char * proto
)
4877 struct servent
* serv
;
4879 if (winsock_lib
== NULL
)
4886 serv
= pfn_getservbyname (name
, proto
);
4893 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4895 if (winsock_lib
== NULL
)
4898 return SOCKET_ERROR
;
4902 if (fd_info
[s
].flags
& FILE_SOCKET
)
4904 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4905 if (rc
== SOCKET_ERROR
)
4910 return SOCKET_ERROR
;
4915 sys_shutdown (int s
, int how
)
4917 if (winsock_lib
== NULL
)
4920 return SOCKET_ERROR
;
4924 if (fd_info
[s
].flags
& FILE_SOCKET
)
4926 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4927 if (rc
== SOCKET_ERROR
)
4932 return SOCKET_ERROR
;
4936 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4938 if (winsock_lib
== NULL
)
4941 return SOCKET_ERROR
;
4945 if (fd_info
[s
].flags
& FILE_SOCKET
)
4947 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4948 (const char *)optval
, optlen
);
4949 if (rc
== SOCKET_ERROR
)
4954 return SOCKET_ERROR
;
4958 sys_listen (int s
, int backlog
)
4960 if (winsock_lib
== NULL
)
4963 return SOCKET_ERROR
;
4967 if (fd_info
[s
].flags
& FILE_SOCKET
)
4969 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4970 if (rc
== SOCKET_ERROR
)
4973 fd_info
[s
].flags
|= FILE_LISTEN
;
4977 return SOCKET_ERROR
;
4981 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4983 if (winsock_lib
== NULL
)
4986 return SOCKET_ERROR
;
4990 if (fd_info
[s
].flags
& FILE_SOCKET
)
4992 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4993 if (rc
== SOCKET_ERROR
)
4998 return SOCKET_ERROR
;
5002 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
5004 if (winsock_lib
== NULL
)
5011 if (fd_info
[s
].flags
& FILE_LISTEN
)
5013 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5015 if (t
== INVALID_SOCKET
)
5018 fd
= socket_to_fd (t
);
5020 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5021 ResetEvent (fd_info
[s
].cp
->char_avail
);
5029 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5030 struct sockaddr
* from
, int * fromlen
)
5032 if (winsock_lib
== NULL
)
5035 return SOCKET_ERROR
;
5039 if (fd_info
[s
].flags
& FILE_SOCKET
)
5041 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5042 if (rc
== SOCKET_ERROR
)
5047 return SOCKET_ERROR
;
5051 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5052 const struct sockaddr
* to
, int tolen
)
5054 if (winsock_lib
== NULL
)
5057 return SOCKET_ERROR
;
5061 if (fd_info
[s
].flags
& FILE_SOCKET
)
5063 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5064 if (rc
== SOCKET_ERROR
)
5069 return SOCKET_ERROR
;
5072 /* Windows does not have an fcntl function. Provide an implementation
5073 solely for making sockets non-blocking. */
5075 fcntl (int s
, int cmd
, int options
)
5077 if (winsock_lib
== NULL
)
5084 if (fd_info
[s
].flags
& FILE_SOCKET
)
5086 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5088 unsigned long nblock
= 1;
5089 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5090 if (rc
== SOCKET_ERROR
)
5092 /* Keep track of the fact that we set this to non-blocking. */
5093 fd_info
[s
].flags
|= FILE_NDELAY
;
5099 return SOCKET_ERROR
;
5103 return SOCKET_ERROR
;
5106 #endif /* HAVE_SOCKETS */
5109 /* Shadow main io functions: we need to handle pipes and sockets more
5110 intelligently, and implement non-blocking mode as well. */
5123 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5125 child_process
* cp
= fd_info
[fd
].cp
;
5127 fd_info
[fd
].cp
= NULL
;
5129 if (CHILD_ACTIVE (cp
))
5131 /* if last descriptor to active child_process then cleanup */
5133 for (i
= 0; i
< MAXDESC
; i
++)
5137 if (fd_info
[i
].cp
== cp
)
5143 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5145 #ifndef SOCK_REPLACE_HANDLE
5146 if (winsock_lib
== NULL
) abort ();
5148 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5149 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5151 winsock_inuse
--; /* count open sockets */
5159 /* Note that sockets do not need special treatment here (at least on
5160 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5161 closesocket is equivalent to CloseHandle, which is to be expected
5162 because socket handles are fully fledged kernel handles. */
5165 if (rc
== 0 && fd
< MAXDESC
)
5166 fd_info
[fd
].flags
= 0;
5177 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5179 /* duplicate our internal info as well */
5180 fd_info
[new_fd
] = fd_info
[fd
];
5187 sys_dup2 (int src
, int dst
)
5191 if (dst
< 0 || dst
>= MAXDESC
)
5197 /* make sure we close the destination first if it's a pipe or socket */
5198 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5201 rc
= _dup2 (src
, dst
);
5204 /* duplicate our internal info as well */
5205 fd_info
[dst
] = fd_info
[src
];
5210 /* Unix pipe() has only one arg */
5212 sys_pipe (int * phandles
)
5217 /* make pipe handles non-inheritable; when we spawn a child, we
5218 replace the relevant handle with an inheritable one. Also put
5219 pipes into binary mode; we will do text mode translation ourselves
5221 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5225 /* Protect against overflow, since Windows can open more handles than
5226 our fd_info array has room for. */
5227 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5229 _close (phandles
[0]);
5230 _close (phandles
[1]);
5235 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5236 fd_info
[phandles
[0]].flags
= flags
;
5238 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5239 fd_info
[phandles
[1]].flags
= flags
;
5247 extern int w32_pipe_read_delay
;
5249 /* Function to do blocking read of one byte, needed to implement
5250 select. It is only allowed on sockets and pipes. */
5252 _sys_read_ahead (int fd
)
5257 if (fd
< 0 || fd
>= MAXDESC
)
5258 return STATUS_READ_ERROR
;
5260 cp
= fd_info
[fd
].cp
;
5262 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5263 return STATUS_READ_ERROR
;
5265 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5266 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5268 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5272 cp
->status
= STATUS_READ_IN_PROGRESS
;
5274 if (fd_info
[fd
].flags
& FILE_PIPE
)
5276 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5278 /* Give subprocess time to buffer some more output for us before
5279 reporting that input is available; we need this because Windows 95
5280 connects DOS programs to pipes by making the pipe appear to be
5281 the normal console stdout - as a result most DOS programs will
5282 write to stdout without buffering, ie. one character at a
5283 time. Even some W32 programs do this - "dir" in a command
5284 shell on NT is very slow if we don't do this. */
5287 int wait
= w32_pipe_read_delay
;
5293 /* Yield remainder of our time slice, effectively giving a
5294 temporary priority boost to the child process. */
5298 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5300 HANDLE hnd
= fd_info
[fd
].hnd
;
5301 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5304 /* Configure timeouts for blocking read. */
5305 if (!GetCommTimeouts (hnd
, &ct
))
5306 return STATUS_READ_ERROR
;
5307 ct
.ReadIntervalTimeout
= 0;
5308 ct
.ReadTotalTimeoutMultiplier
= 0;
5309 ct
.ReadTotalTimeoutConstant
= 0;
5310 if (!SetCommTimeouts (hnd
, &ct
))
5311 return STATUS_READ_ERROR
;
5313 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5315 if (GetLastError () != ERROR_IO_PENDING
)
5316 return STATUS_READ_ERROR
;
5317 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5318 return STATUS_READ_ERROR
;
5322 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5324 unsigned long nblock
= 0;
5325 /* We always want this to block, so temporarily disable NDELAY. */
5326 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5327 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5329 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5331 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5334 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5339 if (rc
== sizeof (char))
5340 cp
->status
= STATUS_READ_SUCCEEDED
;
5342 cp
->status
= STATUS_READ_FAILED
;
5348 _sys_wait_accept (int fd
)
5354 if (fd
< 0 || fd
>= MAXDESC
)
5355 return STATUS_READ_ERROR
;
5357 cp
= fd_info
[fd
].cp
;
5359 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5360 return STATUS_READ_ERROR
;
5362 cp
->status
= STATUS_READ_FAILED
;
5364 hEv
= pfn_WSACreateEvent ();
5365 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5366 if (rc
!= SOCKET_ERROR
)
5368 rc
= WaitForSingleObject (hEv
, INFINITE
);
5369 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5370 if (rc
== WAIT_OBJECT_0
)
5371 cp
->status
= STATUS_READ_SUCCEEDED
;
5373 pfn_WSACloseEvent (hEv
);
5379 sys_read (int fd
, char * buffer
, unsigned int count
)
5384 char * orig_buffer
= buffer
;
5392 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5394 child_process
*cp
= fd_info
[fd
].cp
;
5396 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5404 /* re-read CR carried over from last read */
5405 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5407 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5411 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5414 /* presence of a child_process structure means we are operating in
5415 non-blocking mode - otherwise we just call _read directly.
5416 Note that the child_process structure might be missing because
5417 reap_subprocess has been called; in this case the pipe is
5418 already broken, so calling _read on it is okay. */
5421 int current_status
= cp
->status
;
5423 switch (current_status
)
5425 case STATUS_READ_FAILED
:
5426 case STATUS_READ_ERROR
:
5427 /* report normal EOF if nothing in buffer */
5429 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5432 case STATUS_READ_READY
:
5433 case STATUS_READ_IN_PROGRESS
:
5434 DebPrint (("sys_read called when read is in progress\n"));
5435 errno
= EWOULDBLOCK
;
5438 case STATUS_READ_SUCCEEDED
:
5439 /* consume read-ahead char */
5440 *buffer
++ = cp
->chr
;
5443 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5444 ResetEvent (cp
->char_avail
);
5446 case STATUS_READ_ACKNOWLEDGED
:
5450 DebPrint (("sys_read: bad status %d\n", current_status
));
5455 if (fd_info
[fd
].flags
& FILE_PIPE
)
5457 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5458 to_read
= min (waiting
, (DWORD
) count
);
5461 nchars
+= _read (fd
, buffer
, to_read
);
5463 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5465 HANDLE hnd
= fd_info
[fd
].hnd
;
5466 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5473 /* Configure timeouts for non-blocking read. */
5474 if (!GetCommTimeouts (hnd
, &ct
))
5479 ct
.ReadIntervalTimeout
= MAXDWORD
;
5480 ct
.ReadTotalTimeoutMultiplier
= 0;
5481 ct
.ReadTotalTimeoutConstant
= 0;
5482 if (!SetCommTimeouts (hnd
, &ct
))
5488 if (!ResetEvent (ovl
->hEvent
))
5493 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5495 if (GetLastError () != ERROR_IO_PENDING
)
5500 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5510 else /* FILE_SOCKET */
5512 if (winsock_lib
== NULL
) abort ();
5514 /* do the equivalent of a non-blocking read */
5515 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5516 if (waiting
== 0 && nchars
== 0)
5518 h_errno
= errno
= EWOULDBLOCK
;
5524 /* always use binary mode for sockets */
5525 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5526 if (res
== SOCKET_ERROR
)
5528 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5529 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5540 int nread
= _read (fd
, buffer
, count
);
5543 else if (nchars
== 0)
5548 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5549 /* Perform text mode translation if required. */
5550 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5552 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5553 /* If buffer contains only CR, return that. To be absolutely
5554 sure we should attempt to read the next char, but in
5555 practice a CR to be followed by LF would not appear by
5556 itself in the buffer. */
5557 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5559 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5565 nchars
= _read (fd
, buffer
, count
);
5570 /* From w32xfns.c */
5571 extern HANDLE interrupt_handle
;
5573 /* For now, don't bother with a non-blocking mode */
5575 sys_write (int fd
, const void * buffer
, unsigned int count
)
5585 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5587 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5593 /* Perform text mode translation if required. */
5594 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5596 char * tmpbuf
= alloca (count
* 2);
5597 unsigned char * src
= (void *)buffer
;
5598 unsigned char * dst
= tmpbuf
;
5603 unsigned char *next
;
5604 /* copy next line or remaining bytes */
5605 next
= _memccpy (dst
, src
, '\n', nbytes
);
5608 /* copied one line ending with '\n' */
5609 int copied
= next
- dst
;
5612 /* insert '\r' before '\n' */
5619 /* copied remaining partial line -> now finished */
5626 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5628 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5629 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5630 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5633 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5635 if (GetLastError () != ERROR_IO_PENDING
)
5640 if (detect_input_pending ())
5641 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5644 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5645 if (active
== WAIT_OBJECT_0
)
5646 { /* User pressed C-g, cancel write, then leave. Don't bother
5647 cleaning up as we may only get stuck in buggy drivers. */
5648 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5653 if (active
== WAIT_OBJECT_0
+ 1
5654 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5663 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5665 unsigned long nblock
= 0;
5666 if (winsock_lib
== NULL
) abort ();
5668 /* TODO: implement select() properly so non-blocking I/O works. */
5669 /* For now, make sure the write blocks. */
5670 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5671 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5673 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5675 /* Set the socket back to non-blocking if it was before,
5676 for other operations that support it. */
5677 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5680 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5683 if (nchars
== SOCKET_ERROR
)
5685 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5686 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5693 /* Some networked filesystems don't like too large writes, so
5694 break them into smaller chunks. See the Comments section of
5695 the MSDN documentation of WriteFile for details behind the
5696 choice of the value of CHUNK below. See also the thread
5697 http://thread.gmane.org/gmane.comp.version-control.git/145294
5698 in the git mailing list. */
5699 const unsigned char *p
= buffer
;
5700 const unsigned chunk
= 30 * 1024 * 1024;
5705 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5706 int n
= _write (fd
, p
, this_chunk
);
5714 else if (n
< this_chunk
)
5725 check_windows_init_file (void)
5727 extern int noninteractive
, inhibit_window_system
;
5729 /* A common indication that Emacs is not installed properly is when
5730 it cannot find the Windows installation file. If this file does
5731 not exist in the expected place, tell the user. */
5733 if (!noninteractive
&& !inhibit_window_system
)
5735 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
5736 Lisp_Object objs
[2];
5737 Lisp_Object full_load_path
;
5738 Lisp_Object init_file
;
5741 objs
[0] = Vload_path
;
5742 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5743 full_load_path
= Fappend (2, objs
);
5744 init_file
= build_string ("term/w32-win");
5745 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5748 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5749 char *init_file_name
= SDATA (init_file
);
5750 char *load_path
= SDATA (load_path_print
);
5751 char *buffer
= alloca (1024
5752 + strlen (init_file_name
)
5753 + strlen (load_path
));
5756 "The Emacs Windows initialization file \"%s.el\" "
5757 "could not be found in your Emacs installation. "
5758 "Emacs checked the following directories for this file:\n"
5760 "When Emacs cannot find this file, it usually means that it "
5761 "was not installed properly, or its distribution file was "
5762 "not unpacked properly.\nSee the README.W32 file in the "
5763 "top-level Emacs directory for more information.",
5764 init_file_name
, load_path
);
5767 "Emacs Abort Dialog",
5768 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5769 /* Use the low-level Emacs abort. */
5784 /* shutdown the socket interface if necessary */
5795 /* Initialise the socket interface now if available and requested by
5796 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5797 delayed until open-network-stream is called (w32-has-winsock can
5798 also be used to dynamically load or reload winsock).
5800 Conveniently, init_environment is called before us, so
5801 PRELOAD_WINSOCK can be set in the registry. */
5803 /* Always initialize this correctly. */
5806 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5807 init_winsock (TRUE
);
5810 /* Initial preparation for subprocess support: replace our standard
5811 handles with non-inheritable versions. */
5814 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5815 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5816 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5818 parent
= GetCurrentProcess ();
5820 /* ignore errors when duplicating and closing; typically the
5821 handles will be invalid when running as a gui program. */
5822 DuplicateHandle (parent
,
5823 GetStdHandle (STD_INPUT_HANDLE
),
5828 DUPLICATE_SAME_ACCESS
);
5830 DuplicateHandle (parent
,
5831 GetStdHandle (STD_OUTPUT_HANDLE
),
5836 DUPLICATE_SAME_ACCESS
);
5838 DuplicateHandle (parent
,
5839 GetStdHandle (STD_ERROR_HANDLE
),
5844 DUPLICATE_SAME_ACCESS
);
5850 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5851 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5853 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5856 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5857 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5859 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5862 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5863 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5865 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5869 /* unfortunately, atexit depends on implementation of malloc */
5870 /* atexit (term_ntproc); */
5871 signal (SIGABRT
, term_ntproc
);
5873 /* determine which drives are fixed, for GetCachedVolumeInformation */
5875 /* GetDriveType must have trailing backslash. */
5876 char drive
[] = "A:\\";
5878 /* Loop over all possible drive letters */
5879 while (*drive
<= 'Z')
5881 /* Record if this drive letter refers to a fixed drive. */
5882 fixed_drives
[DRIVE_INDEX (*drive
)] =
5883 (GetDriveType (drive
) == DRIVE_FIXED
);
5888 /* Reset the volume info cache. */
5889 volume_cache
= NULL
;
5892 /* Check to see if Emacs has been installed correctly. */
5893 check_windows_init_file ();
5897 shutdown_handler ensures that buffers' autosave files are
5898 up to date when the user logs off, or the system shuts down.
5901 shutdown_handler (DWORD type
)
5903 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5904 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5905 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5906 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5908 /* Shut down cleanly, making sure autosave files are up to date. */
5909 shut_down_emacs (0, 0, Qnil
);
5912 /* Allow other handlers to handle this signal. */
5917 globals_of_w32 is used to initialize those global variables that
5918 must always be initialized on startup even when the global variable
5919 initialized is non zero (see the function main in emacs.c).
5922 globals_of_w32 (void)
5924 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5926 get_process_times_fn
= (GetProcessTimes_Proc
)
5927 GetProcAddress (kernel32
, "GetProcessTimes");
5929 g_b_init_is_windows_9x
= 0;
5930 g_b_init_open_process_token
= 0;
5931 g_b_init_get_token_information
= 0;
5932 g_b_init_lookup_account_sid
= 0;
5933 g_b_init_get_sid_identifier_authority
= 0;
5934 g_b_init_get_sid_sub_authority
= 0;
5935 g_b_init_get_sid_sub_authority_count
= 0;
5936 g_b_init_get_file_security
= 0;
5937 g_b_init_get_security_descriptor_owner
= 0;
5938 g_b_init_get_security_descriptor_group
= 0;
5939 g_b_init_is_valid_sid
= 0;
5940 g_b_init_create_toolhelp32_snapshot
= 0;
5941 g_b_init_process32_first
= 0;
5942 g_b_init_process32_next
= 0;
5943 g_b_init_open_thread_token
= 0;
5944 g_b_init_impersonate_self
= 0;
5945 g_b_init_revert_to_self
= 0;
5946 g_b_init_get_process_memory_info
= 0;
5947 g_b_init_get_process_working_set_size
= 0;
5948 g_b_init_global_memory_status
= 0;
5949 g_b_init_global_memory_status_ex
= 0;
5950 g_b_init_equal_sid
= 0;
5951 g_b_init_copy_sid
= 0;
5952 g_b_init_get_length_sid
= 0;
5953 g_b_init_get_native_system_info
= 0;
5954 g_b_init_get_system_times
= 0;
5955 num_of_processors
= 0;
5956 /* The following sets a handler for shutdown notifications for
5957 console apps. This actually applies to Emacs in both console and
5958 GUI modes, since we had to fool windows into thinking emacs is a
5959 console application to get console mode to work. */
5960 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
5962 /* "None" is the default group name on standalone workstations. */
5963 strcpy (dflt_group_name
, "None");
5966 /* For make-serial-process */
5968 serial_open (char *port
)
5974 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5975 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5976 if (hnd
== INVALID_HANDLE_VALUE
)
5977 error ("Could not open %s", port
);
5978 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5980 error ("Could not open %s", port
);
5984 error ("Could not create child process");
5986 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5987 fd_info
[ fd
].hnd
= hnd
;
5988 fd_info
[ fd
].flags
|=
5989 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5990 if (fd_info
[ fd
].cp
!= NULL
)
5992 error ("fd_info[fd = %d] is already in use", fd
);
5994 fd_info
[ fd
].cp
= cp
;
5995 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5996 if (cp
->ovl_read
.hEvent
== NULL
)
5997 error ("Could not create read event");
5998 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5999 if (cp
->ovl_write
.hEvent
== NULL
)
6000 error ("Could not create write event");
6005 /* For serial-process-configure */
6007 serial_configure (struct Lisp_Process
*p
,
6008 Lisp_Object contact
)
6010 Lisp_Object childp2
= Qnil
;
6011 Lisp_Object tem
= Qnil
;
6015 char summary
[4] = "???"; /* This usually becomes "8N1". */
6017 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6018 error ("Not a serial process");
6019 hnd
= fd_info
[ p
->outfd
].hnd
;
6021 childp2
= Fcopy_sequence (p
->childp
);
6023 /* Initialize timeouts for blocking read and blocking write. */
6024 if (!GetCommTimeouts (hnd
, &ct
))
6025 error ("GetCommTimeouts() failed");
6026 ct
.ReadIntervalTimeout
= 0;
6027 ct
.ReadTotalTimeoutMultiplier
= 0;
6028 ct
.ReadTotalTimeoutConstant
= 0;
6029 ct
.WriteTotalTimeoutMultiplier
= 0;
6030 ct
.WriteTotalTimeoutConstant
= 0;
6031 if (!SetCommTimeouts (hnd
, &ct
))
6032 error ("SetCommTimeouts() failed");
6033 /* Read port attributes and prepare default configuration. */
6034 memset (&dcb
, 0, sizeof (dcb
));
6035 dcb
.DCBlength
= sizeof (DCB
);
6036 if (!GetCommState (hnd
, &dcb
))
6037 error ("GetCommState() failed");
6040 dcb
.fAbortOnError
= FALSE
;
6041 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6046 /* Configure speed. */
6047 if (!NILP (Fplist_member (contact
, QCspeed
)))
6048 tem
= Fplist_get (contact
, QCspeed
);
6050 tem
= Fplist_get (p
->childp
, QCspeed
);
6052 dcb
.BaudRate
= XINT (tem
);
6053 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6055 /* Configure bytesize. */
6056 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6057 tem
= Fplist_get (contact
, QCbytesize
);
6059 tem
= Fplist_get (p
->childp
, QCbytesize
);
6061 tem
= make_number (8);
6063 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6064 error (":bytesize must be nil (8), 7, or 8");
6065 dcb
.ByteSize
= XINT (tem
);
6066 summary
[0] = XINT (tem
) + '0';
6067 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6069 /* Configure parity. */
6070 if (!NILP (Fplist_member (contact
, QCparity
)))
6071 tem
= Fplist_get (contact
, QCparity
);
6073 tem
= Fplist_get (p
->childp
, QCparity
);
6074 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6075 error (":parity must be nil (no parity), `even', or `odd'");
6076 dcb
.fParity
= FALSE
;
6077 dcb
.Parity
= NOPARITY
;
6078 dcb
.fErrorChar
= FALSE
;
6083 else if (EQ (tem
, Qeven
))
6087 dcb
.Parity
= EVENPARITY
;
6088 dcb
.fErrorChar
= TRUE
;
6090 else if (EQ (tem
, Qodd
))
6094 dcb
.Parity
= ODDPARITY
;
6095 dcb
.fErrorChar
= TRUE
;
6097 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6099 /* Configure stopbits. */
6100 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6101 tem
= Fplist_get (contact
, QCstopbits
);
6103 tem
= Fplist_get (p
->childp
, QCstopbits
);
6105 tem
= make_number (1);
6107 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6108 error (":stopbits must be nil (1 stopbit), 1, or 2");
6109 summary
[2] = XINT (tem
) + '0';
6110 if (XINT (tem
) == 1)
6111 dcb
.StopBits
= ONESTOPBIT
;
6112 else if (XINT (tem
) == 2)
6113 dcb
.StopBits
= TWOSTOPBITS
;
6114 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6116 /* Configure flowcontrol. */
6117 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6118 tem
= Fplist_get (contact
, QCflowcontrol
);
6120 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6121 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6122 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6123 dcb
.fOutxCtsFlow
= FALSE
;
6124 dcb
.fOutxDsrFlow
= FALSE
;
6125 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6126 dcb
.fDsrSensitivity
= FALSE
;
6127 dcb
.fTXContinueOnXoff
= FALSE
;
6130 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6131 dcb
.XonChar
= 17; /* Control-Q */
6132 dcb
.XoffChar
= 19; /* Control-S */
6135 /* Already configured. */
6137 else if (EQ (tem
, Qhw
))
6139 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6140 dcb
.fOutxCtsFlow
= TRUE
;
6142 else if (EQ (tem
, Qsw
))
6147 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6149 /* Activate configuration. */
6150 if (!SetCommState (hnd
, &dcb
))
6151 error ("SetCommState() failed");
6153 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6154 p
->childp
= childp2
;
6159 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6160 (do not change this comment) */