1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23 #include <stddef.h> /* for offsetof */
26 #include <float.h> /* for DBL_EPSILON */
34 #include <sys/utime.h>
35 #include <mbstring.h> /* for _mbspbrk */
39 /* must include CRT headers *before* config.h */
74 #define _ANONYMOUS_UNION
75 #define _ANONYMOUS_STRUCT
78 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
79 use a different name to avoid compilation problems. */
80 typedef struct _MEMORY_STATUS_EX
{
83 DWORDLONG ullTotalPhys
;
84 DWORDLONG ullAvailPhys
;
85 DWORDLONG ullTotalPageFile
;
86 DWORDLONG ullAvailPageFile
;
87 DWORDLONG ullTotalVirtual
;
88 DWORDLONG ullAvailVirtual
;
89 DWORDLONG ullAvailExtendedVirtual
;
90 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
97 /* This either is not in psapi.h or guarded by higher value of
98 _WIN32_WINNT than what we use. */
99 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
101 DWORD PageFaultCount
;
102 DWORD PeakWorkingSetSize
;
103 DWORD WorkingSetSize
;
104 DWORD QuotaPeakPagedPoolUsage
;
105 DWORD QuotaPagedPoolUsage
;
106 DWORD QuotaPeakNonPagedPoolUsage
;
107 DWORD QuotaNonPagedPoolUsage
;
109 DWORD PeakPagefileUsage
;
111 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
113 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
114 #include <sys/socket.h>
138 #include "dispextern.h" /* for xstrcasecmp */
139 #include "coding.h" /* for Vlocale_coding_system */
141 /* For serial_configure and serial_open. */
144 extern Lisp_Object QCport
, QCspeed
, QCprocess
;
145 extern Lisp_Object QCbytesize
, QCstopbits
, QCparity
, Qodd
, Qeven
;
146 extern Lisp_Object QCflowcontrol
, Qhw
, Qsw
, QCsummary
;
148 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
149 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
151 void globals_of_w32 ();
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 sigemptyset (sigset_t
*set
)
1491 sigaddset (sigset_t
*set
, int signo
)
1497 sigfillset (sigset_t
*set
)
1503 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1509 setpgrp (int pid
, int gid
)
1520 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1523 w32_get_resource (key
, lpdwtype
)
1528 HKEY hrootkey
= NULL
;
1531 /* Check both the current user and the local machine to see if
1532 we have any resources. */
1534 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1538 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1539 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1540 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1542 RegCloseKey (hrootkey
);
1548 RegCloseKey (hrootkey
);
1551 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1555 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1556 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1557 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1559 RegCloseKey (hrootkey
);
1565 RegCloseKey (hrootkey
);
1571 char *get_emacs_configuration (void);
1572 extern Lisp_Object Vsystem_configuration
;
1575 init_environment (char ** argv
)
1577 static const char * const tempdirs
[] = {
1578 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1583 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1585 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1586 temporary files and assume "/tmp" if $TMPDIR is unset, which
1587 will break on DOS/Windows. Refuse to work if we cannot find
1588 a directory, not even "c:/", usable for that purpose. */
1589 for (i
= 0; i
< imax
; i
++)
1591 const char *tmp
= tempdirs
[i
];
1594 tmp
= getenv (tmp
+ 1);
1595 /* Note that `access' can lie to us if the directory resides on a
1596 read-only filesystem, like CD-ROM or a write-protected floppy.
1597 The only way to be really sure is to actually create a file and
1598 see if it succeeds. But I think that's too much to ask. */
1599 if (tmp
&& _access (tmp
, D_OK
) == 0)
1601 char * var
= alloca (strlen (tmp
) + 8);
1602 sprintf (var
, "TMPDIR=%s", tmp
);
1603 _putenv (strdup (var
));
1610 Fcons (build_string ("no usable temporary directories found!!"),
1612 "While setting TMPDIR: ");
1614 /* Check for environment variables and use registry settings if they
1615 don't exist. Fallback on default values where applicable. */
1620 char locale_name
[32];
1621 struct stat ignored
;
1622 char default_home
[MAX_PATH
];
1624 static const struct env_entry
1631 {"PRELOAD_WINSOCK", NULL
},
1632 {"emacs_dir", "C:/emacs"},
1633 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1634 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1635 {"EMACSDATA", "%emacs_dir%/etc"},
1636 {"EMACSPATH", "%emacs_dir%/bin"},
1637 /* We no longer set INFOPATH because Info-default-directory-list
1639 /* {"INFOPATH", "%emacs_dir%/info"}, */
1640 {"EMACSDOC", "%emacs_dir%/etc"},
1645 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1647 /* We need to copy dflt_envvars[] and work on the copy because we
1648 don't want the dumped Emacs to inherit the values of
1649 environment variables we saw during dumping (which could be on
1650 a different system). The defaults above must be left intact. */
1651 struct env_entry env_vars
[N_ENV_VARS
];
1653 for (i
= 0; i
< N_ENV_VARS
; i
++)
1654 env_vars
[i
] = dflt_envvars
[i
];
1656 /* For backwards compatibility, check if a .emacs file exists in C:/
1657 If not, then we can try to default to the appdata directory under the
1658 user's profile, which is more likely to be writable. */
1659 if (stat ("C:/.emacs", &ignored
) < 0)
1661 HRESULT profile_result
;
1662 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1663 of Windows 95 and NT4 that have not been updated to include
1665 ShGetFolderPath_fn get_folder_path
;
1666 get_folder_path
= (ShGetFolderPath_fn
)
1667 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1669 if (get_folder_path
!= NULL
)
1671 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1674 /* If we can't get the appdata dir, revert to old behavior. */
1675 if (profile_result
== S_OK
)
1676 env_vars
[0].def_value
= default_home
;
1680 /* Get default locale info and use it for LANG. */
1681 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1682 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1683 locale_name
, sizeof (locale_name
)))
1685 for (i
= 0; i
< N_ENV_VARS
; i
++)
1687 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1689 env_vars
[i
].def_value
= locale_name
;
1695 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1697 /* Treat emacs_dir specially: set it unconditionally based on our
1698 location, if it appears that we are running from the bin subdir
1699 of a standard installation. */
1702 char modname
[MAX_PATH
];
1704 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1706 if ((p
= strrchr (modname
, '\\')) == NULL
)
1710 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 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
));
1721 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1723 /* FIXME: should use substring of get_emacs_configuration ().
1724 But I don't think the Windows build supports alpha, mips etc
1725 anymore, so have taken the easy option for now. */
1726 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1729 p
= strrchr (modname
, '\\');
1733 p
= strrchr (modname
, '\\');
1734 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1736 char buf
[SET_ENV_BUF_SIZE
];
1739 for (p
= modname
; *p
; p
++)
1740 if (*p
== '\\') *p
= '/';
1742 _snprintf (buf
, sizeof(buf
)-1, "emacs_dir=%s", modname
);
1743 _putenv (strdup (buf
));
1749 for (i
= 0; i
< N_ENV_VARS
; i
++)
1751 if (!getenv (env_vars
[i
].name
))
1755 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1756 /* Also ignore empty environment variables. */
1760 lpval
= env_vars
[i
].def_value
;
1761 dwType
= REG_EXPAND_SZ
;
1767 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1769 if (dwType
== REG_EXPAND_SZ
)
1770 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof(buf1
));
1771 else if (dwType
== REG_SZ
)
1772 strcpy (buf1
, lpval
);
1773 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1775 _snprintf (buf2
, sizeof(buf2
)-1, "%s=%s", env_vars
[i
].name
,
1777 _putenv (strdup (buf2
));
1787 /* Rebuild system configuration to reflect invoking system. */
1788 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1790 /* Another special case: on NT, the PATH variable is actually named
1791 "Path" although cmd.exe (perhaps NT itself) arranges for
1792 environment variable lookup and setting to be case insensitive.
1793 However, Emacs assumes a fully case sensitive environment, so we
1794 need to change "Path" to "PATH" to match the expectations of
1795 various elisp packages. We do this by the sneaky method of
1796 modifying the string in the C runtime environ entry.
1798 The same applies to COMSPEC. */
1802 for (envp
= environ
; *envp
; envp
++)
1803 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1804 memcpy (*envp
, "PATH=", 5);
1805 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1806 memcpy (*envp
, "COMSPEC=", 8);
1809 /* Remember the initial working directory for getwd, then make the
1810 real wd be the location of emacs.exe to avoid conflicts when
1811 renaming or deleting directories. (We also don't call chdir when
1812 running subprocesses for the same reason.) */
1813 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1818 static char modname
[MAX_PATH
];
1820 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1822 if ((p
= strrchr (modname
, '\\')) == NULL
)
1826 SetCurrentDirectory (modname
);
1828 /* Ensure argv[0] has the full path to Emacs. */
1833 /* Determine if there is a middle mouse button, to allow parse_button
1834 to decide whether right mouse events should be mouse-2 or
1836 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1842 emacs_root_dir (void)
1844 static char root_dir
[FILENAME_MAX
];
1847 p
= getenv ("emacs_dir");
1850 strcpy (root_dir
, p
);
1851 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1852 dostounix_filename (root_dir
);
1856 /* We don't have scripts to automatically determine the system configuration
1857 for Emacs before it's compiled, and we don't want to have to make the
1858 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1862 get_emacs_configuration (void)
1864 char *arch
, *oem
, *os
;
1866 static char configuration_buffer
[32];
1868 /* Determine the processor type. */
1869 switch (get_processor_type ())
1872 #ifdef PROCESSOR_INTEL_386
1873 case PROCESSOR_INTEL_386
:
1874 case PROCESSOR_INTEL_486
:
1875 case PROCESSOR_INTEL_PENTIUM
:
1880 #ifdef PROCESSOR_MIPS_R2000
1881 case PROCESSOR_MIPS_R2000
:
1882 case PROCESSOR_MIPS_R3000
:
1883 case PROCESSOR_MIPS_R4000
:
1888 #ifdef PROCESSOR_ALPHA_21064
1889 case PROCESSOR_ALPHA_21064
:
1899 /* Use the OEM field to reflect the compiler/library combination. */
1901 #define COMPILER_NAME "msvc"
1904 #define COMPILER_NAME "mingw"
1906 #define COMPILER_NAME "unknown"
1909 oem
= COMPILER_NAME
;
1911 switch (osinfo_cache
.dwPlatformId
) {
1912 case VER_PLATFORM_WIN32_NT
:
1914 build_num
= osinfo_cache
.dwBuildNumber
;
1916 case VER_PLATFORM_WIN32_WINDOWS
:
1917 if (osinfo_cache
.dwMinorVersion
== 0) {
1922 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1924 case VER_PLATFORM_WIN32s
:
1925 /* Not supported, should not happen. */
1927 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1935 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1936 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1937 get_w32_major_version (), get_w32_minor_version (), build_num
);
1939 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1942 return configuration_buffer
;
1946 get_emacs_configuration_options (void)
1948 static char options_buffer
[256];
1950 /* Work out the effective configure options for this build. */
1952 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1955 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1957 #define COMPILER_VERSION ""
1961 sprintf (options_buffer
, COMPILER_VERSION
);
1963 strcat (options_buffer
, " --no-opt");
1966 strcat (options_buffer
, " --cflags");
1967 strcat (options_buffer
, USER_CFLAGS
);
1970 strcat (options_buffer
, " --ldflags");
1971 strcat (options_buffer
, USER_LDFLAGS
);
1973 return options_buffer
;
1977 #include <sys/timeb.h>
1979 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1981 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1986 tv
->tv_sec
= tb
.time
;
1987 tv
->tv_usec
= tb
.millitm
* 1000L;
1990 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1991 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1995 /* ------------------------------------------------------------------------- */
1996 /* IO support and wrapper functions for W32 API. */
1997 /* ------------------------------------------------------------------------- */
1999 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2000 on network directories, so we handle that case here.
2001 (Ulrich Leodolter, 1/11/95). */
2003 sys_ctime (const time_t *t
)
2005 char *str
= (char *) ctime (t
);
2006 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2009 /* Emulate sleep...we could have done this with a define, but that
2010 would necessitate including windows.h in the files that used it.
2011 This is much easier. */
2013 sys_sleep (int seconds
)
2015 Sleep (seconds
* 1000);
2018 /* Internal MSVC functions for low-level descriptor munging */
2019 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2020 extern int __cdecl
_free_osfhnd (int fd
);
2022 /* parallel array of private info on file handles */
2023 filedesc fd_info
[ MAXDESC
];
2025 typedef struct volume_info_data
{
2026 struct volume_info_data
* next
;
2028 /* time when info was obtained */
2031 /* actual volume info */
2040 /* Global referenced by various functions. */
2041 static volume_info_data volume_info
;
2043 /* Vector to indicate which drives are local and fixed (for which cached
2044 data never expires). */
2045 static BOOL fixed_drives
[26];
2047 /* Consider cached volume information to be stale if older than 10s,
2048 at least for non-local drives. Info for fixed drives is never stale. */
2049 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2050 #define VOLINFO_STILL_VALID( root_dir, info ) \
2051 ( ( isalpha (root_dir[0]) && \
2052 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2053 || GetTickCount () - info->timestamp < 10000 )
2055 /* Cache support functions. */
2057 /* Simple linked list with linear search is sufficient. */
2058 static volume_info_data
*volume_cache
= NULL
;
2060 static volume_info_data
*
2061 lookup_volume_info (char * root_dir
)
2063 volume_info_data
* info
;
2065 for (info
= volume_cache
; info
; info
= info
->next
)
2066 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2072 add_volume_info (char * root_dir
, volume_info_data
* info
)
2074 info
->root_dir
= xstrdup (root_dir
);
2075 info
->next
= volume_cache
;
2076 volume_cache
= info
;
2080 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2081 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2082 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2084 GetCachedVolumeInformation (char * root_dir
)
2086 volume_info_data
* info
;
2087 char default_root
[ MAX_PATH
];
2089 /* NULL for root_dir means use root from current directory. */
2090 if (root_dir
== NULL
)
2092 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2094 parse_root (default_root
, &root_dir
);
2096 root_dir
= default_root
;
2099 /* Local fixed drives can be cached permanently. Removable drives
2100 cannot be cached permanently, since the volume name and serial
2101 number (if nothing else) can change. Remote drives should be
2102 treated as if they are removable, since there is no sure way to
2103 tell whether they are or not. Also, the UNC association of drive
2104 letters mapped to remote volumes can be changed at any time (even
2105 by other processes) without notice.
2107 As a compromise, so we can benefit from caching info for remote
2108 volumes, we use a simple expiry mechanism to invalidate cache
2109 entries that are more than ten seconds old. */
2112 /* No point doing this, because WNetGetConnection is even slower than
2113 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2114 GetDriveType is about the only call of this type which does not
2115 involve network access, and so is extremely quick). */
2117 /* Map drive letter to UNC if remote. */
2118 if ( isalpha( root_dir
[0] ) && !fixed
[ DRIVE_INDEX( root_dir
[0] ) ] )
2120 char remote_name
[ 256 ];
2121 char drive
[3] = { root_dir
[0], ':' };
2123 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2125 /* do something */ ;
2129 info
= lookup_volume_info (root_dir
);
2131 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2139 /* Info is not cached, or is stale. */
2140 if (!GetVolumeInformation (root_dir
,
2141 name
, sizeof (name
),
2145 type
, sizeof (type
)))
2148 /* Cache the volume information for future use, overwriting existing
2149 entry if present. */
2152 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2153 add_volume_info (root_dir
, info
);
2161 info
->name
= xstrdup (name
);
2162 info
->serialnum
= serialnum
;
2163 info
->maxcomp
= maxcomp
;
2164 info
->flags
= flags
;
2165 info
->type
= xstrdup (type
);
2166 info
->timestamp
= GetTickCount ();
2172 /* Get information on the volume where name is held; set path pointer to
2173 start of pathname in name (past UNC header\volume header if present). */
2175 get_volume_info (const char * name
, const char ** pPath
)
2177 char temp
[MAX_PATH
];
2178 char *rootname
= NULL
; /* default to current volume */
2179 volume_info_data
* info
;
2184 /* find the root name of the volume if given */
2185 if (isalpha (name
[0]) && name
[1] == ':')
2193 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2200 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2213 info
= GetCachedVolumeInformation (rootname
);
2216 /* Set global referenced by other functions. */
2217 volume_info
= *info
;
2223 /* Determine if volume is FAT format (ie. only supports short 8.3
2224 names); also set path pointer to start of pathname in name. */
2226 is_fat_volume (const char * name
, const char ** pPath
)
2228 if (get_volume_info (name
, pPath
))
2229 return (volume_info
.maxcomp
== 12);
2233 /* Map filename to a valid 8.3 name if necessary. */
2235 map_w32_filename (const char * name
, const char ** pPath
)
2237 static char shortname
[MAX_PATH
];
2238 char * str
= shortname
;
2241 const char * save_name
= name
;
2243 if (strlen (name
) >= MAX_PATH
)
2245 /* Return a filename which will cause callers to fail. */
2246 strcpy (shortname
, "?");
2250 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2252 register int left
= 8; /* maximum number of chars in part */
2253 register int extn
= 0; /* extension added? */
2254 register int dots
= 2; /* maximum number of dots allowed */
2257 *str
++ = *name
++; /* skip past UNC header */
2259 while ((c
= *name
++))
2266 extn
= 0; /* reset extension flags */
2267 dots
= 2; /* max 2 dots */
2268 left
= 8; /* max length 8 for main part */
2272 extn
= 0; /* reset extension flags */
2273 dots
= 2; /* max 2 dots */
2274 left
= 8; /* max length 8 for main part */
2279 /* Convert path components of the form .xxx to _xxx,
2280 but leave . and .. as they are. This allows .emacs
2281 to be read as _emacs, for example. */
2285 IS_DIRECTORY_SEP (*name
))
2300 extn
= 1; /* we've got an extension */
2301 left
= 3; /* 3 chars in extension */
2305 /* any embedded dots after the first are converted to _ */
2310 case '#': /* don't lose these, they're important */
2312 str
[-1] = c
; /* replace last character of part */
2317 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2319 dots
= 0; /* started a path component */
2328 strcpy (shortname
, name
);
2329 unixtodos_filename (shortname
);
2333 *pPath
= shortname
+ (path
- save_name
);
2339 is_exec (const char * name
)
2341 char * p
= strrchr (name
, '.');
2344 && (xstrcasecmp (p
, ".exe") == 0 ||
2345 xstrcasecmp (p
, ".com") == 0 ||
2346 xstrcasecmp (p
, ".bat") == 0 ||
2347 xstrcasecmp (p
, ".cmd") == 0));
2350 /* Emulate the Unix directory procedures opendir, closedir,
2351 and readdir. We can't use the procedures supplied in sysdep.c,
2352 so we provide them here. */
2354 struct direct dir_static
; /* simulated directory contents */
2355 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2356 static int dir_is_fat
;
2357 static char dir_pathname
[MAXPATHLEN
+1];
2358 static WIN32_FIND_DATA dir_find_data
;
2360 /* Support shares on a network resource as subdirectories of a read-only
2362 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2363 HANDLE
open_unc_volume (const char *);
2364 char *read_unc_volume (HANDLE
, char *, int);
2365 void close_unc_volume (HANDLE
);
2368 opendir (char *filename
)
2372 /* Opening is done by FindFirstFile. However, a read is inherent to
2373 this operation, so we defer the open until read time. */
2375 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2377 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2380 if (is_unc_volume (filename
))
2382 wnet_enum_handle
= open_unc_volume (filename
);
2383 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2387 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2394 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2395 dir_pathname
[MAXPATHLEN
] = '\0';
2396 dir_is_fat
= is_fat_volume (filename
, NULL
);
2402 closedir (DIR *dirp
)
2404 /* If we have a find-handle open, close it. */
2405 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2407 FindClose (dir_find_handle
);
2408 dir_find_handle
= INVALID_HANDLE_VALUE
;
2410 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2412 close_unc_volume (wnet_enum_handle
);
2413 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2415 xfree ((char *) dirp
);
2421 int downcase
= !NILP (Vw32_downcase_file_names
);
2423 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2425 if (!read_unc_volume (wnet_enum_handle
,
2426 dir_find_data
.cFileName
,
2430 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2431 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2433 char filename
[MAXNAMLEN
+ 3];
2436 strcpy (filename
, dir_pathname
);
2437 ln
= strlen (filename
) - 1;
2438 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2439 strcat (filename
, "\\");
2440 strcat (filename
, "*");
2442 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2444 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2449 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2453 /* Emacs never uses this value, so don't bother making it match
2454 value returned by stat(). */
2455 dir_static
.d_ino
= 1;
2457 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2459 /* If the file name in cFileName[] includes `?' characters, it means
2460 the original file name used characters that cannot be represented
2461 by the current ANSI codepage. To avoid total lossage, retrieve
2462 the short 8+3 alias of the long file name. */
2463 if (_mbspbrk (dir_static
.d_name
, "?"))
2465 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2466 downcase
= 1; /* 8+3 aliases are returned in all caps */
2468 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2469 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2470 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2472 /* If the file name in cFileName[] includes `?' characters, it means
2473 the original file name used characters that cannot be represented
2474 by the current ANSI codepage. To avoid total lossage, retrieve
2475 the short 8+3 alias of the long file name. */
2476 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2478 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2479 /* 8+3 aliases are returned in all caps, which could break
2480 various alists that look at filenames' extensions. */
2484 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2485 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2487 _strlwr (dir_static
.d_name
);
2491 for (p
= dir_static
.d_name
; *p
; p
++)
2492 if (*p
>= 'a' && *p
<= 'z')
2495 _strlwr (dir_static
.d_name
);
2502 open_unc_volume (const char *path
)
2508 nr
.dwScope
= RESOURCE_GLOBALNET
;
2509 nr
.dwType
= RESOURCETYPE_DISK
;
2510 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2511 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2512 nr
.lpLocalName
= NULL
;
2513 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2514 nr
.lpComment
= NULL
;
2515 nr
.lpProvider
= NULL
;
2517 result
= WNetOpenEnum(RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2518 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2520 if (result
== NO_ERROR
)
2523 return INVALID_HANDLE_VALUE
;
2527 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2531 DWORD bufsize
= 512;
2536 buffer
= alloca (bufsize
);
2537 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2538 if (result
!= NO_ERROR
)
2541 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2542 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2544 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2547 strncpy (readbuf
, ptr
, size
);
2552 close_unc_volume (HANDLE henum
)
2554 if (henum
!= INVALID_HANDLE_VALUE
)
2555 WNetCloseEnum (henum
);
2559 unc_volume_file_attributes (const char *path
)
2564 henum
= open_unc_volume (path
);
2565 if (henum
== INVALID_HANDLE_VALUE
)
2568 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2570 close_unc_volume (henum
);
2575 /* Ensure a network connection is authenticated. */
2577 logon_network_drive (const char *path
)
2579 NETRESOURCE resource
;
2580 char share
[MAX_PATH
];
2585 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2586 drvtype
= DRIVE_REMOTE
;
2587 else if (path
[0] == '\0' || path
[1] != ':')
2588 drvtype
= GetDriveType (NULL
);
2595 drvtype
= GetDriveType (drive
);
2598 /* Only logon to networked drives. */
2599 if (drvtype
!= DRIVE_REMOTE
)
2603 strncpy (share
, path
, MAX_PATH
);
2604 /* Truncate to just server and share name. */
2605 for (i
= 2; i
< MAX_PATH
; i
++)
2607 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2614 resource
.dwType
= RESOURCETYPE_DISK
;
2615 resource
.lpLocalName
= NULL
;
2616 resource
.lpRemoteName
= share
;
2617 resource
.lpProvider
= NULL
;
2619 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2622 /* Shadow some MSVC runtime functions to map requests for long filenames
2623 to reasonable short names if necessary. This was originally added to
2624 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2628 sys_access (const char * path
, int mode
)
2632 /* MSVC implementation doesn't recognize D_OK. */
2633 path
= map_w32_filename (path
, NULL
);
2634 if (is_unc_volume (path
))
2636 attributes
= unc_volume_file_attributes (path
);
2637 if (attributes
== -1) {
2642 else if ((attributes
= GetFileAttributes (path
)) == -1)
2644 /* Should try mapping GetLastError to errno; for now just indicate
2645 that path doesn't exist. */
2649 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2654 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2659 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2668 sys_chdir (const char * path
)
2670 return _chdir (map_w32_filename (path
, NULL
));
2674 sys_chmod (const char * path
, int mode
)
2676 return _chmod (map_w32_filename (path
, NULL
), mode
);
2680 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2682 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2688 sys_creat (const char * path
, int mode
)
2690 return _creat (map_w32_filename (path
, NULL
), mode
);
2694 sys_fopen(const char * path
, const char * mode
)
2698 const char * mode_save
= mode
;
2700 /* Force all file handles to be non-inheritable. This is necessary to
2701 ensure child processes don't unwittingly inherit handles that might
2702 prevent future file access. */
2706 else if (mode
[0] == 'w' || mode
[0] == 'a')
2707 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2711 /* Only do simplistic option parsing. */
2715 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2718 else if (mode
[0] == 'b')
2723 else if (mode
[0] == 't')
2730 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2734 return _fdopen (fd
, mode_save
);
2737 /* This only works on NTFS volumes, but is useful to have. */
2739 sys_link (const char * old
, const char * new)
2743 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2745 if (old
== NULL
|| new == NULL
)
2751 strcpy (oldname
, map_w32_filename (old
, NULL
));
2752 strcpy (newname
, map_w32_filename (new, NULL
));
2754 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2755 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2756 if (fileh
!= INVALID_HANDLE_VALUE
)
2760 /* Confusingly, the "alternate" stream name field does not apply
2761 when restoring a hard link, and instead contains the actual
2762 stream data for the link (ie. the name of the link to create).
2763 The WIN32_STREAM_ID structure before the cStreamName field is
2764 the stream header, which is then immediately followed by the
2768 WIN32_STREAM_ID wid
;
2769 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2772 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2773 data
.wid
.cStreamName
, MAX_PATH
);
2776 LPVOID context
= NULL
;
2779 data
.wid
.dwStreamId
= BACKUP_LINK
;
2780 data
.wid
.dwStreamAttributes
= 0;
2781 data
.wid
.Size
.LowPart
= wlen
* sizeof(WCHAR
);
2782 data
.wid
.Size
.HighPart
= 0;
2783 data
.wid
.dwStreamNameSize
= 0;
2785 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2786 offsetof (WIN32_STREAM_ID
, cStreamName
)
2787 + data
.wid
.Size
.LowPart
,
2788 &wbytes
, FALSE
, FALSE
, &context
)
2789 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2796 /* Should try mapping GetLastError to errno; for now just
2797 indicate a general error (eg. links not supported). */
2798 errno
= EINVAL
; // perhaps EMLINK?
2802 CloseHandle (fileh
);
2811 sys_mkdir (const char * path
)
2813 return _mkdir (map_w32_filename (path
, NULL
));
2816 /* Because of long name mapping issues, we need to implement this
2817 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2818 a unique name, instead of setting the input template to an empty
2821 Standard algorithm seems to be use pid or tid with a letter on the
2822 front (in place of the 6 X's) and cycle through the letters to find a
2823 unique name. We extend that to allow any reasonable character as the
2824 first of the 6 X's. */
2826 sys_mktemp (char * template)
2830 unsigned uid
= GetCurrentThreadId ();
2831 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2833 if (template == NULL
)
2835 p
= template + strlen (template);
2837 /* replace up to the last 5 X's with uid in decimal */
2838 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2840 p
[0] = '0' + uid
% 10;
2844 if (i
< 0 && p
[0] == 'X')
2849 int save_errno
= errno
;
2850 p
[0] = first_char
[i
];
2851 if (sys_access (template, 0) < 0)
2857 while (++i
< sizeof (first_char
));
2860 /* Template is badly formed or else we can't generate a unique name,
2861 so return empty string */
2867 sys_open (const char * path
, int oflag
, int mode
)
2869 const char* mpath
= map_w32_filename (path
, NULL
);
2870 /* Try to open file without _O_CREAT, to be able to write to hidden
2871 and system files. Force all file handles to be
2873 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2876 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2880 sys_rename (const char * oldname
, const char * newname
)
2883 char temp
[MAX_PATH
];
2885 /* MoveFile on Windows 95 doesn't correctly change the short file name
2886 alias in a number of circumstances (it is not easy to predict when
2887 just by looking at oldname and newname, unfortunately). In these
2888 cases, renaming through a temporary name avoids the problem.
2890 A second problem on Windows 95 is that renaming through a temp name when
2891 newname is uppercase fails (the final long name ends up in
2892 lowercase, although the short alias might be uppercase) UNLESS the
2893 long temp name is not 8.3.
2895 So, on Windows 95 we always rename through a temp name, and we make sure
2896 the temp name has a long extension to ensure correct renaming. */
2898 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2900 if (os_subtype
== OS_WIN95
)
2906 oldname
= map_w32_filename (oldname
, NULL
);
2907 if (o
= strrchr (oldname
, '\\'))
2910 o
= (char *) oldname
;
2912 if (p
= strrchr (temp
, '\\'))
2919 /* Force temp name to require a manufactured 8.3 alias - this
2920 seems to make the second rename work properly. */
2921 sprintf (p
, "_.%s.%u", o
, i
);
2923 result
= rename (oldname
, temp
);
2925 /* This loop must surely terminate! */
2926 while (result
< 0 && errno
== EEXIST
);
2931 /* Emulate Unix behavior - newname is deleted if it already exists
2932 (at least if it is a file; don't do this for directories).
2934 Since we mustn't do this if we are just changing the case of the
2935 file name (we would end up deleting the file we are trying to
2936 rename!), we let rename detect if the destination file already
2937 exists - that way we avoid the possible pitfalls of trying to
2938 determine ourselves whether two names really refer to the same
2939 file, which is not always possible in the general case. (Consider
2940 all the permutations of shared or subst'd drives, etc.) */
2942 newname
= map_w32_filename (newname
, NULL
);
2943 result
= rename (temp
, newname
);
2947 && _chmod (newname
, 0666) == 0
2948 && _unlink (newname
) == 0)
2949 result
= rename (temp
, newname
);
2955 sys_rmdir (const char * path
)
2957 return _rmdir (map_w32_filename (path
, NULL
));
2961 sys_unlink (const char * path
)
2963 path
= map_w32_filename (path
, NULL
);
2965 /* On Unix, unlink works without write permission. */
2966 _chmod (path
, 0666);
2967 return _unlink (path
);
2970 static FILETIME utc_base_ft
;
2971 static ULONGLONG utc_base
; /* In 100ns units */
2972 static int init
= 0;
2974 #define FILETIME_TO_U64(result, ft) \
2976 ULARGE_INTEGER uiTemp; \
2977 uiTemp.LowPart = (ft).dwLowDateTime; \
2978 uiTemp.HighPart = (ft).dwHighDateTime; \
2979 result = uiTemp.QuadPart; \
2983 initialize_utc_base ()
2985 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2994 st
.wMilliseconds
= 0;
2996 SystemTimeToFileTime (&st
, &utc_base_ft
);
2997 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3001 convert_time (FILETIME ft
)
3007 initialize_utc_base();
3011 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3014 FILETIME_TO_U64 (tmp
, ft
);
3015 return (time_t) ((tmp
- utc_base
) / 10000000L);
3020 convert_from_time_t (time_t time
, FILETIME
* pft
)
3026 initialize_utc_base ();
3030 /* time in 100ns units since 1-Jan-1601 */
3031 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3032 pft
->dwHighDateTime
= tmp
.HighPart
;
3033 pft
->dwLowDateTime
= tmp
.LowPart
;
3037 /* No reason to keep this; faking inode values either by hashing or even
3038 using the file index from GetInformationByHandle, is not perfect and
3039 so by default Emacs doesn't use the inode values on Windows.
3040 Instead, we now determine file-truename correctly (except for
3041 possible drive aliasing etc). */
3043 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3045 hashval (const unsigned char * str
)
3050 h
= (h
<< 4) + *str
++;
3056 /* Return the hash value of the canonical pathname, excluding the
3057 drive/UNC header, to get a hopefully unique inode number. */
3059 generate_inode_val (const char * name
)
3061 char fullname
[ MAX_PATH
];
3065 /* Get the truly canonical filename, if it exists. (Note: this
3066 doesn't resolve aliasing due to subst commands, or recognise hard
3068 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3071 parse_root (fullname
, &p
);
3072 /* Normal W32 filesystems are still case insensitive. */
3079 static PSECURITY_DESCRIPTOR
3080 get_file_security_desc (const char *fname
)
3082 PSECURITY_DESCRIPTOR psd
= NULL
;
3084 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3085 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3087 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3089 err
= GetLastError ();
3090 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3094 psd
= xmalloc (sd_len
);
3095 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3107 unsigned n_subauthorities
;
3109 /* Use the last sub-authority value of the RID, the relative
3110 portion of the SID, as user/group ID. */
3111 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3112 if (n_subauthorities
< 1)
3113 return 0; /* the "World" RID */
3114 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3117 /* Caching SID and account values for faster lokup. */
3120 # define FLEXIBLE_ARRAY_MEMBER
3122 # define FLEXIBLE_ARRAY_MEMBER 1
3127 struct w32_id
*next
;
3129 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3132 static struct w32_id
*w32_idlist
;
3135 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3137 struct w32_id
*tail
, *found
;
3139 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3141 if (equal_sid ((PSID
)tail
->sid
, sid
))
3150 strcpy (name
, found
->name
);
3158 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3161 struct w32_id
*new_entry
;
3163 /* We don't want to leave behind stale cache from when Emacs was
3167 sid_len
= get_length_sid (sid
);
3168 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3171 new_entry
->rid
= id
;
3172 strcpy (new_entry
->name
, name
);
3173 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3174 new_entry
->next
= w32_idlist
;
3175 w32_idlist
= new_entry
;
3184 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3185 unsigned *id
, char *nm
, int what
)
3188 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3190 SID_NAME_USE ignore
;
3192 DWORD name_len
= sizeof (name
);
3194 DWORD domain_len
= sizeof(domain
);
3200 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3201 else if (what
== GID
)
3202 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3206 if (!result
|| !is_valid_sid (sid
))
3208 else if (!w32_cached_id (sid
, id
, nm
))
3210 /* If FNAME is a UNC, we need to lookup account on the
3211 specified machine. */
3212 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3213 && fname
[2] != '\0')
3218 for (s
= fname
+ 2, p
= machine
;
3219 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3225 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3226 domain
, &domain_len
, &ignore
)
3227 || name_len
> UNLEN
+1)
3231 *id
= get_rid (sid
);
3233 w32_add_to_cache (sid
, *id
, name
);
3240 get_file_owner_and_group (
3241 PSECURITY_DESCRIPTOR psd
,
3245 int dflt_usr
= 0, dflt_grp
= 0;
3254 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3256 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3259 /* Consider files to belong to current user/group, if we cannot get
3260 more accurate information. */
3263 st
->st_uid
= dflt_passwd
.pw_uid
;
3264 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3268 st
->st_gid
= dflt_passwd
.pw_gid
;
3269 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3273 /* Return non-zero if NAME is a potentially slow filesystem. */
3275 is_slow_fs (const char *name
)
3280 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3281 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3282 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3283 devtype
= GetDriveType (NULL
); /* use root of current drive */
3286 /* GetDriveType needs the root directory of the drive. */
3287 strncpy (drive_root
, name
, 2);
3288 drive_root
[2] = '\\';
3289 drive_root
[3] = '\0';
3290 devtype
= GetDriveType (drive_root
);
3292 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3295 /* MSVC stat function can't cope with UNC names and has other bugs, so
3296 replace it with our own. This also allows us to calculate consistent
3297 inode values without hacks in the main Emacs code. */
3299 stat (const char * path
, struct stat
* buf
)
3304 WIN32_FIND_DATA wfd
;
3306 unsigned __int64 fake_inode
;
3309 int rootdir
= FALSE
;
3310 PSECURITY_DESCRIPTOR psd
= NULL
;
3312 if (path
== NULL
|| buf
== NULL
)
3318 name
= (char *) map_w32_filename (path
, &path
);
3319 /* Must be valid filename, no wild cards or other invalid
3320 characters. We use _mbspbrk to support multibyte strings that
3321 might look to strpbrk as if they included literal *, ?, and other
3322 characters mentioned below that are disallowed by Windows
3324 if (_mbspbrk (name
, "*?|<>\""))
3330 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3331 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3332 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3337 /* Remove trailing directory separator, unless name is the root
3338 directory of a drive or UNC volume in which case ensure there
3339 is a trailing separator. */
3340 len
= strlen (name
);
3341 rootdir
= (path
>= name
+ len
- 1
3342 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3343 name
= strcpy (alloca (len
+ 2), name
);
3345 if (is_unc_volume (name
))
3347 DWORD attrs
= unc_volume_file_attributes (name
);
3352 memset (&wfd
, 0, sizeof (wfd
));
3353 wfd
.dwFileAttributes
= attrs
;
3354 wfd
.ftCreationTime
= utc_base_ft
;
3355 wfd
.ftLastAccessTime
= utc_base_ft
;
3356 wfd
.ftLastWriteTime
= utc_base_ft
;
3357 strcpy (wfd
.cFileName
, name
);
3361 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3362 strcat (name
, "\\");
3363 if (GetDriveType (name
) < 2)
3368 memset (&wfd
, 0, sizeof (wfd
));
3369 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3370 wfd
.ftCreationTime
= utc_base_ft
;
3371 wfd
.ftLastAccessTime
= utc_base_ft
;
3372 wfd
.ftLastWriteTime
= utc_base_ft
;
3373 strcpy (wfd
.cFileName
, name
);
3377 if (IS_DIRECTORY_SEP (name
[len
-1]))
3380 /* (This is hacky, but helps when doing file completions on
3381 network drives.) Optimize by using information available from
3382 active readdir if possible. */
3383 len
= strlen (dir_pathname
);
3384 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3386 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3387 && strnicmp (name
, dir_pathname
, len
) == 0
3388 && IS_DIRECTORY_SEP (name
[len
])
3389 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3391 /* This was the last entry returned by readdir. */
3392 wfd
= dir_find_data
;
3396 logon_network_drive (name
);
3398 fh
= FindFirstFile (name
, &wfd
);
3399 if (fh
== INVALID_HANDLE_VALUE
)
3408 if (!(NILP (Vw32_get_true_file_attributes
)
3409 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3410 /* No access rights required to get info. */
3411 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3412 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3413 != INVALID_HANDLE_VALUE
)
3415 /* This is more accurate in terms of gettting the correct number
3416 of links, but is quite slow (it is noticeable when Emacs is
3417 making a list of file name completions). */
3418 BY_HANDLE_FILE_INFORMATION info
;
3420 if (GetFileInformationByHandle (fh
, &info
))
3422 buf
->st_nlink
= info
.nNumberOfLinks
;
3423 /* Might as well use file index to fake inode values, but this
3424 is not guaranteed to be unique unless we keep a handle open
3425 all the time (even then there are situations where it is
3426 not unique). Reputedly, there are at most 48 bits of info
3427 (on NTFS, presumably less on FAT). */
3428 fake_inode
= info
.nFileIndexHigh
;
3430 fake_inode
+= info
.nFileIndexLow
;
3438 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3440 buf
->st_mode
= S_IFDIR
;
3444 switch (GetFileType (fh
))
3446 case FILE_TYPE_DISK
:
3447 buf
->st_mode
= S_IFREG
;
3449 case FILE_TYPE_PIPE
:
3450 buf
->st_mode
= S_IFIFO
;
3452 case FILE_TYPE_CHAR
:
3453 case FILE_TYPE_UNKNOWN
:
3455 buf
->st_mode
= S_IFCHR
;
3459 psd
= get_file_security_desc (name
);
3460 get_file_owner_and_group (psd
, name
, buf
);
3464 /* Don't bother to make this information more accurate. */
3465 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3470 get_file_owner_and_group (NULL
, name
, buf
);
3475 /* Not sure if there is any point in this. */
3476 if (!NILP (Vw32_generate_fake_inodes
))
3477 fake_inode
= generate_inode_val (name
);
3478 else if (fake_inode
== 0)
3480 /* For want of something better, try to make everything unique. */
3481 static DWORD gen_num
= 0;
3482 fake_inode
= ++gen_num
;
3486 /* MSVC defines _ino_t to be short; other libc's might not. */
3487 if (sizeof (buf
->st_ino
) == 2)
3488 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3490 buf
->st_ino
= fake_inode
;
3492 /* volume_info is set indirectly by map_w32_filename */
3493 buf
->st_dev
= volume_info
.serialnum
;
3494 buf
->st_rdev
= volume_info
.serialnum
;
3497 buf
->st_size
= wfd
.nFileSizeHigh
;
3498 buf
->st_size
<<= 32;
3499 buf
->st_size
+= wfd
.nFileSizeLow
;
3501 /* Convert timestamps to Unix format. */
3502 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3503 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3504 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3505 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3506 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3508 /* determine rwx permissions */
3509 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3510 permission
= S_IREAD
;
3512 permission
= S_IREAD
| S_IWRITE
;
3514 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3515 permission
|= S_IEXEC
;
3516 else if (is_exec (name
))
3517 permission
|= S_IEXEC
;
3519 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3524 /* Provide fstat and utime as well as stat for consistent handling of
3527 fstat (int desc
, struct stat
* buf
)
3529 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3530 BY_HANDLE_FILE_INFORMATION info
;
3531 unsigned __int64 fake_inode
;
3534 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3536 case FILE_TYPE_DISK
:
3537 buf
->st_mode
= S_IFREG
;
3538 if (!GetFileInformationByHandle (fh
, &info
))
3544 case FILE_TYPE_PIPE
:
3545 buf
->st_mode
= S_IFIFO
;
3547 case FILE_TYPE_CHAR
:
3548 case FILE_TYPE_UNKNOWN
:
3550 buf
->st_mode
= S_IFCHR
;
3552 memset (&info
, 0, sizeof (info
));
3553 info
.dwFileAttributes
= 0;
3554 info
.ftCreationTime
= utc_base_ft
;
3555 info
.ftLastAccessTime
= utc_base_ft
;
3556 info
.ftLastWriteTime
= utc_base_ft
;
3559 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3560 buf
->st_mode
= S_IFDIR
;
3562 buf
->st_nlink
= info
.nNumberOfLinks
;
3563 /* Might as well use file index to fake inode values, but this
3564 is not guaranteed to be unique unless we keep a handle open
3565 all the time (even then there are situations where it is
3566 not unique). Reputedly, there are at most 48 bits of info
3567 (on NTFS, presumably less on FAT). */
3568 fake_inode
= info
.nFileIndexHigh
;
3570 fake_inode
+= info
.nFileIndexLow
;
3572 /* MSVC defines _ino_t to be short; other libc's might not. */
3573 if (sizeof (buf
->st_ino
) == 2)
3574 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3576 buf
->st_ino
= fake_inode
;
3578 /* Consider files to belong to current user.
3579 FIXME: this should use GetSecurityInfo API, but it is only
3580 available for _WIN32_WINNT >= 0x501. */
3581 buf
->st_uid
= dflt_passwd
.pw_uid
;
3582 buf
->st_gid
= dflt_passwd
.pw_gid
;
3583 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3584 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3586 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3587 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3589 buf
->st_size
= info
.nFileSizeHigh
;
3590 buf
->st_size
<<= 32;
3591 buf
->st_size
+= info
.nFileSizeLow
;
3593 /* Convert timestamps to Unix format. */
3594 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3595 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3596 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3597 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3598 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3600 /* determine rwx permissions */
3601 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3602 permission
= S_IREAD
;
3604 permission
= S_IREAD
| S_IWRITE
;
3606 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3607 permission
|= S_IEXEC
;
3610 #if 0 /* no way of knowing the filename */
3611 char * p
= strrchr (name
, '.');
3613 (xstrcasecmp (p
, ".exe") == 0 ||
3614 xstrcasecmp (p
, ".com") == 0 ||
3615 xstrcasecmp (p
, ".bat") == 0 ||
3616 xstrcasecmp (p
, ".cmd") == 0))
3617 permission
|= S_IEXEC
;
3621 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3627 utime (const char *name
, struct utimbuf
*times
)
3629 struct utimbuf deftime
;
3636 deftime
.modtime
= deftime
.actime
= time (NULL
);
3640 /* Need write access to set times. */
3641 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3642 0, OPEN_EXISTING
, 0, NULL
);
3645 convert_from_time_t (times
->actime
, &atime
);
3646 convert_from_time_t (times
->modtime
, &mtime
);
3647 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3664 /* Support for browsing other processes and their attributes. See
3665 process.c for the Lisp bindings. */
3667 /* Helper wrapper functions. */
3669 HANDLE WINAPI
create_toolhelp32_snapshot(
3673 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3675 if (g_b_init_create_toolhelp32_snapshot
== 0)
3677 g_b_init_create_toolhelp32_snapshot
= 1;
3678 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3679 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3680 "CreateToolhelp32Snapshot");
3682 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3684 return INVALID_HANDLE_VALUE
;
3686 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3689 BOOL WINAPI
process32_first(
3691 LPPROCESSENTRY32 lppe
)
3693 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3695 if (g_b_init_process32_first
== 0)
3697 g_b_init_process32_first
= 1;
3698 s_pfn_Process32_First
= (Process32First_Proc
)
3699 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3702 if (s_pfn_Process32_First
== NULL
)
3706 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3709 BOOL WINAPI
process32_next(
3711 LPPROCESSENTRY32 lppe
)
3713 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3715 if (g_b_init_process32_next
== 0)
3717 g_b_init_process32_next
= 1;
3718 s_pfn_Process32_Next
= (Process32Next_Proc
)
3719 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3722 if (s_pfn_Process32_Next
== NULL
)
3726 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3729 BOOL WINAPI
open_thread_token (
3730 HANDLE ThreadHandle
,
3731 DWORD DesiredAccess
,
3733 PHANDLE TokenHandle
)
3735 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3736 HMODULE hm_advapi32
= NULL
;
3737 if (is_windows_9x () == TRUE
)
3739 SetLastError (ERROR_NOT_SUPPORTED
);
3742 if (g_b_init_open_thread_token
== 0)
3744 g_b_init_open_thread_token
= 1;
3745 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3746 s_pfn_Open_Thread_Token
=
3747 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3749 if (s_pfn_Open_Thread_Token
== NULL
)
3751 SetLastError (ERROR_NOT_SUPPORTED
);
3755 s_pfn_Open_Thread_Token (
3763 BOOL WINAPI
impersonate_self (
3764 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3766 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3767 HMODULE hm_advapi32
= NULL
;
3768 if (is_windows_9x () == TRUE
)
3772 if (g_b_init_impersonate_self
== 0)
3774 g_b_init_impersonate_self
= 1;
3775 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3776 s_pfn_Impersonate_Self
=
3777 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3779 if (s_pfn_Impersonate_Self
== NULL
)
3783 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3786 BOOL WINAPI
revert_to_self (void)
3788 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3789 HMODULE hm_advapi32
= NULL
;
3790 if (is_windows_9x () == TRUE
)
3794 if (g_b_init_revert_to_self
== 0)
3796 g_b_init_revert_to_self
= 1;
3797 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3798 s_pfn_Revert_To_Self
=
3799 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3801 if (s_pfn_Revert_To_Self
== NULL
)
3805 return s_pfn_Revert_To_Self ();
3808 BOOL WINAPI
get_process_memory_info (
3810 PPROCESS_MEMORY_COUNTERS mem_counters
,
3813 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3814 HMODULE hm_psapi
= NULL
;
3815 if (is_windows_9x () == TRUE
)
3819 if (g_b_init_get_process_memory_info
== 0)
3821 g_b_init_get_process_memory_info
= 1;
3822 hm_psapi
= LoadLibrary ("Psapi.dll");
3824 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3825 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3827 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3831 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3834 BOOL WINAPI
get_process_working_set_size (
3839 static GetProcessWorkingSetSize_Proc
3840 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3842 if (is_windows_9x () == TRUE
)
3846 if (g_b_init_get_process_working_set_size
== 0)
3848 g_b_init_get_process_working_set_size
= 1;
3849 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3850 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3851 "GetProcessWorkingSetSize");
3853 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3857 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3860 BOOL WINAPI
global_memory_status (
3863 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3865 if (is_windows_9x () == TRUE
)
3869 if (g_b_init_global_memory_status
== 0)
3871 g_b_init_global_memory_status
= 1;
3872 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3873 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3874 "GlobalMemoryStatus");
3876 if (s_pfn_Global_Memory_Status
== NULL
)
3880 return s_pfn_Global_Memory_Status (buf
);
3883 BOOL WINAPI
global_memory_status_ex (
3884 MEMORY_STATUS_EX
*buf
)
3886 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3888 if (is_windows_9x () == TRUE
)
3892 if (g_b_init_global_memory_status_ex
== 0)
3894 g_b_init_global_memory_status_ex
= 1;
3895 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3896 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3897 "GlobalMemoryStatusEx");
3899 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3903 return s_pfn_Global_Memory_Status_Ex (buf
);
3907 list_system_processes ()
3909 struct gcpro gcpro1
;
3910 Lisp_Object proclist
= Qnil
;
3913 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3915 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3917 PROCESSENTRY32 proc_entry
;
3923 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3924 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3925 res
= process32_next (h_snapshot
, &proc_entry
))
3927 proc_id
= proc_entry
.th32ProcessID
;
3928 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3931 CloseHandle (h_snapshot
);
3933 proclist
= Fnreverse (proclist
);
3940 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3942 TOKEN_PRIVILEGES priv
;
3943 DWORD priv_size
= sizeof (priv
);
3944 DWORD opriv_size
= sizeof (*old_priv
);
3945 HANDLE h_token
= NULL
;
3946 HANDLE h_thread
= GetCurrentThread ();
3950 res
= open_thread_token (h_thread
,
3951 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3953 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3955 if (impersonate_self (SecurityImpersonation
))
3956 res
= open_thread_token (h_thread
,
3957 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3962 priv
.PrivilegeCount
= 1;
3963 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3964 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3965 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3966 old_priv
, &opriv_size
)
3967 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3971 CloseHandle (h_token
);
3977 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3979 DWORD priv_size
= sizeof (*priv
);
3980 HANDLE h_token
= NULL
;
3983 if (open_thread_token (GetCurrentThread (),
3984 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3987 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3988 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3992 CloseHandle (h_token
);
3998 ltime (time_sec
, time_usec
)
3999 long time_sec
, time_usec
;
4001 return list3 (make_number ((time_sec
>> 16) & 0xffff),
4002 make_number (time_sec
& 0xffff),
4003 make_number (time_usec
));
4006 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
4009 process_times (h_proc
, ctime
, etime
, stime
, utime
, ttime
, pcpu
)
4011 Lisp_Object
*ctime
, *etime
, *stime
, *utime
, *ttime
;
4014 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4015 ULONGLONG tem1
, tem2
, tem3
, tem
;
4018 || !get_process_times_fn
4019 || !(*get_process_times_fn
)(h_proc
, &ft_creation
, &ft_exit
,
4020 &ft_kernel
, &ft_user
))
4023 GetSystemTimeAsFileTime (&ft_current
);
4025 FILETIME_TO_U64 (tem1
, ft_kernel
);
4027 *stime
= U64_TO_LISP_TIME (tem1
);
4029 FILETIME_TO_U64 (tem2
, ft_user
);
4031 *utime
= U64_TO_LISP_TIME (tem2
);
4034 *ttime
= U64_TO_LISP_TIME (tem3
);
4036 FILETIME_TO_U64 (tem
, ft_creation
);
4037 /* Process no 4 (System) returns zero creation time. */
4039 tem
= (tem
- utc_base
) / 10L;
4040 *ctime
= U64_TO_LISP_TIME (tem
);
4044 FILETIME_TO_U64 (tem3
, ft_current
);
4045 tem
= (tem3
- utc_base
) / 10L - tem
;
4047 *etime
= U64_TO_LISP_TIME (tem
);
4051 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4062 system_process_attributes (pid
)
4065 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4066 Lisp_Object attrs
= Qnil
;
4067 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4068 HANDLE h_snapshot
, h_proc
;
4071 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4072 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4073 DWORD glength
= sizeof (gname
);
4074 HANDLE token
= NULL
;
4075 SID_NAME_USE user_type
;
4076 unsigned char *buf
= NULL
;
4078 TOKEN_USER user_token
;
4079 TOKEN_PRIMARY_GROUP group_token
;
4083 PROCESS_MEMORY_COUNTERS mem
;
4084 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4085 DWORD minrss
, maxrss
;
4087 MEMORY_STATUS_EX memstex
;
4088 double totphys
= 0.0;
4089 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4091 BOOL result
= FALSE
;
4093 CHECK_NUMBER_OR_FLOAT (pid
);
4094 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4096 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4098 GCPRO3 (attrs
, decoded_cmd
, tem
);
4100 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4105 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4106 for (res
= process32_first (h_snapshot
, &pe
); res
;
4107 res
= process32_next (h_snapshot
, &pe
))
4109 if (proc_id
== pe
.th32ProcessID
)
4112 decoded_cmd
= build_string ("Idle");
4115 /* Decode the command name from locale-specific
4117 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4118 strlen (pe
.szExeFile
));
4120 code_convert_string_norecord (cmd_str
,
4121 Vlocale_coding_system
, 0);
4123 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4124 attrs
= Fcons (Fcons (Qppid
,
4125 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4127 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4129 attrs
= Fcons (Fcons (Qthcount
,
4130 make_fixnum_or_float (pe
.cntThreads
)),
4137 CloseHandle (h_snapshot
);
4146 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4148 /* If we were denied a handle to the process, try again after
4149 enabling the SeDebugPrivilege in our process. */
4152 TOKEN_PRIVILEGES priv_current
;
4154 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4156 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4158 restore_privilege (&priv_current
);
4164 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4167 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4168 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4170 buf
= xmalloc (blen
);
4171 result
= get_token_information (token
, TokenUser
,
4172 (LPVOID
)buf
, blen
, &needed
);
4175 memcpy (&user_token
, buf
, sizeof (user_token
));
4176 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4178 euid
= get_rid (user_token
.User
.Sid
);
4179 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4184 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4187 strcpy (uname
, "unknown");
4191 ulength
= strlen (uname
);
4197 /* Determine a reasonable euid and gid values. */
4198 if (xstrcasecmp ("administrator", uname
) == 0)
4200 euid
= 500; /* well-known Administrator uid */
4201 egid
= 513; /* well-known None gid */
4205 /* Get group id and name. */
4206 result
= get_token_information (token
, TokenPrimaryGroup
,
4207 (LPVOID
)buf
, blen
, &needed
);
4208 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4210 buf
= xrealloc (buf
, blen
= needed
);
4211 result
= get_token_information (token
, TokenPrimaryGroup
,
4212 (LPVOID
)buf
, blen
, &needed
);
4216 memcpy (&group_token
, buf
, sizeof (group_token
));
4217 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4219 egid
= get_rid (group_token
.PrimaryGroup
);
4220 dlength
= sizeof (domain
);
4222 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4223 gname
, &glength
, NULL
, &dlength
,
4226 w32_add_to_cache (group_token
.PrimaryGroup
,
4230 strcpy (gname
, "None");
4234 glength
= strlen (gname
);
4242 if (!is_windows_9x ())
4244 /* We couldn't open the process token, presumably because of
4245 insufficient access rights. Assume this process is run
4247 strcpy (uname
, "SYSTEM");
4248 strcpy (gname
, "None");
4249 euid
= 18; /* SYSTEM */
4250 egid
= 513; /* None */
4251 glength
= strlen (gname
);
4252 ulength
= strlen (uname
);
4254 /* If we are running under Windows 9X, where security calls are
4255 not supported, we assume all processes are run by the current
4257 else if (GetUserName (uname
, &ulength
))
4259 if (xstrcasecmp ("administrator", uname
) == 0)
4264 strcpy (gname
, "None");
4265 glength
= strlen (gname
);
4266 ulength
= strlen (uname
);
4272 strcpy (uname
, "administrator");
4273 ulength
= strlen (uname
);
4274 strcpy (gname
, "None");
4275 glength
= strlen (gname
);
4278 CloseHandle (token
);
4281 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4282 tem
= make_unibyte_string (uname
, ulength
);
4283 attrs
= Fcons (Fcons (Quser
,
4284 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4286 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4287 tem
= make_unibyte_string (gname
, glength
);
4288 attrs
= Fcons (Fcons (Qgroup
,
4289 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4292 if (global_memory_status_ex (&memstex
))
4293 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4294 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4296 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4297 double, so we need to do this for it... */
4299 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4300 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4301 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4303 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4305 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4306 else if (global_memory_status (&memst
))
4307 totphys
= memst
.dwTotalPhys
/ 1024.0;
4310 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4313 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4315 attrs
= Fcons (Fcons (Qmajflt
,
4316 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4318 attrs
= Fcons (Fcons (Qvsize
,
4319 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4321 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4323 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4326 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4328 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4330 attrs
= Fcons (Fcons (Qmajflt
,
4331 make_fixnum_or_float (mem
.PageFaultCount
)),
4333 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4335 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4338 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4340 DWORD rss
= maxrss
/ 1024;
4342 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4344 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4347 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4349 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4350 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4351 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4352 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4353 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4354 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4357 /* FIXME: Retrieve command line by walking the PEB of the process. */
4360 CloseHandle (h_proc
);
4368 /* Wrappers for winsock functions to map between our file descriptors
4369 and winsock's handles; also set h_errno for convenience.
4371 To allow Emacs to run on systems which don't have winsock support
4372 installed, we dynamically link to winsock on startup if present, and
4373 otherwise provide the minimum necessary functionality
4374 (eg. gethostname). */
4376 /* function pointers for relevant socket functions */
4377 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4378 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4379 int (PASCAL
*pfn_WSAGetLastError
) (void);
4380 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4381 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4382 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4383 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4384 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4385 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4386 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4387 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4388 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4389 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4390 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4391 int (PASCAL
*pfn_WSACleanup
) (void);
4393 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4394 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4395 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4396 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4397 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4398 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4399 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4400 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4401 const char * optval
, int optlen
);
4402 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4403 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4405 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4406 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4407 struct sockaddr
* from
, int * fromlen
);
4408 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4409 const struct sockaddr
* to
, int tolen
);
4411 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4412 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4413 #ifndef HANDLE_FLAG_INHERIT
4414 #define HANDLE_FLAG_INHERIT 1
4418 static int winsock_inuse
;
4423 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4425 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4426 after WSAStartup returns successfully, but it seems reasonable
4427 to allow unloading winsock anyway in that case. */
4428 if (pfn_WSACleanup () == 0 ||
4429 pfn_WSAGetLastError () == WSAENETDOWN
)
4431 if (FreeLibrary (winsock_lib
))
4440 init_winsock (int load_now
)
4442 WSADATA winsockData
;
4444 if (winsock_lib
!= NULL
)
4447 pfn_SetHandleInformation
= NULL
;
4448 pfn_SetHandleInformation
4449 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4450 "SetHandleInformation");
4452 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4454 if (winsock_lib
!= NULL
)
4456 /* dynamically link to socket functions */
4458 #define LOAD_PROC(fn) \
4459 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4462 LOAD_PROC( WSAStartup
);
4463 LOAD_PROC( WSASetLastError
);
4464 LOAD_PROC( WSAGetLastError
);
4465 LOAD_PROC( WSAEventSelect
);
4466 LOAD_PROC( WSACreateEvent
);
4467 LOAD_PROC( WSACloseEvent
);
4468 LOAD_PROC( socket
);
4470 LOAD_PROC( connect
);
4471 LOAD_PROC( ioctlsocket
);
4474 LOAD_PROC( closesocket
);
4475 LOAD_PROC( shutdown
);
4478 LOAD_PROC( inet_addr
);
4479 LOAD_PROC( gethostname
);
4480 LOAD_PROC( gethostbyname
);
4481 LOAD_PROC( getservbyname
);
4482 LOAD_PROC( getpeername
);
4483 LOAD_PROC( WSACleanup
);
4484 LOAD_PROC( setsockopt
);
4485 LOAD_PROC( listen
);
4486 LOAD_PROC( getsockname
);
4487 LOAD_PROC( accept
);
4488 LOAD_PROC( recvfrom
);
4489 LOAD_PROC( sendto
);
4492 /* specify version 1.1 of winsock */
4493 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4495 if (winsockData
.wVersion
!= 0x101)
4500 /* Report that winsock exists and is usable, but leave
4501 socket functions disabled. I am assuming that calling
4502 WSAStartup does not require any network interaction,
4503 and in particular does not cause or require a dial-up
4504 connection to be established. */
4507 FreeLibrary (winsock_lib
);
4515 FreeLibrary (winsock_lib
);
4525 /* function to set h_errno for compatibility; map winsock error codes to
4526 normal system codes where they overlap (non-overlapping definitions
4527 are already in <sys/socket.h> */
4531 if (winsock_lib
== NULL
)
4534 h_errno
= pfn_WSAGetLastError ();
4538 case WSAEACCES
: h_errno
= EACCES
; break;
4539 case WSAEBADF
: h_errno
= EBADF
; break;
4540 case WSAEFAULT
: h_errno
= EFAULT
; break;
4541 case WSAEINTR
: h_errno
= EINTR
; break;
4542 case WSAEINVAL
: h_errno
= EINVAL
; break;
4543 case WSAEMFILE
: h_errno
= EMFILE
; break;
4544 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4545 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4553 if (h_errno
== 0 && winsock_lib
!= NULL
)
4554 pfn_WSASetLastError (0);
4557 /* Extend strerror to handle the winsock-specific error codes. */
4561 } _wsa_errlist
[] = {
4562 WSAEINTR
, "Interrupted function call",
4563 WSAEBADF
, "Bad file descriptor",
4564 WSAEACCES
, "Permission denied",
4565 WSAEFAULT
, "Bad address",
4566 WSAEINVAL
, "Invalid argument",
4567 WSAEMFILE
, "Too many open files",
4569 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
4570 WSAEINPROGRESS
, "Operation now in progress",
4571 WSAEALREADY
, "Operation already in progress",
4572 WSAENOTSOCK
, "Socket operation on non-socket",
4573 WSAEDESTADDRREQ
, "Destination address required",
4574 WSAEMSGSIZE
, "Message too long",
4575 WSAEPROTOTYPE
, "Protocol wrong type for socket",
4576 WSAENOPROTOOPT
, "Bad protocol option",
4577 WSAEPROTONOSUPPORT
, "Protocol not supported",
4578 WSAESOCKTNOSUPPORT
, "Socket type not supported",
4579 WSAEOPNOTSUPP
, "Operation not supported",
4580 WSAEPFNOSUPPORT
, "Protocol family not supported",
4581 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
4582 WSAEADDRINUSE
, "Address already in use",
4583 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
4584 WSAENETDOWN
, "Network is down",
4585 WSAENETUNREACH
, "Network is unreachable",
4586 WSAENETRESET
, "Network dropped connection on reset",
4587 WSAECONNABORTED
, "Software caused connection abort",
4588 WSAECONNRESET
, "Connection reset by peer",
4589 WSAENOBUFS
, "No buffer space available",
4590 WSAEISCONN
, "Socket is already connected",
4591 WSAENOTCONN
, "Socket is not connected",
4592 WSAESHUTDOWN
, "Cannot send after socket shutdown",
4593 WSAETOOMANYREFS
, "Too many references", /* not sure */
4594 WSAETIMEDOUT
, "Connection timed out",
4595 WSAECONNREFUSED
, "Connection refused",
4596 WSAELOOP
, "Network loop", /* not sure */
4597 WSAENAMETOOLONG
, "Name is too long",
4598 WSAEHOSTDOWN
, "Host is down",
4599 WSAEHOSTUNREACH
, "No route to host",
4600 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
4601 WSAEPROCLIM
, "Too many processes",
4602 WSAEUSERS
, "Too many users", /* not sure */
4603 WSAEDQUOT
, "Double quote in host name", /* really not sure */
4604 WSAESTALE
, "Data is stale", /* not sure */
4605 WSAEREMOTE
, "Remote error", /* not sure */
4607 WSASYSNOTREADY
, "Network subsystem is unavailable",
4608 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
4609 WSANOTINITIALISED
, "Winsock not initialized successfully",
4610 WSAEDISCON
, "Graceful shutdown in progress",
4612 WSAENOMORE
, "No more operations allowed", /* not sure */
4613 WSAECANCELLED
, "Operation cancelled", /* not sure */
4614 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
4615 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
4616 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
4617 WSASYSCALLFAILURE
, "System call failure",
4618 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
4619 WSATYPE_NOT_FOUND
, "Class type not found",
4620 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
4621 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
4622 WSAEREFUSED
, "Operation refused", /* not sure */
4625 WSAHOST_NOT_FOUND
, "Host not found",
4626 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
4627 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
4628 WSANO_DATA
, "Valid name, no data record of requested type",
4634 sys_strerror(int error_no
)
4637 static char unknown_msg
[40];
4639 if (error_no
>= 0 && error_no
< sys_nerr
)
4640 return sys_errlist
[error_no
];
4642 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4643 if (_wsa_errlist
[i
].errnum
== error_no
)
4644 return _wsa_errlist
[i
].msg
;
4646 sprintf(unknown_msg
, "Unidentified error: %d", error_no
);
4650 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4651 but I believe the method of keeping the socket handle separate (and
4652 insuring it is not inheritable) is the correct one. */
4654 //#define SOCK_REPLACE_HANDLE
4656 #ifdef SOCK_REPLACE_HANDLE
4657 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
4659 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4662 int socket_to_fd (SOCKET s
);
4665 sys_socket(int af
, int type
, int protocol
)
4669 if (winsock_lib
== NULL
)
4672 return INVALID_SOCKET
;
4677 /* call the real socket function */
4678 s
= pfn_socket (af
, type
, protocol
);
4680 if (s
!= INVALID_SOCKET
)
4681 return socket_to_fd (s
);
4687 /* Convert a SOCKET to a file descriptor. */
4689 socket_to_fd (SOCKET s
)
4694 /* Although under NT 3.5 _open_osfhandle will accept a socket
4695 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4696 that does not work under NT 3.1. However, we can get the same
4697 effect by using a backdoor function to replace an existing
4698 descriptor handle with the one we want. */
4700 /* allocate a file descriptor (with appropriate flags) */
4701 fd
= _open ("NUL:", _O_RDWR
);
4704 #ifdef SOCK_REPLACE_HANDLE
4705 /* now replace handle to NUL with our socket handle */
4706 CloseHandle ((HANDLE
) _get_osfhandle (fd
));
4708 _set_osfhnd (fd
, s
);
4709 /* setmode (fd, _O_BINARY); */
4711 /* Make a non-inheritable copy of the socket handle. Note
4712 that it is possible that sockets aren't actually kernel
4713 handles, which appears to be the case on Windows 9x when
4714 the MS Proxy winsock client is installed. */
4716 /* Apparently there is a bug in NT 3.51 with some service
4717 packs, which prevents using DuplicateHandle to make a
4718 socket handle non-inheritable (causes WSACleanup to
4719 hang). The work-around is to use SetHandleInformation
4720 instead if it is available and implemented. */
4721 if (pfn_SetHandleInformation
)
4723 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4727 HANDLE parent
= GetCurrentProcess ();
4728 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4730 if (DuplicateHandle (parent
,
4736 DUPLICATE_SAME_ACCESS
))
4738 /* It is possible that DuplicateHandle succeeds even
4739 though the socket wasn't really a kernel handle,
4740 because a real handle has the same value. So
4741 test whether the new handle really is a socket. */
4742 long nonblocking
= 0;
4743 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4745 pfn_closesocket (s
);
4750 CloseHandle (new_s
);
4755 fd_info
[fd
].hnd
= (HANDLE
) s
;
4758 /* set our own internal flags */
4759 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4765 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4767 /* attach child_process to fd_info */
4768 if (fd_info
[ fd
].cp
!= NULL
)
4770 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4774 fd_info
[ fd
].cp
= cp
;
4777 winsock_inuse
++; /* count open sockets */
4784 pfn_closesocket (s
);
4791 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4793 if (winsock_lib
== NULL
)
4796 return SOCKET_ERROR
;
4800 if (fd_info
[s
].flags
& FILE_SOCKET
)
4802 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4803 if (rc
== SOCKET_ERROR
)
4808 return SOCKET_ERROR
;
4813 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4815 if (winsock_lib
== NULL
)
4818 return SOCKET_ERROR
;
4822 if (fd_info
[s
].flags
& FILE_SOCKET
)
4824 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4825 if (rc
== SOCKET_ERROR
)
4830 return SOCKET_ERROR
;
4834 sys_htons (u_short hostshort
)
4836 return (winsock_lib
!= NULL
) ?
4837 pfn_htons (hostshort
) : hostshort
;
4841 sys_ntohs (u_short netshort
)
4843 return (winsock_lib
!= NULL
) ?
4844 pfn_ntohs (netshort
) : netshort
;
4848 sys_inet_addr (const char * cp
)
4850 return (winsock_lib
!= NULL
) ?
4851 pfn_inet_addr (cp
) : INADDR_NONE
;
4855 sys_gethostname (char * name
, int namelen
)
4857 if (winsock_lib
!= NULL
)
4858 return pfn_gethostname (name
, namelen
);
4860 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4861 return !GetComputerName (name
, (DWORD
*)&namelen
);
4864 return SOCKET_ERROR
;
4868 sys_gethostbyname(const char * name
)
4870 struct hostent
* host
;
4872 if (winsock_lib
== NULL
)
4879 host
= pfn_gethostbyname (name
);
4886 sys_getservbyname(const char * name
, const char * proto
)
4888 struct servent
* serv
;
4890 if (winsock_lib
== NULL
)
4897 serv
= pfn_getservbyname (name
, proto
);
4904 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4906 if (winsock_lib
== NULL
)
4909 return SOCKET_ERROR
;
4913 if (fd_info
[s
].flags
& FILE_SOCKET
)
4915 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4916 if (rc
== SOCKET_ERROR
)
4921 return SOCKET_ERROR
;
4926 sys_shutdown (int s
, int how
)
4928 if (winsock_lib
== NULL
)
4931 return SOCKET_ERROR
;
4935 if (fd_info
[s
].flags
& FILE_SOCKET
)
4937 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4938 if (rc
== SOCKET_ERROR
)
4943 return SOCKET_ERROR
;
4947 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4949 if (winsock_lib
== NULL
)
4952 return SOCKET_ERROR
;
4956 if (fd_info
[s
].flags
& FILE_SOCKET
)
4958 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4959 (const char *)optval
, optlen
);
4960 if (rc
== SOCKET_ERROR
)
4965 return SOCKET_ERROR
;
4969 sys_listen (int s
, int backlog
)
4971 if (winsock_lib
== NULL
)
4974 return SOCKET_ERROR
;
4978 if (fd_info
[s
].flags
& FILE_SOCKET
)
4980 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4981 if (rc
== SOCKET_ERROR
)
4984 fd_info
[s
].flags
|= FILE_LISTEN
;
4988 return SOCKET_ERROR
;
4992 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4994 if (winsock_lib
== NULL
)
4997 return SOCKET_ERROR
;
5001 if (fd_info
[s
].flags
& FILE_SOCKET
)
5003 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
5004 if (rc
== SOCKET_ERROR
)
5009 return SOCKET_ERROR
;
5013 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
5015 if (winsock_lib
== NULL
)
5022 if (fd_info
[s
].flags
& FILE_LISTEN
)
5024 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5026 if (t
== INVALID_SOCKET
)
5029 fd
= socket_to_fd (t
);
5031 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5032 ResetEvent (fd_info
[s
].cp
->char_avail
);
5040 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5041 struct sockaddr
* from
, int * fromlen
)
5043 if (winsock_lib
== NULL
)
5046 return SOCKET_ERROR
;
5050 if (fd_info
[s
].flags
& FILE_SOCKET
)
5052 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5053 if (rc
== SOCKET_ERROR
)
5058 return SOCKET_ERROR
;
5062 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5063 const struct sockaddr
* to
, int tolen
)
5065 if (winsock_lib
== NULL
)
5068 return SOCKET_ERROR
;
5072 if (fd_info
[s
].flags
& FILE_SOCKET
)
5074 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5075 if (rc
== SOCKET_ERROR
)
5080 return SOCKET_ERROR
;
5083 /* Windows does not have an fcntl function. Provide an implementation
5084 solely for making sockets non-blocking. */
5086 fcntl (int s
, int cmd
, int options
)
5088 if (winsock_lib
== NULL
)
5095 if (fd_info
[s
].flags
& FILE_SOCKET
)
5097 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5099 unsigned long nblock
= 1;
5100 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5101 if (rc
== SOCKET_ERROR
)
5103 /* Keep track of the fact that we set this to non-blocking. */
5104 fd_info
[s
].flags
|= FILE_NDELAY
;
5110 return SOCKET_ERROR
;
5114 return SOCKET_ERROR
;
5117 #endif /* HAVE_SOCKETS */
5120 /* Shadow main io functions: we need to handle pipes and sockets more
5121 intelligently, and implement non-blocking mode as well. */
5134 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5136 child_process
* cp
= fd_info
[fd
].cp
;
5138 fd_info
[fd
].cp
= NULL
;
5140 if (CHILD_ACTIVE (cp
))
5142 /* if last descriptor to active child_process then cleanup */
5144 for (i
= 0; i
< MAXDESC
; i
++)
5148 if (fd_info
[i
].cp
== cp
)
5154 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5156 #ifndef SOCK_REPLACE_HANDLE
5157 if (winsock_lib
== NULL
) abort ();
5159 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5160 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5162 winsock_inuse
--; /* count open sockets */
5170 /* Note that sockets do not need special treatment here (at least on
5171 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5172 closesocket is equivalent to CloseHandle, which is to be expected
5173 because socket handles are fully fledged kernel handles. */
5176 if (rc
== 0 && fd
< MAXDESC
)
5177 fd_info
[fd
].flags
= 0;
5188 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5190 /* duplicate our internal info as well */
5191 fd_info
[new_fd
] = fd_info
[fd
];
5198 sys_dup2 (int src
, int dst
)
5202 if (dst
< 0 || dst
>= MAXDESC
)
5208 /* make sure we close the destination first if it's a pipe or socket */
5209 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5212 rc
= _dup2 (src
, dst
);
5215 /* duplicate our internal info as well */
5216 fd_info
[dst
] = fd_info
[src
];
5221 /* Unix pipe() has only one arg */
5223 sys_pipe (int * phandles
)
5228 /* make pipe handles non-inheritable; when we spawn a child, we
5229 replace the relevant handle with an inheritable one. Also put
5230 pipes into binary mode; we will do text mode translation ourselves
5232 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5236 /* Protect against overflow, since Windows can open more handles than
5237 our fd_info array has room for. */
5238 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5240 _close (phandles
[0]);
5241 _close (phandles
[1]);
5246 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5247 fd_info
[phandles
[0]].flags
= flags
;
5249 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5250 fd_info
[phandles
[1]].flags
= flags
;
5258 extern int w32_pipe_read_delay
;
5260 /* Function to do blocking read of one byte, needed to implement
5261 select. It is only allowed on sockets and pipes. */
5263 _sys_read_ahead (int fd
)
5268 if (fd
< 0 || fd
>= MAXDESC
)
5269 return STATUS_READ_ERROR
;
5271 cp
= fd_info
[fd
].cp
;
5273 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5274 return STATUS_READ_ERROR
;
5276 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5277 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5279 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5283 cp
->status
= STATUS_READ_IN_PROGRESS
;
5285 if (fd_info
[fd
].flags
& FILE_PIPE
)
5287 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5289 /* Give subprocess time to buffer some more output for us before
5290 reporting that input is available; we need this because Windows 95
5291 connects DOS programs to pipes by making the pipe appear to be
5292 the normal console stdout - as a result most DOS programs will
5293 write to stdout without buffering, ie. one character at a
5294 time. Even some W32 programs do this - "dir" in a command
5295 shell on NT is very slow if we don't do this. */
5298 int wait
= w32_pipe_read_delay
;
5304 /* Yield remainder of our time slice, effectively giving a
5305 temporary priority boost to the child process. */
5309 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5311 HANDLE hnd
= fd_info
[fd
].hnd
;
5312 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5315 /* Configure timeouts for blocking read. */
5316 if (!GetCommTimeouts (hnd
, &ct
))
5317 return STATUS_READ_ERROR
;
5318 ct
.ReadIntervalTimeout
= 0;
5319 ct
.ReadTotalTimeoutMultiplier
= 0;
5320 ct
.ReadTotalTimeoutConstant
= 0;
5321 if (!SetCommTimeouts (hnd
, &ct
))
5322 return STATUS_READ_ERROR
;
5324 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5326 if (GetLastError () != ERROR_IO_PENDING
)
5327 return STATUS_READ_ERROR
;
5328 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5329 return STATUS_READ_ERROR
;
5333 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5335 unsigned long nblock
= 0;
5336 /* We always want this to block, so temporarily disable NDELAY. */
5337 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5338 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5340 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5342 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5345 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5350 if (rc
== sizeof (char))
5351 cp
->status
= STATUS_READ_SUCCEEDED
;
5353 cp
->status
= STATUS_READ_FAILED
;
5359 _sys_wait_accept (int fd
)
5365 if (fd
< 0 || fd
>= MAXDESC
)
5366 return STATUS_READ_ERROR
;
5368 cp
= fd_info
[fd
].cp
;
5370 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5371 return STATUS_READ_ERROR
;
5373 cp
->status
= STATUS_READ_FAILED
;
5375 hEv
= pfn_WSACreateEvent ();
5376 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5377 if (rc
!= SOCKET_ERROR
)
5379 rc
= WaitForSingleObject (hEv
, INFINITE
);
5380 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5381 if (rc
== WAIT_OBJECT_0
)
5382 cp
->status
= STATUS_READ_SUCCEEDED
;
5384 pfn_WSACloseEvent (hEv
);
5390 sys_read (int fd
, char * buffer
, unsigned int count
)
5395 char * orig_buffer
= buffer
;
5403 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5405 child_process
*cp
= fd_info
[fd
].cp
;
5407 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5415 /* re-read CR carried over from last read */
5416 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5418 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5422 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5425 /* presence of a child_process structure means we are operating in
5426 non-blocking mode - otherwise we just call _read directly.
5427 Note that the child_process structure might be missing because
5428 reap_subprocess has been called; in this case the pipe is
5429 already broken, so calling _read on it is okay. */
5432 int current_status
= cp
->status
;
5434 switch (current_status
)
5436 case STATUS_READ_FAILED
:
5437 case STATUS_READ_ERROR
:
5438 /* report normal EOF if nothing in buffer */
5440 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5443 case STATUS_READ_READY
:
5444 case STATUS_READ_IN_PROGRESS
:
5445 DebPrint (("sys_read called when read is in progress\n"));
5446 errno
= EWOULDBLOCK
;
5449 case STATUS_READ_SUCCEEDED
:
5450 /* consume read-ahead char */
5451 *buffer
++ = cp
->chr
;
5454 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5455 ResetEvent (cp
->char_avail
);
5457 case STATUS_READ_ACKNOWLEDGED
:
5461 DebPrint (("sys_read: bad status %d\n", current_status
));
5466 if (fd_info
[fd
].flags
& FILE_PIPE
)
5468 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5469 to_read
= min (waiting
, (DWORD
) count
);
5472 nchars
+= _read (fd
, buffer
, to_read
);
5474 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5476 HANDLE hnd
= fd_info
[fd
].hnd
;
5477 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5484 /* Configure timeouts for non-blocking read. */
5485 if (!GetCommTimeouts (hnd
, &ct
))
5490 ct
.ReadIntervalTimeout
= MAXDWORD
;
5491 ct
.ReadTotalTimeoutMultiplier
= 0;
5492 ct
.ReadTotalTimeoutConstant
= 0;
5493 if (!SetCommTimeouts (hnd
, &ct
))
5499 if (!ResetEvent (ovl
->hEvent
))
5504 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5506 if (GetLastError () != ERROR_IO_PENDING
)
5511 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5521 else /* FILE_SOCKET */
5523 if (winsock_lib
== NULL
) abort ();
5525 /* do the equivalent of a non-blocking read */
5526 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5527 if (waiting
== 0 && nchars
== 0)
5529 h_errno
= errno
= EWOULDBLOCK
;
5535 /* always use binary mode for sockets */
5536 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5537 if (res
== SOCKET_ERROR
)
5539 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
5540 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5551 int nread
= _read (fd
, buffer
, count
);
5554 else if (nchars
== 0)
5559 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5560 /* Perform text mode translation if required. */
5561 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5563 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5564 /* If buffer contains only CR, return that. To be absolutely
5565 sure we should attempt to read the next char, but in
5566 practice a CR to be followed by LF would not appear by
5567 itself in the buffer. */
5568 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5570 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5576 nchars
= _read (fd
, buffer
, count
);
5581 /* From w32xfns.c */
5582 extern HANDLE interrupt_handle
;
5584 /* For now, don't bother with a non-blocking mode */
5586 sys_write (int fd
, const void * buffer
, unsigned int count
)
5596 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5598 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5604 /* Perform text mode translation if required. */
5605 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5607 char * tmpbuf
= alloca (count
* 2);
5608 unsigned char * src
= (void *)buffer
;
5609 unsigned char * dst
= tmpbuf
;
5614 unsigned char *next
;
5615 /* copy next line or remaining bytes */
5616 next
= _memccpy (dst
, src
, '\n', nbytes
);
5619 /* copied one line ending with '\n' */
5620 int copied
= next
- dst
;
5623 /* insert '\r' before '\n' */
5630 /* copied remaining partial line -> now finished */
5637 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5639 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5640 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5641 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5644 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5646 if (GetLastError () != ERROR_IO_PENDING
)
5651 if (detect_input_pending ())
5652 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5655 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5656 if (active
== WAIT_OBJECT_0
)
5657 { /* User pressed C-g, cancel write, then leave. Don't bother
5658 cleaning up as we may only get stuck in buggy drivers. */
5659 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5664 if (active
== WAIT_OBJECT_0
+ 1
5665 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5674 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5676 unsigned long nblock
= 0;
5677 if (winsock_lib
== NULL
) abort ();
5679 /* TODO: implement select() properly so non-blocking I/O works. */
5680 /* For now, make sure the write blocks. */
5681 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5682 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5684 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5686 /* Set the socket back to non-blocking if it was before,
5687 for other operations that support it. */
5688 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5691 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5694 if (nchars
== SOCKET_ERROR
)
5696 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
5697 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5703 nchars
= _write (fd
, buffer
, count
);
5709 check_windows_init_file ()
5711 extern int noninteractive
, inhibit_window_system
;
5713 /* A common indication that Emacs is not installed properly is when
5714 it cannot find the Windows installation file. If this file does
5715 not exist in the expected place, tell the user. */
5717 if (!noninteractive
&& !inhibit_window_system
)
5719 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
5720 Lisp_Object objs
[2];
5721 Lisp_Object full_load_path
;
5722 Lisp_Object init_file
;
5725 objs
[0] = Vload_path
;
5726 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5727 full_load_path
= Fappend (2, objs
);
5728 init_file
= build_string ("term/w32-win");
5729 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5732 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5733 char *init_file_name
= SDATA (init_file
);
5734 char *load_path
= SDATA (load_path_print
);
5735 char *buffer
= alloca (1024
5736 + strlen (init_file_name
)
5737 + strlen (load_path
));
5740 "The Emacs Windows initialization file \"%s.el\" "
5741 "could not be found in your Emacs installation. "
5742 "Emacs checked the following directories for this file:\n"
5744 "When Emacs cannot find this file, it usually means that it "
5745 "was not installed properly, or its distribution file was "
5746 "not unpacked properly.\nSee the README.W32 file in the "
5747 "top-level Emacs directory for more information.",
5748 init_file_name
, load_path
);
5751 "Emacs Abort Dialog",
5752 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5753 /* Use the low-level Emacs abort. */
5768 /* shutdown the socket interface if necessary */
5779 /* Initialise the socket interface now if available and requested by
5780 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5781 delayed until open-network-stream is called (w32-has-winsock can
5782 also be used to dynamically load or reload winsock).
5784 Conveniently, init_environment is called before us, so
5785 PRELOAD_WINSOCK can be set in the registry. */
5787 /* Always initialize this correctly. */
5790 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5791 init_winsock (TRUE
);
5794 /* Initial preparation for subprocess support: replace our standard
5795 handles with non-inheritable versions. */
5798 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5799 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5800 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5802 parent
= GetCurrentProcess ();
5804 /* ignore errors when duplicating and closing; typically the
5805 handles will be invalid when running as a gui program. */
5806 DuplicateHandle (parent
,
5807 GetStdHandle (STD_INPUT_HANDLE
),
5812 DUPLICATE_SAME_ACCESS
);
5814 DuplicateHandle (parent
,
5815 GetStdHandle (STD_OUTPUT_HANDLE
),
5820 DUPLICATE_SAME_ACCESS
);
5822 DuplicateHandle (parent
,
5823 GetStdHandle (STD_ERROR_HANDLE
),
5828 DUPLICATE_SAME_ACCESS
);
5834 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5835 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5837 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5840 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5841 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5843 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5846 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5847 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5849 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5853 /* unfortunately, atexit depends on implementation of malloc */
5854 /* atexit (term_ntproc); */
5855 signal (SIGABRT
, term_ntproc
);
5857 /* determine which drives are fixed, for GetCachedVolumeInformation */
5859 /* GetDriveType must have trailing backslash. */
5860 char drive
[] = "A:\\";
5862 /* Loop over all possible drive letters */
5863 while (*drive
<= 'Z')
5865 /* Record if this drive letter refers to a fixed drive. */
5866 fixed_drives
[DRIVE_INDEX (*drive
)] =
5867 (GetDriveType (drive
) == DRIVE_FIXED
);
5872 /* Reset the volume info cache. */
5873 volume_cache
= NULL
;
5876 /* Check to see if Emacs has been installed correctly. */
5877 check_windows_init_file ();
5881 shutdown_handler ensures that buffers' autosave files are
5882 up to date when the user logs off, or the system shuts down.
5884 BOOL WINAPI
shutdown_handler(DWORD type
)
5886 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5887 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5888 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5889 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5891 /* Shut down cleanly, making sure autosave files are up to date. */
5892 shut_down_emacs (0, 0, Qnil
);
5895 /* Allow other handlers to handle this signal. */
5900 globals_of_w32 is used to initialize those global variables that
5901 must always be initialized on startup even when the global variable
5902 initialized is non zero (see the function main in emacs.c).
5907 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5909 get_process_times_fn
= (GetProcessTimes_Proc
)
5910 GetProcAddress (kernel32
, "GetProcessTimes");
5912 g_b_init_is_windows_9x
= 0;
5913 g_b_init_open_process_token
= 0;
5914 g_b_init_get_token_information
= 0;
5915 g_b_init_lookup_account_sid
= 0;
5916 g_b_init_get_sid_identifier_authority
= 0;
5917 g_b_init_get_sid_sub_authority
= 0;
5918 g_b_init_get_sid_sub_authority_count
= 0;
5919 g_b_init_get_file_security
= 0;
5920 g_b_init_get_security_descriptor_owner
= 0;
5921 g_b_init_get_security_descriptor_group
= 0;
5922 g_b_init_is_valid_sid
= 0;
5923 g_b_init_create_toolhelp32_snapshot
= 0;
5924 g_b_init_process32_first
= 0;
5925 g_b_init_process32_next
= 0;
5926 g_b_init_open_thread_token
= 0;
5927 g_b_init_impersonate_self
= 0;
5928 g_b_init_revert_to_self
= 0;
5929 g_b_init_get_process_memory_info
= 0;
5930 g_b_init_get_process_working_set_size
= 0;
5931 g_b_init_global_memory_status
= 0;
5932 g_b_init_global_memory_status_ex
= 0;
5933 g_b_init_equal_sid
= 0;
5934 g_b_init_copy_sid
= 0;
5935 g_b_init_get_length_sid
= 0;
5936 g_b_init_get_native_system_info
= 0;
5937 g_b_init_get_system_times
= 0;
5938 num_of_processors
= 0;
5939 /* The following sets a handler for shutdown notifications for
5940 console apps. This actually applies to Emacs in both console and
5941 GUI modes, since we had to fool windows into thinking emacs is a
5942 console application to get console mode to work. */
5943 SetConsoleCtrlHandler(shutdown_handler
, TRUE
);
5945 /* "None" is the default group name on standalone workstations. */
5946 strcpy (dflt_group_name
, "None");
5949 /* For make-serial-process */
5950 int serial_open (char *port
)
5956 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5957 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5958 if (hnd
== INVALID_HANDLE_VALUE
)
5959 error ("Could not open %s", port
);
5960 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5962 error ("Could not open %s", port
);
5966 error ("Could not create child process");
5968 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5969 fd_info
[ fd
].hnd
= hnd
;
5970 fd_info
[ fd
].flags
|=
5971 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5972 if (fd_info
[ fd
].cp
!= NULL
)
5974 error ("fd_info[fd = %d] is already in use", fd
);
5976 fd_info
[ fd
].cp
= cp
;
5977 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5978 if (cp
->ovl_read
.hEvent
== NULL
)
5979 error ("Could not create read event");
5980 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5981 if (cp
->ovl_write
.hEvent
== NULL
)
5982 error ("Could not create write event");
5987 /* For serial-process-configure */
5989 serial_configure (struct Lisp_Process
*p
,
5990 Lisp_Object contact
)
5992 Lisp_Object childp2
= Qnil
;
5993 Lisp_Object tem
= Qnil
;
5997 char summary
[4] = "???"; /* This usually becomes "8N1". */
5999 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6000 error ("Not a serial process");
6001 hnd
= fd_info
[ p
->outfd
].hnd
;
6003 childp2
= Fcopy_sequence (p
->childp
);
6005 /* Initialize timeouts for blocking read and blocking write. */
6006 if (!GetCommTimeouts (hnd
, &ct
))
6007 error ("GetCommTimeouts() failed");
6008 ct
.ReadIntervalTimeout
= 0;
6009 ct
.ReadTotalTimeoutMultiplier
= 0;
6010 ct
.ReadTotalTimeoutConstant
= 0;
6011 ct
.WriteTotalTimeoutMultiplier
= 0;
6012 ct
.WriteTotalTimeoutConstant
= 0;
6013 if (!SetCommTimeouts (hnd
, &ct
))
6014 error ("SetCommTimeouts() failed");
6015 /* Read port attributes and prepare default configuration. */
6016 memset (&dcb
, 0, sizeof (dcb
));
6017 dcb
.DCBlength
= sizeof (DCB
);
6018 if (!GetCommState (hnd
, &dcb
))
6019 error ("GetCommState() failed");
6022 dcb
.fAbortOnError
= FALSE
;
6023 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6028 /* Configure speed. */
6029 if (!NILP (Fplist_member (contact
, QCspeed
)))
6030 tem
= Fplist_get (contact
, QCspeed
);
6032 tem
= Fplist_get (p
->childp
, QCspeed
);
6034 dcb
.BaudRate
= XINT (tem
);
6035 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6037 /* Configure bytesize. */
6038 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6039 tem
= Fplist_get (contact
, QCbytesize
);
6041 tem
= Fplist_get (p
->childp
, QCbytesize
);
6043 tem
= make_number (8);
6045 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6046 error (":bytesize must be nil (8), 7, or 8");
6047 dcb
.ByteSize
= XINT (tem
);
6048 summary
[0] = XINT (tem
) + '0';
6049 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6051 /* Configure parity. */
6052 if (!NILP (Fplist_member (contact
, QCparity
)))
6053 tem
= Fplist_get (contact
, QCparity
);
6055 tem
= Fplist_get (p
->childp
, QCparity
);
6056 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6057 error (":parity must be nil (no parity), `even', or `odd'");
6058 dcb
.fParity
= FALSE
;
6059 dcb
.Parity
= NOPARITY
;
6060 dcb
.fErrorChar
= FALSE
;
6065 else if (EQ (tem
, Qeven
))
6069 dcb
.Parity
= EVENPARITY
;
6070 dcb
.fErrorChar
= TRUE
;
6072 else if (EQ (tem
, Qodd
))
6076 dcb
.Parity
= ODDPARITY
;
6077 dcb
.fErrorChar
= TRUE
;
6079 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6081 /* Configure stopbits. */
6082 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6083 tem
= Fplist_get (contact
, QCstopbits
);
6085 tem
= Fplist_get (p
->childp
, QCstopbits
);
6087 tem
= make_number (1);
6089 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6090 error (":stopbits must be nil (1 stopbit), 1, or 2");
6091 summary
[2] = XINT (tem
) + '0';
6092 if (XINT (tem
) == 1)
6093 dcb
.StopBits
= ONESTOPBIT
;
6094 else if (XINT (tem
) == 2)
6095 dcb
.StopBits
= TWOSTOPBITS
;
6096 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6098 /* Configure flowcontrol. */
6099 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6100 tem
= Fplist_get (contact
, QCflowcontrol
);
6102 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6103 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6104 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6105 dcb
.fOutxCtsFlow
= FALSE
;
6106 dcb
.fOutxDsrFlow
= FALSE
;
6107 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6108 dcb
.fDsrSensitivity
= FALSE
;
6109 dcb
.fTXContinueOnXoff
= FALSE
;
6112 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6113 dcb
.XonChar
= 17; /* Control-Q */
6114 dcb
.XoffChar
= 19; /* Control-S */
6117 /* Already configured. */
6119 else if (EQ (tem
, Qhw
))
6121 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6122 dcb
.fOutxCtsFlow
= TRUE
;
6124 else if (EQ (tem
, Qsw
))
6129 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6131 /* Activate configuration. */
6132 if (!SetCommState (hnd
, &dcb
))
6133 error ("SetCommState() failed");
6135 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6136 p
->childp
= childp2
;
6141 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6142 (do not change this comment) */