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 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 ();
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 ()
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
))
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 (fp
, path_sep
)
1235 /* Always lower-case drive letters a-z, even if the filesystem
1236 preserves case in filenames.
1237 This is so filenames can be compared by string comparison
1238 functions that are case-sensitive. Even case-preserving filesystems
1239 do not distinguish case in drive letters. */
1240 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1246 if (NILP (Vw32_downcase_file_names
))
1250 if (*fp
== '/' || *fp
== '\\')
1257 sep
= path_sep
; /* convert to this path separator */
1258 elem
= fp
; /* start of current path element */
1261 if (*fp
>= 'a' && *fp
<= 'z')
1262 elem
= 0; /* don't convert this element */
1264 if (*fp
== 0 || *fp
== ':')
1266 sep
= *fp
; /* restore current separator (or 0) */
1267 *fp
= '/'; /* after conversion of this element */
1270 if (*fp
== '/' || *fp
== '\\')
1272 if (elem
&& elem
!= fp
)
1274 *fp
= 0; /* temporary end of string */
1275 _strlwr (elem
); /* while we convert to lower case */
1277 *fp
= sep
; /* convert (or restore) path separator */
1278 elem
= fp
+ 1; /* next element starts after separator */
1284 /* Destructively turn backslashes into slashes. */
1286 dostounix_filename (p
)
1289 normalize_filename (p
, '/');
1292 /* Destructively turn slashes into backslashes. */
1294 unixtodos_filename (p
)
1297 normalize_filename (p
, '\\');
1300 /* Remove all CR's that are followed by a LF.
1301 (From msdos.c...probably should figure out a way to share it,
1302 although this code isn't going to ever change.) */
1306 register unsigned char *buf
;
1308 unsigned char *np
= buf
;
1309 unsigned char *startp
= buf
;
1310 unsigned char *endp
= buf
+ n
;
1314 while (buf
< endp
- 1)
1318 if (*(++buf
) != 0x0a)
1329 /* Parse the root part of file name, if present. Return length and
1330 optionally store pointer to char after root. */
1332 parse_root (char * name
, char ** pPath
)
1334 char * start
= name
;
1339 /* find the root name of the volume if given */
1340 if (isalpha (name
[0]) && name
[1] == ':')
1342 /* skip past drive specifier */
1344 if (IS_DIRECTORY_SEP (name
[0]))
1347 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1353 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1358 if (IS_DIRECTORY_SEP (name
[0]))
1365 return name
- start
;
1368 /* Get long base name for name; name is assumed to be absolute. */
1370 get_long_basename (char * name
, char * buf
, int size
)
1372 WIN32_FIND_DATA find_data
;
1376 /* must be valid filename, no wild cards or other invalid characters */
1377 if (_mbspbrk (name
, "*?|<>\""))
1380 dir_handle
= FindFirstFile (name
, &find_data
);
1381 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1383 if ((len
= strlen (find_data
.cFileName
)) < size
)
1384 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1387 FindClose (dir_handle
);
1392 /* Get long name for file, if possible (assumed to be absolute). */
1394 w32_get_long_filename (char * name
, char * buf
, int size
)
1399 char full
[ MAX_PATH
];
1402 len
= strlen (name
);
1403 if (len
>= MAX_PATH
)
1406 /* Use local copy for destructive modification. */
1407 memcpy (full
, name
, len
+1);
1408 unixtodos_filename (full
);
1410 /* Copy root part verbatim. */
1411 len
= parse_root (full
, &p
);
1412 memcpy (o
, full
, len
);
1417 while (p
!= NULL
&& *p
)
1420 p
= strchr (q
, '\\');
1422 len
= get_long_basename (full
, o
, size
);
1445 is_unc_volume (const char *filename
)
1447 const char *ptr
= filename
;
1449 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1452 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1458 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1461 sigsetmask (int signal_mask
)
1479 sigunblock (int sig
)
1485 setpgrp (int pid
, int gid
)
1496 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1499 w32_get_resource (key
, lpdwtype
)
1504 HKEY hrootkey
= NULL
;
1507 /* Check both the current user and the local machine to see if
1508 we have any resources. */
1510 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1514 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1515 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1516 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1518 RegCloseKey (hrootkey
);
1524 RegCloseKey (hrootkey
);
1527 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1531 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1532 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1533 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1535 RegCloseKey (hrootkey
);
1541 RegCloseKey (hrootkey
);
1547 char *get_emacs_configuration (void);
1548 extern Lisp_Object Vsystem_configuration
;
1551 init_environment (char ** argv
)
1553 static const char * const tempdirs
[] = {
1554 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1559 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1561 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1562 temporary files and assume "/tmp" if $TMPDIR is unset, which
1563 will break on DOS/Windows. Refuse to work if we cannot find
1564 a directory, not even "c:/", usable for that purpose. */
1565 for (i
= 0; i
< imax
; i
++)
1567 const char *tmp
= tempdirs
[i
];
1570 tmp
= getenv (tmp
+ 1);
1571 /* Note that `access' can lie to us if the directory resides on a
1572 read-only filesystem, like CD-ROM or a write-protected floppy.
1573 The only way to be really sure is to actually create a file and
1574 see if it succeeds. But I think that's too much to ask. */
1575 if (tmp
&& _access (tmp
, D_OK
) == 0)
1577 char * var
= alloca (strlen (tmp
) + 8);
1578 sprintf (var
, "TMPDIR=%s", tmp
);
1579 _putenv (strdup (var
));
1586 Fcons (build_string ("no usable temporary directories found!!"),
1588 "While setting TMPDIR: ");
1590 /* Check for environment variables and use registry settings if they
1591 don't exist. Fallback on default values where applicable. */
1596 char locale_name
[32];
1597 struct stat ignored
;
1598 char default_home
[MAX_PATH
];
1600 static const struct env_entry
1607 {"PRELOAD_WINSOCK", NULL
},
1608 {"emacs_dir", "C:/emacs"},
1609 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1610 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1611 {"EMACSDATA", "%emacs_dir%/etc"},
1612 {"EMACSPATH", "%emacs_dir%/bin"},
1613 /* We no longer set INFOPATH because Info-default-directory-list
1615 /* {"INFOPATH", "%emacs_dir%/info"}, */
1616 {"EMACSDOC", "%emacs_dir%/etc"},
1621 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1623 /* We need to copy dflt_envvars[] and work on the copy because we
1624 don't want the dumped Emacs to inherit the values of
1625 environment variables we saw during dumping (which could be on
1626 a different system). The defaults above must be left intact. */
1627 struct env_entry env_vars
[N_ENV_VARS
];
1629 for (i
= 0; i
< N_ENV_VARS
; i
++)
1630 env_vars
[i
] = dflt_envvars
[i
];
1632 /* For backwards compatibility, check if a .emacs file exists in C:/
1633 If not, then we can try to default to the appdata directory under the
1634 user's profile, which is more likely to be writable. */
1635 if (stat ("C:/.emacs", &ignored
) < 0)
1637 HRESULT profile_result
;
1638 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1639 of Windows 95 and NT4 that have not been updated to include
1641 ShGetFolderPath_fn get_folder_path
;
1642 get_folder_path
= (ShGetFolderPath_fn
)
1643 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1645 if (get_folder_path
!= NULL
)
1647 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1650 /* If we can't get the appdata dir, revert to old behavior. */
1651 if (profile_result
== S_OK
)
1652 env_vars
[0].def_value
= default_home
;
1656 /* Get default locale info and use it for LANG. */
1657 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1658 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1659 locale_name
, sizeof (locale_name
)))
1661 for (i
= 0; i
< N_ENV_VARS
; i
++)
1663 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1665 env_vars
[i
].def_value
= locale_name
;
1671 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1673 /* Treat emacs_dir specially: set it unconditionally based on our
1674 location, if it appears that we are running from the bin subdir
1675 of a standard installation. */
1678 char modname
[MAX_PATH
];
1680 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1682 if ((p
= strrchr (modname
, '\\')) == NULL
)
1686 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1688 char buf
[SET_ENV_BUF_SIZE
];
1691 for (p
= modname
; *p
; p
++)
1692 if (*p
== '\\') *p
= '/';
1694 _snprintf (buf
, sizeof(buf
)-1, "emacs_dir=%s", modname
);
1695 _putenv (strdup (buf
));
1697 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1699 /* FIXME: should use substring of get_emacs_configuration ().
1700 But I don't think the Windows build supports alpha, mips etc
1701 anymore, so have taken the easy option for now. */
1702 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1705 p
= strrchr (modname
, '\\');
1709 p
= strrchr (modname
, '\\');
1710 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1712 char buf
[SET_ENV_BUF_SIZE
];
1715 for (p
= modname
; *p
; p
++)
1716 if (*p
== '\\') *p
= '/';
1718 _snprintf (buf
, sizeof(buf
)-1, "emacs_dir=%s", modname
);
1719 _putenv (strdup (buf
));
1725 for (i
= 0; i
< N_ENV_VARS
; i
++)
1727 if (!getenv (env_vars
[i
].name
))
1731 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1732 /* Also ignore empty environment variables. */
1736 lpval
= env_vars
[i
].def_value
;
1737 dwType
= REG_EXPAND_SZ
;
1743 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1745 if (dwType
== REG_EXPAND_SZ
)
1746 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof(buf1
));
1747 else if (dwType
== REG_SZ
)
1748 strcpy (buf1
, lpval
);
1749 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1751 _snprintf (buf2
, sizeof(buf2
)-1, "%s=%s", env_vars
[i
].name
,
1753 _putenv (strdup (buf2
));
1763 /* Rebuild system configuration to reflect invoking system. */
1764 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1766 /* Another special case: on NT, the PATH variable is actually named
1767 "Path" although cmd.exe (perhaps NT itself) arranges for
1768 environment variable lookup and setting to be case insensitive.
1769 However, Emacs assumes a fully case sensitive environment, so we
1770 need to change "Path" to "PATH" to match the expectations of
1771 various elisp packages. We do this by the sneaky method of
1772 modifying the string in the C runtime environ entry.
1774 The same applies to COMSPEC. */
1778 for (envp
= environ
; *envp
; envp
++)
1779 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1780 memcpy (*envp
, "PATH=", 5);
1781 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1782 memcpy (*envp
, "COMSPEC=", 8);
1785 /* Remember the initial working directory for getwd, then make the
1786 real wd be the location of emacs.exe to avoid conflicts when
1787 renaming or deleting directories. (We also don't call chdir when
1788 running subprocesses for the same reason.) */
1789 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1794 static char modname
[MAX_PATH
];
1796 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1798 if ((p
= strrchr (modname
, '\\')) == NULL
)
1802 SetCurrentDirectory (modname
);
1804 /* Ensure argv[0] has the full path to Emacs. */
1809 /* Determine if there is a middle mouse button, to allow parse_button
1810 to decide whether right mouse events should be mouse-2 or
1812 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1818 emacs_root_dir (void)
1820 static char root_dir
[FILENAME_MAX
];
1823 p
= getenv ("emacs_dir");
1826 strcpy (root_dir
, p
);
1827 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1828 dostounix_filename (root_dir
);
1832 /* We don't have scripts to automatically determine the system configuration
1833 for Emacs before it's compiled, and we don't want to have to make the
1834 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1838 get_emacs_configuration (void)
1840 char *arch
, *oem
, *os
;
1842 static char configuration_buffer
[32];
1844 /* Determine the processor type. */
1845 switch (get_processor_type ())
1848 #ifdef PROCESSOR_INTEL_386
1849 case PROCESSOR_INTEL_386
:
1850 case PROCESSOR_INTEL_486
:
1851 case PROCESSOR_INTEL_PENTIUM
:
1856 #ifdef PROCESSOR_MIPS_R2000
1857 case PROCESSOR_MIPS_R2000
:
1858 case PROCESSOR_MIPS_R3000
:
1859 case PROCESSOR_MIPS_R4000
:
1864 #ifdef PROCESSOR_ALPHA_21064
1865 case PROCESSOR_ALPHA_21064
:
1875 /* Use the OEM field to reflect the compiler/library combination. */
1877 #define COMPILER_NAME "msvc"
1880 #define COMPILER_NAME "mingw"
1882 #define COMPILER_NAME "unknown"
1885 oem
= COMPILER_NAME
;
1887 switch (osinfo_cache
.dwPlatformId
) {
1888 case VER_PLATFORM_WIN32_NT
:
1890 build_num
= osinfo_cache
.dwBuildNumber
;
1892 case VER_PLATFORM_WIN32_WINDOWS
:
1893 if (osinfo_cache
.dwMinorVersion
== 0) {
1898 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1900 case VER_PLATFORM_WIN32s
:
1901 /* Not supported, should not happen. */
1903 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1911 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1912 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1913 get_w32_major_version (), get_w32_minor_version (), build_num
);
1915 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1918 return configuration_buffer
;
1922 get_emacs_configuration_options (void)
1924 static char options_buffer
[256];
1926 /* Work out the effective configure options for this build. */
1928 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1931 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1933 #define COMPILER_VERSION ""
1937 sprintf (options_buffer
, COMPILER_VERSION
);
1939 strcat (options_buffer
, " --no-opt");
1942 strcat (options_buffer
, " --cflags");
1943 strcat (options_buffer
, USER_CFLAGS
);
1946 strcat (options_buffer
, " --ldflags");
1947 strcat (options_buffer
, USER_LDFLAGS
);
1949 return options_buffer
;
1953 #include <sys/timeb.h>
1955 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1957 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1962 tv
->tv_sec
= tb
.time
;
1963 tv
->tv_usec
= tb
.millitm
* 1000L;
1966 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1967 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1971 /* ------------------------------------------------------------------------- */
1972 /* IO support and wrapper functions for W32 API. */
1973 /* ------------------------------------------------------------------------- */
1975 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1976 on network directories, so we handle that case here.
1977 (Ulrich Leodolter, 1/11/95). */
1979 sys_ctime (const time_t *t
)
1981 char *str
= (char *) ctime (t
);
1982 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1985 /* Emulate sleep...we could have done this with a define, but that
1986 would necessitate including windows.h in the files that used it.
1987 This is much easier. */
1989 sys_sleep (int seconds
)
1991 Sleep (seconds
* 1000);
1994 /* Internal MSVC functions for low-level descriptor munging */
1995 extern int __cdecl
_set_osfhnd (int fd
, long h
);
1996 extern int __cdecl
_free_osfhnd (int fd
);
1998 /* parallel array of private info on file handles */
1999 filedesc fd_info
[ MAXDESC
];
2001 typedef struct volume_info_data
{
2002 struct volume_info_data
* next
;
2004 /* time when info was obtained */
2007 /* actual volume info */
2016 /* Global referenced by various functions. */
2017 static volume_info_data volume_info
;
2019 /* Vector to indicate which drives are local and fixed (for which cached
2020 data never expires). */
2021 static BOOL fixed_drives
[26];
2023 /* Consider cached volume information to be stale if older than 10s,
2024 at least for non-local drives. Info for fixed drives is never stale. */
2025 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2026 #define VOLINFO_STILL_VALID( root_dir, info ) \
2027 ( ( isalpha (root_dir[0]) && \
2028 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2029 || GetTickCount () - info->timestamp < 10000 )
2031 /* Cache support functions. */
2033 /* Simple linked list with linear search is sufficient. */
2034 static volume_info_data
*volume_cache
= NULL
;
2036 static volume_info_data
*
2037 lookup_volume_info (char * root_dir
)
2039 volume_info_data
* info
;
2041 for (info
= volume_cache
; info
; info
= info
->next
)
2042 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2048 add_volume_info (char * root_dir
, volume_info_data
* info
)
2050 info
->root_dir
= xstrdup (root_dir
);
2051 info
->next
= volume_cache
;
2052 volume_cache
= info
;
2056 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2057 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2058 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2060 GetCachedVolumeInformation (char * root_dir
)
2062 volume_info_data
* info
;
2063 char default_root
[ MAX_PATH
];
2065 /* NULL for root_dir means use root from current directory. */
2066 if (root_dir
== NULL
)
2068 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2070 parse_root (default_root
, &root_dir
);
2072 root_dir
= default_root
;
2075 /* Local fixed drives can be cached permanently. Removable drives
2076 cannot be cached permanently, since the volume name and serial
2077 number (if nothing else) can change. Remote drives should be
2078 treated as if they are removable, since there is no sure way to
2079 tell whether they are or not. Also, the UNC association of drive
2080 letters mapped to remote volumes can be changed at any time (even
2081 by other processes) without notice.
2083 As a compromise, so we can benefit from caching info for remote
2084 volumes, we use a simple expiry mechanism to invalidate cache
2085 entries that are more than ten seconds old. */
2088 /* No point doing this, because WNetGetConnection is even slower than
2089 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2090 GetDriveType is about the only call of this type which does not
2091 involve network access, and so is extremely quick). */
2093 /* Map drive letter to UNC if remote. */
2094 if ( isalpha( root_dir
[0] ) && !fixed
[ DRIVE_INDEX( root_dir
[0] ) ] )
2096 char remote_name
[ 256 ];
2097 char drive
[3] = { root_dir
[0], ':' };
2099 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2101 /* do something */ ;
2105 info
= lookup_volume_info (root_dir
);
2107 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2115 /* Info is not cached, or is stale. */
2116 if (!GetVolumeInformation (root_dir
,
2117 name
, sizeof (name
),
2121 type
, sizeof (type
)))
2124 /* Cache the volume information for future use, overwriting existing
2125 entry if present. */
2128 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2129 add_volume_info (root_dir
, info
);
2137 info
->name
= xstrdup (name
);
2138 info
->serialnum
= serialnum
;
2139 info
->maxcomp
= maxcomp
;
2140 info
->flags
= flags
;
2141 info
->type
= xstrdup (type
);
2142 info
->timestamp
= GetTickCount ();
2148 /* Get information on the volume where name is held; set path pointer to
2149 start of pathname in name (past UNC header\volume header if present). */
2151 get_volume_info (const char * name
, const char ** pPath
)
2153 char temp
[MAX_PATH
];
2154 char *rootname
= NULL
; /* default to current volume */
2155 volume_info_data
* info
;
2160 /* find the root name of the volume if given */
2161 if (isalpha (name
[0]) && name
[1] == ':')
2169 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2176 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2189 info
= GetCachedVolumeInformation (rootname
);
2192 /* Set global referenced by other functions. */
2193 volume_info
= *info
;
2199 /* Determine if volume is FAT format (ie. only supports short 8.3
2200 names); also set path pointer to start of pathname in name. */
2202 is_fat_volume (const char * name
, const char ** pPath
)
2204 if (get_volume_info (name
, pPath
))
2205 return (volume_info
.maxcomp
== 12);
2209 /* Map filename to a valid 8.3 name if necessary. */
2211 map_w32_filename (const char * name
, const char ** pPath
)
2213 static char shortname
[MAX_PATH
];
2214 char * str
= shortname
;
2217 const char * save_name
= name
;
2219 if (strlen (name
) >= MAX_PATH
)
2221 /* Return a filename which will cause callers to fail. */
2222 strcpy (shortname
, "?");
2226 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2228 register int left
= 8; /* maximum number of chars in part */
2229 register int extn
= 0; /* extension added? */
2230 register int dots
= 2; /* maximum number of dots allowed */
2233 *str
++ = *name
++; /* skip past UNC header */
2235 while ((c
= *name
++))
2242 extn
= 0; /* reset extension flags */
2243 dots
= 2; /* max 2 dots */
2244 left
= 8; /* max length 8 for main part */
2248 extn
= 0; /* reset extension flags */
2249 dots
= 2; /* max 2 dots */
2250 left
= 8; /* max length 8 for main part */
2255 /* Convert path components of the form .xxx to _xxx,
2256 but leave . and .. as they are. This allows .emacs
2257 to be read as _emacs, for example. */
2261 IS_DIRECTORY_SEP (*name
))
2276 extn
= 1; /* we've got an extension */
2277 left
= 3; /* 3 chars in extension */
2281 /* any embedded dots after the first are converted to _ */
2286 case '#': /* don't lose these, they're important */
2288 str
[-1] = c
; /* replace last character of part */
2293 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2295 dots
= 0; /* started a path component */
2304 strcpy (shortname
, name
);
2305 unixtodos_filename (shortname
);
2309 *pPath
= shortname
+ (path
- save_name
);
2315 is_exec (const char * name
)
2317 char * p
= strrchr (name
, '.');
2320 && (xstrcasecmp (p
, ".exe") == 0 ||
2321 xstrcasecmp (p
, ".com") == 0 ||
2322 xstrcasecmp (p
, ".bat") == 0 ||
2323 xstrcasecmp (p
, ".cmd") == 0));
2326 /* Emulate the Unix directory procedures opendir, closedir,
2327 and readdir. We can't use the procedures supplied in sysdep.c,
2328 so we provide them here. */
2330 struct direct dir_static
; /* simulated directory contents */
2331 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2332 static int dir_is_fat
;
2333 static char dir_pathname
[MAXPATHLEN
+1];
2334 static WIN32_FIND_DATA dir_find_data
;
2336 /* Support shares on a network resource as subdirectories of a read-only
2338 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2339 HANDLE
open_unc_volume (const char *);
2340 char *read_unc_volume (HANDLE
, char *, int);
2341 void close_unc_volume (HANDLE
);
2344 opendir (char *filename
)
2348 /* Opening is done by FindFirstFile. However, a read is inherent to
2349 this operation, so we defer the open until read time. */
2351 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2353 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2356 if (is_unc_volume (filename
))
2358 wnet_enum_handle
= open_unc_volume (filename
);
2359 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2363 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2370 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2371 dir_pathname
[MAXPATHLEN
] = '\0';
2372 dir_is_fat
= is_fat_volume (filename
, NULL
);
2378 closedir (DIR *dirp
)
2380 /* If we have a find-handle open, close it. */
2381 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2383 FindClose (dir_find_handle
);
2384 dir_find_handle
= INVALID_HANDLE_VALUE
;
2386 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2388 close_unc_volume (wnet_enum_handle
);
2389 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2391 xfree ((char *) dirp
);
2397 int downcase
= !NILP (Vw32_downcase_file_names
);
2399 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2401 if (!read_unc_volume (wnet_enum_handle
,
2402 dir_find_data
.cFileName
,
2406 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2407 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2409 char filename
[MAXNAMLEN
+ 3];
2412 strcpy (filename
, dir_pathname
);
2413 ln
= strlen (filename
) - 1;
2414 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2415 strcat (filename
, "\\");
2416 strcat (filename
, "*");
2418 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2420 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2425 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2429 /* Emacs never uses this value, so don't bother making it match
2430 value returned by stat(). */
2431 dir_static
.d_ino
= 1;
2433 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2435 /* If the file name in cFileName[] includes `?' characters, it means
2436 the original file name used characters that cannot be represented
2437 by the current ANSI codepage. To avoid total lossage, retrieve
2438 the short 8+3 alias of the long file name. */
2439 if (_mbspbrk (dir_static
.d_name
, "?"))
2441 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2442 downcase
= 1; /* 8+3 aliases are returned in all caps */
2444 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2445 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2446 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2448 /* If the file name in cFileName[] includes `?' characters, it means
2449 the original file name used characters that cannot be represented
2450 by the current ANSI codepage. To avoid total lossage, retrieve
2451 the short 8+3 alias of the long file name. */
2452 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2454 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2455 /* 8+3 aliases are returned in all caps, which could break
2456 various alists that look at filenames' extensions. */
2460 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2461 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2463 _strlwr (dir_static
.d_name
);
2467 for (p
= dir_static
.d_name
; *p
; p
++)
2468 if (*p
>= 'a' && *p
<= 'z')
2471 _strlwr (dir_static
.d_name
);
2478 open_unc_volume (const char *path
)
2484 nr
.dwScope
= RESOURCE_GLOBALNET
;
2485 nr
.dwType
= RESOURCETYPE_DISK
;
2486 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2487 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2488 nr
.lpLocalName
= NULL
;
2489 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2490 nr
.lpComment
= NULL
;
2491 nr
.lpProvider
= NULL
;
2493 result
= WNetOpenEnum(RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2494 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2496 if (result
== NO_ERROR
)
2499 return INVALID_HANDLE_VALUE
;
2503 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2507 DWORD bufsize
= 512;
2512 buffer
= alloca (bufsize
);
2513 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2514 if (result
!= NO_ERROR
)
2517 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2518 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2520 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2523 strncpy (readbuf
, ptr
, size
);
2528 close_unc_volume (HANDLE henum
)
2530 if (henum
!= INVALID_HANDLE_VALUE
)
2531 WNetCloseEnum (henum
);
2535 unc_volume_file_attributes (const char *path
)
2540 henum
= open_unc_volume (path
);
2541 if (henum
== INVALID_HANDLE_VALUE
)
2544 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2546 close_unc_volume (henum
);
2551 /* Ensure a network connection is authenticated. */
2553 logon_network_drive (const char *path
)
2555 NETRESOURCE resource
;
2556 char share
[MAX_PATH
];
2561 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2562 drvtype
= DRIVE_REMOTE
;
2563 else if (path
[0] == '\0' || path
[1] != ':')
2564 drvtype
= GetDriveType (NULL
);
2571 drvtype
= GetDriveType (drive
);
2574 /* Only logon to networked drives. */
2575 if (drvtype
!= DRIVE_REMOTE
)
2579 strncpy (share
, path
, MAX_PATH
);
2580 /* Truncate to just server and share name. */
2581 for (i
= 2; i
< MAX_PATH
; i
++)
2583 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2590 resource
.dwType
= RESOURCETYPE_DISK
;
2591 resource
.lpLocalName
= NULL
;
2592 resource
.lpRemoteName
= share
;
2593 resource
.lpProvider
= NULL
;
2595 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2598 /* Shadow some MSVC runtime functions to map requests for long filenames
2599 to reasonable short names if necessary. This was originally added to
2600 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2604 sys_access (const char * path
, int mode
)
2608 /* MSVC implementation doesn't recognize D_OK. */
2609 path
= map_w32_filename (path
, NULL
);
2610 if (is_unc_volume (path
))
2612 attributes
= unc_volume_file_attributes (path
);
2613 if (attributes
== -1) {
2618 else if ((attributes
= GetFileAttributes (path
)) == -1)
2620 /* Should try mapping GetLastError to errno; for now just indicate
2621 that path doesn't exist. */
2625 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2630 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2635 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2644 sys_chdir (const char * path
)
2646 return _chdir (map_w32_filename (path
, NULL
));
2650 sys_chmod (const char * path
, int mode
)
2652 return _chmod (map_w32_filename (path
, NULL
), mode
);
2656 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2658 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2664 sys_creat (const char * path
, int mode
)
2666 return _creat (map_w32_filename (path
, NULL
), mode
);
2670 sys_fopen(const char * path
, const char * mode
)
2674 const char * mode_save
= mode
;
2676 /* Force all file handles to be non-inheritable. This is necessary to
2677 ensure child processes don't unwittingly inherit handles that might
2678 prevent future file access. */
2682 else if (mode
[0] == 'w' || mode
[0] == 'a')
2683 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2687 /* Only do simplistic option parsing. */
2691 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2694 else if (mode
[0] == 'b')
2699 else if (mode
[0] == 't')
2706 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2710 return _fdopen (fd
, mode_save
);
2713 /* This only works on NTFS volumes, but is useful to have. */
2715 sys_link (const char * old
, const char * new)
2719 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2721 if (old
== NULL
|| new == NULL
)
2727 strcpy (oldname
, map_w32_filename (old
, NULL
));
2728 strcpy (newname
, map_w32_filename (new, NULL
));
2730 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2731 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2732 if (fileh
!= INVALID_HANDLE_VALUE
)
2736 /* Confusingly, the "alternate" stream name field does not apply
2737 when restoring a hard link, and instead contains the actual
2738 stream data for the link (ie. the name of the link to create).
2739 The WIN32_STREAM_ID structure before the cStreamName field is
2740 the stream header, which is then immediately followed by the
2744 WIN32_STREAM_ID wid
;
2745 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2748 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2749 data
.wid
.cStreamName
, MAX_PATH
);
2752 LPVOID context
= NULL
;
2755 data
.wid
.dwStreamId
= BACKUP_LINK
;
2756 data
.wid
.dwStreamAttributes
= 0;
2757 data
.wid
.Size
.LowPart
= wlen
* sizeof(WCHAR
);
2758 data
.wid
.Size
.HighPart
= 0;
2759 data
.wid
.dwStreamNameSize
= 0;
2761 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2762 offsetof (WIN32_STREAM_ID
, cStreamName
)
2763 + data
.wid
.Size
.LowPart
,
2764 &wbytes
, FALSE
, FALSE
, &context
)
2765 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2772 /* Should try mapping GetLastError to errno; for now just
2773 indicate a general error (eg. links not supported). */
2774 errno
= EINVAL
; // perhaps EMLINK?
2778 CloseHandle (fileh
);
2787 sys_mkdir (const char * path
)
2789 return _mkdir (map_w32_filename (path
, NULL
));
2792 /* Because of long name mapping issues, we need to implement this
2793 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2794 a unique name, instead of setting the input template to an empty
2797 Standard algorithm seems to be use pid or tid with a letter on the
2798 front (in place of the 6 X's) and cycle through the letters to find a
2799 unique name. We extend that to allow any reasonable character as the
2800 first of the 6 X's. */
2802 sys_mktemp (char * template)
2806 unsigned uid
= GetCurrentThreadId ();
2807 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2809 if (template == NULL
)
2811 p
= template + strlen (template);
2813 /* replace up to the last 5 X's with uid in decimal */
2814 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2816 p
[0] = '0' + uid
% 10;
2820 if (i
< 0 && p
[0] == 'X')
2825 int save_errno
= errno
;
2826 p
[0] = first_char
[i
];
2827 if (sys_access (template, 0) < 0)
2833 while (++i
< sizeof (first_char
));
2836 /* Template is badly formed or else we can't generate a unique name,
2837 so return empty string */
2843 sys_open (const char * path
, int oflag
, int mode
)
2845 const char* mpath
= map_w32_filename (path
, NULL
);
2846 /* Try to open file without _O_CREAT, to be able to write to hidden
2847 and system files. Force all file handles to be
2849 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2852 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2856 sys_rename (const char * oldname
, const char * newname
)
2859 char temp
[MAX_PATH
];
2861 /* MoveFile on Windows 95 doesn't correctly change the short file name
2862 alias in a number of circumstances (it is not easy to predict when
2863 just by looking at oldname and newname, unfortunately). In these
2864 cases, renaming through a temporary name avoids the problem.
2866 A second problem on Windows 95 is that renaming through a temp name when
2867 newname is uppercase fails (the final long name ends up in
2868 lowercase, although the short alias might be uppercase) UNLESS the
2869 long temp name is not 8.3.
2871 So, on Windows 95 we always rename through a temp name, and we make sure
2872 the temp name has a long extension to ensure correct renaming. */
2874 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2876 if (os_subtype
== OS_WIN95
)
2882 oldname
= map_w32_filename (oldname
, NULL
);
2883 if (o
= strrchr (oldname
, '\\'))
2886 o
= (char *) oldname
;
2888 if (p
= strrchr (temp
, '\\'))
2895 /* Force temp name to require a manufactured 8.3 alias - this
2896 seems to make the second rename work properly. */
2897 sprintf (p
, "_.%s.%u", o
, i
);
2899 result
= rename (oldname
, temp
);
2901 /* This loop must surely terminate! */
2902 while (result
< 0 && errno
== EEXIST
);
2907 /* Emulate Unix behavior - newname is deleted if it already exists
2908 (at least if it is a file; don't do this for directories).
2910 Since we mustn't do this if we are just changing the case of the
2911 file name (we would end up deleting the file we are trying to
2912 rename!), we let rename detect if the destination file already
2913 exists - that way we avoid the possible pitfalls of trying to
2914 determine ourselves whether two names really refer to the same
2915 file, which is not always possible in the general case. (Consider
2916 all the permutations of shared or subst'd drives, etc.) */
2918 newname
= map_w32_filename (newname
, NULL
);
2919 result
= rename (temp
, newname
);
2923 && _chmod (newname
, 0666) == 0
2924 && _unlink (newname
) == 0)
2925 result
= rename (temp
, newname
);
2931 sys_rmdir (const char * path
)
2933 return _rmdir (map_w32_filename (path
, NULL
));
2937 sys_unlink (const char * path
)
2939 path
= map_w32_filename (path
, NULL
);
2941 /* On Unix, unlink works without write permission. */
2942 _chmod (path
, 0666);
2943 return _unlink (path
);
2946 static FILETIME utc_base_ft
;
2947 static ULONGLONG utc_base
; /* In 100ns units */
2948 static int init
= 0;
2950 #define FILETIME_TO_U64(result, ft) \
2952 ULARGE_INTEGER uiTemp; \
2953 uiTemp.LowPart = (ft).dwLowDateTime; \
2954 uiTemp.HighPart = (ft).dwHighDateTime; \
2955 result = uiTemp.QuadPart; \
2959 initialize_utc_base ()
2961 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2970 st
.wMilliseconds
= 0;
2972 SystemTimeToFileTime (&st
, &utc_base_ft
);
2973 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2977 convert_time (FILETIME ft
)
2983 initialize_utc_base();
2987 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2990 FILETIME_TO_U64 (tmp
, ft
);
2991 return (time_t) ((tmp
- utc_base
) / 10000000L);
2996 convert_from_time_t (time_t time
, FILETIME
* pft
)
3002 initialize_utc_base ();
3006 /* time in 100ns units since 1-Jan-1601 */
3007 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3008 pft
->dwHighDateTime
= tmp
.HighPart
;
3009 pft
->dwLowDateTime
= tmp
.LowPart
;
3013 /* No reason to keep this; faking inode values either by hashing or even
3014 using the file index from GetInformationByHandle, is not perfect and
3015 so by default Emacs doesn't use the inode values on Windows.
3016 Instead, we now determine file-truename correctly (except for
3017 possible drive aliasing etc). */
3019 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3021 hashval (const unsigned char * str
)
3026 h
= (h
<< 4) + *str
++;
3032 /* Return the hash value of the canonical pathname, excluding the
3033 drive/UNC header, to get a hopefully unique inode number. */
3035 generate_inode_val (const char * name
)
3037 char fullname
[ MAX_PATH
];
3041 /* Get the truly canonical filename, if it exists. (Note: this
3042 doesn't resolve aliasing due to subst commands, or recognise hard
3044 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3047 parse_root (fullname
, &p
);
3048 /* Normal W32 filesystems are still case insensitive. */
3055 static PSECURITY_DESCRIPTOR
3056 get_file_security_desc (const char *fname
)
3058 PSECURITY_DESCRIPTOR psd
= NULL
;
3060 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3061 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3063 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3065 err
= GetLastError ();
3066 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3070 psd
= xmalloc (sd_len
);
3071 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3083 unsigned n_subauthorities
;
3085 /* Use the last sub-authority value of the RID, the relative
3086 portion of the SID, as user/group ID. */
3087 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3088 if (n_subauthorities
< 1)
3089 return 0; /* the "World" RID */
3090 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3093 /* Caching SID and account values for faster lokup. */
3096 # define FLEXIBLE_ARRAY_MEMBER
3098 # define FLEXIBLE_ARRAY_MEMBER 1
3103 struct w32_id
*next
;
3105 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3108 static struct w32_id
*w32_idlist
;
3111 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3113 struct w32_id
*tail
, *found
;
3115 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3117 if (equal_sid ((PSID
)tail
->sid
, sid
))
3126 strcpy (name
, found
->name
);
3134 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3137 struct w32_id
*new_entry
;
3139 /* We don't want to leave behind stale cache from when Emacs was
3143 sid_len
= get_length_sid (sid
);
3144 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3147 new_entry
->rid
= id
;
3148 strcpy (new_entry
->name
, name
);
3149 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3150 new_entry
->next
= w32_idlist
;
3151 w32_idlist
= new_entry
;
3160 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3161 unsigned *id
, char *nm
, int what
)
3164 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3166 SID_NAME_USE ignore
;
3168 DWORD name_len
= sizeof (name
);
3170 DWORD domain_len
= sizeof(domain
);
3176 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3177 else if (what
== GID
)
3178 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3182 if (!result
|| !is_valid_sid (sid
))
3184 else if (!w32_cached_id (sid
, id
, nm
))
3186 /* If FNAME is a UNC, we need to lookup account on the
3187 specified machine. */
3188 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3189 && fname
[2] != '\0')
3194 for (s
= fname
+ 2, p
= machine
;
3195 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3201 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3202 domain
, &domain_len
, &ignore
)
3203 || name_len
> UNLEN
+1)
3207 *id
= get_rid (sid
);
3209 w32_add_to_cache (sid
, *id
, name
);
3216 get_file_owner_and_group (
3217 PSECURITY_DESCRIPTOR psd
,
3221 int dflt_usr
= 0, dflt_grp
= 0;
3230 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3232 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3235 /* Consider files to belong to current user/group, if we cannot get
3236 more accurate information. */
3239 st
->st_uid
= dflt_passwd
.pw_uid
;
3240 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3244 st
->st_gid
= dflt_passwd
.pw_gid
;
3245 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3249 /* Return non-zero if NAME is a potentially slow filesystem. */
3251 is_slow_fs (const char *name
)
3256 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3257 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3258 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3259 devtype
= GetDriveType (NULL
); /* use root of current drive */
3262 /* GetDriveType needs the root directory of the drive. */
3263 strncpy (drive_root
, name
, 2);
3264 drive_root
[2] = '\\';
3265 drive_root
[3] = '\0';
3266 devtype
= GetDriveType (drive_root
);
3268 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3271 /* MSVC stat function can't cope with UNC names and has other bugs, so
3272 replace it with our own. This also allows us to calculate consistent
3273 inode values without hacks in the main Emacs code. */
3275 stat (const char * path
, struct stat
* buf
)
3280 WIN32_FIND_DATA wfd
;
3282 unsigned __int64 fake_inode
;
3285 int rootdir
= FALSE
;
3286 PSECURITY_DESCRIPTOR psd
= NULL
;
3288 if (path
== NULL
|| buf
== NULL
)
3294 name
= (char *) map_w32_filename (path
, &path
);
3295 /* Must be valid filename, no wild cards or other invalid
3296 characters. We use _mbspbrk to support multibyte strings that
3297 might look to strpbrk as if they included literal *, ?, and other
3298 characters mentioned below that are disallowed by Windows
3300 if (_mbspbrk (name
, "*?|<>\""))
3306 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3307 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3308 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3313 /* Remove trailing directory separator, unless name is the root
3314 directory of a drive or UNC volume in which case ensure there
3315 is a trailing separator. */
3316 len
= strlen (name
);
3317 rootdir
= (path
>= name
+ len
- 1
3318 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3319 name
= strcpy (alloca (len
+ 2), name
);
3321 if (is_unc_volume (name
))
3323 DWORD attrs
= unc_volume_file_attributes (name
);
3328 memset (&wfd
, 0, sizeof (wfd
));
3329 wfd
.dwFileAttributes
= attrs
;
3330 wfd
.ftCreationTime
= utc_base_ft
;
3331 wfd
.ftLastAccessTime
= utc_base_ft
;
3332 wfd
.ftLastWriteTime
= utc_base_ft
;
3333 strcpy (wfd
.cFileName
, name
);
3337 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3338 strcat (name
, "\\");
3339 if (GetDriveType (name
) < 2)
3344 memset (&wfd
, 0, sizeof (wfd
));
3345 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
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]))
3356 /* (This is hacky, but helps when doing file completions on
3357 network drives.) Optimize by using information available from
3358 active readdir if possible. */
3359 len
= strlen (dir_pathname
);
3360 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3362 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3363 && strnicmp (name
, dir_pathname
, len
) == 0
3364 && IS_DIRECTORY_SEP (name
[len
])
3365 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3367 /* This was the last entry returned by readdir. */
3368 wfd
= dir_find_data
;
3372 logon_network_drive (name
);
3374 fh
= FindFirstFile (name
, &wfd
);
3375 if (fh
== INVALID_HANDLE_VALUE
)
3384 if (!(NILP (Vw32_get_true_file_attributes
)
3385 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3386 /* No access rights required to get info. */
3387 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3388 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3389 != INVALID_HANDLE_VALUE
)
3391 /* This is more accurate in terms of gettting the correct number
3392 of links, but is quite slow (it is noticeable when Emacs is
3393 making a list of file name completions). */
3394 BY_HANDLE_FILE_INFORMATION info
;
3396 if (GetFileInformationByHandle (fh
, &info
))
3398 buf
->st_nlink
= info
.nNumberOfLinks
;
3399 /* Might as well use file index to fake inode values, but this
3400 is not guaranteed to be unique unless we keep a handle open
3401 all the time (even then there are situations where it is
3402 not unique). Reputedly, there are at most 48 bits of info
3403 (on NTFS, presumably less on FAT). */
3404 fake_inode
= info
.nFileIndexHigh
;
3406 fake_inode
+= info
.nFileIndexLow
;
3414 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3416 buf
->st_mode
= S_IFDIR
;
3420 switch (GetFileType (fh
))
3422 case FILE_TYPE_DISK
:
3423 buf
->st_mode
= S_IFREG
;
3425 case FILE_TYPE_PIPE
:
3426 buf
->st_mode
= S_IFIFO
;
3428 case FILE_TYPE_CHAR
:
3429 case FILE_TYPE_UNKNOWN
:
3431 buf
->st_mode
= S_IFCHR
;
3435 psd
= get_file_security_desc (name
);
3436 get_file_owner_and_group (psd
, name
, buf
);
3440 /* Don't bother to make this information more accurate. */
3441 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3446 get_file_owner_and_group (NULL
, name
, buf
);
3451 /* Not sure if there is any point in this. */
3452 if (!NILP (Vw32_generate_fake_inodes
))
3453 fake_inode
= generate_inode_val (name
);
3454 else if (fake_inode
== 0)
3456 /* For want of something better, try to make everything unique. */
3457 static DWORD gen_num
= 0;
3458 fake_inode
= ++gen_num
;
3462 /* MSVC defines _ino_t to be short; other libc's might not. */
3463 if (sizeof (buf
->st_ino
) == 2)
3464 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3466 buf
->st_ino
= fake_inode
;
3468 /* volume_info is set indirectly by map_w32_filename */
3469 buf
->st_dev
= volume_info
.serialnum
;
3470 buf
->st_rdev
= volume_info
.serialnum
;
3473 buf
->st_size
= wfd
.nFileSizeHigh
;
3474 buf
->st_size
<<= 32;
3475 buf
->st_size
+= wfd
.nFileSizeLow
;
3477 /* Convert timestamps to Unix format. */
3478 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3479 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3480 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3481 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3482 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3484 /* determine rwx permissions */
3485 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3486 permission
= S_IREAD
;
3488 permission
= S_IREAD
| S_IWRITE
;
3490 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3491 permission
|= S_IEXEC
;
3492 else if (is_exec (name
))
3493 permission
|= S_IEXEC
;
3495 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3500 /* Provide fstat and utime as well as stat for consistent handling of
3503 fstat (int desc
, struct stat
* buf
)
3505 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3506 BY_HANDLE_FILE_INFORMATION info
;
3507 unsigned __int64 fake_inode
;
3510 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3512 case FILE_TYPE_DISK
:
3513 buf
->st_mode
= S_IFREG
;
3514 if (!GetFileInformationByHandle (fh
, &info
))
3520 case FILE_TYPE_PIPE
:
3521 buf
->st_mode
= S_IFIFO
;
3523 case FILE_TYPE_CHAR
:
3524 case FILE_TYPE_UNKNOWN
:
3526 buf
->st_mode
= S_IFCHR
;
3528 memset (&info
, 0, sizeof (info
));
3529 info
.dwFileAttributes
= 0;
3530 info
.ftCreationTime
= utc_base_ft
;
3531 info
.ftLastAccessTime
= utc_base_ft
;
3532 info
.ftLastWriteTime
= utc_base_ft
;
3535 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3536 buf
->st_mode
= S_IFDIR
;
3538 buf
->st_nlink
= info
.nNumberOfLinks
;
3539 /* Might as well use file index to fake inode values, but this
3540 is not guaranteed to be unique unless we keep a handle open
3541 all the time (even then there are situations where it is
3542 not unique). Reputedly, there are at most 48 bits of info
3543 (on NTFS, presumably less on FAT). */
3544 fake_inode
= info
.nFileIndexHigh
;
3546 fake_inode
+= info
.nFileIndexLow
;
3548 /* MSVC defines _ino_t to be short; other libc's might not. */
3549 if (sizeof (buf
->st_ino
) == 2)
3550 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3552 buf
->st_ino
= fake_inode
;
3554 /* Consider files to belong to current user.
3555 FIXME: this should use GetSecurityInfo API, but it is only
3556 available for _WIN32_WINNT >= 0x501. */
3557 buf
->st_uid
= dflt_passwd
.pw_uid
;
3558 buf
->st_gid
= dflt_passwd
.pw_gid
;
3559 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3560 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3562 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3563 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3565 buf
->st_size
= info
.nFileSizeHigh
;
3566 buf
->st_size
<<= 32;
3567 buf
->st_size
+= info
.nFileSizeLow
;
3569 /* Convert timestamps to Unix format. */
3570 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3571 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3572 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3573 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3574 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3576 /* determine rwx permissions */
3577 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3578 permission
= S_IREAD
;
3580 permission
= S_IREAD
| S_IWRITE
;
3582 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3583 permission
|= S_IEXEC
;
3586 #if 0 /* no way of knowing the filename */
3587 char * p
= strrchr (name
, '.');
3589 (xstrcasecmp (p
, ".exe") == 0 ||
3590 xstrcasecmp (p
, ".com") == 0 ||
3591 xstrcasecmp (p
, ".bat") == 0 ||
3592 xstrcasecmp (p
, ".cmd") == 0))
3593 permission
|= S_IEXEC
;
3597 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3603 utime (const char *name
, struct utimbuf
*times
)
3605 struct utimbuf deftime
;
3612 deftime
.modtime
= deftime
.actime
= time (NULL
);
3616 /* Need write access to set times. */
3617 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3618 0, OPEN_EXISTING
, 0, NULL
);
3621 convert_from_time_t (times
->actime
, &atime
);
3622 convert_from_time_t (times
->modtime
, &mtime
);
3623 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3640 /* Support for browsing other processes and their attributes. See
3641 process.c for the Lisp bindings. */
3643 /* Helper wrapper functions. */
3645 HANDLE WINAPI
create_toolhelp32_snapshot(
3649 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3651 if (g_b_init_create_toolhelp32_snapshot
== 0)
3653 g_b_init_create_toolhelp32_snapshot
= 1;
3654 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3655 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3656 "CreateToolhelp32Snapshot");
3658 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3660 return INVALID_HANDLE_VALUE
;
3662 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3665 BOOL WINAPI
process32_first(
3667 LPPROCESSENTRY32 lppe
)
3669 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3671 if (g_b_init_process32_first
== 0)
3673 g_b_init_process32_first
= 1;
3674 s_pfn_Process32_First
= (Process32First_Proc
)
3675 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3678 if (s_pfn_Process32_First
== NULL
)
3682 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3685 BOOL WINAPI
process32_next(
3687 LPPROCESSENTRY32 lppe
)
3689 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3691 if (g_b_init_process32_next
== 0)
3693 g_b_init_process32_next
= 1;
3694 s_pfn_Process32_Next
= (Process32Next_Proc
)
3695 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3698 if (s_pfn_Process32_Next
== NULL
)
3702 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3705 BOOL WINAPI
open_thread_token (
3706 HANDLE ThreadHandle
,
3707 DWORD DesiredAccess
,
3709 PHANDLE TokenHandle
)
3711 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3712 HMODULE hm_advapi32
= NULL
;
3713 if (is_windows_9x () == TRUE
)
3715 SetLastError (ERROR_NOT_SUPPORTED
);
3718 if (g_b_init_open_thread_token
== 0)
3720 g_b_init_open_thread_token
= 1;
3721 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3722 s_pfn_Open_Thread_Token
=
3723 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3725 if (s_pfn_Open_Thread_Token
== NULL
)
3727 SetLastError (ERROR_NOT_SUPPORTED
);
3731 s_pfn_Open_Thread_Token (
3739 BOOL WINAPI
impersonate_self (
3740 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3742 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3743 HMODULE hm_advapi32
= NULL
;
3744 if (is_windows_9x () == TRUE
)
3748 if (g_b_init_impersonate_self
== 0)
3750 g_b_init_impersonate_self
= 1;
3751 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3752 s_pfn_Impersonate_Self
=
3753 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3755 if (s_pfn_Impersonate_Self
== NULL
)
3759 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3762 BOOL WINAPI
revert_to_self (void)
3764 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3765 HMODULE hm_advapi32
= NULL
;
3766 if (is_windows_9x () == TRUE
)
3770 if (g_b_init_revert_to_self
== 0)
3772 g_b_init_revert_to_self
= 1;
3773 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3774 s_pfn_Revert_To_Self
=
3775 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3777 if (s_pfn_Revert_To_Self
== NULL
)
3781 return s_pfn_Revert_To_Self ();
3784 BOOL WINAPI
get_process_memory_info (
3786 PPROCESS_MEMORY_COUNTERS mem_counters
,
3789 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3790 HMODULE hm_psapi
= NULL
;
3791 if (is_windows_9x () == TRUE
)
3795 if (g_b_init_get_process_memory_info
== 0)
3797 g_b_init_get_process_memory_info
= 1;
3798 hm_psapi
= LoadLibrary ("Psapi.dll");
3800 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3801 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3803 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3807 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3810 BOOL WINAPI
get_process_working_set_size (
3815 static GetProcessWorkingSetSize_Proc
3816 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3818 if (is_windows_9x () == TRUE
)
3822 if (g_b_init_get_process_working_set_size
== 0)
3824 g_b_init_get_process_working_set_size
= 1;
3825 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3826 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3827 "GetProcessWorkingSetSize");
3829 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3833 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3836 BOOL WINAPI
global_memory_status (
3839 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3841 if (is_windows_9x () == TRUE
)
3845 if (g_b_init_global_memory_status
== 0)
3847 g_b_init_global_memory_status
= 1;
3848 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3849 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3850 "GlobalMemoryStatus");
3852 if (s_pfn_Global_Memory_Status
== NULL
)
3856 return s_pfn_Global_Memory_Status (buf
);
3859 BOOL WINAPI
global_memory_status_ex (
3860 MEMORY_STATUS_EX
*buf
)
3862 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3864 if (is_windows_9x () == TRUE
)
3868 if (g_b_init_global_memory_status_ex
== 0)
3870 g_b_init_global_memory_status_ex
= 1;
3871 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3872 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3873 "GlobalMemoryStatusEx");
3875 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3879 return s_pfn_Global_Memory_Status_Ex (buf
);
3883 list_system_processes ()
3885 struct gcpro gcpro1
;
3886 Lisp_Object proclist
= Qnil
;
3889 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3891 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3893 PROCESSENTRY32 proc_entry
;
3899 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3900 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3901 res
= process32_next (h_snapshot
, &proc_entry
))
3903 proc_id
= proc_entry
.th32ProcessID
;
3904 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3907 CloseHandle (h_snapshot
);
3909 proclist
= Fnreverse (proclist
);
3916 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3918 TOKEN_PRIVILEGES priv
;
3919 DWORD priv_size
= sizeof (priv
);
3920 DWORD opriv_size
= sizeof (*old_priv
);
3921 HANDLE h_token
= NULL
;
3922 HANDLE h_thread
= GetCurrentThread ();
3926 res
= open_thread_token (h_thread
,
3927 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3929 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3931 if (impersonate_self (SecurityImpersonation
))
3932 res
= open_thread_token (h_thread
,
3933 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3938 priv
.PrivilegeCount
= 1;
3939 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3940 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3941 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3942 old_priv
, &opriv_size
)
3943 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3947 CloseHandle (h_token
);
3953 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3955 DWORD priv_size
= sizeof (*priv
);
3956 HANDLE h_token
= NULL
;
3959 if (open_thread_token (GetCurrentThread (),
3960 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3963 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3964 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3968 CloseHandle (h_token
);
3974 ltime (time_sec
, time_usec
)
3975 long time_sec
, time_usec
;
3977 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3978 make_number (time_sec
& 0xffff),
3979 make_number (time_usec
));
3982 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
3985 process_times (h_proc
, ctime
, etime
, stime
, utime
, ttime
, pcpu
)
3987 Lisp_Object
*ctime
, *etime
, *stime
, *utime
, *ttime
;
3990 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
3991 ULONGLONG tem1
, tem2
, tem3
, tem
;
3994 || !get_process_times_fn
3995 || !(*get_process_times_fn
)(h_proc
, &ft_creation
, &ft_exit
,
3996 &ft_kernel
, &ft_user
))
3999 GetSystemTimeAsFileTime (&ft_current
);
4001 FILETIME_TO_U64 (tem1
, ft_kernel
);
4003 *stime
= U64_TO_LISP_TIME (tem1
);
4005 FILETIME_TO_U64 (tem2
, ft_user
);
4007 *utime
= U64_TO_LISP_TIME (tem2
);
4010 *ttime
= U64_TO_LISP_TIME (tem3
);
4012 FILETIME_TO_U64 (tem
, ft_creation
);
4013 /* Process no 4 (System) returns zero creation time. */
4015 tem
= (tem
- utc_base
) / 10L;
4016 *ctime
= U64_TO_LISP_TIME (tem
);
4020 FILETIME_TO_U64 (tem3
, ft_current
);
4021 tem
= (tem3
- utc_base
) / 10L - tem
;
4023 *etime
= U64_TO_LISP_TIME (tem
);
4027 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4038 system_process_attributes (pid
)
4041 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4042 Lisp_Object attrs
= Qnil
;
4043 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4044 HANDLE h_snapshot
, h_proc
;
4047 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4048 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4049 DWORD glength
= sizeof (gname
);
4050 HANDLE token
= NULL
;
4051 SID_NAME_USE user_type
;
4052 unsigned char *buf
= NULL
;
4054 TOKEN_USER user_token
;
4055 TOKEN_PRIMARY_GROUP group_token
;
4059 PROCESS_MEMORY_COUNTERS mem
;
4060 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4061 DWORD minrss
, maxrss
;
4063 MEMORY_STATUS_EX memstex
;
4064 double totphys
= 0.0;
4065 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4067 BOOL result
= FALSE
;
4069 CHECK_NUMBER_OR_FLOAT (pid
);
4070 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4072 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4074 GCPRO3 (attrs
, decoded_cmd
, tem
);
4076 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4081 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4082 for (res
= process32_first (h_snapshot
, &pe
); res
;
4083 res
= process32_next (h_snapshot
, &pe
))
4085 if (proc_id
== pe
.th32ProcessID
)
4088 decoded_cmd
= build_string ("Idle");
4091 /* Decode the command name from locale-specific
4093 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4094 strlen (pe
.szExeFile
));
4096 code_convert_string_norecord (cmd_str
,
4097 Vlocale_coding_system
, 0);
4099 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4100 attrs
= Fcons (Fcons (Qppid
,
4101 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4103 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4105 attrs
= Fcons (Fcons (Qthcount
,
4106 make_fixnum_or_float (pe
.cntThreads
)),
4113 CloseHandle (h_snapshot
);
4122 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4124 /* If we were denied a handle to the process, try again after
4125 enabling the SeDebugPrivilege in our process. */
4128 TOKEN_PRIVILEGES priv_current
;
4130 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4132 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4134 restore_privilege (&priv_current
);
4140 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4143 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4144 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4146 buf
= xmalloc (blen
);
4147 result
= get_token_information (token
, TokenUser
,
4148 (LPVOID
)buf
, blen
, &needed
);
4151 memcpy (&user_token
, buf
, sizeof (user_token
));
4152 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4154 euid
= get_rid (user_token
.User
.Sid
);
4155 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4160 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4163 strcpy (uname
, "unknown");
4167 ulength
= strlen (uname
);
4173 /* Determine a reasonable euid and gid values. */
4174 if (xstrcasecmp ("administrator", uname
) == 0)
4176 euid
= 500; /* well-known Administrator uid */
4177 egid
= 513; /* well-known None gid */
4181 /* Get group id and name. */
4182 result
= get_token_information (token
, TokenPrimaryGroup
,
4183 (LPVOID
)buf
, blen
, &needed
);
4184 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4186 buf
= xrealloc (buf
, blen
= needed
);
4187 result
= get_token_information (token
, TokenPrimaryGroup
,
4188 (LPVOID
)buf
, blen
, &needed
);
4192 memcpy (&group_token
, buf
, sizeof (group_token
));
4193 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4195 egid
= get_rid (group_token
.PrimaryGroup
);
4196 dlength
= sizeof (domain
);
4198 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4199 gname
, &glength
, NULL
, &dlength
,
4202 w32_add_to_cache (group_token
.PrimaryGroup
,
4206 strcpy (gname
, "None");
4210 glength
= strlen (gname
);
4218 if (!is_windows_9x ())
4220 /* We couldn't open the process token, presumably because of
4221 insufficient access rights. Assume this process is run
4223 strcpy (uname
, "SYSTEM");
4224 strcpy (gname
, "None");
4225 euid
= 18; /* SYSTEM */
4226 egid
= 513; /* None */
4227 glength
= strlen (gname
);
4228 ulength
= strlen (uname
);
4230 /* If we are running under Windows 9X, where security calls are
4231 not supported, we assume all processes are run by the current
4233 else if (GetUserName (uname
, &ulength
))
4235 if (xstrcasecmp ("administrator", uname
) == 0)
4240 strcpy (gname
, "None");
4241 glength
= strlen (gname
);
4242 ulength
= strlen (uname
);
4248 strcpy (uname
, "administrator");
4249 ulength
= strlen (uname
);
4250 strcpy (gname
, "None");
4251 glength
= strlen (gname
);
4254 CloseHandle (token
);
4257 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4258 tem
= make_unibyte_string (uname
, ulength
);
4259 attrs
= Fcons (Fcons (Quser
,
4260 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4262 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4263 tem
= make_unibyte_string (gname
, glength
);
4264 attrs
= Fcons (Fcons (Qgroup
,
4265 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4268 if (global_memory_status_ex (&memstex
))
4269 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4270 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4272 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4273 double, so we need to do this for it... */
4275 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4276 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4277 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4279 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4281 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4282 else if (global_memory_status (&memst
))
4283 totphys
= memst
.dwTotalPhys
/ 1024.0;
4286 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4289 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4291 attrs
= Fcons (Fcons (Qmajflt
,
4292 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4294 attrs
= Fcons (Fcons (Qvsize
,
4295 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4297 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4299 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4302 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4304 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4306 attrs
= Fcons (Fcons (Qmajflt
,
4307 make_fixnum_or_float (mem
.PageFaultCount
)),
4309 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4311 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4314 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4316 DWORD rss
= maxrss
/ 1024;
4318 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4320 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4323 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4325 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4326 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4327 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4328 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4329 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4330 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4333 /* FIXME: Retrieve command line by walking the PEB of the process. */
4336 CloseHandle (h_proc
);
4344 /* Wrappers for winsock functions to map between our file descriptors
4345 and winsock's handles; also set h_errno for convenience.
4347 To allow Emacs to run on systems which don't have winsock support
4348 installed, we dynamically link to winsock on startup if present, and
4349 otherwise provide the minimum necessary functionality
4350 (eg. gethostname). */
4352 /* function pointers for relevant socket functions */
4353 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4354 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4355 int (PASCAL
*pfn_WSAGetLastError
) (void);
4356 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4357 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4358 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4359 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4360 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4361 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4362 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4363 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4364 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4365 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4366 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4367 int (PASCAL
*pfn_WSACleanup
) (void);
4369 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4370 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4371 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4372 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4373 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4374 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4375 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4376 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4377 const char * optval
, int optlen
);
4378 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4379 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4381 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4382 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4383 struct sockaddr
* from
, int * fromlen
);
4384 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4385 const struct sockaddr
* to
, int tolen
);
4387 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4388 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4389 #ifndef HANDLE_FLAG_INHERIT
4390 #define HANDLE_FLAG_INHERIT 1
4394 static int winsock_inuse
;
4399 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4401 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4402 after WSAStartup returns successfully, but it seems reasonable
4403 to allow unloading winsock anyway in that case. */
4404 if (pfn_WSACleanup () == 0 ||
4405 pfn_WSAGetLastError () == WSAENETDOWN
)
4407 if (FreeLibrary (winsock_lib
))
4416 init_winsock (int load_now
)
4418 WSADATA winsockData
;
4420 if (winsock_lib
!= NULL
)
4423 pfn_SetHandleInformation
= NULL
;
4424 pfn_SetHandleInformation
4425 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4426 "SetHandleInformation");
4428 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4430 if (winsock_lib
!= NULL
)
4432 /* dynamically link to socket functions */
4434 #define LOAD_PROC(fn) \
4435 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4438 LOAD_PROC( WSAStartup
);
4439 LOAD_PROC( WSASetLastError
);
4440 LOAD_PROC( WSAGetLastError
);
4441 LOAD_PROC( WSAEventSelect
);
4442 LOAD_PROC( WSACreateEvent
);
4443 LOAD_PROC( WSACloseEvent
);
4444 LOAD_PROC( socket
);
4446 LOAD_PROC( connect
);
4447 LOAD_PROC( ioctlsocket
);
4450 LOAD_PROC( closesocket
);
4451 LOAD_PROC( shutdown
);
4454 LOAD_PROC( inet_addr
);
4455 LOAD_PROC( gethostname
);
4456 LOAD_PROC( gethostbyname
);
4457 LOAD_PROC( getservbyname
);
4458 LOAD_PROC( getpeername
);
4459 LOAD_PROC( WSACleanup
);
4460 LOAD_PROC( setsockopt
);
4461 LOAD_PROC( listen
);
4462 LOAD_PROC( getsockname
);
4463 LOAD_PROC( accept
);
4464 LOAD_PROC( recvfrom
);
4465 LOAD_PROC( sendto
);
4468 /* specify version 1.1 of winsock */
4469 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4471 if (winsockData
.wVersion
!= 0x101)
4476 /* Report that winsock exists and is usable, but leave
4477 socket functions disabled. I am assuming that calling
4478 WSAStartup does not require any network interaction,
4479 and in particular does not cause or require a dial-up
4480 connection to be established. */
4483 FreeLibrary (winsock_lib
);
4491 FreeLibrary (winsock_lib
);
4501 /* function to set h_errno for compatibility; map winsock error codes to
4502 normal system codes where they overlap (non-overlapping definitions
4503 are already in <sys/socket.h> */
4507 if (winsock_lib
== NULL
)
4510 h_errno
= pfn_WSAGetLastError ();
4514 case WSAEACCES
: h_errno
= EACCES
; break;
4515 case WSAEBADF
: h_errno
= EBADF
; break;
4516 case WSAEFAULT
: h_errno
= EFAULT
; break;
4517 case WSAEINTR
: h_errno
= EINTR
; break;
4518 case WSAEINVAL
: h_errno
= EINVAL
; break;
4519 case WSAEMFILE
: h_errno
= EMFILE
; break;
4520 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4521 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4529 if (h_errno
== 0 && winsock_lib
!= NULL
)
4530 pfn_WSASetLastError (0);
4533 /* Extend strerror to handle the winsock-specific error codes. */
4537 } _wsa_errlist
[] = {
4538 WSAEINTR
, "Interrupted function call",
4539 WSAEBADF
, "Bad file descriptor",
4540 WSAEACCES
, "Permission denied",
4541 WSAEFAULT
, "Bad address",
4542 WSAEINVAL
, "Invalid argument",
4543 WSAEMFILE
, "Too many open files",
4545 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4546 WSAEINPROGRESS
, "Operation now in progress",
4547 WSAEALREADY
, "Operation already in progress",
4548 WSAENOTSOCK
, "Socket operation on non-socket",
4549 WSAEDESTADDRREQ
, "Destination address required",
4550 WSAEMSGSIZE
, "Message too long",
4551 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4552 WSAENOPROTOOPT
, "Bad protocol option",
4553 WSAEPROTONOSUPPORT
, "Protocol not supported",
4554 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4555 WSAEOPNOTSUPP
, "Operation not supported",
4556 WSAEPFNOSUPPORT
, "Protocol family not supported",
4557 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4558 WSAEADDRINUSE
, "Address already in use",
4559 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4560 WSAENETDOWN
, "Network is down",
4561 WSAENETUNREACH
, "Network is unreachable",
4562 WSAENETRESET
, "Network dropped connection on reset",
4563 WSAECONNABORTED
, "Software caused connection abort",
4564 WSAECONNRESET
, "Connection reset by peer",
4565 WSAENOBUFS
, "No buffer space available",
4566 WSAEISCONN
, "Socket is already connected",
4567 WSAENOTCONN
, "Socket is not connected",
4568 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4569 WSAETOOMANYREFS
, "Too many references", /* not sure */
4570 WSAETIMEDOUT
, "Connection timed out",
4571 WSAECONNREFUSED
, "Connection refused",
4572 WSAELOOP
, "Network loop", /* not sure */
4573 WSAENAMETOOLONG
, "Name is too long",
4574 WSAEHOSTDOWN
, "Host is down",
4575 WSAEHOSTUNREACH
, "No route to host",
4576 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4577 WSAEPROCLIM
, "Too many processes",
4578 WSAEUSERS
, "Too many users", /* not sure */
4579 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4580 WSAESTALE
, "Data is stale", /* not sure */
4581 WSAEREMOTE
, "Remote error", /* not sure */
4583 WSASYSNOTREADY
, "Network subsystem is unavailable",
4584 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4585 WSANOTINITIALISED
, "Winsock not initialized successfully",
4586 WSAEDISCON
, "Graceful shutdown in progress",
4588 WSAENOMORE
, "No more operations allowed", /* not sure */
4589 WSAECANCELLED
, "Operation cancelled", /* not sure */
4590 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4591 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4592 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4593 WSASYSCALLFAILURE
, "System call failure",
4594 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4595 WSATYPE_NOT_FOUND
, "Class type not found",
4596 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4597 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4598 WSAEREFUSED
, "Operation refused", /* not sure */
4601 WSAHOST_NOT_FOUND
, "Host not found",
4602 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4603 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4604 WSANO_DATA
, "Valid name, no data record of requested type",
4610 sys_strerror(int error_no
)
4613 static char unknown_msg
[40];
4615 if (error_no
>= 0 && error_no
< sys_nerr
)
4616 return sys_errlist
[error_no
];
4618 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4619 if (_wsa_errlist
[i
].errnum
== error_no
)
4620 return _wsa_errlist
[i
].msg
;
4622 sprintf(unknown_msg
, "Unidentified error: %d", error_no
);
4626 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4627 but I believe the method of keeping the socket handle separate (and
4628 insuring it is not inheritable) is the correct one. */
4630 //#define SOCK_REPLACE_HANDLE
4632 #ifdef SOCK_REPLACE_HANDLE
4633 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4635 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4638 int socket_to_fd (SOCKET s
);
4641 sys_socket(int af
, int type
, int protocol
)
4645 if (winsock_lib
== NULL
)
4648 return INVALID_SOCKET
;
4653 /* call the real socket function */
4654 s
= pfn_socket (af
, type
, protocol
);
4656 if (s
!= INVALID_SOCKET
)
4657 return socket_to_fd (s
);
4663 /* Convert a SOCKET to a file descriptor. */
4665 socket_to_fd (SOCKET s
)
4670 /* Although under NT 3.5 _open_osfhandle will accept a socket
4671 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4672 that does not work under NT 3.1. However, we can get the same
4673 effect by using a backdoor function to replace an existing
4674 descriptor handle with the one we want. */
4676 /* allocate a file descriptor (with appropriate flags) */
4677 fd
= _open ("NUL:", _O_RDWR
);
4680 #ifdef SOCK_REPLACE_HANDLE
4681 /* now replace handle to NUL with our socket handle */
4682 CloseHandle ((HANDLE
) _get_osfhandle (fd
));
4684 _set_osfhnd (fd
, s
);
4685 /* setmode (fd, _O_BINARY); */
4687 /* Make a non-inheritable copy of the socket handle. Note
4688 that it is possible that sockets aren't actually kernel
4689 handles, which appears to be the case on Windows 9x when
4690 the MS Proxy winsock client is installed. */
4692 /* Apparently there is a bug in NT 3.51 with some service
4693 packs, which prevents using DuplicateHandle to make a
4694 socket handle non-inheritable (causes WSACleanup to
4695 hang). The work-around is to use SetHandleInformation
4696 instead if it is available and implemented. */
4697 if (pfn_SetHandleInformation
)
4699 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4703 HANDLE parent
= GetCurrentProcess ();
4704 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4706 if (DuplicateHandle (parent
,
4712 DUPLICATE_SAME_ACCESS
))
4714 /* It is possible that DuplicateHandle succeeds even
4715 though the socket wasn't really a kernel handle,
4716 because a real handle has the same value. So
4717 test whether the new handle really is a socket. */
4718 long nonblocking
= 0;
4719 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4721 pfn_closesocket (s
);
4726 CloseHandle (new_s
);
4731 fd_info
[fd
].hnd
= (HANDLE
) s
;
4734 /* set our own internal flags */
4735 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4741 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4743 /* attach child_process to fd_info */
4744 if (fd_info
[ fd
].cp
!= NULL
)
4746 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4750 fd_info
[ fd
].cp
= cp
;
4753 winsock_inuse
++; /* count open sockets */
4760 pfn_closesocket (s
);
4767 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4769 if (winsock_lib
== NULL
)
4772 return SOCKET_ERROR
;
4776 if (fd_info
[s
].flags
& FILE_SOCKET
)
4778 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4779 if (rc
== SOCKET_ERROR
)
4784 return SOCKET_ERROR
;
4789 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4791 if (winsock_lib
== NULL
)
4794 return SOCKET_ERROR
;
4798 if (fd_info
[s
].flags
& FILE_SOCKET
)
4800 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4801 if (rc
== SOCKET_ERROR
)
4806 return SOCKET_ERROR
;
4810 sys_htons (u_short hostshort
)
4812 return (winsock_lib
!= NULL
) ?
4813 pfn_htons (hostshort
) : hostshort
;
4817 sys_ntohs (u_short netshort
)
4819 return (winsock_lib
!= NULL
) ?
4820 pfn_ntohs (netshort
) : netshort
;
4824 sys_inet_addr (const char * cp
)
4826 return (winsock_lib
!= NULL
) ?
4827 pfn_inet_addr (cp
) : INADDR_NONE
;
4831 sys_gethostname (char * name
, int namelen
)
4833 if (winsock_lib
!= NULL
)
4834 return pfn_gethostname (name
, namelen
);
4836 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4837 return !GetComputerName (name
, (DWORD
*)&namelen
);
4840 return SOCKET_ERROR
;
4844 sys_gethostbyname(const char * name
)
4846 struct hostent
* host
;
4848 if (winsock_lib
== NULL
)
4855 host
= pfn_gethostbyname (name
);
4862 sys_getservbyname(const char * name
, const char * proto
)
4864 struct servent
* serv
;
4866 if (winsock_lib
== NULL
)
4873 serv
= pfn_getservbyname (name
, proto
);
4880 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4882 if (winsock_lib
== NULL
)
4885 return SOCKET_ERROR
;
4889 if (fd_info
[s
].flags
& FILE_SOCKET
)
4891 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4892 if (rc
== SOCKET_ERROR
)
4897 return SOCKET_ERROR
;
4902 sys_shutdown (int s
, int how
)
4904 if (winsock_lib
== NULL
)
4907 return SOCKET_ERROR
;
4911 if (fd_info
[s
].flags
& FILE_SOCKET
)
4913 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4914 if (rc
== SOCKET_ERROR
)
4919 return SOCKET_ERROR
;
4923 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4925 if (winsock_lib
== NULL
)
4928 return SOCKET_ERROR
;
4932 if (fd_info
[s
].flags
& FILE_SOCKET
)
4934 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4935 (const char *)optval
, optlen
);
4936 if (rc
== SOCKET_ERROR
)
4941 return SOCKET_ERROR
;
4945 sys_listen (int s
, int backlog
)
4947 if (winsock_lib
== NULL
)
4950 return SOCKET_ERROR
;
4954 if (fd_info
[s
].flags
& FILE_SOCKET
)
4956 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4957 if (rc
== SOCKET_ERROR
)
4960 fd_info
[s
].flags
|= FILE_LISTEN
;
4964 return SOCKET_ERROR
;
4968 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4970 if (winsock_lib
== NULL
)
4973 return SOCKET_ERROR
;
4977 if (fd_info
[s
].flags
& FILE_SOCKET
)
4979 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4980 if (rc
== SOCKET_ERROR
)
4985 return SOCKET_ERROR
;
4989 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
4991 if (winsock_lib
== NULL
)
4998 if (fd_info
[s
].flags
& FILE_LISTEN
)
5000 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5002 if (t
== INVALID_SOCKET
)
5005 fd
= socket_to_fd (t
);
5007 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5008 ResetEvent (fd_info
[s
].cp
->char_avail
);
5016 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5017 struct sockaddr
* from
, int * fromlen
)
5019 if (winsock_lib
== NULL
)
5022 return SOCKET_ERROR
;
5026 if (fd_info
[s
].flags
& FILE_SOCKET
)
5028 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5029 if (rc
== SOCKET_ERROR
)
5034 return SOCKET_ERROR
;
5038 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5039 const struct sockaddr
* to
, int tolen
)
5041 if (winsock_lib
== NULL
)
5044 return SOCKET_ERROR
;
5048 if (fd_info
[s
].flags
& FILE_SOCKET
)
5050 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5051 if (rc
== SOCKET_ERROR
)
5056 return SOCKET_ERROR
;
5059 /* Windows does not have an fcntl function. Provide an implementation
5060 solely for making sockets non-blocking. */
5062 fcntl (int s
, int cmd
, int options
)
5064 if (winsock_lib
== NULL
)
5071 if (fd_info
[s
].flags
& FILE_SOCKET
)
5073 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5075 unsigned long nblock
= 1;
5076 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5077 if (rc
== SOCKET_ERROR
)
5079 /* Keep track of the fact that we set this to non-blocking. */
5080 fd_info
[s
].flags
|= FILE_NDELAY
;
5086 return SOCKET_ERROR
;
5090 return SOCKET_ERROR
;
5093 #endif /* HAVE_SOCKETS */
5096 /* Shadow main io functions: we need to handle pipes and sockets more
5097 intelligently, and implement non-blocking mode as well. */
5110 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5112 child_process
* cp
= fd_info
[fd
].cp
;
5114 fd_info
[fd
].cp
= NULL
;
5116 if (CHILD_ACTIVE (cp
))
5118 /* if last descriptor to active child_process then cleanup */
5120 for (i
= 0; i
< MAXDESC
; i
++)
5124 if (fd_info
[i
].cp
== cp
)
5130 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5132 #ifndef SOCK_REPLACE_HANDLE
5133 if (winsock_lib
== NULL
) abort ();
5135 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5136 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5138 winsock_inuse
--; /* count open sockets */
5146 /* Note that sockets do not need special treatment here (at least on
5147 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5148 closesocket is equivalent to CloseHandle, which is to be expected
5149 because socket handles are fully fledged kernel handles. */
5152 if (rc
== 0 && fd
< MAXDESC
)
5153 fd_info
[fd
].flags
= 0;
5164 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5166 /* duplicate our internal info as well */
5167 fd_info
[new_fd
] = fd_info
[fd
];
5174 sys_dup2 (int src
, int dst
)
5178 if (dst
< 0 || dst
>= MAXDESC
)
5184 /* make sure we close the destination first if it's a pipe or socket */
5185 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5188 rc
= _dup2 (src
, dst
);
5191 /* duplicate our internal info as well */
5192 fd_info
[dst
] = fd_info
[src
];
5197 /* Unix pipe() has only one arg */
5199 sys_pipe (int * phandles
)
5204 /* make pipe handles non-inheritable; when we spawn a child, we
5205 replace the relevant handle with an inheritable one. Also put
5206 pipes into binary mode; we will do text mode translation ourselves
5208 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5212 /* Protect against overflow, since Windows can open more handles than
5213 our fd_info array has room for. */
5214 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5216 _close (phandles
[0]);
5217 _close (phandles
[1]);
5222 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5223 fd_info
[phandles
[0]].flags
= flags
;
5225 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5226 fd_info
[phandles
[1]].flags
= flags
;
5234 extern int w32_pipe_read_delay
;
5236 /* Function to do blocking read of one byte, needed to implement
5237 select. It is only allowed on sockets and pipes. */
5239 _sys_read_ahead (int fd
)
5244 if (fd
< 0 || fd
>= MAXDESC
)
5245 return STATUS_READ_ERROR
;
5247 cp
= fd_info
[fd
].cp
;
5249 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5250 return STATUS_READ_ERROR
;
5252 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5253 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5255 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5259 cp
->status
= STATUS_READ_IN_PROGRESS
;
5261 if (fd_info
[fd
].flags
& FILE_PIPE
)
5263 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5265 /* Give subprocess time to buffer some more output for us before
5266 reporting that input is available; we need this because Windows 95
5267 connects DOS programs to pipes by making the pipe appear to be
5268 the normal console stdout - as a result most DOS programs will
5269 write to stdout without buffering, ie. one character at a
5270 time. Even some W32 programs do this - "dir" in a command
5271 shell on NT is very slow if we don't do this. */
5274 int wait
= w32_pipe_read_delay
;
5280 /* Yield remainder of our time slice, effectively giving a
5281 temporary priority boost to the child process. */
5285 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5287 HANDLE hnd
= fd_info
[fd
].hnd
;
5288 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5291 /* Configure timeouts for blocking read. */
5292 if (!GetCommTimeouts (hnd
, &ct
))
5293 return STATUS_READ_ERROR
;
5294 ct
.ReadIntervalTimeout
= 0;
5295 ct
.ReadTotalTimeoutMultiplier
= 0;
5296 ct
.ReadTotalTimeoutConstant
= 0;
5297 if (!SetCommTimeouts (hnd
, &ct
))
5298 return STATUS_READ_ERROR
;
5300 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5302 if (GetLastError () != ERROR_IO_PENDING
)
5303 return STATUS_READ_ERROR
;
5304 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5305 return STATUS_READ_ERROR
;
5309 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5311 unsigned long nblock
= 0;
5312 /* We always want this to block, so temporarily disable NDELAY. */
5313 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5314 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5316 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5318 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5321 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5326 if (rc
== sizeof (char))
5327 cp
->status
= STATUS_READ_SUCCEEDED
;
5329 cp
->status
= STATUS_READ_FAILED
;
5335 _sys_wait_accept (int fd
)
5341 if (fd
< 0 || fd
>= MAXDESC
)
5342 return STATUS_READ_ERROR
;
5344 cp
= fd_info
[fd
].cp
;
5346 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5347 return STATUS_READ_ERROR
;
5349 cp
->status
= STATUS_READ_FAILED
;
5351 hEv
= pfn_WSACreateEvent ();
5352 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5353 if (rc
!= SOCKET_ERROR
)
5355 rc
= WaitForSingleObject (hEv
, INFINITE
);
5356 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5357 if (rc
== WAIT_OBJECT_0
)
5358 cp
->status
= STATUS_READ_SUCCEEDED
;
5360 pfn_WSACloseEvent (hEv
);
5366 sys_read (int fd
, char * buffer
, unsigned int count
)
5371 char * orig_buffer
= buffer
;
5379 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5381 child_process
*cp
= fd_info
[fd
].cp
;
5383 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5391 /* re-read CR carried over from last read */
5392 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5394 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5398 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5401 /* presence of a child_process structure means we are operating in
5402 non-blocking mode - otherwise we just call _read directly.
5403 Note that the child_process structure might be missing because
5404 reap_subprocess has been called; in this case the pipe is
5405 already broken, so calling _read on it is okay. */
5408 int current_status
= cp
->status
;
5410 switch (current_status
)
5412 case STATUS_READ_FAILED
:
5413 case STATUS_READ_ERROR
:
5414 /* report normal EOF if nothing in buffer */
5416 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5419 case STATUS_READ_READY
:
5420 case STATUS_READ_IN_PROGRESS
:
5421 DebPrint (("sys_read called when read is in progress\n"));
5422 errno
= EWOULDBLOCK
;
5425 case STATUS_READ_SUCCEEDED
:
5426 /* consume read-ahead char */
5427 *buffer
++ = cp
->chr
;
5430 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5431 ResetEvent (cp
->char_avail
);
5433 case STATUS_READ_ACKNOWLEDGED
:
5437 DebPrint (("sys_read: bad status %d\n", current_status
));
5442 if (fd_info
[fd
].flags
& FILE_PIPE
)
5444 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5445 to_read
= min (waiting
, (DWORD
) count
);
5448 nchars
+= _read (fd
, buffer
, to_read
);
5450 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5452 HANDLE hnd
= fd_info
[fd
].hnd
;
5453 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5460 /* Configure timeouts for non-blocking read. */
5461 if (!GetCommTimeouts (hnd
, &ct
))
5466 ct
.ReadIntervalTimeout
= MAXDWORD
;
5467 ct
.ReadTotalTimeoutMultiplier
= 0;
5468 ct
.ReadTotalTimeoutConstant
= 0;
5469 if (!SetCommTimeouts (hnd
, &ct
))
5475 if (!ResetEvent (ovl
->hEvent
))
5480 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5482 if (GetLastError () != ERROR_IO_PENDING
)
5487 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5497 else /* FILE_SOCKET */
5499 if (winsock_lib
== NULL
) abort ();
5501 /* do the equivalent of a non-blocking read */
5502 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5503 if (waiting
== 0 && nchars
== 0)
5505 h_errno
= errno
= EWOULDBLOCK
;
5511 /* always use binary mode for sockets */
5512 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5513 if (res
== SOCKET_ERROR
)
5515 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
5516 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5527 int nread
= _read (fd
, buffer
, count
);
5530 else if (nchars
== 0)
5535 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5536 /* Perform text mode translation if required. */
5537 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5539 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5540 /* If buffer contains only CR, return that. To be absolutely
5541 sure we should attempt to read the next char, but in
5542 practice a CR to be followed by LF would not appear by
5543 itself in the buffer. */
5544 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5546 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5552 nchars
= _read (fd
, buffer
, count
);
5557 /* From w32xfns.c */
5558 extern HANDLE interrupt_handle
;
5560 /* For now, don't bother with a non-blocking mode */
5562 sys_write (int fd
, const void * buffer
, unsigned int count
)
5572 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5574 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5580 /* Perform text mode translation if required. */
5581 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5583 char * tmpbuf
= alloca (count
* 2);
5584 unsigned char * src
= (void *)buffer
;
5585 unsigned char * dst
= tmpbuf
;
5590 unsigned char *next
;
5591 /* copy next line or remaining bytes */
5592 next
= _memccpy (dst
, src
, '\n', nbytes
);
5595 /* copied one line ending with '\n' */
5596 int copied
= next
- dst
;
5599 /* insert '\r' before '\n' */
5606 /* copied remaining partial line -> now finished */
5613 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5615 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5616 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5617 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5620 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5622 if (GetLastError () != ERROR_IO_PENDING
)
5627 if (detect_input_pending ())
5628 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5631 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5632 if (active
== WAIT_OBJECT_0
)
5633 { /* User pressed C-g, cancel write, then leave. Don't bother
5634 cleaning up as we may only get stuck in buggy drivers. */
5635 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5640 if (active
== WAIT_OBJECT_0
+ 1
5641 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5650 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5652 unsigned long nblock
= 0;
5653 if (winsock_lib
== NULL
) abort ();
5655 /* TODO: implement select() properly so non-blocking I/O works. */
5656 /* For now, make sure the write blocks. */
5657 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5658 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5660 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5662 /* Set the socket back to non-blocking if it was before,
5663 for other operations that support it. */
5664 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5667 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5670 if (nchars
== SOCKET_ERROR
)
5672 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
5673 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5679 nchars
= _write (fd
, buffer
, count
);
5685 check_windows_init_file ()
5687 extern int noninteractive
, inhibit_window_system
;
5689 /* A common indication that Emacs is not installed properly is when
5690 it cannot find the Windows installation file. If this file does
5691 not exist in the expected place, tell the user. */
5693 if (!noninteractive
&& !inhibit_window_system
)
5695 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
5696 Lisp_Object objs
[2];
5697 Lisp_Object full_load_path
;
5698 Lisp_Object init_file
;
5701 objs
[0] = Vload_path
;
5702 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5703 full_load_path
= Fappend (2, objs
);
5704 init_file
= build_string ("term/w32-win");
5705 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5708 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5709 char *init_file_name
= SDATA (init_file
);
5710 char *load_path
= SDATA (load_path_print
);
5711 char *buffer
= alloca (1024
5712 + strlen (init_file_name
)
5713 + strlen (load_path
));
5716 "The Emacs Windows initialization file \"%s.el\" "
5717 "could not be found in your Emacs installation. "
5718 "Emacs checked the following directories for this file:\n"
5720 "When Emacs cannot find this file, it usually means that it "
5721 "was not installed properly, or its distribution file was "
5722 "not unpacked properly.\nSee the README.W32 file in the "
5723 "top-level Emacs directory for more information.",
5724 init_file_name
, load_path
);
5727 "Emacs Abort Dialog",
5728 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5729 /* Use the low-level Emacs abort. */
5744 /* shutdown the socket interface if necessary */
5755 /* Initialise the socket interface now if available and requested by
5756 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5757 delayed until open-network-stream is called (w32-has-winsock can
5758 also be used to dynamically load or reload winsock).
5760 Conveniently, init_environment is called before us, so
5761 PRELOAD_WINSOCK can be set in the registry. */
5763 /* Always initialize this correctly. */
5766 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5767 init_winsock (TRUE
);
5770 /* Initial preparation for subprocess support: replace our standard
5771 handles with non-inheritable versions. */
5774 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5775 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5776 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5778 parent
= GetCurrentProcess ();
5780 /* ignore errors when duplicating and closing; typically the
5781 handles will be invalid when running as a gui program. */
5782 DuplicateHandle (parent
,
5783 GetStdHandle (STD_INPUT_HANDLE
),
5788 DUPLICATE_SAME_ACCESS
);
5790 DuplicateHandle (parent
,
5791 GetStdHandle (STD_OUTPUT_HANDLE
),
5796 DUPLICATE_SAME_ACCESS
);
5798 DuplicateHandle (parent
,
5799 GetStdHandle (STD_ERROR_HANDLE
),
5804 DUPLICATE_SAME_ACCESS
);
5810 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5811 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5813 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5816 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5817 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5819 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5822 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5823 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5825 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5829 /* unfortunately, atexit depends on implementation of malloc */
5830 /* atexit (term_ntproc); */
5831 signal (SIGABRT
, term_ntproc
);
5833 /* determine which drives are fixed, for GetCachedVolumeInformation */
5835 /* GetDriveType must have trailing backslash. */
5836 char drive
[] = "A:\\";
5838 /* Loop over all possible drive letters */
5839 while (*drive
<= 'Z')
5841 /* Record if this drive letter refers to a fixed drive. */
5842 fixed_drives
[DRIVE_INDEX (*drive
)] =
5843 (GetDriveType (drive
) == DRIVE_FIXED
);
5848 /* Reset the volume info cache. */
5849 volume_cache
= NULL
;
5852 /* Check to see if Emacs has been installed correctly. */
5853 check_windows_init_file ();
5857 shutdown_handler ensures that buffers' autosave files are
5858 up to date when the user logs off, or the system shuts down.
5860 BOOL WINAPI
shutdown_handler(DWORD type
)
5862 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5863 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5864 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5865 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5867 /* Shut down cleanly, making sure autosave files are up to date. */
5868 shut_down_emacs (0, 0, Qnil
);
5871 /* Allow other handlers to handle this signal. */
5876 globals_of_w32 is used to initialize those global variables that
5877 must always be initialized on startup even when the global variable
5878 initialized is non zero (see the function main in emacs.c).
5883 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5885 get_process_times_fn
= (GetProcessTimes_Proc
)
5886 GetProcAddress (kernel32
, "GetProcessTimes");
5888 g_b_init_is_windows_9x
= 0;
5889 g_b_init_open_process_token
= 0;
5890 g_b_init_get_token_information
= 0;
5891 g_b_init_lookup_account_sid
= 0;
5892 g_b_init_get_sid_identifier_authority
= 0;
5893 g_b_init_get_sid_sub_authority
= 0;
5894 g_b_init_get_sid_sub_authority_count
= 0;
5895 g_b_init_get_file_security
= 0;
5896 g_b_init_get_security_descriptor_owner
= 0;
5897 g_b_init_get_security_descriptor_group
= 0;
5898 g_b_init_is_valid_sid
= 0;
5899 g_b_init_create_toolhelp32_snapshot
= 0;
5900 g_b_init_process32_first
= 0;
5901 g_b_init_process32_next
= 0;
5902 g_b_init_open_thread_token
= 0;
5903 g_b_init_impersonate_self
= 0;
5904 g_b_init_revert_to_self
= 0;
5905 g_b_init_get_process_memory_info
= 0;
5906 g_b_init_get_process_working_set_size
= 0;
5907 g_b_init_global_memory_status
= 0;
5908 g_b_init_global_memory_status_ex
= 0;
5909 g_b_init_equal_sid
= 0;
5910 g_b_init_copy_sid
= 0;
5911 g_b_init_get_length_sid
= 0;
5912 g_b_init_get_native_system_info
= 0;
5913 g_b_init_get_system_times
= 0;
5914 num_of_processors
= 0;
5915 /* The following sets a handler for shutdown notifications for
5916 console apps. This actually applies to Emacs in both console and
5917 GUI modes, since we had to fool windows into thinking emacs is a
5918 console application to get console mode to work. */
5919 SetConsoleCtrlHandler(shutdown_handler
, TRUE
);
5921 /* "None" is the default group name on standalone workstations. */
5922 strcpy (dflt_group_name
, "None");
5925 /* For make-serial-process */
5926 int serial_open (char *port
)
5932 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5933 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5934 if (hnd
== INVALID_HANDLE_VALUE
)
5935 error ("Could not open %s", port
);
5936 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5938 error ("Could not open %s", port
);
5942 error ("Could not create child process");
5944 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5945 fd_info
[ fd
].hnd
= hnd
;
5946 fd_info
[ fd
].flags
|=
5947 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5948 if (fd_info
[ fd
].cp
!= NULL
)
5950 error ("fd_info[fd = %d] is already in use", fd
);
5952 fd_info
[ fd
].cp
= cp
;
5953 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5954 if (cp
->ovl_read
.hEvent
== NULL
)
5955 error ("Could not create read event");
5956 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5957 if (cp
->ovl_write
.hEvent
== NULL
)
5958 error ("Could not create write event");
5963 /* For serial-process-configure */
5965 serial_configure (struct Lisp_Process
*p
,
5966 Lisp_Object contact
)
5968 Lisp_Object childp2
= Qnil
;
5969 Lisp_Object tem
= Qnil
;
5973 char summary
[4] = "???"; /* This usually becomes "8N1". */
5975 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
5976 error ("Not a serial process");
5977 hnd
= fd_info
[ p
->outfd
].hnd
;
5979 childp2
= Fcopy_sequence (p
->childp
);
5981 /* Initialize timeouts for blocking read and blocking write. */
5982 if (!GetCommTimeouts (hnd
, &ct
))
5983 error ("GetCommTimeouts() failed");
5984 ct
.ReadIntervalTimeout
= 0;
5985 ct
.ReadTotalTimeoutMultiplier
= 0;
5986 ct
.ReadTotalTimeoutConstant
= 0;
5987 ct
.WriteTotalTimeoutMultiplier
= 0;
5988 ct
.WriteTotalTimeoutConstant
= 0;
5989 if (!SetCommTimeouts (hnd
, &ct
))
5990 error ("SetCommTimeouts() failed");
5991 /* Read port attributes and prepare default configuration. */
5992 memset (&dcb
, 0, sizeof (dcb
));
5993 dcb
.DCBlength
= sizeof (DCB
);
5994 if (!GetCommState (hnd
, &dcb
))
5995 error ("GetCommState() failed");
5998 dcb
.fAbortOnError
= FALSE
;
5999 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6004 /* Configure speed. */
6005 if (!NILP (Fplist_member (contact
, QCspeed
)))
6006 tem
= Fplist_get (contact
, QCspeed
);
6008 tem
= Fplist_get (p
->childp
, QCspeed
);
6010 dcb
.BaudRate
= XINT (tem
);
6011 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6013 /* Configure bytesize. */
6014 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6015 tem
= Fplist_get (contact
, QCbytesize
);
6017 tem
= Fplist_get (p
->childp
, QCbytesize
);
6019 tem
= make_number (8);
6021 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6022 error (":bytesize must be nil (8), 7, or 8");
6023 dcb
.ByteSize
= XINT (tem
);
6024 summary
[0] = XINT (tem
) + '0';
6025 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6027 /* Configure parity. */
6028 if (!NILP (Fplist_member (contact
, QCparity
)))
6029 tem
= Fplist_get (contact
, QCparity
);
6031 tem
= Fplist_get (p
->childp
, QCparity
);
6032 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6033 error (":parity must be nil (no parity), `even', or `odd'");
6034 dcb
.fParity
= FALSE
;
6035 dcb
.Parity
= NOPARITY
;
6036 dcb
.fErrorChar
= FALSE
;
6041 else if (EQ (tem
, Qeven
))
6045 dcb
.Parity
= EVENPARITY
;
6046 dcb
.fErrorChar
= TRUE
;
6048 else if (EQ (tem
, Qodd
))
6052 dcb
.Parity
= ODDPARITY
;
6053 dcb
.fErrorChar
= TRUE
;
6055 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6057 /* Configure stopbits. */
6058 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6059 tem
= Fplist_get (contact
, QCstopbits
);
6061 tem
= Fplist_get (p
->childp
, QCstopbits
);
6063 tem
= make_number (1);
6065 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6066 error (":stopbits must be nil (1 stopbit), 1, or 2");
6067 summary
[2] = XINT (tem
) + '0';
6068 if (XINT (tem
) == 1)
6069 dcb
.StopBits
= ONESTOPBIT
;
6070 else if (XINT (tem
) == 2)
6071 dcb
.StopBits
= TWOSTOPBITS
;
6072 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6074 /* Configure flowcontrol. */
6075 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6076 tem
= Fplist_get (contact
, QCflowcontrol
);
6078 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6079 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6080 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6081 dcb
.fOutxCtsFlow
= FALSE
;
6082 dcb
.fOutxDsrFlow
= FALSE
;
6083 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6084 dcb
.fDsrSensitivity
= FALSE
;
6085 dcb
.fTXContinueOnXoff
= FALSE
;
6088 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6089 dcb
.XonChar
= 17; /* Control-Q */
6090 dcb
.XoffChar
= 19; /* Control-S */
6093 /* Already configured. */
6095 else if (EQ (tem
, Qhw
))
6097 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6098 dcb
.fOutxCtsFlow
= TRUE
;
6100 else if (EQ (tem
, Qsw
))
6105 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6107 /* Activate configuration. */
6108 if (!SetCommState (hnd
, &dcb
))
6109 error ("SetCommState() failed");
6111 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6112 p
->childp
= childp2
;
6117 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6118 (do not change this comment) */