1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994-1995, 2000-2011 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
22 #include <stddef.h> /* for offsetof */
25 #include <float.h> /* for DBL_EPSILON */
33 #include <sys/utime.h>
34 #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
;
98 #if !defined(__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
99 /* This either is not in psapi.h or guarded by higher value of
100 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
101 defines it in psapi.h */
102 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
104 DWORD PageFaultCount
;
105 DWORD PeakWorkingSetSize
;
106 DWORD WorkingSetSize
;
107 DWORD QuotaPeakPagedPoolUsage
;
108 DWORD QuotaPagedPoolUsage
;
109 DWORD QuotaPeakNonPagedPoolUsage
;
110 DWORD QuotaNonPagedPoolUsage
;
112 DWORD PeakPagefileUsage
;
114 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
117 /* TCP connection support. */
118 #include <sys/socket.h>
141 #include "dispextern.h" /* for xstrcasecmp */
142 #include "coding.h" /* for Vlocale_coding_system */
144 #include "careadlinkat.h"
145 #include "allocator.h"
147 /* For serial_configure and serial_open. */
150 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
151 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
153 void globals_of_w32 (void);
154 static DWORD
get_rid (PSID
);
157 /* Initialization states.
159 WARNING: If you add any more such variables for additional APIs,
160 you MUST add initialization for them to globals_of_w32
161 below. This is because these variables might get set
162 to non-NULL values during dumping, but the dumped Emacs
163 cannot reuse those values, because it could be run on a
164 different version of the OS, where API addresses are
166 static BOOL g_b_init_is_windows_9x
;
167 static BOOL g_b_init_open_process_token
;
168 static BOOL g_b_init_get_token_information
;
169 static BOOL g_b_init_lookup_account_sid
;
170 static BOOL g_b_init_get_sid_sub_authority
;
171 static BOOL g_b_init_get_sid_sub_authority_count
;
172 static BOOL g_b_init_get_file_security
;
173 static BOOL g_b_init_get_security_descriptor_owner
;
174 static BOOL g_b_init_get_security_descriptor_group
;
175 static BOOL g_b_init_is_valid_sid
;
176 static BOOL g_b_init_create_toolhelp32_snapshot
;
177 static BOOL g_b_init_process32_first
;
178 static BOOL g_b_init_process32_next
;
179 static BOOL g_b_init_open_thread_token
;
180 static BOOL g_b_init_impersonate_self
;
181 static BOOL g_b_init_revert_to_self
;
182 static BOOL g_b_init_get_process_memory_info
;
183 static BOOL g_b_init_get_process_working_set_size
;
184 static BOOL g_b_init_global_memory_status
;
185 static BOOL g_b_init_global_memory_status_ex
;
186 static BOOL g_b_init_get_length_sid
;
187 static BOOL g_b_init_equal_sid
;
188 static BOOL g_b_init_copy_sid
;
189 static BOOL g_b_init_get_native_system_info
;
190 static BOOL g_b_init_get_system_times
;
193 BEGIN: Wrapper functions around OpenProcessToken
194 and other functions in advapi32.dll that are only
195 supported in Windows NT / 2k / XP
197 /* ** Function pointer typedefs ** */
198 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
199 HANDLE ProcessHandle
,
201 PHANDLE TokenHandle
);
202 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
204 TOKEN_INFORMATION_CLASS TokenInformationClass
,
205 LPVOID TokenInformation
,
206 DWORD TokenInformationLength
,
207 PDWORD ReturnLength
);
208 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
209 HANDLE process_handle
,
210 LPFILETIME creation_time
,
211 LPFILETIME exit_time
,
212 LPFILETIME kernel_time
,
213 LPFILETIME user_time
);
215 GetProcessTimes_Proc get_process_times_fn
= NULL
;
218 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
219 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
221 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
222 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
224 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
225 LPCTSTR lpSystemName
,
230 LPDWORD cbDomainName
,
231 PSID_NAME_USE peUse
);
232 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
235 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
237 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
239 SECURITY_INFORMATION RequestedInformation
,
240 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
242 LPDWORD lpnLengthNeeded
);
243 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
244 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
246 LPBOOL lpbOwnerDefaulted
);
247 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
248 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
250 LPBOOL lpbGroupDefaulted
);
251 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
253 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
255 DWORD th32ProcessID
);
256 typedef BOOL (WINAPI
* Process32First_Proc
) (
258 LPPROCESSENTRY32 lppe
);
259 typedef BOOL (WINAPI
* Process32Next_Proc
) (
261 LPPROCESSENTRY32 lppe
);
262 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
266 PHANDLE TokenHandle
);
267 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
268 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
269 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
270 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
272 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
274 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
276 DWORD
* lpMinimumWorkingSetSize
,
277 DWORD
* lpMaximumWorkingSetSize
);
278 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
279 LPMEMORYSTATUS lpBuffer
);
280 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
281 LPMEMORY_STATUS_EX lpBuffer
);
282 typedef BOOL (WINAPI
* CopySid_Proc
) (
283 DWORD nDestinationSidLength
,
284 PSID pDestinationSid
,
286 typedef BOOL (WINAPI
* EqualSid_Proc
) (
289 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
291 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
292 LPSYSTEM_INFO lpSystemInfo
);
293 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
294 LPFILETIME lpIdleTime
,
295 LPFILETIME lpKernelTime
,
296 LPFILETIME lpUserTime
);
298 /* ** A utility function ** */
302 static BOOL s_b_ret
= 0;
303 OSVERSIONINFO os_ver
;
304 if (g_b_init_is_windows_9x
== 0)
306 g_b_init_is_windows_9x
= 1;
307 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
308 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
309 if (GetVersionEx (&os_ver
))
311 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
317 /* Get total user and system times for get-internal-run-time.
318 Returns a list of three integers if the times are provided by the OS
319 (NT derivatives), otherwise it returns the result of current-time. */
321 w32_get_internal_run_time (void)
323 if (get_process_times_fn
)
325 FILETIME create
, exit
, kernel
, user
;
326 HANDLE proc
= GetCurrentProcess ();
327 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
329 LARGE_INTEGER user_int
, kernel_int
, total
;
331 user_int
.LowPart
= user
.dwLowDateTime
;
332 user_int
.HighPart
= user
.dwHighDateTime
;
333 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
334 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
335 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
336 /* FILETIME is 100 nanosecond increments, Emacs only wants
337 microsecond resolution. */
338 total
.QuadPart
/= 10;
339 microseconds
= total
.QuadPart
% 1000000;
340 total
.QuadPart
/= 1000000;
342 /* Sanity check to make sure we can represent the result. */
343 if (total
.HighPart
== 0)
345 int secs
= total
.LowPart
;
347 return list3 (make_number ((secs
>> 16) & 0xffff),
348 make_number (secs
& 0xffff),
349 make_number (microseconds
));
354 return Fcurrent_time ();
357 /* ** The wrapper functions ** */
360 open_process_token (HANDLE ProcessHandle
,
364 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
365 HMODULE hm_advapi32
= NULL
;
366 if (is_windows_9x () == TRUE
)
370 if (g_b_init_open_process_token
== 0)
372 g_b_init_open_process_token
= 1;
373 hm_advapi32
= LoadLibrary ("Advapi32.dll");
374 s_pfn_Open_Process_Token
=
375 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
377 if (s_pfn_Open_Process_Token
== NULL
)
382 s_pfn_Open_Process_Token (
390 get_token_information (HANDLE TokenHandle
,
391 TOKEN_INFORMATION_CLASS TokenInformationClass
,
392 LPVOID TokenInformation
,
393 DWORD TokenInformationLength
,
396 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
397 HMODULE hm_advapi32
= NULL
;
398 if (is_windows_9x () == TRUE
)
402 if (g_b_init_get_token_information
== 0)
404 g_b_init_get_token_information
= 1;
405 hm_advapi32
= LoadLibrary ("Advapi32.dll");
406 s_pfn_Get_Token_Information
=
407 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
409 if (s_pfn_Get_Token_Information
== NULL
)
414 s_pfn_Get_Token_Information (
416 TokenInformationClass
,
418 TokenInformationLength
,
424 lookup_account_sid (LPCTSTR lpSystemName
,
429 LPDWORD cbDomainName
,
432 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
433 HMODULE hm_advapi32
= NULL
;
434 if (is_windows_9x () == TRUE
)
438 if (g_b_init_lookup_account_sid
== 0)
440 g_b_init_lookup_account_sid
= 1;
441 hm_advapi32
= LoadLibrary ("Advapi32.dll");
442 s_pfn_Lookup_Account_Sid
=
443 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
445 if (s_pfn_Lookup_Account_Sid
== NULL
)
450 s_pfn_Lookup_Account_Sid (
462 get_sid_sub_authority (PSID pSid
, DWORD n
)
464 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
465 static DWORD zero
= 0U;
466 HMODULE hm_advapi32
= NULL
;
467 if (is_windows_9x () == TRUE
)
471 if (g_b_init_get_sid_sub_authority
== 0)
473 g_b_init_get_sid_sub_authority
= 1;
474 hm_advapi32
= LoadLibrary ("Advapi32.dll");
475 s_pfn_Get_Sid_Sub_Authority
=
476 (GetSidSubAuthority_Proc
) GetProcAddress (
477 hm_advapi32
, "GetSidSubAuthority");
479 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
483 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
487 get_sid_sub_authority_count (PSID pSid
)
489 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
490 static UCHAR zero
= 0U;
491 HMODULE hm_advapi32
= NULL
;
492 if (is_windows_9x () == TRUE
)
496 if (g_b_init_get_sid_sub_authority_count
== 0)
498 g_b_init_get_sid_sub_authority_count
= 1;
499 hm_advapi32
= LoadLibrary ("Advapi32.dll");
500 s_pfn_Get_Sid_Sub_Authority_Count
=
501 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
502 hm_advapi32
, "GetSidSubAuthorityCount");
504 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
508 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
512 get_file_security (LPCTSTR lpFileName
,
513 SECURITY_INFORMATION RequestedInformation
,
514 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
516 LPDWORD lpnLengthNeeded
)
518 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
519 HMODULE hm_advapi32
= NULL
;
520 if (is_windows_9x () == TRUE
)
524 if (g_b_init_get_file_security
== 0)
526 g_b_init_get_file_security
= 1;
527 hm_advapi32
= LoadLibrary ("Advapi32.dll");
528 s_pfn_Get_File_Security
=
529 (GetFileSecurity_Proc
) GetProcAddress (
530 hm_advapi32
, GetFileSecurity_Name
);
532 if (s_pfn_Get_File_Security
== NULL
)
536 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
537 pSecurityDescriptor
, nLength
,
542 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
544 LPBOOL lpbOwnerDefaulted
)
546 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
547 HMODULE hm_advapi32
= NULL
;
548 if (is_windows_9x () == TRUE
)
552 if (g_b_init_get_security_descriptor_owner
== 0)
554 g_b_init_get_security_descriptor_owner
= 1;
555 hm_advapi32
= LoadLibrary ("Advapi32.dll");
556 s_pfn_Get_Security_Descriptor_Owner
=
557 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
558 hm_advapi32
, "GetSecurityDescriptorOwner");
560 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
564 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
569 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
571 LPBOOL lpbGroupDefaulted
)
573 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
574 HMODULE hm_advapi32
= NULL
;
575 if (is_windows_9x () == TRUE
)
579 if (g_b_init_get_security_descriptor_group
== 0)
581 g_b_init_get_security_descriptor_group
= 1;
582 hm_advapi32
= LoadLibrary ("Advapi32.dll");
583 s_pfn_Get_Security_Descriptor_Group
=
584 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
585 hm_advapi32
, "GetSecurityDescriptorGroup");
587 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
591 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
596 is_valid_sid (PSID sid
)
598 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
599 HMODULE hm_advapi32
= NULL
;
600 if (is_windows_9x () == TRUE
)
604 if (g_b_init_is_valid_sid
== 0)
606 g_b_init_is_valid_sid
= 1;
607 hm_advapi32
= LoadLibrary ("Advapi32.dll");
609 (IsValidSid_Proc
) GetProcAddress (
610 hm_advapi32
, "IsValidSid");
612 if (s_pfn_Is_Valid_Sid
== NULL
)
616 return (s_pfn_Is_Valid_Sid (sid
));
620 equal_sid (PSID sid1
, PSID sid2
)
622 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
623 HMODULE hm_advapi32
= NULL
;
624 if (is_windows_9x () == TRUE
)
628 if (g_b_init_equal_sid
== 0)
630 g_b_init_equal_sid
= 1;
631 hm_advapi32
= LoadLibrary ("Advapi32.dll");
633 (EqualSid_Proc
) GetProcAddress (
634 hm_advapi32
, "EqualSid");
636 if (s_pfn_Equal_Sid
== NULL
)
640 return (s_pfn_Equal_Sid (sid1
, sid2
));
644 get_length_sid (PSID sid
)
646 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
647 HMODULE hm_advapi32
= NULL
;
648 if (is_windows_9x () == TRUE
)
652 if (g_b_init_get_length_sid
== 0)
654 g_b_init_get_length_sid
= 1;
655 hm_advapi32
= LoadLibrary ("Advapi32.dll");
656 s_pfn_Get_Length_Sid
=
657 (GetLengthSid_Proc
) GetProcAddress (
658 hm_advapi32
, "GetLengthSid");
660 if (s_pfn_Get_Length_Sid
== NULL
)
664 return (s_pfn_Get_Length_Sid (sid
));
668 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
670 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
671 HMODULE hm_advapi32
= NULL
;
672 if (is_windows_9x () == TRUE
)
676 if (g_b_init_copy_sid
== 0)
678 g_b_init_copy_sid
= 1;
679 hm_advapi32
= LoadLibrary ("Advapi32.dll");
681 (CopySid_Proc
) GetProcAddress (
682 hm_advapi32
, "CopySid");
684 if (s_pfn_Copy_Sid
== NULL
)
688 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
692 END: Wrapper functions around OpenProcessToken
693 and other functions in advapi32.dll that are only
694 supported in Windows NT / 2k / XP
698 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
700 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
701 if (is_windows_9x () != TRUE
)
703 if (g_b_init_get_native_system_info
== 0)
705 g_b_init_get_native_system_info
= 1;
706 s_pfn_Get_Native_System_Info
=
707 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
708 "GetNativeSystemInfo");
710 if (s_pfn_Get_Native_System_Info
!= NULL
)
711 s_pfn_Get_Native_System_Info (lpSystemInfo
);
714 lpSystemInfo
->dwNumberOfProcessors
= -1;
718 get_system_times (LPFILETIME lpIdleTime
,
719 LPFILETIME lpKernelTime
,
720 LPFILETIME lpUserTime
)
722 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
723 if (is_windows_9x () == TRUE
)
727 if (g_b_init_get_system_times
== 0)
729 g_b_init_get_system_times
= 1;
730 s_pfn_Get_System_times
=
731 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
734 if (s_pfn_Get_System_times
== NULL
)
736 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
739 /* Equivalent of strerror for W32 error codes. */
741 w32_strerror (int error_no
)
743 static char buf
[500];
746 error_no
= GetLastError ();
749 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
751 0, /* choose most suitable language */
752 buf
, sizeof (buf
), NULL
))
753 sprintf (buf
, "w32 error %u", error_no
);
757 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
758 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
760 This is called from alloc.c:valid_pointer_p. */
762 w32_valid_pointer_p (void *p
, int size
)
765 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
769 unsigned char *buf
= alloca (size
);
770 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
779 static char startup_dir
[MAXPATHLEN
];
781 /* Get the current working directory. */
786 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
790 /* Emacs doesn't actually change directory itself, and we want to
791 force our real wd to be where emacs.exe is to avoid unnecessary
792 conflicts when trying to rename or delete directories. */
793 strcpy (dir
, startup_dir
);
798 /* Emulate getloadavg. */
807 /* Number of processors on this machine. */
808 static unsigned num_of_processors
;
810 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
811 static struct load_sample samples
[16*60];
812 static int first_idx
= -1, last_idx
= -1;
813 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
818 int next_idx
= from
+ 1;
820 if (next_idx
>= max_idx
)
829 int prev_idx
= from
- 1;
832 prev_idx
= max_idx
- 1;
838 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
841 FILETIME ft_idle
, ft_user
, ft_kernel
;
843 /* Initialize the number of processors on this machine. */
844 if (num_of_processors
<= 0)
846 get_native_system_info (&sysinfo
);
847 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
848 if (num_of_processors
<= 0)
850 GetSystemInfo (&sysinfo
);
851 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
853 if (num_of_processors
<= 0)
854 num_of_processors
= 1;
857 /* TODO: Take into account threads that are ready to run, by
858 sampling the "\System\Processor Queue Length" performance
859 counter. The code below accounts only for threads that are
862 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
864 ULARGE_INTEGER uidle
, ukernel
, uuser
;
866 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
867 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
868 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
869 *idle
= uidle
.QuadPart
;
870 *kernel
= ukernel
.QuadPart
;
871 *user
= uuser
.QuadPart
;
881 /* Produce the load average for a given time interval, using the
882 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
883 1-minute, 5-minute, or 15-minute average, respectively. */
887 double retval
= -1.0;
890 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
891 time_t now
= samples
[last_idx
].sample_time
;
893 if (first_idx
!= last_idx
)
895 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
897 tdiff
= difftime (now
, samples
[idx
].sample_time
);
898 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
901 samples
[last_idx
].kernel
+ samples
[last_idx
].user
902 - (samples
[idx
].kernel
+ samples
[idx
].user
);
903 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
905 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
908 if (idx
== first_idx
)
917 getloadavg (double loadavg
[], int nelem
)
920 ULONGLONG idle
, kernel
, user
;
921 time_t now
= time (NULL
);
923 /* Store another sample. We ignore samples that are less than 1 sec
925 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
927 sample_system_load (&idle
, &kernel
, &user
);
928 last_idx
= buf_next (last_idx
);
929 samples
[last_idx
].sample_time
= now
;
930 samples
[last_idx
].idle
= idle
;
931 samples
[last_idx
].kernel
= kernel
;
932 samples
[last_idx
].user
= user
;
933 /* If the buffer has more that 15 min worth of samples, discard
936 first_idx
= last_idx
;
937 while (first_idx
!= last_idx
938 && (difftime (now
, samples
[first_idx
].sample_time
)
939 >= 15.0*60 + 2*DBL_EPSILON
*now
))
940 first_idx
= buf_next (first_idx
);
943 for (elem
= 0; elem
< nelem
; elem
++)
945 double avg
= getavg (elem
);
955 /* Emulate getpwuid, getpwnam and others. */
957 #define PASSWD_FIELD_SIZE 256
959 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
960 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
961 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
962 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
963 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
965 static struct passwd dflt_passwd
=
977 static char dflt_group_name
[GNLEN
+1];
979 static struct group dflt_group
=
981 /* When group information is not available, we return this as the
982 group for all files. */
990 return dflt_passwd
.pw_uid
;
996 /* I could imagine arguing for checking to see whether the user is
997 in the Administrators group and returning a UID of 0 for that
998 case, but I don't know how wise that would be in the long run. */
1005 return dflt_passwd
.pw_gid
;
1015 getpwuid (unsigned uid
)
1017 if (uid
== dflt_passwd
.pw_uid
)
1018 return &dflt_passwd
;
1023 getgrgid (gid_t gid
)
1029 getpwnam (char *name
)
1033 pw
= getpwuid (getuid ());
1037 if (xstrcasecmp (name
, pw
->pw_name
))
1044 init_user_info (void)
1046 /* Find the user's real name by opening the process token and
1047 looking up the name associated with the user-sid in that token.
1049 Use the relative portion of the identifier authority value from
1050 the user-sid as the user id value (same for group id using the
1051 primary group sid from the process token). */
1053 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1054 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1055 DWORD glength
= sizeof (gname
);
1056 HANDLE token
= NULL
;
1057 SID_NAME_USE user_type
;
1058 unsigned char *buf
= NULL
;
1060 TOKEN_USER user_token
;
1061 TOKEN_PRIMARY_GROUP group_token
;
1064 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1067 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1068 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1070 buf
= xmalloc (blen
);
1071 result
= get_token_information (token
, TokenUser
,
1072 (LPVOID
)buf
, blen
, &needed
);
1075 memcpy (&user_token
, buf
, sizeof (user_token
));
1076 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1078 domain
, &dlength
, &user_type
);
1086 strcpy (dflt_passwd
.pw_name
, uname
);
1087 /* Determine a reasonable uid value. */
1088 if (xstrcasecmp ("administrator", uname
) == 0)
1090 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1091 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1095 /* Use the last sub-authority value of the RID, the relative
1096 portion of the SID, as user/group ID. */
1097 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1099 /* Get group id and name. */
1100 result
= get_token_information (token
, TokenPrimaryGroup
,
1101 (LPVOID
)buf
, blen
, &needed
);
1102 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1104 buf
= xrealloc (buf
, blen
= needed
);
1105 result
= get_token_information (token
, TokenPrimaryGroup
,
1106 (LPVOID
)buf
, blen
, &needed
);
1110 memcpy (&group_token
, buf
, sizeof (group_token
));
1111 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1112 dlength
= sizeof (domain
);
1113 /* If we can get at the real Primary Group name, use that.
1114 Otherwise, the default group name was already set to
1115 "None" in globals_of_w32. */
1116 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1117 gname
, &glength
, NULL
, &dlength
,
1119 strcpy (dflt_group_name
, gname
);
1122 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1125 /* If security calls are not supported (presumably because we
1126 are running under Windows 9X), fallback to this: */
1127 else if (GetUserName (uname
, &ulength
))
1129 strcpy (dflt_passwd
.pw_name
, uname
);
1130 if (xstrcasecmp ("administrator", uname
) == 0)
1131 dflt_passwd
.pw_uid
= 0;
1133 dflt_passwd
.pw_uid
= 123;
1134 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1138 strcpy (dflt_passwd
.pw_name
, "unknown");
1139 dflt_passwd
.pw_uid
= 123;
1140 dflt_passwd
.pw_gid
= 123;
1142 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1144 /* Ensure HOME and SHELL are defined. */
1145 if (getenv ("HOME") == NULL
)
1147 if (getenv ("SHELL") == NULL
)
1150 /* Set dir and shell from environment variables. */
1151 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1152 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1156 CloseHandle (token
);
1162 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1163 return ((rand () << 15) | rand ());
1173 /* Normalize filename by converting all path separators to
1174 the specified separator. Also conditionally convert upper
1175 case path name components to lower case. */
1178 normalize_filename (register char *fp
, char path_sep
)
1183 /* Always lower-case drive letters a-z, even if the filesystem
1184 preserves case in filenames.
1185 This is so filenames can be compared by string comparison
1186 functions that are case-sensitive. Even case-preserving filesystems
1187 do not distinguish case in drive letters. */
1188 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1194 if (NILP (Vw32_downcase_file_names
))
1198 if (*fp
== '/' || *fp
== '\\')
1205 sep
= path_sep
; /* convert to this path separator */
1206 elem
= fp
; /* start of current path element */
1209 if (*fp
>= 'a' && *fp
<= 'z')
1210 elem
= 0; /* don't convert this element */
1212 if (*fp
== 0 || *fp
== ':')
1214 sep
= *fp
; /* restore current separator (or 0) */
1215 *fp
= '/'; /* after conversion of this element */
1218 if (*fp
== '/' || *fp
== '\\')
1220 if (elem
&& elem
!= fp
)
1222 *fp
= 0; /* temporary end of string */
1223 _strlwr (elem
); /* while we convert to lower case */
1225 *fp
= sep
; /* convert (or restore) path separator */
1226 elem
= fp
+ 1; /* next element starts after separator */
1232 /* Destructively turn backslashes into slashes. */
1234 dostounix_filename (register char *p
)
1236 normalize_filename (p
, '/');
1239 /* Destructively turn slashes into backslashes. */
1241 unixtodos_filename (register char *p
)
1243 normalize_filename (p
, '\\');
1246 /* Remove all CR's that are followed by a LF.
1247 (From msdos.c...probably should figure out a way to share it,
1248 although this code isn't going to ever change.) */
1250 crlf_to_lf (register int n
, register unsigned char *buf
)
1252 unsigned char *np
= buf
;
1253 unsigned char *startp
= buf
;
1254 unsigned char *endp
= buf
+ n
;
1258 while (buf
< endp
- 1)
1262 if (*(++buf
) != 0x0a)
1273 /* Parse the root part of file name, if present. Return length and
1274 optionally store pointer to char after root. */
1276 parse_root (char * name
, char ** pPath
)
1278 char * start
= name
;
1283 /* find the root name of the volume if given */
1284 if (isalpha (name
[0]) && name
[1] == ':')
1286 /* skip past drive specifier */
1288 if (IS_DIRECTORY_SEP (name
[0]))
1291 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1297 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1302 if (IS_DIRECTORY_SEP (name
[0]))
1309 return name
- start
;
1312 /* Get long base name for name; name is assumed to be absolute. */
1314 get_long_basename (char * name
, char * buf
, int size
)
1316 WIN32_FIND_DATA find_data
;
1320 /* must be valid filename, no wild cards or other invalid characters */
1321 if (_mbspbrk (name
, "*?|<>\""))
1324 dir_handle
= FindFirstFile (name
, &find_data
);
1325 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1327 if ((len
= strlen (find_data
.cFileName
)) < size
)
1328 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1331 FindClose (dir_handle
);
1336 /* Get long name for file, if possible (assumed to be absolute). */
1338 w32_get_long_filename (char * name
, char * buf
, int size
)
1343 char full
[ MAX_PATH
];
1346 len
= strlen (name
);
1347 if (len
>= MAX_PATH
)
1350 /* Use local copy for destructive modification. */
1351 memcpy (full
, name
, len
+1);
1352 unixtodos_filename (full
);
1354 /* Copy root part verbatim. */
1355 len
= parse_root (full
, &p
);
1356 memcpy (o
, full
, len
);
1361 while (p
!= NULL
&& *p
)
1364 p
= strchr (q
, '\\');
1366 len
= get_long_basename (full
, o
, size
);
1389 is_unc_volume (const char *filename
)
1391 const char *ptr
= filename
;
1393 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1396 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1402 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1405 sigsetmask (int signal_mask
)
1423 sigunblock (int sig
)
1429 sigemptyset (sigset_t
*set
)
1435 sigaddset (sigset_t
*set
, int signo
)
1441 sigfillset (sigset_t
*set
)
1447 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1453 setpgrp (int pid
, int gid
)
1464 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1467 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1470 HKEY hrootkey
= NULL
;
1473 /* Check both the current user and the local machine to see if
1474 we have any resources. */
1476 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1480 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1481 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1482 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1484 RegCloseKey (hrootkey
);
1490 RegCloseKey (hrootkey
);
1493 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1497 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1498 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1499 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1501 RegCloseKey (hrootkey
);
1507 RegCloseKey (hrootkey
);
1513 char *get_emacs_configuration (void);
1516 init_environment (char ** argv
)
1518 static const char * const tempdirs
[] = {
1519 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1524 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1526 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1527 temporary files and assume "/tmp" if $TMPDIR is unset, which
1528 will break on DOS/Windows. Refuse to work if we cannot find
1529 a directory, not even "c:/", usable for that purpose. */
1530 for (i
= 0; i
< imax
; i
++)
1532 const char *tmp
= tempdirs
[i
];
1535 tmp
= getenv (tmp
+ 1);
1536 /* Note that `access' can lie to us if the directory resides on a
1537 read-only filesystem, like CD-ROM or a write-protected floppy.
1538 The only way to be really sure is to actually create a file and
1539 see if it succeeds. But I think that's too much to ask. */
1540 if (tmp
&& _access (tmp
, D_OK
) == 0)
1542 char * var
= alloca (strlen (tmp
) + 8);
1543 sprintf (var
, "TMPDIR=%s", tmp
);
1544 _putenv (strdup (var
));
1551 Fcons (build_string ("no usable temporary directories found!!"),
1553 "While setting TMPDIR: ");
1555 /* Check for environment variables and use registry settings if they
1556 don't exist. Fallback on default values where applicable. */
1561 char locale_name
[32];
1562 struct stat ignored
;
1563 char default_home
[MAX_PATH
];
1565 static const struct env_entry
1572 {"PRELOAD_WINSOCK", NULL
},
1573 {"emacs_dir", "C:/emacs"},
1574 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1575 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1576 {"EMACSDATA", "%emacs_dir%/etc"},
1577 {"EMACSPATH", "%emacs_dir%/bin"},
1578 /* We no longer set INFOPATH because Info-default-directory-list
1580 /* {"INFOPATH", "%emacs_dir%/info"}, */
1581 {"EMACSDOC", "%emacs_dir%/etc"},
1586 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1588 /* We need to copy dflt_envvars[] and work on the copy because we
1589 don't want the dumped Emacs to inherit the values of
1590 environment variables we saw during dumping (which could be on
1591 a different system). The defaults above must be left intact. */
1592 struct env_entry env_vars
[N_ENV_VARS
];
1594 for (i
= 0; i
< N_ENV_VARS
; i
++)
1595 env_vars
[i
] = dflt_envvars
[i
];
1597 /* For backwards compatibility, check if a .emacs file exists in C:/
1598 If not, then we can try to default to the appdata directory under the
1599 user's profile, which is more likely to be writable. */
1600 if (stat ("C:/.emacs", &ignored
) < 0)
1602 HRESULT profile_result
;
1603 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1604 of Windows 95 and NT4 that have not been updated to include
1606 ShGetFolderPath_fn get_folder_path
;
1607 get_folder_path
= (ShGetFolderPath_fn
)
1608 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1610 if (get_folder_path
!= NULL
)
1612 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1615 /* If we can't get the appdata dir, revert to old behavior. */
1616 if (profile_result
== S_OK
)
1617 env_vars
[0].def_value
= default_home
;
1621 /* Get default locale info and use it for LANG. */
1622 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1623 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1624 locale_name
, sizeof (locale_name
)))
1626 for (i
= 0; i
< N_ENV_VARS
; i
++)
1628 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1630 env_vars
[i
].def_value
= locale_name
;
1636 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1638 /* Treat emacs_dir specially: set it unconditionally based on our
1639 location, if it appears that we are running from the bin subdir
1640 of a standard installation. */
1643 char modname
[MAX_PATH
];
1645 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1647 if ((p
= strrchr (modname
, '\\')) == NULL
)
1651 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1653 char buf
[SET_ENV_BUF_SIZE
];
1656 for (p
= modname
; *p
; p
++)
1657 if (*p
== '\\') *p
= '/';
1659 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1660 _putenv (strdup (buf
));
1662 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1664 /* FIXME: should use substring of get_emacs_configuration ().
1665 But I don't think the Windows build supports alpha, mips etc
1666 anymore, so have taken the easy option for now. */
1667 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1670 p
= strrchr (modname
, '\\');
1674 p
= strrchr (modname
, '\\');
1675 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1677 char buf
[SET_ENV_BUF_SIZE
];
1680 for (p
= modname
; *p
; p
++)
1681 if (*p
== '\\') *p
= '/';
1683 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1684 _putenv (strdup (buf
));
1690 for (i
= 0; i
< N_ENV_VARS
; i
++)
1692 if (!getenv (env_vars
[i
].name
))
1696 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1697 /* Also ignore empty environment variables. */
1701 lpval
= env_vars
[i
].def_value
;
1702 dwType
= REG_EXPAND_SZ
;
1708 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1710 if (dwType
== REG_EXPAND_SZ
)
1711 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1712 else if (dwType
== REG_SZ
)
1713 strcpy (buf1
, lpval
);
1714 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1716 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1718 _putenv (strdup (buf2
));
1728 /* Rebuild system configuration to reflect invoking system. */
1729 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1731 /* Another special case: on NT, the PATH variable is actually named
1732 "Path" although cmd.exe (perhaps NT itself) arranges for
1733 environment variable lookup and setting to be case insensitive.
1734 However, Emacs assumes a fully case sensitive environment, so we
1735 need to change "Path" to "PATH" to match the expectations of
1736 various elisp packages. We do this by the sneaky method of
1737 modifying the string in the C runtime environ entry.
1739 The same applies to COMSPEC. */
1743 for (envp
= environ
; *envp
; envp
++)
1744 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1745 memcpy (*envp
, "PATH=", 5);
1746 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1747 memcpy (*envp
, "COMSPEC=", 8);
1750 /* Remember the initial working directory for getwd, then make the
1751 real wd be the location of emacs.exe to avoid conflicts when
1752 renaming or deleting directories. (We also don't call chdir when
1753 running subprocesses for the same reason.) */
1754 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1759 static char modname
[MAX_PATH
];
1761 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1763 if ((p
= strrchr (modname
, '\\')) == NULL
)
1767 SetCurrentDirectory (modname
);
1769 /* Ensure argv[0] has the full path to Emacs. */
1774 /* Determine if there is a middle mouse button, to allow parse_button
1775 to decide whether right mouse events should be mouse-2 or
1777 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1783 emacs_root_dir (void)
1785 static char root_dir
[FILENAME_MAX
];
1788 p
= getenv ("emacs_dir");
1791 strcpy (root_dir
, p
);
1792 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1793 dostounix_filename (root_dir
);
1797 /* We don't have scripts to automatically determine the system configuration
1798 for Emacs before it's compiled, and we don't want to have to make the
1799 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1803 get_emacs_configuration (void)
1805 char *arch
, *oem
, *os
;
1807 static char configuration_buffer
[32];
1809 /* Determine the processor type. */
1810 switch (get_processor_type ())
1813 #ifdef PROCESSOR_INTEL_386
1814 case PROCESSOR_INTEL_386
:
1815 case PROCESSOR_INTEL_486
:
1816 case PROCESSOR_INTEL_PENTIUM
:
1821 #ifdef PROCESSOR_MIPS_R2000
1822 case PROCESSOR_MIPS_R2000
:
1823 case PROCESSOR_MIPS_R3000
:
1824 case PROCESSOR_MIPS_R4000
:
1829 #ifdef PROCESSOR_ALPHA_21064
1830 case PROCESSOR_ALPHA_21064
:
1840 /* Use the OEM field to reflect the compiler/library combination. */
1842 #define COMPILER_NAME "msvc"
1845 #define COMPILER_NAME "mingw"
1847 #define COMPILER_NAME "unknown"
1850 oem
= COMPILER_NAME
;
1852 switch (osinfo_cache
.dwPlatformId
) {
1853 case VER_PLATFORM_WIN32_NT
:
1855 build_num
= osinfo_cache
.dwBuildNumber
;
1857 case VER_PLATFORM_WIN32_WINDOWS
:
1858 if (osinfo_cache
.dwMinorVersion
== 0) {
1863 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1865 case VER_PLATFORM_WIN32s
:
1866 /* Not supported, should not happen. */
1868 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1876 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1877 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1878 get_w32_major_version (), get_w32_minor_version (), build_num
);
1880 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1883 return configuration_buffer
;
1887 get_emacs_configuration_options (void)
1889 static char *options_buffer
;
1890 char cv
[32]; /* Enough for COMPILER_VERSION. */
1892 cv
, /* To be filled later. */
1896 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1897 with a starting space to save work here. */
1899 " --cflags", USER_CFLAGS
,
1902 " --ldflags", USER_LDFLAGS
,
1909 /* Work out the effective configure options for this build. */
1911 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1914 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1916 #define COMPILER_VERSION ""
1920 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
1921 return "Error: not enough space for compiler version";
1922 cv
[sizeof (cv
) - 1] = '\0';
1924 for (i
= 0; options
[i
]; i
++)
1925 size
+= strlen (options
[i
]);
1927 options_buffer
= xmalloc (size
+ 1);
1928 options_buffer
[0] = '\0';
1930 for (i
= 0; options
[i
]; i
++)
1931 strcat (options_buffer
, options
[i
]);
1933 return options_buffer
;
1937 #include <sys/timeb.h>
1939 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1941 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1946 tv
->tv_sec
= tb
.time
;
1947 tv
->tv_usec
= tb
.millitm
* 1000L;
1948 /* Implementation note: _ftime sometimes doesn't update the dstflag
1949 according to the new timezone when the system timezone is
1950 changed. We could fix that by using GetSystemTime and
1951 GetTimeZoneInformation, but that doesn't seem necessary, since
1952 Emacs always calls gettimeofday with the 2nd argument NULL (see
1956 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1957 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1961 /* ------------------------------------------------------------------------- */
1962 /* IO support and wrapper functions for W32 API. */
1963 /* ------------------------------------------------------------------------- */
1965 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1966 on network directories, so we handle that case here.
1967 (Ulrich Leodolter, 1/11/95). */
1969 sys_ctime (const time_t *t
)
1971 char *str
= (char *) ctime (t
);
1972 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1975 /* Emulate sleep...we could have done this with a define, but that
1976 would necessitate including windows.h in the files that used it.
1977 This is much easier. */
1979 sys_sleep (int seconds
)
1981 Sleep (seconds
* 1000);
1984 /* Internal MSVC functions for low-level descriptor munging */
1985 extern int __cdecl
_set_osfhnd (int fd
, long h
);
1986 extern int __cdecl
_free_osfhnd (int fd
);
1988 /* parallel array of private info on file handles */
1989 filedesc fd_info
[ MAXDESC
];
1991 typedef struct volume_info_data
{
1992 struct volume_info_data
* next
;
1994 /* time when info was obtained */
1997 /* actual volume info */
2006 /* Global referenced by various functions. */
2007 static volume_info_data volume_info
;
2009 /* Vector to indicate which drives are local and fixed (for which cached
2010 data never expires). */
2011 static BOOL fixed_drives
[26];
2013 /* Consider cached volume information to be stale if older than 10s,
2014 at least for non-local drives. Info for fixed drives is never stale. */
2015 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2016 #define VOLINFO_STILL_VALID( root_dir, info ) \
2017 ( ( isalpha (root_dir[0]) && \
2018 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2019 || GetTickCount () - info->timestamp < 10000 )
2021 /* Cache support functions. */
2023 /* Simple linked list with linear search is sufficient. */
2024 static volume_info_data
*volume_cache
= NULL
;
2026 static volume_info_data
*
2027 lookup_volume_info (char * root_dir
)
2029 volume_info_data
* info
;
2031 for (info
= volume_cache
; info
; info
= info
->next
)
2032 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2038 add_volume_info (char * root_dir
, volume_info_data
* info
)
2040 info
->root_dir
= xstrdup (root_dir
);
2041 info
->next
= volume_cache
;
2042 volume_cache
= info
;
2046 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2047 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2048 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2049 static volume_info_data
*
2050 GetCachedVolumeInformation (char * root_dir
)
2052 volume_info_data
* info
;
2053 char default_root
[ MAX_PATH
];
2055 /* NULL for root_dir means use root from current directory. */
2056 if (root_dir
== NULL
)
2058 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2060 parse_root (default_root
, &root_dir
);
2062 root_dir
= default_root
;
2065 /* Local fixed drives can be cached permanently. Removable drives
2066 cannot be cached permanently, since the volume name and serial
2067 number (if nothing else) can change. Remote drives should be
2068 treated as if they are removable, since there is no sure way to
2069 tell whether they are or not. Also, the UNC association of drive
2070 letters mapped to remote volumes can be changed at any time (even
2071 by other processes) without notice.
2073 As a compromise, so we can benefit from caching info for remote
2074 volumes, we use a simple expiry mechanism to invalidate cache
2075 entries that are more than ten seconds old. */
2078 /* No point doing this, because WNetGetConnection is even slower than
2079 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2080 GetDriveType is about the only call of this type which does not
2081 involve network access, and so is extremely quick). */
2083 /* Map drive letter to UNC if remote. */
2084 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2086 char remote_name
[ 256 ];
2087 char drive
[3] = { root_dir
[0], ':' };
2089 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2091 /* do something */ ;
2095 info
= lookup_volume_info (root_dir
);
2097 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2105 /* Info is not cached, or is stale. */
2106 if (!GetVolumeInformation (root_dir
,
2107 name
, sizeof (name
),
2111 type
, sizeof (type
)))
2114 /* Cache the volume information for future use, overwriting existing
2115 entry if present. */
2118 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2119 add_volume_info (root_dir
, info
);
2127 info
->name
= xstrdup (name
);
2128 info
->serialnum
= serialnum
;
2129 info
->maxcomp
= maxcomp
;
2130 info
->flags
= flags
;
2131 info
->type
= xstrdup (type
);
2132 info
->timestamp
= GetTickCount ();
2138 /* Get information on the volume where name is held; set path pointer to
2139 start of pathname in name (past UNC header\volume header if present). */
2141 get_volume_info (const char * name
, const char ** pPath
)
2143 char temp
[MAX_PATH
];
2144 char *rootname
= NULL
; /* default to current volume */
2145 volume_info_data
* info
;
2150 /* find the root name of the volume if given */
2151 if (isalpha (name
[0]) && name
[1] == ':')
2159 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2166 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2179 info
= GetCachedVolumeInformation (rootname
);
2182 /* Set global referenced by other functions. */
2183 volume_info
= *info
;
2189 /* Determine if volume is FAT format (ie. only supports short 8.3
2190 names); also set path pointer to start of pathname in name. */
2192 is_fat_volume (const char * name
, const char ** pPath
)
2194 if (get_volume_info (name
, pPath
))
2195 return (volume_info
.maxcomp
== 12);
2199 /* Map filename to a valid 8.3 name if necessary. */
2201 map_w32_filename (const char * name
, const char ** pPath
)
2203 static char shortname
[MAX_PATH
];
2204 char * str
= shortname
;
2207 const char * save_name
= name
;
2209 if (strlen (name
) >= MAX_PATH
)
2211 /* Return a filename which will cause callers to fail. */
2212 strcpy (shortname
, "?");
2216 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2218 register int left
= 8; /* maximum number of chars in part */
2219 register int extn
= 0; /* extension added? */
2220 register int dots
= 2; /* maximum number of dots allowed */
2223 *str
++ = *name
++; /* skip past UNC header */
2225 while ((c
= *name
++))
2232 extn
= 0; /* reset extension flags */
2233 dots
= 2; /* max 2 dots */
2234 left
= 8; /* max length 8 for main part */
2238 extn
= 0; /* reset extension flags */
2239 dots
= 2; /* max 2 dots */
2240 left
= 8; /* max length 8 for main part */
2245 /* Convert path components of the form .xxx to _xxx,
2246 but leave . and .. as they are. This allows .emacs
2247 to be read as _emacs, for example. */
2251 IS_DIRECTORY_SEP (*name
))
2266 extn
= 1; /* we've got an extension */
2267 left
= 3; /* 3 chars in extension */
2271 /* any embedded dots after the first are converted to _ */
2276 case '#': /* don't lose these, they're important */
2278 str
[-1] = c
; /* replace last character of part */
2283 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2285 dots
= 0; /* started a path component */
2294 strcpy (shortname
, name
);
2295 unixtodos_filename (shortname
);
2299 *pPath
= shortname
+ (path
- save_name
);
2305 is_exec (const char * name
)
2307 char * p
= strrchr (name
, '.');
2310 && (xstrcasecmp (p
, ".exe") == 0 ||
2311 xstrcasecmp (p
, ".com") == 0 ||
2312 xstrcasecmp (p
, ".bat") == 0 ||
2313 xstrcasecmp (p
, ".cmd") == 0));
2316 /* Emulate the Unix directory procedures opendir, closedir,
2317 and readdir. We can't use the procedures supplied in sysdep.c,
2318 so we provide them here. */
2320 struct direct dir_static
; /* simulated directory contents */
2321 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2322 static int dir_is_fat
;
2323 static char dir_pathname
[MAXPATHLEN
+1];
2324 static WIN32_FIND_DATA dir_find_data
;
2326 /* Support shares on a network resource as subdirectories of a read-only
2328 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2329 static HANDLE
open_unc_volume (const char *);
2330 static char *read_unc_volume (HANDLE
, char *, int);
2331 static void close_unc_volume (HANDLE
);
2334 opendir (char *filename
)
2338 /* Opening is done by FindFirstFile. However, a read is inherent to
2339 this operation, so we defer the open until read time. */
2341 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2343 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2346 if (is_unc_volume (filename
))
2348 wnet_enum_handle
= open_unc_volume (filename
);
2349 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2353 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2360 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2361 dir_pathname
[MAXPATHLEN
] = '\0';
2362 dir_is_fat
= is_fat_volume (filename
, NULL
);
2368 closedir (DIR *dirp
)
2370 /* If we have a find-handle open, close it. */
2371 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2373 FindClose (dir_find_handle
);
2374 dir_find_handle
= INVALID_HANDLE_VALUE
;
2376 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2378 close_unc_volume (wnet_enum_handle
);
2379 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2381 xfree ((char *) dirp
);
2387 int downcase
= !NILP (Vw32_downcase_file_names
);
2389 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2391 if (!read_unc_volume (wnet_enum_handle
,
2392 dir_find_data
.cFileName
,
2396 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2397 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2399 char filename
[MAXNAMLEN
+ 3];
2402 strcpy (filename
, dir_pathname
);
2403 ln
= strlen (filename
) - 1;
2404 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2405 strcat (filename
, "\\");
2406 strcat (filename
, "*");
2408 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2410 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2415 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2419 /* Emacs never uses this value, so don't bother making it match
2420 value returned by stat(). */
2421 dir_static
.d_ino
= 1;
2423 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2425 /* If the file name in cFileName[] includes `?' characters, it means
2426 the original file name used characters that cannot be represented
2427 by the current ANSI codepage. To avoid total lossage, retrieve
2428 the short 8+3 alias of the long file name. */
2429 if (_mbspbrk (dir_static
.d_name
, "?"))
2431 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2432 downcase
= 1; /* 8+3 aliases are returned in all caps */
2434 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2435 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2436 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2438 /* If the file name in cFileName[] includes `?' characters, it means
2439 the original file name used characters that cannot be represented
2440 by the current ANSI codepage. To avoid total lossage, retrieve
2441 the short 8+3 alias of the long file name. */
2442 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2444 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2445 /* 8+3 aliases are returned in all caps, which could break
2446 various alists that look at filenames' extensions. */
2450 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2451 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2453 _strlwr (dir_static
.d_name
);
2457 for (p
= dir_static
.d_name
; *p
; p
++)
2458 if (*p
>= 'a' && *p
<= 'z')
2461 _strlwr (dir_static
.d_name
);
2468 open_unc_volume (const char *path
)
2474 nr
.dwScope
= RESOURCE_GLOBALNET
;
2475 nr
.dwType
= RESOURCETYPE_DISK
;
2476 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2477 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2478 nr
.lpLocalName
= NULL
;
2479 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2480 nr
.lpComment
= NULL
;
2481 nr
.lpProvider
= NULL
;
2483 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2484 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2486 if (result
== NO_ERROR
)
2489 return INVALID_HANDLE_VALUE
;
2493 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2497 DWORD bufsize
= 512;
2502 buffer
= alloca (bufsize
);
2503 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
2504 if (result
!= NO_ERROR
)
2507 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2508 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2510 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2513 strncpy (readbuf
, ptr
, size
);
2518 close_unc_volume (HANDLE henum
)
2520 if (henum
!= INVALID_HANDLE_VALUE
)
2521 WNetCloseEnum (henum
);
2525 unc_volume_file_attributes (const char *path
)
2530 henum
= open_unc_volume (path
);
2531 if (henum
== INVALID_HANDLE_VALUE
)
2534 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2536 close_unc_volume (henum
);
2541 /* Ensure a network connection is authenticated. */
2543 logon_network_drive (const char *path
)
2545 NETRESOURCE resource
;
2546 char share
[MAX_PATH
];
2551 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2552 drvtype
= DRIVE_REMOTE
;
2553 else if (path
[0] == '\0' || path
[1] != ':')
2554 drvtype
= GetDriveType (NULL
);
2561 drvtype
= GetDriveType (drive
);
2564 /* Only logon to networked drives. */
2565 if (drvtype
!= DRIVE_REMOTE
)
2569 strncpy (share
, path
, MAX_PATH
);
2570 /* Truncate to just server and share name. */
2571 for (i
= 2; i
< MAX_PATH
; i
++)
2573 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2580 resource
.dwType
= RESOURCETYPE_DISK
;
2581 resource
.lpLocalName
= NULL
;
2582 resource
.lpRemoteName
= share
;
2583 resource
.lpProvider
= NULL
;
2585 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2588 /* Shadow some MSVC runtime functions to map requests for long filenames
2589 to reasonable short names if necessary. This was originally added to
2590 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2594 sys_access (const char * path
, int mode
)
2598 /* MSVC implementation doesn't recognize D_OK. */
2599 path
= map_w32_filename (path
, NULL
);
2600 if (is_unc_volume (path
))
2602 attributes
= unc_volume_file_attributes (path
);
2603 if (attributes
== -1) {
2608 else if ((attributes
= GetFileAttributes (path
)) == -1)
2610 /* Should try mapping GetLastError to errno; for now just indicate
2611 that path doesn't exist. */
2615 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2620 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2625 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2634 sys_chdir (const char * path
)
2636 return _chdir (map_w32_filename (path
, NULL
));
2640 sys_chmod (const char * path
, int mode
)
2642 return _chmod (map_w32_filename (path
, NULL
), mode
);
2646 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2648 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2654 sys_creat (const char * path
, int mode
)
2656 return _creat (map_w32_filename (path
, NULL
), mode
);
2660 sys_fopen (const char * path
, const char * mode
)
2664 const char * mode_save
= mode
;
2666 /* Force all file handles to be non-inheritable. This is necessary to
2667 ensure child processes don't unwittingly inherit handles that might
2668 prevent future file access. */
2672 else if (mode
[0] == 'w' || mode
[0] == 'a')
2673 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2677 /* Only do simplistic option parsing. */
2681 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2684 else if (mode
[0] == 'b')
2689 else if (mode
[0] == 't')
2696 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2700 return _fdopen (fd
, mode_save
);
2703 /* This only works on NTFS volumes, but is useful to have. */
2705 sys_link (const char * old
, const char * new)
2709 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2711 if (old
== NULL
|| new == NULL
)
2717 strcpy (oldname
, map_w32_filename (old
, NULL
));
2718 strcpy (newname
, map_w32_filename (new, NULL
));
2720 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2721 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2722 if (fileh
!= INVALID_HANDLE_VALUE
)
2726 /* Confusingly, the "alternate" stream name field does not apply
2727 when restoring a hard link, and instead contains the actual
2728 stream data for the link (ie. the name of the link to create).
2729 The WIN32_STREAM_ID structure before the cStreamName field is
2730 the stream header, which is then immediately followed by the
2734 WIN32_STREAM_ID wid
;
2735 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2738 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2739 data
.wid
.cStreamName
, MAX_PATH
);
2742 LPVOID context
= NULL
;
2745 data
.wid
.dwStreamId
= BACKUP_LINK
;
2746 data
.wid
.dwStreamAttributes
= 0;
2747 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2748 data
.wid
.Size
.HighPart
= 0;
2749 data
.wid
.dwStreamNameSize
= 0;
2751 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2752 offsetof (WIN32_STREAM_ID
, cStreamName
)
2753 + data
.wid
.Size
.LowPart
,
2754 &wbytes
, FALSE
, FALSE
, &context
)
2755 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2762 /* Should try mapping GetLastError to errno; for now just
2763 indicate a general error (eg. links not supported). */
2764 errno
= EINVAL
; // perhaps EMLINK?
2768 CloseHandle (fileh
);
2777 sys_mkdir (const char * path
)
2779 return _mkdir (map_w32_filename (path
, NULL
));
2782 /* Because of long name mapping issues, we need to implement this
2783 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2784 a unique name, instead of setting the input template to an empty
2787 Standard algorithm seems to be use pid or tid with a letter on the
2788 front (in place of the 6 X's) and cycle through the letters to find a
2789 unique name. We extend that to allow any reasonable character as the
2790 first of the 6 X's. */
2792 sys_mktemp (char * template)
2796 unsigned uid
= GetCurrentThreadId ();
2797 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2799 if (template == NULL
)
2801 p
= template + strlen (template);
2803 /* replace up to the last 5 X's with uid in decimal */
2804 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2806 p
[0] = '0' + uid
% 10;
2810 if (i
< 0 && p
[0] == 'X')
2815 int save_errno
= errno
;
2816 p
[0] = first_char
[i
];
2817 if (sys_access (template, 0) < 0)
2823 while (++i
< sizeof (first_char
));
2826 /* Template is badly formed or else we can't generate a unique name,
2827 so return empty string */
2833 sys_open (const char * path
, int oflag
, int mode
)
2835 const char* mpath
= map_w32_filename (path
, NULL
);
2836 /* Try to open file without _O_CREAT, to be able to write to hidden
2837 and system files. Force all file handles to be
2839 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2842 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2846 sys_rename (const char * oldname
, const char * newname
)
2849 char temp
[MAX_PATH
];
2851 /* MoveFile on Windows 95 doesn't correctly change the short file name
2852 alias in a number of circumstances (it is not easy to predict when
2853 just by looking at oldname and newname, unfortunately). In these
2854 cases, renaming through a temporary name avoids the problem.
2856 A second problem on Windows 95 is that renaming through a temp name when
2857 newname is uppercase fails (the final long name ends up in
2858 lowercase, although the short alias might be uppercase) UNLESS the
2859 long temp name is not 8.3.
2861 So, on Windows 95 we always rename through a temp name, and we make sure
2862 the temp name has a long extension to ensure correct renaming. */
2864 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2866 if (os_subtype
== OS_WIN95
)
2872 oldname
= map_w32_filename (oldname
, NULL
);
2873 if (o
= strrchr (oldname
, '\\'))
2876 o
= (char *) oldname
;
2878 if (p
= strrchr (temp
, '\\'))
2885 /* Force temp name to require a manufactured 8.3 alias - this
2886 seems to make the second rename work properly. */
2887 sprintf (p
, "_.%s.%u", o
, i
);
2889 result
= rename (oldname
, temp
);
2891 /* This loop must surely terminate! */
2892 while (result
< 0 && errno
== EEXIST
);
2897 /* Emulate Unix behavior - newname is deleted if it already exists
2898 (at least if it is a file; don't do this for directories).
2900 Since we mustn't do this if we are just changing the case of the
2901 file name (we would end up deleting the file we are trying to
2902 rename!), we let rename detect if the destination file already
2903 exists - that way we avoid the possible pitfalls of trying to
2904 determine ourselves whether two names really refer to the same
2905 file, which is not always possible in the general case. (Consider
2906 all the permutations of shared or subst'd drives, etc.) */
2908 newname
= map_w32_filename (newname
, NULL
);
2909 result
= rename (temp
, newname
);
2913 && _chmod (newname
, 0666) == 0
2914 && _unlink (newname
) == 0)
2915 result
= rename (temp
, newname
);
2921 sys_rmdir (const char * path
)
2923 return _rmdir (map_w32_filename (path
, NULL
));
2927 sys_unlink (const char * path
)
2929 path
= map_w32_filename (path
, NULL
);
2931 /* On Unix, unlink works without write permission. */
2932 _chmod (path
, 0666);
2933 return _unlink (path
);
2936 static FILETIME utc_base_ft
;
2937 static ULONGLONG utc_base
; /* In 100ns units */
2938 static int init
= 0;
2940 #define FILETIME_TO_U64(result, ft) \
2942 ULARGE_INTEGER uiTemp; \
2943 uiTemp.LowPart = (ft).dwLowDateTime; \
2944 uiTemp.HighPart = (ft).dwHighDateTime; \
2945 result = uiTemp.QuadPart; \
2949 initialize_utc_base (void)
2951 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2960 st
.wMilliseconds
= 0;
2962 SystemTimeToFileTime (&st
, &utc_base_ft
);
2963 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2967 convert_time (FILETIME ft
)
2973 initialize_utc_base ();
2977 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2980 FILETIME_TO_U64 (tmp
, ft
);
2981 return (time_t) ((tmp
- utc_base
) / 10000000L);
2985 convert_from_time_t (time_t time
, FILETIME
* pft
)
2991 initialize_utc_base ();
2995 /* time in 100ns units since 1-Jan-1601 */
2996 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
2997 pft
->dwHighDateTime
= tmp
.HighPart
;
2998 pft
->dwLowDateTime
= tmp
.LowPart
;
3002 /* No reason to keep this; faking inode values either by hashing or even
3003 using the file index from GetInformationByHandle, is not perfect and
3004 so by default Emacs doesn't use the inode values on Windows.
3005 Instead, we now determine file-truename correctly (except for
3006 possible drive aliasing etc). */
3008 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3010 hashval (const unsigned char * str
)
3015 h
= (h
<< 4) + *str
++;
3021 /* Return the hash value of the canonical pathname, excluding the
3022 drive/UNC header, to get a hopefully unique inode number. */
3024 generate_inode_val (const char * name
)
3026 char fullname
[ MAX_PATH
];
3030 /* Get the truly canonical filename, if it exists. (Note: this
3031 doesn't resolve aliasing due to subst commands, or recognise hard
3033 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3036 parse_root (fullname
, &p
);
3037 /* Normal W32 filesystems are still case insensitive. */
3044 static PSECURITY_DESCRIPTOR
3045 get_file_security_desc (const char *fname
)
3047 PSECURITY_DESCRIPTOR psd
= NULL
;
3049 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3050 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3052 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3054 err
= GetLastError ();
3055 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3059 psd
= xmalloc (sd_len
);
3060 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3072 unsigned n_subauthorities
;
3074 /* Use the last sub-authority value of the RID, the relative
3075 portion of the SID, as user/group ID. */
3076 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3077 if (n_subauthorities
< 1)
3078 return 0; /* the "World" RID */
3079 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3082 /* Caching SID and account values for faster lokup. */
3085 # define FLEXIBLE_ARRAY_MEMBER
3087 # define FLEXIBLE_ARRAY_MEMBER 1
3092 struct w32_id
*next
;
3094 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3097 static struct w32_id
*w32_idlist
;
3100 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3102 struct w32_id
*tail
, *found
;
3104 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3106 if (equal_sid ((PSID
)tail
->sid
, sid
))
3115 strcpy (name
, found
->name
);
3123 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3126 struct w32_id
*new_entry
;
3128 /* We don't want to leave behind stale cache from when Emacs was
3132 sid_len
= get_length_sid (sid
);
3133 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3136 new_entry
->rid
= id
;
3137 strcpy (new_entry
->name
, name
);
3138 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3139 new_entry
->next
= w32_idlist
;
3140 w32_idlist
= new_entry
;
3149 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3150 unsigned *id
, char *nm
, int what
)
3153 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3155 SID_NAME_USE ignore
;
3157 DWORD name_len
= sizeof (name
);
3159 DWORD domain_len
= sizeof (domain
);
3165 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3166 else if (what
== GID
)
3167 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3171 if (!result
|| !is_valid_sid (sid
))
3173 else if (!w32_cached_id (sid
, id
, nm
))
3175 /* If FNAME is a UNC, we need to lookup account on the
3176 specified machine. */
3177 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3178 && fname
[2] != '\0')
3183 for (s
= fname
+ 2, p
= machine
;
3184 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3190 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3191 domain
, &domain_len
, &ignore
)
3192 || name_len
> UNLEN
+1)
3196 *id
= get_rid (sid
);
3198 w32_add_to_cache (sid
, *id
, name
);
3205 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3209 int dflt_usr
= 0, dflt_grp
= 0;
3218 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3220 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3223 /* Consider files to belong to current user/group, if we cannot get
3224 more accurate information. */
3227 st
->st_uid
= dflt_passwd
.pw_uid
;
3228 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3232 st
->st_gid
= dflt_passwd
.pw_gid
;
3233 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3237 /* Return non-zero if NAME is a potentially slow filesystem. */
3239 is_slow_fs (const char *name
)
3244 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3245 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3246 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3247 devtype
= GetDriveType (NULL
); /* use root of current drive */
3250 /* GetDriveType needs the root directory of the drive. */
3251 strncpy (drive_root
, name
, 2);
3252 drive_root
[2] = '\\';
3253 drive_root
[3] = '\0';
3254 devtype
= GetDriveType (drive_root
);
3256 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3259 /* MSVC stat function can't cope with UNC names and has other bugs, so
3260 replace it with our own. This also allows us to calculate consistent
3261 inode values without hacks in the main Emacs code. */
3263 stat (const char * path
, struct stat
* buf
)
3266 WIN32_FIND_DATA wfd
;
3268 unsigned __int64 fake_inode
;
3271 int rootdir
= FALSE
;
3272 PSECURITY_DESCRIPTOR psd
= NULL
;
3274 if (path
== NULL
|| buf
== NULL
)
3280 name
= (char *) map_w32_filename (path
, &path
);
3281 /* Must be valid filename, no wild cards or other invalid
3282 characters. We use _mbspbrk to support multibyte strings that
3283 might look to strpbrk as if they included literal *, ?, and other
3284 characters mentioned below that are disallowed by Windows
3286 if (_mbspbrk (name
, "*?|<>\""))
3292 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3293 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3294 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3299 /* Remove trailing directory separator, unless name is the root
3300 directory of a drive or UNC volume in which case ensure there
3301 is a trailing separator. */
3302 len
= strlen (name
);
3303 rootdir
= (path
>= name
+ len
- 1
3304 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3305 name
= strcpy (alloca (len
+ 2), name
);
3307 if (is_unc_volume (name
))
3309 DWORD attrs
= unc_volume_file_attributes (name
);
3314 memset (&wfd
, 0, sizeof (wfd
));
3315 wfd
.dwFileAttributes
= attrs
;
3316 wfd
.ftCreationTime
= utc_base_ft
;
3317 wfd
.ftLastAccessTime
= utc_base_ft
;
3318 wfd
.ftLastWriteTime
= utc_base_ft
;
3319 strcpy (wfd
.cFileName
, name
);
3323 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3324 strcat (name
, "\\");
3325 if (GetDriveType (name
) < 2)
3330 memset (&wfd
, 0, sizeof (wfd
));
3331 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3332 wfd
.ftCreationTime
= utc_base_ft
;
3333 wfd
.ftLastAccessTime
= utc_base_ft
;
3334 wfd
.ftLastWriteTime
= utc_base_ft
;
3335 strcpy (wfd
.cFileName
, name
);
3339 if (IS_DIRECTORY_SEP (name
[len
-1]))
3342 /* (This is hacky, but helps when doing file completions on
3343 network drives.) Optimize by using information available from
3344 active readdir if possible. */
3345 len
= strlen (dir_pathname
);
3346 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3348 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3349 && strnicmp (name
, dir_pathname
, len
) == 0
3350 && IS_DIRECTORY_SEP (name
[len
])
3351 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3353 /* This was the last entry returned by readdir. */
3354 wfd
= dir_find_data
;
3358 logon_network_drive (name
);
3360 fh
= FindFirstFile (name
, &wfd
);
3361 if (fh
== INVALID_HANDLE_VALUE
)
3370 if (!(NILP (Vw32_get_true_file_attributes
)
3371 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3372 /* No access rights required to get info. */
3373 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3374 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3375 != INVALID_HANDLE_VALUE
)
3377 /* This is more accurate in terms of gettting the correct number
3378 of links, but is quite slow (it is noticeable when Emacs is
3379 making a list of file name completions). */
3380 BY_HANDLE_FILE_INFORMATION info
;
3382 if (GetFileInformationByHandle (fh
, &info
))
3384 buf
->st_nlink
= info
.nNumberOfLinks
;
3385 /* Might as well use file index to fake inode values, but this
3386 is not guaranteed to be unique unless we keep a handle open
3387 all the time (even then there are situations where it is
3388 not unique). Reputedly, there are at most 48 bits of info
3389 (on NTFS, presumably less on FAT). */
3390 fake_inode
= info
.nFileIndexHigh
;
3392 fake_inode
+= info
.nFileIndexLow
;
3400 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3402 buf
->st_mode
= S_IFDIR
;
3406 switch (GetFileType (fh
))
3408 case FILE_TYPE_DISK
:
3409 buf
->st_mode
= S_IFREG
;
3411 case FILE_TYPE_PIPE
:
3412 buf
->st_mode
= S_IFIFO
;
3414 case FILE_TYPE_CHAR
:
3415 case FILE_TYPE_UNKNOWN
:
3417 buf
->st_mode
= S_IFCHR
;
3421 psd
= get_file_security_desc (name
);
3422 get_file_owner_and_group (psd
, name
, buf
);
3426 /* Don't bother to make this information more accurate. */
3427 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3432 get_file_owner_and_group (NULL
, name
, buf
);
3437 /* Not sure if there is any point in this. */
3438 if (!NILP (Vw32_generate_fake_inodes
))
3439 fake_inode
= generate_inode_val (name
);
3440 else if (fake_inode
== 0)
3442 /* For want of something better, try to make everything unique. */
3443 static DWORD gen_num
= 0;
3444 fake_inode
= ++gen_num
;
3448 /* MSVC defines _ino_t to be short; other libc's might not. */
3449 if (sizeof (buf
->st_ino
) == 2)
3450 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3452 buf
->st_ino
= fake_inode
;
3454 /* volume_info is set indirectly by map_w32_filename */
3455 buf
->st_dev
= volume_info
.serialnum
;
3456 buf
->st_rdev
= volume_info
.serialnum
;
3458 buf
->st_size
= wfd
.nFileSizeHigh
;
3459 buf
->st_size
<<= 32;
3460 buf
->st_size
+= wfd
.nFileSizeLow
;
3462 /* Convert timestamps to Unix format. */
3463 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3464 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3465 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3466 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3467 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3469 /* determine rwx permissions */
3470 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3471 permission
= S_IREAD
;
3473 permission
= S_IREAD
| S_IWRITE
;
3475 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3476 permission
|= S_IEXEC
;
3477 else if (is_exec (name
))
3478 permission
|= S_IEXEC
;
3480 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3485 /* Provide fstat and utime as well as stat for consistent handling of
3488 fstat (int desc
, struct stat
* buf
)
3490 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3491 BY_HANDLE_FILE_INFORMATION info
;
3492 unsigned __int64 fake_inode
;
3495 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3497 case FILE_TYPE_DISK
:
3498 buf
->st_mode
= S_IFREG
;
3499 if (!GetFileInformationByHandle (fh
, &info
))
3505 case FILE_TYPE_PIPE
:
3506 buf
->st_mode
= S_IFIFO
;
3508 case FILE_TYPE_CHAR
:
3509 case FILE_TYPE_UNKNOWN
:
3511 buf
->st_mode
= S_IFCHR
;
3513 memset (&info
, 0, sizeof (info
));
3514 info
.dwFileAttributes
= 0;
3515 info
.ftCreationTime
= utc_base_ft
;
3516 info
.ftLastAccessTime
= utc_base_ft
;
3517 info
.ftLastWriteTime
= utc_base_ft
;
3520 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3521 buf
->st_mode
= S_IFDIR
;
3523 buf
->st_nlink
= info
.nNumberOfLinks
;
3524 /* Might as well use file index to fake inode values, but this
3525 is not guaranteed to be unique unless we keep a handle open
3526 all the time (even then there are situations where it is
3527 not unique). Reputedly, there are at most 48 bits of info
3528 (on NTFS, presumably less on FAT). */
3529 fake_inode
= info
.nFileIndexHigh
;
3531 fake_inode
+= info
.nFileIndexLow
;
3533 /* MSVC defines _ino_t to be short; other libc's might not. */
3534 if (sizeof (buf
->st_ino
) == 2)
3535 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3537 buf
->st_ino
= fake_inode
;
3539 /* Consider files to belong to current user.
3540 FIXME: this should use GetSecurityInfo API, but it is only
3541 available for _WIN32_WINNT >= 0x501. */
3542 buf
->st_uid
= dflt_passwd
.pw_uid
;
3543 buf
->st_gid
= dflt_passwd
.pw_gid
;
3544 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3545 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3547 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3548 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3550 buf
->st_size
= info
.nFileSizeHigh
;
3551 buf
->st_size
<<= 32;
3552 buf
->st_size
+= info
.nFileSizeLow
;
3554 /* Convert timestamps to Unix format. */
3555 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3556 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3557 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3558 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3559 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3561 /* determine rwx permissions */
3562 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3563 permission
= S_IREAD
;
3565 permission
= S_IREAD
| S_IWRITE
;
3567 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3568 permission
|= S_IEXEC
;
3571 #if 0 /* no way of knowing the filename */
3572 char * p
= strrchr (name
, '.');
3574 (xstrcasecmp (p
, ".exe") == 0 ||
3575 xstrcasecmp (p
, ".com") == 0 ||
3576 xstrcasecmp (p
, ".bat") == 0 ||
3577 xstrcasecmp (p
, ".cmd") == 0))
3578 permission
|= S_IEXEC
;
3582 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3588 utime (const char *name
, struct utimbuf
*times
)
3590 struct utimbuf deftime
;
3597 deftime
.modtime
= deftime
.actime
= time (NULL
);
3601 /* Need write access to set times. */
3602 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3603 0, OPEN_EXISTING
, 0, NULL
);
3606 convert_from_time_t (times
->actime
, &atime
);
3607 convert_from_time_t (times
->modtime
, &mtime
);
3608 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3625 /* Symlink-related functions that always fail. Used in fileio.c and in
3626 sysdep.c to avoid #ifdef's. */
3628 symlink (char const *dummy1
, char const *dummy2
)
3635 readlink (const char *name
, char *dummy1
, size_t dummy2
)
3637 /* `access' is much faster than `stat' on MS-Windows. */
3638 if (sys_access (name
, 0) == 0)
3644 careadlinkat (int fd
, char const *filename
,
3645 char *buffer
, size_t buffer_size
,
3646 struct allocator
const *alloc
,
3647 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
3654 careadlinkatcwd (int fd
, char const *filename
, char *buffer
,
3658 return readlink (filename
, buffer
, buffer_size
);
3662 /* Support for browsing other processes and their attributes. See
3663 process.c for the Lisp bindings. */
3665 /* Helper wrapper functions. */
3667 static HANDLE WINAPI
3668 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
3670 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3672 if (g_b_init_create_toolhelp32_snapshot
== 0)
3674 g_b_init_create_toolhelp32_snapshot
= 1;
3675 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3676 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3677 "CreateToolhelp32Snapshot");
3679 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3681 return INVALID_HANDLE_VALUE
;
3683 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3687 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3689 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3691 if (g_b_init_process32_first
== 0)
3693 g_b_init_process32_first
= 1;
3694 s_pfn_Process32_First
= (Process32First_Proc
)
3695 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3698 if (s_pfn_Process32_First
== NULL
)
3702 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3706 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3708 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3710 if (g_b_init_process32_next
== 0)
3712 g_b_init_process32_next
= 1;
3713 s_pfn_Process32_Next
= (Process32Next_Proc
)
3714 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3717 if (s_pfn_Process32_Next
== NULL
)
3721 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3725 open_thread_token (HANDLE ThreadHandle
,
3726 DWORD DesiredAccess
,
3728 PHANDLE TokenHandle
)
3730 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3731 HMODULE hm_advapi32
= NULL
;
3732 if (is_windows_9x () == TRUE
)
3734 SetLastError (ERROR_NOT_SUPPORTED
);
3737 if (g_b_init_open_thread_token
== 0)
3739 g_b_init_open_thread_token
= 1;
3740 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3741 s_pfn_Open_Thread_Token
=
3742 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3744 if (s_pfn_Open_Thread_Token
== NULL
)
3746 SetLastError (ERROR_NOT_SUPPORTED
);
3750 s_pfn_Open_Thread_Token (
3759 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3761 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3762 HMODULE hm_advapi32
= NULL
;
3763 if (is_windows_9x () == TRUE
)
3767 if (g_b_init_impersonate_self
== 0)
3769 g_b_init_impersonate_self
= 1;
3770 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3771 s_pfn_Impersonate_Self
=
3772 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3774 if (s_pfn_Impersonate_Self
== NULL
)
3778 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3782 revert_to_self (void)
3784 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3785 HMODULE hm_advapi32
= NULL
;
3786 if (is_windows_9x () == TRUE
)
3790 if (g_b_init_revert_to_self
== 0)
3792 g_b_init_revert_to_self
= 1;
3793 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3794 s_pfn_Revert_To_Self
=
3795 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3797 if (s_pfn_Revert_To_Self
== NULL
)
3801 return s_pfn_Revert_To_Self ();
3805 get_process_memory_info (HANDLE h_proc
,
3806 PPROCESS_MEMORY_COUNTERS mem_counters
,
3809 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3810 HMODULE hm_psapi
= NULL
;
3811 if (is_windows_9x () == TRUE
)
3815 if (g_b_init_get_process_memory_info
== 0)
3817 g_b_init_get_process_memory_info
= 1;
3818 hm_psapi
= LoadLibrary ("Psapi.dll");
3820 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3821 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3823 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3827 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3831 get_process_working_set_size (HANDLE h_proc
,
3835 static GetProcessWorkingSetSize_Proc
3836 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3838 if (is_windows_9x () == TRUE
)
3842 if (g_b_init_get_process_working_set_size
== 0)
3844 g_b_init_get_process_working_set_size
= 1;
3845 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3846 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3847 "GetProcessWorkingSetSize");
3849 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3853 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3857 global_memory_status (MEMORYSTATUS
*buf
)
3859 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3861 if (is_windows_9x () == TRUE
)
3865 if (g_b_init_global_memory_status
== 0)
3867 g_b_init_global_memory_status
= 1;
3868 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3869 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3870 "GlobalMemoryStatus");
3872 if (s_pfn_Global_Memory_Status
== NULL
)
3876 return s_pfn_Global_Memory_Status (buf
);
3880 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
3882 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3884 if (is_windows_9x () == TRUE
)
3888 if (g_b_init_global_memory_status_ex
== 0)
3890 g_b_init_global_memory_status_ex
= 1;
3891 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3892 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3893 "GlobalMemoryStatusEx");
3895 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3899 return s_pfn_Global_Memory_Status_Ex (buf
);
3903 list_system_processes (void)
3905 struct gcpro gcpro1
;
3906 Lisp_Object proclist
= Qnil
;
3909 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3911 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3913 PROCESSENTRY32 proc_entry
;
3919 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3920 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3921 res
= process32_next (h_snapshot
, &proc_entry
))
3923 proc_id
= proc_entry
.th32ProcessID
;
3924 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3927 CloseHandle (h_snapshot
);
3929 proclist
= Fnreverse (proclist
);
3936 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3938 TOKEN_PRIVILEGES priv
;
3939 DWORD priv_size
= sizeof (priv
);
3940 DWORD opriv_size
= sizeof (*old_priv
);
3941 HANDLE h_token
= NULL
;
3942 HANDLE h_thread
= GetCurrentThread ();
3946 res
= open_thread_token (h_thread
,
3947 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3949 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3951 if (impersonate_self (SecurityImpersonation
))
3952 res
= open_thread_token (h_thread
,
3953 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3958 priv
.PrivilegeCount
= 1;
3959 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3960 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3961 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3962 old_priv
, &opriv_size
)
3963 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3967 CloseHandle (h_token
);
3973 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3975 DWORD priv_size
= sizeof (*priv
);
3976 HANDLE h_token
= NULL
;
3979 if (open_thread_token (GetCurrentThread (),
3980 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3983 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3984 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3988 CloseHandle (h_token
);
3994 ltime (long time_sec
, long time_usec
)
3996 return list3 (make_number ((time_sec
>> 16) & 0xffff),
3997 make_number (time_sec
& 0xffff),
3998 make_number (time_usec
));
4001 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
4004 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4005 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4008 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4009 ULONGLONG tem1
, tem2
, tem3
, tem
;
4012 || !get_process_times_fn
4013 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4014 &ft_kernel
, &ft_user
))
4017 GetSystemTimeAsFileTime (&ft_current
);
4019 FILETIME_TO_U64 (tem1
, ft_kernel
);
4021 *stime
= U64_TO_LISP_TIME (tem1
);
4023 FILETIME_TO_U64 (tem2
, ft_user
);
4025 *utime
= U64_TO_LISP_TIME (tem2
);
4028 *ttime
= U64_TO_LISP_TIME (tem3
);
4030 FILETIME_TO_U64 (tem
, ft_creation
);
4031 /* Process no 4 (System) returns zero creation time. */
4033 tem
= (tem
- utc_base
) / 10L;
4034 *ctime
= U64_TO_LISP_TIME (tem
);
4038 FILETIME_TO_U64 (tem3
, ft_current
);
4039 tem
= (tem3
- utc_base
) / 10L - tem
;
4041 *etime
= U64_TO_LISP_TIME (tem
);
4045 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4056 system_process_attributes (Lisp_Object pid
)
4058 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4059 Lisp_Object attrs
= Qnil
;
4060 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4061 HANDLE h_snapshot
, h_proc
;
4064 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4065 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4066 DWORD glength
= sizeof (gname
);
4067 HANDLE token
= NULL
;
4068 SID_NAME_USE user_type
;
4069 unsigned char *buf
= NULL
;
4071 TOKEN_USER user_token
;
4072 TOKEN_PRIMARY_GROUP group_token
;
4075 PROCESS_MEMORY_COUNTERS mem
;
4076 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4077 DWORD minrss
, maxrss
;
4079 MEMORY_STATUS_EX memstex
;
4080 double totphys
= 0.0;
4081 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4083 BOOL result
= FALSE
;
4085 CHECK_NUMBER_OR_FLOAT (pid
);
4086 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4088 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4090 GCPRO3 (attrs
, decoded_cmd
, tem
);
4092 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4097 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4098 for (res
= process32_first (h_snapshot
, &pe
); res
;
4099 res
= process32_next (h_snapshot
, &pe
))
4101 if (proc_id
== pe
.th32ProcessID
)
4104 decoded_cmd
= build_string ("Idle");
4107 /* Decode the command name from locale-specific
4109 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4110 strlen (pe
.szExeFile
));
4112 code_convert_string_norecord (cmd_str
,
4113 Vlocale_coding_system
, 0);
4115 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4116 attrs
= Fcons (Fcons (Qppid
,
4117 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4119 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4121 attrs
= Fcons (Fcons (Qthcount
,
4122 make_fixnum_or_float (pe
.cntThreads
)),
4129 CloseHandle (h_snapshot
);
4138 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4140 /* If we were denied a handle to the process, try again after
4141 enabling the SeDebugPrivilege in our process. */
4144 TOKEN_PRIVILEGES priv_current
;
4146 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4148 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4150 restore_privilege (&priv_current
);
4156 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4159 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4160 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4162 buf
= xmalloc (blen
);
4163 result
= get_token_information (token
, TokenUser
,
4164 (LPVOID
)buf
, blen
, &needed
);
4167 memcpy (&user_token
, buf
, sizeof (user_token
));
4168 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4170 euid
= get_rid (user_token
.User
.Sid
);
4171 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4176 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4179 strcpy (uname
, "unknown");
4183 ulength
= strlen (uname
);
4189 /* Determine a reasonable euid and gid values. */
4190 if (xstrcasecmp ("administrator", uname
) == 0)
4192 euid
= 500; /* well-known Administrator uid */
4193 egid
= 513; /* well-known None gid */
4197 /* Get group id and name. */
4198 result
= get_token_information (token
, TokenPrimaryGroup
,
4199 (LPVOID
)buf
, blen
, &needed
);
4200 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4202 buf
= xrealloc (buf
, blen
= needed
);
4203 result
= get_token_information (token
, TokenPrimaryGroup
,
4204 (LPVOID
)buf
, blen
, &needed
);
4208 memcpy (&group_token
, buf
, sizeof (group_token
));
4209 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4211 egid
= get_rid (group_token
.PrimaryGroup
);
4212 dlength
= sizeof (domain
);
4214 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4215 gname
, &glength
, NULL
, &dlength
,
4218 w32_add_to_cache (group_token
.PrimaryGroup
,
4222 strcpy (gname
, "None");
4226 glength
= strlen (gname
);
4234 if (!is_windows_9x ())
4236 /* We couldn't open the process token, presumably because of
4237 insufficient access rights. Assume this process is run
4239 strcpy (uname
, "SYSTEM");
4240 strcpy (gname
, "None");
4241 euid
= 18; /* SYSTEM */
4242 egid
= 513; /* None */
4243 glength
= strlen (gname
);
4244 ulength
= strlen (uname
);
4246 /* If we are running under Windows 9X, where security calls are
4247 not supported, we assume all processes are run by the current
4249 else if (GetUserName (uname
, &ulength
))
4251 if (xstrcasecmp ("administrator", uname
) == 0)
4256 strcpy (gname
, "None");
4257 glength
= strlen (gname
);
4258 ulength
= strlen (uname
);
4264 strcpy (uname
, "administrator");
4265 ulength
= strlen (uname
);
4266 strcpy (gname
, "None");
4267 glength
= strlen (gname
);
4270 CloseHandle (token
);
4273 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4274 tem
= make_unibyte_string (uname
, ulength
);
4275 attrs
= Fcons (Fcons (Quser
,
4276 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4278 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4279 tem
= make_unibyte_string (gname
, glength
);
4280 attrs
= Fcons (Fcons (Qgroup
,
4281 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4284 if (global_memory_status_ex (&memstex
))
4285 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4286 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4288 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4289 double, so we need to do this for it... */
4291 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4292 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4293 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4295 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4297 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4298 else if (global_memory_status (&memst
))
4299 totphys
= memst
.dwTotalPhys
/ 1024.0;
4302 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4305 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4307 attrs
= Fcons (Fcons (Qmajflt
,
4308 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4310 attrs
= Fcons (Fcons (Qvsize
,
4311 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4313 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4315 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4318 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4320 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4322 attrs
= Fcons (Fcons (Qmajflt
,
4323 make_fixnum_or_float (mem
.PageFaultCount
)),
4325 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4327 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4330 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4332 DWORD rss
= maxrss
/ 1024;
4334 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4336 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4339 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4341 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4342 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4343 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4344 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4345 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4346 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4349 /* FIXME: Retrieve command line by walking the PEB of the process. */
4352 CloseHandle (h_proc
);
4358 /* Wrappers for winsock functions to map between our file descriptors
4359 and winsock's handles; also set h_errno for convenience.
4361 To allow Emacs to run on systems which don't have winsock support
4362 installed, we dynamically link to winsock on startup if present, and
4363 otherwise provide the minimum necessary functionality
4364 (eg. gethostname). */
4366 /* function pointers for relevant socket functions */
4367 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4368 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4369 int (PASCAL
*pfn_WSAGetLastError
) (void);
4370 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4371 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4372 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4373 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4374 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4375 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4376 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4377 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4378 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4379 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4380 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4381 int (PASCAL
*pfn_WSACleanup
) (void);
4383 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4384 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4385 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4386 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4387 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4388 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4389 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4390 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4391 const char * optval
, int optlen
);
4392 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4393 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4395 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4396 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4397 struct sockaddr
* from
, int * fromlen
);
4398 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4399 const struct sockaddr
* to
, int tolen
);
4401 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4402 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4403 #ifndef HANDLE_FLAG_INHERIT
4404 #define HANDLE_FLAG_INHERIT 1
4408 static int winsock_inuse
;
4413 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4415 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4416 after WSAStartup returns successfully, but it seems reasonable
4417 to allow unloading winsock anyway in that case. */
4418 if (pfn_WSACleanup () == 0 ||
4419 pfn_WSAGetLastError () == WSAENETDOWN
)
4421 if (FreeLibrary (winsock_lib
))
4430 init_winsock (int load_now
)
4432 WSADATA winsockData
;
4434 if (winsock_lib
!= NULL
)
4437 pfn_SetHandleInformation
4438 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4439 "SetHandleInformation");
4441 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4443 if (winsock_lib
!= NULL
)
4445 /* dynamically link to socket functions */
4447 #define LOAD_PROC(fn) \
4448 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4451 LOAD_PROC (WSAStartup
);
4452 LOAD_PROC (WSASetLastError
);
4453 LOAD_PROC (WSAGetLastError
);
4454 LOAD_PROC (WSAEventSelect
);
4455 LOAD_PROC (WSACreateEvent
);
4456 LOAD_PROC (WSACloseEvent
);
4459 LOAD_PROC (connect
);
4460 LOAD_PROC (ioctlsocket
);
4463 LOAD_PROC (closesocket
);
4464 LOAD_PROC (shutdown
);
4467 LOAD_PROC (inet_addr
);
4468 LOAD_PROC (gethostname
);
4469 LOAD_PROC (gethostbyname
);
4470 LOAD_PROC (getservbyname
);
4471 LOAD_PROC (getpeername
);
4472 LOAD_PROC (WSACleanup
);
4473 LOAD_PROC (setsockopt
);
4475 LOAD_PROC (getsockname
);
4477 LOAD_PROC (recvfrom
);
4481 /* specify version 1.1 of winsock */
4482 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4484 if (winsockData
.wVersion
!= 0x101)
4489 /* Report that winsock exists and is usable, but leave
4490 socket functions disabled. I am assuming that calling
4491 WSAStartup does not require any network interaction,
4492 and in particular does not cause or require a dial-up
4493 connection to be established. */
4496 FreeLibrary (winsock_lib
);
4504 FreeLibrary (winsock_lib
);
4514 /* function to set h_errno for compatibility; map winsock error codes to
4515 normal system codes where they overlap (non-overlapping definitions
4516 are already in <sys/socket.h> */
4520 if (winsock_lib
== NULL
)
4523 h_errno
= pfn_WSAGetLastError ();
4527 case WSAEACCES
: h_errno
= EACCES
; break;
4528 case WSAEBADF
: h_errno
= EBADF
; break;
4529 case WSAEFAULT
: h_errno
= EFAULT
; break;
4530 case WSAEINTR
: h_errno
= EINTR
; break;
4531 case WSAEINVAL
: h_errno
= EINVAL
; break;
4532 case WSAEMFILE
: h_errno
= EMFILE
; break;
4533 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4534 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4542 if (h_errno
== 0 && winsock_lib
!= NULL
)
4543 pfn_WSASetLastError (0);
4546 /* Extend strerror to handle the winsock-specific error codes. */
4550 } _wsa_errlist
[] = {
4551 {WSAEINTR
, "Interrupted function call"},
4552 {WSAEBADF
, "Bad file descriptor"},
4553 {WSAEACCES
, "Permission denied"},
4554 {WSAEFAULT
, "Bad address"},
4555 {WSAEINVAL
, "Invalid argument"},
4556 {WSAEMFILE
, "Too many open files"},
4558 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
4559 {WSAEINPROGRESS
, "Operation now in progress"},
4560 {WSAEALREADY
, "Operation already in progress"},
4561 {WSAENOTSOCK
, "Socket operation on non-socket"},
4562 {WSAEDESTADDRREQ
, "Destination address required"},
4563 {WSAEMSGSIZE
, "Message too long"},
4564 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
4565 {WSAENOPROTOOPT
, "Bad protocol option"},
4566 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
4567 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
4568 {WSAEOPNOTSUPP
, "Operation not supported"},
4569 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
4570 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
4571 {WSAEADDRINUSE
, "Address already in use"},
4572 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
4573 {WSAENETDOWN
, "Network is down"},
4574 {WSAENETUNREACH
, "Network is unreachable"},
4575 {WSAENETRESET
, "Network dropped connection on reset"},
4576 {WSAECONNABORTED
, "Software caused connection abort"},
4577 {WSAECONNRESET
, "Connection reset by peer"},
4578 {WSAENOBUFS
, "No buffer space available"},
4579 {WSAEISCONN
, "Socket is already connected"},
4580 {WSAENOTCONN
, "Socket is not connected"},
4581 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
4582 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
4583 {WSAETIMEDOUT
, "Connection timed out"},
4584 {WSAECONNREFUSED
, "Connection refused"},
4585 {WSAELOOP
, "Network loop"}, /* not sure */
4586 {WSAENAMETOOLONG
, "Name is too long"},
4587 {WSAEHOSTDOWN
, "Host is down"},
4588 {WSAEHOSTUNREACH
, "No route to host"},
4589 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
4590 {WSAEPROCLIM
, "Too many processes"},
4591 {WSAEUSERS
, "Too many users"}, /* not sure */
4592 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
4593 {WSAESTALE
, "Data is stale"}, /* not sure */
4594 {WSAEREMOTE
, "Remote error"}, /* not sure */
4596 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
4597 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
4598 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
4599 {WSAEDISCON
, "Graceful shutdown in progress"},
4601 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
4602 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
4603 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
4604 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
4605 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
4606 {WSASYSCALLFAILURE
, "System call failure"},
4607 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
4608 {WSATYPE_NOT_FOUND
, "Class type not found"},
4609 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
4610 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
4611 {WSAEREFUSED
, "Operation refused"}, /* not sure */
4614 {WSAHOST_NOT_FOUND
, "Host not found"},
4615 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
4616 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
4617 {WSANO_DATA
, "Valid name, no data record of requested type"},
4623 sys_strerror (int error_no
)
4626 static char unknown_msg
[40];
4628 if (error_no
>= 0 && error_no
< sys_nerr
)
4629 return sys_errlist
[error_no
];
4631 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4632 if (_wsa_errlist
[i
].errnum
== error_no
)
4633 return _wsa_errlist
[i
].msg
;
4635 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4639 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4640 but I believe the method of keeping the socket handle separate (and
4641 insuring it is not inheritable) is the correct one. */
4643 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4645 static int socket_to_fd (SOCKET s
);
4648 sys_socket (int af
, int type
, int protocol
)
4652 if (winsock_lib
== NULL
)
4655 return INVALID_SOCKET
;
4660 /* call the real socket function */
4661 s
= pfn_socket (af
, type
, protocol
);
4663 if (s
!= INVALID_SOCKET
)
4664 return socket_to_fd (s
);
4670 /* Convert a SOCKET to a file descriptor. */
4672 socket_to_fd (SOCKET s
)
4677 /* Although under NT 3.5 _open_osfhandle will accept a socket
4678 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4679 that does not work under NT 3.1. However, we can get the same
4680 effect by using a backdoor function to replace an existing
4681 descriptor handle with the one we want. */
4683 /* allocate a file descriptor (with appropriate flags) */
4684 fd
= _open ("NUL:", _O_RDWR
);
4687 /* Make a non-inheritable copy of the socket handle. Note
4688 that it is possible that sockets aren't actually kernel
4689 handles, which appears to be the case on Windows 9x when
4690 the MS Proxy winsock client is installed. */
4692 /* Apparently there is a bug in NT 3.51 with some service
4693 packs, which prevents using DuplicateHandle to make a
4694 socket handle non-inheritable (causes WSACleanup to
4695 hang). The work-around is to use SetHandleInformation
4696 instead if it is available and implemented. */
4697 if (pfn_SetHandleInformation
)
4699 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4703 HANDLE parent
= GetCurrentProcess ();
4704 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4706 if (DuplicateHandle (parent
,
4712 DUPLICATE_SAME_ACCESS
))
4714 /* It is possible that DuplicateHandle succeeds even
4715 though the socket wasn't really a kernel handle,
4716 because a real handle has the same value. So
4717 test whether the new handle really is a socket. */
4718 long nonblocking
= 0;
4719 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4721 pfn_closesocket (s
);
4726 CloseHandle (new_s
);
4731 fd_info
[fd
].hnd
= (HANDLE
) s
;
4733 /* set our own internal flags */
4734 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4740 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4742 /* attach child_process to fd_info */
4743 if (fd_info
[ fd
].cp
!= NULL
)
4745 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4749 fd_info
[ fd
].cp
= cp
;
4752 winsock_inuse
++; /* count open sockets */
4759 pfn_closesocket (s
);
4765 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4767 if (winsock_lib
== NULL
)
4770 return SOCKET_ERROR
;
4774 if (fd_info
[s
].flags
& FILE_SOCKET
)
4776 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4777 if (rc
== SOCKET_ERROR
)
4782 return SOCKET_ERROR
;
4786 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4788 if (winsock_lib
== NULL
)
4791 return SOCKET_ERROR
;
4795 if (fd_info
[s
].flags
& FILE_SOCKET
)
4797 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4798 if (rc
== SOCKET_ERROR
)
4803 return SOCKET_ERROR
;
4807 sys_htons (u_short hostshort
)
4809 return (winsock_lib
!= NULL
) ?
4810 pfn_htons (hostshort
) : hostshort
;
4814 sys_ntohs (u_short netshort
)
4816 return (winsock_lib
!= NULL
) ?
4817 pfn_ntohs (netshort
) : netshort
;
4821 sys_inet_addr (const char * cp
)
4823 return (winsock_lib
!= NULL
) ?
4824 pfn_inet_addr (cp
) : INADDR_NONE
;
4828 sys_gethostname (char * name
, int namelen
)
4830 if (winsock_lib
!= NULL
)
4831 return pfn_gethostname (name
, namelen
);
4833 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4834 return !GetComputerName (name
, (DWORD
*)&namelen
);
4837 return SOCKET_ERROR
;
4841 sys_gethostbyname (const char * name
)
4843 struct hostent
* host
;
4845 if (winsock_lib
== NULL
)
4852 host
= pfn_gethostbyname (name
);
4859 sys_getservbyname (const char * name
, const char * proto
)
4861 struct servent
* serv
;
4863 if (winsock_lib
== NULL
)
4870 serv
= pfn_getservbyname (name
, proto
);
4877 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4879 if (winsock_lib
== NULL
)
4882 return SOCKET_ERROR
;
4886 if (fd_info
[s
].flags
& FILE_SOCKET
)
4888 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4889 if (rc
== SOCKET_ERROR
)
4894 return SOCKET_ERROR
;
4898 sys_shutdown (int s
, int how
)
4900 if (winsock_lib
== NULL
)
4903 return SOCKET_ERROR
;
4907 if (fd_info
[s
].flags
& FILE_SOCKET
)
4909 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4910 if (rc
== SOCKET_ERROR
)
4915 return SOCKET_ERROR
;
4919 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4921 if (winsock_lib
== NULL
)
4924 return SOCKET_ERROR
;
4928 if (fd_info
[s
].flags
& FILE_SOCKET
)
4930 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4931 (const char *)optval
, optlen
);
4932 if (rc
== SOCKET_ERROR
)
4937 return SOCKET_ERROR
;
4941 sys_listen (int s
, int backlog
)
4943 if (winsock_lib
== NULL
)
4946 return SOCKET_ERROR
;
4950 if (fd_info
[s
].flags
& FILE_SOCKET
)
4952 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4953 if (rc
== SOCKET_ERROR
)
4956 fd_info
[s
].flags
|= FILE_LISTEN
;
4960 return SOCKET_ERROR
;
4964 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4966 if (winsock_lib
== NULL
)
4969 return SOCKET_ERROR
;
4973 if (fd_info
[s
].flags
& FILE_SOCKET
)
4975 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4976 if (rc
== SOCKET_ERROR
)
4981 return SOCKET_ERROR
;
4985 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
4987 if (winsock_lib
== NULL
)
4994 if (fd_info
[s
].flags
& FILE_LISTEN
)
4996 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
4998 if (t
== INVALID_SOCKET
)
5001 fd
= socket_to_fd (t
);
5003 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5004 ResetEvent (fd_info
[s
].cp
->char_avail
);
5012 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5013 struct sockaddr
* from
, int * fromlen
)
5015 if (winsock_lib
== NULL
)
5018 return SOCKET_ERROR
;
5022 if (fd_info
[s
].flags
& FILE_SOCKET
)
5024 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5025 if (rc
== SOCKET_ERROR
)
5030 return SOCKET_ERROR
;
5034 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5035 const struct sockaddr
* to
, int tolen
)
5037 if (winsock_lib
== NULL
)
5040 return SOCKET_ERROR
;
5044 if (fd_info
[s
].flags
& FILE_SOCKET
)
5046 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5047 if (rc
== SOCKET_ERROR
)
5052 return SOCKET_ERROR
;
5055 /* Windows does not have an fcntl function. Provide an implementation
5056 solely for making sockets non-blocking. */
5058 fcntl (int s
, int cmd
, int options
)
5060 if (winsock_lib
== NULL
)
5067 if (fd_info
[s
].flags
& FILE_SOCKET
)
5069 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5071 unsigned long nblock
= 1;
5072 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5073 if (rc
== SOCKET_ERROR
)
5075 /* Keep track of the fact that we set this to non-blocking. */
5076 fd_info
[s
].flags
|= FILE_NDELAY
;
5082 return SOCKET_ERROR
;
5086 return SOCKET_ERROR
;
5090 /* Shadow main io functions: we need to handle pipes and sockets more
5091 intelligently, and implement non-blocking mode as well. */
5104 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5106 child_process
* cp
= fd_info
[fd
].cp
;
5108 fd_info
[fd
].cp
= NULL
;
5110 if (CHILD_ACTIVE (cp
))
5112 /* if last descriptor to active child_process then cleanup */
5114 for (i
= 0; i
< MAXDESC
; i
++)
5118 if (fd_info
[i
].cp
== cp
)
5123 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5125 if (winsock_lib
== NULL
) abort ();
5127 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5128 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5130 winsock_inuse
--; /* count open sockets */
5137 /* Note that sockets do not need special treatment here (at least on
5138 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5139 closesocket is equivalent to CloseHandle, which is to be expected
5140 because socket handles are fully fledged kernel handles. */
5143 if (rc
== 0 && fd
< MAXDESC
)
5144 fd_info
[fd
].flags
= 0;
5155 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5157 /* duplicate our internal info as well */
5158 fd_info
[new_fd
] = fd_info
[fd
];
5164 sys_dup2 (int src
, int dst
)
5168 if (dst
< 0 || dst
>= MAXDESC
)
5174 /* make sure we close the destination first if it's a pipe or socket */
5175 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5178 rc
= _dup2 (src
, dst
);
5181 /* duplicate our internal info as well */
5182 fd_info
[dst
] = fd_info
[src
];
5187 /* Unix pipe() has only one arg */
5189 sys_pipe (int * phandles
)
5194 /* make pipe handles non-inheritable; when we spawn a child, we
5195 replace the relevant handle with an inheritable one. Also put
5196 pipes into binary mode; we will do text mode translation ourselves
5198 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5202 /* Protect against overflow, since Windows can open more handles than
5203 our fd_info array has room for. */
5204 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5206 _close (phandles
[0]);
5207 _close (phandles
[1]);
5212 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5213 fd_info
[phandles
[0]].flags
= flags
;
5215 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5216 fd_info
[phandles
[1]].flags
= flags
;
5223 /* Function to do blocking read of one byte, needed to implement
5224 select. It is only allowed on sockets and pipes. */
5226 _sys_read_ahead (int fd
)
5231 if (fd
< 0 || fd
>= MAXDESC
)
5232 return STATUS_READ_ERROR
;
5234 cp
= fd_info
[fd
].cp
;
5236 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5237 return STATUS_READ_ERROR
;
5239 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5240 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5242 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5246 cp
->status
= STATUS_READ_IN_PROGRESS
;
5248 if (fd_info
[fd
].flags
& FILE_PIPE
)
5250 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5252 /* Give subprocess time to buffer some more output for us before
5253 reporting that input is available; we need this because Windows 95
5254 connects DOS programs to pipes by making the pipe appear to be
5255 the normal console stdout - as a result most DOS programs will
5256 write to stdout without buffering, ie. one character at a
5257 time. Even some W32 programs do this - "dir" in a command
5258 shell on NT is very slow if we don't do this. */
5261 int wait
= w32_pipe_read_delay
;
5267 /* Yield remainder of our time slice, effectively giving a
5268 temporary priority boost to the child process. */
5272 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5274 HANDLE hnd
= fd_info
[fd
].hnd
;
5275 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5278 /* Configure timeouts for blocking read. */
5279 if (!GetCommTimeouts (hnd
, &ct
))
5280 return STATUS_READ_ERROR
;
5281 ct
.ReadIntervalTimeout
= 0;
5282 ct
.ReadTotalTimeoutMultiplier
= 0;
5283 ct
.ReadTotalTimeoutConstant
= 0;
5284 if (!SetCommTimeouts (hnd
, &ct
))
5285 return STATUS_READ_ERROR
;
5287 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5289 if (GetLastError () != ERROR_IO_PENDING
)
5290 return STATUS_READ_ERROR
;
5291 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5292 return STATUS_READ_ERROR
;
5295 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5297 unsigned long nblock
= 0;
5298 /* We always want this to block, so temporarily disable NDELAY. */
5299 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5300 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5302 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5304 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5307 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5311 if (rc
== sizeof (char))
5312 cp
->status
= STATUS_READ_SUCCEEDED
;
5314 cp
->status
= STATUS_READ_FAILED
;
5320 _sys_wait_accept (int fd
)
5326 if (fd
< 0 || fd
>= MAXDESC
)
5327 return STATUS_READ_ERROR
;
5329 cp
= fd_info
[fd
].cp
;
5331 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5332 return STATUS_READ_ERROR
;
5334 cp
->status
= STATUS_READ_FAILED
;
5336 hEv
= pfn_WSACreateEvent ();
5337 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5338 if (rc
!= SOCKET_ERROR
)
5340 rc
= WaitForSingleObject (hEv
, INFINITE
);
5341 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5342 if (rc
== WAIT_OBJECT_0
)
5343 cp
->status
= STATUS_READ_SUCCEEDED
;
5345 pfn_WSACloseEvent (hEv
);
5351 sys_read (int fd
, char * buffer
, unsigned int count
)
5356 char * orig_buffer
= buffer
;
5364 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5366 child_process
*cp
= fd_info
[fd
].cp
;
5368 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5376 /* re-read CR carried over from last read */
5377 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5379 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5383 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5386 /* presence of a child_process structure means we are operating in
5387 non-blocking mode - otherwise we just call _read directly.
5388 Note that the child_process structure might be missing because
5389 reap_subprocess has been called; in this case the pipe is
5390 already broken, so calling _read on it is okay. */
5393 int current_status
= cp
->status
;
5395 switch (current_status
)
5397 case STATUS_READ_FAILED
:
5398 case STATUS_READ_ERROR
:
5399 /* report normal EOF if nothing in buffer */
5401 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5404 case STATUS_READ_READY
:
5405 case STATUS_READ_IN_PROGRESS
:
5406 DebPrint (("sys_read called when read is in progress\n"));
5407 errno
= EWOULDBLOCK
;
5410 case STATUS_READ_SUCCEEDED
:
5411 /* consume read-ahead char */
5412 *buffer
++ = cp
->chr
;
5415 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5416 ResetEvent (cp
->char_avail
);
5418 case STATUS_READ_ACKNOWLEDGED
:
5422 DebPrint (("sys_read: bad status %d\n", current_status
));
5427 if (fd_info
[fd
].flags
& FILE_PIPE
)
5429 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5430 to_read
= min (waiting
, (DWORD
) count
);
5433 nchars
+= _read (fd
, buffer
, to_read
);
5435 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5437 HANDLE hnd
= fd_info
[fd
].hnd
;
5438 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5444 /* Configure timeouts for non-blocking read. */
5445 if (!GetCommTimeouts (hnd
, &ct
))
5450 ct
.ReadIntervalTimeout
= MAXDWORD
;
5451 ct
.ReadTotalTimeoutMultiplier
= 0;
5452 ct
.ReadTotalTimeoutConstant
= 0;
5453 if (!SetCommTimeouts (hnd
, &ct
))
5459 if (!ResetEvent (ovl
->hEvent
))
5464 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5466 if (GetLastError () != ERROR_IO_PENDING
)
5471 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5480 else /* FILE_SOCKET */
5482 if (winsock_lib
== NULL
) abort ();
5484 /* do the equivalent of a non-blocking read */
5485 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5486 if (waiting
== 0 && nchars
== 0)
5488 h_errno
= errno
= EWOULDBLOCK
;
5494 /* always use binary mode for sockets */
5495 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5496 if (res
== SOCKET_ERROR
)
5498 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5499 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5509 int nread
= _read (fd
, buffer
, count
);
5512 else if (nchars
== 0)
5517 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5518 /* Perform text mode translation if required. */
5519 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5521 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5522 /* If buffer contains only CR, return that. To be absolutely
5523 sure we should attempt to read the next char, but in
5524 practice a CR to be followed by LF would not appear by
5525 itself in the buffer. */
5526 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5528 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5534 nchars
= _read (fd
, buffer
, count
);
5539 /* From w32xfns.c */
5540 extern HANDLE interrupt_handle
;
5542 /* For now, don't bother with a non-blocking mode */
5544 sys_write (int fd
, const void * buffer
, unsigned int count
)
5554 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5556 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5562 /* Perform text mode translation if required. */
5563 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5565 char * tmpbuf
= alloca (count
* 2);
5566 unsigned char * src
= (void *)buffer
;
5567 unsigned char * dst
= tmpbuf
;
5572 unsigned char *next
;
5573 /* copy next line or remaining bytes */
5574 next
= _memccpy (dst
, src
, '\n', nbytes
);
5577 /* copied one line ending with '\n' */
5578 int copied
= next
- dst
;
5581 /* insert '\r' before '\n' */
5588 /* copied remaining partial line -> now finished */
5595 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5597 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5598 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5599 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5602 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5604 if (GetLastError () != ERROR_IO_PENDING
)
5609 if (detect_input_pending ())
5610 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5613 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5614 if (active
== WAIT_OBJECT_0
)
5615 { /* User pressed C-g, cancel write, then leave. Don't bother
5616 cleaning up as we may only get stuck in buggy drivers. */
5617 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5622 if (active
== WAIT_OBJECT_0
+ 1
5623 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5630 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5632 unsigned long nblock
= 0;
5633 if (winsock_lib
== NULL
) abort ();
5635 /* TODO: implement select() properly so non-blocking I/O works. */
5636 /* For now, make sure the write blocks. */
5637 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5638 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5640 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5642 /* Set the socket back to non-blocking if it was before,
5643 for other operations that support it. */
5644 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5647 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5650 if (nchars
== SOCKET_ERROR
)
5652 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5653 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5659 /* Some networked filesystems don't like too large writes, so
5660 break them into smaller chunks. See the Comments section of
5661 the MSDN documentation of WriteFile for details behind the
5662 choice of the value of CHUNK below. See also the thread
5663 http://thread.gmane.org/gmane.comp.version-control.git/145294
5664 in the git mailing list. */
5665 const unsigned char *p
= buffer
;
5666 const unsigned chunk
= 30 * 1024 * 1024;
5671 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5672 int n
= _write (fd
, p
, this_chunk
);
5680 else if (n
< this_chunk
)
5690 /* The Windows CRT functions are "optimized for speed", so they don't
5691 check for timezone and DST changes if they were last called less
5692 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
5693 all Emacs features that repeatedly call time functions (e.g.,
5694 display-time) are in real danger of missing timezone and DST
5695 changes. Calling tzset before each localtime call fixes that. */
5697 sys_localtime (const time_t *t
)
5700 return localtime (t
);
5704 check_windows_init_file (void)
5706 /* A common indication that Emacs is not installed properly is when
5707 it cannot find the Windows installation file. If this file does
5708 not exist in the expected place, tell the user. */
5710 if (!noninteractive
&& !inhibit_window_system
)
5712 Lisp_Object objs
[2];
5713 Lisp_Object full_load_path
;
5714 Lisp_Object init_file
;
5717 objs
[0] = Vload_path
;
5718 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5719 full_load_path
= Fappend (2, objs
);
5720 init_file
= build_string ("term/w32-win");
5721 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5724 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5725 char *init_file_name
= SDATA (init_file
);
5726 char *load_path
= SDATA (load_path_print
);
5727 char *buffer
= alloca (1024
5728 + strlen (init_file_name
)
5729 + strlen (load_path
));
5732 "The Emacs Windows initialization file \"%s.el\" "
5733 "could not be found in your Emacs installation. "
5734 "Emacs checked the following directories for this file:\n"
5736 "When Emacs cannot find this file, it usually means that it "
5737 "was not installed properly, or its distribution file was "
5738 "not unpacked properly.\nSee the README.W32 file in the "
5739 "top-level Emacs directory for more information.",
5740 init_file_name
, load_path
);
5743 "Emacs Abort Dialog",
5744 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5745 /* Use the low-level Emacs abort. */
5759 /* shutdown the socket interface if necessary */
5768 /* Initialise the socket interface now if available and requested by
5769 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5770 delayed until open-network-stream is called (w32-has-winsock can
5771 also be used to dynamically load or reload winsock).
5773 Conveniently, init_environment is called before us, so
5774 PRELOAD_WINSOCK can be set in the registry. */
5776 /* Always initialize this correctly. */
5779 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5780 init_winsock (TRUE
);
5782 /* Initial preparation for subprocess support: replace our standard
5783 handles with non-inheritable versions. */
5786 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5787 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5788 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5790 parent
= GetCurrentProcess ();
5792 /* ignore errors when duplicating and closing; typically the
5793 handles will be invalid when running as a gui program. */
5794 DuplicateHandle (parent
,
5795 GetStdHandle (STD_INPUT_HANDLE
),
5800 DUPLICATE_SAME_ACCESS
);
5802 DuplicateHandle (parent
,
5803 GetStdHandle (STD_OUTPUT_HANDLE
),
5808 DUPLICATE_SAME_ACCESS
);
5810 DuplicateHandle (parent
,
5811 GetStdHandle (STD_ERROR_HANDLE
),
5816 DUPLICATE_SAME_ACCESS
);
5822 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5823 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5825 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5828 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5829 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5831 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5834 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5835 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5837 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5841 /* unfortunately, atexit depends on implementation of malloc */
5842 /* atexit (term_ntproc); */
5843 signal (SIGABRT
, term_ntproc
);
5845 /* determine which drives are fixed, for GetCachedVolumeInformation */
5847 /* GetDriveType must have trailing backslash. */
5848 char drive
[] = "A:\\";
5850 /* Loop over all possible drive letters */
5851 while (*drive
<= 'Z')
5853 /* Record if this drive letter refers to a fixed drive. */
5854 fixed_drives
[DRIVE_INDEX (*drive
)] =
5855 (GetDriveType (drive
) == DRIVE_FIXED
);
5860 /* Reset the volume info cache. */
5861 volume_cache
= NULL
;
5864 /* Check to see if Emacs has been installed correctly. */
5865 check_windows_init_file ();
5869 shutdown_handler ensures that buffers' autosave files are
5870 up to date when the user logs off, or the system shuts down.
5873 shutdown_handler (DWORD type
)
5875 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5876 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5877 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5878 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5880 /* Shut down cleanly, making sure autosave files are up to date. */
5881 shut_down_emacs (0, 0, Qnil
);
5884 /* Allow other handlers to handle this signal. */
5889 globals_of_w32 is used to initialize those global variables that
5890 must always be initialized on startup even when the global variable
5891 initialized is non zero (see the function main in emacs.c).
5894 globals_of_w32 (void)
5896 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5898 get_process_times_fn
= (GetProcessTimes_Proc
)
5899 GetProcAddress (kernel32
, "GetProcessTimes");
5901 g_b_init_is_windows_9x
= 0;
5902 g_b_init_open_process_token
= 0;
5903 g_b_init_get_token_information
= 0;
5904 g_b_init_lookup_account_sid
= 0;
5905 g_b_init_get_sid_sub_authority
= 0;
5906 g_b_init_get_sid_sub_authority_count
= 0;
5907 g_b_init_get_file_security
= 0;
5908 g_b_init_get_security_descriptor_owner
= 0;
5909 g_b_init_get_security_descriptor_group
= 0;
5910 g_b_init_is_valid_sid
= 0;
5911 g_b_init_create_toolhelp32_snapshot
= 0;
5912 g_b_init_process32_first
= 0;
5913 g_b_init_process32_next
= 0;
5914 g_b_init_open_thread_token
= 0;
5915 g_b_init_impersonate_self
= 0;
5916 g_b_init_revert_to_self
= 0;
5917 g_b_init_get_process_memory_info
= 0;
5918 g_b_init_get_process_working_set_size
= 0;
5919 g_b_init_global_memory_status
= 0;
5920 g_b_init_global_memory_status_ex
= 0;
5921 g_b_init_equal_sid
= 0;
5922 g_b_init_copy_sid
= 0;
5923 g_b_init_get_length_sid
= 0;
5924 g_b_init_get_native_system_info
= 0;
5925 g_b_init_get_system_times
= 0;
5926 num_of_processors
= 0;
5927 /* The following sets a handler for shutdown notifications for
5928 console apps. This actually applies to Emacs in both console and
5929 GUI modes, since we had to fool windows into thinking emacs is a
5930 console application to get console mode to work. */
5931 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
5933 /* "None" is the default group name on standalone workstations. */
5934 strcpy (dflt_group_name
, "None");
5937 /* For make-serial-process */
5939 serial_open (char *port
)
5945 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5946 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5947 if (hnd
== INVALID_HANDLE_VALUE
)
5948 error ("Could not open %s", port
);
5949 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5951 error ("Could not open %s", port
);
5955 error ("Could not create child process");
5957 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5958 fd_info
[ fd
].hnd
= hnd
;
5959 fd_info
[ fd
].flags
|=
5960 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5961 if (fd_info
[ fd
].cp
!= NULL
)
5963 error ("fd_info[fd = %d] is already in use", fd
);
5965 fd_info
[ fd
].cp
= cp
;
5966 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5967 if (cp
->ovl_read
.hEvent
== NULL
)
5968 error ("Could not create read event");
5969 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5970 if (cp
->ovl_write
.hEvent
== NULL
)
5971 error ("Could not create write event");
5976 /* For serial-process-configure */
5978 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
5980 Lisp_Object childp2
= Qnil
;
5981 Lisp_Object tem
= Qnil
;
5985 char summary
[4] = "???"; /* This usually becomes "8N1". */
5987 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
5988 error ("Not a serial process");
5989 hnd
= fd_info
[ p
->outfd
].hnd
;
5991 childp2
= Fcopy_sequence (p
->childp
);
5993 /* Initialize timeouts for blocking read and blocking write. */
5994 if (!GetCommTimeouts (hnd
, &ct
))
5995 error ("GetCommTimeouts() failed");
5996 ct
.ReadIntervalTimeout
= 0;
5997 ct
.ReadTotalTimeoutMultiplier
= 0;
5998 ct
.ReadTotalTimeoutConstant
= 0;
5999 ct
.WriteTotalTimeoutMultiplier
= 0;
6000 ct
.WriteTotalTimeoutConstant
= 0;
6001 if (!SetCommTimeouts (hnd
, &ct
))
6002 error ("SetCommTimeouts() failed");
6003 /* Read port attributes and prepare default configuration. */
6004 memset (&dcb
, 0, sizeof (dcb
));
6005 dcb
.DCBlength
= sizeof (DCB
);
6006 if (!GetCommState (hnd
, &dcb
))
6007 error ("GetCommState() failed");
6010 dcb
.fAbortOnError
= FALSE
;
6011 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6016 /* Configure speed. */
6017 if (!NILP (Fplist_member (contact
, QCspeed
)))
6018 tem
= Fplist_get (contact
, QCspeed
);
6020 tem
= Fplist_get (p
->childp
, QCspeed
);
6022 dcb
.BaudRate
= XINT (tem
);
6023 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6025 /* Configure bytesize. */
6026 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6027 tem
= Fplist_get (contact
, QCbytesize
);
6029 tem
= Fplist_get (p
->childp
, QCbytesize
);
6031 tem
= make_number (8);
6033 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6034 error (":bytesize must be nil (8), 7, or 8");
6035 dcb
.ByteSize
= XINT (tem
);
6036 summary
[0] = XINT (tem
) + '0';
6037 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6039 /* Configure parity. */
6040 if (!NILP (Fplist_member (contact
, QCparity
)))
6041 tem
= Fplist_get (contact
, QCparity
);
6043 tem
= Fplist_get (p
->childp
, QCparity
);
6044 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6045 error (":parity must be nil (no parity), `even', or `odd'");
6046 dcb
.fParity
= FALSE
;
6047 dcb
.Parity
= NOPARITY
;
6048 dcb
.fErrorChar
= FALSE
;
6053 else if (EQ (tem
, Qeven
))
6057 dcb
.Parity
= EVENPARITY
;
6058 dcb
.fErrorChar
= TRUE
;
6060 else if (EQ (tem
, Qodd
))
6064 dcb
.Parity
= ODDPARITY
;
6065 dcb
.fErrorChar
= TRUE
;
6067 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6069 /* Configure stopbits. */
6070 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6071 tem
= Fplist_get (contact
, QCstopbits
);
6073 tem
= Fplist_get (p
->childp
, QCstopbits
);
6075 tem
= make_number (1);
6077 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6078 error (":stopbits must be nil (1 stopbit), 1, or 2");
6079 summary
[2] = XINT (tem
) + '0';
6080 if (XINT (tem
) == 1)
6081 dcb
.StopBits
= ONESTOPBIT
;
6082 else if (XINT (tem
) == 2)
6083 dcb
.StopBits
= TWOSTOPBITS
;
6084 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6086 /* Configure flowcontrol. */
6087 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6088 tem
= Fplist_get (contact
, QCflowcontrol
);
6090 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6091 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6092 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6093 dcb
.fOutxCtsFlow
= FALSE
;
6094 dcb
.fOutxDsrFlow
= FALSE
;
6095 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6096 dcb
.fDsrSensitivity
= FALSE
;
6097 dcb
.fTXContinueOnXoff
= FALSE
;
6100 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6101 dcb
.XonChar
= 17; /* Control-Q */
6102 dcb
.XoffChar
= 19; /* Control-S */
6105 /* Already configured. */
6107 else if (EQ (tem
, Qhw
))
6109 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6110 dcb
.fOutxCtsFlow
= TRUE
;
6112 else if (EQ (tem
, Qsw
))
6117 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6119 /* Activate configuration. */
6120 if (!SetCommState (hnd
, &dcb
))
6121 error ("SetCommState() failed");
6123 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6124 p
->childp
= childp2
;