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 pthread_sigmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1457 if (sigprocmask (how
, set
, oset
) == -1)
1463 setpgrp (int pid
, int gid
)
1474 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1477 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1480 HKEY hrootkey
= NULL
;
1483 /* Check both the current user and the local machine to see if
1484 we have any resources. */
1486 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1490 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1491 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1492 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1494 RegCloseKey (hrootkey
);
1500 RegCloseKey (hrootkey
);
1503 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1507 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1508 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1509 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1511 RegCloseKey (hrootkey
);
1517 RegCloseKey (hrootkey
);
1523 char *get_emacs_configuration (void);
1526 init_environment (char ** argv
)
1528 static const char * const tempdirs
[] = {
1529 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1534 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1536 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1537 temporary files and assume "/tmp" if $TMPDIR is unset, which
1538 will break on DOS/Windows. Refuse to work if we cannot find
1539 a directory, not even "c:/", usable for that purpose. */
1540 for (i
= 0; i
< imax
; i
++)
1542 const char *tmp
= tempdirs
[i
];
1545 tmp
= getenv (tmp
+ 1);
1546 /* Note that `access' can lie to us if the directory resides on a
1547 read-only filesystem, like CD-ROM or a write-protected floppy.
1548 The only way to be really sure is to actually create a file and
1549 see if it succeeds. But I think that's too much to ask. */
1550 if (tmp
&& _access (tmp
, D_OK
) == 0)
1552 char * var
= alloca (strlen (tmp
) + 8);
1553 sprintf (var
, "TMPDIR=%s", tmp
);
1554 _putenv (strdup (var
));
1561 Fcons (build_string ("no usable temporary directories found!!"),
1563 "While setting TMPDIR: ");
1565 /* Check for environment variables and use registry settings if they
1566 don't exist. Fallback on default values where applicable. */
1571 char locale_name
[32];
1572 struct stat ignored
;
1573 char default_home
[MAX_PATH
];
1576 static const struct env_entry
1583 {"PRELOAD_WINSOCK", NULL
},
1584 {"emacs_dir", "C:/emacs"},
1585 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1586 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1587 {"EMACSDATA", "%emacs_dir%/etc"},
1588 {"EMACSPATH", "%emacs_dir%/bin"},
1589 /* We no longer set INFOPATH because Info-default-directory-list
1591 /* {"INFOPATH", "%emacs_dir%/info"}, */
1592 {"EMACSDOC", "%emacs_dir%/etc"},
1597 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1599 /* We need to copy dflt_envvars[] and work on the copy because we
1600 don't want the dumped Emacs to inherit the values of
1601 environment variables we saw during dumping (which could be on
1602 a different system). The defaults above must be left intact. */
1603 struct env_entry env_vars
[N_ENV_VARS
];
1605 for (i
= 0; i
< N_ENV_VARS
; i
++)
1606 env_vars
[i
] = dflt_envvars
[i
];
1608 /* For backwards compatibility, check if a .emacs file exists in C:/
1609 If not, then we can try to default to the appdata directory under the
1610 user's profile, which is more likely to be writable. */
1611 if (stat ("C:/.emacs", &ignored
) < 0)
1613 HRESULT profile_result
;
1614 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1615 of Windows 95 and NT4 that have not been updated to include
1617 ShGetFolderPath_fn get_folder_path
;
1618 get_folder_path
= (ShGetFolderPath_fn
)
1619 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1621 if (get_folder_path
!= NULL
)
1623 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1626 /* If we can't get the appdata dir, revert to old behavior. */
1627 if (profile_result
== S_OK
)
1629 env_vars
[0].def_value
= default_home
;
1635 /* Get default locale info and use it for LANG. */
1636 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1637 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1638 locale_name
, sizeof (locale_name
)))
1640 for (i
= 0; i
< N_ENV_VARS
; i
++)
1642 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1644 env_vars
[i
].def_value
= locale_name
;
1650 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1652 /* Treat emacs_dir specially: set it unconditionally based on our
1653 location, if it appears that we are running from the bin subdir
1654 of a standard installation. */
1657 char modname
[MAX_PATH
];
1659 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1661 if ((p
= strrchr (modname
, '\\')) == NULL
)
1665 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1667 char buf
[SET_ENV_BUF_SIZE
];
1670 for (p
= modname
; *p
; p
++)
1671 if (*p
== '\\') *p
= '/';
1673 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1674 _putenv (strdup (buf
));
1676 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1678 /* FIXME: should use substring of get_emacs_configuration ().
1679 But I don't think the Windows build supports alpha, mips etc
1680 anymore, so have taken the easy option for now. */
1681 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1684 p
= strrchr (modname
, '\\');
1688 p
= strrchr (modname
, '\\');
1689 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1691 char buf
[SET_ENV_BUF_SIZE
];
1694 for (p
= modname
; *p
; p
++)
1695 if (*p
== '\\') *p
= '/';
1697 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1698 _putenv (strdup (buf
));
1704 for (i
= 0; i
< N_ENV_VARS
; i
++)
1706 if (!getenv (env_vars
[i
].name
))
1710 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1711 /* Also ignore empty environment variables. */
1715 lpval
= env_vars
[i
].def_value
;
1716 dwType
= REG_EXPAND_SZ
;
1718 if (!strcmp (env_vars
[i
].name
, "HOME") && !appdata
)
1720 Lisp_Object warning
[2];
1721 warning
[0] = intern ("initialization");
1722 warning
[1] = build_string ("Setting HOME to C:\\ by default is deprecated");
1723 Vdelayed_warnings_list
= Fcons (Flist (2, warning
),
1724 Vdelayed_warnings_list
);
1730 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1732 if (dwType
== REG_EXPAND_SZ
)
1733 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1734 else if (dwType
== REG_SZ
)
1735 strcpy (buf1
, lpval
);
1736 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1738 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1740 _putenv (strdup (buf2
));
1750 /* Rebuild system configuration to reflect invoking system. */
1751 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1753 /* Another special case: on NT, the PATH variable is actually named
1754 "Path" although cmd.exe (perhaps NT itself) arranges for
1755 environment variable lookup and setting to be case insensitive.
1756 However, Emacs assumes a fully case sensitive environment, so we
1757 need to change "Path" to "PATH" to match the expectations of
1758 various elisp packages. We do this by the sneaky method of
1759 modifying the string in the C runtime environ entry.
1761 The same applies to COMSPEC. */
1765 for (envp
= environ
; *envp
; envp
++)
1766 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1767 memcpy (*envp
, "PATH=", 5);
1768 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1769 memcpy (*envp
, "COMSPEC=", 8);
1772 /* Remember the initial working directory for getwd, then make the
1773 real wd be the location of emacs.exe to avoid conflicts when
1774 renaming or deleting directories. (We also don't call chdir when
1775 running subprocesses for the same reason.) */
1776 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1781 static char modname
[MAX_PATH
];
1783 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1785 if ((p
= strrchr (modname
, '\\')) == NULL
)
1789 SetCurrentDirectory (modname
);
1791 /* Ensure argv[0] has the full path to Emacs. */
1796 /* Determine if there is a middle mouse button, to allow parse_button
1797 to decide whether right mouse events should be mouse-2 or
1799 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1805 emacs_root_dir (void)
1807 static char root_dir
[FILENAME_MAX
];
1810 p
= getenv ("emacs_dir");
1813 strcpy (root_dir
, p
);
1814 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1815 dostounix_filename (root_dir
);
1819 /* We don't have scripts to automatically determine the system configuration
1820 for Emacs before it's compiled, and we don't want to have to make the
1821 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1825 get_emacs_configuration (void)
1827 char *arch
, *oem
, *os
;
1829 static char configuration_buffer
[32];
1831 /* Determine the processor type. */
1832 switch (get_processor_type ())
1835 #ifdef PROCESSOR_INTEL_386
1836 case PROCESSOR_INTEL_386
:
1837 case PROCESSOR_INTEL_486
:
1838 case PROCESSOR_INTEL_PENTIUM
:
1843 #ifdef PROCESSOR_MIPS_R2000
1844 case PROCESSOR_MIPS_R2000
:
1845 case PROCESSOR_MIPS_R3000
:
1846 case PROCESSOR_MIPS_R4000
:
1851 #ifdef PROCESSOR_ALPHA_21064
1852 case PROCESSOR_ALPHA_21064
:
1862 /* Use the OEM field to reflect the compiler/library combination. */
1864 #define COMPILER_NAME "msvc"
1867 #define COMPILER_NAME "mingw"
1869 #define COMPILER_NAME "unknown"
1872 oem
= COMPILER_NAME
;
1874 switch (osinfo_cache
.dwPlatformId
) {
1875 case VER_PLATFORM_WIN32_NT
:
1877 build_num
= osinfo_cache
.dwBuildNumber
;
1879 case VER_PLATFORM_WIN32_WINDOWS
:
1880 if (osinfo_cache
.dwMinorVersion
== 0) {
1885 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1887 case VER_PLATFORM_WIN32s
:
1888 /* Not supported, should not happen. */
1890 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1898 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1899 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1900 get_w32_major_version (), get_w32_minor_version (), build_num
);
1902 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1905 return configuration_buffer
;
1909 get_emacs_configuration_options (void)
1911 static char *options_buffer
;
1912 char cv
[32]; /* Enough for COMPILER_VERSION. */
1914 cv
, /* To be filled later. */
1918 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1919 with a starting space to save work here. */
1921 " --cflags", USER_CFLAGS
,
1924 " --ldflags", USER_LDFLAGS
,
1931 /* Work out the effective configure options for this build. */
1933 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1936 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1938 #define COMPILER_VERSION ""
1942 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
1943 return "Error: not enough space for compiler version";
1944 cv
[sizeof (cv
) - 1] = '\0';
1946 for (i
= 0; options
[i
]; i
++)
1947 size
+= strlen (options
[i
]);
1949 options_buffer
= xmalloc (size
+ 1);
1950 options_buffer
[0] = '\0';
1952 for (i
= 0; options
[i
]; i
++)
1953 strcat (options_buffer
, options
[i
]);
1955 return options_buffer
;
1959 #include <sys/timeb.h>
1961 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1963 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1968 tv
->tv_sec
= tb
.time
;
1969 tv
->tv_usec
= tb
.millitm
* 1000L;
1970 /* Implementation note: _ftime sometimes doesn't update the dstflag
1971 according to the new timezone when the system timezone is
1972 changed. We could fix that by using GetSystemTime and
1973 GetTimeZoneInformation, but that doesn't seem necessary, since
1974 Emacs always calls gettimeofday with the 2nd argument NULL (see
1978 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1979 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1983 /* ------------------------------------------------------------------------- */
1984 /* IO support and wrapper functions for W32 API. */
1985 /* ------------------------------------------------------------------------- */
1987 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1988 on network directories, so we handle that case here.
1989 (Ulrich Leodolter, 1/11/95). */
1991 sys_ctime (const time_t *t
)
1993 char *str
= (char *) ctime (t
);
1994 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1997 /* Emulate sleep...we could have done this with a define, but that
1998 would necessitate including windows.h in the files that used it.
1999 This is much easier. */
2001 sys_sleep (int seconds
)
2003 Sleep (seconds
* 1000);
2006 /* Internal MSVC functions for low-level descriptor munging */
2007 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2008 extern int __cdecl
_free_osfhnd (int fd
);
2010 /* parallel array of private info on file handles */
2011 filedesc fd_info
[ MAXDESC
];
2013 typedef struct volume_info_data
{
2014 struct volume_info_data
* next
;
2016 /* time when info was obtained */
2019 /* actual volume info */
2028 /* Global referenced by various functions. */
2029 static volume_info_data volume_info
;
2031 /* Vector to indicate which drives are local and fixed (for which cached
2032 data never expires). */
2033 static BOOL fixed_drives
[26];
2035 /* Consider cached volume information to be stale if older than 10s,
2036 at least for non-local drives. Info for fixed drives is never stale. */
2037 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2038 #define VOLINFO_STILL_VALID( root_dir, info ) \
2039 ( ( isalpha (root_dir[0]) && \
2040 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2041 || GetTickCount () - info->timestamp < 10000 )
2043 /* Cache support functions. */
2045 /* Simple linked list with linear search is sufficient. */
2046 static volume_info_data
*volume_cache
= NULL
;
2048 static volume_info_data
*
2049 lookup_volume_info (char * root_dir
)
2051 volume_info_data
* info
;
2053 for (info
= volume_cache
; info
; info
= info
->next
)
2054 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2060 add_volume_info (char * root_dir
, volume_info_data
* info
)
2062 info
->root_dir
= xstrdup (root_dir
);
2063 info
->next
= volume_cache
;
2064 volume_cache
= info
;
2068 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2069 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2070 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2071 static volume_info_data
*
2072 GetCachedVolumeInformation (char * root_dir
)
2074 volume_info_data
* info
;
2075 char default_root
[ MAX_PATH
];
2077 /* NULL for root_dir means use root from current directory. */
2078 if (root_dir
== NULL
)
2080 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2082 parse_root (default_root
, &root_dir
);
2084 root_dir
= default_root
;
2087 /* Local fixed drives can be cached permanently. Removable drives
2088 cannot be cached permanently, since the volume name and serial
2089 number (if nothing else) can change. Remote drives should be
2090 treated as if they are removable, since there is no sure way to
2091 tell whether they are or not. Also, the UNC association of drive
2092 letters mapped to remote volumes can be changed at any time (even
2093 by other processes) without notice.
2095 As a compromise, so we can benefit from caching info for remote
2096 volumes, we use a simple expiry mechanism to invalidate cache
2097 entries that are more than ten seconds old. */
2100 /* No point doing this, because WNetGetConnection is even slower than
2101 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2102 GetDriveType is about the only call of this type which does not
2103 involve network access, and so is extremely quick). */
2105 /* Map drive letter to UNC if remote. */
2106 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2108 char remote_name
[ 256 ];
2109 char drive
[3] = { root_dir
[0], ':' };
2111 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2113 /* do something */ ;
2117 info
= lookup_volume_info (root_dir
);
2119 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2127 /* Info is not cached, or is stale. */
2128 if (!GetVolumeInformation (root_dir
,
2129 name
, sizeof (name
),
2133 type
, sizeof (type
)))
2136 /* Cache the volume information for future use, overwriting existing
2137 entry if present. */
2140 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
2141 add_volume_info (root_dir
, info
);
2149 info
->name
= xstrdup (name
);
2150 info
->serialnum
= serialnum
;
2151 info
->maxcomp
= maxcomp
;
2152 info
->flags
= flags
;
2153 info
->type
= xstrdup (type
);
2154 info
->timestamp
= GetTickCount ();
2160 /* Get information on the volume where name is held; set path pointer to
2161 start of pathname in name (past UNC header\volume header if present). */
2163 get_volume_info (const char * name
, const char ** pPath
)
2165 char temp
[MAX_PATH
];
2166 char *rootname
= NULL
; /* default to current volume */
2167 volume_info_data
* info
;
2172 /* find the root name of the volume if given */
2173 if (isalpha (name
[0]) && name
[1] == ':')
2181 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2188 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2201 info
= GetCachedVolumeInformation (rootname
);
2204 /* Set global referenced by other functions. */
2205 volume_info
= *info
;
2211 /* Determine if volume is FAT format (ie. only supports short 8.3
2212 names); also set path pointer to start of pathname in name. */
2214 is_fat_volume (const char * name
, const char ** pPath
)
2216 if (get_volume_info (name
, pPath
))
2217 return (volume_info
.maxcomp
== 12);
2221 /* Map filename to a valid 8.3 name if necessary. */
2223 map_w32_filename (const char * name
, const char ** pPath
)
2225 static char shortname
[MAX_PATH
];
2226 char * str
= shortname
;
2229 const char * save_name
= name
;
2231 if (strlen (name
) >= MAX_PATH
)
2233 /* Return a filename which will cause callers to fail. */
2234 strcpy (shortname
, "?");
2238 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2240 register int left
= 8; /* maximum number of chars in part */
2241 register int extn
= 0; /* extension added? */
2242 register int dots
= 2; /* maximum number of dots allowed */
2245 *str
++ = *name
++; /* skip past UNC header */
2247 while ((c
= *name
++))
2254 extn
= 0; /* reset extension flags */
2255 dots
= 2; /* max 2 dots */
2256 left
= 8; /* max length 8 for main part */
2260 extn
= 0; /* reset extension flags */
2261 dots
= 2; /* max 2 dots */
2262 left
= 8; /* max length 8 for main part */
2267 /* Convert path components of the form .xxx to _xxx,
2268 but leave . and .. as they are. This allows .emacs
2269 to be read as _emacs, for example. */
2273 IS_DIRECTORY_SEP (*name
))
2288 extn
= 1; /* we've got an extension */
2289 left
= 3; /* 3 chars in extension */
2293 /* any embedded dots after the first are converted to _ */
2298 case '#': /* don't lose these, they're important */
2300 str
[-1] = c
; /* replace last character of part */
2305 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2307 dots
= 0; /* started a path component */
2316 strcpy (shortname
, name
);
2317 unixtodos_filename (shortname
);
2321 *pPath
= shortname
+ (path
- save_name
);
2327 is_exec (const char * name
)
2329 char * p
= strrchr (name
, '.');
2332 && (xstrcasecmp (p
, ".exe") == 0 ||
2333 xstrcasecmp (p
, ".com") == 0 ||
2334 xstrcasecmp (p
, ".bat") == 0 ||
2335 xstrcasecmp (p
, ".cmd") == 0));
2338 /* Emulate the Unix directory procedures opendir, closedir,
2339 and readdir. We can't use the procedures supplied in sysdep.c,
2340 so we provide them here. */
2342 struct direct dir_static
; /* simulated directory contents */
2343 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2344 static int dir_is_fat
;
2345 static char dir_pathname
[MAXPATHLEN
+1];
2346 static WIN32_FIND_DATA dir_find_data
;
2348 /* Support shares on a network resource as subdirectories of a read-only
2350 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2351 static HANDLE
open_unc_volume (const char *);
2352 static char *read_unc_volume (HANDLE
, char *, int);
2353 static void close_unc_volume (HANDLE
);
2356 opendir (char *filename
)
2360 /* Opening is done by FindFirstFile. However, a read is inherent to
2361 this operation, so we defer the open until read time. */
2363 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2365 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2368 if (is_unc_volume (filename
))
2370 wnet_enum_handle
= open_unc_volume (filename
);
2371 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2375 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2382 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2383 dir_pathname
[MAXPATHLEN
] = '\0';
2384 dir_is_fat
= is_fat_volume (filename
, NULL
);
2390 closedir (DIR *dirp
)
2392 /* If we have a find-handle open, close it. */
2393 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2395 FindClose (dir_find_handle
);
2396 dir_find_handle
= INVALID_HANDLE_VALUE
;
2398 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2400 close_unc_volume (wnet_enum_handle
);
2401 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2403 xfree ((char *) dirp
);
2409 int downcase
= !NILP (Vw32_downcase_file_names
);
2411 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2413 if (!read_unc_volume (wnet_enum_handle
,
2414 dir_find_data
.cFileName
,
2418 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2419 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2421 char filename
[MAXNAMLEN
+ 3];
2424 strcpy (filename
, dir_pathname
);
2425 ln
= strlen (filename
) - 1;
2426 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2427 strcat (filename
, "\\");
2428 strcat (filename
, "*");
2430 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2432 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2437 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2441 /* Emacs never uses this value, so don't bother making it match
2442 value returned by stat(). */
2443 dir_static
.d_ino
= 1;
2445 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2447 /* If the file name in cFileName[] includes `?' characters, it means
2448 the original file name used characters that cannot be represented
2449 by the current ANSI codepage. To avoid total lossage, retrieve
2450 the short 8+3 alias of the long file name. */
2451 if (_mbspbrk (dir_static
.d_name
, "?"))
2453 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2454 downcase
= 1; /* 8+3 aliases are returned in all caps */
2456 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2457 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2458 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2460 /* If the file name in cFileName[] includes `?' characters, it means
2461 the original file name used characters that cannot be represented
2462 by the current ANSI codepage. To avoid total lossage, retrieve
2463 the short 8+3 alias of the long file name. */
2464 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2466 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2467 /* 8+3 aliases are returned in all caps, which could break
2468 various alists that look at filenames' extensions. */
2472 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2473 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2475 _strlwr (dir_static
.d_name
);
2479 for (p
= dir_static
.d_name
; *p
; p
++)
2480 if (*p
>= 'a' && *p
<= 'z')
2483 _strlwr (dir_static
.d_name
);
2490 open_unc_volume (const char *path
)
2496 nr
.dwScope
= RESOURCE_GLOBALNET
;
2497 nr
.dwType
= RESOURCETYPE_DISK
;
2498 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2499 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2500 nr
.lpLocalName
= NULL
;
2501 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2502 nr
.lpComment
= NULL
;
2503 nr
.lpProvider
= NULL
;
2505 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2506 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2508 if (result
== NO_ERROR
)
2511 return INVALID_HANDLE_VALUE
;
2515 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2519 DWORD bufsize
= 512;
2524 buffer
= alloca (bufsize
);
2525 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
2526 if (result
!= NO_ERROR
)
2529 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2530 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2532 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2535 strncpy (readbuf
, ptr
, size
);
2540 close_unc_volume (HANDLE henum
)
2542 if (henum
!= INVALID_HANDLE_VALUE
)
2543 WNetCloseEnum (henum
);
2547 unc_volume_file_attributes (const char *path
)
2552 henum
= open_unc_volume (path
);
2553 if (henum
== INVALID_HANDLE_VALUE
)
2556 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2558 close_unc_volume (henum
);
2563 /* Ensure a network connection is authenticated. */
2565 logon_network_drive (const char *path
)
2567 NETRESOURCE resource
;
2568 char share
[MAX_PATH
];
2573 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2574 drvtype
= DRIVE_REMOTE
;
2575 else if (path
[0] == '\0' || path
[1] != ':')
2576 drvtype
= GetDriveType (NULL
);
2583 drvtype
= GetDriveType (drive
);
2586 /* Only logon to networked drives. */
2587 if (drvtype
!= DRIVE_REMOTE
)
2591 strncpy (share
, path
, MAX_PATH
);
2592 /* Truncate to just server and share name. */
2593 for (i
= 2; i
< MAX_PATH
; i
++)
2595 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2602 resource
.dwType
= RESOURCETYPE_DISK
;
2603 resource
.lpLocalName
= NULL
;
2604 resource
.lpRemoteName
= share
;
2605 resource
.lpProvider
= NULL
;
2607 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2610 /* Shadow some MSVC runtime functions to map requests for long filenames
2611 to reasonable short names if necessary. This was originally added to
2612 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2616 sys_access (const char * path
, int mode
)
2620 /* MSVC implementation doesn't recognize D_OK. */
2621 path
= map_w32_filename (path
, NULL
);
2622 if (is_unc_volume (path
))
2624 attributes
= unc_volume_file_attributes (path
);
2625 if (attributes
== -1) {
2630 else if ((attributes
= GetFileAttributes (path
)) == -1)
2632 /* Should try mapping GetLastError to errno; for now just indicate
2633 that path doesn't exist. */
2637 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2642 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2647 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2656 sys_chdir (const char * path
)
2658 return _chdir (map_w32_filename (path
, NULL
));
2662 sys_chmod (const char * path
, int mode
)
2664 return _chmod (map_w32_filename (path
, NULL
), mode
);
2668 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2670 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2676 sys_creat (const char * path
, int mode
)
2678 return _creat (map_w32_filename (path
, NULL
), mode
);
2682 sys_fopen (const char * path
, const char * mode
)
2686 const char * mode_save
= mode
;
2688 /* Force all file handles to be non-inheritable. This is necessary to
2689 ensure child processes don't unwittingly inherit handles that might
2690 prevent future file access. */
2694 else if (mode
[0] == 'w' || mode
[0] == 'a')
2695 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2699 /* Only do simplistic option parsing. */
2703 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2706 else if (mode
[0] == 'b')
2711 else if (mode
[0] == 't')
2718 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2722 return _fdopen (fd
, mode_save
);
2725 /* This only works on NTFS volumes, but is useful to have. */
2727 sys_link (const char * old
, const char * new)
2731 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2733 if (old
== NULL
|| new == NULL
)
2739 strcpy (oldname
, map_w32_filename (old
, NULL
));
2740 strcpy (newname
, map_w32_filename (new, NULL
));
2742 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2743 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2744 if (fileh
!= INVALID_HANDLE_VALUE
)
2748 /* Confusingly, the "alternate" stream name field does not apply
2749 when restoring a hard link, and instead contains the actual
2750 stream data for the link (ie. the name of the link to create).
2751 The WIN32_STREAM_ID structure before the cStreamName field is
2752 the stream header, which is then immediately followed by the
2756 WIN32_STREAM_ID wid
;
2757 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2760 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2761 data
.wid
.cStreamName
, MAX_PATH
);
2764 LPVOID context
= NULL
;
2767 data
.wid
.dwStreamId
= BACKUP_LINK
;
2768 data
.wid
.dwStreamAttributes
= 0;
2769 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2770 data
.wid
.Size
.HighPart
= 0;
2771 data
.wid
.dwStreamNameSize
= 0;
2773 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2774 offsetof (WIN32_STREAM_ID
, cStreamName
)
2775 + data
.wid
.Size
.LowPart
,
2776 &wbytes
, FALSE
, FALSE
, &context
)
2777 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2784 /* Should try mapping GetLastError to errno; for now just
2785 indicate a general error (eg. links not supported). */
2786 errno
= EINVAL
; // perhaps EMLINK?
2790 CloseHandle (fileh
);
2799 sys_mkdir (const char * path
)
2801 return _mkdir (map_w32_filename (path
, NULL
));
2804 /* Because of long name mapping issues, we need to implement this
2805 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2806 a unique name, instead of setting the input template to an empty
2809 Standard algorithm seems to be use pid or tid with a letter on the
2810 front (in place of the 6 X's) and cycle through the letters to find a
2811 unique name. We extend that to allow any reasonable character as the
2812 first of the 6 X's. */
2814 sys_mktemp (char * template)
2818 unsigned uid
= GetCurrentThreadId ();
2819 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2821 if (template == NULL
)
2823 p
= template + strlen (template);
2825 /* replace up to the last 5 X's with uid in decimal */
2826 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2828 p
[0] = '0' + uid
% 10;
2832 if (i
< 0 && p
[0] == 'X')
2837 int save_errno
= errno
;
2838 p
[0] = first_char
[i
];
2839 if (sys_access (template, 0) < 0)
2845 while (++i
< sizeof (first_char
));
2848 /* Template is badly formed or else we can't generate a unique name,
2849 so return empty string */
2855 sys_open (const char * path
, int oflag
, int mode
)
2857 const char* mpath
= map_w32_filename (path
, NULL
);
2858 /* Try to open file without _O_CREAT, to be able to write to hidden
2859 and system files. Force all file handles to be
2861 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2864 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2868 sys_rename (const char * oldname
, const char * newname
)
2871 char temp
[MAX_PATH
];
2873 /* MoveFile on Windows 95 doesn't correctly change the short file name
2874 alias in a number of circumstances (it is not easy to predict when
2875 just by looking at oldname and newname, unfortunately). In these
2876 cases, renaming through a temporary name avoids the problem.
2878 A second problem on Windows 95 is that renaming through a temp name when
2879 newname is uppercase fails (the final long name ends up in
2880 lowercase, although the short alias might be uppercase) UNLESS the
2881 long temp name is not 8.3.
2883 So, on Windows 95 we always rename through a temp name, and we make sure
2884 the temp name has a long extension to ensure correct renaming. */
2886 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2888 if (os_subtype
== OS_WIN95
)
2894 oldname
= map_w32_filename (oldname
, NULL
);
2895 if (o
= strrchr (oldname
, '\\'))
2898 o
= (char *) oldname
;
2900 if (p
= strrchr (temp
, '\\'))
2907 /* Force temp name to require a manufactured 8.3 alias - this
2908 seems to make the second rename work properly. */
2909 sprintf (p
, "_.%s.%u", o
, i
);
2911 result
= rename (oldname
, temp
);
2913 /* This loop must surely terminate! */
2914 while (result
< 0 && errno
== EEXIST
);
2919 /* Emulate Unix behavior - newname is deleted if it already exists
2920 (at least if it is a file; don't do this for directories).
2922 Since we mustn't do this if we are just changing the case of the
2923 file name (we would end up deleting the file we are trying to
2924 rename!), we let rename detect if the destination file already
2925 exists - that way we avoid the possible pitfalls of trying to
2926 determine ourselves whether two names really refer to the same
2927 file, which is not always possible in the general case. (Consider
2928 all the permutations of shared or subst'd drives, etc.) */
2930 newname
= map_w32_filename (newname
, NULL
);
2931 result
= rename (temp
, newname
);
2935 && _chmod (newname
, 0666) == 0
2936 && _unlink (newname
) == 0)
2937 result
= rename (temp
, newname
);
2943 sys_rmdir (const char * path
)
2945 return _rmdir (map_w32_filename (path
, NULL
));
2949 sys_unlink (const char * path
)
2951 path
= map_w32_filename (path
, NULL
);
2953 /* On Unix, unlink works without write permission. */
2954 _chmod (path
, 0666);
2955 return _unlink (path
);
2958 static FILETIME utc_base_ft
;
2959 static ULONGLONG utc_base
; /* In 100ns units */
2960 static int init
= 0;
2962 #define FILETIME_TO_U64(result, ft) \
2964 ULARGE_INTEGER uiTemp; \
2965 uiTemp.LowPart = (ft).dwLowDateTime; \
2966 uiTemp.HighPart = (ft).dwHighDateTime; \
2967 result = uiTemp.QuadPart; \
2971 initialize_utc_base (void)
2973 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2982 st
.wMilliseconds
= 0;
2984 SystemTimeToFileTime (&st
, &utc_base_ft
);
2985 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
2989 convert_time (FILETIME ft
)
2995 initialize_utc_base ();
2999 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3002 FILETIME_TO_U64 (tmp
, ft
);
3003 return (time_t) ((tmp
- utc_base
) / 10000000L);
3007 convert_from_time_t (time_t time
, FILETIME
* pft
)
3013 initialize_utc_base ();
3017 /* time in 100ns units since 1-Jan-1601 */
3018 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3019 pft
->dwHighDateTime
= tmp
.HighPart
;
3020 pft
->dwLowDateTime
= tmp
.LowPart
;
3024 /* No reason to keep this; faking inode values either by hashing or even
3025 using the file index from GetInformationByHandle, is not perfect and
3026 so by default Emacs doesn't use the inode values on Windows.
3027 Instead, we now determine file-truename correctly (except for
3028 possible drive aliasing etc). */
3030 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3032 hashval (const unsigned char * str
)
3037 h
= (h
<< 4) + *str
++;
3043 /* Return the hash value of the canonical pathname, excluding the
3044 drive/UNC header, to get a hopefully unique inode number. */
3046 generate_inode_val (const char * name
)
3048 char fullname
[ MAX_PATH
];
3052 /* Get the truly canonical filename, if it exists. (Note: this
3053 doesn't resolve aliasing due to subst commands, or recognise hard
3055 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3058 parse_root (fullname
, &p
);
3059 /* Normal W32 filesystems are still case insensitive. */
3066 static PSECURITY_DESCRIPTOR
3067 get_file_security_desc (const char *fname
)
3069 PSECURITY_DESCRIPTOR psd
= NULL
;
3071 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3072 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3074 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3076 err
= GetLastError ();
3077 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3081 psd
= xmalloc (sd_len
);
3082 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3094 unsigned n_subauthorities
;
3096 /* Use the last sub-authority value of the RID, the relative
3097 portion of the SID, as user/group ID. */
3098 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3099 if (n_subauthorities
< 1)
3100 return 0; /* the "World" RID */
3101 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3104 /* Caching SID and account values for faster lokup. */
3107 # define FLEXIBLE_ARRAY_MEMBER
3109 # define FLEXIBLE_ARRAY_MEMBER 1
3114 struct w32_id
*next
;
3116 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3119 static struct w32_id
*w32_idlist
;
3122 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3124 struct w32_id
*tail
, *found
;
3126 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3128 if (equal_sid ((PSID
)tail
->sid
, sid
))
3137 strcpy (name
, found
->name
);
3145 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3148 struct w32_id
*new_entry
;
3150 /* We don't want to leave behind stale cache from when Emacs was
3154 sid_len
= get_length_sid (sid
);
3155 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3158 new_entry
->rid
= id
;
3159 strcpy (new_entry
->name
, name
);
3160 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3161 new_entry
->next
= w32_idlist
;
3162 w32_idlist
= new_entry
;
3171 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3172 unsigned *id
, char *nm
, int what
)
3175 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3177 SID_NAME_USE ignore
;
3179 DWORD name_len
= sizeof (name
);
3181 DWORD domain_len
= sizeof (domain
);
3187 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3188 else if (what
== GID
)
3189 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3193 if (!result
|| !is_valid_sid (sid
))
3195 else if (!w32_cached_id (sid
, id
, nm
))
3197 /* If FNAME is a UNC, we need to lookup account on the
3198 specified machine. */
3199 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3200 && fname
[2] != '\0')
3205 for (s
= fname
+ 2, p
= machine
;
3206 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3212 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3213 domain
, &domain_len
, &ignore
)
3214 || name_len
> UNLEN
+1)
3218 *id
= get_rid (sid
);
3220 w32_add_to_cache (sid
, *id
, name
);
3227 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3231 int dflt_usr
= 0, dflt_grp
= 0;
3240 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3242 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3245 /* Consider files to belong to current user/group, if we cannot get
3246 more accurate information. */
3249 st
->st_uid
= dflt_passwd
.pw_uid
;
3250 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3254 st
->st_gid
= dflt_passwd
.pw_gid
;
3255 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3259 /* Return non-zero if NAME is a potentially slow filesystem. */
3261 is_slow_fs (const char *name
)
3266 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3267 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3268 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3269 devtype
= GetDriveType (NULL
); /* use root of current drive */
3272 /* GetDriveType needs the root directory of the drive. */
3273 strncpy (drive_root
, name
, 2);
3274 drive_root
[2] = '\\';
3275 drive_root
[3] = '\0';
3276 devtype
= GetDriveType (drive_root
);
3278 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3281 /* MSVC stat function can't cope with UNC names and has other bugs, so
3282 replace it with our own. This also allows us to calculate consistent
3283 inode values without hacks in the main Emacs code. */
3285 stat (const char * path
, struct stat
* buf
)
3288 WIN32_FIND_DATA wfd
;
3290 unsigned __int64 fake_inode
;
3293 int rootdir
= FALSE
;
3294 PSECURITY_DESCRIPTOR psd
= NULL
;
3296 if (path
== NULL
|| buf
== NULL
)
3302 name
= (char *) map_w32_filename (path
, &path
);
3303 /* Must be valid filename, no wild cards or other invalid
3304 characters. We use _mbspbrk to support multibyte strings that
3305 might look to strpbrk as if they included literal *, ?, and other
3306 characters mentioned below that are disallowed by Windows
3308 if (_mbspbrk (name
, "*?|<>\""))
3314 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3315 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3316 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3321 /* Remove trailing directory separator, unless name is the root
3322 directory of a drive or UNC volume in which case ensure there
3323 is a trailing separator. */
3324 len
= strlen (name
);
3325 rootdir
= (path
>= name
+ len
- 1
3326 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3327 name
= strcpy (alloca (len
+ 2), name
);
3329 if (is_unc_volume (name
))
3331 DWORD attrs
= unc_volume_file_attributes (name
);
3336 memset (&wfd
, 0, sizeof (wfd
));
3337 wfd
.dwFileAttributes
= attrs
;
3338 wfd
.ftCreationTime
= utc_base_ft
;
3339 wfd
.ftLastAccessTime
= utc_base_ft
;
3340 wfd
.ftLastWriteTime
= utc_base_ft
;
3341 strcpy (wfd
.cFileName
, name
);
3345 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3346 strcat (name
, "\\");
3347 if (GetDriveType (name
) < 2)
3352 memset (&wfd
, 0, sizeof (wfd
));
3353 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3354 wfd
.ftCreationTime
= utc_base_ft
;
3355 wfd
.ftLastAccessTime
= utc_base_ft
;
3356 wfd
.ftLastWriteTime
= utc_base_ft
;
3357 strcpy (wfd
.cFileName
, name
);
3361 if (IS_DIRECTORY_SEP (name
[len
-1]))
3364 /* (This is hacky, but helps when doing file completions on
3365 network drives.) Optimize by using information available from
3366 active readdir if possible. */
3367 len
= strlen (dir_pathname
);
3368 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3370 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3371 && strnicmp (name
, dir_pathname
, len
) == 0
3372 && IS_DIRECTORY_SEP (name
[len
])
3373 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3375 /* This was the last entry returned by readdir. */
3376 wfd
= dir_find_data
;
3380 logon_network_drive (name
);
3382 fh
= FindFirstFile (name
, &wfd
);
3383 if (fh
== INVALID_HANDLE_VALUE
)
3392 if (!(NILP (Vw32_get_true_file_attributes
)
3393 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3394 /* No access rights required to get info. */
3395 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3396 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3397 != INVALID_HANDLE_VALUE
)
3399 /* This is more accurate in terms of gettting the correct number
3400 of links, but is quite slow (it is noticeable when Emacs is
3401 making a list of file name completions). */
3402 BY_HANDLE_FILE_INFORMATION info
;
3404 if (GetFileInformationByHandle (fh
, &info
))
3406 buf
->st_nlink
= info
.nNumberOfLinks
;
3407 /* Might as well use file index to fake inode values, but this
3408 is not guaranteed to be unique unless we keep a handle open
3409 all the time (even then there are situations where it is
3410 not unique). Reputedly, there are at most 48 bits of info
3411 (on NTFS, presumably less on FAT). */
3412 fake_inode
= info
.nFileIndexHigh
;
3414 fake_inode
+= info
.nFileIndexLow
;
3422 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3424 buf
->st_mode
= S_IFDIR
;
3428 switch (GetFileType (fh
))
3430 case FILE_TYPE_DISK
:
3431 buf
->st_mode
= S_IFREG
;
3433 case FILE_TYPE_PIPE
:
3434 buf
->st_mode
= S_IFIFO
;
3436 case FILE_TYPE_CHAR
:
3437 case FILE_TYPE_UNKNOWN
:
3439 buf
->st_mode
= S_IFCHR
;
3443 psd
= get_file_security_desc (name
);
3444 get_file_owner_and_group (psd
, name
, buf
);
3448 /* Don't bother to make this information more accurate. */
3449 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3454 get_file_owner_and_group (NULL
, name
, buf
);
3459 /* Not sure if there is any point in this. */
3460 if (!NILP (Vw32_generate_fake_inodes
))
3461 fake_inode
= generate_inode_val (name
);
3462 else if (fake_inode
== 0)
3464 /* For want of something better, try to make everything unique. */
3465 static DWORD gen_num
= 0;
3466 fake_inode
= ++gen_num
;
3470 /* MSVC defines _ino_t to be short; other libc's might not. */
3471 if (sizeof (buf
->st_ino
) == 2)
3472 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3474 buf
->st_ino
= fake_inode
;
3476 /* volume_info is set indirectly by map_w32_filename */
3477 buf
->st_dev
= volume_info
.serialnum
;
3478 buf
->st_rdev
= volume_info
.serialnum
;
3480 buf
->st_size
= wfd
.nFileSizeHigh
;
3481 buf
->st_size
<<= 32;
3482 buf
->st_size
+= wfd
.nFileSizeLow
;
3484 /* Convert timestamps to Unix format. */
3485 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3486 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3487 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3488 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3489 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3491 /* determine rwx permissions */
3492 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3493 permission
= S_IREAD
;
3495 permission
= S_IREAD
| S_IWRITE
;
3497 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3498 permission
|= S_IEXEC
;
3499 else if (is_exec (name
))
3500 permission
|= S_IEXEC
;
3502 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3507 /* Provide fstat and utime as well as stat for consistent handling of
3510 fstat (int desc
, struct stat
* buf
)
3512 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3513 BY_HANDLE_FILE_INFORMATION info
;
3514 unsigned __int64 fake_inode
;
3517 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3519 case FILE_TYPE_DISK
:
3520 buf
->st_mode
= S_IFREG
;
3521 if (!GetFileInformationByHandle (fh
, &info
))
3527 case FILE_TYPE_PIPE
:
3528 buf
->st_mode
= S_IFIFO
;
3530 case FILE_TYPE_CHAR
:
3531 case FILE_TYPE_UNKNOWN
:
3533 buf
->st_mode
= S_IFCHR
;
3535 memset (&info
, 0, sizeof (info
));
3536 info
.dwFileAttributes
= 0;
3537 info
.ftCreationTime
= utc_base_ft
;
3538 info
.ftLastAccessTime
= utc_base_ft
;
3539 info
.ftLastWriteTime
= utc_base_ft
;
3542 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3543 buf
->st_mode
= S_IFDIR
;
3545 buf
->st_nlink
= info
.nNumberOfLinks
;
3546 /* Might as well use file index to fake inode values, but this
3547 is not guaranteed to be unique unless we keep a handle open
3548 all the time (even then there are situations where it is
3549 not unique). Reputedly, there are at most 48 bits of info
3550 (on NTFS, presumably less on FAT). */
3551 fake_inode
= info
.nFileIndexHigh
;
3553 fake_inode
+= info
.nFileIndexLow
;
3555 /* MSVC defines _ino_t to be short; other libc's might not. */
3556 if (sizeof (buf
->st_ino
) == 2)
3557 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3559 buf
->st_ino
= fake_inode
;
3561 /* Consider files to belong to current user.
3562 FIXME: this should use GetSecurityInfo API, but it is only
3563 available for _WIN32_WINNT >= 0x501. */
3564 buf
->st_uid
= dflt_passwd
.pw_uid
;
3565 buf
->st_gid
= dflt_passwd
.pw_gid
;
3566 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3567 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3569 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3570 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3572 buf
->st_size
= info
.nFileSizeHigh
;
3573 buf
->st_size
<<= 32;
3574 buf
->st_size
+= info
.nFileSizeLow
;
3576 /* Convert timestamps to Unix format. */
3577 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3578 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3579 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3580 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3581 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3583 /* determine rwx permissions */
3584 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3585 permission
= S_IREAD
;
3587 permission
= S_IREAD
| S_IWRITE
;
3589 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3590 permission
|= S_IEXEC
;
3593 #if 0 /* no way of knowing the filename */
3594 char * p
= strrchr (name
, '.');
3596 (xstrcasecmp (p
, ".exe") == 0 ||
3597 xstrcasecmp (p
, ".com") == 0 ||
3598 xstrcasecmp (p
, ".bat") == 0 ||
3599 xstrcasecmp (p
, ".cmd") == 0))
3600 permission
|= S_IEXEC
;
3604 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3610 utime (const char *name
, struct utimbuf
*times
)
3612 struct utimbuf deftime
;
3619 deftime
.modtime
= deftime
.actime
= time (NULL
);
3623 /* Need write access to set times. */
3624 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3625 0, OPEN_EXISTING
, 0, NULL
);
3628 convert_from_time_t (times
->actime
, &atime
);
3629 convert_from_time_t (times
->modtime
, &mtime
);
3630 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3647 /* Symlink-related functions that always fail. Used in fileio.c and in
3648 sysdep.c to avoid #ifdef's. */
3650 symlink (char const *dummy1
, char const *dummy2
)
3657 readlink (const char *name
, char *dummy1
, size_t dummy2
)
3659 /* `access' is much faster than `stat' on MS-Windows. */
3660 if (sys_access (name
, 0) == 0)
3666 careadlinkat (int fd
, char const *filename
,
3667 char *buffer
, size_t buffer_size
,
3668 struct allocator
const *alloc
,
3669 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
3676 careadlinkatcwd (int fd
, char const *filename
, char *buffer
,
3680 return readlink (filename
, buffer
, buffer_size
);
3684 /* Support for browsing other processes and their attributes. See
3685 process.c for the Lisp bindings. */
3687 /* Helper wrapper functions. */
3689 static HANDLE WINAPI
3690 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
3692 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3694 if (g_b_init_create_toolhelp32_snapshot
== 0)
3696 g_b_init_create_toolhelp32_snapshot
= 1;
3697 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3698 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3699 "CreateToolhelp32Snapshot");
3701 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3703 return INVALID_HANDLE_VALUE
;
3705 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3709 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3711 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3713 if (g_b_init_process32_first
== 0)
3715 g_b_init_process32_first
= 1;
3716 s_pfn_Process32_First
= (Process32First_Proc
)
3717 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3720 if (s_pfn_Process32_First
== NULL
)
3724 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3728 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3730 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3732 if (g_b_init_process32_next
== 0)
3734 g_b_init_process32_next
= 1;
3735 s_pfn_Process32_Next
= (Process32Next_Proc
)
3736 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3739 if (s_pfn_Process32_Next
== NULL
)
3743 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3747 open_thread_token (HANDLE ThreadHandle
,
3748 DWORD DesiredAccess
,
3750 PHANDLE TokenHandle
)
3752 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3753 HMODULE hm_advapi32
= NULL
;
3754 if (is_windows_9x () == TRUE
)
3756 SetLastError (ERROR_NOT_SUPPORTED
);
3759 if (g_b_init_open_thread_token
== 0)
3761 g_b_init_open_thread_token
= 1;
3762 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3763 s_pfn_Open_Thread_Token
=
3764 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3766 if (s_pfn_Open_Thread_Token
== NULL
)
3768 SetLastError (ERROR_NOT_SUPPORTED
);
3772 s_pfn_Open_Thread_Token (
3781 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3783 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3784 HMODULE hm_advapi32
= NULL
;
3785 if (is_windows_9x () == TRUE
)
3789 if (g_b_init_impersonate_self
== 0)
3791 g_b_init_impersonate_self
= 1;
3792 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3793 s_pfn_Impersonate_Self
=
3794 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3796 if (s_pfn_Impersonate_Self
== NULL
)
3800 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3804 revert_to_self (void)
3806 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3807 HMODULE hm_advapi32
= NULL
;
3808 if (is_windows_9x () == TRUE
)
3812 if (g_b_init_revert_to_self
== 0)
3814 g_b_init_revert_to_self
= 1;
3815 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3816 s_pfn_Revert_To_Self
=
3817 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3819 if (s_pfn_Revert_To_Self
== NULL
)
3823 return s_pfn_Revert_To_Self ();
3827 get_process_memory_info (HANDLE h_proc
,
3828 PPROCESS_MEMORY_COUNTERS mem_counters
,
3831 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3832 HMODULE hm_psapi
= NULL
;
3833 if (is_windows_9x () == TRUE
)
3837 if (g_b_init_get_process_memory_info
== 0)
3839 g_b_init_get_process_memory_info
= 1;
3840 hm_psapi
= LoadLibrary ("Psapi.dll");
3842 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3843 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3845 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3849 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3853 get_process_working_set_size (HANDLE h_proc
,
3857 static GetProcessWorkingSetSize_Proc
3858 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3860 if (is_windows_9x () == TRUE
)
3864 if (g_b_init_get_process_working_set_size
== 0)
3866 g_b_init_get_process_working_set_size
= 1;
3867 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3868 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3869 "GetProcessWorkingSetSize");
3871 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3875 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3879 global_memory_status (MEMORYSTATUS
*buf
)
3881 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3883 if (is_windows_9x () == TRUE
)
3887 if (g_b_init_global_memory_status
== 0)
3889 g_b_init_global_memory_status
= 1;
3890 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3891 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3892 "GlobalMemoryStatus");
3894 if (s_pfn_Global_Memory_Status
== NULL
)
3898 return s_pfn_Global_Memory_Status (buf
);
3902 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
3904 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3906 if (is_windows_9x () == TRUE
)
3910 if (g_b_init_global_memory_status_ex
== 0)
3912 g_b_init_global_memory_status_ex
= 1;
3913 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3914 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3915 "GlobalMemoryStatusEx");
3917 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3921 return s_pfn_Global_Memory_Status_Ex (buf
);
3925 list_system_processes (void)
3927 struct gcpro gcpro1
;
3928 Lisp_Object proclist
= Qnil
;
3931 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
3933 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
3935 PROCESSENTRY32 proc_entry
;
3941 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
3942 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
3943 res
= process32_next (h_snapshot
, &proc_entry
))
3945 proc_id
= proc_entry
.th32ProcessID
;
3946 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
3949 CloseHandle (h_snapshot
);
3951 proclist
= Fnreverse (proclist
);
3958 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
3960 TOKEN_PRIVILEGES priv
;
3961 DWORD priv_size
= sizeof (priv
);
3962 DWORD opriv_size
= sizeof (*old_priv
);
3963 HANDLE h_token
= NULL
;
3964 HANDLE h_thread
= GetCurrentThread ();
3968 res
= open_thread_token (h_thread
,
3969 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3971 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
3973 if (impersonate_self (SecurityImpersonation
))
3974 res
= open_thread_token (h_thread
,
3975 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
3980 priv
.PrivilegeCount
= 1;
3981 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
3982 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
3983 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
3984 old_priv
, &opriv_size
)
3985 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
3989 CloseHandle (h_token
);
3995 restore_privilege (TOKEN_PRIVILEGES
*priv
)
3997 DWORD priv_size
= sizeof (*priv
);
3998 HANDLE h_token
= NULL
;
4001 if (open_thread_token (GetCurrentThread (),
4002 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4005 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
4006 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4010 CloseHandle (h_token
);
4016 ltime (long time_sec
, long time_usec
)
4018 return list3 (make_number ((time_sec
>> 16) & 0xffff),
4019 make_number (time_sec
& 0xffff),
4020 make_number (time_usec
));
4023 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
4026 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4027 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4030 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4031 ULONGLONG tem1
, tem2
, tem3
, tem
;
4034 || !get_process_times_fn
4035 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4036 &ft_kernel
, &ft_user
))
4039 GetSystemTimeAsFileTime (&ft_current
);
4041 FILETIME_TO_U64 (tem1
, ft_kernel
);
4043 *stime
= U64_TO_LISP_TIME (tem1
);
4045 FILETIME_TO_U64 (tem2
, ft_user
);
4047 *utime
= U64_TO_LISP_TIME (tem2
);
4050 *ttime
= U64_TO_LISP_TIME (tem3
);
4052 FILETIME_TO_U64 (tem
, ft_creation
);
4053 /* Process no 4 (System) returns zero creation time. */
4055 tem
= (tem
- utc_base
) / 10L;
4056 *ctime
= U64_TO_LISP_TIME (tem
);
4060 FILETIME_TO_U64 (tem3
, ft_current
);
4061 tem
= (tem3
- utc_base
) / 10L - tem
;
4063 *etime
= U64_TO_LISP_TIME (tem
);
4067 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4078 system_process_attributes (Lisp_Object pid
)
4080 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4081 Lisp_Object attrs
= Qnil
;
4082 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4083 HANDLE h_snapshot
, h_proc
;
4086 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4087 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4088 DWORD glength
= sizeof (gname
);
4089 HANDLE token
= NULL
;
4090 SID_NAME_USE user_type
;
4091 unsigned char *buf
= NULL
;
4093 TOKEN_USER user_token
;
4094 TOKEN_PRIMARY_GROUP group_token
;
4097 PROCESS_MEMORY_COUNTERS mem
;
4098 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4099 DWORD minrss
, maxrss
;
4101 MEMORY_STATUS_EX memstex
;
4102 double totphys
= 0.0;
4103 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4105 BOOL result
= FALSE
;
4107 CHECK_NUMBER_OR_FLOAT (pid
);
4108 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4110 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4112 GCPRO3 (attrs
, decoded_cmd
, tem
);
4114 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4119 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4120 for (res
= process32_first (h_snapshot
, &pe
); res
;
4121 res
= process32_next (h_snapshot
, &pe
))
4123 if (proc_id
== pe
.th32ProcessID
)
4126 decoded_cmd
= build_string ("Idle");
4129 /* Decode the command name from locale-specific
4131 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4132 strlen (pe
.szExeFile
));
4134 code_convert_string_norecord (cmd_str
,
4135 Vlocale_coding_system
, 0);
4137 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4138 attrs
= Fcons (Fcons (Qppid
,
4139 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4141 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4143 attrs
= Fcons (Fcons (Qthcount
,
4144 make_fixnum_or_float (pe
.cntThreads
)),
4151 CloseHandle (h_snapshot
);
4160 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4162 /* If we were denied a handle to the process, try again after
4163 enabling the SeDebugPrivilege in our process. */
4166 TOKEN_PRIVILEGES priv_current
;
4168 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4170 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4172 restore_privilege (&priv_current
);
4178 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4181 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4182 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4184 buf
= xmalloc (blen
);
4185 result
= get_token_information (token
, TokenUser
,
4186 (LPVOID
)buf
, blen
, &needed
);
4189 memcpy (&user_token
, buf
, sizeof (user_token
));
4190 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4192 euid
= get_rid (user_token
.User
.Sid
);
4193 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4198 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4201 strcpy (uname
, "unknown");
4205 ulength
= strlen (uname
);
4211 /* Determine a reasonable euid and gid values. */
4212 if (xstrcasecmp ("administrator", uname
) == 0)
4214 euid
= 500; /* well-known Administrator uid */
4215 egid
= 513; /* well-known None gid */
4219 /* Get group id and name. */
4220 result
= get_token_information (token
, TokenPrimaryGroup
,
4221 (LPVOID
)buf
, blen
, &needed
);
4222 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4224 buf
= xrealloc (buf
, blen
= needed
);
4225 result
= get_token_information (token
, TokenPrimaryGroup
,
4226 (LPVOID
)buf
, blen
, &needed
);
4230 memcpy (&group_token
, buf
, sizeof (group_token
));
4231 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4233 egid
= get_rid (group_token
.PrimaryGroup
);
4234 dlength
= sizeof (domain
);
4236 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4237 gname
, &glength
, NULL
, &dlength
,
4240 w32_add_to_cache (group_token
.PrimaryGroup
,
4244 strcpy (gname
, "None");
4248 glength
= strlen (gname
);
4256 if (!is_windows_9x ())
4258 /* We couldn't open the process token, presumably because of
4259 insufficient access rights. Assume this process is run
4261 strcpy (uname
, "SYSTEM");
4262 strcpy (gname
, "None");
4263 euid
= 18; /* SYSTEM */
4264 egid
= 513; /* None */
4265 glength
= strlen (gname
);
4266 ulength
= strlen (uname
);
4268 /* If we are running under Windows 9X, where security calls are
4269 not supported, we assume all processes are run by the current
4271 else if (GetUserName (uname
, &ulength
))
4273 if (xstrcasecmp ("administrator", uname
) == 0)
4278 strcpy (gname
, "None");
4279 glength
= strlen (gname
);
4280 ulength
= strlen (uname
);
4286 strcpy (uname
, "administrator");
4287 ulength
= strlen (uname
);
4288 strcpy (gname
, "None");
4289 glength
= strlen (gname
);
4292 CloseHandle (token
);
4295 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4296 tem
= make_unibyte_string (uname
, ulength
);
4297 attrs
= Fcons (Fcons (Quser
,
4298 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4300 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4301 tem
= make_unibyte_string (gname
, glength
);
4302 attrs
= Fcons (Fcons (Qgroup
,
4303 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4306 if (global_memory_status_ex (&memstex
))
4307 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4308 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4310 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4311 double, so we need to do this for it... */
4313 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4314 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4315 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4317 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4319 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4320 else if (global_memory_status (&memst
))
4321 totphys
= memst
.dwTotalPhys
/ 1024.0;
4324 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4327 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4329 attrs
= Fcons (Fcons (Qmajflt
,
4330 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4332 attrs
= Fcons (Fcons (Qvsize
,
4333 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4335 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4337 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4340 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4342 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4344 attrs
= Fcons (Fcons (Qmajflt
,
4345 make_fixnum_or_float (mem
.PageFaultCount
)),
4347 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4349 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4352 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4354 DWORD rss
= maxrss
/ 1024;
4356 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4358 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4361 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4363 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4364 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4365 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4366 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4367 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4368 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4371 /* FIXME: Retrieve command line by walking the PEB of the process. */
4374 CloseHandle (h_proc
);
4380 /* Wrappers for winsock functions to map between our file descriptors
4381 and winsock's handles; also set h_errno for convenience.
4383 To allow Emacs to run on systems which don't have winsock support
4384 installed, we dynamically link to winsock on startup if present, and
4385 otherwise provide the minimum necessary functionality
4386 (eg. gethostname). */
4388 /* function pointers for relevant socket functions */
4389 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4390 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4391 int (PASCAL
*pfn_WSAGetLastError
) (void);
4392 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4393 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4394 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4395 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4396 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4397 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4398 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4399 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4400 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4401 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4402 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4403 int (PASCAL
*pfn_WSACleanup
) (void);
4405 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4406 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4407 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4408 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4409 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4410 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4411 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4412 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4413 const char * optval
, int optlen
);
4414 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4415 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4417 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4418 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4419 struct sockaddr
* from
, int * fromlen
);
4420 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4421 const struct sockaddr
* to
, int tolen
);
4423 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4424 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4425 #ifndef HANDLE_FLAG_INHERIT
4426 #define HANDLE_FLAG_INHERIT 1
4430 static int winsock_inuse
;
4435 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4437 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4438 after WSAStartup returns successfully, but it seems reasonable
4439 to allow unloading winsock anyway in that case. */
4440 if (pfn_WSACleanup () == 0 ||
4441 pfn_WSAGetLastError () == WSAENETDOWN
)
4443 if (FreeLibrary (winsock_lib
))
4452 init_winsock (int load_now
)
4454 WSADATA winsockData
;
4456 if (winsock_lib
!= NULL
)
4459 pfn_SetHandleInformation
4460 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4461 "SetHandleInformation");
4463 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4465 if (winsock_lib
!= NULL
)
4467 /* dynamically link to socket functions */
4469 #define LOAD_PROC(fn) \
4470 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4473 LOAD_PROC (WSAStartup
);
4474 LOAD_PROC (WSASetLastError
);
4475 LOAD_PROC (WSAGetLastError
);
4476 LOAD_PROC (WSAEventSelect
);
4477 LOAD_PROC (WSACreateEvent
);
4478 LOAD_PROC (WSACloseEvent
);
4481 LOAD_PROC (connect
);
4482 LOAD_PROC (ioctlsocket
);
4485 LOAD_PROC (closesocket
);
4486 LOAD_PROC (shutdown
);
4489 LOAD_PROC (inet_addr
);
4490 LOAD_PROC (gethostname
);
4491 LOAD_PROC (gethostbyname
);
4492 LOAD_PROC (getservbyname
);
4493 LOAD_PROC (getpeername
);
4494 LOAD_PROC (WSACleanup
);
4495 LOAD_PROC (setsockopt
);
4497 LOAD_PROC (getsockname
);
4499 LOAD_PROC (recvfrom
);
4503 /* specify version 1.1 of winsock */
4504 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4506 if (winsockData
.wVersion
!= 0x101)
4511 /* Report that winsock exists and is usable, but leave
4512 socket functions disabled. I am assuming that calling
4513 WSAStartup does not require any network interaction,
4514 and in particular does not cause or require a dial-up
4515 connection to be established. */
4518 FreeLibrary (winsock_lib
);
4526 FreeLibrary (winsock_lib
);
4536 /* function to set h_errno for compatibility; map winsock error codes to
4537 normal system codes where they overlap (non-overlapping definitions
4538 are already in <sys/socket.h> */
4542 if (winsock_lib
== NULL
)
4545 h_errno
= pfn_WSAGetLastError ();
4549 case WSAEACCES
: h_errno
= EACCES
; break;
4550 case WSAEBADF
: h_errno
= EBADF
; break;
4551 case WSAEFAULT
: h_errno
= EFAULT
; break;
4552 case WSAEINTR
: h_errno
= EINTR
; break;
4553 case WSAEINVAL
: h_errno
= EINVAL
; break;
4554 case WSAEMFILE
: h_errno
= EMFILE
; break;
4555 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4556 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4564 if (h_errno
== 0 && winsock_lib
!= NULL
)
4565 pfn_WSASetLastError (0);
4568 /* Extend strerror to handle the winsock-specific error codes. */
4572 } _wsa_errlist
[] = {
4573 {WSAEINTR
, "Interrupted function call"},
4574 {WSAEBADF
, "Bad file descriptor"},
4575 {WSAEACCES
, "Permission denied"},
4576 {WSAEFAULT
, "Bad address"},
4577 {WSAEINVAL
, "Invalid argument"},
4578 {WSAEMFILE
, "Too many open files"},
4580 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
4581 {WSAEINPROGRESS
, "Operation now in progress"},
4582 {WSAEALREADY
, "Operation already in progress"},
4583 {WSAENOTSOCK
, "Socket operation on non-socket"},
4584 {WSAEDESTADDRREQ
, "Destination address required"},
4585 {WSAEMSGSIZE
, "Message too long"},
4586 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
4587 {WSAENOPROTOOPT
, "Bad protocol option"},
4588 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
4589 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
4590 {WSAEOPNOTSUPP
, "Operation not supported"},
4591 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
4592 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
4593 {WSAEADDRINUSE
, "Address already in use"},
4594 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
4595 {WSAENETDOWN
, "Network is down"},
4596 {WSAENETUNREACH
, "Network is unreachable"},
4597 {WSAENETRESET
, "Network dropped connection on reset"},
4598 {WSAECONNABORTED
, "Software caused connection abort"},
4599 {WSAECONNRESET
, "Connection reset by peer"},
4600 {WSAENOBUFS
, "No buffer space available"},
4601 {WSAEISCONN
, "Socket is already connected"},
4602 {WSAENOTCONN
, "Socket is not connected"},
4603 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
4604 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
4605 {WSAETIMEDOUT
, "Connection timed out"},
4606 {WSAECONNREFUSED
, "Connection refused"},
4607 {WSAELOOP
, "Network loop"}, /* not sure */
4608 {WSAENAMETOOLONG
, "Name is too long"},
4609 {WSAEHOSTDOWN
, "Host is down"},
4610 {WSAEHOSTUNREACH
, "No route to host"},
4611 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
4612 {WSAEPROCLIM
, "Too many processes"},
4613 {WSAEUSERS
, "Too many users"}, /* not sure */
4614 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
4615 {WSAESTALE
, "Data is stale"}, /* not sure */
4616 {WSAEREMOTE
, "Remote error"}, /* not sure */
4618 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
4619 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
4620 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
4621 {WSAEDISCON
, "Graceful shutdown in progress"},
4623 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
4624 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
4625 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
4626 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
4627 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
4628 {WSASYSCALLFAILURE
, "System call failure"},
4629 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
4630 {WSATYPE_NOT_FOUND
, "Class type not found"},
4631 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
4632 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
4633 {WSAEREFUSED
, "Operation refused"}, /* not sure */
4636 {WSAHOST_NOT_FOUND
, "Host not found"},
4637 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
4638 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
4639 {WSANO_DATA
, "Valid name, no data record of requested type"},
4645 sys_strerror (int error_no
)
4648 static char unknown_msg
[40];
4650 if (error_no
>= 0 && error_no
< sys_nerr
)
4651 return sys_errlist
[error_no
];
4653 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4654 if (_wsa_errlist
[i
].errnum
== error_no
)
4655 return _wsa_errlist
[i
].msg
;
4657 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4661 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4662 but I believe the method of keeping the socket handle separate (and
4663 insuring it is not inheritable) is the correct one. */
4665 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4667 static int socket_to_fd (SOCKET s
);
4670 sys_socket (int af
, int type
, int protocol
)
4674 if (winsock_lib
== NULL
)
4677 return INVALID_SOCKET
;
4682 /* call the real socket function */
4683 s
= pfn_socket (af
, type
, protocol
);
4685 if (s
!= INVALID_SOCKET
)
4686 return socket_to_fd (s
);
4692 /* Convert a SOCKET to a file descriptor. */
4694 socket_to_fd (SOCKET s
)
4699 /* Although under NT 3.5 _open_osfhandle will accept a socket
4700 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4701 that does not work under NT 3.1. However, we can get the same
4702 effect by using a backdoor function to replace an existing
4703 descriptor handle with the one we want. */
4705 /* allocate a file descriptor (with appropriate flags) */
4706 fd
= _open ("NUL:", _O_RDWR
);
4709 /* Make a non-inheritable copy of the socket handle. Note
4710 that it is possible that sockets aren't actually kernel
4711 handles, which appears to be the case on Windows 9x when
4712 the MS Proxy winsock client is installed. */
4714 /* Apparently there is a bug in NT 3.51 with some service
4715 packs, which prevents using DuplicateHandle to make a
4716 socket handle non-inheritable (causes WSACleanup to
4717 hang). The work-around is to use SetHandleInformation
4718 instead if it is available and implemented. */
4719 if (pfn_SetHandleInformation
)
4721 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4725 HANDLE parent
= GetCurrentProcess ();
4726 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4728 if (DuplicateHandle (parent
,
4734 DUPLICATE_SAME_ACCESS
))
4736 /* It is possible that DuplicateHandle succeeds even
4737 though the socket wasn't really a kernel handle,
4738 because a real handle has the same value. So
4739 test whether the new handle really is a socket. */
4740 long nonblocking
= 0;
4741 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4743 pfn_closesocket (s
);
4748 CloseHandle (new_s
);
4753 fd_info
[fd
].hnd
= (HANDLE
) s
;
4755 /* set our own internal flags */
4756 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4762 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4764 /* attach child_process to fd_info */
4765 if (fd_info
[ fd
].cp
!= NULL
)
4767 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4771 fd_info
[ fd
].cp
= cp
;
4774 winsock_inuse
++; /* count open sockets */
4781 pfn_closesocket (s
);
4787 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4789 if (winsock_lib
== NULL
)
4792 return SOCKET_ERROR
;
4796 if (fd_info
[s
].flags
& FILE_SOCKET
)
4798 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4799 if (rc
== SOCKET_ERROR
)
4804 return SOCKET_ERROR
;
4808 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4810 if (winsock_lib
== NULL
)
4813 return SOCKET_ERROR
;
4817 if (fd_info
[s
].flags
& FILE_SOCKET
)
4819 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4820 if (rc
== SOCKET_ERROR
)
4825 return SOCKET_ERROR
;
4829 sys_htons (u_short hostshort
)
4831 return (winsock_lib
!= NULL
) ?
4832 pfn_htons (hostshort
) : hostshort
;
4836 sys_ntohs (u_short netshort
)
4838 return (winsock_lib
!= NULL
) ?
4839 pfn_ntohs (netshort
) : netshort
;
4843 sys_inet_addr (const char * cp
)
4845 return (winsock_lib
!= NULL
) ?
4846 pfn_inet_addr (cp
) : INADDR_NONE
;
4850 sys_gethostname (char * name
, int namelen
)
4852 if (winsock_lib
!= NULL
)
4853 return pfn_gethostname (name
, namelen
);
4855 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4856 return !GetComputerName (name
, (DWORD
*)&namelen
);
4859 return SOCKET_ERROR
;
4863 sys_gethostbyname (const char * name
)
4865 struct hostent
* host
;
4867 if (winsock_lib
== NULL
)
4874 host
= pfn_gethostbyname (name
);
4881 sys_getservbyname (const char * name
, const char * proto
)
4883 struct servent
* serv
;
4885 if (winsock_lib
== NULL
)
4892 serv
= pfn_getservbyname (name
, proto
);
4899 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4901 if (winsock_lib
== NULL
)
4904 return SOCKET_ERROR
;
4908 if (fd_info
[s
].flags
& FILE_SOCKET
)
4910 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4911 if (rc
== SOCKET_ERROR
)
4916 return SOCKET_ERROR
;
4920 sys_shutdown (int s
, int how
)
4922 if (winsock_lib
== NULL
)
4925 return SOCKET_ERROR
;
4929 if (fd_info
[s
].flags
& FILE_SOCKET
)
4931 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
4932 if (rc
== SOCKET_ERROR
)
4937 return SOCKET_ERROR
;
4941 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
4943 if (winsock_lib
== NULL
)
4946 return SOCKET_ERROR
;
4950 if (fd_info
[s
].flags
& FILE_SOCKET
)
4952 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
4953 (const char *)optval
, optlen
);
4954 if (rc
== SOCKET_ERROR
)
4959 return SOCKET_ERROR
;
4963 sys_listen (int s
, int backlog
)
4965 if (winsock_lib
== NULL
)
4968 return SOCKET_ERROR
;
4972 if (fd_info
[s
].flags
& FILE_SOCKET
)
4974 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
4975 if (rc
== SOCKET_ERROR
)
4978 fd_info
[s
].flags
|= FILE_LISTEN
;
4982 return SOCKET_ERROR
;
4986 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
4988 if (winsock_lib
== NULL
)
4991 return SOCKET_ERROR
;
4995 if (fd_info
[s
].flags
& FILE_SOCKET
)
4997 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
4998 if (rc
== SOCKET_ERROR
)
5003 return SOCKET_ERROR
;
5007 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
5009 if (winsock_lib
== NULL
)
5016 if (fd_info
[s
].flags
& FILE_LISTEN
)
5018 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5020 if (t
== INVALID_SOCKET
)
5023 fd
= socket_to_fd (t
);
5025 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5026 ResetEvent (fd_info
[s
].cp
->char_avail
);
5034 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5035 struct sockaddr
* from
, int * fromlen
)
5037 if (winsock_lib
== NULL
)
5040 return SOCKET_ERROR
;
5044 if (fd_info
[s
].flags
& FILE_SOCKET
)
5046 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5047 if (rc
== SOCKET_ERROR
)
5052 return SOCKET_ERROR
;
5056 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5057 const struct sockaddr
* to
, int tolen
)
5059 if (winsock_lib
== NULL
)
5062 return SOCKET_ERROR
;
5066 if (fd_info
[s
].flags
& FILE_SOCKET
)
5068 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5069 if (rc
== SOCKET_ERROR
)
5074 return SOCKET_ERROR
;
5077 /* Windows does not have an fcntl function. Provide an implementation
5078 solely for making sockets non-blocking. */
5080 fcntl (int s
, int cmd
, int options
)
5082 if (winsock_lib
== NULL
)
5089 if (fd_info
[s
].flags
& FILE_SOCKET
)
5091 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5093 unsigned long nblock
= 1;
5094 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5095 if (rc
== SOCKET_ERROR
)
5097 /* Keep track of the fact that we set this to non-blocking. */
5098 fd_info
[s
].flags
|= FILE_NDELAY
;
5104 return SOCKET_ERROR
;
5108 return SOCKET_ERROR
;
5112 /* Shadow main io functions: we need to handle pipes and sockets more
5113 intelligently, and implement non-blocking mode as well. */
5126 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5128 child_process
* cp
= fd_info
[fd
].cp
;
5130 fd_info
[fd
].cp
= NULL
;
5132 if (CHILD_ACTIVE (cp
))
5134 /* if last descriptor to active child_process then cleanup */
5136 for (i
= 0; i
< MAXDESC
; i
++)
5140 if (fd_info
[i
].cp
== cp
)
5145 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5147 if (winsock_lib
== NULL
) abort ();
5149 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5150 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5152 winsock_inuse
--; /* count open sockets */
5159 /* Note that sockets do not need special treatment here (at least on
5160 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5161 closesocket is equivalent to CloseHandle, which is to be expected
5162 because socket handles are fully fledged kernel handles. */
5165 if (rc
== 0 && fd
< MAXDESC
)
5166 fd_info
[fd
].flags
= 0;
5177 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5179 /* duplicate our internal info as well */
5180 fd_info
[new_fd
] = fd_info
[fd
];
5186 sys_dup2 (int src
, int dst
)
5190 if (dst
< 0 || dst
>= MAXDESC
)
5196 /* make sure we close the destination first if it's a pipe or socket */
5197 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5200 rc
= _dup2 (src
, dst
);
5203 /* duplicate our internal info as well */
5204 fd_info
[dst
] = fd_info
[src
];
5209 /* Unix pipe() has only one arg */
5211 sys_pipe (int * phandles
)
5216 /* make pipe handles non-inheritable; when we spawn a child, we
5217 replace the relevant handle with an inheritable one. Also put
5218 pipes into binary mode; we will do text mode translation ourselves
5220 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5224 /* Protect against overflow, since Windows can open more handles than
5225 our fd_info array has room for. */
5226 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5228 _close (phandles
[0]);
5229 _close (phandles
[1]);
5234 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5235 fd_info
[phandles
[0]].flags
= flags
;
5237 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5238 fd_info
[phandles
[1]].flags
= flags
;
5245 /* Function to do blocking read of one byte, needed to implement
5246 select. It is only allowed on sockets and pipes. */
5248 _sys_read_ahead (int fd
)
5253 if (fd
< 0 || fd
>= MAXDESC
)
5254 return STATUS_READ_ERROR
;
5256 cp
= fd_info
[fd
].cp
;
5258 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5259 return STATUS_READ_ERROR
;
5261 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5262 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5264 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5268 cp
->status
= STATUS_READ_IN_PROGRESS
;
5270 if (fd_info
[fd
].flags
& FILE_PIPE
)
5272 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5274 /* Give subprocess time to buffer some more output for us before
5275 reporting that input is available; we need this because Windows 95
5276 connects DOS programs to pipes by making the pipe appear to be
5277 the normal console stdout - as a result most DOS programs will
5278 write to stdout without buffering, ie. one character at a
5279 time. Even some W32 programs do this - "dir" in a command
5280 shell on NT is very slow if we don't do this. */
5283 int wait
= w32_pipe_read_delay
;
5289 /* Yield remainder of our time slice, effectively giving a
5290 temporary priority boost to the child process. */
5294 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5296 HANDLE hnd
= fd_info
[fd
].hnd
;
5297 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5300 /* Configure timeouts for blocking read. */
5301 if (!GetCommTimeouts (hnd
, &ct
))
5302 return STATUS_READ_ERROR
;
5303 ct
.ReadIntervalTimeout
= 0;
5304 ct
.ReadTotalTimeoutMultiplier
= 0;
5305 ct
.ReadTotalTimeoutConstant
= 0;
5306 if (!SetCommTimeouts (hnd
, &ct
))
5307 return STATUS_READ_ERROR
;
5309 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5311 if (GetLastError () != ERROR_IO_PENDING
)
5312 return STATUS_READ_ERROR
;
5313 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5314 return STATUS_READ_ERROR
;
5317 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5319 unsigned long nblock
= 0;
5320 /* We always want this to block, so temporarily disable NDELAY. */
5321 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5322 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5324 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5326 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5329 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5333 if (rc
== sizeof (char))
5334 cp
->status
= STATUS_READ_SUCCEEDED
;
5336 cp
->status
= STATUS_READ_FAILED
;
5342 _sys_wait_accept (int fd
)
5348 if (fd
< 0 || fd
>= MAXDESC
)
5349 return STATUS_READ_ERROR
;
5351 cp
= fd_info
[fd
].cp
;
5353 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5354 return STATUS_READ_ERROR
;
5356 cp
->status
= STATUS_READ_FAILED
;
5358 hEv
= pfn_WSACreateEvent ();
5359 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5360 if (rc
!= SOCKET_ERROR
)
5362 rc
= WaitForSingleObject (hEv
, INFINITE
);
5363 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5364 if (rc
== WAIT_OBJECT_0
)
5365 cp
->status
= STATUS_READ_SUCCEEDED
;
5367 pfn_WSACloseEvent (hEv
);
5373 sys_read (int fd
, char * buffer
, unsigned int count
)
5378 char * orig_buffer
= buffer
;
5386 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5388 child_process
*cp
= fd_info
[fd
].cp
;
5390 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5398 /* re-read CR carried over from last read */
5399 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5401 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5405 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5408 /* presence of a child_process structure means we are operating in
5409 non-blocking mode - otherwise we just call _read directly.
5410 Note that the child_process structure might be missing because
5411 reap_subprocess has been called; in this case the pipe is
5412 already broken, so calling _read on it is okay. */
5415 int current_status
= cp
->status
;
5417 switch (current_status
)
5419 case STATUS_READ_FAILED
:
5420 case STATUS_READ_ERROR
:
5421 /* report normal EOF if nothing in buffer */
5423 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5426 case STATUS_READ_READY
:
5427 case STATUS_READ_IN_PROGRESS
:
5428 DebPrint (("sys_read called when read is in progress\n"));
5429 errno
= EWOULDBLOCK
;
5432 case STATUS_READ_SUCCEEDED
:
5433 /* consume read-ahead char */
5434 *buffer
++ = cp
->chr
;
5437 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5438 ResetEvent (cp
->char_avail
);
5440 case STATUS_READ_ACKNOWLEDGED
:
5444 DebPrint (("sys_read: bad status %d\n", current_status
));
5449 if (fd_info
[fd
].flags
& FILE_PIPE
)
5451 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5452 to_read
= min (waiting
, (DWORD
) count
);
5455 nchars
+= _read (fd
, buffer
, to_read
);
5457 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5459 HANDLE hnd
= fd_info
[fd
].hnd
;
5460 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5466 /* Configure timeouts for non-blocking read. */
5467 if (!GetCommTimeouts (hnd
, &ct
))
5472 ct
.ReadIntervalTimeout
= MAXDWORD
;
5473 ct
.ReadTotalTimeoutMultiplier
= 0;
5474 ct
.ReadTotalTimeoutConstant
= 0;
5475 if (!SetCommTimeouts (hnd
, &ct
))
5481 if (!ResetEvent (ovl
->hEvent
))
5486 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5488 if (GetLastError () != ERROR_IO_PENDING
)
5493 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5502 else /* FILE_SOCKET */
5504 if (winsock_lib
== NULL
) abort ();
5506 /* do the equivalent of a non-blocking read */
5507 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5508 if (waiting
== 0 && nchars
== 0)
5510 h_errno
= errno
= EWOULDBLOCK
;
5516 /* always use binary mode for sockets */
5517 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5518 if (res
== SOCKET_ERROR
)
5520 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5521 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5531 int nread
= _read (fd
, buffer
, count
);
5534 else if (nchars
== 0)
5539 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5540 /* Perform text mode translation if required. */
5541 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5543 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5544 /* If buffer contains only CR, return that. To be absolutely
5545 sure we should attempt to read the next char, but in
5546 practice a CR to be followed by LF would not appear by
5547 itself in the buffer. */
5548 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5550 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5556 nchars
= _read (fd
, buffer
, count
);
5561 /* From w32xfns.c */
5562 extern HANDLE interrupt_handle
;
5564 /* For now, don't bother with a non-blocking mode */
5566 sys_write (int fd
, const void * buffer
, unsigned int count
)
5576 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5578 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5584 /* Perform text mode translation if required. */
5585 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5587 char * tmpbuf
= alloca (count
* 2);
5588 unsigned char * src
= (void *)buffer
;
5589 unsigned char * dst
= tmpbuf
;
5594 unsigned char *next
;
5595 /* copy next line or remaining bytes */
5596 next
= _memccpy (dst
, src
, '\n', nbytes
);
5599 /* copied one line ending with '\n' */
5600 int copied
= next
- dst
;
5603 /* insert '\r' before '\n' */
5610 /* copied remaining partial line -> now finished */
5617 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5619 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5620 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5621 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5624 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5626 if (GetLastError () != ERROR_IO_PENDING
)
5631 if (detect_input_pending ())
5632 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5635 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5636 if (active
== WAIT_OBJECT_0
)
5637 { /* User pressed C-g, cancel write, then leave. Don't bother
5638 cleaning up as we may only get stuck in buggy drivers. */
5639 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5644 if (active
== WAIT_OBJECT_0
+ 1
5645 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5652 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5654 unsigned long nblock
= 0;
5655 if (winsock_lib
== NULL
) abort ();
5657 /* TODO: implement select() properly so non-blocking I/O works. */
5658 /* For now, make sure the write blocks. */
5659 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5660 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5662 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5664 /* Set the socket back to non-blocking if it was before,
5665 for other operations that support it. */
5666 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5669 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5672 if (nchars
== SOCKET_ERROR
)
5674 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5675 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5681 /* Some networked filesystems don't like too large writes, so
5682 break them into smaller chunks. See the Comments section of
5683 the MSDN documentation of WriteFile for details behind the
5684 choice of the value of CHUNK below. See also the thread
5685 http://thread.gmane.org/gmane.comp.version-control.git/145294
5686 in the git mailing list. */
5687 const unsigned char *p
= buffer
;
5688 const unsigned chunk
= 30 * 1024 * 1024;
5693 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5694 int n
= _write (fd
, p
, this_chunk
);
5702 else if (n
< this_chunk
)
5712 /* The Windows CRT functions are "optimized for speed", so they don't
5713 check for timezone and DST changes if they were last called less
5714 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
5715 all Emacs features that repeatedly call time functions (e.g.,
5716 display-time) are in real danger of missing timezone and DST
5717 changes. Calling tzset before each localtime call fixes that. */
5719 sys_localtime (const time_t *t
)
5722 return localtime (t
);
5727 /* Delayed loading of libraries. */
5729 Lisp_Object Vlibrary_cache
;
5731 /* The argument LIBRARIES is an alist that associates a symbol
5732 LIBRARY_ID, identifying an external DLL library known to Emacs, to
5733 a list of filenames under which the library is usually found. In
5734 most cases, the argument passed as LIBRARIES is the variable
5735 `dynamic-library-alist', which is initialized to a list of common
5736 library names. If the function loads the library successfully, it
5737 returns the handle of the DLL, and records the filename in the
5738 property :loaded-from of LIBRARY_ID; it returns NULL if the library
5739 could not be found, or when it was already loaded (because the
5740 handle is not recorded anywhere, and so is lost after use). It
5741 would be trivial to save the handle too in :loaded-from, but
5742 currently there's no use case for it. */
5744 w32_delayed_load (Lisp_Object libraries
, Lisp_Object library_id
)
5746 HMODULE library_dll
= NULL
;
5748 CHECK_SYMBOL (library_id
);
5750 if (CONSP (libraries
) && NILP (Fassq (library_id
, Vlibrary_cache
)))
5752 Lisp_Object found
= Qnil
;
5753 Lisp_Object dlls
= Fassq (library_id
, libraries
);
5756 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
5758 CHECK_STRING_CAR (dlls
);
5759 if (library_dll
= LoadLibrary (SDATA (XCAR (dlls
))))
5761 found
= XCAR (dlls
);
5766 Fput (library_id
, QCloaded_from
, found
);
5774 check_windows_init_file (void)
5776 /* A common indication that Emacs is not installed properly is when
5777 it cannot find the Windows installation file. If this file does
5778 not exist in the expected place, tell the user. */
5780 if (!noninteractive
&& !inhibit_window_system
)
5782 Lisp_Object objs
[2];
5783 Lisp_Object full_load_path
;
5784 Lisp_Object init_file
;
5787 objs
[0] = Vload_path
;
5788 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5789 full_load_path
= Fappend (2, objs
);
5790 init_file
= build_string ("term/w32-win");
5791 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5794 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5795 char *init_file_name
= SDATA (init_file
);
5796 char *load_path
= SDATA (load_path_print
);
5797 char *buffer
= alloca (1024
5798 + strlen (init_file_name
)
5799 + strlen (load_path
));
5802 "The Emacs Windows initialization file \"%s.el\" "
5803 "could not be found in your Emacs installation. "
5804 "Emacs checked the following directories for this file:\n"
5806 "When Emacs cannot find this file, it usually means that it "
5807 "was not installed properly, or its distribution file was "
5808 "not unpacked properly.\nSee the README.W32 file in the "
5809 "top-level Emacs directory for more information.",
5810 init_file_name
, load_path
);
5813 "Emacs Abort Dialog",
5814 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5815 /* Use the low-level Emacs abort. */
5829 /* shutdown the socket interface if necessary */
5838 /* Initialise the socket interface now if available and requested by
5839 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5840 delayed until open-network-stream is called (w32-has-winsock can
5841 also be used to dynamically load or reload winsock).
5843 Conveniently, init_environment is called before us, so
5844 PRELOAD_WINSOCK can be set in the registry. */
5846 /* Always initialize this correctly. */
5849 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5850 init_winsock (TRUE
);
5852 /* Initial preparation for subprocess support: replace our standard
5853 handles with non-inheritable versions. */
5856 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5857 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5858 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5860 parent
= GetCurrentProcess ();
5862 /* ignore errors when duplicating and closing; typically the
5863 handles will be invalid when running as a gui program. */
5864 DuplicateHandle (parent
,
5865 GetStdHandle (STD_INPUT_HANDLE
),
5870 DUPLICATE_SAME_ACCESS
);
5872 DuplicateHandle (parent
,
5873 GetStdHandle (STD_OUTPUT_HANDLE
),
5878 DUPLICATE_SAME_ACCESS
);
5880 DuplicateHandle (parent
,
5881 GetStdHandle (STD_ERROR_HANDLE
),
5886 DUPLICATE_SAME_ACCESS
);
5892 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5893 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5895 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5898 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5899 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5901 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5904 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5905 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5907 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5911 /* unfortunately, atexit depends on implementation of malloc */
5912 /* atexit (term_ntproc); */
5913 signal (SIGABRT
, term_ntproc
);
5915 /* determine which drives are fixed, for GetCachedVolumeInformation */
5917 /* GetDriveType must have trailing backslash. */
5918 char drive
[] = "A:\\";
5920 /* Loop over all possible drive letters */
5921 while (*drive
<= 'Z')
5923 /* Record if this drive letter refers to a fixed drive. */
5924 fixed_drives
[DRIVE_INDEX (*drive
)] =
5925 (GetDriveType (drive
) == DRIVE_FIXED
);
5930 /* Reset the volume info cache. */
5931 volume_cache
= NULL
;
5934 /* Check to see if Emacs has been installed correctly. */
5935 check_windows_init_file ();
5939 shutdown_handler ensures that buffers' autosave files are
5940 up to date when the user logs off, or the system shuts down.
5943 shutdown_handler (DWORD type
)
5945 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5946 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
5947 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
5948 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
5950 /* Shut down cleanly, making sure autosave files are up to date. */
5951 shut_down_emacs (0, 0, Qnil
);
5954 /* Allow other handlers to handle this signal. */
5959 globals_of_w32 is used to initialize those global variables that
5960 must always be initialized on startup even when the global variable
5961 initialized is non zero (see the function main in emacs.c).
5964 globals_of_w32 (void)
5966 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
5968 get_process_times_fn
= (GetProcessTimes_Proc
)
5969 GetProcAddress (kernel32
, "GetProcessTimes");
5971 DEFSYM (QCloaded_from
, ":loaded-from");
5973 Vlibrary_cache
= Qnil
;
5974 staticpro (&Vlibrary_cache
);
5976 g_b_init_is_windows_9x
= 0;
5977 g_b_init_open_process_token
= 0;
5978 g_b_init_get_token_information
= 0;
5979 g_b_init_lookup_account_sid
= 0;
5980 g_b_init_get_sid_sub_authority
= 0;
5981 g_b_init_get_sid_sub_authority_count
= 0;
5982 g_b_init_get_file_security
= 0;
5983 g_b_init_get_security_descriptor_owner
= 0;
5984 g_b_init_get_security_descriptor_group
= 0;
5985 g_b_init_is_valid_sid
= 0;
5986 g_b_init_create_toolhelp32_snapshot
= 0;
5987 g_b_init_process32_first
= 0;
5988 g_b_init_process32_next
= 0;
5989 g_b_init_open_thread_token
= 0;
5990 g_b_init_impersonate_self
= 0;
5991 g_b_init_revert_to_self
= 0;
5992 g_b_init_get_process_memory_info
= 0;
5993 g_b_init_get_process_working_set_size
= 0;
5994 g_b_init_global_memory_status
= 0;
5995 g_b_init_global_memory_status_ex
= 0;
5996 g_b_init_equal_sid
= 0;
5997 g_b_init_copy_sid
= 0;
5998 g_b_init_get_length_sid
= 0;
5999 g_b_init_get_native_system_info
= 0;
6000 g_b_init_get_system_times
= 0;
6001 num_of_processors
= 0;
6002 /* The following sets a handler for shutdown notifications for
6003 console apps. This actually applies to Emacs in both console and
6004 GUI modes, since we had to fool windows into thinking emacs is a
6005 console application to get console mode to work. */
6006 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
6008 /* "None" is the default group name on standalone workstations. */
6009 strcpy (dflt_group_name
, "None");
6012 /* For make-serial-process */
6014 serial_open (char *port
)
6020 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
6021 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
6022 if (hnd
== INVALID_HANDLE_VALUE
)
6023 error ("Could not open %s", port
);
6024 fd
= (int) _open_osfhandle ((int) hnd
, 0);
6026 error ("Could not open %s", port
);
6030 error ("Could not create child process");
6032 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6033 fd_info
[ fd
].hnd
= hnd
;
6034 fd_info
[ fd
].flags
|=
6035 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
6036 if (fd_info
[ fd
].cp
!= NULL
)
6038 error ("fd_info[fd = %d] is already in use", fd
);
6040 fd_info
[ fd
].cp
= cp
;
6041 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6042 if (cp
->ovl_read
.hEvent
== NULL
)
6043 error ("Could not create read event");
6044 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6045 if (cp
->ovl_write
.hEvent
== NULL
)
6046 error ("Could not create write event");
6051 /* For serial-process-configure */
6053 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
6055 Lisp_Object childp2
= Qnil
;
6056 Lisp_Object tem
= Qnil
;
6060 char summary
[4] = "???"; /* This usually becomes "8N1". */
6062 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6063 error ("Not a serial process");
6064 hnd
= fd_info
[ p
->outfd
].hnd
;
6066 childp2
= Fcopy_sequence (p
->childp
);
6068 /* Initialize timeouts for blocking read and blocking write. */
6069 if (!GetCommTimeouts (hnd
, &ct
))
6070 error ("GetCommTimeouts() failed");
6071 ct
.ReadIntervalTimeout
= 0;
6072 ct
.ReadTotalTimeoutMultiplier
= 0;
6073 ct
.ReadTotalTimeoutConstant
= 0;
6074 ct
.WriteTotalTimeoutMultiplier
= 0;
6075 ct
.WriteTotalTimeoutConstant
= 0;
6076 if (!SetCommTimeouts (hnd
, &ct
))
6077 error ("SetCommTimeouts() failed");
6078 /* Read port attributes and prepare default configuration. */
6079 memset (&dcb
, 0, sizeof (dcb
));
6080 dcb
.DCBlength
= sizeof (DCB
);
6081 if (!GetCommState (hnd
, &dcb
))
6082 error ("GetCommState() failed");
6085 dcb
.fAbortOnError
= FALSE
;
6086 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6091 /* Configure speed. */
6092 if (!NILP (Fplist_member (contact
, QCspeed
)))
6093 tem
= Fplist_get (contact
, QCspeed
);
6095 tem
= Fplist_get (p
->childp
, QCspeed
);
6097 dcb
.BaudRate
= XINT (tem
);
6098 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6100 /* Configure bytesize. */
6101 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6102 tem
= Fplist_get (contact
, QCbytesize
);
6104 tem
= Fplist_get (p
->childp
, QCbytesize
);
6106 tem
= make_number (8);
6108 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6109 error (":bytesize must be nil (8), 7, or 8");
6110 dcb
.ByteSize
= XINT (tem
);
6111 summary
[0] = XINT (tem
) + '0';
6112 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6114 /* Configure parity. */
6115 if (!NILP (Fplist_member (contact
, QCparity
)))
6116 tem
= Fplist_get (contact
, QCparity
);
6118 tem
= Fplist_get (p
->childp
, QCparity
);
6119 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6120 error (":parity must be nil (no parity), `even', or `odd'");
6121 dcb
.fParity
= FALSE
;
6122 dcb
.Parity
= NOPARITY
;
6123 dcb
.fErrorChar
= FALSE
;
6128 else if (EQ (tem
, Qeven
))
6132 dcb
.Parity
= EVENPARITY
;
6133 dcb
.fErrorChar
= TRUE
;
6135 else if (EQ (tem
, Qodd
))
6139 dcb
.Parity
= ODDPARITY
;
6140 dcb
.fErrorChar
= TRUE
;
6142 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6144 /* Configure stopbits. */
6145 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6146 tem
= Fplist_get (contact
, QCstopbits
);
6148 tem
= Fplist_get (p
->childp
, QCstopbits
);
6150 tem
= make_number (1);
6152 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6153 error (":stopbits must be nil (1 stopbit), 1, or 2");
6154 summary
[2] = XINT (tem
) + '0';
6155 if (XINT (tem
) == 1)
6156 dcb
.StopBits
= ONESTOPBIT
;
6157 else if (XINT (tem
) == 2)
6158 dcb
.StopBits
= TWOSTOPBITS
;
6159 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6161 /* Configure flowcontrol. */
6162 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6163 tem
= Fplist_get (contact
, QCflowcontrol
);
6165 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6166 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6167 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6168 dcb
.fOutxCtsFlow
= FALSE
;
6169 dcb
.fOutxDsrFlow
= FALSE
;
6170 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6171 dcb
.fDsrSensitivity
= FALSE
;
6172 dcb
.fTXContinueOnXoff
= FALSE
;
6175 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6176 dcb
.XonChar
= 17; /* Control-Q */
6177 dcb
.XoffChar
= 19; /* Control-S */
6180 /* Already configured. */
6182 else if (EQ (tem
, Qhw
))
6184 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6185 dcb
.fOutxCtsFlow
= TRUE
;
6187 else if (EQ (tem
, Qsw
))
6192 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6194 /* Activate configuration. */
6195 if (!SetCommState (hnd
, &dcb
))
6196 error ("SetCommState() failed");
6198 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6199 p
->childp
= childp2
;
6205 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
6210 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
6211 int fd
= process
->infd
;
6215 n
= sys_read (fd
, (char*)buf
, sz
);
6222 if (err
== EWOULDBLOCK
)
6224 /* Set a small timeout. */
6225 EMACS_SET_SECS_USECS (timeout
, 1, 0);
6227 FD_SET ((int)fd
, &fdset
);
6229 /* Use select with the timeout to poll the selector. */
6230 sc
= select (fd
+ 1, &fdset
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0,
6234 continue; /* Try again. */
6236 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
6237 Also accept select return 0 as an indicator to EAGAIN. */
6238 if (sc
== 0 || errno
== EWOULDBLOCK
)
6241 err
= errno
; /* Other errors are just passed on. */
6244 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
6251 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
6253 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
6254 int fd
= process
->outfd
;
6255 ssize_t n
= sys_write (fd
, buf
, sz
);
6257 /* 0 or more bytes written means everything went fine. */
6261 /* Negative bytes written means we got an error in errno.
6262 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
6263 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
6264 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
6268 #endif /* HAVE_GNUTLS */