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 Lisp_Object QCloaded_from
;
155 void globals_of_w32 (void);
156 static DWORD
get_rid (PSID
);
159 /* Initialization states.
161 WARNING: If you add any more such variables for additional APIs,
162 you MUST add initialization for them to globals_of_w32
163 below. This is because these variables might get set
164 to non-NULL values during dumping, but the dumped Emacs
165 cannot reuse those values, because it could be run on a
166 different version of the OS, where API addresses are
168 static BOOL g_b_init_is_windows_9x
;
169 static BOOL g_b_init_open_process_token
;
170 static BOOL g_b_init_get_token_information
;
171 static BOOL g_b_init_lookup_account_sid
;
172 static BOOL g_b_init_get_sid_sub_authority
;
173 static BOOL g_b_init_get_sid_sub_authority_count
;
174 static BOOL g_b_init_get_file_security
;
175 static BOOL g_b_init_get_security_descriptor_owner
;
176 static BOOL g_b_init_get_security_descriptor_group
;
177 static BOOL g_b_init_is_valid_sid
;
178 static BOOL g_b_init_create_toolhelp32_snapshot
;
179 static BOOL g_b_init_process32_first
;
180 static BOOL g_b_init_process32_next
;
181 static BOOL g_b_init_open_thread_token
;
182 static BOOL g_b_init_impersonate_self
;
183 static BOOL g_b_init_revert_to_self
;
184 static BOOL g_b_init_get_process_memory_info
;
185 static BOOL g_b_init_get_process_working_set_size
;
186 static BOOL g_b_init_global_memory_status
;
187 static BOOL g_b_init_global_memory_status_ex
;
188 static BOOL g_b_init_get_length_sid
;
189 static BOOL g_b_init_equal_sid
;
190 static BOOL g_b_init_copy_sid
;
191 static BOOL g_b_init_get_native_system_info
;
192 static BOOL g_b_init_get_system_times
;
195 BEGIN: Wrapper functions around OpenProcessToken
196 and other functions in advapi32.dll that are only
197 supported in Windows NT / 2k / XP
199 /* ** Function pointer typedefs ** */
200 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
201 HANDLE ProcessHandle
,
203 PHANDLE TokenHandle
);
204 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
206 TOKEN_INFORMATION_CLASS TokenInformationClass
,
207 LPVOID TokenInformation
,
208 DWORD TokenInformationLength
,
209 PDWORD ReturnLength
);
210 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
211 HANDLE process_handle
,
212 LPFILETIME creation_time
,
213 LPFILETIME exit_time
,
214 LPFILETIME kernel_time
,
215 LPFILETIME user_time
);
217 GetProcessTimes_Proc get_process_times_fn
= NULL
;
220 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
221 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
223 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
224 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
226 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
227 LPCTSTR lpSystemName
,
232 LPDWORD cbDomainName
,
233 PSID_NAME_USE peUse
);
234 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
237 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
239 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
241 SECURITY_INFORMATION RequestedInformation
,
242 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
244 LPDWORD lpnLengthNeeded
);
245 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
246 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
248 LPBOOL lpbOwnerDefaulted
);
249 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
250 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
252 LPBOOL lpbGroupDefaulted
);
253 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
255 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
257 DWORD th32ProcessID
);
258 typedef BOOL (WINAPI
* Process32First_Proc
) (
260 LPPROCESSENTRY32 lppe
);
261 typedef BOOL (WINAPI
* Process32Next_Proc
) (
263 LPPROCESSENTRY32 lppe
);
264 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
268 PHANDLE TokenHandle
);
269 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
270 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
271 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
272 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
274 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
276 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
278 DWORD
* lpMinimumWorkingSetSize
,
279 DWORD
* lpMaximumWorkingSetSize
);
280 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
281 LPMEMORYSTATUS lpBuffer
);
282 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
283 LPMEMORY_STATUS_EX lpBuffer
);
284 typedef BOOL (WINAPI
* CopySid_Proc
) (
285 DWORD nDestinationSidLength
,
286 PSID pDestinationSid
,
288 typedef BOOL (WINAPI
* EqualSid_Proc
) (
291 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
293 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
294 LPSYSTEM_INFO lpSystemInfo
);
295 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
296 LPFILETIME lpIdleTime
,
297 LPFILETIME lpKernelTime
,
298 LPFILETIME lpUserTime
);
300 /* ** A utility function ** */
304 static BOOL s_b_ret
= 0;
305 OSVERSIONINFO os_ver
;
306 if (g_b_init_is_windows_9x
== 0)
308 g_b_init_is_windows_9x
= 1;
309 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
310 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
311 if (GetVersionEx (&os_ver
))
313 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
319 /* Get total user and system times for get-internal-run-time.
320 Returns a list of three integers if the times are provided by the OS
321 (NT derivatives), otherwise it returns the result of current-time. */
323 w32_get_internal_run_time (void)
325 if (get_process_times_fn
)
327 FILETIME create
, exit
, kernel
, user
;
328 HANDLE proc
= GetCurrentProcess ();
329 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
331 LARGE_INTEGER user_int
, kernel_int
, total
;
333 user_int
.LowPart
= user
.dwLowDateTime
;
334 user_int
.HighPart
= user
.dwHighDateTime
;
335 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
336 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
337 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
338 /* FILETIME is 100 nanosecond increments, Emacs only wants
339 microsecond resolution. */
340 total
.QuadPart
/= 10;
341 microseconds
= total
.QuadPart
% 1000000;
342 total
.QuadPart
/= 1000000;
344 /* Sanity check to make sure we can represent the result. */
345 if (total
.HighPart
== 0)
347 int secs
= total
.LowPart
;
349 return list3 (make_number ((secs
>> 16) & 0xffff),
350 make_number (secs
& 0xffff),
351 make_number (microseconds
));
356 return Fcurrent_time ();
359 /* ** The wrapper functions ** */
362 open_process_token (HANDLE ProcessHandle
,
366 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
367 HMODULE hm_advapi32
= NULL
;
368 if (is_windows_9x () == TRUE
)
372 if (g_b_init_open_process_token
== 0)
374 g_b_init_open_process_token
= 1;
375 hm_advapi32
= LoadLibrary ("Advapi32.dll");
376 s_pfn_Open_Process_Token
=
377 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
379 if (s_pfn_Open_Process_Token
== NULL
)
384 s_pfn_Open_Process_Token (
392 get_token_information (HANDLE TokenHandle
,
393 TOKEN_INFORMATION_CLASS TokenInformationClass
,
394 LPVOID TokenInformation
,
395 DWORD TokenInformationLength
,
398 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
399 HMODULE hm_advapi32
= NULL
;
400 if (is_windows_9x () == TRUE
)
404 if (g_b_init_get_token_information
== 0)
406 g_b_init_get_token_information
= 1;
407 hm_advapi32
= LoadLibrary ("Advapi32.dll");
408 s_pfn_Get_Token_Information
=
409 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
411 if (s_pfn_Get_Token_Information
== NULL
)
416 s_pfn_Get_Token_Information (
418 TokenInformationClass
,
420 TokenInformationLength
,
426 lookup_account_sid (LPCTSTR lpSystemName
,
431 LPDWORD cbDomainName
,
434 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
435 HMODULE hm_advapi32
= NULL
;
436 if (is_windows_9x () == TRUE
)
440 if (g_b_init_lookup_account_sid
== 0)
442 g_b_init_lookup_account_sid
= 1;
443 hm_advapi32
= LoadLibrary ("Advapi32.dll");
444 s_pfn_Lookup_Account_Sid
=
445 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
447 if (s_pfn_Lookup_Account_Sid
== NULL
)
452 s_pfn_Lookup_Account_Sid (
464 get_sid_sub_authority (PSID pSid
, DWORD n
)
466 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
467 static DWORD zero
= 0U;
468 HMODULE hm_advapi32
= NULL
;
469 if (is_windows_9x () == TRUE
)
473 if (g_b_init_get_sid_sub_authority
== 0)
475 g_b_init_get_sid_sub_authority
= 1;
476 hm_advapi32
= LoadLibrary ("Advapi32.dll");
477 s_pfn_Get_Sid_Sub_Authority
=
478 (GetSidSubAuthority_Proc
) GetProcAddress (
479 hm_advapi32
, "GetSidSubAuthority");
481 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
485 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
489 get_sid_sub_authority_count (PSID pSid
)
491 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
492 static UCHAR zero
= 0U;
493 HMODULE hm_advapi32
= NULL
;
494 if (is_windows_9x () == TRUE
)
498 if (g_b_init_get_sid_sub_authority_count
== 0)
500 g_b_init_get_sid_sub_authority_count
= 1;
501 hm_advapi32
= LoadLibrary ("Advapi32.dll");
502 s_pfn_Get_Sid_Sub_Authority_Count
=
503 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
504 hm_advapi32
, "GetSidSubAuthorityCount");
506 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
510 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
514 get_file_security (LPCTSTR lpFileName
,
515 SECURITY_INFORMATION RequestedInformation
,
516 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
518 LPDWORD lpnLengthNeeded
)
520 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
521 HMODULE hm_advapi32
= NULL
;
522 if (is_windows_9x () == TRUE
)
526 if (g_b_init_get_file_security
== 0)
528 g_b_init_get_file_security
= 1;
529 hm_advapi32
= LoadLibrary ("Advapi32.dll");
530 s_pfn_Get_File_Security
=
531 (GetFileSecurity_Proc
) GetProcAddress (
532 hm_advapi32
, GetFileSecurity_Name
);
534 if (s_pfn_Get_File_Security
== NULL
)
538 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
539 pSecurityDescriptor
, nLength
,
544 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
546 LPBOOL lpbOwnerDefaulted
)
548 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
549 HMODULE hm_advapi32
= NULL
;
550 if (is_windows_9x () == TRUE
)
554 if (g_b_init_get_security_descriptor_owner
== 0)
556 g_b_init_get_security_descriptor_owner
= 1;
557 hm_advapi32
= LoadLibrary ("Advapi32.dll");
558 s_pfn_Get_Security_Descriptor_Owner
=
559 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
560 hm_advapi32
, "GetSecurityDescriptorOwner");
562 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
566 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
571 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
573 LPBOOL lpbGroupDefaulted
)
575 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
576 HMODULE hm_advapi32
= NULL
;
577 if (is_windows_9x () == TRUE
)
581 if (g_b_init_get_security_descriptor_group
== 0)
583 g_b_init_get_security_descriptor_group
= 1;
584 hm_advapi32
= LoadLibrary ("Advapi32.dll");
585 s_pfn_Get_Security_Descriptor_Group
=
586 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
587 hm_advapi32
, "GetSecurityDescriptorGroup");
589 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
593 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
598 is_valid_sid (PSID sid
)
600 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
601 HMODULE hm_advapi32
= NULL
;
602 if (is_windows_9x () == TRUE
)
606 if (g_b_init_is_valid_sid
== 0)
608 g_b_init_is_valid_sid
= 1;
609 hm_advapi32
= LoadLibrary ("Advapi32.dll");
611 (IsValidSid_Proc
) GetProcAddress (
612 hm_advapi32
, "IsValidSid");
614 if (s_pfn_Is_Valid_Sid
== NULL
)
618 return (s_pfn_Is_Valid_Sid (sid
));
622 equal_sid (PSID sid1
, PSID sid2
)
624 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
625 HMODULE hm_advapi32
= NULL
;
626 if (is_windows_9x () == TRUE
)
630 if (g_b_init_equal_sid
== 0)
632 g_b_init_equal_sid
= 1;
633 hm_advapi32
= LoadLibrary ("Advapi32.dll");
635 (EqualSid_Proc
) GetProcAddress (
636 hm_advapi32
, "EqualSid");
638 if (s_pfn_Equal_Sid
== NULL
)
642 return (s_pfn_Equal_Sid (sid1
, sid2
));
646 get_length_sid (PSID sid
)
648 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
649 HMODULE hm_advapi32
= NULL
;
650 if (is_windows_9x () == TRUE
)
654 if (g_b_init_get_length_sid
== 0)
656 g_b_init_get_length_sid
= 1;
657 hm_advapi32
= LoadLibrary ("Advapi32.dll");
658 s_pfn_Get_Length_Sid
=
659 (GetLengthSid_Proc
) GetProcAddress (
660 hm_advapi32
, "GetLengthSid");
662 if (s_pfn_Get_Length_Sid
== NULL
)
666 return (s_pfn_Get_Length_Sid (sid
));
670 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
672 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
673 HMODULE hm_advapi32
= NULL
;
674 if (is_windows_9x () == TRUE
)
678 if (g_b_init_copy_sid
== 0)
680 g_b_init_copy_sid
= 1;
681 hm_advapi32
= LoadLibrary ("Advapi32.dll");
683 (CopySid_Proc
) GetProcAddress (
684 hm_advapi32
, "CopySid");
686 if (s_pfn_Copy_Sid
== NULL
)
690 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
694 END: Wrapper functions around OpenProcessToken
695 and other functions in advapi32.dll that are only
696 supported in Windows NT / 2k / XP
700 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
702 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
703 if (is_windows_9x () != TRUE
)
705 if (g_b_init_get_native_system_info
== 0)
707 g_b_init_get_native_system_info
= 1;
708 s_pfn_Get_Native_System_Info
=
709 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
710 "GetNativeSystemInfo");
712 if (s_pfn_Get_Native_System_Info
!= NULL
)
713 s_pfn_Get_Native_System_Info (lpSystemInfo
);
716 lpSystemInfo
->dwNumberOfProcessors
= -1;
720 get_system_times (LPFILETIME lpIdleTime
,
721 LPFILETIME lpKernelTime
,
722 LPFILETIME lpUserTime
)
724 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
725 if (is_windows_9x () == TRUE
)
729 if (g_b_init_get_system_times
== 0)
731 g_b_init_get_system_times
= 1;
732 s_pfn_Get_System_times
=
733 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
736 if (s_pfn_Get_System_times
== NULL
)
738 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
741 /* Equivalent of strerror for W32 error codes. */
743 w32_strerror (int error_no
)
745 static char buf
[500];
748 error_no
= GetLastError ();
751 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
753 0, /* choose most suitable language */
754 buf
, sizeof (buf
), NULL
))
755 sprintf (buf
, "w32 error %u", error_no
);
759 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
760 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
762 This is called from alloc.c:valid_pointer_p. */
764 w32_valid_pointer_p (void *p
, int size
)
767 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
771 unsigned char *buf
= alloca (size
);
772 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
781 static char startup_dir
[MAXPATHLEN
];
783 /* Get the current working directory. */
788 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
792 /* Emacs doesn't actually change directory itself, and we want to
793 force our real wd to be where emacs.exe is to avoid unnecessary
794 conflicts when trying to rename or delete directories. */
795 strcpy (dir
, startup_dir
);
800 /* Emulate getloadavg. */
809 /* Number of processors on this machine. */
810 static unsigned num_of_processors
;
812 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
813 static struct load_sample samples
[16*60];
814 static int first_idx
= -1, last_idx
= -1;
815 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
820 int next_idx
= from
+ 1;
822 if (next_idx
>= max_idx
)
831 int prev_idx
= from
- 1;
834 prev_idx
= max_idx
- 1;
840 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
843 FILETIME ft_idle
, ft_user
, ft_kernel
;
845 /* Initialize the number of processors on this machine. */
846 if (num_of_processors
<= 0)
848 get_native_system_info (&sysinfo
);
849 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
850 if (num_of_processors
<= 0)
852 GetSystemInfo (&sysinfo
);
853 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
855 if (num_of_processors
<= 0)
856 num_of_processors
= 1;
859 /* TODO: Take into account threads that are ready to run, by
860 sampling the "\System\Processor Queue Length" performance
861 counter. The code below accounts only for threads that are
864 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
866 ULARGE_INTEGER uidle
, ukernel
, uuser
;
868 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
869 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
870 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
871 *idle
= uidle
.QuadPart
;
872 *kernel
= ukernel
.QuadPart
;
873 *user
= uuser
.QuadPart
;
883 /* Produce the load average for a given time interval, using the
884 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
885 1-minute, 5-minute, or 15-minute average, respectively. */
889 double retval
= -1.0;
892 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
893 time_t now
= samples
[last_idx
].sample_time
;
895 if (first_idx
!= last_idx
)
897 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
899 tdiff
= difftime (now
, samples
[idx
].sample_time
);
900 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
903 samples
[last_idx
].kernel
+ samples
[last_idx
].user
904 - (samples
[idx
].kernel
+ samples
[idx
].user
);
905 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
907 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
910 if (idx
== first_idx
)
919 getloadavg (double loadavg
[], int nelem
)
922 ULONGLONG idle
, kernel
, user
;
923 time_t now
= time (NULL
);
925 /* Store another sample. We ignore samples that are less than 1 sec
927 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
929 sample_system_load (&idle
, &kernel
, &user
);
930 last_idx
= buf_next (last_idx
);
931 samples
[last_idx
].sample_time
= now
;
932 samples
[last_idx
].idle
= idle
;
933 samples
[last_idx
].kernel
= kernel
;
934 samples
[last_idx
].user
= user
;
935 /* If the buffer has more that 15 min worth of samples, discard
938 first_idx
= last_idx
;
939 while (first_idx
!= last_idx
940 && (difftime (now
, samples
[first_idx
].sample_time
)
941 >= 15.0*60 + 2*DBL_EPSILON
*now
))
942 first_idx
= buf_next (first_idx
);
945 for (elem
= 0; elem
< nelem
; elem
++)
947 double avg
= getavg (elem
);
957 /* Emulate getpwuid, getpwnam and others. */
959 #define PASSWD_FIELD_SIZE 256
961 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
962 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
963 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
964 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
965 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
967 static struct passwd dflt_passwd
=
979 static char dflt_group_name
[GNLEN
+1];
981 static struct group dflt_group
=
983 /* When group information is not available, we return this as the
984 group for all files. */
992 return dflt_passwd
.pw_uid
;
998 /* I could imagine arguing for checking to see whether the user is
999 in the Administrators group and returning a UID of 0 for that
1000 case, but I don't know how wise that would be in the long run. */
1007 return dflt_passwd
.pw_gid
;
1017 getpwuid (unsigned uid
)
1019 if (uid
== dflt_passwd
.pw_uid
)
1020 return &dflt_passwd
;
1025 getgrgid (gid_t gid
)
1031 getpwnam (char *name
)
1035 pw
= getpwuid (getuid ());
1039 if (xstrcasecmp (name
, pw
->pw_name
))
1046 init_user_info (void)
1048 /* Find the user's real name by opening the process token and
1049 looking up the name associated with the user-sid in that token.
1051 Use the relative portion of the identifier authority value from
1052 the user-sid as the user id value (same for group id using the
1053 primary group sid from the process token). */
1055 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1056 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1057 DWORD glength
= sizeof (gname
);
1058 HANDLE token
= NULL
;
1059 SID_NAME_USE user_type
;
1060 unsigned char *buf
= NULL
;
1062 TOKEN_USER user_token
;
1063 TOKEN_PRIMARY_GROUP group_token
;
1066 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1069 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1070 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1072 buf
= xmalloc (blen
);
1073 result
= get_token_information (token
, TokenUser
,
1074 (LPVOID
)buf
, blen
, &needed
);
1077 memcpy (&user_token
, buf
, sizeof (user_token
));
1078 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1080 domain
, &dlength
, &user_type
);
1088 strcpy (dflt_passwd
.pw_name
, uname
);
1089 /* Determine a reasonable uid value. */
1090 if (xstrcasecmp ("administrator", uname
) == 0)
1092 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1093 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1097 /* Use the last sub-authority value of the RID, the relative
1098 portion of the SID, as user/group ID. */
1099 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1101 /* Get group id and name. */
1102 result
= get_token_information (token
, TokenPrimaryGroup
,
1103 (LPVOID
)buf
, blen
, &needed
);
1104 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1106 buf
= xrealloc (buf
, blen
= needed
);
1107 result
= get_token_information (token
, TokenPrimaryGroup
,
1108 (LPVOID
)buf
, blen
, &needed
);
1112 memcpy (&group_token
, buf
, sizeof (group_token
));
1113 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1114 dlength
= sizeof (domain
);
1115 /* If we can get at the real Primary Group name, use that.
1116 Otherwise, the default group name was already set to
1117 "None" in globals_of_w32. */
1118 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1119 gname
, &glength
, NULL
, &dlength
,
1121 strcpy (dflt_group_name
, gname
);
1124 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1127 /* If security calls are not supported (presumably because we
1128 are running under Windows 9X), fallback to this: */
1129 else if (GetUserName (uname
, &ulength
))
1131 strcpy (dflt_passwd
.pw_name
, uname
);
1132 if (xstrcasecmp ("administrator", uname
) == 0)
1133 dflt_passwd
.pw_uid
= 0;
1135 dflt_passwd
.pw_uid
= 123;
1136 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1140 strcpy (dflt_passwd
.pw_name
, "unknown");
1141 dflt_passwd
.pw_uid
= 123;
1142 dflt_passwd
.pw_gid
= 123;
1144 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1146 /* Ensure HOME and SHELL are defined. */
1147 if (getenv ("HOME") == NULL
)
1149 if (getenv ("SHELL") == NULL
)
1152 /* Set dir and shell from environment variables. */
1153 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1154 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1158 CloseHandle (token
);
1164 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1165 return ((rand () << 15) | rand ());
1175 /* Normalize filename by converting all path separators to
1176 the specified separator. Also conditionally convert upper
1177 case path name components to lower case. */
1180 normalize_filename (register char *fp
, char path_sep
)
1185 /* Always lower-case drive letters a-z, even if the filesystem
1186 preserves case in filenames.
1187 This is so filenames can be compared by string comparison
1188 functions that are case-sensitive. Even case-preserving filesystems
1189 do not distinguish case in drive letters. */
1190 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1196 if (NILP (Vw32_downcase_file_names
))
1200 if (*fp
== '/' || *fp
== '\\')
1207 sep
= path_sep
; /* convert to this path separator */
1208 elem
= fp
; /* start of current path element */
1211 if (*fp
>= 'a' && *fp
<= 'z')
1212 elem
= 0; /* don't convert this element */
1214 if (*fp
== 0 || *fp
== ':')
1216 sep
= *fp
; /* restore current separator (or 0) */
1217 *fp
= '/'; /* after conversion of this element */
1220 if (*fp
== '/' || *fp
== '\\')
1222 if (elem
&& elem
!= fp
)
1224 *fp
= 0; /* temporary end of string */
1225 _strlwr (elem
); /* while we convert to lower case */
1227 *fp
= sep
; /* convert (or restore) path separator */
1228 elem
= fp
+ 1; /* next element starts after separator */
1234 /* Destructively turn backslashes into slashes. */
1236 dostounix_filename (register char *p
)
1238 normalize_filename (p
, '/');
1241 /* Destructively turn slashes into backslashes. */
1243 unixtodos_filename (register char *p
)
1245 normalize_filename (p
, '\\');
1248 /* Remove all CR's that are followed by a LF.
1249 (From msdos.c...probably should figure out a way to share it,
1250 although this code isn't going to ever change.) */
1252 crlf_to_lf (register int n
, register unsigned char *buf
)
1254 unsigned char *np
= buf
;
1255 unsigned char *startp
= buf
;
1256 unsigned char *endp
= buf
+ n
;
1260 while (buf
< endp
- 1)
1264 if (*(++buf
) != 0x0a)
1275 /* Parse the root part of file name, if present. Return length and
1276 optionally store pointer to char after root. */
1278 parse_root (char * name
, char ** pPath
)
1280 char * start
= name
;
1285 /* find the root name of the volume if given */
1286 if (isalpha (name
[0]) && name
[1] == ':')
1288 /* skip past drive specifier */
1290 if (IS_DIRECTORY_SEP (name
[0]))
1293 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1299 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1304 if (IS_DIRECTORY_SEP (name
[0]))
1311 return name
- start
;
1314 /* Get long base name for name; name is assumed to be absolute. */
1316 get_long_basename (char * name
, char * buf
, int size
)
1318 WIN32_FIND_DATA find_data
;
1322 /* must be valid filename, no wild cards or other invalid characters */
1323 if (_mbspbrk (name
, "*?|<>\""))
1326 dir_handle
= FindFirstFile (name
, &find_data
);
1327 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1329 if ((len
= strlen (find_data
.cFileName
)) < size
)
1330 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1333 FindClose (dir_handle
);
1338 /* Get long name for file, if possible (assumed to be absolute). */
1340 w32_get_long_filename (char * name
, char * buf
, int size
)
1345 char full
[ MAX_PATH
];
1348 len
= strlen (name
);
1349 if (len
>= MAX_PATH
)
1352 /* Use local copy for destructive modification. */
1353 memcpy (full
, name
, len
+1);
1354 unixtodos_filename (full
);
1356 /* Copy root part verbatim. */
1357 len
= parse_root (full
, &p
);
1358 memcpy (o
, full
, len
);
1363 while (p
!= NULL
&& *p
)
1366 p
= strchr (q
, '\\');
1368 len
= get_long_basename (full
, o
, size
);
1391 is_unc_volume (const char *filename
)
1393 const char *ptr
= filename
;
1395 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1398 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1404 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1407 sigsetmask (int signal_mask
)
1425 sigunblock (int sig
)
1431 sigemptyset (sigset_t
*set
)
1437 sigaddset (sigset_t
*set
, int signo
)
1443 sigfillset (sigset_t
*set
)
1449 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1455 setpgrp (int pid
, int gid
)
1466 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1469 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1472 HKEY hrootkey
= NULL
;
1475 /* Check both the current user and the local machine to see if
1476 we have any resources. */
1478 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1482 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1483 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1484 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1486 RegCloseKey (hrootkey
);
1492 RegCloseKey (hrootkey
);
1495 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1499 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1500 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1501 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1503 RegCloseKey (hrootkey
);
1509 RegCloseKey (hrootkey
);
1515 char *get_emacs_configuration (void);
1518 init_environment (char ** argv
)
1520 static const char * const tempdirs
[] = {
1521 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1526 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1528 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1529 temporary files and assume "/tmp" if $TMPDIR is unset, which
1530 will break on DOS/Windows. Refuse to work if we cannot find
1531 a directory, not even "c:/", usable for that purpose. */
1532 for (i
= 0; i
< imax
; i
++)
1534 const char *tmp
= tempdirs
[i
];
1537 tmp
= getenv (tmp
+ 1);
1538 /* Note that `access' can lie to us if the directory resides on a
1539 read-only filesystem, like CD-ROM or a write-protected floppy.
1540 The only way to be really sure is to actually create a file and
1541 see if it succeeds. But I think that's too much to ask. */
1542 if (tmp
&& _access (tmp
, D_OK
) == 0)
1544 char * var
= alloca (strlen (tmp
) + 8);
1545 sprintf (var
, "TMPDIR=%s", tmp
);
1546 _putenv (strdup (var
));
1553 Fcons (build_string ("no usable temporary directories found!!"),
1555 "While setting TMPDIR: ");
1557 /* Check for environment variables and use registry settings if they
1558 don't exist. Fallback on default values where applicable. */
1563 char locale_name
[32];
1564 struct stat ignored
;
1565 char default_home
[MAX_PATH
];
1568 static const struct env_entry
1575 {"PRELOAD_WINSOCK", NULL
},
1576 {"emacs_dir", "C:/emacs"},
1577 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1578 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1579 {"EMACSDATA", "%emacs_dir%/etc"},
1580 {"EMACSPATH", "%emacs_dir%/bin"},
1581 /* We no longer set INFOPATH because Info-default-directory-list
1583 /* {"INFOPATH", "%emacs_dir%/info"}, */
1584 {"EMACSDOC", "%emacs_dir%/etc"},
1589 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1591 /* We need to copy dflt_envvars[] and work on the copy because we
1592 don't want the dumped Emacs to inherit the values of
1593 environment variables we saw during dumping (which could be on
1594 a different system). The defaults above must be left intact. */
1595 struct env_entry env_vars
[N_ENV_VARS
];
1597 for (i
= 0; i
< N_ENV_VARS
; i
++)
1598 env_vars
[i
] = dflt_envvars
[i
];
1600 /* For backwards compatibility, check if a .emacs file exists in C:/
1601 If not, then we can try to default to the appdata directory under the
1602 user's profile, which is more likely to be writable. */
1603 if (stat ("C:/.emacs", &ignored
) < 0)
1605 HRESULT profile_result
;
1606 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1607 of Windows 95 and NT4 that have not been updated to include
1609 ShGetFolderPath_fn get_folder_path
;
1610 get_folder_path
= (ShGetFolderPath_fn
)
1611 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1613 if (get_folder_path
!= NULL
)
1615 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1618 /* If we can't get the appdata dir, revert to old behavior. */
1619 if (profile_result
== S_OK
)
1621 env_vars
[0].def_value
= default_home
;
1627 /* Get default locale info and use it for LANG. */
1628 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1629 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1630 locale_name
, sizeof (locale_name
)))
1632 for (i
= 0; i
< N_ENV_VARS
; i
++)
1634 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1636 env_vars
[i
].def_value
= locale_name
;
1642 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1644 /* Treat emacs_dir specially: set it unconditionally based on our
1645 location, if it appears that we are running from the bin subdir
1646 of a standard installation. */
1649 char modname
[MAX_PATH
];
1651 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1653 if ((p
= strrchr (modname
, '\\')) == NULL
)
1657 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1659 char buf
[SET_ENV_BUF_SIZE
];
1662 for (p
= modname
; *p
; p
++)
1663 if (*p
== '\\') *p
= '/';
1665 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1666 _putenv (strdup (buf
));
1668 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1670 /* FIXME: should use substring of get_emacs_configuration ().
1671 But I don't think the Windows build supports alpha, mips etc
1672 anymore, so have taken the easy option for now. */
1673 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1676 p
= strrchr (modname
, '\\');
1680 p
= strrchr (modname
, '\\');
1681 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1683 char buf
[SET_ENV_BUF_SIZE
];
1686 for (p
= modname
; *p
; p
++)
1687 if (*p
== '\\') *p
= '/';
1689 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1690 _putenv (strdup (buf
));
1696 for (i
= 0; i
< N_ENV_VARS
; i
++)
1698 if (!getenv (env_vars
[i
].name
))
1702 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1703 /* Also ignore empty environment variables. */
1707 lpval
= env_vars
[i
].def_value
;
1708 dwType
= REG_EXPAND_SZ
;
1710 if (!strcmp (env_vars
[i
].name
, "HOME") && !appdata
)
1712 Lisp_Object warning
[2];
1713 warning
[0] = intern ("initialization");
1714 warning
[1] = build_string ("Setting HOME to C:\\ by default is deprecated");
1715 Vdelayed_warnings_list
= Fcons (Flist (2, warning
),
1716 Vdelayed_warnings_list
);
1722 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1724 if (dwType
== REG_EXPAND_SZ
)
1725 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1726 else if (dwType
== REG_SZ
)
1727 strcpy (buf1
, lpval
);
1728 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1730 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1732 _putenv (strdup (buf2
));
1742 /* Rebuild system configuration to reflect invoking system. */
1743 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1745 /* Another special case: on NT, the PATH variable is actually named
1746 "Path" although cmd.exe (perhaps NT itself) arranges for
1747 environment variable lookup and setting to be case insensitive.
1748 However, Emacs assumes a fully case sensitive environment, so we
1749 need to change "Path" to "PATH" to match the expectations of
1750 various elisp packages. We do this by the sneaky method of
1751 modifying the string in the C runtime environ entry.
1753 The same applies to COMSPEC. */
1757 for (envp
= environ
; *envp
; envp
++)
1758 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1759 memcpy (*envp
, "PATH=", 5);
1760 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1761 memcpy (*envp
, "COMSPEC=", 8);
1764 /* Remember the initial working directory for getwd, then make the
1765 real wd be the location of emacs.exe to avoid conflicts when
1766 renaming or deleting directories. (We also don't call chdir when
1767 running subprocesses for the same reason.) */
1768 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1773 static char modname
[MAX_PATH
];
1775 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1777 if ((p
= strrchr (modname
, '\\')) == NULL
)
1781 SetCurrentDirectory (modname
);
1783 /* Ensure argv[0] has the full path to Emacs. */
1788 /* Determine if there is a middle mouse button, to allow parse_button
1789 to decide whether right mouse events should be mouse-2 or
1791 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1797 emacs_root_dir (void)
1799 static char root_dir
[FILENAME_MAX
];
1802 p
= getenv ("emacs_dir");
1805 strcpy (root_dir
, p
);
1806 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1807 dostounix_filename (root_dir
);
1811 /* We don't have scripts to automatically determine the system configuration
1812 for Emacs before it's compiled, and we don't want to have to make the
1813 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1817 get_emacs_configuration (void)
1819 char *arch
, *oem
, *os
;
1821 static char configuration_buffer
[32];
1823 /* Determine the processor type. */
1824 switch (get_processor_type ())
1827 #ifdef PROCESSOR_INTEL_386
1828 case PROCESSOR_INTEL_386
:
1829 case PROCESSOR_INTEL_486
:
1830 case PROCESSOR_INTEL_PENTIUM
:
1835 #ifdef PROCESSOR_MIPS_R2000
1836 case PROCESSOR_MIPS_R2000
:
1837 case PROCESSOR_MIPS_R3000
:
1838 case PROCESSOR_MIPS_R4000
:
1843 #ifdef PROCESSOR_ALPHA_21064
1844 case PROCESSOR_ALPHA_21064
:
1854 /* Use the OEM field to reflect the compiler/library combination. */
1856 #define COMPILER_NAME "msvc"
1859 #define COMPILER_NAME "mingw"
1861 #define COMPILER_NAME "unknown"
1864 oem
= COMPILER_NAME
;
1866 switch (osinfo_cache
.dwPlatformId
) {
1867 case VER_PLATFORM_WIN32_NT
:
1869 build_num
= osinfo_cache
.dwBuildNumber
;
1871 case VER_PLATFORM_WIN32_WINDOWS
:
1872 if (osinfo_cache
.dwMinorVersion
== 0) {
1877 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1879 case VER_PLATFORM_WIN32s
:
1880 /* Not supported, should not happen. */
1882 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1890 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1891 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1892 get_w32_major_version (), get_w32_minor_version (), build_num
);
1894 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1897 return configuration_buffer
;
1901 get_emacs_configuration_options (void)
1903 static char *options_buffer
;
1904 char cv
[32]; /* Enough for COMPILER_VERSION. */
1906 cv
, /* To be filled later. */
1910 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1911 with a starting space to save work here. */
1913 " --cflags", USER_CFLAGS
,
1916 " --ldflags", USER_LDFLAGS
,
1923 /* Work out the effective configure options for this build. */
1925 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1928 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1930 #define COMPILER_VERSION ""
1934 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
1935 return "Error: not enough space for compiler version";
1936 cv
[sizeof (cv
) - 1] = '\0';
1938 for (i
= 0; options
[i
]; i
++)
1939 size
+= strlen (options
[i
]);
1941 options_buffer
= xmalloc (size
+ 1);
1942 options_buffer
[0] = '\0';
1944 for (i
= 0; options
[i
]; i
++)
1945 strcat (options_buffer
, options
[i
]);
1947 return options_buffer
;
1951 #include <sys/timeb.h>
1953 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1955 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1960 tv
->tv_sec
= tb
.time
;
1961 tv
->tv_usec
= tb
.millitm
* 1000L;
1962 /* Implementation note: _ftime sometimes doesn't update the dstflag
1963 according to the new timezone when the system timezone is
1964 changed. We could fix that by using GetSystemTime and
1965 GetTimeZoneInformation, but that doesn't seem necessary, since
1966 Emacs always calls gettimeofday with the 2nd argument NULL (see
1970 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1971 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1975 /* ------------------------------------------------------------------------- */
1976 /* IO support and wrapper functions for W32 API. */
1977 /* ------------------------------------------------------------------------- */
1979 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1980 on network directories, so we handle that case here.
1981 (Ulrich Leodolter, 1/11/95). */
1983 sys_ctime (const time_t *t
)
1985 char *str
= (char *) ctime (t
);
1986 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1989 /* Emulate sleep...we could have done this with a define, but that
1990 would necessitate including windows.h in the files that used it.
1991 This is much easier. */
1993 sys_sleep (int seconds
)
1995 Sleep (seconds
* 1000);
1998 /* Internal MSVC functions for low-level descriptor munging */
1999 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2000 extern int __cdecl
_free_osfhnd (int fd
);
2002 /* parallel array of private info on file handles */
2003 filedesc fd_info
[ MAXDESC
];
2005 typedef struct volume_info_data
{
2006 struct volume_info_data
* next
;
2008 /* time when info was obtained */
2011 /* actual volume info */
2020 /* Global referenced by various functions. */
2021 static volume_info_data volume_info
;
2023 /* Vector to indicate which drives are local and fixed (for which cached
2024 data never expires). */
2025 static BOOL fixed_drives
[26];
2027 /* Consider cached volume information to be stale if older than 10s,
2028 at least for non-local drives. Info for fixed drives is never stale. */
2029 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2030 #define VOLINFO_STILL_VALID( root_dir, info ) \
2031 ( ( isalpha (root_dir[0]) && \
2032 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2033 || GetTickCount () - info->timestamp < 10000 )
2035 /* Cache support functions. */
2037 /* Simple linked list with linear search is sufficient. */
2038 static volume_info_data
*volume_cache
= NULL
;
2040 static volume_info_data
*
2041 lookup_volume_info (char * root_dir
)
2043 volume_info_data
* info
;
2045 for (info
= volume_cache
; info
; info
= info
->next
)
2046 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2052 add_volume_info (char * root_dir
, volume_info_data
* info
)
2054 info
->root_dir
= xstrdup (root_dir
);
2055 info
->next
= volume_cache
;
2056 volume_cache
= info
;
2060 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2061 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2062 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2063 static volume_info_data
*
2064 GetCachedVolumeInformation (char * root_dir
)
2066 volume_info_data
* info
;
2067 char default_root
[ MAX_PATH
];
2069 /* NULL for root_dir means use root from current directory. */
2070 if (root_dir
== NULL
)
2072 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2074 parse_root (default_root
, &root_dir
);
2076 root_dir
= default_root
;
2079 /* Local fixed drives can be cached permanently. Removable drives
2080 cannot be cached permanently, since the volume name and serial
2081 number (if nothing else) can change. Remote drives should be
2082 treated as if they are removable, since there is no sure way to
2083 tell whether they are or not. Also, the UNC association of drive
2084 letters mapped to remote volumes can be changed at any time (even
2085 by other processes) without notice.
2087 As a compromise, so we can benefit from caching info for remote
2088 volumes, we use a simple expiry mechanism to invalidate cache
2089 entries that are more than ten seconds old. */
2092 /* No point doing this, because WNetGetConnection is even slower than
2093 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2094 GetDriveType is about the only call of this type which does not
2095 involve network access, and so is extremely quick). */
2097 /* Map drive letter to UNC if remote. */
2098 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2100 char remote_name
[ 256 ];
2101 char drive
[3] = { root_dir
[0], ':' };
2103 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2105 /* do something */ ;
2109 info
= lookup_volume_info (root_dir
);
2111 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2119 /* Info is not cached, or is stale. */
2120 if (!GetVolumeInformation (root_dir
,
2121 name
, sizeof (name
),
2125 type
, sizeof (type
)))
2128 /* Cache the volume information for future use, overwriting existing
2129 entry if present. */
2132 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2133 add_volume_info (root_dir
, info
);
2141 info
->name
= xstrdup (name
);
2142 info
->serialnum
= serialnum
;
2143 info
->maxcomp
= maxcomp
;
2144 info
->flags
= flags
;
2145 info
->type
= xstrdup (type
);
2146 info
->timestamp
= GetTickCount ();
2152 /* Get information on the volume where name is held; set path pointer to
2153 start of pathname in name (past UNC header\volume header if present). */
2155 get_volume_info (const char * name
, const char ** pPath
)
2157 char temp
[MAX_PATH
];
2158 char *rootname
= NULL
; /* default to current volume */
2159 volume_info_data
* info
;
2164 /* find the root name of the volume if given */
2165 if (isalpha (name
[0]) && name
[1] == ':')
2173 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2180 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2193 info
= GetCachedVolumeInformation (rootname
);
2196 /* Set global referenced by other functions. */
2197 volume_info
= *info
;
2203 /* Determine if volume is FAT format (ie. only supports short 8.3
2204 names); also set path pointer to start of pathname in name. */
2206 is_fat_volume (const char * name
, const char ** pPath
)
2208 if (get_volume_info (name
, pPath
))
2209 return (volume_info
.maxcomp
== 12);
2213 /* Map filename to a valid 8.3 name if necessary. */
2215 map_w32_filename (const char * name
, const char ** pPath
)
2217 static char shortname
[MAX_PATH
];
2218 char * str
= shortname
;
2221 const char * save_name
= name
;
2223 if (strlen (name
) >= MAX_PATH
)
2225 /* Return a filename which will cause callers to fail. */
2226 strcpy (shortname
, "?");
2230 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2232 register int left
= 8; /* maximum number of chars in part */
2233 register int extn
= 0; /* extension added? */
2234 register int dots
= 2; /* maximum number of dots allowed */
2237 *str
++ = *name
++; /* skip past UNC header */
2239 while ((c
= *name
++))
2246 extn
= 0; /* reset extension flags */
2247 dots
= 2; /* max 2 dots */
2248 left
= 8; /* max length 8 for main part */
2252 extn
= 0; /* reset extension flags */
2253 dots
= 2; /* max 2 dots */
2254 left
= 8; /* max length 8 for main part */
2259 /* Convert path components of the form .xxx to _xxx,
2260 but leave . and .. as they are. This allows .emacs
2261 to be read as _emacs, for example. */
2265 IS_DIRECTORY_SEP (*name
))
2280 extn
= 1; /* we've got an extension */
2281 left
= 3; /* 3 chars in extension */
2285 /* any embedded dots after the first are converted to _ */
2290 case '#': /* don't lose these, they're important */
2292 str
[-1] = c
; /* replace last character of part */
2297 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2299 dots
= 0; /* started a path component */
2308 strcpy (shortname
, name
);
2309 unixtodos_filename (shortname
);
2313 *pPath
= shortname
+ (path
- save_name
);
2319 is_exec (const char * name
)
2321 char * p
= strrchr (name
, '.');
2324 && (xstrcasecmp (p
, ".exe") == 0 ||
2325 xstrcasecmp (p
, ".com") == 0 ||
2326 xstrcasecmp (p
, ".bat") == 0 ||
2327 xstrcasecmp (p
, ".cmd") == 0));
2330 /* Emulate the Unix directory procedures opendir, closedir,
2331 and readdir. We can't use the procedures supplied in sysdep.c,
2332 so we provide them here. */
2334 struct direct dir_static
; /* simulated directory contents */
2335 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2336 static int dir_is_fat
;
2337 static char dir_pathname
[MAXPATHLEN
+1];
2338 static WIN32_FIND_DATA dir_find_data
;
2340 /* Support shares on a network resource as subdirectories of a read-only
2342 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2343 static HANDLE
open_unc_volume (const char *);
2344 static char *read_unc_volume (HANDLE
, char *, int);
2345 static void close_unc_volume (HANDLE
);
2348 opendir (char *filename
)
2352 /* Opening is done by FindFirstFile. However, a read is inherent to
2353 this operation, so we defer the open until read time. */
2355 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2357 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2360 if (is_unc_volume (filename
))
2362 wnet_enum_handle
= open_unc_volume (filename
);
2363 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2367 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2374 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2375 dir_pathname
[MAXPATHLEN
] = '\0';
2376 dir_is_fat
= is_fat_volume (filename
, NULL
);
2382 closedir (DIR *dirp
)
2384 /* If we have a find-handle open, close it. */
2385 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2387 FindClose (dir_find_handle
);
2388 dir_find_handle
= INVALID_HANDLE_VALUE
;
2390 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2392 close_unc_volume (wnet_enum_handle
);
2393 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2395 xfree ((char *) dirp
);
2401 int downcase
= !NILP (Vw32_downcase_file_names
);
2403 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2405 if (!read_unc_volume (wnet_enum_handle
,
2406 dir_find_data
.cFileName
,
2410 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2411 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2413 char filename
[MAXNAMLEN
+ 3];
2416 strcpy (filename
, dir_pathname
);
2417 ln
= strlen (filename
) - 1;
2418 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2419 strcat (filename
, "\\");
2420 strcat (filename
, "*");
2422 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2424 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2429 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2433 /* Emacs never uses this value, so don't bother making it match
2434 value returned by stat(). */
2435 dir_static
.d_ino
= 1;
2437 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2439 /* If the file name in cFileName[] includes `?' characters, it means
2440 the original file name used characters that cannot be represented
2441 by the current ANSI codepage. To avoid total lossage, retrieve
2442 the short 8+3 alias of the long file name. */
2443 if (_mbspbrk (dir_static
.d_name
, "?"))
2445 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2446 downcase
= 1; /* 8+3 aliases are returned in all caps */
2448 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2449 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2450 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2452 /* If the file name in cFileName[] includes `?' characters, it means
2453 the original file name used characters that cannot be represented
2454 by the current ANSI codepage. To avoid total lossage, retrieve
2455 the short 8+3 alias of the long file name. */
2456 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2458 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2459 /* 8+3 aliases are returned in all caps, which could break
2460 various alists that look at filenames' extensions. */
2464 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2465 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2467 _strlwr (dir_static
.d_name
);
2471 for (p
= dir_static
.d_name
; *p
; p
++)
2472 if (*p
>= 'a' && *p
<= 'z')
2475 _strlwr (dir_static
.d_name
);
2482 open_unc_volume (const char *path
)
2488 nr
.dwScope
= RESOURCE_GLOBALNET
;
2489 nr
.dwType
= RESOURCETYPE_DISK
;
2490 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2491 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2492 nr
.lpLocalName
= NULL
;
2493 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2494 nr
.lpComment
= NULL
;
2495 nr
.lpProvider
= NULL
;
2497 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2498 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2500 if (result
== NO_ERROR
)
2503 return INVALID_HANDLE_VALUE
;
2507 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2511 DWORD bufsize
= 512;
2516 buffer
= alloca (bufsize
);
2517 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
2518 if (result
!= NO_ERROR
)
2521 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2522 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2524 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2527 strncpy (readbuf
, ptr
, size
);
2532 close_unc_volume (HANDLE henum
)
2534 if (henum
!= INVALID_HANDLE_VALUE
)
2535 WNetCloseEnum (henum
);
2539 unc_volume_file_attributes (const char *path
)
2544 henum
= open_unc_volume (path
);
2545 if (henum
== INVALID_HANDLE_VALUE
)
2548 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2550 close_unc_volume (henum
);
2555 /* Ensure a network connection is authenticated. */
2557 logon_network_drive (const char *path
)
2559 NETRESOURCE resource
;
2560 char share
[MAX_PATH
];
2565 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2566 drvtype
= DRIVE_REMOTE
;
2567 else if (path
[0] == '\0' || path
[1] != ':')
2568 drvtype
= GetDriveType (NULL
);
2575 drvtype
= GetDriveType (drive
);
2578 /* Only logon to networked drives. */
2579 if (drvtype
!= DRIVE_REMOTE
)
2583 strncpy (share
, path
, MAX_PATH
);
2584 /* Truncate to just server and share name. */
2585 for (i
= 2; i
< MAX_PATH
; i
++)
2587 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2594 resource
.dwType
= RESOURCETYPE_DISK
;
2595 resource
.lpLocalName
= NULL
;
2596 resource
.lpRemoteName
= share
;
2597 resource
.lpProvider
= NULL
;
2599 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2602 /* Shadow some MSVC runtime functions to map requests for long filenames
2603 to reasonable short names if necessary. This was originally added to
2604 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2608 sys_access (const char * path
, int mode
)
2612 /* MSVC implementation doesn't recognize D_OK. */
2613 path
= map_w32_filename (path
, NULL
);
2614 if (is_unc_volume (path
))
2616 attributes
= unc_volume_file_attributes (path
);
2617 if (attributes
== -1) {
2622 else if ((attributes
= GetFileAttributes (path
)) == -1)
2624 /* Should try mapping GetLastError to errno; for now just indicate
2625 that path doesn't exist. */
2629 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2634 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2639 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2648 sys_chdir (const char * path
)
2650 return _chdir (map_w32_filename (path
, NULL
));
2654 sys_chmod (const char * path
, int mode
)
2656 return _chmod (map_w32_filename (path
, NULL
), mode
);
2660 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2662 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2668 sys_creat (const char * path
, int mode
)
2670 return _creat (map_w32_filename (path
, NULL
), mode
);
2674 sys_fopen (const char * path
, const char * mode
)
2678 const char * mode_save
= mode
;
2680 /* Force all file handles to be non-inheritable. This is necessary to
2681 ensure child processes don't unwittingly inherit handles that might
2682 prevent future file access. */
2686 else if (mode
[0] == 'w' || mode
[0] == 'a')
2687 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2691 /* Only do simplistic option parsing. */
2695 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2698 else if (mode
[0] == 'b')
2703 else if (mode
[0] == 't')
2710 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2714 return _fdopen (fd
, mode_save
);
2717 /* This only works on NTFS volumes, but is useful to have. */
2719 sys_link (const char * old
, const char * new)
2723 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2725 if (old
== NULL
|| new == NULL
)
2731 strcpy (oldname
, map_w32_filename (old
, NULL
));
2732 strcpy (newname
, map_w32_filename (new, NULL
));
2734 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2735 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2736 if (fileh
!= INVALID_HANDLE_VALUE
)
2740 /* Confusingly, the "alternate" stream name field does not apply
2741 when restoring a hard link, and instead contains the actual
2742 stream data for the link (ie. the name of the link to create).
2743 The WIN32_STREAM_ID structure before the cStreamName field is
2744 the stream header, which is then immediately followed by the
2748 WIN32_STREAM_ID wid
;
2749 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2752 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2753 data
.wid
.cStreamName
, MAX_PATH
);
2756 LPVOID context
= NULL
;
2759 data
.wid
.dwStreamId
= BACKUP_LINK
;
2760 data
.wid
.dwStreamAttributes
= 0;
2761 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2762 data
.wid
.Size
.HighPart
= 0;
2763 data
.wid
.dwStreamNameSize
= 0;
2765 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2766 offsetof (WIN32_STREAM_ID
, cStreamName
)
2767 + data
.wid
.Size
.LowPart
,
2768 &wbytes
, FALSE
, FALSE
, &context
)
2769 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2776 /* Should try mapping GetLastError to errno; for now just
2777 indicate a general error (eg. links not supported). */
2778 errno
= EINVAL
; // perhaps EMLINK?
2782 CloseHandle (fileh
);
2791 sys_mkdir (const char * path
)
2793 return _mkdir (map_w32_filename (path
, NULL
));
2796 /* Because of long name mapping issues, we need to implement this
2797 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2798 a unique name, instead of setting the input template to an empty
2801 Standard algorithm seems to be use pid or tid with a letter on the
2802 front (in place of the 6 X's) and cycle through the letters to find a
2803 unique name. We extend that to allow any reasonable character as the
2804 first of the 6 X's. */
2806 sys_mktemp (char * template)
2810 unsigned uid
= GetCurrentThreadId ();
2811 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2813 if (template == NULL
)
2815 p
= template + strlen (template);
2817 /* replace up to the last 5 X's with uid in decimal */
2818 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2820 p
[0] = '0' + uid
% 10;
2824 if (i
< 0 && p
[0] == 'X')
2829 int save_errno
= errno
;
2830 p
[0] = first_char
[i
];
2831 if (sys_access (template, 0) < 0)
2837 while (++i
< sizeof (first_char
));
2840 /* Template is badly formed or else we can't generate a unique name,
2841 so return empty string */
2847 sys_open (const char * path
, int oflag
, int mode
)
2849 const char* mpath
= map_w32_filename (path
, NULL
);
2850 /* Try to open file without _O_CREAT, to be able to write to hidden
2851 and system files. Force all file handles to be
2853 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2856 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2860 sys_rename (const char * oldname
, const char * newname
)
2863 char temp
[MAX_PATH
];
2865 /* MoveFile on Windows 95 doesn't correctly change the short file name
2866 alias in a number of circumstances (it is not easy to predict when
2867 just by looking at oldname and newname, unfortunately). In these
2868 cases, renaming through a temporary name avoids the problem.
2870 A second problem on Windows 95 is that renaming through a temp name when
2871 newname is uppercase fails (the final long name ends up in
2872 lowercase, although the short alias might be uppercase) UNLESS the
2873 long temp name is not 8.3.
2875 So, on Windows 95 we always rename through a temp name, and we make sure
2876 the temp name has a long extension to ensure correct renaming. */
2878 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2880 if (os_subtype
== OS_WIN95
)
2886 oldname
= map_w32_filename (oldname
, NULL
);
2887 if (o
= strrchr (oldname
, '\\'))
2890 o
= (char *) oldname
;
2892 if (p
= strrchr (temp
, '\\'))
2899 /* Force temp name to require a manufactured 8.3 alias - this
2900 seems to make the second rename work properly. */
2901 sprintf (p
, "_.%s.%u", o
, i
);
2903 result
= rename (oldname
, temp
);
2905 /* This loop must surely terminate! */
2906 while (result
< 0 && errno
== EEXIST
);
2911 /* Emulate Unix behavior - newname is deleted if it already exists
2912 (at least if it is a file; don't do this for directories).
2914 Since we mustn't do this if we are just changing the case of the
2915 file name (we would end up deleting the file we are trying to
2916 rename!), we let rename detect if the destination file already
2917 exists - that way we avoid the possible pitfalls of trying to
2918 determine ourselves whether two names really refer to the same
2919 file, which is not always possible in the general case. (Consider
2920 all the permutations of shared or subst'd drives, etc.) */
2922 newname
= map_w32_filename (newname
, NULL
);
2923 result
= rename (temp
, newname
);
2927 && _chmod (newname
, 0666) == 0
2928 && _unlink (newname
) == 0)
2929 result
= rename (temp
, newname
);
2935 sys_rmdir (const char * path
)
2937 return _rmdir (map_w32_filename (path
, NULL
));
2941 sys_unlink (const char * path
)
2943 path
= map_w32_filename (path
, NULL
);
2945 /* On Unix, unlink works without write permission. */
2946 _chmod (path
, 0666);
2947 return _unlink (path
);
2950 static FILETIME utc_base_ft
;
2951 static ULONGLONG utc_base
; /* In 100ns units */
2952 static int init
= 0;
2954 #define FILETIME_TO_U64(result, ft) \
2956 ULARGE_INTEGER uiTemp; \
2957 uiTemp.LowPart = (ft).dwLowDateTime; \
2958 uiTemp.HighPart = (ft).dwHighDateTime; \
2959 result = uiTemp.QuadPart; \
2963 initialize_utc_base (void)
2965 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2974 st
.wMilliseconds
= 0;
2976 SystemTimeToFileTime (&st
, &utc_base_ft
);
2977 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2981 convert_time (FILETIME ft
)
2987 initialize_utc_base ();
2991 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2994 FILETIME_TO_U64 (tmp
, ft
);
2995 return (time_t) ((tmp
- utc_base
) / 10000000L);
2999 convert_from_time_t (time_t time
, FILETIME
* pft
)
3005 initialize_utc_base ();
3009 /* time in 100ns units since 1-Jan-1601 */
3010 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3011 pft
->dwHighDateTime
= tmp
.HighPart
;
3012 pft
->dwLowDateTime
= tmp
.LowPart
;
3016 /* No reason to keep this; faking inode values either by hashing or even
3017 using the file index from GetInformationByHandle, is not perfect and
3018 so by default Emacs doesn't use the inode values on Windows.
3019 Instead, we now determine file-truename correctly (except for
3020 possible drive aliasing etc). */
3022 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3024 hashval (const unsigned char * str
)
3029 h
= (h
<< 4) + *str
++;
3035 /* Return the hash value of the canonical pathname, excluding the
3036 drive/UNC header, to get a hopefully unique inode number. */
3038 generate_inode_val (const char * name
)
3040 char fullname
[ MAX_PATH
];
3044 /* Get the truly canonical filename, if it exists. (Note: this
3045 doesn't resolve aliasing due to subst commands, or recognise hard
3047 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3050 parse_root (fullname
, &p
);
3051 /* Normal W32 filesystems are still case insensitive. */
3058 static PSECURITY_DESCRIPTOR
3059 get_file_security_desc (const char *fname
)
3061 PSECURITY_DESCRIPTOR psd
= NULL
;
3063 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3064 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3066 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3068 err
= GetLastError ();
3069 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3073 psd
= xmalloc (sd_len
);
3074 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3086 unsigned n_subauthorities
;
3088 /* Use the last sub-authority value of the RID, the relative
3089 portion of the SID, as user/group ID. */
3090 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3091 if (n_subauthorities
< 1)
3092 return 0; /* the "World" RID */
3093 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3096 /* Caching SID and account values for faster lokup. */
3099 # define FLEXIBLE_ARRAY_MEMBER
3101 # define FLEXIBLE_ARRAY_MEMBER 1
3106 struct w32_id
*next
;
3108 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3111 static struct w32_id
*w32_idlist
;
3114 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3116 struct w32_id
*tail
, *found
;
3118 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3120 if (equal_sid ((PSID
)tail
->sid
, sid
))
3129 strcpy (name
, found
->name
);
3137 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3140 struct w32_id
*new_entry
;
3142 /* We don't want to leave behind stale cache from when Emacs was
3146 sid_len
= get_length_sid (sid
);
3147 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3150 new_entry
->rid
= id
;
3151 strcpy (new_entry
->name
, name
);
3152 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3153 new_entry
->next
= w32_idlist
;
3154 w32_idlist
= new_entry
;
3163 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3164 unsigned *id
, char *nm
, int what
)
3167 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3169 SID_NAME_USE ignore
;
3171 DWORD name_len
= sizeof (name
);
3173 DWORD domain_len
= sizeof (domain
);
3179 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3180 else if (what
== GID
)
3181 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3185 if (!result
|| !is_valid_sid (sid
))
3187 else if (!w32_cached_id (sid
, id
, nm
))
3189 /* If FNAME is a UNC, we need to lookup account on the
3190 specified machine. */
3191 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3192 && fname
[2] != '\0')
3197 for (s
= fname
+ 2, p
= machine
;
3198 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3204 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3205 domain
, &domain_len
, &ignore
)
3206 || name_len
> UNLEN
+1)
3210 *id
= get_rid (sid
);
3212 w32_add_to_cache (sid
, *id
, name
);
3219 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3223 int dflt_usr
= 0, dflt_grp
= 0;
3232 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3234 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3237 /* Consider files to belong to current user/group, if we cannot get
3238 more accurate information. */
3241 st
->st_uid
= dflt_passwd
.pw_uid
;
3242 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3246 st
->st_gid
= dflt_passwd
.pw_gid
;
3247 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3251 /* Return non-zero if NAME is a potentially slow filesystem. */
3253 is_slow_fs (const char *name
)
3258 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3259 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3260 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3261 devtype
= GetDriveType (NULL
); /* use root of current drive */
3264 /* GetDriveType needs the root directory of the drive. */
3265 strncpy (drive_root
, name
, 2);
3266 drive_root
[2] = '\\';
3267 drive_root
[3] = '\0';
3268 devtype
= GetDriveType (drive_root
);
3270 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3273 /* MSVC stat function can't cope with UNC names and has other bugs, so
3274 replace it with our own. This also allows us to calculate consistent
3275 inode values without hacks in the main Emacs code. */
3277 stat (const char * path
, struct stat
* buf
)
3280 WIN32_FIND_DATA wfd
;
3282 unsigned __int64 fake_inode
;
3285 int rootdir
= FALSE
;
3286 PSECURITY_DESCRIPTOR psd
= NULL
;
3288 if (path
== NULL
|| buf
== NULL
)
3294 name
= (char *) map_w32_filename (path
, &path
);
3295 /* Must be valid filename, no wild cards or other invalid
3296 characters. We use _mbspbrk to support multibyte strings that
3297 might look to strpbrk as if they included literal *, ?, and other
3298 characters mentioned below that are disallowed by Windows
3300 if (_mbspbrk (name
, "*?|<>\""))
3306 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3307 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3308 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3313 /* Remove trailing directory separator, unless name is the root
3314 directory of a drive or UNC volume in which case ensure there
3315 is a trailing separator. */
3316 len
= strlen (name
);
3317 rootdir
= (path
>= name
+ len
- 1
3318 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3319 name
= strcpy (alloca (len
+ 2), name
);
3321 if (is_unc_volume (name
))
3323 DWORD attrs
= unc_volume_file_attributes (name
);
3328 memset (&wfd
, 0, sizeof (wfd
));
3329 wfd
.dwFileAttributes
= attrs
;
3330 wfd
.ftCreationTime
= utc_base_ft
;
3331 wfd
.ftLastAccessTime
= utc_base_ft
;
3332 wfd
.ftLastWriteTime
= utc_base_ft
;
3333 strcpy (wfd
.cFileName
, name
);
3337 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3338 strcat (name
, "\\");
3339 if (GetDriveType (name
) < 2)
3344 memset (&wfd
, 0, sizeof (wfd
));
3345 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3346 wfd
.ftCreationTime
= utc_base_ft
;
3347 wfd
.ftLastAccessTime
= utc_base_ft
;
3348 wfd
.ftLastWriteTime
= utc_base_ft
;
3349 strcpy (wfd
.cFileName
, name
);
3353 if (IS_DIRECTORY_SEP (name
[len
-1]))
3356 /* (This is hacky, but helps when doing file completions on
3357 network drives.) Optimize by using information available from
3358 active readdir if possible. */
3359 len
= strlen (dir_pathname
);
3360 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3362 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3363 && strnicmp (name
, dir_pathname
, len
) == 0
3364 && IS_DIRECTORY_SEP (name
[len
])
3365 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3367 /* This was the last entry returned by readdir. */
3368 wfd
= dir_find_data
;
3372 logon_network_drive (name
);
3374 fh
= FindFirstFile (name
, &wfd
);
3375 if (fh
== INVALID_HANDLE_VALUE
)
3384 if (!(NILP (Vw32_get_true_file_attributes
)
3385 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3386 /* No access rights required to get info. */
3387 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3388 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3389 != INVALID_HANDLE_VALUE
)
3391 /* This is more accurate in terms of gettting the correct number
3392 of links, but is quite slow (it is noticeable when Emacs is
3393 making a list of file name completions). */
3394 BY_HANDLE_FILE_INFORMATION info
;
3396 if (GetFileInformationByHandle (fh
, &info
))
3398 buf
->st_nlink
= info
.nNumberOfLinks
;
3399 /* Might as well use file index to fake inode values, but this
3400 is not guaranteed to be unique unless we keep a handle open
3401 all the time (even then there are situations where it is
3402 not unique). Reputedly, there are at most 48 bits of info
3403 (on NTFS, presumably less on FAT). */
3404 fake_inode
= info
.nFileIndexHigh
;
3406 fake_inode
+= info
.nFileIndexLow
;
3414 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3416 buf
->st_mode
= S_IFDIR
;
3420 switch (GetFileType (fh
))
3422 case FILE_TYPE_DISK
:
3423 buf
->st_mode
= S_IFREG
;
3425 case FILE_TYPE_PIPE
:
3426 buf
->st_mode
= S_IFIFO
;
3428 case FILE_TYPE_CHAR
:
3429 case FILE_TYPE_UNKNOWN
:
3431 buf
->st_mode
= S_IFCHR
;
3435 psd
= get_file_security_desc (name
);
3436 get_file_owner_and_group (psd
, name
, buf
);
3440 /* Don't bother to make this information more accurate. */
3441 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3446 get_file_owner_and_group (NULL
, name
, buf
);
3451 /* Not sure if there is any point in this. */
3452 if (!NILP (Vw32_generate_fake_inodes
))
3453 fake_inode
= generate_inode_val (name
);
3454 else if (fake_inode
== 0)
3456 /* For want of something better, try to make everything unique. */
3457 static DWORD gen_num
= 0;
3458 fake_inode
= ++gen_num
;
3462 /* MSVC defines _ino_t to be short; other libc's might not. */
3463 if (sizeof (buf
->st_ino
) == 2)
3464 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3466 buf
->st_ino
= fake_inode
;
3468 /* volume_info is set indirectly by map_w32_filename */
3469 buf
->st_dev
= volume_info
.serialnum
;
3470 buf
->st_rdev
= volume_info
.serialnum
;
3472 buf
->st_size
= wfd
.nFileSizeHigh
;
3473 buf
->st_size
<<= 32;
3474 buf
->st_size
+= wfd
.nFileSizeLow
;
3476 /* Convert timestamps to Unix format. */
3477 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3478 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3479 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3480 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3481 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3483 /* determine rwx permissions */
3484 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3485 permission
= S_IREAD
;
3487 permission
= S_IREAD
| S_IWRITE
;
3489 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3490 permission
|= S_IEXEC
;
3491 else if (is_exec (name
))
3492 permission
|= S_IEXEC
;
3494 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3499 /* Provide fstat and utime as well as stat for consistent handling of
3502 fstat (int desc
, struct stat
* buf
)
3504 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3505 BY_HANDLE_FILE_INFORMATION info
;
3506 unsigned __int64 fake_inode
;
3509 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3511 case FILE_TYPE_DISK
:
3512 buf
->st_mode
= S_IFREG
;
3513 if (!GetFileInformationByHandle (fh
, &info
))
3519 case FILE_TYPE_PIPE
:
3520 buf
->st_mode
= S_IFIFO
;
3522 case FILE_TYPE_CHAR
:
3523 case FILE_TYPE_UNKNOWN
:
3525 buf
->st_mode
= S_IFCHR
;
3527 memset (&info
, 0, sizeof (info
));
3528 info
.dwFileAttributes
= 0;
3529 info
.ftCreationTime
= utc_base_ft
;
3530 info
.ftLastAccessTime
= utc_base_ft
;
3531 info
.ftLastWriteTime
= utc_base_ft
;
3534 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3535 buf
->st_mode
= S_IFDIR
;
3537 buf
->st_nlink
= info
.nNumberOfLinks
;
3538 /* Might as well use file index to fake inode values, but this
3539 is not guaranteed to be unique unless we keep a handle open
3540 all the time (even then there are situations where it is
3541 not unique). Reputedly, there are at most 48 bits of info
3542 (on NTFS, presumably less on FAT). */
3543 fake_inode
= info
.nFileIndexHigh
;
3545 fake_inode
+= info
.nFileIndexLow
;
3547 /* MSVC defines _ino_t to be short; other libc's might not. */
3548 if (sizeof (buf
->st_ino
) == 2)
3549 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3551 buf
->st_ino
= fake_inode
;
3553 /* Consider files to belong to current user.
3554 FIXME: this should use GetSecurityInfo API, but it is only
3555 available for _WIN32_WINNT >= 0x501. */
3556 buf
->st_uid
= dflt_passwd
.pw_uid
;
3557 buf
->st_gid
= dflt_passwd
.pw_gid
;
3558 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3559 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3561 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3562 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3564 buf
->st_size
= info
.nFileSizeHigh
;
3565 buf
->st_size
<<= 32;
3566 buf
->st_size
+= info
.nFileSizeLow
;
3568 /* Convert timestamps to Unix format. */
3569 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3570 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3571 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3572 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3573 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3575 /* determine rwx permissions */
3576 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3577 permission
= S_IREAD
;
3579 permission
= S_IREAD
| S_IWRITE
;
3581 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3582 permission
|= S_IEXEC
;
3585 #if 0 /* no way of knowing the filename */
3586 char * p
= strrchr (name
, '.');
3588 (xstrcasecmp (p
, ".exe") == 0 ||
3589 xstrcasecmp (p
, ".com") == 0 ||
3590 xstrcasecmp (p
, ".bat") == 0 ||
3591 xstrcasecmp (p
, ".cmd") == 0))
3592 permission
|= S_IEXEC
;
3596 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3602 utime (const char *name
, struct utimbuf
*times
)
3604 struct utimbuf deftime
;
3611 deftime
.modtime
= deftime
.actime
= time (NULL
);
3615 /* Need write access to set times. */
3616 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3617 0, OPEN_EXISTING
, 0, NULL
);
3620 convert_from_time_t (times
->actime
, &atime
);
3621 convert_from_time_t (times
->modtime
, &mtime
);
3622 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3639 /* Symlink-related functions that always fail. Used in fileio.c and in
3640 sysdep.c to avoid #ifdef's. */
3642 symlink (char const *dummy1
, char const *dummy2
)
3649 readlink (const char *name
, char *dummy1
, size_t dummy2
)
3651 /* `access' is much faster than `stat' on MS-Windows. */
3652 if (sys_access (name
, 0) == 0)
3658 careadlinkat (int fd
, char const *filename
,
3659 char *buffer
, size_t buffer_size
,
3660 struct allocator
const *alloc
,
3661 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
3668 careadlinkatcwd (int fd
, char const *filename
, char *buffer
,
3672 return readlink (filename
, buffer
, buffer_size
);
3676 /* Support for browsing other processes and their attributes. See
3677 process.c for the Lisp bindings. */
3679 /* Helper wrapper functions. */
3681 static HANDLE WINAPI
3682 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
3684 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3686 if (g_b_init_create_toolhelp32_snapshot
== 0)
3688 g_b_init_create_toolhelp32_snapshot
= 1;
3689 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3690 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3691 "CreateToolhelp32Snapshot");
3693 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3695 return INVALID_HANDLE_VALUE
;
3697 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3701 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3703 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3705 if (g_b_init_process32_first
== 0)
3707 g_b_init_process32_first
= 1;
3708 s_pfn_Process32_First
= (Process32First_Proc
)
3709 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3712 if (s_pfn_Process32_First
== NULL
)
3716 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3720 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3722 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3724 if (g_b_init_process32_next
== 0)
3726 g_b_init_process32_next
= 1;
3727 s_pfn_Process32_Next
= (Process32Next_Proc
)
3728 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3731 if (s_pfn_Process32_Next
== NULL
)
3735 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3739 open_thread_token (HANDLE ThreadHandle
,
3740 DWORD DesiredAccess
,
3742 PHANDLE TokenHandle
)
3744 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3745 HMODULE hm_advapi32
= NULL
;
3746 if (is_windows_9x () == TRUE
)
3748 SetLastError (ERROR_NOT_SUPPORTED
);
3751 if (g_b_init_open_thread_token
== 0)
3753 g_b_init_open_thread_token
= 1;
3754 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3755 s_pfn_Open_Thread_Token
=
3756 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3758 if (s_pfn_Open_Thread_Token
== NULL
)
3760 SetLastError (ERROR_NOT_SUPPORTED
);
3764 s_pfn_Open_Thread_Token (
3773 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3775 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3776 HMODULE hm_advapi32
= NULL
;
3777 if (is_windows_9x () == TRUE
)
3781 if (g_b_init_impersonate_self
== 0)
3783 g_b_init_impersonate_self
= 1;
3784 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3785 s_pfn_Impersonate_Self
=
3786 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3788 if (s_pfn_Impersonate_Self
== NULL
)
3792 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3796 revert_to_self (void)
3798 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3799 HMODULE hm_advapi32
= NULL
;
3800 if (is_windows_9x () == TRUE
)
3804 if (g_b_init_revert_to_self
== 0)
3806 g_b_init_revert_to_self
= 1;
3807 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3808 s_pfn_Revert_To_Self
=
3809 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3811 if (s_pfn_Revert_To_Self
== NULL
)
3815 return s_pfn_Revert_To_Self ();
3819 get_process_memory_info (HANDLE h_proc
,
3820 PPROCESS_MEMORY_COUNTERS mem_counters
,
3823 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3824 HMODULE hm_psapi
= NULL
;
3825 if (is_windows_9x () == TRUE
)
3829 if (g_b_init_get_process_memory_info
== 0)
3831 g_b_init_get_process_memory_info
= 1;
3832 hm_psapi
= LoadLibrary ("Psapi.dll");
3834 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3835 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3837 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3841 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3845 get_process_working_set_size (HANDLE h_proc
,
3849 static GetProcessWorkingSetSize_Proc
3850 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3852 if (is_windows_9x () == TRUE
)
3856 if (g_b_init_get_process_working_set_size
== 0)
3858 g_b_init_get_process_working_set_size
= 1;
3859 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3860 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3861 "GetProcessWorkingSetSize");
3863 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3867 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3871 global_memory_status (MEMORYSTATUS
*buf
)
3873 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3875 if (is_windows_9x () == TRUE
)
3879 if (g_b_init_global_memory_status
== 0)
3881 g_b_init_global_memory_status
= 1;
3882 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3883 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3884 "GlobalMemoryStatus");
3886 if (s_pfn_Global_Memory_Status
== NULL
)
3890 return s_pfn_Global_Memory_Status (buf
);
3894 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
3896 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3898 if (is_windows_9x () == TRUE
)
3902 if (g_b_init_global_memory_status_ex
== 0)
3904 g_b_init_global_memory_status_ex
= 1;
3905 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3906 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3907 "GlobalMemoryStatusEx");
3909 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3913 return s_pfn_Global_Memory_Status_Ex (buf
);
3917 list_system_processes (void)
3919 struct gcpro gcpro1
;
3920 Lisp_Object proclist
= Qnil
;
3923 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3925 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3927 PROCESSENTRY32 proc_entry
;
3933 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3934 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3935 res
= process32_next (h_snapshot
, &proc_entry
))
3937 proc_id
= proc_entry
.th32ProcessID
;
3938 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3941 CloseHandle (h_snapshot
);
3943 proclist
= Fnreverse (proclist
);
3950 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3952 TOKEN_PRIVILEGES priv
;
3953 DWORD priv_size
= sizeof (priv
);
3954 DWORD opriv_size
= sizeof (*old_priv
);
3955 HANDLE h_token
= NULL
;
3956 HANDLE h_thread
= GetCurrentThread ();
3960 res
= open_thread_token (h_thread
,
3961 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3963 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3965 if (impersonate_self (SecurityImpersonation
))
3966 res
= open_thread_token (h_thread
,
3967 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3972 priv
.PrivilegeCount
= 1;
3973 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3974 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3975 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3976 old_priv
, &opriv_size
)
3977 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3981 CloseHandle (h_token
);
3987 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3989 DWORD priv_size
= sizeof (*priv
);
3990 HANDLE h_token
= NULL
;
3993 if (open_thread_token (GetCurrentThread (),
3994 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3997 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
3998 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4002 CloseHandle (h_token
);
4008 ltime (long time_sec
, long time_usec
)
4010 return list3 (make_number ((time_sec
>> 16) & 0xffff),
4011 make_number (time_sec
& 0xffff),
4012 make_number (time_usec
));
4015 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
4018 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4019 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4022 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4023 ULONGLONG tem1
, tem2
, tem3
, tem
;
4026 || !get_process_times_fn
4027 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4028 &ft_kernel
, &ft_user
))
4031 GetSystemTimeAsFileTime (&ft_current
);
4033 FILETIME_TO_U64 (tem1
, ft_kernel
);
4035 *stime
= U64_TO_LISP_TIME (tem1
);
4037 FILETIME_TO_U64 (tem2
, ft_user
);
4039 *utime
= U64_TO_LISP_TIME (tem2
);
4042 *ttime
= U64_TO_LISP_TIME (tem3
);
4044 FILETIME_TO_U64 (tem
, ft_creation
);
4045 /* Process no 4 (System) returns zero creation time. */
4047 tem
= (tem
- utc_base
) / 10L;
4048 *ctime
= U64_TO_LISP_TIME (tem
);
4052 FILETIME_TO_U64 (tem3
, ft_current
);
4053 tem
= (tem3
- utc_base
) / 10L - tem
;
4055 *etime
= U64_TO_LISP_TIME (tem
);
4059 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4070 system_process_attributes (Lisp_Object pid
)
4072 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4073 Lisp_Object attrs
= Qnil
;
4074 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4075 HANDLE h_snapshot
, h_proc
;
4078 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4079 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4080 DWORD glength
= sizeof (gname
);
4081 HANDLE token
= NULL
;
4082 SID_NAME_USE user_type
;
4083 unsigned char *buf
= NULL
;
4085 TOKEN_USER user_token
;
4086 TOKEN_PRIMARY_GROUP group_token
;
4089 PROCESS_MEMORY_COUNTERS mem
;
4090 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4091 DWORD minrss
, maxrss
;
4093 MEMORY_STATUS_EX memstex
;
4094 double totphys
= 0.0;
4095 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4097 BOOL result
= FALSE
;
4099 CHECK_NUMBER_OR_FLOAT (pid
);
4100 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4102 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4104 GCPRO3 (attrs
, decoded_cmd
, tem
);
4106 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4111 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4112 for (res
= process32_first (h_snapshot
, &pe
); res
;
4113 res
= process32_next (h_snapshot
, &pe
))
4115 if (proc_id
== pe
.th32ProcessID
)
4118 decoded_cmd
= build_string ("Idle");
4121 /* Decode the command name from locale-specific
4123 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4124 strlen (pe
.szExeFile
));
4126 code_convert_string_norecord (cmd_str
,
4127 Vlocale_coding_system
, 0);
4129 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4130 attrs
= Fcons (Fcons (Qppid
,
4131 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4133 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4135 attrs
= Fcons (Fcons (Qthcount
,
4136 make_fixnum_or_float (pe
.cntThreads
)),
4143 CloseHandle (h_snapshot
);
4152 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4154 /* If we were denied a handle to the process, try again after
4155 enabling the SeDebugPrivilege in our process. */
4158 TOKEN_PRIVILEGES priv_current
;
4160 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4162 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4164 restore_privilege (&priv_current
);
4170 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4173 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4174 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4176 buf
= xmalloc (blen
);
4177 result
= get_token_information (token
, TokenUser
,
4178 (LPVOID
)buf
, blen
, &needed
);
4181 memcpy (&user_token
, buf
, sizeof (user_token
));
4182 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4184 euid
= get_rid (user_token
.User
.Sid
);
4185 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4190 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4193 strcpy (uname
, "unknown");
4197 ulength
= strlen (uname
);
4203 /* Determine a reasonable euid and gid values. */
4204 if (xstrcasecmp ("administrator", uname
) == 0)
4206 euid
= 500; /* well-known Administrator uid */
4207 egid
= 513; /* well-known None gid */
4211 /* Get group id and name. */
4212 result
= get_token_information (token
, TokenPrimaryGroup
,
4213 (LPVOID
)buf
, blen
, &needed
);
4214 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4216 buf
= xrealloc (buf
, blen
= needed
);
4217 result
= get_token_information (token
, TokenPrimaryGroup
,
4218 (LPVOID
)buf
, blen
, &needed
);
4222 memcpy (&group_token
, buf
, sizeof (group_token
));
4223 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4225 egid
= get_rid (group_token
.PrimaryGroup
);
4226 dlength
= sizeof (domain
);
4228 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4229 gname
, &glength
, NULL
, &dlength
,
4232 w32_add_to_cache (group_token
.PrimaryGroup
,
4236 strcpy (gname
, "None");
4240 glength
= strlen (gname
);
4248 if (!is_windows_9x ())
4250 /* We couldn't open the process token, presumably because of
4251 insufficient access rights. Assume this process is run
4253 strcpy (uname
, "SYSTEM");
4254 strcpy (gname
, "None");
4255 euid
= 18; /* SYSTEM */
4256 egid
= 513; /* None */
4257 glength
= strlen (gname
);
4258 ulength
= strlen (uname
);
4260 /* If we are running under Windows 9X, where security calls are
4261 not supported, we assume all processes are run by the current
4263 else if (GetUserName (uname
, &ulength
))
4265 if (xstrcasecmp ("administrator", uname
) == 0)
4270 strcpy (gname
, "None");
4271 glength
= strlen (gname
);
4272 ulength
= strlen (uname
);
4278 strcpy (uname
, "administrator");
4279 ulength
= strlen (uname
);
4280 strcpy (gname
, "None");
4281 glength
= strlen (gname
);
4284 CloseHandle (token
);
4287 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4288 tem
= make_unibyte_string (uname
, ulength
);
4289 attrs
= Fcons (Fcons (Quser
,
4290 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4292 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4293 tem
= make_unibyte_string (gname
, glength
);
4294 attrs
= Fcons (Fcons (Qgroup
,
4295 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4298 if (global_memory_status_ex (&memstex
))
4299 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4300 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4302 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4303 double, so we need to do this for it... */
4305 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4306 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4307 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4309 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4311 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4312 else if (global_memory_status (&memst
))
4313 totphys
= memst
.dwTotalPhys
/ 1024.0;
4316 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4319 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4321 attrs
= Fcons (Fcons (Qmajflt
,
4322 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4324 attrs
= Fcons (Fcons (Qvsize
,
4325 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4327 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4329 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4332 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4334 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4336 attrs
= Fcons (Fcons (Qmajflt
,
4337 make_fixnum_or_float (mem
.PageFaultCount
)),
4339 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4341 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4344 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4346 DWORD rss
= maxrss
/ 1024;
4348 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4350 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4353 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4355 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4356 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4357 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4358 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4359 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4360 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4363 /* FIXME: Retrieve command line by walking the PEB of the process. */
4366 CloseHandle (h_proc
);
4372 /* Wrappers for winsock functions to map between our file descriptors
4373 and winsock's handles; also set h_errno for convenience.
4375 To allow Emacs to run on systems which don't have winsock support
4376 installed, we dynamically link to winsock on startup if present, and
4377 otherwise provide the minimum necessary functionality
4378 (eg. gethostname). */
4380 /* function pointers for relevant socket functions */
4381 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4382 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4383 int (PASCAL
*pfn_WSAGetLastError
) (void);
4384 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4385 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4386 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4387 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4388 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4389 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4390 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4391 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4392 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4393 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4394 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4395 int (PASCAL
*pfn_WSACleanup
) (void);
4397 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4398 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4399 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4400 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4401 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4402 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4403 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4404 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4405 const char * optval
, int optlen
);
4406 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4407 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4409 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4410 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4411 struct sockaddr
* from
, int * fromlen
);
4412 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4413 const struct sockaddr
* to
, int tolen
);
4415 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4416 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4417 #ifndef HANDLE_FLAG_INHERIT
4418 #define HANDLE_FLAG_INHERIT 1
4422 static int winsock_inuse
;
4427 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4429 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4430 after WSAStartup returns successfully, but it seems reasonable
4431 to allow unloading winsock anyway in that case. */
4432 if (pfn_WSACleanup () == 0 ||
4433 pfn_WSAGetLastError () == WSAENETDOWN
)
4435 if (FreeLibrary (winsock_lib
))
4444 init_winsock (int load_now
)
4446 WSADATA winsockData
;
4448 if (winsock_lib
!= NULL
)
4451 pfn_SetHandleInformation
4452 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4453 "SetHandleInformation");
4455 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4457 if (winsock_lib
!= NULL
)
4459 /* dynamically link to socket functions */
4461 #define LOAD_PROC(fn) \
4462 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4465 LOAD_PROC (WSAStartup
);
4466 LOAD_PROC (WSASetLastError
);
4467 LOAD_PROC (WSAGetLastError
);
4468 LOAD_PROC (WSAEventSelect
);
4469 LOAD_PROC (WSACreateEvent
);
4470 LOAD_PROC (WSACloseEvent
);
4473 LOAD_PROC (connect
);
4474 LOAD_PROC (ioctlsocket
);
4477 LOAD_PROC (closesocket
);
4478 LOAD_PROC (shutdown
);
4481 LOAD_PROC (inet_addr
);
4482 LOAD_PROC (gethostname
);
4483 LOAD_PROC (gethostbyname
);
4484 LOAD_PROC (getservbyname
);
4485 LOAD_PROC (getpeername
);
4486 LOAD_PROC (WSACleanup
);
4487 LOAD_PROC (setsockopt
);
4489 LOAD_PROC (getsockname
);
4491 LOAD_PROC (recvfrom
);
4495 /* specify version 1.1 of winsock */
4496 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4498 if (winsockData
.wVersion
!= 0x101)
4503 /* Report that winsock exists and is usable, but leave
4504 socket functions disabled. I am assuming that calling
4505 WSAStartup does not require any network interaction,
4506 and in particular does not cause or require a dial-up
4507 connection to be established. */
4510 FreeLibrary (winsock_lib
);
4518 FreeLibrary (winsock_lib
);
4528 /* function to set h_errno for compatibility; map winsock error codes to
4529 normal system codes where they overlap (non-overlapping definitions
4530 are already in <sys/socket.h> */
4534 if (winsock_lib
== NULL
)
4537 h_errno
= pfn_WSAGetLastError ();
4541 case WSAEACCES
: h_errno
= EACCES
; break;
4542 case WSAEBADF
: h_errno
= EBADF
; break;
4543 case WSAEFAULT
: h_errno
= EFAULT
; break;
4544 case WSAEINTR
: h_errno
= EINTR
; break;
4545 case WSAEINVAL
: h_errno
= EINVAL
; break;
4546 case WSAEMFILE
: h_errno
= EMFILE
; break;
4547 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4548 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4556 if (h_errno
== 0 && winsock_lib
!= NULL
)
4557 pfn_WSASetLastError (0);
4560 /* Extend strerror to handle the winsock-specific error codes. */
4564 } _wsa_errlist
[] = {
4565 {WSAEINTR
, "Interrupted function call"},
4566 {WSAEBADF
, "Bad file descriptor"},
4567 {WSAEACCES
, "Permission denied"},
4568 {WSAEFAULT
, "Bad address"},
4569 {WSAEINVAL
, "Invalid argument"},
4570 {WSAEMFILE
, "Too many open files"},
4572 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
4573 {WSAEINPROGRESS
, "Operation now in progress"},
4574 {WSAEALREADY
, "Operation already in progress"},
4575 {WSAENOTSOCK
, "Socket operation on non-socket"},
4576 {WSAEDESTADDRREQ
, "Destination address required"},
4577 {WSAEMSGSIZE
, "Message too long"},
4578 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
4579 {WSAENOPROTOOPT
, "Bad protocol option"},
4580 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
4581 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
4582 {WSAEOPNOTSUPP
, "Operation not supported"},
4583 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
4584 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
4585 {WSAEADDRINUSE
, "Address already in use"},
4586 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
4587 {WSAENETDOWN
, "Network is down"},
4588 {WSAENETUNREACH
, "Network is unreachable"},
4589 {WSAENETRESET
, "Network dropped connection on reset"},
4590 {WSAECONNABORTED
, "Software caused connection abort"},
4591 {WSAECONNRESET
, "Connection reset by peer"},
4592 {WSAENOBUFS
, "No buffer space available"},
4593 {WSAEISCONN
, "Socket is already connected"},
4594 {WSAENOTCONN
, "Socket is not connected"},
4595 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
4596 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
4597 {WSAETIMEDOUT
, "Connection timed out"},
4598 {WSAECONNREFUSED
, "Connection refused"},
4599 {WSAELOOP
, "Network loop"}, /* not sure */
4600 {WSAENAMETOOLONG
, "Name is too long"},
4601 {WSAEHOSTDOWN
, "Host is down"},
4602 {WSAEHOSTUNREACH
, "No route to host"},
4603 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
4604 {WSAEPROCLIM
, "Too many processes"},
4605 {WSAEUSERS
, "Too many users"}, /* not sure */
4606 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
4607 {WSAESTALE
, "Data is stale"}, /* not sure */
4608 {WSAEREMOTE
, "Remote error"}, /* not sure */
4610 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
4611 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
4612 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
4613 {WSAEDISCON
, "Graceful shutdown in progress"},
4615 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
4616 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
4617 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
4618 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
4619 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
4620 {WSASYSCALLFAILURE
, "System call failure"},
4621 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
4622 {WSATYPE_NOT_FOUND
, "Class type not found"},
4623 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
4624 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
4625 {WSAEREFUSED
, "Operation refused"}, /* not sure */
4628 {WSAHOST_NOT_FOUND
, "Host not found"},
4629 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
4630 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
4631 {WSANO_DATA
, "Valid name, no data record of requested type"},
4637 sys_strerror (int error_no
)
4640 static char unknown_msg
[40];
4642 if (error_no
>= 0 && error_no
< sys_nerr
)
4643 return sys_errlist
[error_no
];
4645 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4646 if (_wsa_errlist
[i
].errnum
== error_no
)
4647 return _wsa_errlist
[i
].msg
;
4649 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4653 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4654 but I believe the method of keeping the socket handle separate (and
4655 insuring it is not inheritable) is the correct one. */
4657 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4659 static int socket_to_fd (SOCKET s
);
4662 sys_socket (int af
, int type
, int protocol
)
4666 if (winsock_lib
== NULL
)
4669 return INVALID_SOCKET
;
4674 /* call the real socket function */
4675 s
= pfn_socket (af
, type
, protocol
);
4677 if (s
!= INVALID_SOCKET
)
4678 return socket_to_fd (s
);
4684 /* Convert a SOCKET to a file descriptor. */
4686 socket_to_fd (SOCKET s
)
4691 /* Although under NT 3.5 _open_osfhandle will accept a socket
4692 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4693 that does not work under NT 3.1. However, we can get the same
4694 effect by using a backdoor function to replace an existing
4695 descriptor handle with the one we want. */
4697 /* allocate a file descriptor (with appropriate flags) */
4698 fd
= _open ("NUL:", _O_RDWR
);
4701 /* Make a non-inheritable copy of the socket handle. Note
4702 that it is possible that sockets aren't actually kernel
4703 handles, which appears to be the case on Windows 9x when
4704 the MS Proxy winsock client is installed. */
4706 /* Apparently there is a bug in NT 3.51 with some service
4707 packs, which prevents using DuplicateHandle to make a
4708 socket handle non-inheritable (causes WSACleanup to
4709 hang). The work-around is to use SetHandleInformation
4710 instead if it is available and implemented. */
4711 if (pfn_SetHandleInformation
)
4713 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4717 HANDLE parent
= GetCurrentProcess ();
4718 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4720 if (DuplicateHandle (parent
,
4726 DUPLICATE_SAME_ACCESS
))
4728 /* It is possible that DuplicateHandle succeeds even
4729 though the socket wasn't really a kernel handle,
4730 because a real handle has the same value. So
4731 test whether the new handle really is a socket. */
4732 long nonblocking
= 0;
4733 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4735 pfn_closesocket (s
);
4740 CloseHandle (new_s
);
4745 fd_info
[fd
].hnd
= (HANDLE
) s
;
4747 /* set our own internal flags */
4748 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4754 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4756 /* attach child_process to fd_info */
4757 if (fd_info
[ fd
].cp
!= NULL
)
4759 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4763 fd_info
[ fd
].cp
= cp
;
4766 winsock_inuse
++; /* count open sockets */
4773 pfn_closesocket (s
);
4779 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4781 if (winsock_lib
== NULL
)
4784 return SOCKET_ERROR
;
4788 if (fd_info
[s
].flags
& FILE_SOCKET
)
4790 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4791 if (rc
== SOCKET_ERROR
)
4796 return SOCKET_ERROR
;
4800 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4802 if (winsock_lib
== NULL
)
4805 return SOCKET_ERROR
;
4809 if (fd_info
[s
].flags
& FILE_SOCKET
)
4811 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4812 if (rc
== SOCKET_ERROR
)
4817 return SOCKET_ERROR
;
4821 sys_htons (u_short hostshort
)
4823 return (winsock_lib
!= NULL
) ?
4824 pfn_htons (hostshort
) : hostshort
;
4828 sys_ntohs (u_short netshort
)
4830 return (winsock_lib
!= NULL
) ?
4831 pfn_ntohs (netshort
) : netshort
;
4835 sys_inet_addr (const char * cp
)
4837 return (winsock_lib
!= NULL
) ?
4838 pfn_inet_addr (cp
) : INADDR_NONE
;
4842 sys_gethostname (char * name
, int namelen
)
4844 if (winsock_lib
!= NULL
)
4845 return pfn_gethostname (name
, namelen
);
4847 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4848 return !GetComputerName (name
, (DWORD
*)&namelen
);
4851 return SOCKET_ERROR
;
4855 sys_gethostbyname (const char * name
)
4857 struct hostent
* host
;
4859 if (winsock_lib
== NULL
)
4866 host
= pfn_gethostbyname (name
);
4873 sys_getservbyname (const char * name
, const char * proto
)
4875 struct servent
* serv
;
4877 if (winsock_lib
== NULL
)
4884 serv
= pfn_getservbyname (name
, proto
);
4891 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4893 if (winsock_lib
== NULL
)
4896 return SOCKET_ERROR
;
4900 if (fd_info
[s
].flags
& FILE_SOCKET
)
4902 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4903 if (rc
== SOCKET_ERROR
)
4908 return SOCKET_ERROR
;
4912 sys_shutdown (int s
, int how
)
4914 if (winsock_lib
== NULL
)
4917 return SOCKET_ERROR
;
4921 if (fd_info
[s
].flags
& FILE_SOCKET
)
4923 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4924 if (rc
== SOCKET_ERROR
)
4929 return SOCKET_ERROR
;
4933 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4935 if (winsock_lib
== NULL
)
4938 return SOCKET_ERROR
;
4942 if (fd_info
[s
].flags
& FILE_SOCKET
)
4944 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4945 (const char *)optval
, optlen
);
4946 if (rc
== SOCKET_ERROR
)
4951 return SOCKET_ERROR
;
4955 sys_listen (int s
, int backlog
)
4957 if (winsock_lib
== NULL
)
4960 return SOCKET_ERROR
;
4964 if (fd_info
[s
].flags
& FILE_SOCKET
)
4966 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4967 if (rc
== SOCKET_ERROR
)
4970 fd_info
[s
].flags
|= FILE_LISTEN
;
4974 return SOCKET_ERROR
;
4978 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4980 if (winsock_lib
== NULL
)
4983 return SOCKET_ERROR
;
4987 if (fd_info
[s
].flags
& FILE_SOCKET
)
4989 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4990 if (rc
== SOCKET_ERROR
)
4995 return SOCKET_ERROR
;
4999 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
5001 if (winsock_lib
== NULL
)
5008 if (fd_info
[s
].flags
& FILE_LISTEN
)
5010 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5012 if (t
== INVALID_SOCKET
)
5015 fd
= socket_to_fd (t
);
5017 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5018 ResetEvent (fd_info
[s
].cp
->char_avail
);
5026 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5027 struct sockaddr
* from
, int * fromlen
)
5029 if (winsock_lib
== NULL
)
5032 return SOCKET_ERROR
;
5036 if (fd_info
[s
].flags
& FILE_SOCKET
)
5038 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5039 if (rc
== SOCKET_ERROR
)
5044 return SOCKET_ERROR
;
5048 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5049 const struct sockaddr
* to
, int tolen
)
5051 if (winsock_lib
== NULL
)
5054 return SOCKET_ERROR
;
5058 if (fd_info
[s
].flags
& FILE_SOCKET
)
5060 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5061 if (rc
== SOCKET_ERROR
)
5066 return SOCKET_ERROR
;
5069 /* Windows does not have an fcntl function. Provide an implementation
5070 solely for making sockets non-blocking. */
5072 fcntl (int s
, int cmd
, int options
)
5074 if (winsock_lib
== NULL
)
5081 if (fd_info
[s
].flags
& FILE_SOCKET
)
5083 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5085 unsigned long nblock
= 1;
5086 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5087 if (rc
== SOCKET_ERROR
)
5089 /* Keep track of the fact that we set this to non-blocking. */
5090 fd_info
[s
].flags
|= FILE_NDELAY
;
5096 return SOCKET_ERROR
;
5100 return SOCKET_ERROR
;
5104 /* Shadow main io functions: we need to handle pipes and sockets more
5105 intelligently, and implement non-blocking mode as well. */
5118 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5120 child_process
* cp
= fd_info
[fd
].cp
;
5122 fd_info
[fd
].cp
= NULL
;
5124 if (CHILD_ACTIVE (cp
))
5126 /* if last descriptor to active child_process then cleanup */
5128 for (i
= 0; i
< MAXDESC
; i
++)
5132 if (fd_info
[i
].cp
== cp
)
5137 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5139 if (winsock_lib
== NULL
) abort ();
5141 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5142 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5144 winsock_inuse
--; /* count open sockets */
5151 /* Note that sockets do not need special treatment here (at least on
5152 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5153 closesocket is equivalent to CloseHandle, which is to be expected
5154 because socket handles are fully fledged kernel handles. */
5157 if (rc
== 0 && fd
< MAXDESC
)
5158 fd_info
[fd
].flags
= 0;
5169 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5171 /* duplicate our internal info as well */
5172 fd_info
[new_fd
] = fd_info
[fd
];
5178 sys_dup2 (int src
, int dst
)
5182 if (dst
< 0 || dst
>= MAXDESC
)
5188 /* make sure we close the destination first if it's a pipe or socket */
5189 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5192 rc
= _dup2 (src
, dst
);
5195 /* duplicate our internal info as well */
5196 fd_info
[dst
] = fd_info
[src
];
5201 /* Unix pipe() has only one arg */
5203 sys_pipe (int * phandles
)
5208 /* make pipe handles non-inheritable; when we spawn a child, we
5209 replace the relevant handle with an inheritable one. Also put
5210 pipes into binary mode; we will do text mode translation ourselves
5212 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5216 /* Protect against overflow, since Windows can open more handles than
5217 our fd_info array has room for. */
5218 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5220 _close (phandles
[0]);
5221 _close (phandles
[1]);
5226 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5227 fd_info
[phandles
[0]].flags
= flags
;
5229 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5230 fd_info
[phandles
[1]].flags
= flags
;
5237 /* Function to do blocking read of one byte, needed to implement
5238 select. It is only allowed on sockets and pipes. */
5240 _sys_read_ahead (int fd
)
5245 if (fd
< 0 || fd
>= MAXDESC
)
5246 return STATUS_READ_ERROR
;
5248 cp
= fd_info
[fd
].cp
;
5250 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5251 return STATUS_READ_ERROR
;
5253 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5254 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5256 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5260 cp
->status
= STATUS_READ_IN_PROGRESS
;
5262 if (fd_info
[fd
].flags
& FILE_PIPE
)
5264 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5266 /* Give subprocess time to buffer some more output for us before
5267 reporting that input is available; we need this because Windows 95
5268 connects DOS programs to pipes by making the pipe appear to be
5269 the normal console stdout - as a result most DOS programs will
5270 write to stdout without buffering, ie. one character at a
5271 time. Even some W32 programs do this - "dir" in a command
5272 shell on NT is very slow if we don't do this. */
5275 int wait
= w32_pipe_read_delay
;
5281 /* Yield remainder of our time slice, effectively giving a
5282 temporary priority boost to the child process. */
5286 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5288 HANDLE hnd
= fd_info
[fd
].hnd
;
5289 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5292 /* Configure timeouts for blocking read. */
5293 if (!GetCommTimeouts (hnd
, &ct
))
5294 return STATUS_READ_ERROR
;
5295 ct
.ReadIntervalTimeout
= 0;
5296 ct
.ReadTotalTimeoutMultiplier
= 0;
5297 ct
.ReadTotalTimeoutConstant
= 0;
5298 if (!SetCommTimeouts (hnd
, &ct
))
5299 return STATUS_READ_ERROR
;
5301 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5303 if (GetLastError () != ERROR_IO_PENDING
)
5304 return STATUS_READ_ERROR
;
5305 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5306 return STATUS_READ_ERROR
;
5309 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5311 unsigned long nblock
= 0;
5312 /* We always want this to block, so temporarily disable NDELAY. */
5313 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5314 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5316 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5318 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5321 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5325 if (rc
== sizeof (char))
5326 cp
->status
= STATUS_READ_SUCCEEDED
;
5328 cp
->status
= STATUS_READ_FAILED
;
5334 _sys_wait_accept (int fd
)
5340 if (fd
< 0 || fd
>= MAXDESC
)
5341 return STATUS_READ_ERROR
;
5343 cp
= fd_info
[fd
].cp
;
5345 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5346 return STATUS_READ_ERROR
;
5348 cp
->status
= STATUS_READ_FAILED
;
5350 hEv
= pfn_WSACreateEvent ();
5351 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5352 if (rc
!= SOCKET_ERROR
)
5354 rc
= WaitForSingleObject (hEv
, INFINITE
);
5355 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5356 if (rc
== WAIT_OBJECT_0
)
5357 cp
->status
= STATUS_READ_SUCCEEDED
;
5359 pfn_WSACloseEvent (hEv
);
5365 sys_read (int fd
, char * buffer
, unsigned int count
)
5370 char * orig_buffer
= buffer
;
5378 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5380 child_process
*cp
= fd_info
[fd
].cp
;
5382 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5390 /* re-read CR carried over from last read */
5391 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5393 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5397 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5400 /* presence of a child_process structure means we are operating in
5401 non-blocking mode - otherwise we just call _read directly.
5402 Note that the child_process structure might be missing because
5403 reap_subprocess has been called; in this case the pipe is
5404 already broken, so calling _read on it is okay. */
5407 int current_status
= cp
->status
;
5409 switch (current_status
)
5411 case STATUS_READ_FAILED
:
5412 case STATUS_READ_ERROR
:
5413 /* report normal EOF if nothing in buffer */
5415 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5418 case STATUS_READ_READY
:
5419 case STATUS_READ_IN_PROGRESS
:
5420 DebPrint (("sys_read called when read is in progress\n"));
5421 errno
= EWOULDBLOCK
;
5424 case STATUS_READ_SUCCEEDED
:
5425 /* consume read-ahead char */
5426 *buffer
++ = cp
->chr
;
5429 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5430 ResetEvent (cp
->char_avail
);
5432 case STATUS_READ_ACKNOWLEDGED
:
5436 DebPrint (("sys_read: bad status %d\n", current_status
));
5441 if (fd_info
[fd
].flags
& FILE_PIPE
)
5443 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5444 to_read
= min (waiting
, (DWORD
) count
);
5447 nchars
+= _read (fd
, buffer
, to_read
);
5449 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5451 HANDLE hnd
= fd_info
[fd
].hnd
;
5452 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5458 /* Configure timeouts for non-blocking read. */
5459 if (!GetCommTimeouts (hnd
, &ct
))
5464 ct
.ReadIntervalTimeout
= MAXDWORD
;
5465 ct
.ReadTotalTimeoutMultiplier
= 0;
5466 ct
.ReadTotalTimeoutConstant
= 0;
5467 if (!SetCommTimeouts (hnd
, &ct
))
5473 if (!ResetEvent (ovl
->hEvent
))
5478 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5480 if (GetLastError () != ERROR_IO_PENDING
)
5485 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5494 else /* FILE_SOCKET */
5496 if (winsock_lib
== NULL
) abort ();
5498 /* do the equivalent of a non-blocking read */
5499 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5500 if (waiting
== 0 && nchars
== 0)
5502 h_errno
= errno
= EWOULDBLOCK
;
5508 /* always use binary mode for sockets */
5509 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5510 if (res
== SOCKET_ERROR
)
5512 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5513 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5523 int nread
= _read (fd
, buffer
, count
);
5526 else if (nchars
== 0)
5531 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5532 /* Perform text mode translation if required. */
5533 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5535 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5536 /* If buffer contains only CR, return that. To be absolutely
5537 sure we should attempt to read the next char, but in
5538 practice a CR to be followed by LF would not appear by
5539 itself in the buffer. */
5540 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5542 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5548 nchars
= _read (fd
, buffer
, count
);
5553 /* From w32xfns.c */
5554 extern HANDLE interrupt_handle
;
5556 /* For now, don't bother with a non-blocking mode */
5558 sys_write (int fd
, const void * buffer
, unsigned int count
)
5568 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5570 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5576 /* Perform text mode translation if required. */
5577 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5579 char * tmpbuf
= alloca (count
* 2);
5580 unsigned char * src
= (void *)buffer
;
5581 unsigned char * dst
= tmpbuf
;
5586 unsigned char *next
;
5587 /* copy next line or remaining bytes */
5588 next
= _memccpy (dst
, src
, '\n', nbytes
);
5591 /* copied one line ending with '\n' */
5592 int copied
= next
- dst
;
5595 /* insert '\r' before '\n' */
5602 /* copied remaining partial line -> now finished */
5609 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5611 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5612 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5613 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5616 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5618 if (GetLastError () != ERROR_IO_PENDING
)
5623 if (detect_input_pending ())
5624 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5627 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5628 if (active
== WAIT_OBJECT_0
)
5629 { /* User pressed C-g, cancel write, then leave. Don't bother
5630 cleaning up as we may only get stuck in buggy drivers. */
5631 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5636 if (active
== WAIT_OBJECT_0
+ 1
5637 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5644 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5646 unsigned long nblock
= 0;
5647 if (winsock_lib
== NULL
) abort ();
5649 /* TODO: implement select() properly so non-blocking I/O works. */
5650 /* For now, make sure the write blocks. */
5651 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5652 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5654 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5656 /* Set the socket back to non-blocking if it was before,
5657 for other operations that support it. */
5658 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5661 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5664 if (nchars
== SOCKET_ERROR
)
5666 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5667 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5673 /* Some networked filesystems don't like too large writes, so
5674 break them into smaller chunks. See the Comments section of
5675 the MSDN documentation of WriteFile for details behind the
5676 choice of the value of CHUNK below. See also the thread
5677 http://thread.gmane.org/gmane.comp.version-control.git/145294
5678 in the git mailing list. */
5679 const unsigned char *p
= buffer
;
5680 const unsigned chunk
= 30 * 1024 * 1024;
5685 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5686 int n
= _write (fd
, p
, this_chunk
);
5694 else if (n
< this_chunk
)
5704 /* The Windows CRT functions are "optimized for speed", so they don't
5705 check for timezone and DST changes if they were last called less
5706 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
5707 all Emacs features that repeatedly call time functions (e.g.,
5708 display-time) are in real danger of missing timezone and DST
5709 changes. Calling tzset before each localtime call fixes that. */
5711 sys_localtime (const time_t *t
)
5714 return localtime (t
);
5719 /* Delayed loading of libraries. */
5721 Lisp_Object Vlibrary_cache
;
5723 /* The argument LIBRARIES is an alist that associates a symbol
5724 LIBRARY_ID, identifying an external DLL library known to Emacs, to
5725 a list of filenames under which the library is usually found. In
5726 most cases, the argument passed as LIBRARIES is the variable
5727 `dynamic-library-alist', which is initialized to a list of common
5728 library names. If the function loads the library successfully, it
5729 returns the handle of the DLL, and records the filename in the
5730 property :loaded-from of LIBRARY_ID; it returns NULL if the library
5731 could not be found, or when it was already loaded (because the
5732 handle is not recorded anywhere, and so is lost after use). It
5733 would be trivial to save the handle too in :loaded-from, but
5734 currently there's no use case for it. */
5736 w32_delayed_load (Lisp_Object libraries
, Lisp_Object library_id
)
5738 HMODULE library_dll
= NULL
;
5740 CHECK_SYMBOL (library_id
);
5742 if (CONSP (libraries
) && NILP (Fassq (library_id
, Vlibrary_cache
)))
5744 Lisp_Object found
= Qnil
;
5745 Lisp_Object dlls
= Fassq (library_id
, libraries
);
5748 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
5750 CHECK_STRING_CAR (dlls
);
5751 if (library_dll
= LoadLibrary (SDATA (XCAR (dlls
))))
5753 found
= XCAR (dlls
);
5758 Fput (library_id
, QCloaded_from
, found
);
5766 check_windows_init_file (void)
5768 /* A common indication that Emacs is not installed properly is when
5769 it cannot find the Windows installation file. If this file does
5770 not exist in the expected place, tell the user. */
5772 if (!noninteractive
&& !inhibit_window_system
)
5774 Lisp_Object objs
[2];
5775 Lisp_Object full_load_path
;
5776 Lisp_Object init_file
;
5779 objs
[0] = Vload_path
;
5780 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5781 full_load_path
= Fappend (2, objs
);
5782 init_file
= build_string ("term/w32-win");
5783 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5786 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5787 char *init_file_name
= SDATA (init_file
);
5788 char *load_path
= SDATA (load_path_print
);
5789 char *buffer
= alloca (1024
5790 + strlen (init_file_name
)
5791 + strlen (load_path
));
5794 "The Emacs Windows initialization file \"%s.el\" "
5795 "could not be found in your Emacs installation. "
5796 "Emacs checked the following directories for this file:\n"
5798 "When Emacs cannot find this file, it usually means that it "
5799 "was not installed properly, or its distribution file was "
5800 "not unpacked properly.\nSee the README.W32 file in the "
5801 "top-level Emacs directory for more information.",
5802 init_file_name
, load_path
);
5805 "Emacs Abort Dialog",
5806 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5807 /* Use the low-level Emacs abort. */
5821 /* shutdown the socket interface if necessary */
5830 /* Initialise the socket interface now if available and requested by
5831 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5832 delayed until open-network-stream is called (w32-has-winsock can
5833 also be used to dynamically load or reload winsock).
5835 Conveniently, init_environment is called before us, so
5836 PRELOAD_WINSOCK can be set in the registry. */
5838 /* Always initialize this correctly. */
5841 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5842 init_winsock (TRUE
);
5844 /* Initial preparation for subprocess support: replace our standard
5845 handles with non-inheritable versions. */
5848 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5849 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5850 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5852 parent
= GetCurrentProcess ();
5854 /* ignore errors when duplicating and closing; typically the
5855 handles will be invalid when running as a gui program. */
5856 DuplicateHandle (parent
,
5857 GetStdHandle (STD_INPUT_HANDLE
),
5862 DUPLICATE_SAME_ACCESS
);
5864 DuplicateHandle (parent
,
5865 GetStdHandle (STD_OUTPUT_HANDLE
),
5870 DUPLICATE_SAME_ACCESS
);
5872 DuplicateHandle (parent
,
5873 GetStdHandle (STD_ERROR_HANDLE
),
5878 DUPLICATE_SAME_ACCESS
);
5884 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5885 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5887 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5890 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5891 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5893 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5896 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5897 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5899 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5903 /* unfortunately, atexit depends on implementation of malloc */
5904 /* atexit (term_ntproc); */
5905 signal (SIGABRT
, term_ntproc
);
5907 /* determine which drives are fixed, for GetCachedVolumeInformation */
5909 /* GetDriveType must have trailing backslash. */
5910 char drive
[] = "A:\\";
5912 /* Loop over all possible drive letters */
5913 while (*drive
<= 'Z')
5915 /* Record if this drive letter refers to a fixed drive. */
5916 fixed_drives
[DRIVE_INDEX (*drive
)] =
5917 (GetDriveType (drive
) == DRIVE_FIXED
);
5922 /* Reset the volume info cache. */
5923 volume_cache
= NULL
;
5926 /* Check to see if Emacs has been installed correctly. */
5927 check_windows_init_file ();
5931 shutdown_handler ensures that buffers' autosave files are
5932 up to date when the user logs off, or the system shuts down.
5935 shutdown_handler (DWORD type
)
5937 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5938 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5939 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5940 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5942 /* Shut down cleanly, making sure autosave files are up to date. */
5943 shut_down_emacs (0, 0, Qnil
);
5946 /* Allow other handlers to handle this signal. */
5951 globals_of_w32 is used to initialize those global variables that
5952 must always be initialized on startup even when the global variable
5953 initialized is non zero (see the function main in emacs.c).
5956 globals_of_w32 (void)
5958 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5960 get_process_times_fn
= (GetProcessTimes_Proc
)
5961 GetProcAddress (kernel32
, "GetProcessTimes");
5963 QCloaded_from
= intern_c_string (":loaded-from");
5964 staticpro (&QCloaded_from
);
5966 Vlibrary_cache
= Qnil
;
5967 staticpro (&Vlibrary_cache
);
5969 g_b_init_is_windows_9x
= 0;
5970 g_b_init_open_process_token
= 0;
5971 g_b_init_get_token_information
= 0;
5972 g_b_init_lookup_account_sid
= 0;
5973 g_b_init_get_sid_sub_authority
= 0;
5974 g_b_init_get_sid_sub_authority_count
= 0;
5975 g_b_init_get_file_security
= 0;
5976 g_b_init_get_security_descriptor_owner
= 0;
5977 g_b_init_get_security_descriptor_group
= 0;
5978 g_b_init_is_valid_sid
= 0;
5979 g_b_init_create_toolhelp32_snapshot
= 0;
5980 g_b_init_process32_first
= 0;
5981 g_b_init_process32_next
= 0;
5982 g_b_init_open_thread_token
= 0;
5983 g_b_init_impersonate_self
= 0;
5984 g_b_init_revert_to_self
= 0;
5985 g_b_init_get_process_memory_info
= 0;
5986 g_b_init_get_process_working_set_size
= 0;
5987 g_b_init_global_memory_status
= 0;
5988 g_b_init_global_memory_status_ex
= 0;
5989 g_b_init_equal_sid
= 0;
5990 g_b_init_copy_sid
= 0;
5991 g_b_init_get_length_sid
= 0;
5992 g_b_init_get_native_system_info
= 0;
5993 g_b_init_get_system_times
= 0;
5994 num_of_processors
= 0;
5995 /* The following sets a handler for shutdown notifications for
5996 console apps. This actually applies to Emacs in both console and
5997 GUI modes, since we had to fool windows into thinking emacs is a
5998 console application to get console mode to work. */
5999 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
6001 /* "None" is the default group name on standalone workstations. */
6002 strcpy (dflt_group_name
, "None");
6005 /* For make-serial-process */
6007 serial_open (char *port
)
6013 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
6014 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
6015 if (hnd
== INVALID_HANDLE_VALUE
)
6016 error ("Could not open %s", port
);
6017 fd
= (int) _open_osfhandle ((int) hnd
, 0);
6019 error ("Could not open %s", port
);
6023 error ("Could not create child process");
6025 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6026 fd_info
[ fd
].hnd
= hnd
;
6027 fd_info
[ fd
].flags
|=
6028 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
6029 if (fd_info
[ fd
].cp
!= NULL
)
6031 error ("fd_info[fd = %d] is already in use", fd
);
6033 fd_info
[ fd
].cp
= cp
;
6034 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6035 if (cp
->ovl_read
.hEvent
== NULL
)
6036 error ("Could not create read event");
6037 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6038 if (cp
->ovl_write
.hEvent
== NULL
)
6039 error ("Could not create write event");
6044 /* For serial-process-configure */
6046 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
6048 Lisp_Object childp2
= Qnil
;
6049 Lisp_Object tem
= Qnil
;
6053 char summary
[4] = "???"; /* This usually becomes "8N1". */
6055 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6056 error ("Not a serial process");
6057 hnd
= fd_info
[ p
->outfd
].hnd
;
6059 childp2
= Fcopy_sequence (p
->childp
);
6061 /* Initialize timeouts for blocking read and blocking write. */
6062 if (!GetCommTimeouts (hnd
, &ct
))
6063 error ("GetCommTimeouts() failed");
6064 ct
.ReadIntervalTimeout
= 0;
6065 ct
.ReadTotalTimeoutMultiplier
= 0;
6066 ct
.ReadTotalTimeoutConstant
= 0;
6067 ct
.WriteTotalTimeoutMultiplier
= 0;
6068 ct
.WriteTotalTimeoutConstant
= 0;
6069 if (!SetCommTimeouts (hnd
, &ct
))
6070 error ("SetCommTimeouts() failed");
6071 /* Read port attributes and prepare default configuration. */
6072 memset (&dcb
, 0, sizeof (dcb
));
6073 dcb
.DCBlength
= sizeof (DCB
);
6074 if (!GetCommState (hnd
, &dcb
))
6075 error ("GetCommState() failed");
6078 dcb
.fAbortOnError
= FALSE
;
6079 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6084 /* Configure speed. */
6085 if (!NILP (Fplist_member (contact
, QCspeed
)))
6086 tem
= Fplist_get (contact
, QCspeed
);
6088 tem
= Fplist_get (p
->childp
, QCspeed
);
6090 dcb
.BaudRate
= XINT (tem
);
6091 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6093 /* Configure bytesize. */
6094 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6095 tem
= Fplist_get (contact
, QCbytesize
);
6097 tem
= Fplist_get (p
->childp
, QCbytesize
);
6099 tem
= make_number (8);
6101 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6102 error (":bytesize must be nil (8), 7, or 8");
6103 dcb
.ByteSize
= XINT (tem
);
6104 summary
[0] = XINT (tem
) + '0';
6105 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6107 /* Configure parity. */
6108 if (!NILP (Fplist_member (contact
, QCparity
)))
6109 tem
= Fplist_get (contact
, QCparity
);
6111 tem
= Fplist_get (p
->childp
, QCparity
);
6112 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6113 error (":parity must be nil (no parity), `even', or `odd'");
6114 dcb
.fParity
= FALSE
;
6115 dcb
.Parity
= NOPARITY
;
6116 dcb
.fErrorChar
= FALSE
;
6121 else if (EQ (tem
, Qeven
))
6125 dcb
.Parity
= EVENPARITY
;
6126 dcb
.fErrorChar
= TRUE
;
6128 else if (EQ (tem
, Qodd
))
6132 dcb
.Parity
= ODDPARITY
;
6133 dcb
.fErrorChar
= TRUE
;
6135 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6137 /* Configure stopbits. */
6138 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6139 tem
= Fplist_get (contact
, QCstopbits
);
6141 tem
= Fplist_get (p
->childp
, QCstopbits
);
6143 tem
= make_number (1);
6145 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6146 error (":stopbits must be nil (1 stopbit), 1, or 2");
6147 summary
[2] = XINT (tem
) + '0';
6148 if (XINT (tem
) == 1)
6149 dcb
.StopBits
= ONESTOPBIT
;
6150 else if (XINT (tem
) == 2)
6151 dcb
.StopBits
= TWOSTOPBITS
;
6152 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6154 /* Configure flowcontrol. */
6155 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6156 tem
= Fplist_get (contact
, QCflowcontrol
);
6158 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6159 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6160 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6161 dcb
.fOutxCtsFlow
= FALSE
;
6162 dcb
.fOutxDsrFlow
= FALSE
;
6163 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6164 dcb
.fDsrSensitivity
= FALSE
;
6165 dcb
.fTXContinueOnXoff
= FALSE
;
6168 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6169 dcb
.XonChar
= 17; /* Control-Q */
6170 dcb
.XoffChar
= 19; /* Control-S */
6173 /* Already configured. */
6175 else if (EQ (tem
, Qhw
))
6177 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6178 dcb
.fOutxCtsFlow
= TRUE
;
6180 else if (EQ (tem
, Qsw
))
6185 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6187 /* Activate configuration. */
6188 if (!SetCommState (hnd
, &dcb
))
6189 error ("SetCommState() failed");
6191 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6192 p
->childp
= childp2
;
6198 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
6203 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
6204 int fd
= process
->infd
;
6208 n
= sys_read(fd
, (char*)buf
, sz
);
6215 if (err
== EWOULDBLOCK
)
6217 /* Set a small timeout. */
6218 EMACS_SET_SECS_USECS(timeout
, 1, 0);
6220 FD_SET ((int)fd
, &fdset
);
6222 /* Use select with the timeout to poll the selector. */
6223 sc
= select (fd
+ 1, &fdset
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0,
6227 continue; /* Try again. */
6229 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
6230 Also accept select return 0 as an indicator to EAGAIN. */
6231 if (sc
== 0 || errno
== EWOULDBLOCK
)
6234 err
= errno
; /* Other errors are just passed on. */
6237 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
6244 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
6246 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
6247 int fd
= process
->outfd
;
6248 ssize_t n
= sys_write(fd
, buf
, sz
);
6250 /* 0 or more bytes written means everything went fine. */
6254 /* Negative bytes written means we got an error in errno.
6255 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
6256 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
6257 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
6261 #endif /* HAVE_GNUTLS */