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
];
1566 static const struct env_entry
1573 {"PRELOAD_WINSOCK", NULL
},
1574 {"emacs_dir", "C:/emacs"},
1575 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1576 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1577 {"EMACSDATA", "%emacs_dir%/etc"},
1578 {"EMACSPATH", "%emacs_dir%/bin"},
1579 /* We no longer set INFOPATH because Info-default-directory-list
1581 /* {"INFOPATH", "%emacs_dir%/info"}, */
1582 {"EMACSDOC", "%emacs_dir%/etc"},
1587 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1589 /* We need to copy dflt_envvars[] and work on the copy because we
1590 don't want the dumped Emacs to inherit the values of
1591 environment variables we saw during dumping (which could be on
1592 a different system). The defaults above must be left intact. */
1593 struct env_entry env_vars
[N_ENV_VARS
];
1595 for (i
= 0; i
< N_ENV_VARS
; i
++)
1596 env_vars
[i
] = dflt_envvars
[i
];
1598 /* For backwards compatibility, check if a .emacs file exists in C:/
1599 If not, then we can try to default to the appdata directory under the
1600 user's profile, which is more likely to be writable. */
1601 if (stat ("C:/.emacs", &ignored
) < 0)
1603 HRESULT profile_result
;
1604 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1605 of Windows 95 and NT4 that have not been updated to include
1607 ShGetFolderPath_fn get_folder_path
;
1608 get_folder_path
= (ShGetFolderPath_fn
)
1609 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1611 if (get_folder_path
!= NULL
)
1613 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1616 /* If we can't get the appdata dir, revert to old behavior. */
1617 if (profile_result
== S_OK
)
1619 env_vars
[0].def_value
= default_home
;
1625 /* Get default locale info and use it for LANG. */
1626 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1627 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1628 locale_name
, sizeof (locale_name
)))
1630 for (i
= 0; i
< N_ENV_VARS
; i
++)
1632 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1634 env_vars
[i
].def_value
= locale_name
;
1640 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1642 /* Treat emacs_dir specially: set it unconditionally based on our
1643 location, if it appears that we are running from the bin subdir
1644 of a standard installation. */
1647 char modname
[MAX_PATH
];
1649 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1651 if ((p
= strrchr (modname
, '\\')) == NULL
)
1655 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1657 char buf
[SET_ENV_BUF_SIZE
];
1660 for (p
= modname
; *p
; p
++)
1661 if (*p
== '\\') *p
= '/';
1663 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1664 _putenv (strdup (buf
));
1666 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1668 /* FIXME: should use substring of get_emacs_configuration ().
1669 But I don't think the Windows build supports alpha, mips etc
1670 anymore, so have taken the easy option for now. */
1671 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1674 p
= strrchr (modname
, '\\');
1678 p
= strrchr (modname
, '\\');
1679 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1681 char buf
[SET_ENV_BUF_SIZE
];
1684 for (p
= modname
; *p
; p
++)
1685 if (*p
== '\\') *p
= '/';
1687 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1688 _putenv (strdup (buf
));
1694 for (i
= 0; i
< N_ENV_VARS
; i
++)
1696 if (!getenv (env_vars
[i
].name
))
1700 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1701 /* Also ignore empty environment variables. */
1705 lpval
= env_vars
[i
].def_value
;
1706 dwType
= REG_EXPAND_SZ
;
1708 if (!strcmp (env_vars
[i
].name
, "HOME") && !appdata
)
1710 Lisp_Object warning
[2];
1711 warning
[0] = intern ("initialization");
1712 warning
[1] = build_string ("Setting HOME to C:\\ by default is deprecated");
1713 Vdelayed_warnings_list
= Fcons (Flist (2, warning
),
1714 Vdelayed_warnings_list
);
1720 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1722 if (dwType
== REG_EXPAND_SZ
)
1723 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1724 else if (dwType
== REG_SZ
)
1725 strcpy (buf1
, lpval
);
1726 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1728 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1730 _putenv (strdup (buf2
));
1740 /* Rebuild system configuration to reflect invoking system. */
1741 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1743 /* Another special case: on NT, the PATH variable is actually named
1744 "Path" although cmd.exe (perhaps NT itself) arranges for
1745 environment variable lookup and setting to be case insensitive.
1746 However, Emacs assumes a fully case sensitive environment, so we
1747 need to change "Path" to "PATH" to match the expectations of
1748 various elisp packages. We do this by the sneaky method of
1749 modifying the string in the C runtime environ entry.
1751 The same applies to COMSPEC. */
1755 for (envp
= environ
; *envp
; envp
++)
1756 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1757 memcpy (*envp
, "PATH=", 5);
1758 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1759 memcpy (*envp
, "COMSPEC=", 8);
1762 /* Remember the initial working directory for getwd, then make the
1763 real wd be the location of emacs.exe to avoid conflicts when
1764 renaming or deleting directories. (We also don't call chdir when
1765 running subprocesses for the same reason.) */
1766 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1771 static char modname
[MAX_PATH
];
1773 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1775 if ((p
= strrchr (modname
, '\\')) == NULL
)
1779 SetCurrentDirectory (modname
);
1781 /* Ensure argv[0] has the full path to Emacs. */
1786 /* Determine if there is a middle mouse button, to allow parse_button
1787 to decide whether right mouse events should be mouse-2 or
1789 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1795 emacs_root_dir (void)
1797 static char root_dir
[FILENAME_MAX
];
1800 p
= getenv ("emacs_dir");
1803 strcpy (root_dir
, p
);
1804 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1805 dostounix_filename (root_dir
);
1809 /* We don't have scripts to automatically determine the system configuration
1810 for Emacs before it's compiled, and we don't want to have to make the
1811 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1815 get_emacs_configuration (void)
1817 char *arch
, *oem
, *os
;
1819 static char configuration_buffer
[32];
1821 /* Determine the processor type. */
1822 switch (get_processor_type ())
1825 #ifdef PROCESSOR_INTEL_386
1826 case PROCESSOR_INTEL_386
:
1827 case PROCESSOR_INTEL_486
:
1828 case PROCESSOR_INTEL_PENTIUM
:
1833 #ifdef PROCESSOR_MIPS_R2000
1834 case PROCESSOR_MIPS_R2000
:
1835 case PROCESSOR_MIPS_R3000
:
1836 case PROCESSOR_MIPS_R4000
:
1841 #ifdef PROCESSOR_ALPHA_21064
1842 case PROCESSOR_ALPHA_21064
:
1852 /* Use the OEM field to reflect the compiler/library combination. */
1854 #define COMPILER_NAME "msvc"
1857 #define COMPILER_NAME "mingw"
1859 #define COMPILER_NAME "unknown"
1862 oem
= COMPILER_NAME
;
1864 switch (osinfo_cache
.dwPlatformId
) {
1865 case VER_PLATFORM_WIN32_NT
:
1867 build_num
= osinfo_cache
.dwBuildNumber
;
1869 case VER_PLATFORM_WIN32_WINDOWS
:
1870 if (osinfo_cache
.dwMinorVersion
== 0) {
1875 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1877 case VER_PLATFORM_WIN32s
:
1878 /* Not supported, should not happen. */
1880 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1888 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1889 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1890 get_w32_major_version (), get_w32_minor_version (), build_num
);
1892 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1895 return configuration_buffer
;
1899 get_emacs_configuration_options (void)
1901 static char *options_buffer
;
1902 char cv
[32]; /* Enough for COMPILER_VERSION. */
1904 cv
, /* To be filled later. */
1908 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1909 with a starting space to save work here. */
1911 " --cflags", USER_CFLAGS
,
1914 " --ldflags", USER_LDFLAGS
,
1921 /* Work out the effective configure options for this build. */
1923 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1926 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1928 #define COMPILER_VERSION ""
1932 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
1933 return "Error: not enough space for compiler version";
1934 cv
[sizeof (cv
) - 1] = '\0';
1936 for (i
= 0; options
[i
]; i
++)
1937 size
+= strlen (options
[i
]);
1939 options_buffer
= xmalloc (size
+ 1);
1940 options_buffer
[0] = '\0';
1942 for (i
= 0; options
[i
]; i
++)
1943 strcat (options_buffer
, options
[i
]);
1945 return options_buffer
;
1949 #include <sys/timeb.h>
1951 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1953 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1958 tv
->tv_sec
= tb
.time
;
1959 tv
->tv_usec
= tb
.millitm
* 1000L;
1960 /* Implementation note: _ftime sometimes doesn't update the dstflag
1961 according to the new timezone when the system timezone is
1962 changed. We could fix that by using GetSystemTime and
1963 GetTimeZoneInformation, but that doesn't seem necessary, since
1964 Emacs always calls gettimeofday with the 2nd argument NULL (see
1968 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1969 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1973 /* ------------------------------------------------------------------------- */
1974 /* IO support and wrapper functions for W32 API. */
1975 /* ------------------------------------------------------------------------- */
1977 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1978 on network directories, so we handle that case here.
1979 (Ulrich Leodolter, 1/11/95). */
1981 sys_ctime (const time_t *t
)
1983 char *str
= (char *) ctime (t
);
1984 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1987 /* Emulate sleep...we could have done this with a define, but that
1988 would necessitate including windows.h in the files that used it.
1989 This is much easier. */
1991 sys_sleep (int seconds
)
1993 Sleep (seconds
* 1000);
1996 /* Internal MSVC functions for low-level descriptor munging */
1997 extern int __cdecl
_set_osfhnd (int fd
, long h
);
1998 extern int __cdecl
_free_osfhnd (int fd
);
2000 /* parallel array of private info on file handles */
2001 filedesc fd_info
[ MAXDESC
];
2003 typedef struct volume_info_data
{
2004 struct volume_info_data
* next
;
2006 /* time when info was obtained */
2009 /* actual volume info */
2018 /* Global referenced by various functions. */
2019 static volume_info_data volume_info
;
2021 /* Vector to indicate which drives are local and fixed (for which cached
2022 data never expires). */
2023 static BOOL fixed_drives
[26];
2025 /* Consider cached volume information to be stale if older than 10s,
2026 at least for non-local drives. Info for fixed drives is never stale. */
2027 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2028 #define VOLINFO_STILL_VALID( root_dir, info ) \
2029 ( ( isalpha (root_dir[0]) && \
2030 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2031 || GetTickCount () - info->timestamp < 10000 )
2033 /* Cache support functions. */
2035 /* Simple linked list with linear search is sufficient. */
2036 static volume_info_data
*volume_cache
= NULL
;
2038 static volume_info_data
*
2039 lookup_volume_info (char * root_dir
)
2041 volume_info_data
* info
;
2043 for (info
= volume_cache
; info
; info
= info
->next
)
2044 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2050 add_volume_info (char * root_dir
, volume_info_data
* info
)
2052 info
->root_dir
= xstrdup (root_dir
);
2053 info
->next
= volume_cache
;
2054 volume_cache
= info
;
2058 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2059 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2060 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2061 static volume_info_data
*
2062 GetCachedVolumeInformation (char * root_dir
)
2064 volume_info_data
* info
;
2065 char default_root
[ MAX_PATH
];
2067 /* NULL for root_dir means use root from current directory. */
2068 if (root_dir
== NULL
)
2070 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2072 parse_root (default_root
, &root_dir
);
2074 root_dir
= default_root
;
2077 /* Local fixed drives can be cached permanently. Removable drives
2078 cannot be cached permanently, since the volume name and serial
2079 number (if nothing else) can change. Remote drives should be
2080 treated as if they are removable, since there is no sure way to
2081 tell whether they are or not. Also, the UNC association of drive
2082 letters mapped to remote volumes can be changed at any time (even
2083 by other processes) without notice.
2085 As a compromise, so we can benefit from caching info for remote
2086 volumes, we use a simple expiry mechanism to invalidate cache
2087 entries that are more than ten seconds old. */
2090 /* No point doing this, because WNetGetConnection is even slower than
2091 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2092 GetDriveType is about the only call of this type which does not
2093 involve network access, and so is extremely quick). */
2095 /* Map drive letter to UNC if remote. */
2096 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2098 char remote_name
[ 256 ];
2099 char drive
[3] = { root_dir
[0], ':' };
2101 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2103 /* do something */ ;
2107 info
= lookup_volume_info (root_dir
);
2109 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2117 /* Info is not cached, or is stale. */
2118 if (!GetVolumeInformation (root_dir
,
2119 name
, sizeof (name
),
2123 type
, sizeof (type
)))
2126 /* Cache the volume information for future use, overwriting existing
2127 entry if present. */
2130 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2131 add_volume_info (root_dir
, info
);
2139 info
->name
= xstrdup (name
);
2140 info
->serialnum
= serialnum
;
2141 info
->maxcomp
= maxcomp
;
2142 info
->flags
= flags
;
2143 info
->type
= xstrdup (type
);
2144 info
->timestamp
= GetTickCount ();
2150 /* Get information on the volume where name is held; set path pointer to
2151 start of pathname in name (past UNC header\volume header if present). */
2153 get_volume_info (const char * name
, const char ** pPath
)
2155 char temp
[MAX_PATH
];
2156 char *rootname
= NULL
; /* default to current volume */
2157 volume_info_data
* info
;
2162 /* find the root name of the volume if given */
2163 if (isalpha (name
[0]) && name
[1] == ':')
2171 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2178 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2191 info
= GetCachedVolumeInformation (rootname
);
2194 /* Set global referenced by other functions. */
2195 volume_info
= *info
;
2201 /* Determine if volume is FAT format (ie. only supports short 8.3
2202 names); also set path pointer to start of pathname in name. */
2204 is_fat_volume (const char * name
, const char ** pPath
)
2206 if (get_volume_info (name
, pPath
))
2207 return (volume_info
.maxcomp
== 12);
2211 /* Map filename to a valid 8.3 name if necessary. */
2213 map_w32_filename (const char * name
, const char ** pPath
)
2215 static char shortname
[MAX_PATH
];
2216 char * str
= shortname
;
2219 const char * save_name
= name
;
2221 if (strlen (name
) >= MAX_PATH
)
2223 /* Return a filename which will cause callers to fail. */
2224 strcpy (shortname
, "?");
2228 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2230 register int left
= 8; /* maximum number of chars in part */
2231 register int extn
= 0; /* extension added? */
2232 register int dots
= 2; /* maximum number of dots allowed */
2235 *str
++ = *name
++; /* skip past UNC header */
2237 while ((c
= *name
++))
2244 extn
= 0; /* reset extension flags */
2245 dots
= 2; /* max 2 dots */
2246 left
= 8; /* max length 8 for main part */
2250 extn
= 0; /* reset extension flags */
2251 dots
= 2; /* max 2 dots */
2252 left
= 8; /* max length 8 for main part */
2257 /* Convert path components of the form .xxx to _xxx,
2258 but leave . and .. as they are. This allows .emacs
2259 to be read as _emacs, for example. */
2263 IS_DIRECTORY_SEP (*name
))
2278 extn
= 1; /* we've got an extension */
2279 left
= 3; /* 3 chars in extension */
2283 /* any embedded dots after the first are converted to _ */
2288 case '#': /* don't lose these, they're important */
2290 str
[-1] = c
; /* replace last character of part */
2295 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2297 dots
= 0; /* started a path component */
2306 strcpy (shortname
, name
);
2307 unixtodos_filename (shortname
);
2311 *pPath
= shortname
+ (path
- save_name
);
2317 is_exec (const char * name
)
2319 char * p
= strrchr (name
, '.');
2322 && (xstrcasecmp (p
, ".exe") == 0 ||
2323 xstrcasecmp (p
, ".com") == 0 ||
2324 xstrcasecmp (p
, ".bat") == 0 ||
2325 xstrcasecmp (p
, ".cmd") == 0));
2328 /* Emulate the Unix directory procedures opendir, closedir,
2329 and readdir. We can't use the procedures supplied in sysdep.c,
2330 so we provide them here. */
2332 struct direct dir_static
; /* simulated directory contents */
2333 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2334 static int dir_is_fat
;
2335 static char dir_pathname
[MAXPATHLEN
+1];
2336 static WIN32_FIND_DATA dir_find_data
;
2338 /* Support shares on a network resource as subdirectories of a read-only
2340 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2341 static HANDLE
open_unc_volume (const char *);
2342 static char *read_unc_volume (HANDLE
, char *, int);
2343 static void close_unc_volume (HANDLE
);
2346 opendir (char *filename
)
2350 /* Opening is done by FindFirstFile. However, a read is inherent to
2351 this operation, so we defer the open until read time. */
2353 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2355 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2358 if (is_unc_volume (filename
))
2360 wnet_enum_handle
= open_unc_volume (filename
);
2361 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2365 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2372 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2373 dir_pathname
[MAXPATHLEN
] = '\0';
2374 dir_is_fat
= is_fat_volume (filename
, NULL
);
2380 closedir (DIR *dirp
)
2382 /* If we have a find-handle open, close it. */
2383 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2385 FindClose (dir_find_handle
);
2386 dir_find_handle
= INVALID_HANDLE_VALUE
;
2388 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2390 close_unc_volume (wnet_enum_handle
);
2391 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2393 xfree ((char *) dirp
);
2399 int downcase
= !NILP (Vw32_downcase_file_names
);
2401 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2403 if (!read_unc_volume (wnet_enum_handle
,
2404 dir_find_data
.cFileName
,
2408 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2409 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2411 char filename
[MAXNAMLEN
+ 3];
2414 strcpy (filename
, dir_pathname
);
2415 ln
= strlen (filename
) - 1;
2416 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2417 strcat (filename
, "\\");
2418 strcat (filename
, "*");
2420 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2422 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2427 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2431 /* Emacs never uses this value, so don't bother making it match
2432 value returned by stat(). */
2433 dir_static
.d_ino
= 1;
2435 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2437 /* If the file name in cFileName[] includes `?' characters, it means
2438 the original file name used characters that cannot be represented
2439 by the current ANSI codepage. To avoid total lossage, retrieve
2440 the short 8+3 alias of the long file name. */
2441 if (_mbspbrk (dir_static
.d_name
, "?"))
2443 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2444 downcase
= 1; /* 8+3 aliases are returned in all caps */
2446 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2447 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2448 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2450 /* If the file name in cFileName[] includes `?' characters, it means
2451 the original file name used characters that cannot be represented
2452 by the current ANSI codepage. To avoid total lossage, retrieve
2453 the short 8+3 alias of the long file name. */
2454 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2456 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2457 /* 8+3 aliases are returned in all caps, which could break
2458 various alists that look at filenames' extensions. */
2462 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2463 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2465 _strlwr (dir_static
.d_name
);
2469 for (p
= dir_static
.d_name
; *p
; p
++)
2470 if (*p
>= 'a' && *p
<= 'z')
2473 _strlwr (dir_static
.d_name
);
2480 open_unc_volume (const char *path
)
2486 nr
.dwScope
= RESOURCE_GLOBALNET
;
2487 nr
.dwType
= RESOURCETYPE_DISK
;
2488 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2489 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2490 nr
.lpLocalName
= NULL
;
2491 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2492 nr
.lpComment
= NULL
;
2493 nr
.lpProvider
= NULL
;
2495 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2496 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2498 if (result
== NO_ERROR
)
2501 return INVALID_HANDLE_VALUE
;
2505 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2509 DWORD bufsize
= 512;
2514 buffer
= alloca (bufsize
);
2515 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
2516 if (result
!= NO_ERROR
)
2519 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2520 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2522 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2525 strncpy (readbuf
, ptr
, size
);
2530 close_unc_volume (HANDLE henum
)
2532 if (henum
!= INVALID_HANDLE_VALUE
)
2533 WNetCloseEnum (henum
);
2537 unc_volume_file_attributes (const char *path
)
2542 henum
= open_unc_volume (path
);
2543 if (henum
== INVALID_HANDLE_VALUE
)
2546 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2548 close_unc_volume (henum
);
2553 /* Ensure a network connection is authenticated. */
2555 logon_network_drive (const char *path
)
2557 NETRESOURCE resource
;
2558 char share
[MAX_PATH
];
2563 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2564 drvtype
= DRIVE_REMOTE
;
2565 else if (path
[0] == '\0' || path
[1] != ':')
2566 drvtype
= GetDriveType (NULL
);
2573 drvtype
= GetDriveType (drive
);
2576 /* Only logon to networked drives. */
2577 if (drvtype
!= DRIVE_REMOTE
)
2581 strncpy (share
, path
, MAX_PATH
);
2582 /* Truncate to just server and share name. */
2583 for (i
= 2; i
< MAX_PATH
; i
++)
2585 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2592 resource
.dwType
= RESOURCETYPE_DISK
;
2593 resource
.lpLocalName
= NULL
;
2594 resource
.lpRemoteName
= share
;
2595 resource
.lpProvider
= NULL
;
2597 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2600 /* Shadow some MSVC runtime functions to map requests for long filenames
2601 to reasonable short names if necessary. This was originally added to
2602 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2606 sys_access (const char * path
, int mode
)
2610 /* MSVC implementation doesn't recognize D_OK. */
2611 path
= map_w32_filename (path
, NULL
);
2612 if (is_unc_volume (path
))
2614 attributes
= unc_volume_file_attributes (path
);
2615 if (attributes
== -1) {
2620 else if ((attributes
= GetFileAttributes (path
)) == -1)
2622 /* Should try mapping GetLastError to errno; for now just indicate
2623 that path doesn't exist. */
2627 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2632 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2637 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2646 sys_chdir (const char * path
)
2648 return _chdir (map_w32_filename (path
, NULL
));
2652 sys_chmod (const char * path
, int mode
)
2654 return _chmod (map_w32_filename (path
, NULL
), mode
);
2658 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2660 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2666 sys_creat (const char * path
, int mode
)
2668 return _creat (map_w32_filename (path
, NULL
), mode
);
2672 sys_fopen (const char * path
, const char * mode
)
2676 const char * mode_save
= mode
;
2678 /* Force all file handles to be non-inheritable. This is necessary to
2679 ensure child processes don't unwittingly inherit handles that might
2680 prevent future file access. */
2684 else if (mode
[0] == 'w' || mode
[0] == 'a')
2685 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2689 /* Only do simplistic option parsing. */
2693 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2696 else if (mode
[0] == 'b')
2701 else if (mode
[0] == 't')
2708 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2712 return _fdopen (fd
, mode_save
);
2715 /* This only works on NTFS volumes, but is useful to have. */
2717 sys_link (const char * old
, const char * new)
2721 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2723 if (old
== NULL
|| new == NULL
)
2729 strcpy (oldname
, map_w32_filename (old
, NULL
));
2730 strcpy (newname
, map_w32_filename (new, NULL
));
2732 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2733 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2734 if (fileh
!= INVALID_HANDLE_VALUE
)
2738 /* Confusingly, the "alternate" stream name field does not apply
2739 when restoring a hard link, and instead contains the actual
2740 stream data for the link (ie. the name of the link to create).
2741 The WIN32_STREAM_ID structure before the cStreamName field is
2742 the stream header, which is then immediately followed by the
2746 WIN32_STREAM_ID wid
;
2747 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2750 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2751 data
.wid
.cStreamName
, MAX_PATH
);
2754 LPVOID context
= NULL
;
2757 data
.wid
.dwStreamId
= BACKUP_LINK
;
2758 data
.wid
.dwStreamAttributes
= 0;
2759 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2760 data
.wid
.Size
.HighPart
= 0;
2761 data
.wid
.dwStreamNameSize
= 0;
2763 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2764 offsetof (WIN32_STREAM_ID
, cStreamName
)
2765 + data
.wid
.Size
.LowPart
,
2766 &wbytes
, FALSE
, FALSE
, &context
)
2767 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2774 /* Should try mapping GetLastError to errno; for now just
2775 indicate a general error (eg. links not supported). */
2776 errno
= EINVAL
; // perhaps EMLINK?
2780 CloseHandle (fileh
);
2789 sys_mkdir (const char * path
)
2791 return _mkdir (map_w32_filename (path
, NULL
));
2794 /* Because of long name mapping issues, we need to implement this
2795 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2796 a unique name, instead of setting the input template to an empty
2799 Standard algorithm seems to be use pid or tid with a letter on the
2800 front (in place of the 6 X's) and cycle through the letters to find a
2801 unique name. We extend that to allow any reasonable character as the
2802 first of the 6 X's. */
2804 sys_mktemp (char * template)
2808 unsigned uid
= GetCurrentThreadId ();
2809 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2811 if (template == NULL
)
2813 p
= template + strlen (template);
2815 /* replace up to the last 5 X's with uid in decimal */
2816 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2818 p
[0] = '0' + uid
% 10;
2822 if (i
< 0 && p
[0] == 'X')
2827 int save_errno
= errno
;
2828 p
[0] = first_char
[i
];
2829 if (sys_access (template, 0) < 0)
2835 while (++i
< sizeof (first_char
));
2838 /* Template is badly formed or else we can't generate a unique name,
2839 so return empty string */
2845 sys_open (const char * path
, int oflag
, int mode
)
2847 const char* mpath
= map_w32_filename (path
, NULL
);
2848 /* Try to open file without _O_CREAT, to be able to write to hidden
2849 and system files. Force all file handles to be
2851 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2854 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2858 sys_rename (const char * oldname
, const char * newname
)
2861 char temp
[MAX_PATH
];
2863 /* MoveFile on Windows 95 doesn't correctly change the short file name
2864 alias in a number of circumstances (it is not easy to predict when
2865 just by looking at oldname and newname, unfortunately). In these
2866 cases, renaming through a temporary name avoids the problem.
2868 A second problem on Windows 95 is that renaming through a temp name when
2869 newname is uppercase fails (the final long name ends up in
2870 lowercase, although the short alias might be uppercase) UNLESS the
2871 long temp name is not 8.3.
2873 So, on Windows 95 we always rename through a temp name, and we make sure
2874 the temp name has a long extension to ensure correct renaming. */
2876 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2878 if (os_subtype
== OS_WIN95
)
2884 oldname
= map_w32_filename (oldname
, NULL
);
2885 if (o
= strrchr (oldname
, '\\'))
2888 o
= (char *) oldname
;
2890 if (p
= strrchr (temp
, '\\'))
2897 /* Force temp name to require a manufactured 8.3 alias - this
2898 seems to make the second rename work properly. */
2899 sprintf (p
, "_.%s.%u", o
, i
);
2901 result
= rename (oldname
, temp
);
2903 /* This loop must surely terminate! */
2904 while (result
< 0 && errno
== EEXIST
);
2909 /* Emulate Unix behavior - newname is deleted if it already exists
2910 (at least if it is a file; don't do this for directories).
2912 Since we mustn't do this if we are just changing the case of the
2913 file name (we would end up deleting the file we are trying to
2914 rename!), we let rename detect if the destination file already
2915 exists - that way we avoid the possible pitfalls of trying to
2916 determine ourselves whether two names really refer to the same
2917 file, which is not always possible in the general case. (Consider
2918 all the permutations of shared or subst'd drives, etc.) */
2920 newname
= map_w32_filename (newname
, NULL
);
2921 result
= rename (temp
, newname
);
2925 && _chmod (newname
, 0666) == 0
2926 && _unlink (newname
) == 0)
2927 result
= rename (temp
, newname
);
2933 sys_rmdir (const char * path
)
2935 return _rmdir (map_w32_filename (path
, NULL
));
2939 sys_unlink (const char * path
)
2941 path
= map_w32_filename (path
, NULL
);
2943 /* On Unix, unlink works without write permission. */
2944 _chmod (path
, 0666);
2945 return _unlink (path
);
2948 static FILETIME utc_base_ft
;
2949 static ULONGLONG utc_base
; /* In 100ns units */
2950 static int init
= 0;
2952 #define FILETIME_TO_U64(result, ft) \
2954 ULARGE_INTEGER uiTemp; \
2955 uiTemp.LowPart = (ft).dwLowDateTime; \
2956 uiTemp.HighPart = (ft).dwHighDateTime; \
2957 result = uiTemp.QuadPart; \
2961 initialize_utc_base (void)
2963 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2972 st
.wMilliseconds
= 0;
2974 SystemTimeToFileTime (&st
, &utc_base_ft
);
2975 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2979 convert_time (FILETIME ft
)
2985 initialize_utc_base ();
2989 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2992 FILETIME_TO_U64 (tmp
, ft
);
2993 return (time_t) ((tmp
- utc_base
) / 10000000L);
2997 convert_from_time_t (time_t time
, FILETIME
* pft
)
3003 initialize_utc_base ();
3007 /* time in 100ns units since 1-Jan-1601 */
3008 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3009 pft
->dwHighDateTime
= tmp
.HighPart
;
3010 pft
->dwLowDateTime
= tmp
.LowPart
;
3014 /* No reason to keep this; faking inode values either by hashing or even
3015 using the file index from GetInformationByHandle, is not perfect and
3016 so by default Emacs doesn't use the inode values on Windows.
3017 Instead, we now determine file-truename correctly (except for
3018 possible drive aliasing etc). */
3020 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3022 hashval (const unsigned char * str
)
3027 h
= (h
<< 4) + *str
++;
3033 /* Return the hash value of the canonical pathname, excluding the
3034 drive/UNC header, to get a hopefully unique inode number. */
3036 generate_inode_val (const char * name
)
3038 char fullname
[ MAX_PATH
];
3042 /* Get the truly canonical filename, if it exists. (Note: this
3043 doesn't resolve aliasing due to subst commands, or recognise hard
3045 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3048 parse_root (fullname
, &p
);
3049 /* Normal W32 filesystems are still case insensitive. */
3056 static PSECURITY_DESCRIPTOR
3057 get_file_security_desc (const char *fname
)
3059 PSECURITY_DESCRIPTOR psd
= NULL
;
3061 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3062 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3064 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3066 err
= GetLastError ();
3067 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3071 psd
= xmalloc (sd_len
);
3072 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3084 unsigned n_subauthorities
;
3086 /* Use the last sub-authority value of the RID, the relative
3087 portion of the SID, as user/group ID. */
3088 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3089 if (n_subauthorities
< 1)
3090 return 0; /* the "World" RID */
3091 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3094 /* Caching SID and account values for faster lokup. */
3097 # define FLEXIBLE_ARRAY_MEMBER
3099 # define FLEXIBLE_ARRAY_MEMBER 1
3104 struct w32_id
*next
;
3106 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3109 static struct w32_id
*w32_idlist
;
3112 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3114 struct w32_id
*tail
, *found
;
3116 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3118 if (equal_sid ((PSID
)tail
->sid
, sid
))
3127 strcpy (name
, found
->name
);
3135 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3138 struct w32_id
*new_entry
;
3140 /* We don't want to leave behind stale cache from when Emacs was
3144 sid_len
= get_length_sid (sid
);
3145 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3148 new_entry
->rid
= id
;
3149 strcpy (new_entry
->name
, name
);
3150 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3151 new_entry
->next
= w32_idlist
;
3152 w32_idlist
= new_entry
;
3161 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3162 unsigned *id
, char *nm
, int what
)
3165 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3167 SID_NAME_USE ignore
;
3169 DWORD name_len
= sizeof (name
);
3171 DWORD domain_len
= sizeof (domain
);
3177 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3178 else if (what
== GID
)
3179 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3183 if (!result
|| !is_valid_sid (sid
))
3185 else if (!w32_cached_id (sid
, id
, nm
))
3187 /* If FNAME is a UNC, we need to lookup account on the
3188 specified machine. */
3189 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3190 && fname
[2] != '\0')
3195 for (s
= fname
+ 2, p
= machine
;
3196 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3202 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3203 domain
, &domain_len
, &ignore
)
3204 || name_len
> UNLEN
+1)
3208 *id
= get_rid (sid
);
3210 w32_add_to_cache (sid
, *id
, name
);
3217 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3221 int dflt_usr
= 0, dflt_grp
= 0;
3230 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3232 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3235 /* Consider files to belong to current user/group, if we cannot get
3236 more accurate information. */
3239 st
->st_uid
= dflt_passwd
.pw_uid
;
3240 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3244 st
->st_gid
= dflt_passwd
.pw_gid
;
3245 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3249 /* Return non-zero if NAME is a potentially slow filesystem. */
3251 is_slow_fs (const char *name
)
3256 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3257 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3258 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3259 devtype
= GetDriveType (NULL
); /* use root of current drive */
3262 /* GetDriveType needs the root directory of the drive. */
3263 strncpy (drive_root
, name
, 2);
3264 drive_root
[2] = '\\';
3265 drive_root
[3] = '\0';
3266 devtype
= GetDriveType (drive_root
);
3268 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3271 /* MSVC stat function can't cope with UNC names and has other bugs, so
3272 replace it with our own. This also allows us to calculate consistent
3273 inode values without hacks in the main Emacs code. */
3275 stat (const char * path
, struct stat
* buf
)
3278 WIN32_FIND_DATA wfd
;
3280 unsigned __int64 fake_inode
;
3283 int rootdir
= FALSE
;
3284 PSECURITY_DESCRIPTOR psd
= NULL
;
3286 if (path
== NULL
|| buf
== NULL
)
3292 name
= (char *) map_w32_filename (path
, &path
);
3293 /* Must be valid filename, no wild cards or other invalid
3294 characters. We use _mbspbrk to support multibyte strings that
3295 might look to strpbrk as if they included literal *, ?, and other
3296 characters mentioned below that are disallowed by Windows
3298 if (_mbspbrk (name
, "*?|<>\""))
3304 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3305 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3306 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3311 /* Remove trailing directory separator, unless name is the root
3312 directory of a drive or UNC volume in which case ensure there
3313 is a trailing separator. */
3314 len
= strlen (name
);
3315 rootdir
= (path
>= name
+ len
- 1
3316 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3317 name
= strcpy (alloca (len
+ 2), name
);
3319 if (is_unc_volume (name
))
3321 DWORD attrs
= unc_volume_file_attributes (name
);
3326 memset (&wfd
, 0, sizeof (wfd
));
3327 wfd
.dwFileAttributes
= attrs
;
3328 wfd
.ftCreationTime
= utc_base_ft
;
3329 wfd
.ftLastAccessTime
= utc_base_ft
;
3330 wfd
.ftLastWriteTime
= utc_base_ft
;
3331 strcpy (wfd
.cFileName
, name
);
3335 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3336 strcat (name
, "\\");
3337 if (GetDriveType (name
) < 2)
3342 memset (&wfd
, 0, sizeof (wfd
));
3343 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3344 wfd
.ftCreationTime
= utc_base_ft
;
3345 wfd
.ftLastAccessTime
= utc_base_ft
;
3346 wfd
.ftLastWriteTime
= utc_base_ft
;
3347 strcpy (wfd
.cFileName
, name
);
3351 if (IS_DIRECTORY_SEP (name
[len
-1]))
3354 /* (This is hacky, but helps when doing file completions on
3355 network drives.) Optimize by using information available from
3356 active readdir if possible. */
3357 len
= strlen (dir_pathname
);
3358 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3360 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3361 && strnicmp (name
, dir_pathname
, len
) == 0
3362 && IS_DIRECTORY_SEP (name
[len
])
3363 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3365 /* This was the last entry returned by readdir. */
3366 wfd
= dir_find_data
;
3370 logon_network_drive (name
);
3372 fh
= FindFirstFile (name
, &wfd
);
3373 if (fh
== INVALID_HANDLE_VALUE
)
3382 if (!(NILP (Vw32_get_true_file_attributes
)
3383 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3384 /* No access rights required to get info. */
3385 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3386 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3387 != INVALID_HANDLE_VALUE
)
3389 /* This is more accurate in terms of gettting the correct number
3390 of links, but is quite slow (it is noticeable when Emacs is
3391 making a list of file name completions). */
3392 BY_HANDLE_FILE_INFORMATION info
;
3394 if (GetFileInformationByHandle (fh
, &info
))
3396 buf
->st_nlink
= info
.nNumberOfLinks
;
3397 /* Might as well use file index to fake inode values, but this
3398 is not guaranteed to be unique unless we keep a handle open
3399 all the time (even then there are situations where it is
3400 not unique). Reputedly, there are at most 48 bits of info
3401 (on NTFS, presumably less on FAT). */
3402 fake_inode
= info
.nFileIndexHigh
;
3404 fake_inode
+= info
.nFileIndexLow
;
3412 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3414 buf
->st_mode
= S_IFDIR
;
3418 switch (GetFileType (fh
))
3420 case FILE_TYPE_DISK
:
3421 buf
->st_mode
= S_IFREG
;
3423 case FILE_TYPE_PIPE
:
3424 buf
->st_mode
= S_IFIFO
;
3426 case FILE_TYPE_CHAR
:
3427 case FILE_TYPE_UNKNOWN
:
3429 buf
->st_mode
= S_IFCHR
;
3433 psd
= get_file_security_desc (name
);
3434 get_file_owner_and_group (psd
, name
, buf
);
3438 /* Don't bother to make this information more accurate. */
3439 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3444 get_file_owner_and_group (NULL
, name
, buf
);
3449 /* Not sure if there is any point in this. */
3450 if (!NILP (Vw32_generate_fake_inodes
))
3451 fake_inode
= generate_inode_val (name
);
3452 else if (fake_inode
== 0)
3454 /* For want of something better, try to make everything unique. */
3455 static DWORD gen_num
= 0;
3456 fake_inode
= ++gen_num
;
3460 /* MSVC defines _ino_t to be short; other libc's might not. */
3461 if (sizeof (buf
->st_ino
) == 2)
3462 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3464 buf
->st_ino
= fake_inode
;
3466 /* volume_info is set indirectly by map_w32_filename */
3467 buf
->st_dev
= volume_info
.serialnum
;
3468 buf
->st_rdev
= volume_info
.serialnum
;
3470 buf
->st_size
= wfd
.nFileSizeHigh
;
3471 buf
->st_size
<<= 32;
3472 buf
->st_size
+= wfd
.nFileSizeLow
;
3474 /* Convert timestamps to Unix format. */
3475 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3476 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3477 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3478 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3479 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3481 /* determine rwx permissions */
3482 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3483 permission
= S_IREAD
;
3485 permission
= S_IREAD
| S_IWRITE
;
3487 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3488 permission
|= S_IEXEC
;
3489 else if (is_exec (name
))
3490 permission
|= S_IEXEC
;
3492 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3497 /* Provide fstat and utime as well as stat for consistent handling of
3500 fstat (int desc
, struct stat
* buf
)
3502 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3503 BY_HANDLE_FILE_INFORMATION info
;
3504 unsigned __int64 fake_inode
;
3507 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3509 case FILE_TYPE_DISK
:
3510 buf
->st_mode
= S_IFREG
;
3511 if (!GetFileInformationByHandle (fh
, &info
))
3517 case FILE_TYPE_PIPE
:
3518 buf
->st_mode
= S_IFIFO
;
3520 case FILE_TYPE_CHAR
:
3521 case FILE_TYPE_UNKNOWN
:
3523 buf
->st_mode
= S_IFCHR
;
3525 memset (&info
, 0, sizeof (info
));
3526 info
.dwFileAttributes
= 0;
3527 info
.ftCreationTime
= utc_base_ft
;
3528 info
.ftLastAccessTime
= utc_base_ft
;
3529 info
.ftLastWriteTime
= utc_base_ft
;
3532 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3533 buf
->st_mode
= S_IFDIR
;
3535 buf
->st_nlink
= info
.nNumberOfLinks
;
3536 /* Might as well use file index to fake inode values, but this
3537 is not guaranteed to be unique unless we keep a handle open
3538 all the time (even then there are situations where it is
3539 not unique). Reputedly, there are at most 48 bits of info
3540 (on NTFS, presumably less on FAT). */
3541 fake_inode
= info
.nFileIndexHigh
;
3543 fake_inode
+= info
.nFileIndexLow
;
3545 /* MSVC defines _ino_t to be short; other libc's might not. */
3546 if (sizeof (buf
->st_ino
) == 2)
3547 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3549 buf
->st_ino
= fake_inode
;
3551 /* Consider files to belong to current user.
3552 FIXME: this should use GetSecurityInfo API, but it is only
3553 available for _WIN32_WINNT >= 0x501. */
3554 buf
->st_uid
= dflt_passwd
.pw_uid
;
3555 buf
->st_gid
= dflt_passwd
.pw_gid
;
3556 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3557 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3559 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3560 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3562 buf
->st_size
= info
.nFileSizeHigh
;
3563 buf
->st_size
<<= 32;
3564 buf
->st_size
+= info
.nFileSizeLow
;
3566 /* Convert timestamps to Unix format. */
3567 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3568 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3569 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3570 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3571 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3573 /* determine rwx permissions */
3574 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3575 permission
= S_IREAD
;
3577 permission
= S_IREAD
| S_IWRITE
;
3579 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3580 permission
|= S_IEXEC
;
3583 #if 0 /* no way of knowing the filename */
3584 char * p
= strrchr (name
, '.');
3586 (xstrcasecmp (p
, ".exe") == 0 ||
3587 xstrcasecmp (p
, ".com") == 0 ||
3588 xstrcasecmp (p
, ".bat") == 0 ||
3589 xstrcasecmp (p
, ".cmd") == 0))
3590 permission
|= S_IEXEC
;
3594 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3600 utime (const char *name
, struct utimbuf
*times
)
3602 struct utimbuf deftime
;
3609 deftime
.modtime
= deftime
.actime
= time (NULL
);
3613 /* Need write access to set times. */
3614 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3615 0, OPEN_EXISTING
, 0, NULL
);
3618 convert_from_time_t (times
->actime
, &atime
);
3619 convert_from_time_t (times
->modtime
, &mtime
);
3620 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3637 /* Symlink-related functions that always fail. Used in fileio.c and in
3638 sysdep.c to avoid #ifdef's. */
3640 symlink (char const *dummy1
, char const *dummy2
)
3647 readlink (const char *name
, char *dummy1
, size_t dummy2
)
3649 /* `access' is much faster than `stat' on MS-Windows. */
3650 if (sys_access (name
, 0) == 0)
3656 careadlinkat (int fd
, char const *filename
,
3657 char *buffer
, size_t buffer_size
,
3658 struct allocator
const *alloc
,
3659 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
3666 careadlinkatcwd (int fd
, char const *filename
, char *buffer
,
3670 return readlink (filename
, buffer
, buffer_size
);
3674 /* Support for browsing other processes and their attributes. See
3675 process.c for the Lisp bindings. */
3677 /* Helper wrapper functions. */
3679 static HANDLE WINAPI
3680 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
3682 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3684 if (g_b_init_create_toolhelp32_snapshot
== 0)
3686 g_b_init_create_toolhelp32_snapshot
= 1;
3687 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3688 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3689 "CreateToolhelp32Snapshot");
3691 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3693 return INVALID_HANDLE_VALUE
;
3695 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3699 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3701 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3703 if (g_b_init_process32_first
== 0)
3705 g_b_init_process32_first
= 1;
3706 s_pfn_Process32_First
= (Process32First_Proc
)
3707 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3710 if (s_pfn_Process32_First
== NULL
)
3714 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3718 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3720 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3722 if (g_b_init_process32_next
== 0)
3724 g_b_init_process32_next
= 1;
3725 s_pfn_Process32_Next
= (Process32Next_Proc
)
3726 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3729 if (s_pfn_Process32_Next
== NULL
)
3733 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3737 open_thread_token (HANDLE ThreadHandle
,
3738 DWORD DesiredAccess
,
3740 PHANDLE TokenHandle
)
3742 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3743 HMODULE hm_advapi32
= NULL
;
3744 if (is_windows_9x () == TRUE
)
3746 SetLastError (ERROR_NOT_SUPPORTED
);
3749 if (g_b_init_open_thread_token
== 0)
3751 g_b_init_open_thread_token
= 1;
3752 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3753 s_pfn_Open_Thread_Token
=
3754 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3756 if (s_pfn_Open_Thread_Token
== NULL
)
3758 SetLastError (ERROR_NOT_SUPPORTED
);
3762 s_pfn_Open_Thread_Token (
3771 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3773 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3774 HMODULE hm_advapi32
= NULL
;
3775 if (is_windows_9x () == TRUE
)
3779 if (g_b_init_impersonate_self
== 0)
3781 g_b_init_impersonate_self
= 1;
3782 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3783 s_pfn_Impersonate_Self
=
3784 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3786 if (s_pfn_Impersonate_Self
== NULL
)
3790 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3794 revert_to_self (void)
3796 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3797 HMODULE hm_advapi32
= NULL
;
3798 if (is_windows_9x () == TRUE
)
3802 if (g_b_init_revert_to_self
== 0)
3804 g_b_init_revert_to_self
= 1;
3805 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3806 s_pfn_Revert_To_Self
=
3807 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3809 if (s_pfn_Revert_To_Self
== NULL
)
3813 return s_pfn_Revert_To_Self ();
3817 get_process_memory_info (HANDLE h_proc
,
3818 PPROCESS_MEMORY_COUNTERS mem_counters
,
3821 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3822 HMODULE hm_psapi
= NULL
;
3823 if (is_windows_9x () == TRUE
)
3827 if (g_b_init_get_process_memory_info
== 0)
3829 g_b_init_get_process_memory_info
= 1;
3830 hm_psapi
= LoadLibrary ("Psapi.dll");
3832 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3833 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3835 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3839 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3843 get_process_working_set_size (HANDLE h_proc
,
3847 static GetProcessWorkingSetSize_Proc
3848 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3850 if (is_windows_9x () == TRUE
)
3854 if (g_b_init_get_process_working_set_size
== 0)
3856 g_b_init_get_process_working_set_size
= 1;
3857 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3858 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3859 "GetProcessWorkingSetSize");
3861 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3865 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3869 global_memory_status (MEMORYSTATUS
*buf
)
3871 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3873 if (is_windows_9x () == TRUE
)
3877 if (g_b_init_global_memory_status
== 0)
3879 g_b_init_global_memory_status
= 1;
3880 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3881 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3882 "GlobalMemoryStatus");
3884 if (s_pfn_Global_Memory_Status
== NULL
)
3888 return s_pfn_Global_Memory_Status (buf
);
3892 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
3894 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3896 if (is_windows_9x () == TRUE
)
3900 if (g_b_init_global_memory_status_ex
== 0)
3902 g_b_init_global_memory_status_ex
= 1;
3903 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3904 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3905 "GlobalMemoryStatusEx");
3907 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3911 return s_pfn_Global_Memory_Status_Ex (buf
);
3915 list_system_processes (void)
3917 struct gcpro gcpro1
;
3918 Lisp_Object proclist
= Qnil
;
3921 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3923 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3925 PROCESSENTRY32 proc_entry
;
3931 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3932 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3933 res
= process32_next (h_snapshot
, &proc_entry
))
3935 proc_id
= proc_entry
.th32ProcessID
;
3936 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3939 CloseHandle (h_snapshot
);
3941 proclist
= Fnreverse (proclist
);
3948 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3950 TOKEN_PRIVILEGES priv
;
3951 DWORD priv_size
= sizeof (priv
);
3952 DWORD opriv_size
= sizeof (*old_priv
);
3953 HANDLE h_token
= NULL
;
3954 HANDLE h_thread
= GetCurrentThread ();
3958 res
= open_thread_token (h_thread
,
3959 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3961 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3963 if (impersonate_self (SecurityImpersonation
))
3964 res
= open_thread_token (h_thread
,
3965 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3970 priv
.PrivilegeCount
= 1;
3971 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3972 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3973 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3974 old_priv
, &opriv_size
)
3975 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3979 CloseHandle (h_token
);
3985 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3987 DWORD priv_size
= sizeof (*priv
);
3988 HANDLE h_token
= NULL
;
3991 if (open_thread_token (GetCurrentThread (),
3992 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3995 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3996 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4000 CloseHandle (h_token
);
4006 ltime (long time_sec
, long time_usec
)
4008 return list3 (make_number ((time_sec
>> 16) & 0xffff),
4009 make_number (time_sec
& 0xffff),
4010 make_number (time_usec
));
4013 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
4016 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4017 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4020 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4021 ULONGLONG tem1
, tem2
, tem3
, tem
;
4024 || !get_process_times_fn
4025 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4026 &ft_kernel
, &ft_user
))
4029 GetSystemTimeAsFileTime (&ft_current
);
4031 FILETIME_TO_U64 (tem1
, ft_kernel
);
4033 *stime
= U64_TO_LISP_TIME (tem1
);
4035 FILETIME_TO_U64 (tem2
, ft_user
);
4037 *utime
= U64_TO_LISP_TIME (tem2
);
4040 *ttime
= U64_TO_LISP_TIME (tem3
);
4042 FILETIME_TO_U64 (tem
, ft_creation
);
4043 /* Process no 4 (System) returns zero creation time. */
4045 tem
= (tem
- utc_base
) / 10L;
4046 *ctime
= U64_TO_LISP_TIME (tem
);
4050 FILETIME_TO_U64 (tem3
, ft_current
);
4051 tem
= (tem3
- utc_base
) / 10L - tem
;
4053 *etime
= U64_TO_LISP_TIME (tem
);
4057 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4068 system_process_attributes (Lisp_Object pid
)
4070 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4071 Lisp_Object attrs
= Qnil
;
4072 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4073 HANDLE h_snapshot
, h_proc
;
4076 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4077 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4078 DWORD glength
= sizeof (gname
);
4079 HANDLE token
= NULL
;
4080 SID_NAME_USE user_type
;
4081 unsigned char *buf
= NULL
;
4083 TOKEN_USER user_token
;
4084 TOKEN_PRIMARY_GROUP group_token
;
4087 PROCESS_MEMORY_COUNTERS mem
;
4088 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4089 DWORD minrss
, maxrss
;
4091 MEMORY_STATUS_EX memstex
;
4092 double totphys
= 0.0;
4093 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4095 BOOL result
= FALSE
;
4097 CHECK_NUMBER_OR_FLOAT (pid
);
4098 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4100 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4102 GCPRO3 (attrs
, decoded_cmd
, tem
);
4104 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4109 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4110 for (res
= process32_first (h_snapshot
, &pe
); res
;
4111 res
= process32_next (h_snapshot
, &pe
))
4113 if (proc_id
== pe
.th32ProcessID
)
4116 decoded_cmd
= build_string ("Idle");
4119 /* Decode the command name from locale-specific
4121 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4122 strlen (pe
.szExeFile
));
4124 code_convert_string_norecord (cmd_str
,
4125 Vlocale_coding_system
, 0);
4127 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4128 attrs
= Fcons (Fcons (Qppid
,
4129 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4131 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4133 attrs
= Fcons (Fcons (Qthcount
,
4134 make_fixnum_or_float (pe
.cntThreads
)),
4141 CloseHandle (h_snapshot
);
4150 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4152 /* If we were denied a handle to the process, try again after
4153 enabling the SeDebugPrivilege in our process. */
4156 TOKEN_PRIVILEGES priv_current
;
4158 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4160 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4162 restore_privilege (&priv_current
);
4168 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4171 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4172 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4174 buf
= xmalloc (blen
);
4175 result
= get_token_information (token
, TokenUser
,
4176 (LPVOID
)buf
, blen
, &needed
);
4179 memcpy (&user_token
, buf
, sizeof (user_token
));
4180 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4182 euid
= get_rid (user_token
.User
.Sid
);
4183 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4188 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4191 strcpy (uname
, "unknown");
4195 ulength
= strlen (uname
);
4201 /* Determine a reasonable euid and gid values. */
4202 if (xstrcasecmp ("administrator", uname
) == 0)
4204 euid
= 500; /* well-known Administrator uid */
4205 egid
= 513; /* well-known None gid */
4209 /* Get group id and name. */
4210 result
= get_token_information (token
, TokenPrimaryGroup
,
4211 (LPVOID
)buf
, blen
, &needed
);
4212 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4214 buf
= xrealloc (buf
, blen
= needed
);
4215 result
= get_token_information (token
, TokenPrimaryGroup
,
4216 (LPVOID
)buf
, blen
, &needed
);
4220 memcpy (&group_token
, buf
, sizeof (group_token
));
4221 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4223 egid
= get_rid (group_token
.PrimaryGroup
);
4224 dlength
= sizeof (domain
);
4226 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4227 gname
, &glength
, NULL
, &dlength
,
4230 w32_add_to_cache (group_token
.PrimaryGroup
,
4234 strcpy (gname
, "None");
4238 glength
= strlen (gname
);
4246 if (!is_windows_9x ())
4248 /* We couldn't open the process token, presumably because of
4249 insufficient access rights. Assume this process is run
4251 strcpy (uname
, "SYSTEM");
4252 strcpy (gname
, "None");
4253 euid
= 18; /* SYSTEM */
4254 egid
= 513; /* None */
4255 glength
= strlen (gname
);
4256 ulength
= strlen (uname
);
4258 /* If we are running under Windows 9X, where security calls are
4259 not supported, we assume all processes are run by the current
4261 else if (GetUserName (uname
, &ulength
))
4263 if (xstrcasecmp ("administrator", uname
) == 0)
4268 strcpy (gname
, "None");
4269 glength
= strlen (gname
);
4270 ulength
= strlen (uname
);
4276 strcpy (uname
, "administrator");
4277 ulength
= strlen (uname
);
4278 strcpy (gname
, "None");
4279 glength
= strlen (gname
);
4282 CloseHandle (token
);
4285 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4286 tem
= make_unibyte_string (uname
, ulength
);
4287 attrs
= Fcons (Fcons (Quser
,
4288 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4290 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4291 tem
= make_unibyte_string (gname
, glength
);
4292 attrs
= Fcons (Fcons (Qgroup
,
4293 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4296 if (global_memory_status_ex (&memstex
))
4297 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4298 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4300 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4301 double, so we need to do this for it... */
4303 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4304 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4305 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4307 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4309 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4310 else if (global_memory_status (&memst
))
4311 totphys
= memst
.dwTotalPhys
/ 1024.0;
4314 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4317 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4319 attrs
= Fcons (Fcons (Qmajflt
,
4320 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4322 attrs
= Fcons (Fcons (Qvsize
,
4323 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
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_memory_info (h_proc
, &mem
, sizeof (mem
)))
4332 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4334 attrs
= Fcons (Fcons (Qmajflt
,
4335 make_fixnum_or_float (mem
.PageFaultCount
)),
4337 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4339 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4342 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4344 DWORD rss
= maxrss
/ 1024;
4346 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4348 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4351 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4353 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4354 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4355 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4356 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4357 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4358 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4361 /* FIXME: Retrieve command line by walking the PEB of the process. */
4364 CloseHandle (h_proc
);
4370 /* Wrappers for winsock functions to map between our file descriptors
4371 and winsock's handles; also set h_errno for convenience.
4373 To allow Emacs to run on systems which don't have winsock support
4374 installed, we dynamically link to winsock on startup if present, and
4375 otherwise provide the minimum necessary functionality
4376 (eg. gethostname). */
4378 /* function pointers for relevant socket functions */
4379 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4380 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4381 int (PASCAL
*pfn_WSAGetLastError
) (void);
4382 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4383 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4384 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4385 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4386 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4387 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4388 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4389 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4390 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4391 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4392 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4393 int (PASCAL
*pfn_WSACleanup
) (void);
4395 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4396 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4397 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4398 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4399 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4400 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4401 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4402 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4403 const char * optval
, int optlen
);
4404 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4405 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4407 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4408 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4409 struct sockaddr
* from
, int * fromlen
);
4410 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4411 const struct sockaddr
* to
, int tolen
);
4413 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4414 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4415 #ifndef HANDLE_FLAG_INHERIT
4416 #define HANDLE_FLAG_INHERIT 1
4420 static int winsock_inuse
;
4425 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4427 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4428 after WSAStartup returns successfully, but it seems reasonable
4429 to allow unloading winsock anyway in that case. */
4430 if (pfn_WSACleanup () == 0 ||
4431 pfn_WSAGetLastError () == WSAENETDOWN
)
4433 if (FreeLibrary (winsock_lib
))
4442 init_winsock (int load_now
)
4444 WSADATA winsockData
;
4446 if (winsock_lib
!= NULL
)
4449 pfn_SetHandleInformation
4450 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4451 "SetHandleInformation");
4453 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4455 if (winsock_lib
!= NULL
)
4457 /* dynamically link to socket functions */
4459 #define LOAD_PROC(fn) \
4460 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4463 LOAD_PROC (WSAStartup
);
4464 LOAD_PROC (WSASetLastError
);
4465 LOAD_PROC (WSAGetLastError
);
4466 LOAD_PROC (WSAEventSelect
);
4467 LOAD_PROC (WSACreateEvent
);
4468 LOAD_PROC (WSACloseEvent
);
4471 LOAD_PROC (connect
);
4472 LOAD_PROC (ioctlsocket
);
4475 LOAD_PROC (closesocket
);
4476 LOAD_PROC (shutdown
);
4479 LOAD_PROC (inet_addr
);
4480 LOAD_PROC (gethostname
);
4481 LOAD_PROC (gethostbyname
);
4482 LOAD_PROC (getservbyname
);
4483 LOAD_PROC (getpeername
);
4484 LOAD_PROC (WSACleanup
);
4485 LOAD_PROC (setsockopt
);
4487 LOAD_PROC (getsockname
);
4489 LOAD_PROC (recvfrom
);
4493 /* specify version 1.1 of winsock */
4494 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4496 if (winsockData
.wVersion
!= 0x101)
4501 /* Report that winsock exists and is usable, but leave
4502 socket functions disabled. I am assuming that calling
4503 WSAStartup does not require any network interaction,
4504 and in particular does not cause or require a dial-up
4505 connection to be established. */
4508 FreeLibrary (winsock_lib
);
4516 FreeLibrary (winsock_lib
);
4526 /* function to set h_errno for compatibility; map winsock error codes to
4527 normal system codes where they overlap (non-overlapping definitions
4528 are already in <sys/socket.h> */
4532 if (winsock_lib
== NULL
)
4535 h_errno
= pfn_WSAGetLastError ();
4539 case WSAEACCES
: h_errno
= EACCES
; break;
4540 case WSAEBADF
: h_errno
= EBADF
; break;
4541 case WSAEFAULT
: h_errno
= EFAULT
; break;
4542 case WSAEINTR
: h_errno
= EINTR
; break;
4543 case WSAEINVAL
: h_errno
= EINVAL
; break;
4544 case WSAEMFILE
: h_errno
= EMFILE
; break;
4545 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4546 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4554 if (h_errno
== 0 && winsock_lib
!= NULL
)
4555 pfn_WSASetLastError (0);
4558 /* Extend strerror to handle the winsock-specific error codes. */
4562 } _wsa_errlist
[] = {
4563 {WSAEINTR
, "Interrupted function call"},
4564 {WSAEBADF
, "Bad file descriptor"},
4565 {WSAEACCES
, "Permission denied"},
4566 {WSAEFAULT
, "Bad address"},
4567 {WSAEINVAL
, "Invalid argument"},
4568 {WSAEMFILE
, "Too many open files"},
4570 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
4571 {WSAEINPROGRESS
, "Operation now in progress"},
4572 {WSAEALREADY
, "Operation already in progress"},
4573 {WSAENOTSOCK
, "Socket operation on non-socket"},
4574 {WSAEDESTADDRREQ
, "Destination address required"},
4575 {WSAEMSGSIZE
, "Message too long"},
4576 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
4577 {WSAENOPROTOOPT
, "Bad protocol option"},
4578 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
4579 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
4580 {WSAEOPNOTSUPP
, "Operation not supported"},
4581 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
4582 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
4583 {WSAEADDRINUSE
, "Address already in use"},
4584 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
4585 {WSAENETDOWN
, "Network is down"},
4586 {WSAENETUNREACH
, "Network is unreachable"},
4587 {WSAENETRESET
, "Network dropped connection on reset"},
4588 {WSAECONNABORTED
, "Software caused connection abort"},
4589 {WSAECONNRESET
, "Connection reset by peer"},
4590 {WSAENOBUFS
, "No buffer space available"},
4591 {WSAEISCONN
, "Socket is already connected"},
4592 {WSAENOTCONN
, "Socket is not connected"},
4593 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
4594 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
4595 {WSAETIMEDOUT
, "Connection timed out"},
4596 {WSAECONNREFUSED
, "Connection refused"},
4597 {WSAELOOP
, "Network loop"}, /* not sure */
4598 {WSAENAMETOOLONG
, "Name is too long"},
4599 {WSAEHOSTDOWN
, "Host is down"},
4600 {WSAEHOSTUNREACH
, "No route to host"},
4601 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
4602 {WSAEPROCLIM
, "Too many processes"},
4603 {WSAEUSERS
, "Too many users"}, /* not sure */
4604 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
4605 {WSAESTALE
, "Data is stale"}, /* not sure */
4606 {WSAEREMOTE
, "Remote error"}, /* not sure */
4608 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
4609 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
4610 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
4611 {WSAEDISCON
, "Graceful shutdown in progress"},
4613 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
4614 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
4615 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
4616 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
4617 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
4618 {WSASYSCALLFAILURE
, "System call failure"},
4619 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
4620 {WSATYPE_NOT_FOUND
, "Class type not found"},
4621 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
4622 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
4623 {WSAEREFUSED
, "Operation refused"}, /* not sure */
4626 {WSAHOST_NOT_FOUND
, "Host not found"},
4627 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
4628 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
4629 {WSANO_DATA
, "Valid name, no data record of requested type"},
4635 sys_strerror (int error_no
)
4638 static char unknown_msg
[40];
4640 if (error_no
>= 0 && error_no
< sys_nerr
)
4641 return sys_errlist
[error_no
];
4643 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4644 if (_wsa_errlist
[i
].errnum
== error_no
)
4645 return _wsa_errlist
[i
].msg
;
4647 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4651 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4652 but I believe the method of keeping the socket handle separate (and
4653 insuring it is not inheritable) is the correct one. */
4655 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4657 static int socket_to_fd (SOCKET s
);
4660 sys_socket (int af
, int type
, int protocol
)
4664 if (winsock_lib
== NULL
)
4667 return INVALID_SOCKET
;
4672 /* call the real socket function */
4673 s
= pfn_socket (af
, type
, protocol
);
4675 if (s
!= INVALID_SOCKET
)
4676 return socket_to_fd (s
);
4682 /* Convert a SOCKET to a file descriptor. */
4684 socket_to_fd (SOCKET s
)
4689 /* Although under NT 3.5 _open_osfhandle will accept a socket
4690 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4691 that does not work under NT 3.1. However, we can get the same
4692 effect by using a backdoor function to replace an existing
4693 descriptor handle with the one we want. */
4695 /* allocate a file descriptor (with appropriate flags) */
4696 fd
= _open ("NUL:", _O_RDWR
);
4699 /* Make a non-inheritable copy of the socket handle. Note
4700 that it is possible that sockets aren't actually kernel
4701 handles, which appears to be the case on Windows 9x when
4702 the MS Proxy winsock client is installed. */
4704 /* Apparently there is a bug in NT 3.51 with some service
4705 packs, which prevents using DuplicateHandle to make a
4706 socket handle non-inheritable (causes WSACleanup to
4707 hang). The work-around is to use SetHandleInformation
4708 instead if it is available and implemented. */
4709 if (pfn_SetHandleInformation
)
4711 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4715 HANDLE parent
= GetCurrentProcess ();
4716 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4718 if (DuplicateHandle (parent
,
4724 DUPLICATE_SAME_ACCESS
))
4726 /* It is possible that DuplicateHandle succeeds even
4727 though the socket wasn't really a kernel handle,
4728 because a real handle has the same value. So
4729 test whether the new handle really is a socket. */
4730 long nonblocking
= 0;
4731 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4733 pfn_closesocket (s
);
4738 CloseHandle (new_s
);
4743 fd_info
[fd
].hnd
= (HANDLE
) s
;
4745 /* set our own internal flags */
4746 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4752 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4754 /* attach child_process to fd_info */
4755 if (fd_info
[ fd
].cp
!= NULL
)
4757 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4761 fd_info
[ fd
].cp
= cp
;
4764 winsock_inuse
++; /* count open sockets */
4771 pfn_closesocket (s
);
4777 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4779 if (winsock_lib
== NULL
)
4782 return SOCKET_ERROR
;
4786 if (fd_info
[s
].flags
& FILE_SOCKET
)
4788 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4789 if (rc
== SOCKET_ERROR
)
4794 return SOCKET_ERROR
;
4798 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4800 if (winsock_lib
== NULL
)
4803 return SOCKET_ERROR
;
4807 if (fd_info
[s
].flags
& FILE_SOCKET
)
4809 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4810 if (rc
== SOCKET_ERROR
)
4815 return SOCKET_ERROR
;
4819 sys_htons (u_short hostshort
)
4821 return (winsock_lib
!= NULL
) ?
4822 pfn_htons (hostshort
) : hostshort
;
4826 sys_ntohs (u_short netshort
)
4828 return (winsock_lib
!= NULL
) ?
4829 pfn_ntohs (netshort
) : netshort
;
4833 sys_inet_addr (const char * cp
)
4835 return (winsock_lib
!= NULL
) ?
4836 pfn_inet_addr (cp
) : INADDR_NONE
;
4840 sys_gethostname (char * name
, int namelen
)
4842 if (winsock_lib
!= NULL
)
4843 return pfn_gethostname (name
, namelen
);
4845 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4846 return !GetComputerName (name
, (DWORD
*)&namelen
);
4849 return SOCKET_ERROR
;
4853 sys_gethostbyname (const char * name
)
4855 struct hostent
* host
;
4857 if (winsock_lib
== NULL
)
4864 host
= pfn_gethostbyname (name
);
4871 sys_getservbyname (const char * name
, const char * proto
)
4873 struct servent
* serv
;
4875 if (winsock_lib
== NULL
)
4882 serv
= pfn_getservbyname (name
, proto
);
4889 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4891 if (winsock_lib
== NULL
)
4894 return SOCKET_ERROR
;
4898 if (fd_info
[s
].flags
& FILE_SOCKET
)
4900 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4901 if (rc
== SOCKET_ERROR
)
4906 return SOCKET_ERROR
;
4910 sys_shutdown (int s
, int how
)
4912 if (winsock_lib
== NULL
)
4915 return SOCKET_ERROR
;
4919 if (fd_info
[s
].flags
& FILE_SOCKET
)
4921 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4922 if (rc
== SOCKET_ERROR
)
4927 return SOCKET_ERROR
;
4931 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4933 if (winsock_lib
== NULL
)
4936 return SOCKET_ERROR
;
4940 if (fd_info
[s
].flags
& FILE_SOCKET
)
4942 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4943 (const char *)optval
, optlen
);
4944 if (rc
== SOCKET_ERROR
)
4949 return SOCKET_ERROR
;
4953 sys_listen (int s
, int backlog
)
4955 if (winsock_lib
== NULL
)
4958 return SOCKET_ERROR
;
4962 if (fd_info
[s
].flags
& FILE_SOCKET
)
4964 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4965 if (rc
== SOCKET_ERROR
)
4968 fd_info
[s
].flags
|= FILE_LISTEN
;
4972 return SOCKET_ERROR
;
4976 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4978 if (winsock_lib
== NULL
)
4981 return SOCKET_ERROR
;
4985 if (fd_info
[s
].flags
& FILE_SOCKET
)
4987 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4988 if (rc
== SOCKET_ERROR
)
4993 return SOCKET_ERROR
;
4997 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
4999 if (winsock_lib
== NULL
)
5006 if (fd_info
[s
].flags
& FILE_LISTEN
)
5008 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5010 if (t
== INVALID_SOCKET
)
5013 fd
= socket_to_fd (t
);
5015 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5016 ResetEvent (fd_info
[s
].cp
->char_avail
);
5024 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5025 struct sockaddr
* from
, int * fromlen
)
5027 if (winsock_lib
== NULL
)
5030 return SOCKET_ERROR
;
5034 if (fd_info
[s
].flags
& FILE_SOCKET
)
5036 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5037 if (rc
== SOCKET_ERROR
)
5042 return SOCKET_ERROR
;
5046 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5047 const struct sockaddr
* to
, int tolen
)
5049 if (winsock_lib
== NULL
)
5052 return SOCKET_ERROR
;
5056 if (fd_info
[s
].flags
& FILE_SOCKET
)
5058 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5059 if (rc
== SOCKET_ERROR
)
5064 return SOCKET_ERROR
;
5067 /* Windows does not have an fcntl function. Provide an implementation
5068 solely for making sockets non-blocking. */
5070 fcntl (int s
, int cmd
, int options
)
5072 if (winsock_lib
== NULL
)
5079 if (fd_info
[s
].flags
& FILE_SOCKET
)
5081 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5083 unsigned long nblock
= 1;
5084 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5085 if (rc
== SOCKET_ERROR
)
5087 /* Keep track of the fact that we set this to non-blocking. */
5088 fd_info
[s
].flags
|= FILE_NDELAY
;
5094 return SOCKET_ERROR
;
5098 return SOCKET_ERROR
;
5102 /* Shadow main io functions: we need to handle pipes and sockets more
5103 intelligently, and implement non-blocking mode as well. */
5116 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5118 child_process
* cp
= fd_info
[fd
].cp
;
5120 fd_info
[fd
].cp
= NULL
;
5122 if (CHILD_ACTIVE (cp
))
5124 /* if last descriptor to active child_process then cleanup */
5126 for (i
= 0; i
< MAXDESC
; i
++)
5130 if (fd_info
[i
].cp
== cp
)
5135 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5137 if (winsock_lib
== NULL
) abort ();
5139 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5140 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5142 winsock_inuse
--; /* count open sockets */
5149 /* Note that sockets do not need special treatment here (at least on
5150 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5151 closesocket is equivalent to CloseHandle, which is to be expected
5152 because socket handles are fully fledged kernel handles. */
5155 if (rc
== 0 && fd
< MAXDESC
)
5156 fd_info
[fd
].flags
= 0;
5167 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5169 /* duplicate our internal info as well */
5170 fd_info
[new_fd
] = fd_info
[fd
];
5176 sys_dup2 (int src
, int dst
)
5180 if (dst
< 0 || dst
>= MAXDESC
)
5186 /* make sure we close the destination first if it's a pipe or socket */
5187 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5190 rc
= _dup2 (src
, dst
);
5193 /* duplicate our internal info as well */
5194 fd_info
[dst
] = fd_info
[src
];
5199 /* Unix pipe() has only one arg */
5201 sys_pipe (int * phandles
)
5206 /* make pipe handles non-inheritable; when we spawn a child, we
5207 replace the relevant handle with an inheritable one. Also put
5208 pipes into binary mode; we will do text mode translation ourselves
5210 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5214 /* Protect against overflow, since Windows can open more handles than
5215 our fd_info array has room for. */
5216 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5218 _close (phandles
[0]);
5219 _close (phandles
[1]);
5224 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5225 fd_info
[phandles
[0]].flags
= flags
;
5227 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5228 fd_info
[phandles
[1]].flags
= flags
;
5235 /* Function to do blocking read of one byte, needed to implement
5236 select. It is only allowed on sockets and pipes. */
5238 _sys_read_ahead (int fd
)
5243 if (fd
< 0 || fd
>= MAXDESC
)
5244 return STATUS_READ_ERROR
;
5246 cp
= fd_info
[fd
].cp
;
5248 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5249 return STATUS_READ_ERROR
;
5251 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5252 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5254 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5258 cp
->status
= STATUS_READ_IN_PROGRESS
;
5260 if (fd_info
[fd
].flags
& FILE_PIPE
)
5262 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5264 /* Give subprocess time to buffer some more output for us before
5265 reporting that input is available; we need this because Windows 95
5266 connects DOS programs to pipes by making the pipe appear to be
5267 the normal console stdout - as a result most DOS programs will
5268 write to stdout without buffering, ie. one character at a
5269 time. Even some W32 programs do this - "dir" in a command
5270 shell on NT is very slow if we don't do this. */
5273 int wait
= w32_pipe_read_delay
;
5279 /* Yield remainder of our time slice, effectively giving a
5280 temporary priority boost to the child process. */
5284 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5286 HANDLE hnd
= fd_info
[fd
].hnd
;
5287 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5290 /* Configure timeouts for blocking read. */
5291 if (!GetCommTimeouts (hnd
, &ct
))
5292 return STATUS_READ_ERROR
;
5293 ct
.ReadIntervalTimeout
= 0;
5294 ct
.ReadTotalTimeoutMultiplier
= 0;
5295 ct
.ReadTotalTimeoutConstant
= 0;
5296 if (!SetCommTimeouts (hnd
, &ct
))
5297 return STATUS_READ_ERROR
;
5299 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5301 if (GetLastError () != ERROR_IO_PENDING
)
5302 return STATUS_READ_ERROR
;
5303 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5304 return STATUS_READ_ERROR
;
5307 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5309 unsigned long nblock
= 0;
5310 /* We always want this to block, so temporarily disable NDELAY. */
5311 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5312 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5314 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5316 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5319 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5323 if (rc
== sizeof (char))
5324 cp
->status
= STATUS_READ_SUCCEEDED
;
5326 cp
->status
= STATUS_READ_FAILED
;
5332 _sys_wait_accept (int fd
)
5338 if (fd
< 0 || fd
>= MAXDESC
)
5339 return STATUS_READ_ERROR
;
5341 cp
= fd_info
[fd
].cp
;
5343 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5344 return STATUS_READ_ERROR
;
5346 cp
->status
= STATUS_READ_FAILED
;
5348 hEv
= pfn_WSACreateEvent ();
5349 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5350 if (rc
!= SOCKET_ERROR
)
5352 rc
= WaitForSingleObject (hEv
, INFINITE
);
5353 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5354 if (rc
== WAIT_OBJECT_0
)
5355 cp
->status
= STATUS_READ_SUCCEEDED
;
5357 pfn_WSACloseEvent (hEv
);
5363 sys_read (int fd
, char * buffer
, unsigned int count
)
5368 char * orig_buffer
= buffer
;
5376 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5378 child_process
*cp
= fd_info
[fd
].cp
;
5380 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5388 /* re-read CR carried over from last read */
5389 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5391 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5395 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5398 /* presence of a child_process structure means we are operating in
5399 non-blocking mode - otherwise we just call _read directly.
5400 Note that the child_process structure might be missing because
5401 reap_subprocess has been called; in this case the pipe is
5402 already broken, so calling _read on it is okay. */
5405 int current_status
= cp
->status
;
5407 switch (current_status
)
5409 case STATUS_READ_FAILED
:
5410 case STATUS_READ_ERROR
:
5411 /* report normal EOF if nothing in buffer */
5413 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5416 case STATUS_READ_READY
:
5417 case STATUS_READ_IN_PROGRESS
:
5418 DebPrint (("sys_read called when read is in progress\n"));
5419 errno
= EWOULDBLOCK
;
5422 case STATUS_READ_SUCCEEDED
:
5423 /* consume read-ahead char */
5424 *buffer
++ = cp
->chr
;
5427 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5428 ResetEvent (cp
->char_avail
);
5430 case STATUS_READ_ACKNOWLEDGED
:
5434 DebPrint (("sys_read: bad status %d\n", current_status
));
5439 if (fd_info
[fd
].flags
& FILE_PIPE
)
5441 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5442 to_read
= min (waiting
, (DWORD
) count
);
5445 nchars
+= _read (fd
, buffer
, to_read
);
5447 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5449 HANDLE hnd
= fd_info
[fd
].hnd
;
5450 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5456 /* Configure timeouts for non-blocking read. */
5457 if (!GetCommTimeouts (hnd
, &ct
))
5462 ct
.ReadIntervalTimeout
= MAXDWORD
;
5463 ct
.ReadTotalTimeoutMultiplier
= 0;
5464 ct
.ReadTotalTimeoutConstant
= 0;
5465 if (!SetCommTimeouts (hnd
, &ct
))
5471 if (!ResetEvent (ovl
->hEvent
))
5476 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5478 if (GetLastError () != ERROR_IO_PENDING
)
5483 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5492 else /* FILE_SOCKET */
5494 if (winsock_lib
== NULL
) abort ();
5496 /* do the equivalent of a non-blocking read */
5497 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5498 if (waiting
== 0 && nchars
== 0)
5500 h_errno
= errno
= EWOULDBLOCK
;
5506 /* always use binary mode for sockets */
5507 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5508 if (res
== SOCKET_ERROR
)
5510 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5511 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5521 int nread
= _read (fd
, buffer
, count
);
5524 else if (nchars
== 0)
5529 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5530 /* Perform text mode translation if required. */
5531 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5533 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5534 /* If buffer contains only CR, return that. To be absolutely
5535 sure we should attempt to read the next char, but in
5536 practice a CR to be followed by LF would not appear by
5537 itself in the buffer. */
5538 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5540 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5546 nchars
= _read (fd
, buffer
, count
);
5551 /* From w32xfns.c */
5552 extern HANDLE interrupt_handle
;
5554 /* For now, don't bother with a non-blocking mode */
5556 sys_write (int fd
, const void * buffer
, unsigned int count
)
5566 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5568 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5574 /* Perform text mode translation if required. */
5575 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5577 char * tmpbuf
= alloca (count
* 2);
5578 unsigned char * src
= (void *)buffer
;
5579 unsigned char * dst
= tmpbuf
;
5584 unsigned char *next
;
5585 /* copy next line or remaining bytes */
5586 next
= _memccpy (dst
, src
, '\n', nbytes
);
5589 /* copied one line ending with '\n' */
5590 int copied
= next
- dst
;
5593 /* insert '\r' before '\n' */
5600 /* copied remaining partial line -> now finished */
5607 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5609 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5610 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5611 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5614 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5616 if (GetLastError () != ERROR_IO_PENDING
)
5621 if (detect_input_pending ())
5622 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5625 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5626 if (active
== WAIT_OBJECT_0
)
5627 { /* User pressed C-g, cancel write, then leave. Don't bother
5628 cleaning up as we may only get stuck in buggy drivers. */
5629 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5634 if (active
== WAIT_OBJECT_0
+ 1
5635 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5642 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5644 unsigned long nblock
= 0;
5645 if (winsock_lib
== NULL
) abort ();
5647 /* TODO: implement select() properly so non-blocking I/O works. */
5648 /* For now, make sure the write blocks. */
5649 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5650 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5652 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5654 /* Set the socket back to non-blocking if it was before,
5655 for other operations that support it. */
5656 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5659 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5662 if (nchars
== SOCKET_ERROR
)
5664 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5665 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5671 /* Some networked filesystems don't like too large writes, so
5672 break them into smaller chunks. See the Comments section of
5673 the MSDN documentation of WriteFile for details behind the
5674 choice of the value of CHUNK below. See also the thread
5675 http://thread.gmane.org/gmane.comp.version-control.git/145294
5676 in the git mailing list. */
5677 const unsigned char *p
= buffer
;
5678 const unsigned chunk
= 30 * 1024 * 1024;
5683 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5684 int n
= _write (fd
, p
, this_chunk
);
5692 else if (n
< this_chunk
)
5702 /* The Windows CRT functions are "optimized for speed", so they don't
5703 check for timezone and DST changes if they were last called less
5704 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
5705 all Emacs features that repeatedly call time functions (e.g.,
5706 display-time) are in real danger of missing timezone and DST
5707 changes. Calling tzset before each localtime call fixes that. */
5709 sys_localtime (const time_t *t
)
5712 return localtime (t
);
5716 check_windows_init_file (void)
5718 /* A common indication that Emacs is not installed properly is when
5719 it cannot find the Windows installation file. If this file does
5720 not exist in the expected place, tell the user. */
5722 if (!noninteractive
&& !inhibit_window_system
)
5724 Lisp_Object objs
[2];
5725 Lisp_Object full_load_path
;
5726 Lisp_Object init_file
;
5729 objs
[0] = Vload_path
;
5730 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5731 full_load_path
= Fappend (2, objs
);
5732 init_file
= build_string ("term/w32-win");
5733 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5736 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5737 char *init_file_name
= SDATA (init_file
);
5738 char *load_path
= SDATA (load_path_print
);
5739 char *buffer
= alloca (1024
5740 + strlen (init_file_name
)
5741 + strlen (load_path
));
5744 "The Emacs Windows initialization file \"%s.el\" "
5745 "could not be found in your Emacs installation. "
5746 "Emacs checked the following directories for this file:\n"
5748 "When Emacs cannot find this file, it usually means that it "
5749 "was not installed properly, or its distribution file was "
5750 "not unpacked properly.\nSee the README.W32 file in the "
5751 "top-level Emacs directory for more information.",
5752 init_file_name
, load_path
);
5755 "Emacs Abort Dialog",
5756 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5757 /* Use the low-level Emacs abort. */
5771 /* shutdown the socket interface if necessary */
5780 /* Initialise the socket interface now if available and requested by
5781 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5782 delayed until open-network-stream is called (w32-has-winsock can
5783 also be used to dynamically load or reload winsock).
5785 Conveniently, init_environment is called before us, so
5786 PRELOAD_WINSOCK can be set in the registry. */
5788 /* Always initialize this correctly. */
5791 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5792 init_winsock (TRUE
);
5794 /* Initial preparation for subprocess support: replace our standard
5795 handles with non-inheritable versions. */
5798 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5799 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5800 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5802 parent
= GetCurrentProcess ();
5804 /* ignore errors when duplicating and closing; typically the
5805 handles will be invalid when running as a gui program. */
5806 DuplicateHandle (parent
,
5807 GetStdHandle (STD_INPUT_HANDLE
),
5812 DUPLICATE_SAME_ACCESS
);
5814 DuplicateHandle (parent
,
5815 GetStdHandle (STD_OUTPUT_HANDLE
),
5820 DUPLICATE_SAME_ACCESS
);
5822 DuplicateHandle (parent
,
5823 GetStdHandle (STD_ERROR_HANDLE
),
5828 DUPLICATE_SAME_ACCESS
);
5834 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5835 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5837 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5840 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5841 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5843 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5846 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5847 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5849 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5853 /* unfortunately, atexit depends on implementation of malloc */
5854 /* atexit (term_ntproc); */
5855 signal (SIGABRT
, term_ntproc
);
5857 /* determine which drives are fixed, for GetCachedVolumeInformation */
5859 /* GetDriveType must have trailing backslash. */
5860 char drive
[] = "A:\\";
5862 /* Loop over all possible drive letters */
5863 while (*drive
<= 'Z')
5865 /* Record if this drive letter refers to a fixed drive. */
5866 fixed_drives
[DRIVE_INDEX (*drive
)] =
5867 (GetDriveType (drive
) == DRIVE_FIXED
);
5872 /* Reset the volume info cache. */
5873 volume_cache
= NULL
;
5876 /* Check to see if Emacs has been installed correctly. */
5877 check_windows_init_file ();
5881 shutdown_handler ensures that buffers' autosave files are
5882 up to date when the user logs off, or the system shuts down.
5885 shutdown_handler (DWORD type
)
5887 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5888 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5889 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5890 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5892 /* Shut down cleanly, making sure autosave files are up to date. */
5893 shut_down_emacs (0, 0, Qnil
);
5896 /* Allow other handlers to handle this signal. */
5901 globals_of_w32 is used to initialize those global variables that
5902 must always be initialized on startup even when the global variable
5903 initialized is non zero (see the function main in emacs.c).
5906 globals_of_w32 (void)
5908 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5910 get_process_times_fn
= (GetProcessTimes_Proc
)
5911 GetProcAddress (kernel32
, "GetProcessTimes");
5913 g_b_init_is_windows_9x
= 0;
5914 g_b_init_open_process_token
= 0;
5915 g_b_init_get_token_information
= 0;
5916 g_b_init_lookup_account_sid
= 0;
5917 g_b_init_get_sid_sub_authority
= 0;
5918 g_b_init_get_sid_sub_authority_count
= 0;
5919 g_b_init_get_file_security
= 0;
5920 g_b_init_get_security_descriptor_owner
= 0;
5921 g_b_init_get_security_descriptor_group
= 0;
5922 g_b_init_is_valid_sid
= 0;
5923 g_b_init_create_toolhelp32_snapshot
= 0;
5924 g_b_init_process32_first
= 0;
5925 g_b_init_process32_next
= 0;
5926 g_b_init_open_thread_token
= 0;
5927 g_b_init_impersonate_self
= 0;
5928 g_b_init_revert_to_self
= 0;
5929 g_b_init_get_process_memory_info
= 0;
5930 g_b_init_get_process_working_set_size
= 0;
5931 g_b_init_global_memory_status
= 0;
5932 g_b_init_global_memory_status_ex
= 0;
5933 g_b_init_equal_sid
= 0;
5934 g_b_init_copy_sid
= 0;
5935 g_b_init_get_length_sid
= 0;
5936 g_b_init_get_native_system_info
= 0;
5937 g_b_init_get_system_times
= 0;
5938 num_of_processors
= 0;
5939 /* The following sets a handler for shutdown notifications for
5940 console apps. This actually applies to Emacs in both console and
5941 GUI modes, since we had to fool windows into thinking emacs is a
5942 console application to get console mode to work. */
5943 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
5945 /* "None" is the default group name on standalone workstations. */
5946 strcpy (dflt_group_name
, "None");
5949 /* For make-serial-process */
5951 serial_open (char *port
)
5957 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
5958 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
5959 if (hnd
== INVALID_HANDLE_VALUE
)
5960 error ("Could not open %s", port
);
5961 fd
= (int) _open_osfhandle ((int) hnd
, 0);
5963 error ("Could not open %s", port
);
5967 error ("Could not create child process");
5969 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5970 fd_info
[ fd
].hnd
= hnd
;
5971 fd_info
[ fd
].flags
|=
5972 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
5973 if (fd_info
[ fd
].cp
!= NULL
)
5975 error ("fd_info[fd = %d] is already in use", fd
);
5977 fd_info
[ fd
].cp
= cp
;
5978 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5979 if (cp
->ovl_read
.hEvent
== NULL
)
5980 error ("Could not create read event");
5981 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
5982 if (cp
->ovl_write
.hEvent
== NULL
)
5983 error ("Could not create write event");
5988 /* For serial-process-configure */
5990 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
5992 Lisp_Object childp2
= Qnil
;
5993 Lisp_Object tem
= Qnil
;
5997 char summary
[4] = "???"; /* This usually becomes "8N1". */
5999 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6000 error ("Not a serial process");
6001 hnd
= fd_info
[ p
->outfd
].hnd
;
6003 childp2
= Fcopy_sequence (p
->childp
);
6005 /* Initialize timeouts for blocking read and blocking write. */
6006 if (!GetCommTimeouts (hnd
, &ct
))
6007 error ("GetCommTimeouts() failed");
6008 ct
.ReadIntervalTimeout
= 0;
6009 ct
.ReadTotalTimeoutMultiplier
= 0;
6010 ct
.ReadTotalTimeoutConstant
= 0;
6011 ct
.WriteTotalTimeoutMultiplier
= 0;
6012 ct
.WriteTotalTimeoutConstant
= 0;
6013 if (!SetCommTimeouts (hnd
, &ct
))
6014 error ("SetCommTimeouts() failed");
6015 /* Read port attributes and prepare default configuration. */
6016 memset (&dcb
, 0, sizeof (dcb
));
6017 dcb
.DCBlength
= sizeof (DCB
);
6018 if (!GetCommState (hnd
, &dcb
))
6019 error ("GetCommState() failed");
6022 dcb
.fAbortOnError
= FALSE
;
6023 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6028 /* Configure speed. */
6029 if (!NILP (Fplist_member (contact
, QCspeed
)))
6030 tem
= Fplist_get (contact
, QCspeed
);
6032 tem
= Fplist_get (p
->childp
, QCspeed
);
6034 dcb
.BaudRate
= XINT (tem
);
6035 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6037 /* Configure bytesize. */
6038 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6039 tem
= Fplist_get (contact
, QCbytesize
);
6041 tem
= Fplist_get (p
->childp
, QCbytesize
);
6043 tem
= make_number (8);
6045 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6046 error (":bytesize must be nil (8), 7, or 8");
6047 dcb
.ByteSize
= XINT (tem
);
6048 summary
[0] = XINT (tem
) + '0';
6049 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6051 /* Configure parity. */
6052 if (!NILP (Fplist_member (contact
, QCparity
)))
6053 tem
= Fplist_get (contact
, QCparity
);
6055 tem
= Fplist_get (p
->childp
, QCparity
);
6056 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6057 error (":parity must be nil (no parity), `even', or `odd'");
6058 dcb
.fParity
= FALSE
;
6059 dcb
.Parity
= NOPARITY
;
6060 dcb
.fErrorChar
= FALSE
;
6065 else if (EQ (tem
, Qeven
))
6069 dcb
.Parity
= EVENPARITY
;
6070 dcb
.fErrorChar
= TRUE
;
6072 else if (EQ (tem
, Qodd
))
6076 dcb
.Parity
= ODDPARITY
;
6077 dcb
.fErrorChar
= TRUE
;
6079 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6081 /* Configure stopbits. */
6082 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6083 tem
= Fplist_get (contact
, QCstopbits
);
6085 tem
= Fplist_get (p
->childp
, QCstopbits
);
6087 tem
= make_number (1);
6089 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6090 error (":stopbits must be nil (1 stopbit), 1, or 2");
6091 summary
[2] = XINT (tem
) + '0';
6092 if (XINT (tem
) == 1)
6093 dcb
.StopBits
= ONESTOPBIT
;
6094 else if (XINT (tem
) == 2)
6095 dcb
.StopBits
= TWOSTOPBITS
;
6096 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6098 /* Configure flowcontrol. */
6099 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6100 tem
= Fplist_get (contact
, QCflowcontrol
);
6102 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6103 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6104 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6105 dcb
.fOutxCtsFlow
= FALSE
;
6106 dcb
.fOutxDsrFlow
= FALSE
;
6107 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6108 dcb
.fDsrSensitivity
= FALSE
;
6109 dcb
.fTXContinueOnXoff
= FALSE
;
6112 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6113 dcb
.XonChar
= 17; /* Control-Q */
6114 dcb
.XoffChar
= 19; /* Control-S */
6117 /* Already configured. */
6119 else if (EQ (tem
, Qhw
))
6121 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6122 dcb
.fOutxCtsFlow
= TRUE
;
6124 else if (EQ (tem
, Qsw
))
6129 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6131 /* Activate configuration. */
6132 if (!SetCommState (hnd
, &dcb
))
6133 error ("SetCommState() failed");
6135 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6136 p
->childp
= childp2
;
6142 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
6147 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
6148 int fd
= process
->infd
;
6152 n
= sys_read(fd
, (char*)buf
, sz
);
6159 if (err
== EWOULDBLOCK
)
6161 /* Set a small timeout. */
6162 EMACS_SET_SECS_USECS(timeout
, 1, 0);
6164 FD_SET ((int)fd
, &fdset
);
6166 /* Use select with the timeout to poll the selector. */
6167 sc
= select (fd
+ 1, &fdset
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0,
6171 continue; /* Try again. */
6173 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
6174 Also accept select return 0 as an indicator to EAGAIN. */
6175 if (sc
== 0 || errno
== EWOULDBLOCK
)
6178 err
= errno
; /* Other errors are just passed on. */
6181 gnutls_transport_set_errno (process
->gnutls_state
, err
);
6188 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
6190 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
6191 int fd
= process
->outfd
;
6192 ssize_t n
= sys_write(fd
, buf
, sz
);
6194 /* 0 or more bytes written means everything went fine. */
6198 /* Negative bytes written means we got an error in errno.
6199 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
6200 gnutls_transport_set_errno (process
->gnutls_state
,
6201 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
6205 #endif /* HAVE_GNUTLS */