1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994-1995, 2000-2012 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
;
100 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
101 /* This either is not in psapi.h or guarded by higher value of
102 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
103 defines it in psapi.h */
104 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
106 DWORD PageFaultCount
;
107 DWORD PeakWorkingSetSize
;
108 DWORD WorkingSetSize
;
109 DWORD QuotaPeakPagedPoolUsage
;
110 DWORD QuotaPagedPoolUsage
;
111 DWORD QuotaPeakNonPagedPoolUsage
;
112 DWORD QuotaNonPagedPoolUsage
;
114 DWORD PeakPagefileUsage
;
116 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
119 /* TCP connection support. */
120 #include <sys/socket.h>
143 #include "dispextern.h" /* for xstrcasecmp */
144 #include "coding.h" /* for Vlocale_coding_system */
146 #include "careadlinkat.h"
147 #include "allocator.h"
149 /* For serial_configure and serial_open. */
152 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
153 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
155 Lisp_Object QCloaded_from
;
157 void globals_of_w32 (void);
158 static DWORD
get_rid (PSID
);
161 /* Initialization states.
163 WARNING: If you add any more such variables for additional APIs,
164 you MUST add initialization for them to globals_of_w32
165 below. This is because these variables might get set
166 to non-NULL values during dumping, but the dumped Emacs
167 cannot reuse those values, because it could be run on a
168 different version of the OS, where API addresses are
170 static BOOL g_b_init_is_windows_9x
;
171 static BOOL g_b_init_open_process_token
;
172 static BOOL g_b_init_get_token_information
;
173 static BOOL g_b_init_lookup_account_sid
;
174 static BOOL g_b_init_get_sid_sub_authority
;
175 static BOOL g_b_init_get_sid_sub_authority_count
;
176 static BOOL g_b_init_get_file_security
;
177 static BOOL g_b_init_get_security_descriptor_owner
;
178 static BOOL g_b_init_get_security_descriptor_group
;
179 static BOOL g_b_init_is_valid_sid
;
180 static BOOL g_b_init_create_toolhelp32_snapshot
;
181 static BOOL g_b_init_process32_first
;
182 static BOOL g_b_init_process32_next
;
183 static BOOL g_b_init_open_thread_token
;
184 static BOOL g_b_init_impersonate_self
;
185 static BOOL g_b_init_revert_to_self
;
186 static BOOL g_b_init_get_process_memory_info
;
187 static BOOL g_b_init_get_process_working_set_size
;
188 static BOOL g_b_init_global_memory_status
;
189 static BOOL g_b_init_global_memory_status_ex
;
190 static BOOL g_b_init_get_length_sid
;
191 static BOOL g_b_init_equal_sid
;
192 static BOOL g_b_init_copy_sid
;
193 static BOOL g_b_init_get_native_system_info
;
194 static BOOL g_b_init_get_system_times
;
197 BEGIN: Wrapper functions around OpenProcessToken
198 and other functions in advapi32.dll that are only
199 supported in Windows NT / 2k / XP
201 /* ** Function pointer typedefs ** */
202 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
203 HANDLE ProcessHandle
,
205 PHANDLE TokenHandle
);
206 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
208 TOKEN_INFORMATION_CLASS TokenInformationClass
,
209 LPVOID TokenInformation
,
210 DWORD TokenInformationLength
,
211 PDWORD ReturnLength
);
212 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
213 HANDLE process_handle
,
214 LPFILETIME creation_time
,
215 LPFILETIME exit_time
,
216 LPFILETIME kernel_time
,
217 LPFILETIME user_time
);
219 GetProcessTimes_Proc get_process_times_fn
= NULL
;
222 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
223 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
225 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
226 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
228 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
229 LPCTSTR lpSystemName
,
234 LPDWORD cbDomainName
,
235 PSID_NAME_USE peUse
);
236 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
239 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
241 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
243 SECURITY_INFORMATION RequestedInformation
,
244 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
246 LPDWORD lpnLengthNeeded
);
247 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
248 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
250 LPBOOL lpbOwnerDefaulted
);
251 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
252 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
254 LPBOOL lpbGroupDefaulted
);
255 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
257 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
259 DWORD th32ProcessID
);
260 typedef BOOL (WINAPI
* Process32First_Proc
) (
262 LPPROCESSENTRY32 lppe
);
263 typedef BOOL (WINAPI
* Process32Next_Proc
) (
265 LPPROCESSENTRY32 lppe
);
266 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
270 PHANDLE TokenHandle
);
271 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
272 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
273 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
274 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
276 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
278 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
280 DWORD
* lpMinimumWorkingSetSize
,
281 DWORD
* lpMaximumWorkingSetSize
);
282 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
283 LPMEMORYSTATUS lpBuffer
);
284 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
285 LPMEMORY_STATUS_EX lpBuffer
);
286 typedef BOOL (WINAPI
* CopySid_Proc
) (
287 DWORD nDestinationSidLength
,
288 PSID pDestinationSid
,
290 typedef BOOL (WINAPI
* EqualSid_Proc
) (
293 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
295 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
296 LPSYSTEM_INFO lpSystemInfo
);
297 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
298 LPFILETIME lpIdleTime
,
299 LPFILETIME lpKernelTime
,
300 LPFILETIME lpUserTime
);
302 /* ** A utility function ** */
306 static BOOL s_b_ret
= 0;
307 OSVERSIONINFO os_ver
;
308 if (g_b_init_is_windows_9x
== 0)
310 g_b_init_is_windows_9x
= 1;
311 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
312 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
313 if (GetVersionEx (&os_ver
))
315 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
321 static Lisp_Object
ltime (ULONGLONG
);
323 /* Get total user and system times for get-internal-run-time.
324 Returns a list of integers if the times are provided by the OS
325 (NT derivatives), otherwise it returns the result of current-time. */
327 w32_get_internal_run_time (void)
329 if (get_process_times_fn
)
331 FILETIME create
, exit
, kernel
, user
;
332 HANDLE proc
= GetCurrentProcess ();
333 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
335 LARGE_INTEGER user_int
, kernel_int
, total
;
336 user_int
.LowPart
= user
.dwLowDateTime
;
337 user_int
.HighPart
= user
.dwHighDateTime
;
338 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
339 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
340 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
341 return ltime (total
.QuadPart
);
345 return Fcurrent_time ();
348 /* ** The wrapper functions ** */
351 open_process_token (HANDLE ProcessHandle
,
355 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
356 HMODULE hm_advapi32
= NULL
;
357 if (is_windows_9x () == TRUE
)
361 if (g_b_init_open_process_token
== 0)
363 g_b_init_open_process_token
= 1;
364 hm_advapi32
= LoadLibrary ("Advapi32.dll");
365 s_pfn_Open_Process_Token
=
366 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
368 if (s_pfn_Open_Process_Token
== NULL
)
373 s_pfn_Open_Process_Token (
381 get_token_information (HANDLE TokenHandle
,
382 TOKEN_INFORMATION_CLASS TokenInformationClass
,
383 LPVOID TokenInformation
,
384 DWORD TokenInformationLength
,
387 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
388 HMODULE hm_advapi32
= NULL
;
389 if (is_windows_9x () == TRUE
)
393 if (g_b_init_get_token_information
== 0)
395 g_b_init_get_token_information
= 1;
396 hm_advapi32
= LoadLibrary ("Advapi32.dll");
397 s_pfn_Get_Token_Information
=
398 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
400 if (s_pfn_Get_Token_Information
== NULL
)
405 s_pfn_Get_Token_Information (
407 TokenInformationClass
,
409 TokenInformationLength
,
415 lookup_account_sid (LPCTSTR lpSystemName
,
420 LPDWORD cbDomainName
,
423 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
424 HMODULE hm_advapi32
= NULL
;
425 if (is_windows_9x () == TRUE
)
429 if (g_b_init_lookup_account_sid
== 0)
431 g_b_init_lookup_account_sid
= 1;
432 hm_advapi32
= LoadLibrary ("Advapi32.dll");
433 s_pfn_Lookup_Account_Sid
=
434 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
436 if (s_pfn_Lookup_Account_Sid
== NULL
)
441 s_pfn_Lookup_Account_Sid (
453 get_sid_sub_authority (PSID pSid
, DWORD n
)
455 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
456 static DWORD zero
= 0U;
457 HMODULE hm_advapi32
= NULL
;
458 if (is_windows_9x () == TRUE
)
462 if (g_b_init_get_sid_sub_authority
== 0)
464 g_b_init_get_sid_sub_authority
= 1;
465 hm_advapi32
= LoadLibrary ("Advapi32.dll");
466 s_pfn_Get_Sid_Sub_Authority
=
467 (GetSidSubAuthority_Proc
) GetProcAddress (
468 hm_advapi32
, "GetSidSubAuthority");
470 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
474 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
478 get_sid_sub_authority_count (PSID pSid
)
480 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
481 static UCHAR zero
= 0U;
482 HMODULE hm_advapi32
= NULL
;
483 if (is_windows_9x () == TRUE
)
487 if (g_b_init_get_sid_sub_authority_count
== 0)
489 g_b_init_get_sid_sub_authority_count
= 1;
490 hm_advapi32
= LoadLibrary ("Advapi32.dll");
491 s_pfn_Get_Sid_Sub_Authority_Count
=
492 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
493 hm_advapi32
, "GetSidSubAuthorityCount");
495 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
499 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
503 get_file_security (LPCTSTR lpFileName
,
504 SECURITY_INFORMATION RequestedInformation
,
505 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
507 LPDWORD lpnLengthNeeded
)
509 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
510 HMODULE hm_advapi32
= NULL
;
511 if (is_windows_9x () == TRUE
)
515 if (g_b_init_get_file_security
== 0)
517 g_b_init_get_file_security
= 1;
518 hm_advapi32
= LoadLibrary ("Advapi32.dll");
519 s_pfn_Get_File_Security
=
520 (GetFileSecurity_Proc
) GetProcAddress (
521 hm_advapi32
, GetFileSecurity_Name
);
523 if (s_pfn_Get_File_Security
== NULL
)
527 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
528 pSecurityDescriptor
, nLength
,
533 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
535 LPBOOL lpbOwnerDefaulted
)
537 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
538 HMODULE hm_advapi32
= NULL
;
539 if (is_windows_9x () == TRUE
)
543 if (g_b_init_get_security_descriptor_owner
== 0)
545 g_b_init_get_security_descriptor_owner
= 1;
546 hm_advapi32
= LoadLibrary ("Advapi32.dll");
547 s_pfn_Get_Security_Descriptor_Owner
=
548 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
549 hm_advapi32
, "GetSecurityDescriptorOwner");
551 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
555 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
560 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
562 LPBOOL lpbGroupDefaulted
)
564 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
565 HMODULE hm_advapi32
= NULL
;
566 if (is_windows_9x () == TRUE
)
570 if (g_b_init_get_security_descriptor_group
== 0)
572 g_b_init_get_security_descriptor_group
= 1;
573 hm_advapi32
= LoadLibrary ("Advapi32.dll");
574 s_pfn_Get_Security_Descriptor_Group
=
575 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
576 hm_advapi32
, "GetSecurityDescriptorGroup");
578 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
582 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
587 is_valid_sid (PSID sid
)
589 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
590 HMODULE hm_advapi32
= NULL
;
591 if (is_windows_9x () == TRUE
)
595 if (g_b_init_is_valid_sid
== 0)
597 g_b_init_is_valid_sid
= 1;
598 hm_advapi32
= LoadLibrary ("Advapi32.dll");
600 (IsValidSid_Proc
) GetProcAddress (
601 hm_advapi32
, "IsValidSid");
603 if (s_pfn_Is_Valid_Sid
== NULL
)
607 return (s_pfn_Is_Valid_Sid (sid
));
611 equal_sid (PSID sid1
, PSID sid2
)
613 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
614 HMODULE hm_advapi32
= NULL
;
615 if (is_windows_9x () == TRUE
)
619 if (g_b_init_equal_sid
== 0)
621 g_b_init_equal_sid
= 1;
622 hm_advapi32
= LoadLibrary ("Advapi32.dll");
624 (EqualSid_Proc
) GetProcAddress (
625 hm_advapi32
, "EqualSid");
627 if (s_pfn_Equal_Sid
== NULL
)
631 return (s_pfn_Equal_Sid (sid1
, sid2
));
635 get_length_sid (PSID sid
)
637 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
638 HMODULE hm_advapi32
= NULL
;
639 if (is_windows_9x () == TRUE
)
643 if (g_b_init_get_length_sid
== 0)
645 g_b_init_get_length_sid
= 1;
646 hm_advapi32
= LoadLibrary ("Advapi32.dll");
647 s_pfn_Get_Length_Sid
=
648 (GetLengthSid_Proc
) GetProcAddress (
649 hm_advapi32
, "GetLengthSid");
651 if (s_pfn_Get_Length_Sid
== NULL
)
655 return (s_pfn_Get_Length_Sid (sid
));
659 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
661 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
662 HMODULE hm_advapi32
= NULL
;
663 if (is_windows_9x () == TRUE
)
667 if (g_b_init_copy_sid
== 0)
669 g_b_init_copy_sid
= 1;
670 hm_advapi32
= LoadLibrary ("Advapi32.dll");
672 (CopySid_Proc
) GetProcAddress (
673 hm_advapi32
, "CopySid");
675 if (s_pfn_Copy_Sid
== NULL
)
679 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
683 END: Wrapper functions around OpenProcessToken
684 and other functions in advapi32.dll that are only
685 supported in Windows NT / 2k / XP
689 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
691 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
692 if (is_windows_9x () != TRUE
)
694 if (g_b_init_get_native_system_info
== 0)
696 g_b_init_get_native_system_info
= 1;
697 s_pfn_Get_Native_System_Info
=
698 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
699 "GetNativeSystemInfo");
701 if (s_pfn_Get_Native_System_Info
!= NULL
)
702 s_pfn_Get_Native_System_Info (lpSystemInfo
);
705 lpSystemInfo
->dwNumberOfProcessors
= -1;
709 get_system_times (LPFILETIME lpIdleTime
,
710 LPFILETIME lpKernelTime
,
711 LPFILETIME lpUserTime
)
713 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
714 if (is_windows_9x () == TRUE
)
718 if (g_b_init_get_system_times
== 0)
720 g_b_init_get_system_times
= 1;
721 s_pfn_Get_System_times
=
722 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
725 if (s_pfn_Get_System_times
== NULL
)
727 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
730 /* Equivalent of strerror for W32 error codes. */
732 w32_strerror (int error_no
)
734 static char buf
[500];
737 error_no
= GetLastError ();
740 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
742 0, /* choose most suitable language */
743 buf
, sizeof (buf
), NULL
))
744 sprintf (buf
, "w32 error %u", error_no
);
748 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
749 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
751 This is called from alloc.c:valid_pointer_p. */
753 w32_valid_pointer_p (void *p
, int size
)
756 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
760 unsigned char *buf
= alloca (size
);
761 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
770 static char startup_dir
[MAXPATHLEN
];
772 /* Get the current working directory. */
777 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
781 /* Emacs doesn't actually change directory itself, it stays in the
782 same directory where it was started. */
783 strcpy (dir
, startup_dir
);
788 /* Emulate getloadavg. */
797 /* Number of processors on this machine. */
798 static unsigned num_of_processors
;
800 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
801 static struct load_sample samples
[16*60];
802 static int first_idx
= -1, last_idx
= -1;
803 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
808 int next_idx
= from
+ 1;
810 if (next_idx
>= max_idx
)
819 int prev_idx
= from
- 1;
822 prev_idx
= max_idx
- 1;
828 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
831 FILETIME ft_idle
, ft_user
, ft_kernel
;
833 /* Initialize the number of processors on this machine. */
834 if (num_of_processors
<= 0)
836 get_native_system_info (&sysinfo
);
837 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
838 if (num_of_processors
<= 0)
840 GetSystemInfo (&sysinfo
);
841 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
843 if (num_of_processors
<= 0)
844 num_of_processors
= 1;
847 /* TODO: Take into account threads that are ready to run, by
848 sampling the "\System\Processor Queue Length" performance
849 counter. The code below accounts only for threads that are
852 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
854 ULARGE_INTEGER uidle
, ukernel
, uuser
;
856 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
857 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
858 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
859 *idle
= uidle
.QuadPart
;
860 *kernel
= ukernel
.QuadPart
;
861 *user
= uuser
.QuadPart
;
871 /* Produce the load average for a given time interval, using the
872 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
873 1-minute, 5-minute, or 15-minute average, respectively. */
877 double retval
= -1.0;
880 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
881 time_t now
= samples
[last_idx
].sample_time
;
883 if (first_idx
!= last_idx
)
885 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
887 tdiff
= difftime (now
, samples
[idx
].sample_time
);
888 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
891 samples
[last_idx
].kernel
+ samples
[last_idx
].user
892 - (samples
[idx
].kernel
+ samples
[idx
].user
);
893 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
895 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
898 if (idx
== first_idx
)
907 getloadavg (double loadavg
[], int nelem
)
910 ULONGLONG idle
, kernel
, user
;
911 time_t now
= time (NULL
);
913 /* Store another sample. We ignore samples that are less than 1 sec
915 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
917 sample_system_load (&idle
, &kernel
, &user
);
918 last_idx
= buf_next (last_idx
);
919 samples
[last_idx
].sample_time
= now
;
920 samples
[last_idx
].idle
= idle
;
921 samples
[last_idx
].kernel
= kernel
;
922 samples
[last_idx
].user
= user
;
923 /* If the buffer has more that 15 min worth of samples, discard
926 first_idx
= last_idx
;
927 while (first_idx
!= last_idx
928 && (difftime (now
, samples
[first_idx
].sample_time
)
929 >= 15.0*60 + 2*DBL_EPSILON
*now
))
930 first_idx
= buf_next (first_idx
);
933 for (elem
= 0; elem
< nelem
; elem
++)
935 double avg
= getavg (elem
);
945 /* Emulate getpwuid, getpwnam and others. */
947 #define PASSWD_FIELD_SIZE 256
949 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
950 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
951 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
952 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
953 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
955 static struct passwd dflt_passwd
=
967 static char dflt_group_name
[GNLEN
+1];
969 static struct group dflt_group
=
971 /* When group information is not available, we return this as the
972 group for all files. */
980 return dflt_passwd
.pw_uid
;
986 /* I could imagine arguing for checking to see whether the user is
987 in the Administrators group and returning a UID of 0 for that
988 case, but I don't know how wise that would be in the long run. */
995 return dflt_passwd
.pw_gid
;
1005 getpwuid (unsigned uid
)
1007 if (uid
== dflt_passwd
.pw_uid
)
1008 return &dflt_passwd
;
1013 getgrgid (gid_t gid
)
1019 getpwnam (char *name
)
1023 pw
= getpwuid (getuid ());
1027 if (xstrcasecmp (name
, pw
->pw_name
))
1034 init_user_info (void)
1036 /* Find the user's real name by opening the process token and
1037 looking up the name associated with the user-sid in that token.
1039 Use the relative portion of the identifier authority value from
1040 the user-sid as the user id value (same for group id using the
1041 primary group sid from the process token). */
1043 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1044 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1045 DWORD glength
= sizeof (gname
);
1046 HANDLE token
= NULL
;
1047 SID_NAME_USE user_type
;
1048 unsigned char *buf
= NULL
;
1050 TOKEN_USER user_token
;
1051 TOKEN_PRIMARY_GROUP group_token
;
1054 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1057 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1058 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1060 buf
= xmalloc (blen
);
1061 result
= get_token_information (token
, TokenUser
,
1062 (LPVOID
)buf
, blen
, &needed
);
1065 memcpy (&user_token
, buf
, sizeof (user_token
));
1066 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1068 domain
, &dlength
, &user_type
);
1076 strcpy (dflt_passwd
.pw_name
, uname
);
1077 /* Determine a reasonable uid value. */
1078 if (xstrcasecmp ("administrator", uname
) == 0)
1080 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1081 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1085 /* Use the last sub-authority value of the RID, the relative
1086 portion of the SID, as user/group ID. */
1087 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1089 /* Get group id and name. */
1090 result
= get_token_information (token
, TokenPrimaryGroup
,
1091 (LPVOID
)buf
, blen
, &needed
);
1092 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1094 buf
= xrealloc (buf
, blen
= needed
);
1095 result
= get_token_information (token
, TokenPrimaryGroup
,
1096 (LPVOID
)buf
, blen
, &needed
);
1100 memcpy (&group_token
, buf
, sizeof (group_token
));
1101 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1102 dlength
= sizeof (domain
);
1103 /* If we can get at the real Primary Group name, use that.
1104 Otherwise, the default group name was already set to
1105 "None" in globals_of_w32. */
1106 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1107 gname
, &glength
, NULL
, &dlength
,
1109 strcpy (dflt_group_name
, gname
);
1112 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1115 /* If security calls are not supported (presumably because we
1116 are running under Windows 9X), fallback to this: */
1117 else if (GetUserName (uname
, &ulength
))
1119 strcpy (dflt_passwd
.pw_name
, uname
);
1120 if (xstrcasecmp ("administrator", uname
) == 0)
1121 dflt_passwd
.pw_uid
= 0;
1123 dflt_passwd
.pw_uid
= 123;
1124 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1128 strcpy (dflt_passwd
.pw_name
, "unknown");
1129 dflt_passwd
.pw_uid
= 123;
1130 dflt_passwd
.pw_gid
= 123;
1132 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1134 /* Ensure HOME and SHELL are defined. */
1135 if (getenv ("HOME") == NULL
)
1137 if (getenv ("SHELL") == NULL
)
1140 /* Set dir and shell from environment variables. */
1141 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1142 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1146 CloseHandle (token
);
1152 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1153 return ((rand () << 15) | rand ());
1163 /* Normalize filename by converting all path separators to
1164 the specified separator. Also conditionally convert upper
1165 case path name components to lower case. */
1168 normalize_filename (register char *fp
, char path_sep
)
1173 /* Always lower-case drive letters a-z, even if the filesystem
1174 preserves case in filenames.
1175 This is so filenames can be compared by string comparison
1176 functions that are case-sensitive. Even case-preserving filesystems
1177 do not distinguish case in drive letters. */
1178 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1184 if (NILP (Vw32_downcase_file_names
))
1188 if (*fp
== '/' || *fp
== '\\')
1195 sep
= path_sep
; /* convert to this path separator */
1196 elem
= fp
; /* start of current path element */
1199 if (*fp
>= 'a' && *fp
<= 'z')
1200 elem
= 0; /* don't convert this element */
1202 if (*fp
== 0 || *fp
== ':')
1204 sep
= *fp
; /* restore current separator (or 0) */
1205 *fp
= '/'; /* after conversion of this element */
1208 if (*fp
== '/' || *fp
== '\\')
1210 if (elem
&& elem
!= fp
)
1212 *fp
= 0; /* temporary end of string */
1213 _strlwr (elem
); /* while we convert to lower case */
1215 *fp
= sep
; /* convert (or restore) path separator */
1216 elem
= fp
+ 1; /* next element starts after separator */
1222 /* Destructively turn backslashes into slashes. */
1224 dostounix_filename (register char *p
)
1226 normalize_filename (p
, '/');
1229 /* Destructively turn slashes into backslashes. */
1231 unixtodos_filename (register char *p
)
1233 normalize_filename (p
, '\\');
1236 /* Remove all CR's that are followed by a LF.
1237 (From msdos.c...probably should figure out a way to share it,
1238 although this code isn't going to ever change.) */
1240 crlf_to_lf (register int n
, register unsigned char *buf
)
1242 unsigned char *np
= buf
;
1243 unsigned char *startp
= buf
;
1244 unsigned char *endp
= buf
+ n
;
1248 while (buf
< endp
- 1)
1252 if (*(++buf
) != 0x0a)
1263 /* Parse the root part of file name, if present. Return length and
1264 optionally store pointer to char after root. */
1266 parse_root (char * name
, char ** pPath
)
1268 char * start
= name
;
1273 /* find the root name of the volume if given */
1274 if (isalpha (name
[0]) && name
[1] == ':')
1276 /* skip past drive specifier */
1278 if (IS_DIRECTORY_SEP (name
[0]))
1281 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1287 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1292 if (IS_DIRECTORY_SEP (name
[0]))
1299 return name
- start
;
1302 /* Get long base name for name; name is assumed to be absolute. */
1304 get_long_basename (char * name
, char * buf
, int size
)
1306 WIN32_FIND_DATA find_data
;
1310 /* must be valid filename, no wild cards or other invalid characters */
1311 if (_mbspbrk (name
, "*?|<>\""))
1314 dir_handle
= FindFirstFile (name
, &find_data
);
1315 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1317 if ((len
= strlen (find_data
.cFileName
)) < size
)
1318 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1321 FindClose (dir_handle
);
1326 /* Get long name for file, if possible (assumed to be absolute). */
1328 w32_get_long_filename (char * name
, char * buf
, int size
)
1333 char full
[ MAX_PATH
];
1336 len
= strlen (name
);
1337 if (len
>= MAX_PATH
)
1340 /* Use local copy for destructive modification. */
1341 memcpy (full
, name
, len
+1);
1342 unixtodos_filename (full
);
1344 /* Copy root part verbatim. */
1345 len
= parse_root (full
, &p
);
1346 memcpy (o
, full
, len
);
1351 while (p
!= NULL
&& *p
)
1354 p
= strchr (q
, '\\');
1356 len
= get_long_basename (full
, o
, size
);
1379 is_unc_volume (const char *filename
)
1381 const char *ptr
= filename
;
1383 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1386 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1392 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1395 sigsetmask (int signal_mask
)
1413 sigunblock (int sig
)
1419 sigemptyset (sigset_t
*set
)
1425 sigaddset (sigset_t
*set
, int signo
)
1431 sigfillset (sigset_t
*set
)
1437 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1443 pthread_sigmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1445 if (sigprocmask (how
, set
, oset
) == -1)
1451 setpgrp (int pid
, int gid
)
1462 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1465 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1468 HKEY hrootkey
= NULL
;
1471 /* Check both the current user and the local machine to see if
1472 we have any resources. */
1474 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1478 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1479 && (lpvalue
= xmalloc (cbData
)) != NULL
1480 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1482 RegCloseKey (hrootkey
);
1488 RegCloseKey (hrootkey
);
1491 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1495 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1496 && (lpvalue
= xmalloc (cbData
)) != NULL
1497 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1499 RegCloseKey (hrootkey
);
1505 RegCloseKey (hrootkey
);
1511 char *get_emacs_configuration (void);
1514 init_environment (char ** argv
)
1516 static const char * const tempdirs
[] = {
1517 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1522 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1524 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1525 temporary files and assume "/tmp" if $TMPDIR is unset, which
1526 will break on DOS/Windows. Refuse to work if we cannot find
1527 a directory, not even "c:/", usable for that purpose. */
1528 for (i
= 0; i
< imax
; i
++)
1530 const char *tmp
= tempdirs
[i
];
1533 tmp
= getenv (tmp
+ 1);
1534 /* Note that `access' can lie to us if the directory resides on a
1535 read-only filesystem, like CD-ROM or a write-protected floppy.
1536 The only way to be really sure is to actually create a file and
1537 see if it succeeds. But I think that's too much to ask. */
1538 if (tmp
&& sys_access (tmp
, D_OK
) == 0)
1540 char * var
= alloca (strlen (tmp
) + 8);
1541 sprintf (var
, "TMPDIR=%s", tmp
);
1542 _putenv (strdup (var
));
1549 Fcons (build_string ("no usable temporary directories found!!"),
1551 "While setting TMPDIR: ");
1553 /* Check for environment variables and use registry settings if they
1554 don't exist. Fallback on default values where applicable. */
1559 char locale_name
[32];
1560 struct stat ignored
;
1561 char default_home
[MAX_PATH
];
1564 static const struct env_entry
1571 {"PRELOAD_WINSOCK", NULL
},
1572 {"emacs_dir", "C:/emacs"},
1573 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1574 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1575 {"EMACSDATA", "%emacs_dir%/etc"},
1576 {"EMACSPATH", "%emacs_dir%/bin"},
1577 /* We no longer set INFOPATH because Info-default-directory-list
1579 /* {"INFOPATH", "%emacs_dir%/info"}, */
1580 {"EMACSDOC", "%emacs_dir%/etc"},
1585 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1587 /* We need to copy dflt_envvars[] and work on the copy because we
1588 don't want the dumped Emacs to inherit the values of
1589 environment variables we saw during dumping (which could be on
1590 a different system). The defaults above must be left intact. */
1591 struct env_entry env_vars
[N_ENV_VARS
];
1593 for (i
= 0; i
< N_ENV_VARS
; i
++)
1594 env_vars
[i
] = dflt_envvars
[i
];
1596 /* For backwards compatibility, check if a .emacs file exists in C:/
1597 If not, then we can try to default to the appdata directory under the
1598 user's profile, which is more likely to be writable. */
1599 if (stat ("C:/.emacs", &ignored
) < 0)
1601 HRESULT profile_result
;
1602 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1603 of Windows 95 and NT4 that have not been updated to include
1605 ShGetFolderPath_fn get_folder_path
;
1606 get_folder_path
= (ShGetFolderPath_fn
)
1607 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1609 if (get_folder_path
!= NULL
)
1611 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1614 /* If we can't get the appdata dir, revert to old behavior. */
1615 if (profile_result
== S_OK
)
1617 env_vars
[0].def_value
= default_home
;
1623 /* Get default locale info and use it for LANG. */
1624 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1625 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1626 locale_name
, sizeof (locale_name
)))
1628 for (i
= 0; i
< N_ENV_VARS
; i
++)
1630 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1632 env_vars
[i
].def_value
= locale_name
;
1638 /* When Emacs is invoked with --no-site-lisp, we must remove the
1639 site-lisp directories from the default value of EMACSLOADPATH.
1640 This assumes that the site-lisp entries are at the front, and
1641 that additional entries do exist. */
1644 for (i
= 0; i
< N_ENV_VARS
; i
++)
1646 if (strcmp (env_vars
[i
].name
, "EMACSLOADPATH") == 0)
1649 while ((site
= strstr (env_vars
[i
].def_value
, "site-lisp")))
1650 env_vars
[i
].def_value
= strchr (site
, ';') + 1;
1656 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1658 /* Treat emacs_dir specially: set it unconditionally based on our
1659 location, if it appears that we are running from the bin subdir
1660 of a standard installation. */
1663 char modname
[MAX_PATH
];
1665 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1667 if ((p
= strrchr (modname
, '\\')) == NULL
)
1671 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1673 char buf
[SET_ENV_BUF_SIZE
];
1676 for (p
= modname
; *p
; p
++)
1677 if (*p
== '\\') *p
= '/';
1679 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1680 _putenv (strdup (buf
));
1682 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1684 /* FIXME: should use substring of get_emacs_configuration ().
1685 But I don't think the Windows build supports alpha, mips etc
1686 anymore, so have taken the easy option for now. */
1687 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1690 p
= strrchr (modname
, '\\');
1694 p
= strrchr (modname
, '\\');
1695 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1697 char buf
[SET_ENV_BUF_SIZE
];
1700 for (p
= modname
; *p
; p
++)
1701 if (*p
== '\\') *p
= '/';
1703 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1704 _putenv (strdup (buf
));
1710 for (i
= 0; i
< N_ENV_VARS
; i
++)
1712 if (!getenv (env_vars
[i
].name
))
1716 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1717 /* Also ignore empty environment variables. */
1721 lpval
= env_vars
[i
].def_value
;
1722 dwType
= REG_EXPAND_SZ
;
1724 if (!strcmp (env_vars
[i
].name
, "HOME") && !appdata
)
1726 Lisp_Object warning
[2];
1727 warning
[0] = intern ("initialization");
1728 warning
[1] = build_string ("Setting HOME to C:\\ by default is deprecated");
1729 Vdelayed_warnings_list
= Fcons (Flist (2, warning
),
1730 Vdelayed_warnings_list
);
1736 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1738 if (dwType
== REG_EXPAND_SZ
)
1739 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1740 else if (dwType
== REG_SZ
)
1741 strcpy (buf1
, lpval
);
1742 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1744 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1746 _putenv (strdup (buf2
));
1756 /* Rebuild system configuration to reflect invoking system. */
1757 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1759 /* Another special case: on NT, the PATH variable is actually named
1760 "Path" although cmd.exe (perhaps NT itself) arranges for
1761 environment variable lookup and setting to be case insensitive.
1762 However, Emacs assumes a fully case sensitive environment, so we
1763 need to change "Path" to "PATH" to match the expectations of
1764 various elisp packages. We do this by the sneaky method of
1765 modifying the string in the C runtime environ entry.
1767 The same applies to COMSPEC. */
1771 for (envp
= environ
; *envp
; envp
++)
1772 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1773 memcpy (*envp
, "PATH=", 5);
1774 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1775 memcpy (*envp
, "COMSPEC=", 8);
1778 /* Remember the initial working directory for getwd. */
1779 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1783 static char modname
[MAX_PATH
];
1785 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1790 /* Determine if there is a middle mouse button, to allow parse_button
1791 to decide whether right mouse events should be mouse-2 or
1793 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1799 emacs_root_dir (void)
1801 static char root_dir
[FILENAME_MAX
];
1804 p
= getenv ("emacs_dir");
1807 strcpy (root_dir
, p
);
1808 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1809 dostounix_filename (root_dir
);
1813 /* We don't have scripts to automatically determine the system configuration
1814 for Emacs before it's compiled, and we don't want to have to make the
1815 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1819 get_emacs_configuration (void)
1821 char *arch
, *oem
, *os
;
1823 static char configuration_buffer
[32];
1825 /* Determine the processor type. */
1826 switch (get_processor_type ())
1829 #ifdef PROCESSOR_INTEL_386
1830 case PROCESSOR_INTEL_386
:
1831 case PROCESSOR_INTEL_486
:
1832 case PROCESSOR_INTEL_PENTIUM
:
1837 #ifdef PROCESSOR_MIPS_R2000
1838 case PROCESSOR_MIPS_R2000
:
1839 case PROCESSOR_MIPS_R3000
:
1840 case PROCESSOR_MIPS_R4000
:
1845 #ifdef PROCESSOR_ALPHA_21064
1846 case PROCESSOR_ALPHA_21064
:
1856 /* Use the OEM field to reflect the compiler/library combination. */
1858 #define COMPILER_NAME "msvc"
1861 #define COMPILER_NAME "mingw"
1863 #define COMPILER_NAME "unknown"
1866 oem
= COMPILER_NAME
;
1868 switch (osinfo_cache
.dwPlatformId
) {
1869 case VER_PLATFORM_WIN32_NT
:
1871 build_num
= osinfo_cache
.dwBuildNumber
;
1873 case VER_PLATFORM_WIN32_WINDOWS
:
1874 if (osinfo_cache
.dwMinorVersion
== 0) {
1879 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1881 case VER_PLATFORM_WIN32s
:
1882 /* Not supported, should not happen. */
1884 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1892 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1893 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1894 get_w32_major_version (), get_w32_minor_version (), build_num
);
1896 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1899 return configuration_buffer
;
1903 get_emacs_configuration_options (void)
1905 static char *options_buffer
;
1906 char cv
[32]; /* Enough for COMPILER_VERSION. */
1908 cv
, /* To be filled later. */
1912 #ifdef ENABLE_CHECKING
1913 " --enable-checking",
1915 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1916 with a starting space to save work here. */
1918 " --cflags", USER_CFLAGS
,
1921 " --ldflags", USER_LDFLAGS
,
1928 /* Work out the effective configure options for this build. */
1930 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1933 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1935 #define COMPILER_VERSION ""
1939 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
1940 return "Error: not enough space for compiler version";
1941 cv
[sizeof (cv
) - 1] = '\0';
1943 for (i
= 0; options
[i
]; i
++)
1944 size
+= strlen (options
[i
]);
1946 options_buffer
= xmalloc (size
+ 1);
1947 options_buffer
[0] = '\0';
1949 for (i
= 0; options
[i
]; i
++)
1950 strcat (options_buffer
, options
[i
]);
1952 return options_buffer
;
1956 #include <sys/timeb.h>
1958 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1960 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1965 tv
->tv_sec
= tb
.time
;
1966 tv
->tv_usec
= tb
.millitm
* 1000L;
1967 /* Implementation note: _ftime sometimes doesn't update the dstflag
1968 according to the new timezone when the system timezone is
1969 changed. We could fix that by using GetSystemTime and
1970 GetTimeZoneInformation, but that doesn't seem necessary, since
1971 Emacs always calls gettimeofday with the 2nd argument NULL (see
1972 current_emacs_time). */
1975 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1976 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1980 /* Emulate fdutimens. */
1982 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
1983 TIMESPEC[0] and TIMESPEC[1], respectively.
1984 FD must be either negative -- in which case it is ignored --
1985 or a file descriptor that is open on FILE.
1986 If FD is nonnegative, then FILE can be NULL, which means
1987 use just futimes instead of utimes.
1988 If TIMESPEC is null, FAIL.
1989 Return 0 on success, -1 (setting errno) on failure. */
1992 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
2001 if (fd
< 0 && !file
)
2006 ut
.actime
= timespec
[0].tv_sec
;
2007 ut
.modtime
= timespec
[1].tv_sec
;
2009 return _futime (fd
, &ut
);
2011 return _utime (file
, &ut
);
2015 /* ------------------------------------------------------------------------- */
2016 /* IO support and wrapper functions for W32 API. */
2017 /* ------------------------------------------------------------------------- */
2019 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2020 on network directories, so we handle that case here.
2021 (Ulrich Leodolter, 1/11/95). */
2023 sys_ctime (const time_t *t
)
2025 char *str
= (char *) ctime (t
);
2026 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2029 /* Emulate sleep...we could have done this with a define, but that
2030 would necessitate including windows.h in the files that used it.
2031 This is much easier. */
2033 sys_sleep (int seconds
)
2035 Sleep (seconds
* 1000);
2038 /* Internal MSVC functions for low-level descriptor munging */
2039 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2040 extern int __cdecl
_free_osfhnd (int fd
);
2042 /* parallel array of private info on file handles */
2043 filedesc fd_info
[ MAXDESC
];
2045 typedef struct volume_info_data
{
2046 struct volume_info_data
* next
;
2048 /* time when info was obtained */
2051 /* actual volume info */
2060 /* Global referenced by various functions. */
2061 static volume_info_data volume_info
;
2063 /* Vector to indicate which drives are local and fixed (for which cached
2064 data never expires). */
2065 static BOOL fixed_drives
[26];
2067 /* Consider cached volume information to be stale if older than 10s,
2068 at least for non-local drives. Info for fixed drives is never stale. */
2069 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2070 #define VOLINFO_STILL_VALID( root_dir, info ) \
2071 ( ( isalpha (root_dir[0]) && \
2072 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2073 || GetTickCount () - info->timestamp < 10000 )
2075 /* Cache support functions. */
2077 /* Simple linked list with linear search is sufficient. */
2078 static volume_info_data
*volume_cache
= NULL
;
2080 static volume_info_data
*
2081 lookup_volume_info (char * root_dir
)
2083 volume_info_data
* info
;
2085 for (info
= volume_cache
; info
; info
= info
->next
)
2086 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2092 add_volume_info (char * root_dir
, volume_info_data
* info
)
2094 info
->root_dir
= xstrdup (root_dir
);
2095 info
->next
= volume_cache
;
2096 volume_cache
= info
;
2100 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2101 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2102 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2103 static volume_info_data
*
2104 GetCachedVolumeInformation (char * root_dir
)
2106 volume_info_data
* info
;
2107 char default_root
[ MAX_PATH
];
2109 /* NULL for root_dir means use root from current directory. */
2110 if (root_dir
== NULL
)
2112 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2114 parse_root (default_root
, &root_dir
);
2116 root_dir
= default_root
;
2119 /* Local fixed drives can be cached permanently. Removable drives
2120 cannot be cached permanently, since the volume name and serial
2121 number (if nothing else) can change. Remote drives should be
2122 treated as if they are removable, since there is no sure way to
2123 tell whether they are or not. Also, the UNC association of drive
2124 letters mapped to remote volumes can be changed at any time (even
2125 by other processes) without notice.
2127 As a compromise, so we can benefit from caching info for remote
2128 volumes, we use a simple expiry mechanism to invalidate cache
2129 entries that are more than ten seconds old. */
2132 /* No point doing this, because WNetGetConnection is even slower than
2133 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2134 GetDriveType is about the only call of this type which does not
2135 involve network access, and so is extremely quick). */
2137 /* Map drive letter to UNC if remote. */
2138 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2140 char remote_name
[ 256 ];
2141 char drive
[3] = { root_dir
[0], ':' };
2143 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2145 /* do something */ ;
2149 info
= lookup_volume_info (root_dir
);
2151 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2159 /* Info is not cached, or is stale. */
2160 if (!GetVolumeInformation (root_dir
,
2161 name
, sizeof (name
),
2165 type
, sizeof (type
)))
2168 /* Cache the volume information for future use, overwriting existing
2169 entry if present. */
2172 info
= xmalloc (sizeof (volume_info_data
));
2173 add_volume_info (root_dir
, info
);
2181 info
->name
= xstrdup (name
);
2182 info
->serialnum
= serialnum
;
2183 info
->maxcomp
= maxcomp
;
2184 info
->flags
= flags
;
2185 info
->type
= xstrdup (type
);
2186 info
->timestamp
= GetTickCount ();
2192 /* Get information on the volume where name is held; set path pointer to
2193 start of pathname in name (past UNC header\volume header if present). */
2195 get_volume_info (const char * name
, const char ** pPath
)
2197 char temp
[MAX_PATH
];
2198 char *rootname
= NULL
; /* default to current volume */
2199 volume_info_data
* info
;
2204 /* find the root name of the volume if given */
2205 if (isalpha (name
[0]) && name
[1] == ':')
2213 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2220 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2233 info
= GetCachedVolumeInformation (rootname
);
2236 /* Set global referenced by other functions. */
2237 volume_info
= *info
;
2243 /* Determine if volume is FAT format (ie. only supports short 8.3
2244 names); also set path pointer to start of pathname in name. */
2246 is_fat_volume (const char * name
, const char ** pPath
)
2248 if (get_volume_info (name
, pPath
))
2249 return (volume_info
.maxcomp
== 12);
2253 /* Map filename to a valid 8.3 name if necessary. */
2255 map_w32_filename (const char * name
, const char ** pPath
)
2257 static char shortname
[MAX_PATH
];
2258 char * str
= shortname
;
2261 const char * save_name
= name
;
2263 if (strlen (name
) >= MAX_PATH
)
2265 /* Return a filename which will cause callers to fail. */
2266 strcpy (shortname
, "?");
2270 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2272 register int left
= 8; /* maximum number of chars in part */
2273 register int extn
= 0; /* extension added? */
2274 register int dots
= 2; /* maximum number of dots allowed */
2277 *str
++ = *name
++; /* skip past UNC header */
2279 while ((c
= *name
++))
2286 extn
= 0; /* reset extension flags */
2287 dots
= 2; /* max 2 dots */
2288 left
= 8; /* max length 8 for main part */
2292 extn
= 0; /* reset extension flags */
2293 dots
= 2; /* max 2 dots */
2294 left
= 8; /* max length 8 for main part */
2299 /* Convert path components of the form .xxx to _xxx,
2300 but leave . and .. as they are. This allows .emacs
2301 to be read as _emacs, for example. */
2305 IS_DIRECTORY_SEP (*name
))
2320 extn
= 1; /* we've got an extension */
2321 left
= 3; /* 3 chars in extension */
2325 /* any embedded dots after the first are converted to _ */
2330 case '#': /* don't lose these, they're important */
2332 str
[-1] = c
; /* replace last character of part */
2337 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2339 dots
= 0; /* started a path component */
2348 strcpy (shortname
, name
);
2349 unixtodos_filename (shortname
);
2353 *pPath
= shortname
+ (path
- save_name
);
2359 is_exec (const char * name
)
2361 char * p
= strrchr (name
, '.');
2364 && (xstrcasecmp (p
, ".exe") == 0 ||
2365 xstrcasecmp (p
, ".com") == 0 ||
2366 xstrcasecmp (p
, ".bat") == 0 ||
2367 xstrcasecmp (p
, ".cmd") == 0));
2370 /* Emulate the Unix directory procedures opendir, closedir,
2371 and readdir. We can't use the procedures supplied in sysdep.c,
2372 so we provide them here. */
2374 struct direct dir_static
; /* simulated directory contents */
2375 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2376 static int dir_is_fat
;
2377 static char dir_pathname
[MAXPATHLEN
+1];
2378 static WIN32_FIND_DATA dir_find_data
;
2380 /* Support shares on a network resource as subdirectories of a read-only
2382 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2383 static HANDLE
open_unc_volume (const char *);
2384 static char *read_unc_volume (HANDLE
, char *, int);
2385 static void close_unc_volume (HANDLE
);
2388 opendir (char *filename
)
2392 /* Opening is done by FindFirstFile. However, a read is inherent to
2393 this operation, so we defer the open until read time. */
2395 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2397 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2400 if (is_unc_volume (filename
))
2402 wnet_enum_handle
= open_unc_volume (filename
);
2403 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2407 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2414 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2415 dir_pathname
[MAXPATHLEN
] = '\0';
2416 dir_is_fat
= is_fat_volume (filename
, NULL
);
2422 closedir (DIR *dirp
)
2424 /* If we have a find-handle open, close it. */
2425 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2427 FindClose (dir_find_handle
);
2428 dir_find_handle
= INVALID_HANDLE_VALUE
;
2430 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2432 close_unc_volume (wnet_enum_handle
);
2433 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2435 xfree ((char *) dirp
);
2441 int downcase
= !NILP (Vw32_downcase_file_names
);
2443 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2445 if (!read_unc_volume (wnet_enum_handle
,
2446 dir_find_data
.cFileName
,
2450 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2451 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2453 char filename
[MAXNAMLEN
+ 3];
2456 strcpy (filename
, dir_pathname
);
2457 ln
= strlen (filename
) - 1;
2458 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2459 strcat (filename
, "\\");
2460 strcat (filename
, "*");
2462 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2464 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2469 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2473 /* Emacs never uses this value, so don't bother making it match
2474 value returned by stat(). */
2475 dir_static
.d_ino
= 1;
2477 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2479 /* If the file name in cFileName[] includes `?' characters, it means
2480 the original file name used characters that cannot be represented
2481 by the current ANSI codepage. To avoid total lossage, retrieve
2482 the short 8+3 alias of the long file name. */
2483 if (_mbspbrk (dir_static
.d_name
, "?"))
2485 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2486 downcase
= 1; /* 8+3 aliases are returned in all caps */
2488 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2489 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2490 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2492 /* If the file name in cFileName[] includes `?' characters, it means
2493 the original file name used characters that cannot be represented
2494 by the current ANSI codepage. To avoid total lossage, retrieve
2495 the short 8+3 alias of the long file name. */
2496 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2498 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2499 /* 8+3 aliases are returned in all caps, which could break
2500 various alists that look at filenames' extensions. */
2504 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2505 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2507 _strlwr (dir_static
.d_name
);
2511 for (p
= dir_static
.d_name
; *p
; p
++)
2512 if (*p
>= 'a' && *p
<= 'z')
2515 _strlwr (dir_static
.d_name
);
2522 open_unc_volume (const char *path
)
2528 nr
.dwScope
= RESOURCE_GLOBALNET
;
2529 nr
.dwType
= RESOURCETYPE_DISK
;
2530 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2531 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2532 nr
.lpLocalName
= NULL
;
2533 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2534 nr
.lpComment
= NULL
;
2535 nr
.lpProvider
= NULL
;
2537 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2538 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2540 if (result
== NO_ERROR
)
2543 return INVALID_HANDLE_VALUE
;
2547 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2551 DWORD bufsize
= 512;
2556 buffer
= alloca (bufsize
);
2557 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
2558 if (result
!= NO_ERROR
)
2561 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2562 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2564 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2567 strncpy (readbuf
, ptr
, size
);
2572 close_unc_volume (HANDLE henum
)
2574 if (henum
!= INVALID_HANDLE_VALUE
)
2575 WNetCloseEnum (henum
);
2579 unc_volume_file_attributes (const char *path
)
2584 henum
= open_unc_volume (path
);
2585 if (henum
== INVALID_HANDLE_VALUE
)
2588 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2590 close_unc_volume (henum
);
2595 /* Ensure a network connection is authenticated. */
2597 logon_network_drive (const char *path
)
2599 NETRESOURCE resource
;
2600 char share
[MAX_PATH
];
2605 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2606 drvtype
= DRIVE_REMOTE
;
2607 else if (path
[0] == '\0' || path
[1] != ':')
2608 drvtype
= GetDriveType (NULL
);
2615 drvtype
= GetDriveType (drive
);
2618 /* Only logon to networked drives. */
2619 if (drvtype
!= DRIVE_REMOTE
)
2623 strncpy (share
, path
, MAX_PATH
);
2624 /* Truncate to just server and share name. */
2625 for (i
= 2; i
< MAX_PATH
; i
++)
2627 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2634 resource
.dwType
= RESOURCETYPE_DISK
;
2635 resource
.lpLocalName
= NULL
;
2636 resource
.lpRemoteName
= share
;
2637 resource
.lpProvider
= NULL
;
2639 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2642 /* Shadow some MSVC runtime functions to map requests for long filenames
2643 to reasonable short names if necessary. This was originally added to
2644 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2648 sys_access (const char * path
, int mode
)
2652 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
2653 newer versions blow up when passed D_OK. */
2654 path
= map_w32_filename (path
, NULL
);
2655 if (is_unc_volume (path
))
2657 attributes
= unc_volume_file_attributes (path
);
2658 if (attributes
== -1) {
2663 else if ((attributes
= GetFileAttributes (path
)) == -1)
2665 DWORD w32err
= GetLastError ();
2669 case ERROR_FILE_NOT_FOUND
:
2678 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2683 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2688 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2697 sys_chdir (const char * path
)
2699 return _chdir (map_w32_filename (path
, NULL
));
2703 sys_chmod (const char * path
, int mode
)
2705 return _chmod (map_w32_filename (path
, NULL
), mode
);
2709 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2711 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2717 sys_creat (const char * path
, int mode
)
2719 return _creat (map_w32_filename (path
, NULL
), mode
);
2723 sys_fopen (const char * path
, const char * mode
)
2727 const char * mode_save
= mode
;
2729 /* Force all file handles to be non-inheritable. This is necessary to
2730 ensure child processes don't unwittingly inherit handles that might
2731 prevent future file access. */
2735 else if (mode
[0] == 'w' || mode
[0] == 'a')
2736 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2740 /* Only do simplistic option parsing. */
2744 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2747 else if (mode
[0] == 'b')
2752 else if (mode
[0] == 't')
2759 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2763 return _fdopen (fd
, mode_save
);
2766 /* This only works on NTFS volumes, but is useful to have. */
2768 sys_link (const char * old
, const char * new)
2772 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2774 if (old
== NULL
|| new == NULL
)
2780 strcpy (oldname
, map_w32_filename (old
, NULL
));
2781 strcpy (newname
, map_w32_filename (new, NULL
));
2783 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2784 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2785 if (fileh
!= INVALID_HANDLE_VALUE
)
2789 /* Confusingly, the "alternate" stream name field does not apply
2790 when restoring a hard link, and instead contains the actual
2791 stream data for the link (ie. the name of the link to create).
2792 The WIN32_STREAM_ID structure before the cStreamName field is
2793 the stream header, which is then immediately followed by the
2797 WIN32_STREAM_ID wid
;
2798 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2801 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2802 data
.wid
.cStreamName
, MAX_PATH
);
2805 LPVOID context
= NULL
;
2808 data
.wid
.dwStreamId
= BACKUP_LINK
;
2809 data
.wid
.dwStreamAttributes
= 0;
2810 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2811 data
.wid
.Size
.HighPart
= 0;
2812 data
.wid
.dwStreamNameSize
= 0;
2814 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2815 offsetof (WIN32_STREAM_ID
, cStreamName
)
2816 + data
.wid
.Size
.LowPart
,
2817 &wbytes
, FALSE
, FALSE
, &context
)
2818 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2825 /* Should try mapping GetLastError to errno; for now just
2826 indicate a general error (eg. links not supported). */
2827 errno
= EINVAL
; // perhaps EMLINK?
2831 CloseHandle (fileh
);
2840 sys_mkdir (const char * path
)
2842 return _mkdir (map_w32_filename (path
, NULL
));
2845 /* Because of long name mapping issues, we need to implement this
2846 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2847 a unique name, instead of setting the input template to an empty
2850 Standard algorithm seems to be use pid or tid with a letter on the
2851 front (in place of the 6 X's) and cycle through the letters to find a
2852 unique name. We extend that to allow any reasonable character as the
2853 first of the 6 X's. */
2855 sys_mktemp (char * template)
2859 unsigned uid
= GetCurrentThreadId ();
2860 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2862 if (template == NULL
)
2864 p
= template + strlen (template);
2866 /* replace up to the last 5 X's with uid in decimal */
2867 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2869 p
[0] = '0' + uid
% 10;
2873 if (i
< 0 && p
[0] == 'X')
2878 int save_errno
= errno
;
2879 p
[0] = first_char
[i
];
2880 if (sys_access (template, 0) < 0)
2886 while (++i
< sizeof (first_char
));
2889 /* Template is badly formed or else we can't generate a unique name,
2890 so return empty string */
2896 sys_open (const char * path
, int oflag
, int mode
)
2898 const char* mpath
= map_w32_filename (path
, NULL
);
2899 /* Try to open file without _O_CREAT, to be able to write to hidden
2900 and system files. Force all file handles to be
2902 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2905 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2909 sys_rename (const char * oldname
, const char * newname
)
2912 char temp
[MAX_PATH
];
2916 /* MoveFile on Windows 95 doesn't correctly change the short file name
2917 alias in a number of circumstances (it is not easy to predict when
2918 just by looking at oldname and newname, unfortunately). In these
2919 cases, renaming through a temporary name avoids the problem.
2921 A second problem on Windows 95 is that renaming through a temp name when
2922 newname is uppercase fails (the final long name ends up in
2923 lowercase, although the short alias might be uppercase) UNLESS the
2924 long temp name is not 8.3.
2926 So, on Windows 95 we always rename through a temp name, and we make sure
2927 the temp name has a long extension to ensure correct renaming. */
2929 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2931 /* volume_info is set indirectly by map_w32_filename. */
2932 oldname_dev
= volume_info
.serialnum
;
2934 if (os_subtype
== OS_WIN95
)
2940 oldname
= map_w32_filename (oldname
, NULL
);
2941 if ((o
= strrchr (oldname
, '\\')))
2944 o
= (char *) oldname
;
2946 if ((p
= strrchr (temp
, '\\')))
2953 /* Force temp name to require a manufactured 8.3 alias - this
2954 seems to make the second rename work properly. */
2955 sprintf (p
, "_.%s.%u", o
, i
);
2957 result
= rename (oldname
, temp
);
2959 /* This loop must surely terminate! */
2960 while (result
< 0 && errno
== EEXIST
);
2965 /* Emulate Unix behavior - newname is deleted if it already exists
2966 (at least if it is a file; don't do this for directories).
2968 Since we mustn't do this if we are just changing the case of the
2969 file name (we would end up deleting the file we are trying to
2970 rename!), we let rename detect if the destination file already
2971 exists - that way we avoid the possible pitfalls of trying to
2972 determine ourselves whether two names really refer to the same
2973 file, which is not always possible in the general case. (Consider
2974 all the permutations of shared or subst'd drives, etc.) */
2976 newname
= map_w32_filename (newname
, NULL
);
2978 /* volume_info is set indirectly by map_w32_filename. */
2979 newname_dev
= volume_info
.serialnum
;
2981 result
= rename (temp
, newname
);
2987 && newname_dev
!= oldname_dev
)
2989 /* The implementation of `rename' on Windows does not return
2990 errno = EXDEV when you are moving a directory to a
2991 different storage device (ex. logical disk). It returns
2992 EACCES instead. So here we handle such situations and
2996 if ((attributes
= GetFileAttributes (temp
)) != -1
2997 && attributes
& FILE_ATTRIBUTE_DIRECTORY
)
3000 else if (errno
== EEXIST
)
3002 if (_chmod (newname
, 0666) != 0)
3004 if (_unlink (newname
) != 0)
3006 result
= rename (temp
, newname
);
3014 sys_rmdir (const char * path
)
3016 return _rmdir (map_w32_filename (path
, NULL
));
3020 sys_unlink (const char * path
)
3022 path
= map_w32_filename (path
, NULL
);
3024 /* On Unix, unlink works without write permission. */
3025 _chmod (path
, 0666);
3026 return _unlink (path
);
3029 static FILETIME utc_base_ft
;
3030 static ULONGLONG utc_base
; /* In 100ns units */
3031 static int init
= 0;
3033 #define FILETIME_TO_U64(result, ft) \
3035 ULARGE_INTEGER uiTemp; \
3036 uiTemp.LowPart = (ft).dwLowDateTime; \
3037 uiTemp.HighPart = (ft).dwHighDateTime; \
3038 result = uiTemp.QuadPart; \
3042 initialize_utc_base (void)
3044 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3053 st
.wMilliseconds
= 0;
3055 SystemTimeToFileTime (&st
, &utc_base_ft
);
3056 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3060 convert_time (FILETIME ft
)
3066 initialize_utc_base ();
3070 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3073 FILETIME_TO_U64 (tmp
, ft
);
3074 return (time_t) ((tmp
- utc_base
) / 10000000L);
3078 convert_from_time_t (time_t time
, FILETIME
* pft
)
3084 initialize_utc_base ();
3088 /* time in 100ns units since 1-Jan-1601 */
3089 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3090 pft
->dwHighDateTime
= tmp
.HighPart
;
3091 pft
->dwLowDateTime
= tmp
.LowPart
;
3095 /* No reason to keep this; faking inode values either by hashing or even
3096 using the file index from GetInformationByHandle, is not perfect and
3097 so by default Emacs doesn't use the inode values on Windows.
3098 Instead, we now determine file-truename correctly (except for
3099 possible drive aliasing etc). */
3101 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3103 hashval (const unsigned char * str
)
3108 h
= (h
<< 4) + *str
++;
3114 /* Return the hash value of the canonical pathname, excluding the
3115 drive/UNC header, to get a hopefully unique inode number. */
3117 generate_inode_val (const char * name
)
3119 char fullname
[ MAX_PATH
];
3123 /* Get the truly canonical filename, if it exists. (Note: this
3124 doesn't resolve aliasing due to subst commands, or recognize hard
3126 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3129 parse_root (fullname
, &p
);
3130 /* Normal W32 filesystems are still case insensitive. */
3137 static PSECURITY_DESCRIPTOR
3138 get_file_security_desc (const char *fname
)
3140 PSECURITY_DESCRIPTOR psd
= NULL
;
3142 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3143 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3145 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3147 err
= GetLastError ();
3148 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3152 psd
= xmalloc (sd_len
);
3153 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3165 unsigned n_subauthorities
;
3167 /* Use the last sub-authority value of the RID, the relative
3168 portion of the SID, as user/group ID. */
3169 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3170 if (n_subauthorities
< 1)
3171 return 0; /* the "World" RID */
3172 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3175 /* Caching SID and account values for faster lokup. */
3178 # define FLEXIBLE_ARRAY_MEMBER
3180 # define FLEXIBLE_ARRAY_MEMBER 1
3185 struct w32_id
*next
;
3187 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3190 static struct w32_id
*w32_idlist
;
3193 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3195 struct w32_id
*tail
, *found
;
3197 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3199 if (equal_sid ((PSID
)tail
->sid
, sid
))
3208 strcpy (name
, found
->name
);
3216 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3219 struct w32_id
*new_entry
;
3221 /* We don't want to leave behind stale cache from when Emacs was
3225 sid_len
= get_length_sid (sid
);
3226 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3229 new_entry
->rid
= id
;
3230 strcpy (new_entry
->name
, name
);
3231 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3232 new_entry
->next
= w32_idlist
;
3233 w32_idlist
= new_entry
;
3242 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3243 unsigned *id
, char *nm
, int what
)
3246 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3248 SID_NAME_USE ignore
;
3250 DWORD name_len
= sizeof (name
);
3252 DWORD domain_len
= sizeof (domain
);
3258 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3259 else if (what
== GID
)
3260 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3264 if (!result
|| !is_valid_sid (sid
))
3266 else if (!w32_cached_id (sid
, id
, nm
))
3268 /* If FNAME is a UNC, we need to lookup account on the
3269 specified machine. */
3270 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3271 && fname
[2] != '\0')
3276 for (s
= fname
+ 2, p
= machine
;
3277 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3283 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3284 domain
, &domain_len
, &ignore
)
3285 || name_len
> UNLEN
+1)
3289 *id
= get_rid (sid
);
3291 w32_add_to_cache (sid
, *id
, name
);
3298 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3302 int dflt_usr
= 0, dflt_grp
= 0;
3311 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3313 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3316 /* Consider files to belong to current user/group, if we cannot get
3317 more accurate information. */
3320 st
->st_uid
= dflt_passwd
.pw_uid
;
3321 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3325 st
->st_gid
= dflt_passwd
.pw_gid
;
3326 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3330 /* Return non-zero if NAME is a potentially slow filesystem. */
3332 is_slow_fs (const char *name
)
3337 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3338 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3339 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3340 devtype
= GetDriveType (NULL
); /* use root of current drive */
3343 /* GetDriveType needs the root directory of the drive. */
3344 strncpy (drive_root
, name
, 2);
3345 drive_root
[2] = '\\';
3346 drive_root
[3] = '\0';
3347 devtype
= GetDriveType (drive_root
);
3349 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3352 /* MSVC stat function can't cope with UNC names and has other bugs, so
3353 replace it with our own. This also allows us to calculate consistent
3354 inode values without hacks in the main Emacs code. */
3356 stat (const char * path
, struct stat
* buf
)
3359 WIN32_FIND_DATA wfd
;
3361 unsigned __int64 fake_inode
;
3364 int rootdir
= FALSE
;
3365 PSECURITY_DESCRIPTOR psd
= NULL
;
3367 if (path
== NULL
|| buf
== NULL
)
3373 name
= (char *) map_w32_filename (path
, &path
);
3374 /* Must be valid filename, no wild cards or other invalid
3375 characters. We use _mbspbrk to support multibyte strings that
3376 might look to strpbrk as if they included literal *, ?, and other
3377 characters mentioned below that are disallowed by Windows
3379 if (_mbspbrk (name
, "*?|<>\""))
3385 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3386 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3387 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3392 /* Remove trailing directory separator, unless name is the root
3393 directory of a drive or UNC volume in which case ensure there
3394 is a trailing separator. */
3395 len
= strlen (name
);
3396 rootdir
= (path
>= name
+ len
- 1
3397 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3398 name
= strcpy (alloca (len
+ 2), name
);
3400 if (is_unc_volume (name
))
3402 DWORD attrs
= unc_volume_file_attributes (name
);
3407 memset (&wfd
, 0, sizeof (wfd
));
3408 wfd
.dwFileAttributes
= attrs
;
3409 wfd
.ftCreationTime
= utc_base_ft
;
3410 wfd
.ftLastAccessTime
= utc_base_ft
;
3411 wfd
.ftLastWriteTime
= utc_base_ft
;
3412 strcpy (wfd
.cFileName
, name
);
3416 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3417 strcat (name
, "\\");
3418 if (GetDriveType (name
) < 2)
3423 memset (&wfd
, 0, sizeof (wfd
));
3424 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
3425 wfd
.ftCreationTime
= utc_base_ft
;
3426 wfd
.ftLastAccessTime
= utc_base_ft
;
3427 wfd
.ftLastWriteTime
= utc_base_ft
;
3428 strcpy (wfd
.cFileName
, name
);
3432 if (IS_DIRECTORY_SEP (name
[len
-1]))
3435 /* (This is hacky, but helps when doing file completions on
3436 network drives.) Optimize by using information available from
3437 active readdir if possible. */
3438 len
= strlen (dir_pathname
);
3439 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3441 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3442 && strnicmp (name
, dir_pathname
, len
) == 0
3443 && IS_DIRECTORY_SEP (name
[len
])
3444 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3446 /* This was the last entry returned by readdir. */
3447 wfd
= dir_find_data
;
3451 logon_network_drive (name
);
3453 fh
= FindFirstFile (name
, &wfd
);
3454 if (fh
== INVALID_HANDLE_VALUE
)
3463 if (!(NILP (Vw32_get_true_file_attributes
)
3464 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3465 /* No access rights required to get info. */
3466 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3467 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
3468 != INVALID_HANDLE_VALUE
)
3470 /* This is more accurate in terms of getting the correct number
3471 of links, but is quite slow (it is noticeable when Emacs is
3472 making a list of file name completions). */
3473 BY_HANDLE_FILE_INFORMATION info
;
3475 if (GetFileInformationByHandle (fh
, &info
))
3477 buf
->st_nlink
= info
.nNumberOfLinks
;
3478 /* Might as well use file index to fake inode values, but this
3479 is not guaranteed to be unique unless we keep a handle open
3480 all the time (even then there are situations where it is
3481 not unique). Reputedly, there are at most 48 bits of info
3482 (on NTFS, presumably less on FAT). */
3483 fake_inode
= info
.nFileIndexHigh
;
3485 fake_inode
+= info
.nFileIndexLow
;
3493 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3495 buf
->st_mode
= S_IFDIR
;
3499 switch (GetFileType (fh
))
3501 case FILE_TYPE_DISK
:
3502 buf
->st_mode
= S_IFREG
;
3504 case FILE_TYPE_PIPE
:
3505 buf
->st_mode
= S_IFIFO
;
3507 case FILE_TYPE_CHAR
:
3508 case FILE_TYPE_UNKNOWN
:
3510 buf
->st_mode
= S_IFCHR
;
3514 psd
= get_file_security_desc (name
);
3515 get_file_owner_and_group (psd
, name
, buf
);
3519 /* Don't bother to make this information more accurate. */
3520 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
3525 get_file_owner_and_group (NULL
, name
, buf
);
3530 /* Not sure if there is any point in this. */
3531 if (!NILP (Vw32_generate_fake_inodes
))
3532 fake_inode
= generate_inode_val (name
);
3533 else if (fake_inode
== 0)
3535 /* For want of something better, try to make everything unique. */
3536 static DWORD gen_num
= 0;
3537 fake_inode
= ++gen_num
;
3541 /* MSVC defines _ino_t to be short; other libc's might not. */
3542 if (sizeof (buf
->st_ino
) == 2)
3543 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3545 buf
->st_ino
= fake_inode
;
3547 /* volume_info is set indirectly by map_w32_filename */
3548 buf
->st_dev
= volume_info
.serialnum
;
3549 buf
->st_rdev
= volume_info
.serialnum
;
3551 buf
->st_size
= wfd
.nFileSizeHigh
;
3552 buf
->st_size
<<= 32;
3553 buf
->st_size
+= wfd
.nFileSizeLow
;
3555 /* Convert timestamps to Unix format. */
3556 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
3557 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
3558 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3559 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3560 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3562 /* determine rwx permissions */
3563 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3564 permission
= S_IREAD
;
3566 permission
= S_IREAD
| S_IWRITE
;
3568 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3569 permission
|= S_IEXEC
;
3570 else if (is_exec (name
))
3571 permission
|= S_IEXEC
;
3573 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3578 /* Provide fstat and utime as well as stat for consistent handling of
3581 fstat (int desc
, struct stat
* buf
)
3583 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3584 BY_HANDLE_FILE_INFORMATION info
;
3585 unsigned __int64 fake_inode
;
3588 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3590 case FILE_TYPE_DISK
:
3591 buf
->st_mode
= S_IFREG
;
3592 if (!GetFileInformationByHandle (fh
, &info
))
3598 case FILE_TYPE_PIPE
:
3599 buf
->st_mode
= S_IFIFO
;
3601 case FILE_TYPE_CHAR
:
3602 case FILE_TYPE_UNKNOWN
:
3604 buf
->st_mode
= S_IFCHR
;
3606 memset (&info
, 0, sizeof (info
));
3607 info
.dwFileAttributes
= 0;
3608 info
.ftCreationTime
= utc_base_ft
;
3609 info
.ftLastAccessTime
= utc_base_ft
;
3610 info
.ftLastWriteTime
= utc_base_ft
;
3613 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3614 buf
->st_mode
= S_IFDIR
;
3616 buf
->st_nlink
= info
.nNumberOfLinks
;
3617 /* Might as well use file index to fake inode values, but this
3618 is not guaranteed to be unique unless we keep a handle open
3619 all the time (even then there are situations where it is
3620 not unique). Reputedly, there are at most 48 bits of info
3621 (on NTFS, presumably less on FAT). */
3622 fake_inode
= info
.nFileIndexHigh
;
3624 fake_inode
+= info
.nFileIndexLow
;
3626 /* MSVC defines _ino_t to be short; other libc's might not. */
3627 if (sizeof (buf
->st_ino
) == 2)
3628 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3630 buf
->st_ino
= fake_inode
;
3632 /* Consider files to belong to current user.
3633 FIXME: this should use GetSecurityInfo API, but it is only
3634 available for _WIN32_WINNT >= 0x501. */
3635 buf
->st_uid
= dflt_passwd
.pw_uid
;
3636 buf
->st_gid
= dflt_passwd
.pw_gid
;
3637 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3638 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3640 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3641 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3643 buf
->st_size
= info
.nFileSizeHigh
;
3644 buf
->st_size
<<= 32;
3645 buf
->st_size
+= info
.nFileSizeLow
;
3647 /* Convert timestamps to Unix format. */
3648 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3649 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3650 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3651 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3652 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3654 /* determine rwx permissions */
3655 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3656 permission
= S_IREAD
;
3658 permission
= S_IREAD
| S_IWRITE
;
3660 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3661 permission
|= S_IEXEC
;
3664 #if 0 /* no way of knowing the filename */
3665 char * p
= strrchr (name
, '.');
3667 (xstrcasecmp (p
, ".exe") == 0 ||
3668 xstrcasecmp (p
, ".com") == 0 ||
3669 xstrcasecmp (p
, ".bat") == 0 ||
3670 xstrcasecmp (p
, ".cmd") == 0))
3671 permission
|= S_IEXEC
;
3675 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3681 utime (const char *name
, struct utimbuf
*times
)
3683 struct utimbuf deftime
;
3690 deftime
.modtime
= deftime
.actime
= time (NULL
);
3694 /* Need write access to set times. */
3695 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3696 0, OPEN_EXISTING
, 0, NULL
);
3699 convert_from_time_t (times
->actime
, &atime
);
3700 convert_from_time_t (times
->modtime
, &mtime
);
3701 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3718 /* Symlink-related functions that always fail. Used in fileio.c and in
3719 sysdep.c to avoid #ifdef's. */
3721 symlink (char const *dummy1
, char const *dummy2
)
3728 readlink (const char *name
, char *dummy1
, size_t dummy2
)
3730 /* `access' is much faster than `stat' on MS-Windows. */
3731 if (sys_access (name
, 0) == 0)
3737 careadlinkat (int fd
, char const *filename
,
3738 char *buffer
, size_t buffer_size
,
3739 struct allocator
const *alloc
,
3740 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
3747 careadlinkatcwd (int fd
, char const *filename
, char *buffer
,
3751 return readlink (filename
, buffer
, buffer_size
);
3755 /* Support for browsing other processes and their attributes. See
3756 process.c for the Lisp bindings. */
3758 /* Helper wrapper functions. */
3760 static HANDLE WINAPI
3761 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
3763 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
3765 if (g_b_init_create_toolhelp32_snapshot
== 0)
3767 g_b_init_create_toolhelp32_snapshot
= 1;
3768 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
3769 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3770 "CreateToolhelp32Snapshot");
3772 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
3774 return INVALID_HANDLE_VALUE
;
3776 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
3780 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3782 static Process32First_Proc s_pfn_Process32_First
= NULL
;
3784 if (g_b_init_process32_first
== 0)
3786 g_b_init_process32_first
= 1;
3787 s_pfn_Process32_First
= (Process32First_Proc
)
3788 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3791 if (s_pfn_Process32_First
== NULL
)
3795 return (s_pfn_Process32_First (hSnapshot
, lppe
));
3799 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
3801 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
3803 if (g_b_init_process32_next
== 0)
3805 g_b_init_process32_next
= 1;
3806 s_pfn_Process32_Next
= (Process32Next_Proc
)
3807 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3810 if (s_pfn_Process32_Next
== NULL
)
3814 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
3818 open_thread_token (HANDLE ThreadHandle
,
3819 DWORD DesiredAccess
,
3821 PHANDLE TokenHandle
)
3823 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
3824 HMODULE hm_advapi32
= NULL
;
3825 if (is_windows_9x () == TRUE
)
3827 SetLastError (ERROR_NOT_SUPPORTED
);
3830 if (g_b_init_open_thread_token
== 0)
3832 g_b_init_open_thread_token
= 1;
3833 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3834 s_pfn_Open_Thread_Token
=
3835 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
3837 if (s_pfn_Open_Thread_Token
== NULL
)
3839 SetLastError (ERROR_NOT_SUPPORTED
);
3843 s_pfn_Open_Thread_Token (
3852 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
3854 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
3855 HMODULE hm_advapi32
= NULL
;
3856 if (is_windows_9x () == TRUE
)
3860 if (g_b_init_impersonate_self
== 0)
3862 g_b_init_impersonate_self
= 1;
3863 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3864 s_pfn_Impersonate_Self
=
3865 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
3867 if (s_pfn_Impersonate_Self
== NULL
)
3871 return s_pfn_Impersonate_Self (ImpersonationLevel
);
3875 revert_to_self (void)
3877 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
3878 HMODULE hm_advapi32
= NULL
;
3879 if (is_windows_9x () == TRUE
)
3883 if (g_b_init_revert_to_self
== 0)
3885 g_b_init_revert_to_self
= 1;
3886 hm_advapi32
= LoadLibrary ("Advapi32.dll");
3887 s_pfn_Revert_To_Self
=
3888 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
3890 if (s_pfn_Revert_To_Self
== NULL
)
3894 return s_pfn_Revert_To_Self ();
3898 get_process_memory_info (HANDLE h_proc
,
3899 PPROCESS_MEMORY_COUNTERS mem_counters
,
3902 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
3903 HMODULE hm_psapi
= NULL
;
3904 if (is_windows_9x () == TRUE
)
3908 if (g_b_init_get_process_memory_info
== 0)
3910 g_b_init_get_process_memory_info
= 1;
3911 hm_psapi
= LoadLibrary ("Psapi.dll");
3913 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
3914 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
3916 if (s_pfn_Get_Process_Memory_Info
== NULL
)
3920 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
3924 get_process_working_set_size (HANDLE h_proc
,
3928 static GetProcessWorkingSetSize_Proc
3929 s_pfn_Get_Process_Working_Set_Size
= NULL
;
3931 if (is_windows_9x () == TRUE
)
3935 if (g_b_init_get_process_working_set_size
== 0)
3937 g_b_init_get_process_working_set_size
= 1;
3938 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
3939 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3940 "GetProcessWorkingSetSize");
3942 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
3946 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
3950 global_memory_status (MEMORYSTATUS
*buf
)
3952 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
3954 if (is_windows_9x () == TRUE
)
3958 if (g_b_init_global_memory_status
== 0)
3960 g_b_init_global_memory_status
= 1;
3961 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
3962 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3963 "GlobalMemoryStatus");
3965 if (s_pfn_Global_Memory_Status
== NULL
)
3969 return s_pfn_Global_Memory_Status (buf
);
3973 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
3975 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
3977 if (is_windows_9x () == TRUE
)
3981 if (g_b_init_global_memory_status_ex
== 0)
3983 g_b_init_global_memory_status_ex
= 1;
3984 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
3985 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3986 "GlobalMemoryStatusEx");
3988 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
3992 return s_pfn_Global_Memory_Status_Ex (buf
);
3996 list_system_processes (void)
3998 struct gcpro gcpro1
;
3999 Lisp_Object proclist
= Qnil
;
4002 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4004 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4006 PROCESSENTRY32 proc_entry
;
4012 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
4013 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
4014 res
= process32_next (h_snapshot
, &proc_entry
))
4016 proc_id
= proc_entry
.th32ProcessID
;
4017 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
4020 CloseHandle (h_snapshot
);
4022 proclist
= Fnreverse (proclist
);
4029 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
4031 TOKEN_PRIVILEGES priv
;
4032 DWORD priv_size
= sizeof (priv
);
4033 DWORD opriv_size
= sizeof (*old_priv
);
4034 HANDLE h_token
= NULL
;
4035 HANDLE h_thread
= GetCurrentThread ();
4039 res
= open_thread_token (h_thread
,
4040 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4042 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
4044 if (impersonate_self (SecurityImpersonation
))
4045 res
= open_thread_token (h_thread
,
4046 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4051 priv
.PrivilegeCount
= 1;
4052 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
4053 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
4054 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
4055 old_priv
, &opriv_size
)
4056 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4060 CloseHandle (h_token
);
4066 restore_privilege (TOKEN_PRIVILEGES
*priv
)
4068 DWORD priv_size
= sizeof (*priv
);
4069 HANDLE h_token
= NULL
;
4072 if (open_thread_token (GetCurrentThread (),
4073 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4076 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
4077 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4081 CloseHandle (h_token
);
4087 ltime (ULONGLONG time_100ns
)
4089 ULONGLONG time_sec
= time_100ns
/ 10000000;
4090 int subsec
= time_100ns
% 10000000;
4091 return list4 (make_number (time_sec
>> 16),
4092 make_number (time_sec
& 0xffff),
4093 make_number (subsec
/ 10),
4094 make_number (subsec
% 10 * 100000));
4097 #define U64_TO_LISP_TIME(time) ltime (time)
4100 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4101 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4104 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4105 ULONGLONG tem1
, tem2
, tem3
, tem
;
4108 || !get_process_times_fn
4109 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4110 &ft_kernel
, &ft_user
))
4113 GetSystemTimeAsFileTime (&ft_current
);
4115 FILETIME_TO_U64 (tem1
, ft_kernel
);
4116 *stime
= U64_TO_LISP_TIME (tem1
);
4118 FILETIME_TO_U64 (tem2
, ft_user
);
4119 *utime
= U64_TO_LISP_TIME (tem2
);
4122 *ttime
= U64_TO_LISP_TIME (tem3
);
4124 FILETIME_TO_U64 (tem
, ft_creation
);
4125 /* Process no 4 (System) returns zero creation time. */
4128 *ctime
= U64_TO_LISP_TIME (tem
);
4132 FILETIME_TO_U64 (tem3
, ft_current
);
4133 tem
= (tem3
- utc_base
) - tem
;
4135 *etime
= U64_TO_LISP_TIME (tem
);
4139 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4150 system_process_attributes (Lisp_Object pid
)
4152 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4153 Lisp_Object attrs
= Qnil
;
4154 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4155 HANDLE h_snapshot
, h_proc
;
4158 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4159 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4160 DWORD glength
= sizeof (gname
);
4161 HANDLE token
= NULL
;
4162 SID_NAME_USE user_type
;
4163 unsigned char *buf
= NULL
;
4165 TOKEN_USER user_token
;
4166 TOKEN_PRIMARY_GROUP group_token
;
4169 PROCESS_MEMORY_COUNTERS mem
;
4170 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4171 DWORD minrss
, maxrss
;
4173 MEMORY_STATUS_EX memstex
;
4174 double totphys
= 0.0;
4175 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4177 BOOL result
= FALSE
;
4179 CHECK_NUMBER_OR_FLOAT (pid
);
4180 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4182 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4184 GCPRO3 (attrs
, decoded_cmd
, tem
);
4186 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4191 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4192 for (res
= process32_first (h_snapshot
, &pe
); res
;
4193 res
= process32_next (h_snapshot
, &pe
))
4195 if (proc_id
== pe
.th32ProcessID
)
4198 decoded_cmd
= build_string ("Idle");
4201 /* Decode the command name from locale-specific
4203 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4204 strlen (pe
.szExeFile
));
4206 code_convert_string_norecord (cmd_str
,
4207 Vlocale_coding_system
, 0);
4209 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4210 attrs
= Fcons (Fcons (Qppid
,
4211 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4213 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4215 attrs
= Fcons (Fcons (Qthcount
,
4216 make_fixnum_or_float (pe
.cntThreads
)),
4223 CloseHandle (h_snapshot
);
4232 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4234 /* If we were denied a handle to the process, try again after
4235 enabling the SeDebugPrivilege in our process. */
4238 TOKEN_PRIVILEGES priv_current
;
4240 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4242 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4244 restore_privilege (&priv_current
);
4250 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4253 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4254 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4256 buf
= xmalloc (blen
);
4257 result
= get_token_information (token
, TokenUser
,
4258 (LPVOID
)buf
, blen
, &needed
);
4261 memcpy (&user_token
, buf
, sizeof (user_token
));
4262 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4264 euid
= get_rid (user_token
.User
.Sid
);
4265 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4270 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4273 strcpy (uname
, "unknown");
4277 ulength
= strlen (uname
);
4283 /* Determine a reasonable euid and gid values. */
4284 if (xstrcasecmp ("administrator", uname
) == 0)
4286 euid
= 500; /* well-known Administrator uid */
4287 egid
= 513; /* well-known None gid */
4291 /* Get group id and name. */
4292 result
= get_token_information (token
, TokenPrimaryGroup
,
4293 (LPVOID
)buf
, blen
, &needed
);
4294 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4296 buf
= xrealloc (buf
, blen
= needed
);
4297 result
= get_token_information (token
, TokenPrimaryGroup
,
4298 (LPVOID
)buf
, blen
, &needed
);
4302 memcpy (&group_token
, buf
, sizeof (group_token
));
4303 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
4305 egid
= get_rid (group_token
.PrimaryGroup
);
4306 dlength
= sizeof (domain
);
4308 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
4309 gname
, &glength
, NULL
, &dlength
,
4312 w32_add_to_cache (group_token
.PrimaryGroup
,
4316 strcpy (gname
, "None");
4320 glength
= strlen (gname
);
4328 if (!is_windows_9x ())
4330 /* We couldn't open the process token, presumably because of
4331 insufficient access rights. Assume this process is run
4333 strcpy (uname
, "SYSTEM");
4334 strcpy (gname
, "None");
4335 euid
= 18; /* SYSTEM */
4336 egid
= 513; /* None */
4337 glength
= strlen (gname
);
4338 ulength
= strlen (uname
);
4340 /* If we are running under Windows 9X, where security calls are
4341 not supported, we assume all processes are run by the current
4343 else if (GetUserName (uname
, &ulength
))
4345 if (xstrcasecmp ("administrator", uname
) == 0)
4350 strcpy (gname
, "None");
4351 glength
= strlen (gname
);
4352 ulength
= strlen (uname
);
4358 strcpy (uname
, "administrator");
4359 ulength
= strlen (uname
);
4360 strcpy (gname
, "None");
4361 glength
= strlen (gname
);
4364 CloseHandle (token
);
4367 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
4368 tem
= make_unibyte_string (uname
, ulength
);
4369 attrs
= Fcons (Fcons (Quser
,
4370 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4372 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
4373 tem
= make_unibyte_string (gname
, glength
);
4374 attrs
= Fcons (Fcons (Qgroup
,
4375 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
4378 if (global_memory_status_ex (&memstex
))
4379 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4380 totphys
= memstex
.ullTotalPhys
/ 1024.0;
4382 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4383 double, so we need to do this for it... */
4385 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
4386 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
4387 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
4389 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
4391 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4392 else if (global_memory_status (&memst
))
4393 totphys
= memst
.dwTotalPhys
/ 1024.0;
4396 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
4399 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4401 attrs
= Fcons (Fcons (Qmajflt
,
4402 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
4404 attrs
= Fcons (Fcons (Qvsize
,
4405 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
4407 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4409 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4412 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
4414 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
4416 attrs
= Fcons (Fcons (Qmajflt
,
4417 make_fixnum_or_float (mem
.PageFaultCount
)),
4419 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
4421 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4424 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
4426 DWORD rss
= maxrss
/ 1024;
4428 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
4430 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
4433 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
4435 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
4436 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
4437 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
4438 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
4439 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
4440 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
4443 /* FIXME: Retrieve command line by walking the PEB of the process. */
4446 CloseHandle (h_proc
);
4452 /* Wrappers for winsock functions to map between our file descriptors
4453 and winsock's handles; also set h_errno for convenience.
4455 To allow Emacs to run on systems which don't have winsock support
4456 installed, we dynamically link to winsock on startup if present, and
4457 otherwise provide the minimum necessary functionality
4458 (eg. gethostname). */
4460 /* function pointers for relevant socket functions */
4461 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
4462 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
4463 int (PASCAL
*pfn_WSAGetLastError
) (void);
4464 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
4465 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
4466 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
4467 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
4468 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4469 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
4470 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
4471 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
4472 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
4473 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
4474 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
4475 int (PASCAL
*pfn_WSACleanup
) (void);
4477 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
4478 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
4479 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
4480 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
4481 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
4482 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
4483 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
4484 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
4485 const char * optval
, int optlen
);
4486 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
4487 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
4489 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
4490 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
4491 struct sockaddr
* from
, int * fromlen
);
4492 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
4493 const struct sockaddr
* to
, int tolen
);
4495 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4496 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
4497 #ifndef HANDLE_FLAG_INHERIT
4498 #define HANDLE_FLAG_INHERIT 1
4502 static int winsock_inuse
;
4507 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
4509 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4510 after WSAStartup returns successfully, but it seems reasonable
4511 to allow unloading winsock anyway in that case. */
4512 if (pfn_WSACleanup () == 0 ||
4513 pfn_WSAGetLastError () == WSAENETDOWN
)
4515 if (FreeLibrary (winsock_lib
))
4524 init_winsock (int load_now
)
4526 WSADATA winsockData
;
4528 if (winsock_lib
!= NULL
)
4531 pfn_SetHandleInformation
4532 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4533 "SetHandleInformation");
4535 winsock_lib
= LoadLibrary ("Ws2_32.dll");
4537 if (winsock_lib
!= NULL
)
4539 /* dynamically link to socket functions */
4541 #define LOAD_PROC(fn) \
4542 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4545 LOAD_PROC (WSAStartup
);
4546 LOAD_PROC (WSASetLastError
);
4547 LOAD_PROC (WSAGetLastError
);
4548 LOAD_PROC (WSAEventSelect
);
4549 LOAD_PROC (WSACreateEvent
);
4550 LOAD_PROC (WSACloseEvent
);
4553 LOAD_PROC (connect
);
4554 LOAD_PROC (ioctlsocket
);
4557 LOAD_PROC (closesocket
);
4558 LOAD_PROC (shutdown
);
4561 LOAD_PROC (inet_addr
);
4562 LOAD_PROC (gethostname
);
4563 LOAD_PROC (gethostbyname
);
4564 LOAD_PROC (getservbyname
);
4565 LOAD_PROC (getpeername
);
4566 LOAD_PROC (WSACleanup
);
4567 LOAD_PROC (setsockopt
);
4569 LOAD_PROC (getsockname
);
4571 LOAD_PROC (recvfrom
);
4575 /* specify version 1.1 of winsock */
4576 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
4578 if (winsockData
.wVersion
!= 0x101)
4583 /* Report that winsock exists and is usable, but leave
4584 socket functions disabled. I am assuming that calling
4585 WSAStartup does not require any network interaction,
4586 and in particular does not cause or require a dial-up
4587 connection to be established. */
4590 FreeLibrary (winsock_lib
);
4598 FreeLibrary (winsock_lib
);
4608 /* function to set h_errno for compatibility; map winsock error codes to
4609 normal system codes where they overlap (non-overlapping definitions
4610 are already in <sys/socket.h> */
4614 if (winsock_lib
== NULL
)
4617 h_errno
= pfn_WSAGetLastError ();
4621 case WSAEACCES
: h_errno
= EACCES
; break;
4622 case WSAEBADF
: h_errno
= EBADF
; break;
4623 case WSAEFAULT
: h_errno
= EFAULT
; break;
4624 case WSAEINTR
: h_errno
= EINTR
; break;
4625 case WSAEINVAL
: h_errno
= EINVAL
; break;
4626 case WSAEMFILE
: h_errno
= EMFILE
; break;
4627 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
4628 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
4636 if (h_errno
== 0 && winsock_lib
!= NULL
)
4637 pfn_WSASetLastError (0);
4640 /* Extend strerror to handle the winsock-specific error codes. */
4644 } _wsa_errlist
[] = {
4645 {WSAEINTR
, "Interrupted function call"},
4646 {WSAEBADF
, "Bad file descriptor"},
4647 {WSAEACCES
, "Permission denied"},
4648 {WSAEFAULT
, "Bad address"},
4649 {WSAEINVAL
, "Invalid argument"},
4650 {WSAEMFILE
, "Too many open files"},
4652 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
4653 {WSAEINPROGRESS
, "Operation now in progress"},
4654 {WSAEALREADY
, "Operation already in progress"},
4655 {WSAENOTSOCK
, "Socket operation on non-socket"},
4656 {WSAEDESTADDRREQ
, "Destination address required"},
4657 {WSAEMSGSIZE
, "Message too long"},
4658 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
4659 {WSAENOPROTOOPT
, "Bad protocol option"},
4660 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
4661 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
4662 {WSAEOPNOTSUPP
, "Operation not supported"},
4663 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
4664 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
4665 {WSAEADDRINUSE
, "Address already in use"},
4666 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
4667 {WSAENETDOWN
, "Network is down"},
4668 {WSAENETUNREACH
, "Network is unreachable"},
4669 {WSAENETRESET
, "Network dropped connection on reset"},
4670 {WSAECONNABORTED
, "Software caused connection abort"},
4671 {WSAECONNRESET
, "Connection reset by peer"},
4672 {WSAENOBUFS
, "No buffer space available"},
4673 {WSAEISCONN
, "Socket is already connected"},
4674 {WSAENOTCONN
, "Socket is not connected"},
4675 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
4676 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
4677 {WSAETIMEDOUT
, "Connection timed out"},
4678 {WSAECONNREFUSED
, "Connection refused"},
4679 {WSAELOOP
, "Network loop"}, /* not sure */
4680 {WSAENAMETOOLONG
, "Name is too long"},
4681 {WSAEHOSTDOWN
, "Host is down"},
4682 {WSAEHOSTUNREACH
, "No route to host"},
4683 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
4684 {WSAEPROCLIM
, "Too many processes"},
4685 {WSAEUSERS
, "Too many users"}, /* not sure */
4686 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
4687 {WSAESTALE
, "Data is stale"}, /* not sure */
4688 {WSAEREMOTE
, "Remote error"}, /* not sure */
4690 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
4691 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
4692 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
4693 {WSAEDISCON
, "Graceful shutdown in progress"},
4695 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
4696 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
4697 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
4698 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
4699 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
4700 {WSASYSCALLFAILURE
, "System call failure"},
4701 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
4702 {WSATYPE_NOT_FOUND
, "Class type not found"},
4703 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
4704 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
4705 {WSAEREFUSED
, "Operation refused"}, /* not sure */
4708 {WSAHOST_NOT_FOUND
, "Host not found"},
4709 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
4710 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
4711 {WSANO_DATA
, "Valid name, no data record of requested type"},
4717 sys_strerror (int error_no
)
4720 static char unknown_msg
[40];
4722 if (error_no
>= 0 && error_no
< sys_nerr
)
4723 return sys_errlist
[error_no
];
4725 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
4726 if (_wsa_errlist
[i
].errnum
== error_no
)
4727 return _wsa_errlist
[i
].msg
;
4729 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
4733 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4734 but I believe the method of keeping the socket handle separate (and
4735 insuring it is not inheritable) is the correct one. */
4737 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4739 static int socket_to_fd (SOCKET s
);
4742 sys_socket (int af
, int type
, int protocol
)
4746 if (winsock_lib
== NULL
)
4749 return INVALID_SOCKET
;
4754 /* call the real socket function */
4755 s
= pfn_socket (af
, type
, protocol
);
4757 if (s
!= INVALID_SOCKET
)
4758 return socket_to_fd (s
);
4764 /* Convert a SOCKET to a file descriptor. */
4766 socket_to_fd (SOCKET s
)
4771 /* Although under NT 3.5 _open_osfhandle will accept a socket
4772 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4773 that does not work under NT 3.1. However, we can get the same
4774 effect by using a backdoor function to replace an existing
4775 descriptor handle with the one we want. */
4777 /* allocate a file descriptor (with appropriate flags) */
4778 fd
= _open ("NUL:", _O_RDWR
);
4781 /* Make a non-inheritable copy of the socket handle. Note
4782 that it is possible that sockets aren't actually kernel
4783 handles, which appears to be the case on Windows 9x when
4784 the MS Proxy winsock client is installed. */
4786 /* Apparently there is a bug in NT 3.51 with some service
4787 packs, which prevents using DuplicateHandle to make a
4788 socket handle non-inheritable (causes WSACleanup to
4789 hang). The work-around is to use SetHandleInformation
4790 instead if it is available and implemented. */
4791 if (pfn_SetHandleInformation
)
4793 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
4797 HANDLE parent
= GetCurrentProcess ();
4798 HANDLE new_s
= INVALID_HANDLE_VALUE
;
4800 if (DuplicateHandle (parent
,
4806 DUPLICATE_SAME_ACCESS
))
4808 /* It is possible that DuplicateHandle succeeds even
4809 though the socket wasn't really a kernel handle,
4810 because a real handle has the same value. So
4811 test whether the new handle really is a socket. */
4812 long nonblocking
= 0;
4813 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
4815 pfn_closesocket (s
);
4820 CloseHandle (new_s
);
4825 fd_info
[fd
].hnd
= (HANDLE
) s
;
4827 /* set our own internal flags */
4828 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
4834 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4836 /* attach child_process to fd_info */
4837 if (fd_info
[ fd
].cp
!= NULL
)
4839 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
4843 fd_info
[ fd
].cp
= cp
;
4846 winsock_inuse
++; /* count open sockets */
4853 pfn_closesocket (s
);
4859 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
4861 if (winsock_lib
== NULL
)
4864 return SOCKET_ERROR
;
4868 if (fd_info
[s
].flags
& FILE_SOCKET
)
4870 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
4871 if (rc
== SOCKET_ERROR
)
4876 return SOCKET_ERROR
;
4880 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
4882 if (winsock_lib
== NULL
)
4885 return SOCKET_ERROR
;
4889 if (fd_info
[s
].flags
& FILE_SOCKET
)
4891 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
4892 if (rc
== SOCKET_ERROR
)
4897 return SOCKET_ERROR
;
4901 sys_htons (u_short hostshort
)
4903 return (winsock_lib
!= NULL
) ?
4904 pfn_htons (hostshort
) : hostshort
;
4908 sys_ntohs (u_short netshort
)
4910 return (winsock_lib
!= NULL
) ?
4911 pfn_ntohs (netshort
) : netshort
;
4915 sys_inet_addr (const char * cp
)
4917 return (winsock_lib
!= NULL
) ?
4918 pfn_inet_addr (cp
) : INADDR_NONE
;
4922 sys_gethostname (char * name
, int namelen
)
4924 if (winsock_lib
!= NULL
)
4925 return pfn_gethostname (name
, namelen
);
4927 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
4928 return !GetComputerName (name
, (DWORD
*)&namelen
);
4931 return SOCKET_ERROR
;
4935 sys_gethostbyname (const char * name
)
4937 struct hostent
* host
;
4939 if (winsock_lib
== NULL
)
4946 host
= pfn_gethostbyname (name
);
4953 sys_getservbyname (const char * name
, const char * proto
)
4955 struct servent
* serv
;
4957 if (winsock_lib
== NULL
)
4964 serv
= pfn_getservbyname (name
, proto
);
4971 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
4973 if (winsock_lib
== NULL
)
4976 return SOCKET_ERROR
;
4980 if (fd_info
[s
].flags
& FILE_SOCKET
)
4982 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
4983 if (rc
== SOCKET_ERROR
)
4988 return SOCKET_ERROR
;
4992 sys_shutdown (int s
, int how
)
4994 if (winsock_lib
== NULL
)
4997 return SOCKET_ERROR
;
5001 if (fd_info
[s
].flags
& FILE_SOCKET
)
5003 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
5004 if (rc
== SOCKET_ERROR
)
5009 return SOCKET_ERROR
;
5013 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
5015 if (winsock_lib
== NULL
)
5018 return SOCKET_ERROR
;
5022 if (fd_info
[s
].flags
& FILE_SOCKET
)
5024 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
5025 (const char *)optval
, optlen
);
5026 if (rc
== SOCKET_ERROR
)
5031 return SOCKET_ERROR
;
5035 sys_listen (int s
, int backlog
)
5037 if (winsock_lib
== NULL
)
5040 return SOCKET_ERROR
;
5044 if (fd_info
[s
].flags
& FILE_SOCKET
)
5046 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
5047 if (rc
== SOCKET_ERROR
)
5050 fd_info
[s
].flags
|= FILE_LISTEN
;
5054 return SOCKET_ERROR
;
5058 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
5060 if (winsock_lib
== NULL
)
5063 return SOCKET_ERROR
;
5067 if (fd_info
[s
].flags
& FILE_SOCKET
)
5069 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
5070 if (rc
== SOCKET_ERROR
)
5075 return SOCKET_ERROR
;
5079 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
5081 if (winsock_lib
== NULL
)
5088 if (fd_info
[s
].flags
& FILE_LISTEN
)
5090 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5092 if (t
== INVALID_SOCKET
)
5095 fd
= socket_to_fd (t
);
5097 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5098 ResetEvent (fd_info
[s
].cp
->char_avail
);
5106 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5107 struct sockaddr
* from
, int * fromlen
)
5109 if (winsock_lib
== NULL
)
5112 return SOCKET_ERROR
;
5116 if (fd_info
[s
].flags
& FILE_SOCKET
)
5118 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5119 if (rc
== SOCKET_ERROR
)
5124 return SOCKET_ERROR
;
5128 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5129 const struct sockaddr
* to
, int tolen
)
5131 if (winsock_lib
== NULL
)
5134 return SOCKET_ERROR
;
5138 if (fd_info
[s
].flags
& FILE_SOCKET
)
5140 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5141 if (rc
== SOCKET_ERROR
)
5146 return SOCKET_ERROR
;
5149 /* Windows does not have an fcntl function. Provide an implementation
5150 solely for making sockets non-blocking. */
5152 fcntl (int s
, int cmd
, int options
)
5154 if (winsock_lib
== NULL
)
5161 if (fd_info
[s
].flags
& FILE_SOCKET
)
5163 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5165 unsigned long nblock
= 1;
5166 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5167 if (rc
== SOCKET_ERROR
)
5169 /* Keep track of the fact that we set this to non-blocking. */
5170 fd_info
[s
].flags
|= FILE_NDELAY
;
5176 return SOCKET_ERROR
;
5180 return SOCKET_ERROR
;
5184 /* Shadow main io functions: we need to handle pipes and sockets more
5185 intelligently, and implement non-blocking mode as well. */
5198 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5200 child_process
* cp
= fd_info
[fd
].cp
;
5202 fd_info
[fd
].cp
= NULL
;
5204 if (CHILD_ACTIVE (cp
))
5206 /* if last descriptor to active child_process then cleanup */
5208 for (i
= 0; i
< MAXDESC
; i
++)
5212 if (fd_info
[i
].cp
== cp
)
5217 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5219 if (winsock_lib
== NULL
) abort ();
5221 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5222 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5224 winsock_inuse
--; /* count open sockets */
5231 /* Note that sockets do not need special treatment here (at least on
5232 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5233 closesocket is equivalent to CloseHandle, which is to be expected
5234 because socket handles are fully fledged kernel handles. */
5237 if (rc
== 0 && fd
< MAXDESC
)
5238 fd_info
[fd
].flags
= 0;
5249 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5251 /* duplicate our internal info as well */
5252 fd_info
[new_fd
] = fd_info
[fd
];
5258 sys_dup2 (int src
, int dst
)
5262 if (dst
< 0 || dst
>= MAXDESC
)
5268 /* make sure we close the destination first if it's a pipe or socket */
5269 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5272 rc
= _dup2 (src
, dst
);
5275 /* duplicate our internal info as well */
5276 fd_info
[dst
] = fd_info
[src
];
5281 /* Unix pipe() has only one arg */
5283 sys_pipe (int * phandles
)
5288 /* make pipe handles non-inheritable; when we spawn a child, we
5289 replace the relevant handle with an inheritable one. Also put
5290 pipes into binary mode; we will do text mode translation ourselves
5292 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
5296 /* Protect against overflow, since Windows can open more handles than
5297 our fd_info array has room for. */
5298 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
5300 _close (phandles
[0]);
5301 _close (phandles
[1]);
5306 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
5307 fd_info
[phandles
[0]].flags
= flags
;
5309 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
5310 fd_info
[phandles
[1]].flags
= flags
;
5317 /* Function to do blocking read of one byte, needed to implement
5318 select. It is only allowed on sockets and pipes. */
5320 _sys_read_ahead (int fd
)
5325 if (fd
< 0 || fd
>= MAXDESC
)
5326 return STATUS_READ_ERROR
;
5328 cp
= fd_info
[fd
].cp
;
5330 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5331 return STATUS_READ_ERROR
;
5333 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
5334 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
5336 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
5340 cp
->status
= STATUS_READ_IN_PROGRESS
;
5342 if (fd_info
[fd
].flags
& FILE_PIPE
)
5344 rc
= _read (fd
, &cp
->chr
, sizeof (char));
5346 /* Give subprocess time to buffer some more output for us before
5347 reporting that input is available; we need this because Windows 95
5348 connects DOS programs to pipes by making the pipe appear to be
5349 the normal console stdout - as a result most DOS programs will
5350 write to stdout without buffering, ie. one character at a
5351 time. Even some W32 programs do this - "dir" in a command
5352 shell on NT is very slow if we don't do this. */
5355 int wait
= w32_pipe_read_delay
;
5361 /* Yield remainder of our time slice, effectively giving a
5362 temporary priority boost to the child process. */
5366 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5368 HANDLE hnd
= fd_info
[fd
].hnd
;
5369 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5372 /* Configure timeouts for blocking read. */
5373 if (!GetCommTimeouts (hnd
, &ct
))
5374 return STATUS_READ_ERROR
;
5375 ct
.ReadIntervalTimeout
= 0;
5376 ct
.ReadTotalTimeoutMultiplier
= 0;
5377 ct
.ReadTotalTimeoutConstant
= 0;
5378 if (!SetCommTimeouts (hnd
, &ct
))
5379 return STATUS_READ_ERROR
;
5381 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
5383 if (GetLastError () != ERROR_IO_PENDING
)
5384 return STATUS_READ_ERROR
;
5385 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5386 return STATUS_READ_ERROR
;
5389 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
5391 unsigned long nblock
= 0;
5392 /* We always want this to block, so temporarily disable NDELAY. */
5393 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5394 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5396 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
5398 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5401 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5405 if (rc
== sizeof (char))
5406 cp
->status
= STATUS_READ_SUCCEEDED
;
5408 cp
->status
= STATUS_READ_FAILED
;
5414 _sys_wait_accept (int fd
)
5420 if (fd
< 0 || fd
>= MAXDESC
)
5421 return STATUS_READ_ERROR
;
5423 cp
= fd_info
[fd
].cp
;
5425 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
5426 return STATUS_READ_ERROR
;
5428 cp
->status
= STATUS_READ_FAILED
;
5430 hEv
= pfn_WSACreateEvent ();
5431 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
5432 if (rc
!= SOCKET_ERROR
)
5434 rc
= WaitForSingleObject (hEv
, INFINITE
);
5435 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
5436 if (rc
== WAIT_OBJECT_0
)
5437 cp
->status
= STATUS_READ_SUCCEEDED
;
5439 pfn_WSACloseEvent (hEv
);
5445 sys_read (int fd
, char * buffer
, unsigned int count
)
5450 char * orig_buffer
= buffer
;
5458 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5460 child_process
*cp
= fd_info
[fd
].cp
;
5462 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
5470 /* re-read CR carried over from last read */
5471 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
5473 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
5477 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
5480 /* presence of a child_process structure means we are operating in
5481 non-blocking mode - otherwise we just call _read directly.
5482 Note that the child_process structure might be missing because
5483 reap_subprocess has been called; in this case the pipe is
5484 already broken, so calling _read on it is okay. */
5487 int current_status
= cp
->status
;
5489 switch (current_status
)
5491 case STATUS_READ_FAILED
:
5492 case STATUS_READ_ERROR
:
5493 /* report normal EOF if nothing in buffer */
5495 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5498 case STATUS_READ_READY
:
5499 case STATUS_READ_IN_PROGRESS
:
5500 DebPrint (("sys_read called when read is in progress\n"));
5501 errno
= EWOULDBLOCK
;
5504 case STATUS_READ_SUCCEEDED
:
5505 /* consume read-ahead char */
5506 *buffer
++ = cp
->chr
;
5509 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5510 ResetEvent (cp
->char_avail
);
5512 case STATUS_READ_ACKNOWLEDGED
:
5516 DebPrint (("sys_read: bad status %d\n", current_status
));
5521 if (fd_info
[fd
].flags
& FILE_PIPE
)
5523 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
5524 to_read
= min (waiting
, (DWORD
) count
);
5527 nchars
+= _read (fd
, buffer
, to_read
);
5529 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
5531 HANDLE hnd
= fd_info
[fd
].hnd
;
5532 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
5538 /* Configure timeouts for non-blocking read. */
5539 if (!GetCommTimeouts (hnd
, &ct
))
5544 ct
.ReadIntervalTimeout
= MAXDWORD
;
5545 ct
.ReadTotalTimeoutMultiplier
= 0;
5546 ct
.ReadTotalTimeoutConstant
= 0;
5547 if (!SetCommTimeouts (hnd
, &ct
))
5553 if (!ResetEvent (ovl
->hEvent
))
5558 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
5560 if (GetLastError () != ERROR_IO_PENDING
)
5565 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
5574 else /* FILE_SOCKET */
5576 if (winsock_lib
== NULL
) abort ();
5578 /* do the equivalent of a non-blocking read */
5579 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
5580 if (waiting
== 0 && nchars
== 0)
5582 h_errno
= errno
= EWOULDBLOCK
;
5588 /* always use binary mode for sockets */
5589 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
5590 if (res
== SOCKET_ERROR
)
5592 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5593 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5603 int nread
= _read (fd
, buffer
, count
);
5606 else if (nchars
== 0)
5611 fd_info
[fd
].flags
|= FILE_AT_EOF
;
5612 /* Perform text mode translation if required. */
5613 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5615 nchars
= crlf_to_lf (nchars
, orig_buffer
);
5616 /* If buffer contains only CR, return that. To be absolutely
5617 sure we should attempt to read the next char, but in
5618 practice a CR to be followed by LF would not appear by
5619 itself in the buffer. */
5620 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
5622 fd_info
[fd
].flags
|= FILE_LAST_CR
;
5628 nchars
= _read (fd
, buffer
, count
);
5633 /* From w32xfns.c */
5634 extern HANDLE interrupt_handle
;
5636 /* For now, don't bother with a non-blocking mode */
5638 sys_write (int fd
, const void * buffer
, unsigned int count
)
5648 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
5650 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
5656 /* Perform text mode translation if required. */
5657 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
5659 char * tmpbuf
= alloca (count
* 2);
5660 unsigned char * src
= (void *)buffer
;
5661 unsigned char * dst
= tmpbuf
;
5666 unsigned char *next
;
5667 /* copy next line or remaining bytes */
5668 next
= _memccpy (dst
, src
, '\n', nbytes
);
5671 /* copied one line ending with '\n' */
5672 int copied
= next
- dst
;
5675 /* insert '\r' before '\n' */
5682 /* copied remaining partial line -> now finished */
5689 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
5691 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
5692 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
5693 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
5696 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
5698 if (GetLastError () != ERROR_IO_PENDING
)
5703 if (detect_input_pending ())
5704 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
5707 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
5708 if (active
== WAIT_OBJECT_0
)
5709 { /* User pressed C-g, cancel write, then leave. Don't bother
5710 cleaning up as we may only get stuck in buggy drivers. */
5711 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
5716 if (active
== WAIT_OBJECT_0
+ 1
5717 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
5724 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
5726 unsigned long nblock
= 0;
5727 if (winsock_lib
== NULL
) abort ();
5729 /* TODO: implement select() properly so non-blocking I/O works. */
5730 /* For now, make sure the write blocks. */
5731 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5732 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5734 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
5736 /* Set the socket back to non-blocking if it was before,
5737 for other operations that support it. */
5738 if (fd_info
[fd
].flags
& FILE_NDELAY
)
5741 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
5744 if (nchars
== SOCKET_ERROR
)
5746 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5747 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
5753 /* Some networked filesystems don't like too large writes, so
5754 break them into smaller chunks. See the Comments section of
5755 the MSDN documentation of WriteFile for details behind the
5756 choice of the value of CHUNK below. See also the thread
5757 http://thread.gmane.org/gmane.comp.version-control.git/145294
5758 in the git mailing list. */
5759 const unsigned char *p
= buffer
;
5760 const unsigned chunk
= 30 * 1024 * 1024;
5765 unsigned this_chunk
= count
< chunk
? count
: chunk
;
5766 int n
= _write (fd
, p
, this_chunk
);
5774 else if (n
< this_chunk
)
5784 /* The Windows CRT functions are "optimized for speed", so they don't
5785 check for timezone and DST changes if they were last called less
5786 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
5787 all Emacs features that repeatedly call time functions (e.g.,
5788 display-time) are in real danger of missing timezone and DST
5789 changes. Calling tzset before each localtime call fixes that. */
5791 sys_localtime (const time_t *t
)
5794 return localtime (t
);
5799 /* Delayed loading of libraries. */
5801 Lisp_Object Vlibrary_cache
;
5803 /* The argument LIBRARIES is an alist that associates a symbol
5804 LIBRARY_ID, identifying an external DLL library known to Emacs, to
5805 a list of filenames under which the library is usually found. In
5806 most cases, the argument passed as LIBRARIES is the variable
5807 `dynamic-library-alist', which is initialized to a list of common
5808 library names. If the function loads the library successfully, it
5809 returns the handle of the DLL, and records the filename in the
5810 property :loaded-from of LIBRARY_ID; it returns NULL if the library
5811 could not be found, or when it was already loaded (because the
5812 handle is not recorded anywhere, and so is lost after use). It
5813 would be trivial to save the handle too in :loaded-from, but
5814 currently there's no use case for it. */
5816 w32_delayed_load (Lisp_Object libraries
, Lisp_Object library_id
)
5818 HMODULE library_dll
= NULL
;
5820 CHECK_SYMBOL (library_id
);
5822 if (CONSP (libraries
) && NILP (Fassq (library_id
, Vlibrary_cache
)))
5824 Lisp_Object found
= Qnil
;
5825 Lisp_Object dlls
= Fassq (library_id
, libraries
);
5828 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
5830 CHECK_STRING_CAR (dlls
);
5831 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
5833 char name
[MAX_PATH
];
5836 len
= GetModuleFileNameA (library_dll
, name
, sizeof (name
));
5837 found
= Fcons (XCAR (dlls
),
5839 /* Possibly truncated */
5840 ? make_specified_string (name
, -1, len
, 1)
5846 Fput (library_id
, QCloaded_from
, found
);
5854 check_windows_init_file (void)
5856 /* A common indication that Emacs is not installed properly is when
5857 it cannot find the Windows installation file. If this file does
5858 not exist in the expected place, tell the user. */
5860 if (!noninteractive
&& !inhibit_window_system
5861 /* Vload_path is not yet initialized when we are loading
5863 && NILP (Vpurify_flag
))
5865 Lisp_Object objs
[2];
5866 Lisp_Object full_load_path
;
5867 Lisp_Object init_file
;
5870 objs
[0] = Vload_path
;
5871 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5872 full_load_path
= Fappend (2, objs
);
5873 init_file
= build_string ("term/w32-win");
5874 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
5877 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
5878 char *init_file_name
= SDATA (init_file
);
5879 char *load_path
= SDATA (load_path_print
);
5880 char *buffer
= alloca (1024
5881 + strlen (init_file_name
)
5882 + strlen (load_path
));
5885 "The Emacs Windows initialization file \"%s.el\" "
5886 "could not be found in your Emacs installation. "
5887 "Emacs checked the following directories for this file:\n"
5889 "When Emacs cannot find this file, it usually means that it "
5890 "was not installed properly, or its distribution file was "
5891 "not unpacked properly.\nSee the README.W32 file in the "
5892 "top-level Emacs directory for more information.",
5893 init_file_name
, load_path
);
5896 "Emacs Abort Dialog",
5897 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
5898 /* Use the low-level Emacs abort. */
5912 /* shutdown the socket interface if necessary */
5921 /* Initialize the socket interface now if available and requested by
5922 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5923 delayed until open-network-stream is called (w32-has-winsock can
5924 also be used to dynamically load or reload winsock).
5926 Conveniently, init_environment is called before us, so
5927 PRELOAD_WINSOCK can be set in the registry. */
5929 /* Always initialize this correctly. */
5932 if (getenv ("PRELOAD_WINSOCK") != NULL
)
5933 init_winsock (TRUE
);
5935 /* Initial preparation for subprocess support: replace our standard
5936 handles with non-inheritable versions. */
5939 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
5940 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
5941 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
5943 parent
= GetCurrentProcess ();
5945 /* ignore errors when duplicating and closing; typically the
5946 handles will be invalid when running as a gui program. */
5947 DuplicateHandle (parent
,
5948 GetStdHandle (STD_INPUT_HANDLE
),
5953 DUPLICATE_SAME_ACCESS
);
5955 DuplicateHandle (parent
,
5956 GetStdHandle (STD_OUTPUT_HANDLE
),
5961 DUPLICATE_SAME_ACCESS
);
5963 DuplicateHandle (parent
,
5964 GetStdHandle (STD_ERROR_HANDLE
),
5969 DUPLICATE_SAME_ACCESS
);
5975 if (stdin_save
!= INVALID_HANDLE_VALUE
)
5976 _open_osfhandle ((long) stdin_save
, O_TEXT
);
5978 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
5981 if (stdout_save
!= INVALID_HANDLE_VALUE
)
5982 _open_osfhandle ((long) stdout_save
, O_TEXT
);
5984 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5987 if (stderr_save
!= INVALID_HANDLE_VALUE
)
5988 _open_osfhandle ((long) stderr_save
, O_TEXT
);
5990 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
5994 /* unfortunately, atexit depends on implementation of malloc */
5995 /* atexit (term_ntproc); */
5996 signal (SIGABRT
, term_ntproc
);
5998 /* determine which drives are fixed, for GetCachedVolumeInformation */
6000 /* GetDriveType must have trailing backslash. */
6001 char drive
[] = "A:\\";
6003 /* Loop over all possible drive letters */
6004 while (*drive
<= 'Z')
6006 /* Record if this drive letter refers to a fixed drive. */
6007 fixed_drives
[DRIVE_INDEX (*drive
)] =
6008 (GetDriveType (drive
) == DRIVE_FIXED
);
6013 /* Reset the volume info cache. */
6014 volume_cache
= NULL
;
6017 /* Check to see if Emacs has been installed correctly. */
6018 check_windows_init_file ();
6022 shutdown_handler ensures that buffers' autosave files are
6023 up to date when the user logs off, or the system shuts down.
6026 shutdown_handler (DWORD type
)
6028 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
6029 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
6030 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
6031 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
6033 /* Shut down cleanly, making sure autosave files are up to date. */
6034 shut_down_emacs (0, 0, Qnil
);
6037 /* Allow other handlers to handle this signal. */
6042 globals_of_w32 is used to initialize those global variables that
6043 must always be initialized on startup even when the global variable
6044 initialized is non zero (see the function main in emacs.c).
6047 globals_of_w32 (void)
6049 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
6051 get_process_times_fn
= (GetProcessTimes_Proc
)
6052 GetProcAddress (kernel32
, "GetProcessTimes");
6054 DEFSYM (QCloaded_from
, ":loaded-from");
6056 Vlibrary_cache
= Qnil
;
6057 staticpro (&Vlibrary_cache
);
6059 g_b_init_is_windows_9x
= 0;
6060 g_b_init_open_process_token
= 0;
6061 g_b_init_get_token_information
= 0;
6062 g_b_init_lookup_account_sid
= 0;
6063 g_b_init_get_sid_sub_authority
= 0;
6064 g_b_init_get_sid_sub_authority_count
= 0;
6065 g_b_init_get_file_security
= 0;
6066 g_b_init_get_security_descriptor_owner
= 0;
6067 g_b_init_get_security_descriptor_group
= 0;
6068 g_b_init_is_valid_sid
= 0;
6069 g_b_init_create_toolhelp32_snapshot
= 0;
6070 g_b_init_process32_first
= 0;
6071 g_b_init_process32_next
= 0;
6072 g_b_init_open_thread_token
= 0;
6073 g_b_init_impersonate_self
= 0;
6074 g_b_init_revert_to_self
= 0;
6075 g_b_init_get_process_memory_info
= 0;
6076 g_b_init_get_process_working_set_size
= 0;
6077 g_b_init_global_memory_status
= 0;
6078 g_b_init_global_memory_status_ex
= 0;
6079 g_b_init_equal_sid
= 0;
6080 g_b_init_copy_sid
= 0;
6081 g_b_init_get_length_sid
= 0;
6082 g_b_init_get_native_system_info
= 0;
6083 g_b_init_get_system_times
= 0;
6084 num_of_processors
= 0;
6085 /* The following sets a handler for shutdown notifications for
6086 console apps. This actually applies to Emacs in both console and
6087 GUI modes, since we had to fool windows into thinking emacs is a
6088 console application to get console mode to work. */
6089 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
6091 /* "None" is the default group name on standalone workstations. */
6092 strcpy (dflt_group_name
, "None");
6095 /* For make-serial-process */
6097 serial_open (char *port
)
6103 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
6104 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
6105 if (hnd
== INVALID_HANDLE_VALUE
)
6106 error ("Could not open %s", port
);
6107 fd
= (int) _open_osfhandle ((int) hnd
, 0);
6109 error ("Could not open %s", port
);
6113 error ("Could not create child process");
6115 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6116 fd_info
[ fd
].hnd
= hnd
;
6117 fd_info
[ fd
].flags
|=
6118 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
6119 if (fd_info
[ fd
].cp
!= NULL
)
6121 error ("fd_info[fd = %d] is already in use", fd
);
6123 fd_info
[ fd
].cp
= cp
;
6124 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6125 if (cp
->ovl_read
.hEvent
== NULL
)
6126 error ("Could not create read event");
6127 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6128 if (cp
->ovl_write
.hEvent
== NULL
)
6129 error ("Could not create write event");
6134 /* For serial-process-configure */
6136 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
6138 Lisp_Object childp2
= Qnil
;
6139 Lisp_Object tem
= Qnil
;
6143 char summary
[4] = "???"; /* This usually becomes "8N1". */
6145 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6146 error ("Not a serial process");
6147 hnd
= fd_info
[ p
->outfd
].hnd
;
6149 childp2
= Fcopy_sequence (p
->childp
);
6151 /* Initialize timeouts for blocking read and blocking write. */
6152 if (!GetCommTimeouts (hnd
, &ct
))
6153 error ("GetCommTimeouts() failed");
6154 ct
.ReadIntervalTimeout
= 0;
6155 ct
.ReadTotalTimeoutMultiplier
= 0;
6156 ct
.ReadTotalTimeoutConstant
= 0;
6157 ct
.WriteTotalTimeoutMultiplier
= 0;
6158 ct
.WriteTotalTimeoutConstant
= 0;
6159 if (!SetCommTimeouts (hnd
, &ct
))
6160 error ("SetCommTimeouts() failed");
6161 /* Read port attributes and prepare default configuration. */
6162 memset (&dcb
, 0, sizeof (dcb
));
6163 dcb
.DCBlength
= sizeof (DCB
);
6164 if (!GetCommState (hnd
, &dcb
))
6165 error ("GetCommState() failed");
6168 dcb
.fAbortOnError
= FALSE
;
6169 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6174 /* Configure speed. */
6175 if (!NILP (Fplist_member (contact
, QCspeed
)))
6176 tem
= Fplist_get (contact
, QCspeed
);
6178 tem
= Fplist_get (p
->childp
, QCspeed
);
6180 dcb
.BaudRate
= XINT (tem
);
6181 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6183 /* Configure bytesize. */
6184 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6185 tem
= Fplist_get (contact
, QCbytesize
);
6187 tem
= Fplist_get (p
->childp
, QCbytesize
);
6189 tem
= make_number (8);
6191 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6192 error (":bytesize must be nil (8), 7, or 8");
6193 dcb
.ByteSize
= XINT (tem
);
6194 summary
[0] = XINT (tem
) + '0';
6195 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6197 /* Configure parity. */
6198 if (!NILP (Fplist_member (contact
, QCparity
)))
6199 tem
= Fplist_get (contact
, QCparity
);
6201 tem
= Fplist_get (p
->childp
, QCparity
);
6202 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6203 error (":parity must be nil (no parity), `even', or `odd'");
6204 dcb
.fParity
= FALSE
;
6205 dcb
.Parity
= NOPARITY
;
6206 dcb
.fErrorChar
= FALSE
;
6211 else if (EQ (tem
, Qeven
))
6215 dcb
.Parity
= EVENPARITY
;
6216 dcb
.fErrorChar
= TRUE
;
6218 else if (EQ (tem
, Qodd
))
6222 dcb
.Parity
= ODDPARITY
;
6223 dcb
.fErrorChar
= TRUE
;
6225 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6227 /* Configure stopbits. */
6228 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6229 tem
= Fplist_get (contact
, QCstopbits
);
6231 tem
= Fplist_get (p
->childp
, QCstopbits
);
6233 tem
= make_number (1);
6235 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6236 error (":stopbits must be nil (1 stopbit), 1, or 2");
6237 summary
[2] = XINT (tem
) + '0';
6238 if (XINT (tem
) == 1)
6239 dcb
.StopBits
= ONESTOPBIT
;
6240 else if (XINT (tem
) == 2)
6241 dcb
.StopBits
= TWOSTOPBITS
;
6242 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6244 /* Configure flowcontrol. */
6245 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6246 tem
= Fplist_get (contact
, QCflowcontrol
);
6248 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6249 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6250 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6251 dcb
.fOutxCtsFlow
= FALSE
;
6252 dcb
.fOutxDsrFlow
= FALSE
;
6253 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6254 dcb
.fDsrSensitivity
= FALSE
;
6255 dcb
.fTXContinueOnXoff
= FALSE
;
6258 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6259 dcb
.XonChar
= 17; /* Control-Q */
6260 dcb
.XoffChar
= 19; /* Control-S */
6263 /* Already configured. */
6265 else if (EQ (tem
, Qhw
))
6267 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6268 dcb
.fOutxCtsFlow
= TRUE
;
6270 else if (EQ (tem
, Qsw
))
6275 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6277 /* Activate configuration. */
6278 if (!SetCommState (hnd
, &dcb
))
6279 error ("SetCommState() failed");
6281 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
6282 p
->childp
= childp2
;
6288 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
6292 struct timeval timeout
;
6293 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
6294 int fd
= process
->infd
;
6298 n
= sys_read (fd
, (char*)buf
, sz
);
6305 if (err
== EWOULDBLOCK
)
6307 /* Set a small timeout. */
6309 timeout
.tv_usec
= 0;
6311 FD_SET ((int)fd
, &fdset
);
6313 /* Use select with the timeout to poll the selector. */
6314 sc
= select (fd
+ 1, &fdset
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0,
6318 continue; /* Try again. */
6320 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
6321 Also accept select return 0 as an indicator to EAGAIN. */
6322 if (sc
== 0 || errno
== EWOULDBLOCK
)
6325 err
= errno
; /* Other errors are just passed on. */
6328 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
6335 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
6337 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
6338 int fd
= process
->outfd
;
6339 ssize_t n
= sys_write (fd
, buf
, sz
);
6341 /* 0 or more bytes written means everything went fine. */
6345 /* Negative bytes written means we got an error in errno.
6346 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
6347 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
6348 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
6352 #endif /* HAVE_GNUTLS */