1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows 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>
38 /* must include CRT headers *before* config.h */
41 #include <mbstring.h> /* for _mbspbrk */
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 #include <winioctl.h>
123 /* MSVC doesn't provide the definition of REPARSE_DATA_BUFFER, except
124 on ntifs.h, which cannot be included because it triggers conflicts
125 with other Windows API headers. So we define it here by hand. */
127 typedef struct _REPARSE_DATA_BUFFER
{
129 USHORT ReparseDataLength
;
133 USHORT SubstituteNameOffset
;
134 USHORT SubstituteNameLength
;
135 USHORT PrintNameOffset
;
136 USHORT PrintNameLength
;
139 } SymbolicLinkReparseBuffer
;
141 USHORT SubstituteNameOffset
;
142 USHORT SubstituteNameLength
;
143 USHORT PrintNameOffset
;
144 USHORT PrintNameLength
;
146 } MountPointReparseBuffer
;
149 } GenericReparseBuffer
;
151 } REPARSE_DATA_BUFFER
, *PREPARSE_DATA_BUFFER
;
155 /* TCP connection support. */
156 #include <sys/socket.h>
179 #include "dispextern.h" /* for xstrcasecmp */
180 #include "coding.h" /* for Vlocale_coding_system */
182 #include "careadlinkat.h"
183 #include "allocator.h"
185 /* For serial_configure and serial_open. */
188 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
189 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
191 Lisp_Object QCloaded_from
;
193 void globals_of_w32 (void);
194 static DWORD
get_rid (PSID
);
195 static int is_symlink (const char *);
196 static char * chase_symlinks (const char *);
197 static int enable_privilege (LPCTSTR
, BOOL
, TOKEN_PRIVILEGES
*);
198 static int restore_privilege (TOKEN_PRIVILEGES
*);
199 static BOOL WINAPI
revert_to_self (void);
202 /* Initialization states.
204 WARNING: If you add any more such variables for additional APIs,
205 you MUST add initialization for them to globals_of_w32
206 below. This is because these variables might get set
207 to non-NULL values during dumping, but the dumped Emacs
208 cannot reuse those values, because it could be run on a
209 different version of the OS, where API addresses are
211 static BOOL g_b_init_is_windows_9x
;
212 static BOOL g_b_init_open_process_token
;
213 static BOOL g_b_init_get_token_information
;
214 static BOOL g_b_init_lookup_account_sid
;
215 static BOOL g_b_init_get_sid_sub_authority
;
216 static BOOL g_b_init_get_sid_sub_authority_count
;
217 static BOOL g_b_init_get_security_info
;
218 static BOOL g_b_init_get_file_security
;
219 static BOOL g_b_init_get_security_descriptor_owner
;
220 static BOOL g_b_init_get_security_descriptor_group
;
221 static BOOL g_b_init_is_valid_sid
;
222 static BOOL g_b_init_create_toolhelp32_snapshot
;
223 static BOOL g_b_init_process32_first
;
224 static BOOL g_b_init_process32_next
;
225 static BOOL g_b_init_open_thread_token
;
226 static BOOL g_b_init_impersonate_self
;
227 static BOOL g_b_init_revert_to_self
;
228 static BOOL g_b_init_get_process_memory_info
;
229 static BOOL g_b_init_get_process_working_set_size
;
230 static BOOL g_b_init_global_memory_status
;
231 static BOOL g_b_init_global_memory_status_ex
;
232 static BOOL g_b_init_get_length_sid
;
233 static BOOL g_b_init_equal_sid
;
234 static BOOL g_b_init_copy_sid
;
235 static BOOL g_b_init_get_native_system_info
;
236 static BOOL g_b_init_get_system_times
;
237 static BOOL g_b_init_create_symbolic_link
;
240 BEGIN: Wrapper functions around OpenProcessToken
241 and other functions in advapi32.dll that are only
242 supported in Windows NT / 2k / XP
244 /* ** Function pointer typedefs ** */
245 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
246 HANDLE ProcessHandle
,
248 PHANDLE TokenHandle
);
249 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
251 TOKEN_INFORMATION_CLASS TokenInformationClass
,
252 LPVOID TokenInformation
,
253 DWORD TokenInformationLength
,
254 PDWORD ReturnLength
);
255 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
256 HANDLE process_handle
,
257 LPFILETIME creation_time
,
258 LPFILETIME exit_time
,
259 LPFILETIME kernel_time
,
260 LPFILETIME user_time
);
262 GetProcessTimes_Proc get_process_times_fn
= NULL
;
265 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
266 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
268 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
269 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
271 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
272 LPCTSTR lpSystemName
,
277 LPDWORD cbDomainName
,
278 PSID_NAME_USE peUse
);
279 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
282 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
284 typedef DWORD (WINAPI
* GetSecurityInfo_Proc
) (
286 SE_OBJECT_TYPE ObjectType
,
287 SECURITY_INFORMATION SecurityInfo
,
292 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
);
293 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
295 SECURITY_INFORMATION RequestedInformation
,
296 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
298 LPDWORD lpnLengthNeeded
);
299 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
300 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
302 LPBOOL lpbOwnerDefaulted
);
303 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
304 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
306 LPBOOL lpbGroupDefaulted
);
307 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
309 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
311 DWORD th32ProcessID
);
312 typedef BOOL (WINAPI
* Process32First_Proc
) (
314 LPPROCESSENTRY32 lppe
);
315 typedef BOOL (WINAPI
* Process32Next_Proc
) (
317 LPPROCESSENTRY32 lppe
);
318 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
322 PHANDLE TokenHandle
);
323 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
324 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
325 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
326 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
328 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
330 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
332 DWORD
* lpMinimumWorkingSetSize
,
333 DWORD
* lpMaximumWorkingSetSize
);
334 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
335 LPMEMORYSTATUS lpBuffer
);
336 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
337 LPMEMORY_STATUS_EX lpBuffer
);
338 typedef BOOL (WINAPI
* CopySid_Proc
) (
339 DWORD nDestinationSidLength
,
340 PSID pDestinationSid
,
342 typedef BOOL (WINAPI
* EqualSid_Proc
) (
345 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
347 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
348 LPSYSTEM_INFO lpSystemInfo
);
349 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
350 LPFILETIME lpIdleTime
,
351 LPFILETIME lpKernelTime
,
352 LPFILETIME lpUserTime
);
353 typedef BOOLEAN (WINAPI
*CreateSymbolicLink_Proc
) (
354 LPTSTR lpSymlinkFileName
,
355 LPTSTR lpTargetFileName
,
358 /* ** A utility function ** */
362 static BOOL s_b_ret
= 0;
363 OSVERSIONINFO os_ver
;
364 if (g_b_init_is_windows_9x
== 0)
366 g_b_init_is_windows_9x
= 1;
367 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
368 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
369 if (GetVersionEx (&os_ver
))
371 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
377 static Lisp_Object
ltime (ULONGLONG
);
379 /* Get total user and system times for get-internal-run-time.
380 Returns a list of integers if the times are provided by the OS
381 (NT derivatives), otherwise it returns the result of current-time. */
383 w32_get_internal_run_time (void)
385 if (get_process_times_fn
)
387 FILETIME create
, exit
, kernel
, user
;
388 HANDLE proc
= GetCurrentProcess ();
389 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
391 LARGE_INTEGER user_int
, kernel_int
, total
;
392 user_int
.LowPart
= user
.dwLowDateTime
;
393 user_int
.HighPart
= user
.dwHighDateTime
;
394 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
395 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
396 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
397 return ltime (total
.QuadPart
);
401 return Fcurrent_time ();
404 /* ** The wrapper functions ** */
407 open_process_token (HANDLE ProcessHandle
,
411 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
412 HMODULE hm_advapi32
= NULL
;
413 if (is_windows_9x () == TRUE
)
417 if (g_b_init_open_process_token
== 0)
419 g_b_init_open_process_token
= 1;
420 hm_advapi32
= LoadLibrary ("Advapi32.dll");
421 s_pfn_Open_Process_Token
=
422 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
424 if (s_pfn_Open_Process_Token
== NULL
)
429 s_pfn_Open_Process_Token (
437 get_token_information (HANDLE TokenHandle
,
438 TOKEN_INFORMATION_CLASS TokenInformationClass
,
439 LPVOID TokenInformation
,
440 DWORD TokenInformationLength
,
443 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
444 HMODULE hm_advapi32
= NULL
;
445 if (is_windows_9x () == TRUE
)
449 if (g_b_init_get_token_information
== 0)
451 g_b_init_get_token_information
= 1;
452 hm_advapi32
= LoadLibrary ("Advapi32.dll");
453 s_pfn_Get_Token_Information
=
454 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
456 if (s_pfn_Get_Token_Information
== NULL
)
461 s_pfn_Get_Token_Information (
463 TokenInformationClass
,
465 TokenInformationLength
,
471 lookup_account_sid (LPCTSTR lpSystemName
,
476 LPDWORD cbDomainName
,
479 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
480 HMODULE hm_advapi32
= NULL
;
481 if (is_windows_9x () == TRUE
)
485 if (g_b_init_lookup_account_sid
== 0)
487 g_b_init_lookup_account_sid
= 1;
488 hm_advapi32
= LoadLibrary ("Advapi32.dll");
489 s_pfn_Lookup_Account_Sid
=
490 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
492 if (s_pfn_Lookup_Account_Sid
== NULL
)
497 s_pfn_Lookup_Account_Sid (
509 get_sid_sub_authority (PSID pSid
, DWORD n
)
511 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
512 static DWORD zero
= 0U;
513 HMODULE hm_advapi32
= NULL
;
514 if (is_windows_9x () == TRUE
)
518 if (g_b_init_get_sid_sub_authority
== 0)
520 g_b_init_get_sid_sub_authority
= 1;
521 hm_advapi32
= LoadLibrary ("Advapi32.dll");
522 s_pfn_Get_Sid_Sub_Authority
=
523 (GetSidSubAuthority_Proc
) GetProcAddress (
524 hm_advapi32
, "GetSidSubAuthority");
526 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
530 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
534 get_sid_sub_authority_count (PSID pSid
)
536 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
537 static UCHAR zero
= 0U;
538 HMODULE hm_advapi32
= NULL
;
539 if (is_windows_9x () == TRUE
)
543 if (g_b_init_get_sid_sub_authority_count
== 0)
545 g_b_init_get_sid_sub_authority_count
= 1;
546 hm_advapi32
= LoadLibrary ("Advapi32.dll");
547 s_pfn_Get_Sid_Sub_Authority_Count
=
548 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
549 hm_advapi32
, "GetSidSubAuthorityCount");
551 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
555 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
559 get_security_info (HANDLE handle
,
560 SE_OBJECT_TYPE ObjectType
,
561 SECURITY_INFORMATION SecurityInfo
,
566 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
)
568 static GetSecurityInfo_Proc s_pfn_Get_Security_Info
= NULL
;
569 HMODULE hm_advapi32
= NULL
;
570 if (is_windows_9x () == TRUE
)
574 if (g_b_init_get_security_info
== 0)
576 g_b_init_get_security_info
= 1;
577 hm_advapi32
= LoadLibrary ("Advapi32.dll");
578 s_pfn_Get_Security_Info
=
579 (GetSecurityInfo_Proc
) GetProcAddress (
580 hm_advapi32
, "GetSecurityInfo");
582 if (s_pfn_Get_Security_Info
== NULL
)
586 return (s_pfn_Get_Security_Info (handle
, ObjectType
, SecurityInfo
,
587 ppsidOwner
, ppsidGroup
, ppDacl
, ppSacl
,
588 ppSecurityDescriptor
));
592 get_file_security (LPCTSTR lpFileName
,
593 SECURITY_INFORMATION RequestedInformation
,
594 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
596 LPDWORD lpnLengthNeeded
)
598 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
599 HMODULE hm_advapi32
= NULL
;
600 if (is_windows_9x () == TRUE
)
604 if (g_b_init_get_file_security
== 0)
606 g_b_init_get_file_security
= 1;
607 hm_advapi32
= LoadLibrary ("Advapi32.dll");
608 s_pfn_Get_File_Security
=
609 (GetFileSecurity_Proc
) GetProcAddress (
610 hm_advapi32
, GetFileSecurity_Name
);
612 if (s_pfn_Get_File_Security
== NULL
)
616 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
617 pSecurityDescriptor
, nLength
,
622 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
624 LPBOOL lpbOwnerDefaulted
)
626 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
627 HMODULE hm_advapi32
= NULL
;
628 if (is_windows_9x () == TRUE
)
632 if (g_b_init_get_security_descriptor_owner
== 0)
634 g_b_init_get_security_descriptor_owner
= 1;
635 hm_advapi32
= LoadLibrary ("Advapi32.dll");
636 s_pfn_Get_Security_Descriptor_Owner
=
637 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
638 hm_advapi32
, "GetSecurityDescriptorOwner");
640 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
644 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
649 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
651 LPBOOL lpbGroupDefaulted
)
653 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
654 HMODULE hm_advapi32
= NULL
;
655 if (is_windows_9x () == TRUE
)
659 if (g_b_init_get_security_descriptor_group
== 0)
661 g_b_init_get_security_descriptor_group
= 1;
662 hm_advapi32
= LoadLibrary ("Advapi32.dll");
663 s_pfn_Get_Security_Descriptor_Group
=
664 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
665 hm_advapi32
, "GetSecurityDescriptorGroup");
667 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
671 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
676 is_valid_sid (PSID sid
)
678 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
679 HMODULE hm_advapi32
= NULL
;
680 if (is_windows_9x () == TRUE
)
684 if (g_b_init_is_valid_sid
== 0)
686 g_b_init_is_valid_sid
= 1;
687 hm_advapi32
= LoadLibrary ("Advapi32.dll");
689 (IsValidSid_Proc
) GetProcAddress (
690 hm_advapi32
, "IsValidSid");
692 if (s_pfn_Is_Valid_Sid
== NULL
)
696 return (s_pfn_Is_Valid_Sid (sid
));
700 equal_sid (PSID sid1
, PSID sid2
)
702 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
703 HMODULE hm_advapi32
= NULL
;
704 if (is_windows_9x () == TRUE
)
708 if (g_b_init_equal_sid
== 0)
710 g_b_init_equal_sid
= 1;
711 hm_advapi32
= LoadLibrary ("Advapi32.dll");
713 (EqualSid_Proc
) GetProcAddress (
714 hm_advapi32
, "EqualSid");
716 if (s_pfn_Equal_Sid
== NULL
)
720 return (s_pfn_Equal_Sid (sid1
, sid2
));
724 get_length_sid (PSID sid
)
726 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
727 HMODULE hm_advapi32
= NULL
;
728 if (is_windows_9x () == TRUE
)
732 if (g_b_init_get_length_sid
== 0)
734 g_b_init_get_length_sid
= 1;
735 hm_advapi32
= LoadLibrary ("Advapi32.dll");
736 s_pfn_Get_Length_Sid
=
737 (GetLengthSid_Proc
) GetProcAddress (
738 hm_advapi32
, "GetLengthSid");
740 if (s_pfn_Get_Length_Sid
== NULL
)
744 return (s_pfn_Get_Length_Sid (sid
));
748 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
750 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
751 HMODULE hm_advapi32
= NULL
;
752 if (is_windows_9x () == TRUE
)
756 if (g_b_init_copy_sid
== 0)
758 g_b_init_copy_sid
= 1;
759 hm_advapi32
= LoadLibrary ("Advapi32.dll");
761 (CopySid_Proc
) GetProcAddress (
762 hm_advapi32
, "CopySid");
764 if (s_pfn_Copy_Sid
== NULL
)
768 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
772 END: Wrapper functions around OpenProcessToken
773 and other functions in advapi32.dll that are only
774 supported in Windows NT / 2k / XP
778 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
780 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
781 if (is_windows_9x () != TRUE
)
783 if (g_b_init_get_native_system_info
== 0)
785 g_b_init_get_native_system_info
= 1;
786 s_pfn_Get_Native_System_Info
=
787 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
788 "GetNativeSystemInfo");
790 if (s_pfn_Get_Native_System_Info
!= NULL
)
791 s_pfn_Get_Native_System_Info (lpSystemInfo
);
794 lpSystemInfo
->dwNumberOfProcessors
= -1;
798 get_system_times (LPFILETIME lpIdleTime
,
799 LPFILETIME lpKernelTime
,
800 LPFILETIME lpUserTime
)
802 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
803 if (is_windows_9x () == TRUE
)
807 if (g_b_init_get_system_times
== 0)
809 g_b_init_get_system_times
= 1;
810 s_pfn_Get_System_times
=
811 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
814 if (s_pfn_Get_System_times
== NULL
)
816 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
819 static BOOLEAN WINAPI
820 create_symbolic_link (LPTSTR lpSymlinkFilename
,
821 LPTSTR lpTargetFileName
,
824 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link
= NULL
;
827 if (is_windows_9x () == TRUE
)
832 if (g_b_init_create_symbolic_link
== 0)
834 g_b_init_create_symbolic_link
= 1;
836 s_pfn_Create_Symbolic_Link
=
837 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
838 "CreateSymbolicLinkW");
840 s_pfn_Create_Symbolic_Link
=
841 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
842 "CreateSymbolicLinkA");
845 if (s_pfn_Create_Symbolic_Link
== NULL
)
851 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
853 /* If we were denied creation of the symlink, try again after
854 enabling the SeCreateSymbolicLinkPrivilege for our process. */
857 TOKEN_PRIVILEGES priv_current
;
859 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME
, TRUE
, &priv_current
))
861 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
863 restore_privilege (&priv_current
);
871 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
872 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
874 This is called from alloc.c:valid_pointer_p. */
876 w32_valid_pointer_p (void *p
, int size
)
879 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
883 unsigned char *buf
= alloca (size
);
884 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
893 static char startup_dir
[MAXPATHLEN
];
895 /* Get the current working directory. */
900 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
904 /* Emacs doesn't actually change directory itself, it stays in the
905 same directory where it was started. */
906 strcpy (dir
, startup_dir
);
911 /* Emulate getloadavg. */
920 /* Number of processors on this machine. */
921 static unsigned num_of_processors
;
923 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
924 static struct load_sample samples
[16*60];
925 static int first_idx
= -1, last_idx
= -1;
926 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
931 int next_idx
= from
+ 1;
933 if (next_idx
>= max_idx
)
942 int prev_idx
= from
- 1;
945 prev_idx
= max_idx
- 1;
951 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
954 FILETIME ft_idle
, ft_user
, ft_kernel
;
956 /* Initialize the number of processors on this machine. */
957 if (num_of_processors
<= 0)
959 get_native_system_info (&sysinfo
);
960 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
961 if (num_of_processors
<= 0)
963 GetSystemInfo (&sysinfo
);
964 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
966 if (num_of_processors
<= 0)
967 num_of_processors
= 1;
970 /* TODO: Take into account threads that are ready to run, by
971 sampling the "\System\Processor Queue Length" performance
972 counter. The code below accounts only for threads that are
975 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
977 ULARGE_INTEGER uidle
, ukernel
, uuser
;
979 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
980 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
981 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
982 *idle
= uidle
.QuadPart
;
983 *kernel
= ukernel
.QuadPart
;
984 *user
= uuser
.QuadPart
;
994 /* Produce the load average for a given time interval, using the
995 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
996 1-minute, 5-minute, or 15-minute average, respectively. */
1000 double retval
= -1.0;
1003 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
1004 time_t now
= samples
[last_idx
].sample_time
;
1006 if (first_idx
!= last_idx
)
1008 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
1010 tdiff
= difftime (now
, samples
[idx
].sample_time
);
1011 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
1014 samples
[last_idx
].kernel
+ samples
[last_idx
].user
1015 - (samples
[idx
].kernel
+ samples
[idx
].user
);
1016 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
1018 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
1021 if (idx
== first_idx
)
1030 getloadavg (double loadavg
[], int nelem
)
1033 ULONGLONG idle
, kernel
, user
;
1034 time_t now
= time (NULL
);
1036 /* Store another sample. We ignore samples that are less than 1 sec
1038 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
1040 sample_system_load (&idle
, &kernel
, &user
);
1041 last_idx
= buf_next (last_idx
);
1042 samples
[last_idx
].sample_time
= now
;
1043 samples
[last_idx
].idle
= idle
;
1044 samples
[last_idx
].kernel
= kernel
;
1045 samples
[last_idx
].user
= user
;
1046 /* If the buffer has more that 15 min worth of samples, discard
1048 if (first_idx
== -1)
1049 first_idx
= last_idx
;
1050 while (first_idx
!= last_idx
1051 && (difftime (now
, samples
[first_idx
].sample_time
)
1052 >= 15.0*60 + 2*DBL_EPSILON
*now
))
1053 first_idx
= buf_next (first_idx
);
1056 for (elem
= 0; elem
< nelem
; elem
++)
1058 double avg
= getavg (elem
);
1062 loadavg
[elem
] = avg
;
1068 /* Emulate getpwuid, getpwnam and others. */
1070 #define PASSWD_FIELD_SIZE 256
1072 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1073 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1074 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1075 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
1076 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
1078 static struct passwd dflt_passwd
=
1090 static char dflt_group_name
[GNLEN
+1];
1092 static struct group dflt_group
=
1094 /* When group information is not available, we return this as the
1095 group for all files. */
1103 return dflt_passwd
.pw_uid
;
1109 /* I could imagine arguing for checking to see whether the user is
1110 in the Administrators group and returning a UID of 0 for that
1111 case, but I don't know how wise that would be in the long run. */
1118 return dflt_passwd
.pw_gid
;
1128 getpwuid (unsigned uid
)
1130 if (uid
== dflt_passwd
.pw_uid
)
1131 return &dflt_passwd
;
1136 getgrgid (gid_t gid
)
1142 getpwnam (char *name
)
1146 pw
= getpwuid (getuid ());
1150 if (xstrcasecmp (name
, pw
->pw_name
))
1157 init_user_info (void)
1159 /* Find the user's real name by opening the process token and
1160 looking up the name associated with the user-sid in that token.
1162 Use the relative portion of the identifier authority value from
1163 the user-sid as the user id value (same for group id using the
1164 primary group sid from the process token). */
1166 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1167 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1168 DWORD glength
= sizeof (gname
);
1169 HANDLE token
= NULL
;
1170 SID_NAME_USE user_type
;
1171 unsigned char *buf
= NULL
;
1173 TOKEN_USER user_token
;
1174 TOKEN_PRIMARY_GROUP group_token
;
1177 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1180 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1181 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1183 buf
= xmalloc (blen
);
1184 result
= get_token_information (token
, TokenUser
,
1185 (LPVOID
)buf
, blen
, &needed
);
1188 memcpy (&user_token
, buf
, sizeof (user_token
));
1189 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1191 domain
, &dlength
, &user_type
);
1199 strcpy (dflt_passwd
.pw_name
, uname
);
1200 /* Determine a reasonable uid value. */
1201 if (xstrcasecmp ("administrator", uname
) == 0)
1203 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1204 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1208 /* Use the last sub-authority value of the RID, the relative
1209 portion of the SID, as user/group ID. */
1210 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1212 /* Get group id and name. */
1213 result
= get_token_information (token
, TokenPrimaryGroup
,
1214 (LPVOID
)buf
, blen
, &needed
);
1215 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1217 buf
= xrealloc (buf
, blen
= needed
);
1218 result
= get_token_information (token
, TokenPrimaryGroup
,
1219 (LPVOID
)buf
, blen
, &needed
);
1223 memcpy (&group_token
, buf
, sizeof (group_token
));
1224 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1225 dlength
= sizeof (domain
);
1226 /* If we can get at the real Primary Group name, use that.
1227 Otherwise, the default group name was already set to
1228 "None" in globals_of_w32. */
1229 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1230 gname
, &glength
, NULL
, &dlength
,
1232 strcpy (dflt_group_name
, gname
);
1235 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1238 /* If security calls are not supported (presumably because we
1239 are running under Windows 9X), fallback to this: */
1240 else if (GetUserName (uname
, &ulength
))
1242 strcpy (dflt_passwd
.pw_name
, uname
);
1243 if (xstrcasecmp ("administrator", uname
) == 0)
1244 dflt_passwd
.pw_uid
= 0;
1246 dflt_passwd
.pw_uid
= 123;
1247 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1251 strcpy (dflt_passwd
.pw_name
, "unknown");
1252 dflt_passwd
.pw_uid
= 123;
1253 dflt_passwd
.pw_gid
= 123;
1255 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1257 /* Ensure HOME and SHELL are defined. */
1258 if (getenv ("HOME") == NULL
)
1260 if (getenv ("SHELL") == NULL
)
1263 /* Set dir and shell from environment variables. */
1264 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1265 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1269 CloseHandle (token
);
1275 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1276 return ((rand () << 15) | rand ());
1286 /* Normalize filename by converting all path separators to
1287 the specified separator. Also conditionally convert upper
1288 case path name components to lower case. */
1291 normalize_filename (register char *fp
, char path_sep
)
1296 /* Always lower-case drive letters a-z, even if the filesystem
1297 preserves case in filenames.
1298 This is so filenames can be compared by string comparison
1299 functions that are case-sensitive. Even case-preserving filesystems
1300 do not distinguish case in drive letters. */
1301 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1307 if (NILP (Vw32_downcase_file_names
))
1311 if (*fp
== '/' || *fp
== '\\')
1318 sep
= path_sep
; /* convert to this path separator */
1319 elem
= fp
; /* start of current path element */
1322 if (*fp
>= 'a' && *fp
<= 'z')
1323 elem
= 0; /* don't convert this element */
1325 if (*fp
== 0 || *fp
== ':')
1327 sep
= *fp
; /* restore current separator (or 0) */
1328 *fp
= '/'; /* after conversion of this element */
1331 if (*fp
== '/' || *fp
== '\\')
1333 if (elem
&& elem
!= fp
)
1335 *fp
= 0; /* temporary end of string */
1336 _strlwr (elem
); /* while we convert to lower case */
1338 *fp
= sep
; /* convert (or restore) path separator */
1339 elem
= fp
+ 1; /* next element starts after separator */
1345 /* Destructively turn backslashes into slashes. */
1347 dostounix_filename (register char *p
)
1349 normalize_filename (p
, '/');
1352 /* Destructively turn slashes into backslashes. */
1354 unixtodos_filename (register char *p
)
1356 normalize_filename (p
, '\\');
1359 /* Remove all CR's that are followed by a LF.
1360 (From msdos.c...probably should figure out a way to share it,
1361 although this code isn't going to ever change.) */
1363 crlf_to_lf (register int n
, register unsigned char *buf
)
1365 unsigned char *np
= buf
;
1366 unsigned char *startp
= buf
;
1367 unsigned char *endp
= buf
+ n
;
1371 while (buf
< endp
- 1)
1375 if (*(++buf
) != 0x0a)
1386 /* Parse the root part of file name, if present. Return length and
1387 optionally store pointer to char after root. */
1389 parse_root (char * name
, char ** pPath
)
1391 char * start
= name
;
1396 /* find the root name of the volume if given */
1397 if (isalpha (name
[0]) && name
[1] == ':')
1399 /* skip past drive specifier */
1401 if (IS_DIRECTORY_SEP (name
[0]))
1404 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1410 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1415 if (IS_DIRECTORY_SEP (name
[0]))
1422 return name
- start
;
1425 /* Get long base name for name; name is assumed to be absolute. */
1427 get_long_basename (char * name
, char * buf
, int size
)
1429 WIN32_FIND_DATA find_data
;
1433 /* must be valid filename, no wild cards or other invalid characters */
1434 if (_mbspbrk (name
, "*?|<>\""))
1437 dir_handle
= FindFirstFile (name
, &find_data
);
1438 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1440 if ((len
= strlen (find_data
.cFileName
)) < size
)
1441 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1444 FindClose (dir_handle
);
1449 /* Get long name for file, if possible (assumed to be absolute). */
1451 w32_get_long_filename (char * name
, char * buf
, int size
)
1456 char full
[ MAX_PATH
];
1459 len
= strlen (name
);
1460 if (len
>= MAX_PATH
)
1463 /* Use local copy for destructive modification. */
1464 memcpy (full
, name
, len
+1);
1465 unixtodos_filename (full
);
1467 /* Copy root part verbatim. */
1468 len
= parse_root (full
, &p
);
1469 memcpy (o
, full
, len
);
1474 while (p
!= NULL
&& *p
)
1477 p
= strchr (q
, '\\');
1479 len
= get_long_basename (full
, o
, size
);
1502 is_unc_volume (const char *filename
)
1504 const char *ptr
= filename
;
1506 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1509 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1515 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1518 sigsetmask (int signal_mask
)
1536 sigunblock (int sig
)
1542 sigemptyset (sigset_t
*set
)
1548 sigaddset (sigset_t
*set
, int signo
)
1554 sigfillset (sigset_t
*set
)
1560 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1566 pthread_sigmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1568 if (sigprocmask (how
, set
, oset
) == -1)
1574 setpgrp (int pid
, int gid
)
1585 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1588 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1591 HKEY hrootkey
= NULL
;
1594 /* Check both the current user and the local machine to see if
1595 we have any resources. */
1597 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1601 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1602 && (lpvalue
= xmalloc (cbData
)) != NULL
1603 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1605 RegCloseKey (hrootkey
);
1611 RegCloseKey (hrootkey
);
1614 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1618 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1619 && (lpvalue
= xmalloc (cbData
)) != NULL
1620 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1622 RegCloseKey (hrootkey
);
1628 RegCloseKey (hrootkey
);
1634 char *get_emacs_configuration (void);
1637 init_environment (char ** argv
)
1639 static const char * const tempdirs
[] = {
1640 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1645 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1647 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1648 temporary files and assume "/tmp" if $TMPDIR is unset, which
1649 will break on DOS/Windows. Refuse to work if we cannot find
1650 a directory, not even "c:/", usable for that purpose. */
1651 for (i
= 0; i
< imax
; i
++)
1653 const char *tmp
= tempdirs
[i
];
1656 tmp
= getenv (tmp
+ 1);
1657 /* Note that `access' can lie to us if the directory resides on a
1658 read-only filesystem, like CD-ROM or a write-protected floppy.
1659 The only way to be really sure is to actually create a file and
1660 see if it succeeds. But I think that's too much to ask. */
1662 /* MSVCRT's _access crashes with D_OK. */
1663 if (tmp
&& sys_access (tmp
, D_OK
) == 0)
1665 char * var
= alloca (strlen (tmp
) + 8);
1666 sprintf (var
, "TMPDIR=%s", tmp
);
1667 _putenv (strdup (var
));
1674 Fcons (build_string ("no usable temporary directories found!!"),
1676 "While setting TMPDIR: ");
1678 /* Check for environment variables and use registry settings if they
1679 don't exist. Fallback on default values where applicable. */
1684 char locale_name
[32];
1685 struct stat ignored
;
1686 char default_home
[MAX_PATH
];
1689 static const struct env_entry
1695 /* If the default value is NULL, we will use the value from the
1696 outside environment or the Registry, but will not push the
1697 variable into the Emacs environment if it is defined neither
1698 in the Registry nor in the outside environment. */
1700 {"PRELOAD_WINSOCK", NULL
},
1701 {"emacs_dir", "C:/emacs"},
1702 {"EMACSLOADPATH", NULL
},
1703 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1704 {"EMACSDATA", NULL
},
1705 {"EMACSPATH", NULL
},
1712 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1714 /* We need to copy dflt_envvars[] and work on the copy because we
1715 don't want the dumped Emacs to inherit the values of
1716 environment variables we saw during dumping (which could be on
1717 a different system). The defaults above must be left intact. */
1718 struct env_entry env_vars
[N_ENV_VARS
];
1720 for (i
= 0; i
< N_ENV_VARS
; i
++)
1721 env_vars
[i
] = dflt_envvars
[i
];
1723 /* For backwards compatibility, check if a .emacs file exists in C:/
1724 If not, then we can try to default to the appdata directory under the
1725 user's profile, which is more likely to be writable. */
1726 if (stat ("C:/.emacs", &ignored
) < 0)
1728 HRESULT profile_result
;
1729 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1730 of Windows 95 and NT4 that have not been updated to include
1732 ShGetFolderPath_fn get_folder_path
;
1733 get_folder_path
= (ShGetFolderPath_fn
)
1734 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1736 if (get_folder_path
!= NULL
)
1738 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1741 /* If we can't get the appdata dir, revert to old behavior. */
1742 if (profile_result
== S_OK
)
1744 env_vars
[0].def_value
= default_home
;
1750 /* Get default locale info and use it for LANG. */
1751 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1752 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1753 locale_name
, sizeof (locale_name
)))
1755 for (i
= 0; i
< N_ENV_VARS
; i
++)
1757 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1759 env_vars
[i
].def_value
= locale_name
;
1765 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1767 /* Treat emacs_dir specially: set it unconditionally based on our
1771 char modname
[MAX_PATH
];
1773 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1775 if ((p
= strrchr (modname
, '\\')) == NULL
)
1779 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1781 char buf
[SET_ENV_BUF_SIZE
];
1784 for (p
= modname
; *p
; p
++)
1785 if (*p
== '\\') *p
= '/';
1787 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1788 _putenv (strdup (buf
));
1790 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1792 /* FIXME: should use substring of get_emacs_configuration ().
1793 But I don't think the Windows build supports alpha, mips etc
1794 anymore, so have taken the easy option for now. */
1795 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1798 p
= strrchr (modname
, '\\');
1802 p
= strrchr (modname
, '\\');
1803 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1805 char buf
[SET_ENV_BUF_SIZE
];
1808 for (p
= modname
; *p
; p
++)
1809 if (*p
== '\\') *p
= '/';
1811 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1812 _putenv (strdup (buf
));
1818 for (i
= 0; i
< N_ENV_VARS
; i
++)
1820 if (!getenv (env_vars
[i
].name
))
1824 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1825 /* Also ignore empty environment variables. */
1829 lpval
= env_vars
[i
].def_value
;
1830 dwType
= REG_EXPAND_SZ
;
1832 if (!strcmp (env_vars
[i
].name
, "HOME") && !appdata
)
1833 Vdelayed_warnings_list
1834 = Fcons (listn (CONSTYPE_HEAP
, 2,
1835 intern ("initialization"),
1836 build_string ("Setting HOME to C:\\ by default is deprecated")),
1837 Vdelayed_warnings_list
);
1842 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1844 if (dwType
== REG_EXPAND_SZ
)
1845 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1846 else if (dwType
== REG_SZ
)
1847 strcpy (buf1
, lpval
);
1848 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1850 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1852 _putenv (strdup (buf2
));
1862 /* Rebuild system configuration to reflect invoking system. */
1863 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1865 /* Another special case: on NT, the PATH variable is actually named
1866 "Path" although cmd.exe (perhaps NT itself) arranges for
1867 environment variable lookup and setting to be case insensitive.
1868 However, Emacs assumes a fully case sensitive environment, so we
1869 need to change "Path" to "PATH" to match the expectations of
1870 various elisp packages. We do this by the sneaky method of
1871 modifying the string in the C runtime environ entry.
1873 The same applies to COMSPEC. */
1877 for (envp
= environ
; *envp
; envp
++)
1878 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1879 memcpy (*envp
, "PATH=", 5);
1880 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1881 memcpy (*envp
, "COMSPEC=", 8);
1884 /* Remember the initial working directory for getwd. */
1885 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
1886 Does it matter anywhere in Emacs? */
1887 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1891 static char modname
[MAX_PATH
];
1893 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1898 /* Determine if there is a middle mouse button, to allow parse_button
1899 to decide whether right mouse events should be mouse-2 or
1901 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1906 /* Called from expand-file-name when default-directory is not a string. */
1909 emacs_root_dir (void)
1911 static char root_dir
[FILENAME_MAX
];
1914 p
= getenv ("emacs_dir");
1917 strcpy (root_dir
, p
);
1918 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1919 dostounix_filename (root_dir
);
1923 /* We don't have scripts to automatically determine the system configuration
1924 for Emacs before it's compiled, and we don't want to have to make the
1925 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1929 get_emacs_configuration (void)
1931 char *arch
, *oem
, *os
;
1933 static char configuration_buffer
[32];
1935 /* Determine the processor type. */
1936 switch (get_processor_type ())
1939 #ifdef PROCESSOR_INTEL_386
1940 case PROCESSOR_INTEL_386
:
1941 case PROCESSOR_INTEL_486
:
1942 case PROCESSOR_INTEL_PENTIUM
:
1947 #ifdef PROCESSOR_MIPS_R2000
1948 case PROCESSOR_MIPS_R2000
:
1949 case PROCESSOR_MIPS_R3000
:
1950 case PROCESSOR_MIPS_R4000
:
1955 #ifdef PROCESSOR_ALPHA_21064
1956 case PROCESSOR_ALPHA_21064
:
1966 /* Use the OEM field to reflect the compiler/library combination. */
1968 #define COMPILER_NAME "msvc"
1971 #define COMPILER_NAME "mingw"
1973 #define COMPILER_NAME "unknown"
1976 oem
= COMPILER_NAME
;
1978 switch (osinfo_cache
.dwPlatformId
) {
1979 case VER_PLATFORM_WIN32_NT
:
1981 build_num
= osinfo_cache
.dwBuildNumber
;
1983 case VER_PLATFORM_WIN32_WINDOWS
:
1984 if (osinfo_cache
.dwMinorVersion
== 0) {
1989 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1991 case VER_PLATFORM_WIN32s
:
1992 /* Not supported, should not happen. */
1994 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
2002 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
2003 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
2004 get_w32_major_version (), get_w32_minor_version (), build_num
);
2006 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
2009 return configuration_buffer
;
2013 get_emacs_configuration_options (void)
2015 static char *options_buffer
;
2016 char cv
[32]; /* Enough for COMPILER_VERSION. */
2018 cv
, /* To be filled later. */
2022 #ifdef ENABLE_CHECKING
2023 " --enable-checking",
2025 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2026 with a starting space to save work here. */
2028 " --cflags", USER_CFLAGS
,
2031 " --ldflags", USER_LDFLAGS
,
2038 /* Work out the effective configure options for this build. */
2040 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2043 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2045 #define COMPILER_VERSION ""
2049 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
2050 return "Error: not enough space for compiler version";
2051 cv
[sizeof (cv
) - 1] = '\0';
2053 for (i
= 0; options
[i
]; i
++)
2054 size
+= strlen (options
[i
]);
2056 options_buffer
= xmalloc (size
+ 1);
2057 options_buffer
[0] = '\0';
2059 for (i
= 0; options
[i
]; i
++)
2060 strcat (options_buffer
, options
[i
]);
2062 return options_buffer
;
2066 #include <sys/timeb.h>
2068 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2070 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
2075 tv
->tv_sec
= tb
.time
;
2076 tv
->tv_usec
= tb
.millitm
* 1000L;
2077 /* Implementation note: _ftime sometimes doesn't update the dstflag
2078 according to the new timezone when the system timezone is
2079 changed. We could fix that by using GetSystemTime and
2080 GetTimeZoneInformation, but that doesn't seem necessary, since
2081 Emacs always calls gettimeofday with the 2nd argument NULL (see
2082 current_emacs_time). */
2085 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
2086 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
2090 /* Emulate fdutimens. */
2092 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2093 TIMESPEC[0] and TIMESPEC[1], respectively.
2094 FD must be either negative -- in which case it is ignored --
2095 or a file descriptor that is open on FILE.
2096 If FD is nonnegative, then FILE can be NULL, which means
2097 use just futimes instead of utimes.
2098 If TIMESPEC is null, FAIL.
2099 Return 0 on success, -1 (setting errno) on failure. */
2102 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
2111 if (fd
< 0 && !file
)
2116 ut
.actime
= timespec
[0].tv_sec
;
2117 ut
.modtime
= timespec
[1].tv_sec
;
2119 return _futime (fd
, &ut
);
2121 return _utime (file
, &ut
);
2125 /* ------------------------------------------------------------------------- */
2126 /* IO support and wrapper functions for the Windows API. */
2127 /* ------------------------------------------------------------------------- */
2129 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2130 on network directories, so we handle that case here.
2131 (Ulrich Leodolter, 1/11/95). */
2133 sys_ctime (const time_t *t
)
2135 char *str
= (char *) ctime (t
);
2136 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2139 /* Emulate sleep...we could have done this with a define, but that
2140 would necessitate including windows.h in the files that used it.
2141 This is much easier. */
2143 sys_sleep (int seconds
)
2145 Sleep (seconds
* 1000);
2148 /* Internal MSVC functions for low-level descriptor munging */
2149 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2150 extern int __cdecl
_free_osfhnd (int fd
);
2152 /* parallel array of private info on file handles */
2153 filedesc fd_info
[ MAXDESC
];
2155 typedef struct volume_info_data
{
2156 struct volume_info_data
* next
;
2158 /* time when info was obtained */
2161 /* actual volume info */
2170 /* Global referenced by various functions. */
2171 static volume_info_data volume_info
;
2173 /* Vector to indicate which drives are local and fixed (for which cached
2174 data never expires). */
2175 static BOOL fixed_drives
[26];
2177 /* Consider cached volume information to be stale if older than 10s,
2178 at least for non-local drives. Info for fixed drives is never stale. */
2179 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2180 #define VOLINFO_STILL_VALID( root_dir, info ) \
2181 ( ( isalpha (root_dir[0]) && \
2182 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2183 || GetTickCount () - info->timestamp < 10000 )
2185 /* Cache support functions. */
2187 /* Simple linked list with linear search is sufficient. */
2188 static volume_info_data
*volume_cache
= NULL
;
2190 static volume_info_data
*
2191 lookup_volume_info (char * root_dir
)
2193 volume_info_data
* info
;
2195 for (info
= volume_cache
; info
; info
= info
->next
)
2196 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2202 add_volume_info (char * root_dir
, volume_info_data
* info
)
2204 info
->root_dir
= xstrdup (root_dir
);
2205 info
->next
= volume_cache
;
2206 volume_cache
= info
;
2210 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2211 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2212 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2213 static volume_info_data
*
2214 GetCachedVolumeInformation (char * root_dir
)
2216 volume_info_data
* info
;
2217 char default_root
[ MAX_PATH
];
2219 /* NULL for root_dir means use root from current directory. */
2220 if (root_dir
== NULL
)
2222 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2224 parse_root (default_root
, &root_dir
);
2226 root_dir
= default_root
;
2229 /* Local fixed drives can be cached permanently. Removable drives
2230 cannot be cached permanently, since the volume name and serial
2231 number (if nothing else) can change. Remote drives should be
2232 treated as if they are removable, since there is no sure way to
2233 tell whether they are or not. Also, the UNC association of drive
2234 letters mapped to remote volumes can be changed at any time (even
2235 by other processes) without notice.
2237 As a compromise, so we can benefit from caching info for remote
2238 volumes, we use a simple expiry mechanism to invalidate cache
2239 entries that are more than ten seconds old. */
2242 /* No point doing this, because WNetGetConnection is even slower than
2243 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2244 GetDriveType is about the only call of this type which does not
2245 involve network access, and so is extremely quick). */
2247 /* Map drive letter to UNC if remote. */
2248 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2250 char remote_name
[ 256 ];
2251 char drive
[3] = { root_dir
[0], ':' };
2253 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2255 /* do something */ ;
2259 info
= lookup_volume_info (root_dir
);
2261 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2269 /* Info is not cached, or is stale. */
2270 if (!GetVolumeInformation (root_dir
,
2271 name
, sizeof (name
),
2275 type
, sizeof (type
)))
2278 /* Cache the volume information for future use, overwriting existing
2279 entry if present. */
2282 info
= xmalloc (sizeof (volume_info_data
));
2283 add_volume_info (root_dir
, info
);
2291 info
->name
= xstrdup (name
);
2292 info
->serialnum
= serialnum
;
2293 info
->maxcomp
= maxcomp
;
2294 info
->flags
= flags
;
2295 info
->type
= xstrdup (type
);
2296 info
->timestamp
= GetTickCount ();
2302 /* Get information on the volume where NAME is held; set path pointer to
2303 start of pathname in NAME (past UNC header\volume header if present),
2304 if pPath is non-NULL.
2306 Note: if NAME includes symlinks, the information is for the volume
2307 of the symlink, not of its target. That's because, even though
2308 GetVolumeInformation returns information about the symlink target
2309 of its argument, we only pass the root directory to
2310 GetVolumeInformation, not the full NAME. */
2312 get_volume_info (const char * name
, const char ** pPath
)
2314 char temp
[MAX_PATH
];
2315 char *rootname
= NULL
; /* default to current volume */
2316 volume_info_data
* info
;
2321 /* Find the root name of the volume if given. */
2322 if (isalpha (name
[0]) && name
[1] == ':')
2330 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2337 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2350 info
= GetCachedVolumeInformation (rootname
);
2353 /* Set global referenced by other functions. */
2354 volume_info
= *info
;
2360 /* Determine if volume is FAT format (ie. only supports short 8.3
2361 names); also set path pointer to start of pathname in name, if
2362 pPath is non-NULL. */
2364 is_fat_volume (const char * name
, const char ** pPath
)
2366 if (get_volume_info (name
, pPath
))
2367 return (volume_info
.maxcomp
== 12);
2371 /* Map filename to a valid 8.3 name if necessary.
2372 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2374 map_w32_filename (const char * name
, const char ** pPath
)
2376 static char shortname
[MAX_PATH
];
2377 char * str
= shortname
;
2380 const char * save_name
= name
;
2382 if (strlen (name
) >= MAX_PATH
)
2384 /* Return a filename which will cause callers to fail. */
2385 strcpy (shortname
, "?");
2389 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2391 register int left
= 8; /* maximum number of chars in part */
2392 register int extn
= 0; /* extension added? */
2393 register int dots
= 2; /* maximum number of dots allowed */
2396 *str
++ = *name
++; /* skip past UNC header */
2398 while ((c
= *name
++))
2405 *str
++ = (c
== ':' ? ':' : '\\');
2406 extn
= 0; /* reset extension flags */
2407 dots
= 2; /* max 2 dots */
2408 left
= 8; /* max length 8 for main part */
2413 /* Convert path components of the form .xxx to _xxx,
2414 but leave . and .. as they are. This allows .emacs
2415 to be read as _emacs, for example. */
2419 IS_DIRECTORY_SEP (*name
))
2434 extn
= 1; /* we've got an extension */
2435 left
= 3; /* 3 chars in extension */
2439 /* any embedded dots after the first are converted to _ */
2444 case '#': /* don't lose these, they're important */
2446 str
[-1] = c
; /* replace last character of part */
2451 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2453 dots
= 0; /* started a path component */
2462 strcpy (shortname
, name
);
2463 unixtodos_filename (shortname
);
2467 *pPath
= shortname
+ (path
- save_name
);
2473 is_exec (const char * name
)
2475 char * p
= strrchr (name
, '.');
2478 && (xstrcasecmp (p
, ".exe") == 0 ||
2479 xstrcasecmp (p
, ".com") == 0 ||
2480 xstrcasecmp (p
, ".bat") == 0 ||
2481 xstrcasecmp (p
, ".cmd") == 0));
2484 /* Emulate the Unix directory procedures opendir, closedir,
2485 and readdir. We can't use the procedures supplied in sysdep.c,
2486 so we provide them here. */
2488 struct direct dir_static
; /* simulated directory contents */
2489 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2490 static int dir_is_fat
;
2491 static char dir_pathname
[MAXPATHLEN
+1];
2492 static WIN32_FIND_DATA dir_find_data
;
2494 /* Support shares on a network resource as subdirectories of a read-only
2496 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2497 static HANDLE
open_unc_volume (const char *);
2498 static char *read_unc_volume (HANDLE
, char *, int);
2499 static void close_unc_volume (HANDLE
);
2502 opendir (char *filename
)
2506 /* Opening is done by FindFirstFile. However, a read is inherent to
2507 this operation, so we defer the open until read time. */
2509 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2511 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2514 /* Note: We don't support traversal of UNC volumes via symlinks.
2515 Doing so would mean punishing 99.99% of use cases by resolving
2516 all the possible symlinks in FILENAME, recursively. */
2517 if (is_unc_volume (filename
))
2519 wnet_enum_handle
= open_unc_volume (filename
);
2520 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2524 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2531 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2532 dir_pathname
[MAXPATHLEN
] = '\0';
2533 /* Note: We don't support symlinks to file names on FAT volumes.
2534 Doing so would mean punishing 99.99% of use cases by resolving
2535 all the possible symlinks in FILENAME, recursively. */
2536 dir_is_fat
= is_fat_volume (filename
, NULL
);
2542 closedir (DIR *dirp
)
2544 /* If we have a find-handle open, close it. */
2545 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2547 FindClose (dir_find_handle
);
2548 dir_find_handle
= INVALID_HANDLE_VALUE
;
2550 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2552 close_unc_volume (wnet_enum_handle
);
2553 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2555 xfree ((char *) dirp
);
2561 int downcase
= !NILP (Vw32_downcase_file_names
);
2563 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2565 if (!read_unc_volume (wnet_enum_handle
,
2566 dir_find_data
.cFileName
,
2570 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2571 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2573 char filename
[MAXNAMLEN
+ 3];
2576 strcpy (filename
, dir_pathname
);
2577 ln
= strlen (filename
) - 1;
2578 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2579 strcat (filename
, "\\");
2580 strcat (filename
, "*");
2582 /* Note: No need to resolve symlinks in FILENAME, because
2583 FindFirst opens the directory that is the target of a
2585 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2587 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2592 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2596 /* Emacs never uses this value, so don't bother making it match
2597 value returned by stat(). */
2598 dir_static
.d_ino
= 1;
2600 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2602 /* If the file name in cFileName[] includes `?' characters, it means
2603 the original file name used characters that cannot be represented
2604 by the current ANSI codepage. To avoid total lossage, retrieve
2605 the short 8+3 alias of the long file name. */
2606 if (_mbspbrk (dir_static
.d_name
, "?"))
2608 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2609 downcase
= 1; /* 8+3 aliases are returned in all caps */
2611 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2612 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2613 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2615 /* If the file name in cFileName[] includes `?' characters, it means
2616 the original file name used characters that cannot be represented
2617 by the current ANSI codepage. To avoid total lossage, retrieve
2618 the short 8+3 alias of the long file name. */
2619 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2621 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2622 /* 8+3 aliases are returned in all caps, which could break
2623 various alists that look at filenames' extensions. */
2627 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2628 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2630 _strlwr (dir_static
.d_name
);
2634 for (p
= dir_static
.d_name
; *p
; p
++)
2635 if (*p
>= 'a' && *p
<= 'z')
2638 _strlwr (dir_static
.d_name
);
2645 open_unc_volume (const char *path
)
2651 nr
.dwScope
= RESOURCE_GLOBALNET
;
2652 nr
.dwType
= RESOURCETYPE_DISK
;
2653 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2654 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2655 nr
.lpLocalName
= NULL
;
2656 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2657 nr
.lpComment
= NULL
;
2658 nr
.lpProvider
= NULL
;
2660 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2661 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2663 if (result
== NO_ERROR
)
2666 return INVALID_HANDLE_VALUE
;
2670 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2674 DWORD bufsize
= 512;
2679 buffer
= alloca (bufsize
);
2680 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
2681 if (result
!= NO_ERROR
)
2684 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2685 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2687 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2690 strncpy (readbuf
, ptr
, size
);
2695 close_unc_volume (HANDLE henum
)
2697 if (henum
!= INVALID_HANDLE_VALUE
)
2698 WNetCloseEnum (henum
);
2702 unc_volume_file_attributes (const char *path
)
2707 henum
= open_unc_volume (path
);
2708 if (henum
== INVALID_HANDLE_VALUE
)
2711 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2713 close_unc_volume (henum
);
2718 /* Ensure a network connection is authenticated. */
2720 logon_network_drive (const char *path
)
2722 NETRESOURCE resource
;
2723 char share
[MAX_PATH
];
2728 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2729 drvtype
= DRIVE_REMOTE
;
2730 else if (path
[0] == '\0' || path
[1] != ':')
2731 drvtype
= GetDriveType (NULL
);
2738 drvtype
= GetDriveType (drive
);
2741 /* Only logon to networked drives. */
2742 if (drvtype
!= DRIVE_REMOTE
)
2746 strncpy (share
, path
, MAX_PATH
);
2747 /* Truncate to just server and share name. */
2748 for (i
= 2; i
< MAX_PATH
; i
++)
2750 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2757 resource
.dwType
= RESOURCETYPE_DISK
;
2758 resource
.lpLocalName
= NULL
;
2759 resource
.lpRemoteName
= share
;
2760 resource
.lpProvider
= NULL
;
2762 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2765 /* Shadow some MSVC runtime functions to map requests for long filenames
2766 to reasonable short names if necessary. This was originally added to
2767 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2771 sys_access (const char * path
, int mode
)
2775 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
2776 newer versions blow up when passed D_OK. */
2777 path
= map_w32_filename (path
, NULL
);
2778 /* If the last element of PATH is a symlink, we need to resolve it
2779 to get the attributes of its target file. Note: any symlinks in
2780 PATH elements other than the last one are transparently resolved
2781 by GetFileAttributes below. */
2782 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
2783 path
= chase_symlinks (path
);
2785 if ((attributes
= GetFileAttributes (path
)) == -1)
2787 DWORD w32err
= GetLastError ();
2791 case ERROR_INVALID_NAME
:
2792 case ERROR_BAD_PATHNAME
:
2793 if (is_unc_volume (path
))
2795 attributes
= unc_volume_file_attributes (path
);
2796 if (attributes
== -1)
2804 case ERROR_FILE_NOT_FOUND
:
2805 case ERROR_BAD_NETPATH
:
2814 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2819 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2824 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2833 sys_chdir (const char * path
)
2835 return _chdir (map_w32_filename (path
, NULL
));
2839 sys_chmod (const char * path
, int mode
)
2841 path
= chase_symlinks (map_w32_filename (path
, NULL
));
2842 return _chmod (path
, mode
);
2846 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2848 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2854 sys_creat (const char * path
, int mode
)
2856 return _creat (map_w32_filename (path
, NULL
), mode
);
2860 sys_fopen (const char * path
, const char * mode
)
2864 const char * mode_save
= mode
;
2866 /* Force all file handles to be non-inheritable. This is necessary to
2867 ensure child processes don't unwittingly inherit handles that might
2868 prevent future file access. */
2872 else if (mode
[0] == 'w' || mode
[0] == 'a')
2873 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2877 /* Only do simplistic option parsing. */
2881 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2884 else if (mode
[0] == 'b')
2889 else if (mode
[0] == 't')
2896 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2900 return _fdopen (fd
, mode_save
);
2903 /* This only works on NTFS volumes, but is useful to have. */
2905 sys_link (const char * old
, const char * new)
2909 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2911 if (old
== NULL
|| new == NULL
)
2917 strcpy (oldname
, map_w32_filename (old
, NULL
));
2918 strcpy (newname
, map_w32_filename (new, NULL
));
2920 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2921 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2922 if (fileh
!= INVALID_HANDLE_VALUE
)
2926 /* Confusingly, the "alternate" stream name field does not apply
2927 when restoring a hard link, and instead contains the actual
2928 stream data for the link (ie. the name of the link to create).
2929 The WIN32_STREAM_ID structure before the cStreamName field is
2930 the stream header, which is then immediately followed by the
2934 WIN32_STREAM_ID wid
;
2935 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2938 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2939 data
.wid
.cStreamName
, MAX_PATH
);
2942 LPVOID context
= NULL
;
2945 data
.wid
.dwStreamId
= BACKUP_LINK
;
2946 data
.wid
.dwStreamAttributes
= 0;
2947 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2948 data
.wid
.Size
.HighPart
= 0;
2949 data
.wid
.dwStreamNameSize
= 0;
2951 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2952 offsetof (WIN32_STREAM_ID
, cStreamName
)
2953 + data
.wid
.Size
.LowPart
,
2954 &wbytes
, FALSE
, FALSE
, &context
)
2955 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2962 /* Should try mapping GetLastError to errno; for now just
2963 indicate a general error (eg. links not supported). */
2964 errno
= EINVAL
; // perhaps EMLINK?
2968 CloseHandle (fileh
);
2977 sys_mkdir (const char * path
)
2979 return _mkdir (map_w32_filename (path
, NULL
));
2982 /* Because of long name mapping issues, we need to implement this
2983 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2984 a unique name, instead of setting the input template to an empty
2987 Standard algorithm seems to be use pid or tid with a letter on the
2988 front (in place of the 6 X's) and cycle through the letters to find a
2989 unique name. We extend that to allow any reasonable character as the
2990 first of the 6 X's. */
2992 sys_mktemp (char * template)
2996 unsigned uid
= GetCurrentThreadId ();
2997 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2999 if (template == NULL
)
3001 p
= template + strlen (template);
3003 /* replace up to the last 5 X's with uid in decimal */
3004 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
3006 p
[0] = '0' + uid
% 10;
3010 if (i
< 0 && p
[0] == 'X')
3015 int save_errno
= errno
;
3016 p
[0] = first_char
[i
];
3017 if (sys_access (template, 0) < 0)
3023 while (++i
< sizeof (first_char
));
3026 /* Template is badly formed or else we can't generate a unique name,
3027 so return empty string */
3033 sys_open (const char * path
, int oflag
, int mode
)
3035 const char* mpath
= map_w32_filename (path
, NULL
);
3036 /* Try to open file without _O_CREAT, to be able to write to hidden
3037 and system files. Force all file handles to be
3039 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3042 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
3046 sys_rename (const char * oldname
, const char * newname
)
3049 char temp
[MAX_PATH
];
3053 /* MoveFile on Windows 95 doesn't correctly change the short file name
3054 alias in a number of circumstances (it is not easy to predict when
3055 just by looking at oldname and newname, unfortunately). In these
3056 cases, renaming through a temporary name avoids the problem.
3058 A second problem on Windows 95 is that renaming through a temp name when
3059 newname is uppercase fails (the final long name ends up in
3060 lowercase, although the short alias might be uppercase) UNLESS the
3061 long temp name is not 8.3.
3063 So, on Windows 95 we always rename through a temp name, and we make sure
3064 the temp name has a long extension to ensure correct renaming. */
3066 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3068 /* volume_info is set indirectly by map_w32_filename. */
3069 oldname_dev
= volume_info
.serialnum
;
3071 if (os_subtype
== OS_9X
)
3077 oldname
= map_w32_filename (oldname
, NULL
);
3078 if ((o
= strrchr (oldname
, '\\')))
3081 o
= (char *) oldname
;
3083 if ((p
= strrchr (temp
, '\\')))
3090 /* Force temp name to require a manufactured 8.3 alias - this
3091 seems to make the second rename work properly. */
3092 sprintf (p
, "_.%s.%u", o
, i
);
3094 result
= rename (oldname
, temp
);
3096 /* This loop must surely terminate! */
3097 while (result
< 0 && errno
== EEXIST
);
3102 /* Emulate Unix behavior - newname is deleted if it already exists
3103 (at least if it is a file; don't do this for directories).
3105 Since we mustn't do this if we are just changing the case of the
3106 file name (we would end up deleting the file we are trying to
3107 rename!), we let rename detect if the destination file already
3108 exists - that way we avoid the possible pitfalls of trying to
3109 determine ourselves whether two names really refer to the same
3110 file, which is not always possible in the general case. (Consider
3111 all the permutations of shared or subst'd drives, etc.) */
3113 newname
= map_w32_filename (newname
, NULL
);
3115 /* volume_info is set indirectly by map_w32_filename. */
3116 newname_dev
= volume_info
.serialnum
;
3118 result
= rename (temp
, newname
);
3122 DWORD w32err
= GetLastError ();
3125 && newname_dev
!= oldname_dev
)
3127 /* The implementation of `rename' on Windows does not return
3128 errno = EXDEV when you are moving a directory to a
3129 different storage device (ex. logical disk). It returns
3130 EACCES instead. So here we handle such situations and
3134 if ((attributes
= GetFileAttributes (temp
)) != -1
3135 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3138 else if (errno
== EEXIST
)
3140 if (_chmod (newname
, 0666) != 0)
3142 if (_unlink (newname
) != 0)
3144 result
= rename (temp
, newname
);
3146 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
3147 && is_symlink (temp
))
3149 /* This is Windows prohibiting the user from creating a
3150 symlink in another place, since that requires
3160 sys_rmdir (const char * path
)
3162 return _rmdir (map_w32_filename (path
, NULL
));
3166 sys_unlink (const char * path
)
3168 path
= map_w32_filename (path
, NULL
);
3170 /* On Unix, unlink works without write permission. */
3171 _chmod (path
, 0666);
3172 return _unlink (path
);
3175 static FILETIME utc_base_ft
;
3176 static ULONGLONG utc_base
; /* In 100ns units */
3177 static int init
= 0;
3179 #define FILETIME_TO_U64(result, ft) \
3181 ULARGE_INTEGER uiTemp; \
3182 uiTemp.LowPart = (ft).dwLowDateTime; \
3183 uiTemp.HighPart = (ft).dwHighDateTime; \
3184 result = uiTemp.QuadPart; \
3188 initialize_utc_base (void)
3190 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3199 st
.wMilliseconds
= 0;
3201 SystemTimeToFileTime (&st
, &utc_base_ft
);
3202 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3206 convert_time (FILETIME ft
)
3212 initialize_utc_base ();
3216 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3219 FILETIME_TO_U64 (tmp
, ft
);
3220 return (time_t) ((tmp
- utc_base
) / 10000000L);
3224 convert_from_time_t (time_t time
, FILETIME
* pft
)
3230 initialize_utc_base ();
3234 /* time in 100ns units since 1-Jan-1601 */
3235 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3236 pft
->dwHighDateTime
= tmp
.HighPart
;
3237 pft
->dwLowDateTime
= tmp
.LowPart
;
3241 /* No reason to keep this; faking inode values either by hashing or even
3242 using the file index from GetInformationByHandle, is not perfect and
3243 so by default Emacs doesn't use the inode values on Windows.
3244 Instead, we now determine file-truename correctly (except for
3245 possible drive aliasing etc). */
3247 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3249 hashval (const unsigned char * str
)
3254 h
= (h
<< 4) + *str
++;
3260 /* Return the hash value of the canonical pathname, excluding the
3261 drive/UNC header, to get a hopefully unique inode number. */
3263 generate_inode_val (const char * name
)
3265 char fullname
[ MAX_PATH
];
3269 /* Get the truly canonical filename, if it exists. (Note: this
3270 doesn't resolve aliasing due to subst commands, or recognize hard
3272 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3275 parse_root (fullname
, &p
);
3276 /* Normal W32 filesystems are still case insensitive. */
3283 static PSECURITY_DESCRIPTOR
3284 get_file_security_desc_by_handle (HANDLE h
)
3286 PSECURITY_DESCRIPTOR psd
= NULL
;
3288 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3289 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3291 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
3292 NULL
, NULL
, NULL
, NULL
, &psd
);
3293 if (err
!= ERROR_SUCCESS
)
3299 static PSECURITY_DESCRIPTOR
3300 get_file_security_desc_by_name (const char *fname
)
3302 PSECURITY_DESCRIPTOR psd
= NULL
;
3304 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3305 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3307 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3309 err
= GetLastError ();
3310 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3314 psd
= xmalloc (sd_len
);
3315 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3327 unsigned n_subauthorities
;
3329 /* Use the last sub-authority value of the RID, the relative
3330 portion of the SID, as user/group ID. */
3331 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3332 if (n_subauthorities
< 1)
3333 return 0; /* the "World" RID */
3334 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3337 /* Caching SID and account values for faster lokup. */
3340 # define FLEXIBLE_ARRAY_MEMBER
3342 # define FLEXIBLE_ARRAY_MEMBER 1
3347 struct w32_id
*next
;
3349 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3352 static struct w32_id
*w32_idlist
;
3355 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3357 struct w32_id
*tail
, *found
;
3359 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3361 if (equal_sid ((PSID
)tail
->sid
, sid
))
3370 strcpy (name
, found
->name
);
3378 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3381 struct w32_id
*new_entry
;
3383 /* We don't want to leave behind stale cache from when Emacs was
3387 sid_len
= get_length_sid (sid
);
3388 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3391 new_entry
->rid
= id
;
3392 strcpy (new_entry
->name
, name
);
3393 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3394 new_entry
->next
= w32_idlist
;
3395 w32_idlist
= new_entry
;
3404 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3405 unsigned *id
, char *nm
, int what
)
3408 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3410 SID_NAME_USE ignore
;
3412 DWORD name_len
= sizeof (name
);
3414 DWORD domain_len
= sizeof (domain
);
3420 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3421 else if (what
== GID
)
3422 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3426 if (!result
|| !is_valid_sid (sid
))
3428 else if (!w32_cached_id (sid
, id
, nm
))
3430 /* If FNAME is a UNC, we need to lookup account on the
3431 specified machine. */
3432 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3433 && fname
[2] != '\0')
3438 for (s
= fname
+ 2, p
= machine
;
3439 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3445 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3446 domain
, &domain_len
, &ignore
)
3447 || name_len
> UNLEN
+1)
3451 *id
= get_rid (sid
);
3453 w32_add_to_cache (sid
, *id
, name
);
3460 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3464 int dflt_usr
= 0, dflt_grp
= 0;
3473 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3475 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3478 /* Consider files to belong to current user/group, if we cannot get
3479 more accurate information. */
3482 st
->st_uid
= dflt_passwd
.pw_uid
;
3483 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3487 st
->st_gid
= dflt_passwd
.pw_gid
;
3488 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3492 /* Return non-zero if NAME is a potentially slow filesystem. */
3494 is_slow_fs (const char *name
)
3499 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3500 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3501 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3502 devtype
= GetDriveType (NULL
); /* use root of current drive */
3505 /* GetDriveType needs the root directory of the drive. */
3506 strncpy (drive_root
, name
, 2);
3507 drive_root
[2] = '\\';
3508 drive_root
[3] = '\0';
3509 devtype
= GetDriveType (drive_root
);
3511 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3514 /* MSVC stat function can't cope with UNC names and has other bugs, so
3515 replace it with our own. This also allows us to calculate consistent
3516 inode values and owner/group without hacks in the main Emacs code. */
3519 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
3521 char *name
, *save_name
, *r
;
3522 WIN32_FIND_DATA wfd
;
3524 unsigned __int64 fake_inode
= 0;
3527 int rootdir
= FALSE
;
3528 PSECURITY_DESCRIPTOR psd
= NULL
;
3529 int is_a_symlink
= 0;
3530 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
3531 DWORD access_rights
= 0;
3532 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
3533 FILETIME ctime
, atime
, wtime
;
3535 if (path
== NULL
|| buf
== NULL
)
3541 save_name
= name
= (char *) map_w32_filename (path
, &path
);
3542 /* Must be valid filename, no wild cards or other invalid
3543 characters. We use _mbspbrk to support multibyte strings that
3544 might look to strpbrk as if they included literal *, ?, and other
3545 characters mentioned below that are disallowed by Windows
3547 if (_mbspbrk (name
, "*?|<>\""))
3553 /* Remove trailing directory separator, unless name is the root
3554 directory of a drive or UNC volume in which case ensure there
3555 is a trailing separator. */
3556 len
= strlen (name
);
3557 name
= strcpy (alloca (len
+ 2), name
);
3559 /* Avoid a somewhat costly call to is_symlink if the filesystem
3560 doesn't support symlinks. */
3561 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
3562 is_a_symlink
= is_symlink (name
);
3564 /* Plan A: Open the file and get all the necessary information via
3565 the resulting handle. This solves several issues in one blow:
3567 . retrieves attributes for the target of a symlink, if needed
3568 . gets attributes of root directories and symlinks pointing to
3569 root directories, thus avoiding the need for special-casing
3570 these and detecting them by examining the file-name format
3571 . retrieves more accurate attributes (e.g., non-zero size for
3572 some directories, esp. directories that are junction points)
3573 . correctly resolves "c:/..", "/.." and similar file names
3574 . avoids run-time penalties for 99% of use cases
3576 Plan A is always tried first, unless the user asked not to (but
3577 if the file is a symlink and we need to follow links, we try Plan
3578 A even if the user asked not to).
3580 If Plan A fails, we go to Plan B (below), where various
3581 potentially expensive techniques must be used to handle "special"
3582 files such as UNC volumes etc. */
3583 if (!(NILP (Vw32_get_true_file_attributes
)
3584 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3585 /* Following symlinks requires getting the info by handle. */
3586 || (is_a_symlink
&& follow_symlinks
))
3588 BY_HANDLE_FILE_INFORMATION info
;
3590 if (is_a_symlink
&& !follow_symlinks
)
3591 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
3592 /* READ_CONTROL access rights are required to get security info
3593 by handle. But if the OS doesn't support security in the
3594 first place, we don't need to try. */
3595 if (is_windows_9x () != TRUE
)
3596 access_rights
|= READ_CONTROL
;
3598 fh
= CreateFile (name
, access_rights
, 0, NULL
, OPEN_EXISTING
,
3600 /* If CreateFile fails with READ_CONTROL, try again with zero as
3602 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
3603 fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3605 if (fh
== INVALID_HANDLE_VALUE
)
3606 goto no_true_file_attributes
;
3608 /* This is more accurate in terms of getting the correct number
3609 of links, but is quite slow (it is noticeable when Emacs is
3610 making a list of file name completions). */
3611 if (GetFileInformationByHandle (fh
, &info
))
3613 nlinks
= info
.nNumberOfLinks
;
3614 /* Might as well use file index to fake inode values, but this
3615 is not guaranteed to be unique unless we keep a handle open
3616 all the time (even then there are situations where it is
3617 not unique). Reputedly, there are at most 48 bits of info
3618 (on NTFS, presumably less on FAT). */
3619 fake_inode
= info
.nFileIndexHigh
;
3621 fake_inode
+= info
.nFileIndexLow
;
3622 serialnum
= info
.dwVolumeSerialNumber
;
3623 fs_high
= info
.nFileSizeHigh
;
3624 fs_low
= info
.nFileSizeLow
;
3625 ctime
= info
.ftCreationTime
;
3626 atime
= info
.ftLastAccessTime
;
3627 wtime
= info
.ftLastWriteTime
;
3628 fattrs
= info
.dwFileAttributes
;
3632 /* We don't go to Plan B here, because it's not clear that
3633 it's a good idea. The only known use case where
3634 CreateFile succeeds, but GetFileInformationByHandle fails
3635 (with ERROR_INVALID_FUNCTION) is for character devices
3636 such as NUL, PRN, etc. For these, switching to Plan B is
3637 a net loss, because we lose the character device
3638 attribute returned by GetFileType below (FindFirstFile
3639 doesn't set that bit in the attributes), and the other
3640 fields don't make sense for character devices anyway.
3641 Emacs doesn't really care for non-file entities in the
3642 context of l?stat, so neither do we. */
3644 /* w32err is assigned so one could put a breakpoint here and
3645 examine its value, when GetFileInformationByHandle
3647 DWORD w32err
= GetLastError ();
3651 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
3657 /* Test for a symlink before testing for a directory, since
3658 symlinks to directories have the directory bit set, but we
3659 don't want them to appear as directories. */
3660 if (is_a_symlink
&& !follow_symlinks
)
3661 buf
->st_mode
= S_IFLNK
;
3662 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3663 buf
->st_mode
= S_IFDIR
;
3666 DWORD ftype
= GetFileType (fh
);
3670 case FILE_TYPE_DISK
:
3671 buf
->st_mode
= S_IFREG
;
3673 case FILE_TYPE_PIPE
:
3674 buf
->st_mode
= S_IFIFO
;
3676 case FILE_TYPE_CHAR
:
3677 case FILE_TYPE_UNKNOWN
:
3679 buf
->st_mode
= S_IFCHR
;
3682 /* We produce the fallback owner and group data, based on the
3683 current user that runs Emacs, in the following cases:
3685 . this is Windows 9X
3686 . getting security by handle failed, and we need to produce
3687 information for the target of a symlink (this is better
3688 than producing a potentially misleading info about the
3691 If getting security by handle fails, and we don't need to
3692 resolve symlinks, we try getting security by name. */
3693 if (is_windows_9x () != TRUE
)
3694 psd
= get_file_security_desc_by_handle (fh
);
3697 get_file_owner_and_group (psd
, name
, buf
);
3700 else if (is_windows_9x () == TRUE
)
3701 get_file_owner_and_group (NULL
, name
, buf
);
3702 else if (!(is_a_symlink
&& follow_symlinks
))
3704 psd
= get_file_security_desc_by_name (name
);
3705 get_file_owner_and_group (psd
, name
, buf
);
3709 get_file_owner_and_group (NULL
, name
, buf
);
3714 no_true_file_attributes
:
3715 /* Plan B: Either getting a handle on the file failed, or the
3716 caller explicitly asked us to not bother making this
3717 information more accurate.
3719 Implementation note: In Plan B, we never bother to resolve
3720 symlinks, even if we got here because we tried Plan A and
3721 failed. That's because, even if the caller asked for extra
3722 precision by setting Vw32_get_true_file_attributes to t,
3723 resolving symlinks requires acquiring a file handle to the
3724 symlink, which we already know will fail. And if the user
3725 did not ask for extra precision, resolving symlinks will fly
3726 in the face of that request, since the user then wants the
3727 lightweight version of the code. */
3728 rootdir
= (path
>= save_name
+ len
- 1
3729 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3731 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3732 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3733 if (IS_DIRECTORY_SEP (r
[0])
3734 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3737 /* Note: If NAME is a symlink to the root of a UNC volume
3738 (i.e. "\\SERVER"), we will not detect that here, and we will
3739 return data about the symlink as result of FindFirst below.
3740 This is unfortunate, but that marginal use case does not
3741 justify a call to chase_symlinks which would impose a penalty
3742 on all the other use cases. (We get here for symlinks to
3743 roots of UNC volumes because CreateFile above fails for them,
3744 unlike with symlinks to root directories X:\ of drives.) */
3745 if (is_unc_volume (name
))
3747 fattrs
= unc_volume_file_attributes (name
);
3751 ctime
= atime
= wtime
= utc_base_ft
;
3755 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3756 strcat (name
, "\\");
3757 if (GetDriveType (name
) < 2)
3763 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
3764 ctime
= atime
= wtime
= utc_base_ft
;
3768 if (IS_DIRECTORY_SEP (name
[len
-1]))
3771 /* (This is hacky, but helps when doing file completions on
3772 network drives.) Optimize by using information available from
3773 active readdir if possible. */
3774 len
= strlen (dir_pathname
);
3775 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3777 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3778 && !(is_a_symlink
&& follow_symlinks
)
3779 && strnicmp (save_name
, dir_pathname
, len
) == 0
3780 && IS_DIRECTORY_SEP (name
[len
])
3781 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3783 /* This was the last entry returned by readdir. */
3784 wfd
= dir_find_data
;
3788 logon_network_drive (name
);
3790 fh
= FindFirstFile (name
, &wfd
);
3791 if (fh
== INVALID_HANDLE_VALUE
)
3798 /* Note: if NAME is a symlink, the information we get from
3799 FindFirstFile is for the symlink, not its target. */
3800 fattrs
= wfd
.dwFileAttributes
;
3801 ctime
= wfd
.ftCreationTime
;
3802 atime
= wfd
.ftLastAccessTime
;
3803 wtime
= wfd
.ftLastWriteTime
;
3804 fs_high
= wfd
.nFileSizeHigh
;
3805 fs_low
= wfd
.nFileSizeLow
;
3808 serialnum
= volume_info
.serialnum
;
3810 if (is_a_symlink
&& !follow_symlinks
)
3811 buf
->st_mode
= S_IFLNK
;
3812 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3813 buf
->st_mode
= S_IFDIR
;
3815 buf
->st_mode
= S_IFREG
;
3817 get_file_owner_and_group (NULL
, name
, buf
);
3821 /* Not sure if there is any point in this. */
3822 if (!NILP (Vw32_generate_fake_inodes
))
3823 fake_inode
= generate_inode_val (name
);
3824 else if (fake_inode
== 0)
3826 /* For want of something better, try to make everything unique. */
3827 static DWORD gen_num
= 0;
3828 fake_inode
= ++gen_num
;
3832 buf
->st_ino
= fake_inode
;
3834 buf
->st_dev
= serialnum
;
3835 buf
->st_rdev
= serialnum
;
3837 buf
->st_size
= fs_high
;
3838 buf
->st_size
<<= 32;
3839 buf
->st_size
+= fs_low
;
3840 buf
->st_nlink
= nlinks
;
3842 /* Convert timestamps to Unix format. */
3843 buf
->st_mtime
= convert_time (wtime
);
3844 buf
->st_atime
= convert_time (atime
);
3845 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3846 buf
->st_ctime
= convert_time (ctime
);
3847 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3849 /* determine rwx permissions */
3850 if (is_a_symlink
&& !follow_symlinks
)
3851 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
3854 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
3855 permission
= S_IREAD
;
3857 permission
= S_IREAD
| S_IWRITE
;
3859 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3860 permission
|= S_IEXEC
;
3861 else if (is_exec (name
))
3862 permission
|= S_IEXEC
;
3865 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3871 stat (const char * path
, struct stat
* buf
)
3873 return stat_worker (path
, buf
, 1);
3877 lstat (const char * path
, struct stat
* buf
)
3879 return stat_worker (path
, buf
, 0);
3882 /* Provide fstat and utime as well as stat for consistent handling of
3885 fstat (int desc
, struct stat
* buf
)
3887 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3888 BY_HANDLE_FILE_INFORMATION info
;
3889 unsigned __int64 fake_inode
;
3892 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3894 case FILE_TYPE_DISK
:
3895 buf
->st_mode
= S_IFREG
;
3896 if (!GetFileInformationByHandle (fh
, &info
))
3902 case FILE_TYPE_PIPE
:
3903 buf
->st_mode
= S_IFIFO
;
3905 case FILE_TYPE_CHAR
:
3906 case FILE_TYPE_UNKNOWN
:
3908 buf
->st_mode
= S_IFCHR
;
3910 memset (&info
, 0, sizeof (info
));
3911 info
.dwFileAttributes
= 0;
3912 info
.ftCreationTime
= utc_base_ft
;
3913 info
.ftLastAccessTime
= utc_base_ft
;
3914 info
.ftLastWriteTime
= utc_base_ft
;
3917 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3918 buf
->st_mode
= S_IFDIR
;
3920 buf
->st_nlink
= info
.nNumberOfLinks
;
3921 /* Might as well use file index to fake inode values, but this
3922 is not guaranteed to be unique unless we keep a handle open
3923 all the time (even then there are situations where it is
3924 not unique). Reputedly, there are at most 48 bits of info
3925 (on NTFS, presumably less on FAT). */
3926 fake_inode
= info
.nFileIndexHigh
;
3928 fake_inode
+= info
.nFileIndexLow
;
3930 /* MSVC defines _ino_t to be short; other libc's might not. */
3931 if (sizeof (buf
->st_ino
) == 2)
3932 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3934 buf
->st_ino
= fake_inode
;
3936 /* Consider files to belong to current user.
3937 FIXME: this should use GetSecurityInfo API, but it is only
3938 available for _WIN32_WINNT >= 0x501. */
3939 buf
->st_uid
= dflt_passwd
.pw_uid
;
3940 buf
->st_gid
= dflt_passwd
.pw_gid
;
3941 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3942 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3944 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3945 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3947 buf
->st_size
= info
.nFileSizeHigh
;
3948 buf
->st_size
<<= 32;
3949 buf
->st_size
+= info
.nFileSizeLow
;
3951 /* Convert timestamps to Unix format. */
3952 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3953 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3954 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3955 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3956 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3958 /* determine rwx permissions */
3959 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3960 permission
= S_IREAD
;
3962 permission
= S_IREAD
| S_IWRITE
;
3964 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3965 permission
|= S_IEXEC
;
3968 #if 0 /* no way of knowing the filename */
3969 char * p
= strrchr (name
, '.');
3971 (xstrcasecmp (p
, ".exe") == 0 ||
3972 xstrcasecmp (p
, ".com") == 0 ||
3973 xstrcasecmp (p
, ".bat") == 0 ||
3974 xstrcasecmp (p
, ".cmd") == 0))
3975 permission
|= S_IEXEC
;
3979 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3985 utime (const char *name
, struct utimbuf
*times
)
3987 struct utimbuf deftime
;
3994 deftime
.modtime
= deftime
.actime
= time (NULL
);
3998 /* Need write access to set times. */
3999 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
4000 0, OPEN_EXISTING
, 0, NULL
);
4003 convert_from_time_t (times
->actime
, &atime
);
4004 convert_from_time_t (times
->modtime
, &mtime
);
4005 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
4022 /* Symlink-related functions. */
4023 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4024 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4028 symlink (char const *filename
, char const *linkname
)
4030 char linkfn
[MAX_PATH
], *tgtfn
;
4032 int dir_access
, filename_ends_in_slash
;
4034 /* Diagnostics follows Posix as much as possible. */
4035 if (filename
== NULL
|| linkname
== NULL
)
4045 if (strlen (filename
) > MAX_PATH
|| strlen (linkname
) > MAX_PATH
)
4047 errno
= ENAMETOOLONG
;
4051 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
4052 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
4058 /* Note: since empty FILENAME was already rejected, we can safely
4059 refer to FILENAME[1]. */
4060 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
4062 /* Non-absolute FILENAME is understood as being relative to
4063 LINKNAME's directory. We need to prepend that directory to
4064 FILENAME to get correct results from sys_access below, since
4065 otherwise it will interpret FILENAME relative to the
4066 directory where the Emacs process runs. Note that
4067 make-symbolic-link always makes sure LINKNAME is a fully
4068 expanded file name. */
4070 char *p
= linkfn
+ strlen (linkfn
);
4072 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
4075 strncpy (tem
, linkfn
, p
- linkfn
);
4076 tem
[p
- linkfn
] = '\0';
4077 strcat (tem
, filename
);
4078 dir_access
= sys_access (tem
, D_OK
);
4081 dir_access
= sys_access (filename
, D_OK
);
4083 /* Since Windows distinguishes between symlinks to directories and
4084 to files, we provide a kludgy feature: if FILENAME doesn't
4085 exist, but ends in a slash, we create a symlink to directory. If
4086 FILENAME exists and is a directory, we always create a symlink to
4088 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
4089 if (dir_access
== 0 || filename_ends_in_slash
)
4090 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
4092 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
4093 if (filename_ends_in_slash
)
4094 tgtfn
[strlen (tgtfn
) - 1] = '\0';
4097 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
4099 /* ENOSYS is set by create_symbolic_link, when it detects that
4100 the OS doesn't support the CreateSymbolicLink API. */
4101 if (errno
!= ENOSYS
)
4103 DWORD w32err
= GetLastError ();
4107 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4108 TGTFN point to the same file name, go figure. */
4110 case ERROR_FILE_EXISTS
:
4113 case ERROR_ACCESS_DENIED
:
4116 case ERROR_FILE_NOT_FOUND
:
4117 case ERROR_PATH_NOT_FOUND
:
4118 case ERROR_BAD_NETPATH
:
4119 case ERROR_INVALID_REPARSE_DATA
:
4122 case ERROR_DIRECTORY
:
4125 case ERROR_PRIVILEGE_NOT_HELD
:
4126 case ERROR_NOT_ALL_ASSIGNED
:
4129 case ERROR_DISK_FULL
:
4142 /* A quick inexpensive test of whether FILENAME identifies a file that
4143 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4144 must already be in the normalized form returned by
4147 Note: for repeated operations on many files, it is best to test
4148 whether the underlying volume actually supports symlinks, by
4149 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4150 avoid the call to this function if it doesn't. That's because the
4151 call to GetFileAttributes takes a non-negligible time, especially
4152 on non-local or removable filesystems. See stat_worker for an
4153 example of how to do that. */
4155 is_symlink (const char *filename
)
4158 WIN32_FIND_DATA wfd
;
4161 attrs
= GetFileAttributes (filename
);
4164 DWORD w32err
= GetLastError ();
4168 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
4170 case ERROR_ACCESS_DENIED
:
4173 case ERROR_FILE_NOT_FOUND
:
4174 case ERROR_PATH_NOT_FOUND
:
4181 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
4183 logon_network_drive (filename
);
4184 fh
= FindFirstFile (filename
, &wfd
);
4185 if (fh
== INVALID_HANDLE_VALUE
)
4188 return (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
4189 && (wfd
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
4192 /* If NAME identifies a symbolic link, copy into BUF the file name of
4193 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4194 null-terminate the target name, even if it fits. Return the number
4195 of bytes copied, or -1 if NAME is not a symlink or any error was
4196 encountered while resolving it. The file name copied into BUF is
4197 encoded in the current ANSI codepage. */
4199 readlink (const char *name
, char *buf
, size_t buf_size
)
4202 TOKEN_PRIVILEGES privs
;
4203 int restore_privs
= 0;
4218 path
= map_w32_filename (name
, NULL
);
4220 if (strlen (path
) > MAX_PATH
)
4222 errno
= ENAMETOOLONG
;
4227 if (is_windows_9x () == TRUE
4228 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
4229 || !is_symlink (path
))
4232 errno
= EINVAL
; /* not a symlink */
4236 /* Done with simple tests, now we're in for some _real_ work. */
4237 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
4239 /* Implementation note: From here and onward, don't return early,
4240 since that will fail to restore the original set of privileges of
4241 the calling thread. */
4243 retval
= -1; /* not too optimistic, are we? */
4245 /* Note: In the next call to CreateFile, we use zero as the 2nd
4246 argument because, when the symlink is a hidden/system file,
4247 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4248 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4249 and directory symlinks. */
4250 sh
= CreateFile (path
, 0, 0, NULL
, OPEN_EXISTING
,
4251 FILE_FLAG_OPEN_REPARSE_POINT
| FILE_FLAG_BACKUP_SEMANTICS
,
4253 if (sh
!= INVALID_HANDLE_VALUE
)
4255 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
4256 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
4259 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
4260 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
4263 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
4267 /* Copy the link target name, in wide characters, fro
4268 reparse_data, then convert it to multibyte encoding in
4269 the current locale's codepage. */
4271 BYTE lname
[MAX_PATH
];
4274 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
4276 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
4277 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
4279 /* According to MSDN, PrintNameLength does not include the
4280 terminating null character. */
4281 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
4282 memcpy (lwname
, lwname_src
, lwname_len
);
4283 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
4285 /* FIXME: Should we use the current file-name coding system
4286 instead of the fixed value of the ANSI codepage? */
4287 lname_len
= WideCharToMultiByte (w32_ansi_code_page
, 0, lwname
, -1,
4288 lname
, MAX_PATH
, NULL
, NULL
);
4291 /* WideCharToMultiByte failed. */
4292 DWORD w32err1
= GetLastError ();
4296 case ERROR_INSUFFICIENT_BUFFER
:
4297 errno
= ENAMETOOLONG
;
4299 case ERROR_INVALID_PARAMETER
:
4302 case ERROR_NO_UNICODE_TRANSLATION
:
4312 size_t size_to_copy
= buf_size
;
4314 BYTE
*pend
= p
+ lname_len
;
4316 /* Normalize like dostounix_filename does, but we don't
4317 want to assume that lname is null-terminated. */
4318 if (*p
&& p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4326 /* Testing for null-terminated LNAME is paranoia:
4327 WideCharToMultiByte should always return a
4328 null-terminated string when its 4th argument is -1
4329 and its 3rd argument is null-terminated (which they
4331 if (lname
[lname_len
- 1] == '\0')
4333 if (lname_len
<= buf_size
)
4334 size_to_copy
= lname_len
;
4335 strncpy (buf
, lname
, size_to_copy
);
4337 retval
= size_to_copy
;
4344 /* CreateFile failed. */
4345 DWORD w32err2
= GetLastError ();
4349 case ERROR_FILE_NOT_FOUND
:
4350 case ERROR_PATH_NOT_FOUND
:
4353 case ERROR_ACCESS_DENIED
:
4354 case ERROR_TOO_MANY_OPEN_FILES
:
4364 restore_privilege (&privs
);
4371 /* If FILE is a symlink, return its target (stored in a static
4372 buffer); otherwise return FILE.
4374 This function repeatedly resolves symlinks in the last component of
4375 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4376 until it arrives at a file whose last component is not a symlink,
4377 or some error occurs. It returns the target of the last
4378 successfully resolved symlink in the chain. If it succeeds to
4379 resolve even a single symlink, the value returned is an absolute
4380 file name with backslashes (result of GetFullPathName). By
4381 contrast, if the original FILE is returned, it is unaltered.
4383 Note: This function can set errno even if it succeeds.
4385 Implementation note: we only resolve the last portion ("basename")
4386 of the argument FILE and of each following file in the chain,
4387 disregarding any possible symlinks in its leading directories.
4388 This is because Windows system calls and library functions
4389 transparently resolve symlinks in leading directories and return
4390 correct information, as long as the basename is not a symlink. */
4392 chase_symlinks (const char *file
)
4394 static char target
[MAX_PATH
];
4395 char link
[MAX_PATH
];
4396 ssize_t res
, link_len
;
4399 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
4400 return (char *)file
;
4402 if ((link_len
= GetFullPathName (file
, MAX_PATH
, link
, NULL
)) == 0)
4403 return (char *)file
;
4408 /* Remove trailing slashes, as we want to resolve the last
4409 non-trivial part of the link name. */
4410 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
4411 link
[link_len
--] = '\0';
4413 res
= readlink (link
, target
, MAX_PATH
);
4417 if (!(IS_DEVICE_SEP (target
[1])
4418 || (IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1]))))
4420 /* Target is relative. Append it to the directory part of
4421 the symlink, then copy the result back to target. */
4422 char *p
= link
+ link_len
;
4424 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
4427 strcpy (target
, link
);
4429 /* Resolve any "." and ".." to get a fully-qualified file name
4431 link_len
= GetFullPathName (target
, MAX_PATH
, link
, NULL
);
4433 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
4435 if (loop_count
> 100)
4438 if (target
[0] == '\0') /* not a single call to readlink succeeded */
4439 return (char *)file
;
4443 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
4444 have a fixed max size for file names, so we don't need the kind of
4445 alloc/malloc/realloc dance the gnulib version does. We also don't
4446 support FD-relative symlinks. */
4448 careadlinkat (int fd
, char const *filename
,
4449 char *buffer
, size_t buffer_size
,
4450 struct allocator
const *alloc
,
4451 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
4453 char linkname
[MAX_PATH
];
4462 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
4466 char *retval
= buffer
;
4468 linkname
[link_size
++] = '\0';
4469 if (link_size
> buffer_size
)
4470 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
4472 memcpy (retval
, linkname
, link_size
);
4480 careadlinkatcwd (int fd
, char const *filename
, char *buffer
,
4484 return readlink (filename
, buffer
, buffer_size
);
4488 /* Support for browsing other processes and their attributes. See
4489 process.c for the Lisp bindings. */
4491 /* Helper wrapper functions. */
4493 static HANDLE WINAPI
4494 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
4496 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
4498 if (g_b_init_create_toolhelp32_snapshot
== 0)
4500 g_b_init_create_toolhelp32_snapshot
= 1;
4501 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
4502 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4503 "CreateToolhelp32Snapshot");
4505 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
4507 return INVALID_HANDLE_VALUE
;
4509 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
4513 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
4515 static Process32First_Proc s_pfn_Process32_First
= NULL
;
4517 if (g_b_init_process32_first
== 0)
4519 g_b_init_process32_first
= 1;
4520 s_pfn_Process32_First
= (Process32First_Proc
)
4521 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4524 if (s_pfn_Process32_First
== NULL
)
4528 return (s_pfn_Process32_First (hSnapshot
, lppe
));
4532 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
4534 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
4536 if (g_b_init_process32_next
== 0)
4538 g_b_init_process32_next
= 1;
4539 s_pfn_Process32_Next
= (Process32Next_Proc
)
4540 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4543 if (s_pfn_Process32_Next
== NULL
)
4547 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
4551 open_thread_token (HANDLE ThreadHandle
,
4552 DWORD DesiredAccess
,
4554 PHANDLE TokenHandle
)
4556 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
4557 HMODULE hm_advapi32
= NULL
;
4558 if (is_windows_9x () == TRUE
)
4560 SetLastError (ERROR_NOT_SUPPORTED
);
4563 if (g_b_init_open_thread_token
== 0)
4565 g_b_init_open_thread_token
= 1;
4566 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4567 s_pfn_Open_Thread_Token
=
4568 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
4570 if (s_pfn_Open_Thread_Token
== NULL
)
4572 SetLastError (ERROR_NOT_SUPPORTED
);
4576 s_pfn_Open_Thread_Token (
4585 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
4587 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
4588 HMODULE hm_advapi32
= NULL
;
4589 if (is_windows_9x () == TRUE
)
4593 if (g_b_init_impersonate_self
== 0)
4595 g_b_init_impersonate_self
= 1;
4596 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4597 s_pfn_Impersonate_Self
=
4598 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
4600 if (s_pfn_Impersonate_Self
== NULL
)
4604 return s_pfn_Impersonate_Self (ImpersonationLevel
);
4608 revert_to_self (void)
4610 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
4611 HMODULE hm_advapi32
= NULL
;
4612 if (is_windows_9x () == TRUE
)
4616 if (g_b_init_revert_to_self
== 0)
4618 g_b_init_revert_to_self
= 1;
4619 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4620 s_pfn_Revert_To_Self
=
4621 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
4623 if (s_pfn_Revert_To_Self
== NULL
)
4627 return s_pfn_Revert_To_Self ();
4631 get_process_memory_info (HANDLE h_proc
,
4632 PPROCESS_MEMORY_COUNTERS mem_counters
,
4635 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
4636 HMODULE hm_psapi
= NULL
;
4637 if (is_windows_9x () == TRUE
)
4641 if (g_b_init_get_process_memory_info
== 0)
4643 g_b_init_get_process_memory_info
= 1;
4644 hm_psapi
= LoadLibrary ("Psapi.dll");
4646 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
4647 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
4649 if (s_pfn_Get_Process_Memory_Info
== NULL
)
4653 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
4657 get_process_working_set_size (HANDLE h_proc
,
4661 static GetProcessWorkingSetSize_Proc
4662 s_pfn_Get_Process_Working_Set_Size
= NULL
;
4664 if (is_windows_9x () == TRUE
)
4668 if (g_b_init_get_process_working_set_size
== 0)
4670 g_b_init_get_process_working_set_size
= 1;
4671 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
4672 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4673 "GetProcessWorkingSetSize");
4675 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
4679 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
4683 global_memory_status (MEMORYSTATUS
*buf
)
4685 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
4687 if (is_windows_9x () == TRUE
)
4691 if (g_b_init_global_memory_status
== 0)
4693 g_b_init_global_memory_status
= 1;
4694 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
4695 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4696 "GlobalMemoryStatus");
4698 if (s_pfn_Global_Memory_Status
== NULL
)
4702 return s_pfn_Global_Memory_Status (buf
);
4706 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
4708 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
4710 if (is_windows_9x () == TRUE
)
4714 if (g_b_init_global_memory_status_ex
== 0)
4716 g_b_init_global_memory_status_ex
= 1;
4717 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
4718 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4719 "GlobalMemoryStatusEx");
4721 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
4725 return s_pfn_Global_Memory_Status_Ex (buf
);
4729 list_system_processes (void)
4731 struct gcpro gcpro1
;
4732 Lisp_Object proclist
= Qnil
;
4735 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4737 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4739 PROCESSENTRY32 proc_entry
;
4745 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
4746 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
4747 res
= process32_next (h_snapshot
, &proc_entry
))
4749 proc_id
= proc_entry
.th32ProcessID
;
4750 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
4753 CloseHandle (h_snapshot
);
4755 proclist
= Fnreverse (proclist
);
4762 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
4764 TOKEN_PRIVILEGES priv
;
4765 DWORD priv_size
= sizeof (priv
);
4766 DWORD opriv_size
= sizeof (*old_priv
);
4767 HANDLE h_token
= NULL
;
4768 HANDLE h_thread
= GetCurrentThread ();
4772 res
= open_thread_token (h_thread
,
4773 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4775 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
4777 if (impersonate_self (SecurityImpersonation
))
4778 res
= open_thread_token (h_thread
,
4779 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4784 priv
.PrivilegeCount
= 1;
4785 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
4786 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
4787 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
4788 old_priv
, &opriv_size
)
4789 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4793 CloseHandle (h_token
);
4799 restore_privilege (TOKEN_PRIVILEGES
*priv
)
4801 DWORD priv_size
= sizeof (*priv
);
4802 HANDLE h_token
= NULL
;
4805 if (open_thread_token (GetCurrentThread (),
4806 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4809 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
4810 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4814 CloseHandle (h_token
);
4820 ltime (ULONGLONG time_100ns
)
4822 ULONGLONG time_sec
= time_100ns
/ 10000000;
4823 int subsec
= time_100ns
% 10000000;
4824 return list4 (make_number (time_sec
>> 16),
4825 make_number (time_sec
& 0xffff),
4826 make_number (subsec
/ 10),
4827 make_number (subsec
% 10 * 100000));
4830 #define U64_TO_LISP_TIME(time) ltime (time)
4833 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4834 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4837 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4838 ULONGLONG tem1
, tem2
, tem3
, tem
;
4841 || !get_process_times_fn
4842 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4843 &ft_kernel
, &ft_user
))
4846 GetSystemTimeAsFileTime (&ft_current
);
4848 FILETIME_TO_U64 (tem1
, ft_kernel
);
4849 *stime
= U64_TO_LISP_TIME (tem1
);
4851 FILETIME_TO_U64 (tem2
, ft_user
);
4852 *utime
= U64_TO_LISP_TIME (tem2
);
4855 *ttime
= U64_TO_LISP_TIME (tem3
);
4857 FILETIME_TO_U64 (tem
, ft_creation
);
4858 /* Process no 4 (System) returns zero creation time. */
4861 *ctime
= U64_TO_LISP_TIME (tem
);
4865 FILETIME_TO_U64 (tem3
, ft_current
);
4866 tem
= (tem3
- utc_base
) - tem
;
4868 *etime
= U64_TO_LISP_TIME (tem
);
4872 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4883 system_process_attributes (Lisp_Object pid
)
4885 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4886 Lisp_Object attrs
= Qnil
;
4887 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4888 HANDLE h_snapshot
, h_proc
;
4891 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4892 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4893 DWORD glength
= sizeof (gname
);
4894 HANDLE token
= NULL
;
4895 SID_NAME_USE user_type
;
4896 unsigned char *buf
= NULL
;
4898 TOKEN_USER user_token
;
4899 TOKEN_PRIMARY_GROUP group_token
;
4902 PROCESS_MEMORY_COUNTERS mem
;
4903 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4904 DWORD minrss
, maxrss
;
4906 MEMORY_STATUS_EX memstex
;
4907 double totphys
= 0.0;
4908 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4910 BOOL result
= FALSE
;
4912 CHECK_NUMBER_OR_FLOAT (pid
);
4913 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4915 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4917 GCPRO3 (attrs
, decoded_cmd
, tem
);
4919 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4924 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4925 for (res
= process32_first (h_snapshot
, &pe
); res
;
4926 res
= process32_next (h_snapshot
, &pe
))
4928 if (proc_id
== pe
.th32ProcessID
)
4931 decoded_cmd
= build_string ("Idle");
4934 /* Decode the command name from locale-specific
4936 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4937 strlen (pe
.szExeFile
));
4939 code_convert_string_norecord (cmd_str
,
4940 Vlocale_coding_system
, 0);
4942 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4943 attrs
= Fcons (Fcons (Qppid
,
4944 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4946 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4948 attrs
= Fcons (Fcons (Qthcount
,
4949 make_fixnum_or_float (pe
.cntThreads
)),
4956 CloseHandle (h_snapshot
);
4965 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4967 /* If we were denied a handle to the process, try again after
4968 enabling the SeDebugPrivilege in our process. */
4971 TOKEN_PRIVILEGES priv_current
;
4973 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4975 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4977 restore_privilege (&priv_current
);
4983 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4986 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4987 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4989 buf
= xmalloc (blen
);
4990 result
= get_token_information (token
, TokenUser
,
4991 (LPVOID
)buf
, blen
, &needed
);
4994 memcpy (&user_token
, buf
, sizeof (user_token
));
4995 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4997 euid
= get_rid (user_token
.User
.Sid
);
4998 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
5003 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
5006 strcpy (uname
, "unknown");
5010 ulength
= strlen (uname
);
5016 /* Determine a reasonable euid and gid values. */
5017 if (xstrcasecmp ("administrator", uname
) == 0)
5019 euid
= 500; /* well-known Administrator uid */
5020 egid
= 513; /* well-known None gid */
5024 /* Get group id and name. */
5025 result
= get_token_information (token
, TokenPrimaryGroup
,
5026 (LPVOID
)buf
, blen
, &needed
);
5027 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5029 buf
= xrealloc (buf
, blen
= needed
);
5030 result
= get_token_information (token
, TokenPrimaryGroup
,
5031 (LPVOID
)buf
, blen
, &needed
);
5035 memcpy (&group_token
, buf
, sizeof (group_token
));
5036 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
5038 egid
= get_rid (group_token
.PrimaryGroup
);
5039 dlength
= sizeof (domain
);
5041 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
5042 gname
, &glength
, NULL
, &dlength
,
5045 w32_add_to_cache (group_token
.PrimaryGroup
,
5049 strcpy (gname
, "None");
5053 glength
= strlen (gname
);
5061 if (!is_windows_9x ())
5063 /* We couldn't open the process token, presumably because of
5064 insufficient access rights. Assume this process is run
5066 strcpy (uname
, "SYSTEM");
5067 strcpy (gname
, "None");
5068 euid
= 18; /* SYSTEM */
5069 egid
= 513; /* None */
5070 glength
= strlen (gname
);
5071 ulength
= strlen (uname
);
5073 /* If we are running under Windows 9X, where security calls are
5074 not supported, we assume all processes are run by the current
5076 else if (GetUserName (uname
, &ulength
))
5078 if (xstrcasecmp ("administrator", uname
) == 0)
5083 strcpy (gname
, "None");
5084 glength
= strlen (gname
);
5085 ulength
= strlen (uname
);
5091 strcpy (uname
, "administrator");
5092 ulength
= strlen (uname
);
5093 strcpy (gname
, "None");
5094 glength
= strlen (gname
);
5097 CloseHandle (token
);
5100 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
5101 tem
= make_unibyte_string (uname
, ulength
);
5102 attrs
= Fcons (Fcons (Quser
,
5103 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5105 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
5106 tem
= make_unibyte_string (gname
, glength
);
5107 attrs
= Fcons (Fcons (Qgroup
,
5108 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5111 if (global_memory_status_ex (&memstex
))
5112 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5113 totphys
= memstex
.ullTotalPhys
/ 1024.0;
5115 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5116 double, so we need to do this for it... */
5118 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
5119 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
5120 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
5122 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
5124 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5125 else if (global_memory_status (&memst
))
5126 totphys
= memst
.dwTotalPhys
/ 1024.0;
5129 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
5132 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
5134 attrs
= Fcons (Fcons (Qmajflt
,
5135 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
5137 attrs
= Fcons (Fcons (Qvsize
,
5138 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
5140 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5142 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5145 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
5147 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
5149 attrs
= Fcons (Fcons (Qmajflt
,
5150 make_fixnum_or_float (mem
.PageFaultCount
)),
5152 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5154 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5157 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
5159 DWORD rss
= maxrss
/ 1024;
5161 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
5163 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5166 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
5168 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
5169 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
5170 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
5171 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
5172 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
5173 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
5176 /* FIXME: Retrieve command line by walking the PEB of the process. */
5179 CloseHandle (h_proc
);
5185 /* Wrappers for winsock functions to map between our file descriptors
5186 and winsock's handles; also set h_errno for convenience.
5188 To allow Emacs to run on systems which don't have winsock support
5189 installed, we dynamically link to winsock on startup if present, and
5190 otherwise provide the minimum necessary functionality
5191 (eg. gethostname). */
5193 /* function pointers for relevant socket functions */
5194 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
5195 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
5196 int (PASCAL
*pfn_WSAGetLastError
) (void);
5197 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
5198 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
5199 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
5200 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
5201 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
5202 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
5203 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
5204 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
5205 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
5206 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
5207 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
5208 int (PASCAL
*pfn_WSACleanup
) (void);
5210 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
5211 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
5212 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
5213 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
5214 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
5215 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
5216 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
5217 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
5218 const char * optval
, int optlen
);
5219 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
5220 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
5222 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
5223 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
5224 struct sockaddr
* from
, int * fromlen
);
5225 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
5226 const struct sockaddr
* to
, int tolen
);
5228 /* SetHandleInformation is only needed to make sockets non-inheritable. */
5229 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
5230 #ifndef HANDLE_FLAG_INHERIT
5231 #define HANDLE_FLAG_INHERIT 1
5235 static int winsock_inuse
;
5240 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
5242 /* Not sure what would cause WSAENETDOWN, or even if it can happen
5243 after WSAStartup returns successfully, but it seems reasonable
5244 to allow unloading winsock anyway in that case. */
5245 if (pfn_WSACleanup () == 0 ||
5246 pfn_WSAGetLastError () == WSAENETDOWN
)
5248 if (FreeLibrary (winsock_lib
))
5257 init_winsock (int load_now
)
5259 WSADATA winsockData
;
5261 if (winsock_lib
!= NULL
)
5264 pfn_SetHandleInformation
5265 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
5266 "SetHandleInformation");
5268 winsock_lib
= LoadLibrary ("Ws2_32.dll");
5270 if (winsock_lib
!= NULL
)
5272 /* dynamically link to socket functions */
5274 #define LOAD_PROC(fn) \
5275 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
5278 LOAD_PROC (WSAStartup
);
5279 LOAD_PROC (WSASetLastError
);
5280 LOAD_PROC (WSAGetLastError
);
5281 LOAD_PROC (WSAEventSelect
);
5282 LOAD_PROC (WSACreateEvent
);
5283 LOAD_PROC (WSACloseEvent
);
5286 LOAD_PROC (connect
);
5287 LOAD_PROC (ioctlsocket
);
5290 LOAD_PROC (closesocket
);
5291 LOAD_PROC (shutdown
);
5294 LOAD_PROC (inet_addr
);
5295 LOAD_PROC (gethostname
);
5296 LOAD_PROC (gethostbyname
);
5297 LOAD_PROC (getservbyname
);
5298 LOAD_PROC (getpeername
);
5299 LOAD_PROC (WSACleanup
);
5300 LOAD_PROC (setsockopt
);
5302 LOAD_PROC (getsockname
);
5304 LOAD_PROC (recvfrom
);
5308 /* specify version 1.1 of winsock */
5309 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
5311 if (winsockData
.wVersion
!= 0x101)
5316 /* Report that winsock exists and is usable, but leave
5317 socket functions disabled. I am assuming that calling
5318 WSAStartup does not require any network interaction,
5319 and in particular does not cause or require a dial-up
5320 connection to be established. */
5323 FreeLibrary (winsock_lib
);
5331 FreeLibrary (winsock_lib
);
5341 /* function to set h_errno for compatibility; map winsock error codes to
5342 normal system codes where they overlap (non-overlapping definitions
5343 are already in <sys/socket.h> */
5347 if (winsock_lib
== NULL
)
5350 h_errno
= pfn_WSAGetLastError ();
5354 case WSAEACCES
: h_errno
= EACCES
; break;
5355 case WSAEBADF
: h_errno
= EBADF
; break;
5356 case WSAEFAULT
: h_errno
= EFAULT
; break;
5357 case WSAEINTR
: h_errno
= EINTR
; break;
5358 case WSAEINVAL
: h_errno
= EINVAL
; break;
5359 case WSAEMFILE
: h_errno
= EMFILE
; break;
5360 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
5361 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
5369 if (h_errno
== 0 && winsock_lib
!= NULL
)
5370 pfn_WSASetLastError (0);
5373 /* Extend strerror to handle the winsock-specific error codes. */
5377 } _wsa_errlist
[] = {
5378 {WSAEINTR
, "Interrupted function call"},
5379 {WSAEBADF
, "Bad file descriptor"},
5380 {WSAEACCES
, "Permission denied"},
5381 {WSAEFAULT
, "Bad address"},
5382 {WSAEINVAL
, "Invalid argument"},
5383 {WSAEMFILE
, "Too many open files"},
5385 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
5386 {WSAEINPROGRESS
, "Operation now in progress"},
5387 {WSAEALREADY
, "Operation already in progress"},
5388 {WSAENOTSOCK
, "Socket operation on non-socket"},
5389 {WSAEDESTADDRREQ
, "Destination address required"},
5390 {WSAEMSGSIZE
, "Message too long"},
5391 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
5392 {WSAENOPROTOOPT
, "Bad protocol option"},
5393 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
5394 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
5395 {WSAEOPNOTSUPP
, "Operation not supported"},
5396 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
5397 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
5398 {WSAEADDRINUSE
, "Address already in use"},
5399 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
5400 {WSAENETDOWN
, "Network is down"},
5401 {WSAENETUNREACH
, "Network is unreachable"},
5402 {WSAENETRESET
, "Network dropped connection on reset"},
5403 {WSAECONNABORTED
, "Software caused connection abort"},
5404 {WSAECONNRESET
, "Connection reset by peer"},
5405 {WSAENOBUFS
, "No buffer space available"},
5406 {WSAEISCONN
, "Socket is already connected"},
5407 {WSAENOTCONN
, "Socket is not connected"},
5408 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
5409 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
5410 {WSAETIMEDOUT
, "Connection timed out"},
5411 {WSAECONNREFUSED
, "Connection refused"},
5412 {WSAELOOP
, "Network loop"}, /* not sure */
5413 {WSAENAMETOOLONG
, "Name is too long"},
5414 {WSAEHOSTDOWN
, "Host is down"},
5415 {WSAEHOSTUNREACH
, "No route to host"},
5416 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
5417 {WSAEPROCLIM
, "Too many processes"},
5418 {WSAEUSERS
, "Too many users"}, /* not sure */
5419 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
5420 {WSAESTALE
, "Data is stale"}, /* not sure */
5421 {WSAEREMOTE
, "Remote error"}, /* not sure */
5423 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
5424 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
5425 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
5426 {WSAEDISCON
, "Graceful shutdown in progress"},
5428 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
5429 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
5430 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
5431 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
5432 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
5433 {WSASYSCALLFAILURE
, "System call failure"},
5434 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
5435 {WSATYPE_NOT_FOUND
, "Class type not found"},
5436 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
5437 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
5438 {WSAEREFUSED
, "Operation refused"}, /* not sure */
5441 {WSAHOST_NOT_FOUND
, "Host not found"},
5442 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
5443 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
5444 {WSANO_DATA
, "Valid name, no data record of requested type"},
5450 sys_strerror (int error_no
)
5453 static char unknown_msg
[40];
5455 if (error_no
>= 0 && error_no
< sys_nerr
)
5456 return sys_errlist
[error_no
];
5458 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
5459 if (_wsa_errlist
[i
].errnum
== error_no
)
5460 return _wsa_errlist
[i
].msg
;
5462 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
5466 /* [andrewi 3-May-96] I've had conflicting results using both methods,
5467 but I believe the method of keeping the socket handle separate (and
5468 insuring it is not inheritable) is the correct one. */
5470 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
5472 static int socket_to_fd (SOCKET s
);
5475 sys_socket (int af
, int type
, int protocol
)
5479 if (winsock_lib
== NULL
)
5482 return INVALID_SOCKET
;
5487 /* call the real socket function */
5488 s
= pfn_socket (af
, type
, protocol
);
5490 if (s
!= INVALID_SOCKET
)
5491 return socket_to_fd (s
);
5497 /* Convert a SOCKET to a file descriptor. */
5499 socket_to_fd (SOCKET s
)
5504 /* Although under NT 3.5 _open_osfhandle will accept a socket
5505 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
5506 that does not work under NT 3.1. However, we can get the same
5507 effect by using a backdoor function to replace an existing
5508 descriptor handle with the one we want. */
5510 /* allocate a file descriptor (with appropriate flags) */
5511 fd
= _open ("NUL:", _O_RDWR
);
5514 /* Make a non-inheritable copy of the socket handle. Note
5515 that it is possible that sockets aren't actually kernel
5516 handles, which appears to be the case on Windows 9x when
5517 the MS Proxy winsock client is installed. */
5519 /* Apparently there is a bug in NT 3.51 with some service
5520 packs, which prevents using DuplicateHandle to make a
5521 socket handle non-inheritable (causes WSACleanup to
5522 hang). The work-around is to use SetHandleInformation
5523 instead if it is available and implemented. */
5524 if (pfn_SetHandleInformation
)
5526 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
5530 HANDLE parent
= GetCurrentProcess ();
5531 HANDLE new_s
= INVALID_HANDLE_VALUE
;
5533 if (DuplicateHandle (parent
,
5539 DUPLICATE_SAME_ACCESS
))
5541 /* It is possible that DuplicateHandle succeeds even
5542 though the socket wasn't really a kernel handle,
5543 because a real handle has the same value. So
5544 test whether the new handle really is a socket. */
5545 long nonblocking
= 0;
5546 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
5548 pfn_closesocket (s
);
5553 CloseHandle (new_s
);
5558 fd_info
[fd
].hnd
= (HANDLE
) s
;
5560 /* set our own internal flags */
5561 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
5567 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5569 /* attach child_process to fd_info */
5570 if (fd_info
[ fd
].cp
!= NULL
)
5572 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
5576 fd_info
[ fd
].cp
= cp
;
5579 winsock_inuse
++; /* count open sockets */
5586 pfn_closesocket (s
);
5592 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
5594 if (winsock_lib
== NULL
)
5597 return SOCKET_ERROR
;
5601 if (fd_info
[s
].flags
& FILE_SOCKET
)
5603 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
5604 if (rc
== SOCKET_ERROR
)
5609 return SOCKET_ERROR
;
5613 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
5615 if (winsock_lib
== NULL
)
5618 return SOCKET_ERROR
;
5622 if (fd_info
[s
].flags
& FILE_SOCKET
)
5624 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
5625 if (rc
== SOCKET_ERROR
)
5630 return SOCKET_ERROR
;
5634 sys_htons (u_short hostshort
)
5636 return (winsock_lib
!= NULL
) ?
5637 pfn_htons (hostshort
) : hostshort
;
5641 sys_ntohs (u_short netshort
)
5643 return (winsock_lib
!= NULL
) ?
5644 pfn_ntohs (netshort
) : netshort
;
5648 sys_inet_addr (const char * cp
)
5650 return (winsock_lib
!= NULL
) ?
5651 pfn_inet_addr (cp
) : INADDR_NONE
;
5655 sys_gethostname (char * name
, int namelen
)
5657 if (winsock_lib
!= NULL
)
5658 return pfn_gethostname (name
, namelen
);
5660 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
5661 return !GetComputerName (name
, (DWORD
*)&namelen
);
5664 return SOCKET_ERROR
;
5668 sys_gethostbyname (const char * name
)
5670 struct hostent
* host
;
5672 if (winsock_lib
== NULL
)
5679 host
= pfn_gethostbyname (name
);
5686 sys_getservbyname (const char * name
, const char * proto
)
5688 struct servent
* serv
;
5690 if (winsock_lib
== NULL
)
5697 serv
= pfn_getservbyname (name
, proto
);
5704 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
5706 if (winsock_lib
== NULL
)
5709 return SOCKET_ERROR
;
5713 if (fd_info
[s
].flags
& FILE_SOCKET
)
5715 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
5716 if (rc
== SOCKET_ERROR
)
5721 return SOCKET_ERROR
;
5725 sys_shutdown (int s
, int how
)
5727 if (winsock_lib
== NULL
)
5730 return SOCKET_ERROR
;
5734 if (fd_info
[s
].flags
& FILE_SOCKET
)
5736 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
5737 if (rc
== SOCKET_ERROR
)
5742 return SOCKET_ERROR
;
5746 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
5748 if (winsock_lib
== NULL
)
5751 return SOCKET_ERROR
;
5755 if (fd_info
[s
].flags
& FILE_SOCKET
)
5757 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
5758 (const char *)optval
, optlen
);
5759 if (rc
== SOCKET_ERROR
)
5764 return SOCKET_ERROR
;
5768 sys_listen (int s
, int backlog
)
5770 if (winsock_lib
== NULL
)
5773 return SOCKET_ERROR
;
5777 if (fd_info
[s
].flags
& FILE_SOCKET
)
5779 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
5780 if (rc
== SOCKET_ERROR
)
5783 fd_info
[s
].flags
|= FILE_LISTEN
;
5787 return SOCKET_ERROR
;
5791 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
5793 if (winsock_lib
== NULL
)
5796 return SOCKET_ERROR
;
5800 if (fd_info
[s
].flags
& FILE_SOCKET
)
5802 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
5803 if (rc
== SOCKET_ERROR
)
5808 return SOCKET_ERROR
;
5812 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
5814 if (winsock_lib
== NULL
)
5821 if (fd_info
[s
].flags
& FILE_LISTEN
)
5823 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5825 if (t
== INVALID_SOCKET
)
5828 fd
= socket_to_fd (t
);
5830 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5831 ResetEvent (fd_info
[s
].cp
->char_avail
);
5839 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5840 struct sockaddr
* from
, int * fromlen
)
5842 if (winsock_lib
== NULL
)
5845 return SOCKET_ERROR
;
5849 if (fd_info
[s
].flags
& FILE_SOCKET
)
5851 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5852 if (rc
== SOCKET_ERROR
)
5857 return SOCKET_ERROR
;
5861 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5862 const struct sockaddr
* to
, int tolen
)
5864 if (winsock_lib
== NULL
)
5867 return SOCKET_ERROR
;
5871 if (fd_info
[s
].flags
& FILE_SOCKET
)
5873 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5874 if (rc
== SOCKET_ERROR
)
5879 return SOCKET_ERROR
;
5882 /* Windows does not have an fcntl function. Provide an implementation
5883 solely for making sockets non-blocking. */
5885 fcntl (int s
, int cmd
, int options
)
5887 if (winsock_lib
== NULL
)
5894 if (fd_info
[s
].flags
& FILE_SOCKET
)
5896 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5898 unsigned long nblock
= 1;
5899 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5900 if (rc
== SOCKET_ERROR
)
5902 /* Keep track of the fact that we set this to non-blocking. */
5903 fd_info
[s
].flags
|= FILE_NDELAY
;
5909 return SOCKET_ERROR
;
5913 return SOCKET_ERROR
;
5917 /* Shadow main io functions: we need to handle pipes and sockets more
5918 intelligently, and implement non-blocking mode as well. */
5931 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5933 child_process
* cp
= fd_info
[fd
].cp
;
5935 fd_info
[fd
].cp
= NULL
;
5937 if (CHILD_ACTIVE (cp
))
5939 /* if last descriptor to active child_process then cleanup */
5941 for (i
= 0; i
< MAXDESC
; i
++)
5945 if (fd_info
[i
].cp
== cp
)
5950 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5952 if (winsock_lib
== NULL
) abort ();
5954 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5955 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5957 winsock_inuse
--; /* count open sockets */
5964 /* Note that sockets do not need special treatment here (at least on
5965 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5966 closesocket is equivalent to CloseHandle, which is to be expected
5967 because socket handles are fully fledged kernel handles. */
5970 if (rc
== 0 && fd
< MAXDESC
)
5971 fd_info
[fd
].flags
= 0;
5982 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5984 /* duplicate our internal info as well */
5985 fd_info
[new_fd
] = fd_info
[fd
];
5991 sys_dup2 (int src
, int dst
)
5995 if (dst
< 0 || dst
>= MAXDESC
)
6001 /* make sure we close the destination first if it's a pipe or socket */
6002 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
6005 rc
= _dup2 (src
, dst
);
6008 /* duplicate our internal info as well */
6009 fd_info
[dst
] = fd_info
[src
];
6014 /* Unix pipe() has only one arg */
6016 sys_pipe (int * phandles
)
6021 /* make pipe handles non-inheritable; when we spawn a child, we
6022 replace the relevant handle with an inheritable one. Also put
6023 pipes into binary mode; we will do text mode translation ourselves
6025 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
6029 /* Protect against overflow, since Windows can open more handles than
6030 our fd_info array has room for. */
6031 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
6033 _close (phandles
[0]);
6034 _close (phandles
[1]);
6039 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
6040 fd_info
[phandles
[0]].flags
= flags
;
6042 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
6043 fd_info
[phandles
[1]].flags
= flags
;
6050 /* Function to do blocking read of one byte, needed to implement
6051 select. It is only allowed on sockets and pipes. */
6053 _sys_read_ahead (int fd
)
6058 if (fd
< 0 || fd
>= MAXDESC
)
6059 return STATUS_READ_ERROR
;
6061 cp
= fd_info
[fd
].cp
;
6063 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6064 return STATUS_READ_ERROR
;
6066 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
6067 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
6069 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
6073 cp
->status
= STATUS_READ_IN_PROGRESS
;
6075 if (fd_info
[fd
].flags
& FILE_PIPE
)
6077 rc
= _read (fd
, &cp
->chr
, sizeof (char));
6079 /* Give subprocess time to buffer some more output for us before
6080 reporting that input is available; we need this because Windows 95
6081 connects DOS programs to pipes by making the pipe appear to be
6082 the normal console stdout - as a result most DOS programs will
6083 write to stdout without buffering, ie. one character at a
6084 time. Even some W32 programs do this - "dir" in a command
6085 shell on NT is very slow if we don't do this. */
6088 int wait
= w32_pipe_read_delay
;
6094 /* Yield remainder of our time slice, effectively giving a
6095 temporary priority boost to the child process. */
6099 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
6101 HANDLE hnd
= fd_info
[fd
].hnd
;
6102 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
6105 /* Configure timeouts for blocking read. */
6106 if (!GetCommTimeouts (hnd
, &ct
))
6107 return STATUS_READ_ERROR
;
6108 ct
.ReadIntervalTimeout
= 0;
6109 ct
.ReadTotalTimeoutMultiplier
= 0;
6110 ct
.ReadTotalTimeoutConstant
= 0;
6111 if (!SetCommTimeouts (hnd
, &ct
))
6112 return STATUS_READ_ERROR
;
6114 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
6116 if (GetLastError () != ERROR_IO_PENDING
)
6117 return STATUS_READ_ERROR
;
6118 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
6119 return STATUS_READ_ERROR
;
6122 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
6124 unsigned long nblock
= 0;
6125 /* We always want this to block, so temporarily disable NDELAY. */
6126 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6127 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6129 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
6131 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6134 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6138 if (rc
== sizeof (char))
6139 cp
->status
= STATUS_READ_SUCCEEDED
;
6141 cp
->status
= STATUS_READ_FAILED
;
6147 _sys_wait_accept (int fd
)
6153 if (fd
< 0 || fd
>= MAXDESC
)
6154 return STATUS_READ_ERROR
;
6156 cp
= fd_info
[fd
].cp
;
6158 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6159 return STATUS_READ_ERROR
;
6161 cp
->status
= STATUS_READ_FAILED
;
6163 hEv
= pfn_WSACreateEvent ();
6164 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
6165 if (rc
!= SOCKET_ERROR
)
6167 rc
= WaitForSingleObject (hEv
, INFINITE
);
6168 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
6169 if (rc
== WAIT_OBJECT_0
)
6170 cp
->status
= STATUS_READ_SUCCEEDED
;
6172 pfn_WSACloseEvent (hEv
);
6178 sys_read (int fd
, char * buffer
, unsigned int count
)
6183 char * orig_buffer
= buffer
;
6191 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
6193 child_process
*cp
= fd_info
[fd
].cp
;
6195 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
6203 /* re-read CR carried over from last read */
6204 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
6206 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
6210 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
6213 /* presence of a child_process structure means we are operating in
6214 non-blocking mode - otherwise we just call _read directly.
6215 Note that the child_process structure might be missing because
6216 reap_subprocess has been called; in this case the pipe is
6217 already broken, so calling _read on it is okay. */
6220 int current_status
= cp
->status
;
6222 switch (current_status
)
6224 case STATUS_READ_FAILED
:
6225 case STATUS_READ_ERROR
:
6226 /* report normal EOF if nothing in buffer */
6228 fd_info
[fd
].flags
|= FILE_AT_EOF
;
6231 case STATUS_READ_READY
:
6232 case STATUS_READ_IN_PROGRESS
:
6233 DebPrint (("sys_read called when read is in progress\n"));
6234 errno
= EWOULDBLOCK
;
6237 case STATUS_READ_SUCCEEDED
:
6238 /* consume read-ahead char */
6239 *buffer
++ = cp
->chr
;
6242 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6243 ResetEvent (cp
->char_avail
);
6245 case STATUS_READ_ACKNOWLEDGED
:
6249 DebPrint (("sys_read: bad status %d\n", current_status
));
6254 if (fd_info
[fd
].flags
& FILE_PIPE
)
6256 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
6257 to_read
= min (waiting
, (DWORD
) count
);
6260 nchars
+= _read (fd
, buffer
, to_read
);
6262 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
6264 HANDLE hnd
= fd_info
[fd
].hnd
;
6265 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
6271 /* Configure timeouts for non-blocking read. */
6272 if (!GetCommTimeouts (hnd
, &ct
))
6277 ct
.ReadIntervalTimeout
= MAXDWORD
;
6278 ct
.ReadTotalTimeoutMultiplier
= 0;
6279 ct
.ReadTotalTimeoutConstant
= 0;
6280 if (!SetCommTimeouts (hnd
, &ct
))
6286 if (!ResetEvent (ovl
->hEvent
))
6291 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
6293 if (GetLastError () != ERROR_IO_PENDING
)
6298 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
6307 else /* FILE_SOCKET */
6309 if (winsock_lib
== NULL
) abort ();
6311 /* do the equivalent of a non-blocking read */
6312 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
6313 if (waiting
== 0 && nchars
== 0)
6315 h_errno
= errno
= EWOULDBLOCK
;
6321 /* always use binary mode for sockets */
6322 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
6323 if (res
== SOCKET_ERROR
)
6325 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
6326 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
6336 int nread
= _read (fd
, buffer
, count
);
6339 else if (nchars
== 0)
6344 fd_info
[fd
].flags
|= FILE_AT_EOF
;
6345 /* Perform text mode translation if required. */
6346 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
6348 nchars
= crlf_to_lf (nchars
, orig_buffer
);
6349 /* If buffer contains only CR, return that. To be absolutely
6350 sure we should attempt to read the next char, but in
6351 practice a CR to be followed by LF would not appear by
6352 itself in the buffer. */
6353 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
6355 fd_info
[fd
].flags
|= FILE_LAST_CR
;
6361 nchars
= _read (fd
, buffer
, count
);
6366 /* From w32xfns.c */
6367 extern HANDLE interrupt_handle
;
6369 /* For now, don't bother with a non-blocking mode */
6371 sys_write (int fd
, const void * buffer
, unsigned int count
)
6381 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
6383 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
6389 /* Perform text mode translation if required. */
6390 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
6392 char * tmpbuf
= alloca (count
* 2);
6393 unsigned char * src
= (void *)buffer
;
6394 unsigned char * dst
= tmpbuf
;
6399 unsigned char *next
;
6400 /* copy next line or remaining bytes */
6401 next
= _memccpy (dst
, src
, '\n', nbytes
);
6404 /* copied one line ending with '\n' */
6405 int copied
= next
- dst
;
6408 /* insert '\r' before '\n' */
6415 /* copied remaining partial line -> now finished */
6422 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
6424 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
6425 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
6426 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
6429 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
6431 if (GetLastError () != ERROR_IO_PENDING
)
6436 if (detect_input_pending ())
6437 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
6440 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
6441 if (active
== WAIT_OBJECT_0
)
6442 { /* User pressed C-g, cancel write, then leave. Don't bother
6443 cleaning up as we may only get stuck in buggy drivers. */
6444 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
6449 if (active
== WAIT_OBJECT_0
+ 1
6450 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
6457 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
6459 unsigned long nblock
= 0;
6460 if (winsock_lib
== NULL
) abort ();
6462 /* TODO: implement select() properly so non-blocking I/O works. */
6463 /* For now, make sure the write blocks. */
6464 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6465 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6467 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
6469 /* Set the socket back to non-blocking if it was before,
6470 for other operations that support it. */
6471 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6474 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6477 if (nchars
== SOCKET_ERROR
)
6479 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
6480 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
6486 /* Some networked filesystems don't like too large writes, so
6487 break them into smaller chunks. See the Comments section of
6488 the MSDN documentation of WriteFile for details behind the
6489 choice of the value of CHUNK below. See also the thread
6490 http://thread.gmane.org/gmane.comp.version-control.git/145294
6491 in the git mailing list. */
6492 const unsigned char *p
= buffer
;
6493 const unsigned chunk
= 30 * 1024 * 1024;
6498 unsigned this_chunk
= count
< chunk
? count
: chunk
;
6499 int n
= _write (fd
, p
, this_chunk
);
6507 else if (n
< this_chunk
)
6517 /* The Windows CRT functions are "optimized for speed", so they don't
6518 check for timezone and DST changes if they were last called less
6519 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
6520 all Emacs features that repeatedly call time functions (e.g.,
6521 display-time) are in real danger of missing timezone and DST
6522 changes. Calling tzset before each localtime call fixes that. */
6524 sys_localtime (const time_t *t
)
6527 return localtime (t
);
6532 /* Delayed loading of libraries. */
6534 Lisp_Object Vlibrary_cache
;
6536 /* The argument LIBRARIES is an alist that associates a symbol
6537 LIBRARY_ID, identifying an external DLL library known to Emacs, to
6538 a list of filenames under which the library is usually found. In
6539 most cases, the argument passed as LIBRARIES is the variable
6540 `dynamic-library-alist', which is initialized to a list of common
6541 library names. If the function loads the library successfully, it
6542 returns the handle of the DLL, and records the filename in the
6543 property :loaded-from of LIBRARY_ID; it returns NULL if the library
6544 could not be found, or when it was already loaded (because the
6545 handle is not recorded anywhere, and so is lost after use). It
6546 would be trivial to save the handle too in :loaded-from, but
6547 currently there's no use case for it. */
6549 w32_delayed_load (Lisp_Object libraries
, Lisp_Object library_id
)
6551 HMODULE library_dll
= NULL
;
6553 CHECK_SYMBOL (library_id
);
6555 if (CONSP (libraries
) && NILP (Fassq (library_id
, Vlibrary_cache
)))
6557 Lisp_Object found
= Qnil
;
6558 Lisp_Object dlls
= Fassq (library_id
, libraries
);
6561 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
6563 CHECK_STRING_CAR (dlls
);
6564 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
6566 char name
[MAX_PATH
];
6569 len
= GetModuleFileNameA (library_dll
, name
, sizeof (name
));
6570 found
= Fcons (XCAR (dlls
),
6572 /* Possibly truncated */
6573 ? make_specified_string (name
, -1, len
, 1)
6579 Fput (library_id
, QCloaded_from
, found
);
6587 check_windows_init_file (void)
6589 /* A common indication that Emacs is not installed properly is when
6590 it cannot find the Windows installation file. If this file does
6591 not exist in the expected place, tell the user. */
6593 if (!noninteractive
&& !inhibit_window_system
6594 /* Vload_path is not yet initialized when we are loading
6596 && NILP (Vpurify_flag
))
6598 Lisp_Object init_file
;
6601 init_file
= build_string ("term/w32-win");
6602 fd
= openp (Vload_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
6605 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
6606 char *init_file_name
= SDATA (init_file
);
6607 char *load_path
= SDATA (load_path_print
);
6608 char *buffer
= alloca (1024
6609 + strlen (init_file_name
)
6610 + strlen (load_path
));
6613 "The Emacs Windows initialization file \"%s.el\" "
6614 "could not be found in your Emacs installation. "
6615 "Emacs checked the following directories for this file:\n"
6617 "When Emacs cannot find this file, it usually means that it "
6618 "was not installed properly, or its distribution file was "
6619 "not unpacked properly.\nSee the README.W32 file in the "
6620 "top-level Emacs directory for more information.",
6621 init_file_name
, load_path
);
6624 "Emacs Abort Dialog",
6625 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
6626 /* Use the low-level Emacs abort. */
6640 /* shutdown the socket interface if necessary */
6649 /* Initialize the socket interface now if available and requested by
6650 the user by defining PRELOAD_WINSOCK; otherwise loading will be
6651 delayed until open-network-stream is called (w32-has-winsock can
6652 also be used to dynamically load or reload winsock).
6654 Conveniently, init_environment is called before us, so
6655 PRELOAD_WINSOCK can be set in the registry. */
6657 /* Always initialize this correctly. */
6660 if (getenv ("PRELOAD_WINSOCK") != NULL
)
6661 init_winsock (TRUE
);
6663 /* Initial preparation for subprocess support: replace our standard
6664 handles with non-inheritable versions. */
6667 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
6668 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
6669 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
6671 parent
= GetCurrentProcess ();
6673 /* ignore errors when duplicating and closing; typically the
6674 handles will be invalid when running as a gui program. */
6675 DuplicateHandle (parent
,
6676 GetStdHandle (STD_INPUT_HANDLE
),
6681 DUPLICATE_SAME_ACCESS
);
6683 DuplicateHandle (parent
,
6684 GetStdHandle (STD_OUTPUT_HANDLE
),
6689 DUPLICATE_SAME_ACCESS
);
6691 DuplicateHandle (parent
,
6692 GetStdHandle (STD_ERROR_HANDLE
),
6697 DUPLICATE_SAME_ACCESS
);
6703 if (stdin_save
!= INVALID_HANDLE_VALUE
)
6704 _open_osfhandle ((long) stdin_save
, O_TEXT
);
6706 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
6709 if (stdout_save
!= INVALID_HANDLE_VALUE
)
6710 _open_osfhandle ((long) stdout_save
, O_TEXT
);
6712 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
6715 if (stderr_save
!= INVALID_HANDLE_VALUE
)
6716 _open_osfhandle ((long) stderr_save
, O_TEXT
);
6718 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
6722 /* unfortunately, atexit depends on implementation of malloc */
6723 /* atexit (term_ntproc); */
6724 signal (SIGABRT
, term_ntproc
);
6726 /* determine which drives are fixed, for GetCachedVolumeInformation */
6728 /* GetDriveType must have trailing backslash. */
6729 char drive
[] = "A:\\";
6731 /* Loop over all possible drive letters */
6732 while (*drive
<= 'Z')
6734 /* Record if this drive letter refers to a fixed drive. */
6735 fixed_drives
[DRIVE_INDEX (*drive
)] =
6736 (GetDriveType (drive
) == DRIVE_FIXED
);
6741 /* Reset the volume info cache. */
6742 volume_cache
= NULL
;
6747 shutdown_handler ensures that buffers' autosave files are
6748 up to date when the user logs off, or the system shuts down.
6751 shutdown_handler (DWORD type
)
6753 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
6754 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
6755 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
6756 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
6758 /* Shut down cleanly, making sure autosave files are up to date. */
6759 shut_down_emacs (0, 0, Qnil
);
6762 /* Allow other handlers to handle this signal. */
6767 globals_of_w32 is used to initialize those global variables that
6768 must always be initialized on startup even when the global variable
6769 initialized is non zero (see the function main in emacs.c).
6772 globals_of_w32 (void)
6774 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
6776 get_process_times_fn
= (GetProcessTimes_Proc
)
6777 GetProcAddress (kernel32
, "GetProcessTimes");
6779 DEFSYM (QCloaded_from
, ":loaded-from");
6781 Vlibrary_cache
= Qnil
;
6782 staticpro (&Vlibrary_cache
);
6784 g_b_init_is_windows_9x
= 0;
6785 g_b_init_open_process_token
= 0;
6786 g_b_init_get_token_information
= 0;
6787 g_b_init_lookup_account_sid
= 0;
6788 g_b_init_get_sid_sub_authority
= 0;
6789 g_b_init_get_sid_sub_authority_count
= 0;
6790 g_b_init_get_security_info
= 0;
6791 g_b_init_get_file_security
= 0;
6792 g_b_init_get_security_descriptor_owner
= 0;
6793 g_b_init_get_security_descriptor_group
= 0;
6794 g_b_init_is_valid_sid
= 0;
6795 g_b_init_create_toolhelp32_snapshot
= 0;
6796 g_b_init_process32_first
= 0;
6797 g_b_init_process32_next
= 0;
6798 g_b_init_open_thread_token
= 0;
6799 g_b_init_impersonate_self
= 0;
6800 g_b_init_revert_to_self
= 0;
6801 g_b_init_get_process_memory_info
= 0;
6802 g_b_init_get_process_working_set_size
= 0;
6803 g_b_init_global_memory_status
= 0;
6804 g_b_init_global_memory_status_ex
= 0;
6805 g_b_init_equal_sid
= 0;
6806 g_b_init_copy_sid
= 0;
6807 g_b_init_get_length_sid
= 0;
6808 g_b_init_get_native_system_info
= 0;
6809 g_b_init_get_system_times
= 0;
6810 g_b_init_create_symbolic_link
= 0;
6811 num_of_processors
= 0;
6812 /* The following sets a handler for shutdown notifications for
6813 console apps. This actually applies to Emacs in both console and
6814 GUI modes, since we had to fool windows into thinking emacs is a
6815 console application to get console mode to work. */
6816 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
6818 /* "None" is the default group name on standalone workstations. */
6819 strcpy (dflt_group_name
, "None");
6822 /* For make-serial-process */
6824 serial_open (char *port
)
6830 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
6831 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
6832 if (hnd
== INVALID_HANDLE_VALUE
)
6833 error ("Could not open %s", port
);
6834 fd
= (int) _open_osfhandle ((int) hnd
, 0);
6836 error ("Could not open %s", port
);
6840 error ("Could not create child process");
6842 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6843 fd_info
[ fd
].hnd
= hnd
;
6844 fd_info
[ fd
].flags
|=
6845 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
6846 if (fd_info
[ fd
].cp
!= NULL
)
6848 error ("fd_info[fd = %d] is already in use", fd
);
6850 fd_info
[ fd
].cp
= cp
;
6851 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6852 if (cp
->ovl_read
.hEvent
== NULL
)
6853 error ("Could not create read event");
6854 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6855 if (cp
->ovl_write
.hEvent
== NULL
)
6856 error ("Could not create write event");
6861 /* For serial-process-configure */
6863 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
6865 Lisp_Object childp2
= Qnil
;
6866 Lisp_Object tem
= Qnil
;
6870 char summary
[4] = "???"; /* This usually becomes "8N1". */
6872 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6873 error ("Not a serial process");
6874 hnd
= fd_info
[ p
->outfd
].hnd
;
6876 childp2
= Fcopy_sequence (p
->childp
);
6878 /* Initialize timeouts for blocking read and blocking write. */
6879 if (!GetCommTimeouts (hnd
, &ct
))
6880 error ("GetCommTimeouts() failed");
6881 ct
.ReadIntervalTimeout
= 0;
6882 ct
.ReadTotalTimeoutMultiplier
= 0;
6883 ct
.ReadTotalTimeoutConstant
= 0;
6884 ct
.WriteTotalTimeoutMultiplier
= 0;
6885 ct
.WriteTotalTimeoutConstant
= 0;
6886 if (!SetCommTimeouts (hnd
, &ct
))
6887 error ("SetCommTimeouts() failed");
6888 /* Read port attributes and prepare default configuration. */
6889 memset (&dcb
, 0, sizeof (dcb
));
6890 dcb
.DCBlength
= sizeof (DCB
);
6891 if (!GetCommState (hnd
, &dcb
))
6892 error ("GetCommState() failed");
6895 dcb
.fAbortOnError
= FALSE
;
6896 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6901 /* Configure speed. */
6902 if (!NILP (Fplist_member (contact
, QCspeed
)))
6903 tem
= Fplist_get (contact
, QCspeed
);
6905 tem
= Fplist_get (p
->childp
, QCspeed
);
6907 dcb
.BaudRate
= XINT (tem
);
6908 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6910 /* Configure bytesize. */
6911 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6912 tem
= Fplist_get (contact
, QCbytesize
);
6914 tem
= Fplist_get (p
->childp
, QCbytesize
);
6916 tem
= make_number (8);
6918 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6919 error (":bytesize must be nil (8), 7, or 8");
6920 dcb
.ByteSize
= XINT (tem
);
6921 summary
[0] = XINT (tem
) + '0';
6922 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6924 /* Configure parity. */
6925 if (!NILP (Fplist_member (contact
, QCparity
)))
6926 tem
= Fplist_get (contact
, QCparity
);
6928 tem
= Fplist_get (p
->childp
, QCparity
);
6929 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6930 error (":parity must be nil (no parity), `even', or `odd'");
6931 dcb
.fParity
= FALSE
;
6932 dcb
.Parity
= NOPARITY
;
6933 dcb
.fErrorChar
= FALSE
;
6938 else if (EQ (tem
, Qeven
))
6942 dcb
.Parity
= EVENPARITY
;
6943 dcb
.fErrorChar
= TRUE
;
6945 else if (EQ (tem
, Qodd
))
6949 dcb
.Parity
= ODDPARITY
;
6950 dcb
.fErrorChar
= TRUE
;
6952 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6954 /* Configure stopbits. */
6955 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6956 tem
= Fplist_get (contact
, QCstopbits
);
6958 tem
= Fplist_get (p
->childp
, QCstopbits
);
6960 tem
= make_number (1);
6962 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6963 error (":stopbits must be nil (1 stopbit), 1, or 2");
6964 summary
[2] = XINT (tem
) + '0';
6965 if (XINT (tem
) == 1)
6966 dcb
.StopBits
= ONESTOPBIT
;
6967 else if (XINT (tem
) == 2)
6968 dcb
.StopBits
= TWOSTOPBITS
;
6969 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6971 /* Configure flowcontrol. */
6972 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6973 tem
= Fplist_get (contact
, QCflowcontrol
);
6975 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6976 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6977 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6978 dcb
.fOutxCtsFlow
= FALSE
;
6979 dcb
.fOutxDsrFlow
= FALSE
;
6980 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6981 dcb
.fDsrSensitivity
= FALSE
;
6982 dcb
.fTXContinueOnXoff
= FALSE
;
6985 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6986 dcb
.XonChar
= 17; /* Control-Q */
6987 dcb
.XoffChar
= 19; /* Control-S */
6990 /* Already configured. */
6992 else if (EQ (tem
, Qhw
))
6994 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6995 dcb
.fOutxCtsFlow
= TRUE
;
6997 else if (EQ (tem
, Qsw
))
7002 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
7004 /* Activate configuration. */
7005 if (!SetCommState (hnd
, &dcb
))
7006 error ("SetCommState() failed");
7008 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
7009 pset_childp (p
, childp2
);
7015 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
7019 struct timeval timeout
;
7020 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7021 int fd
= process
->infd
;
7025 n
= sys_read (fd
, (char*)buf
, sz
);
7032 if (err
== EWOULDBLOCK
)
7034 /* Set a small timeout. */
7036 timeout
.tv_usec
= 0;
7038 FD_SET ((int)fd
, &fdset
);
7040 /* Use select with the timeout to poll the selector. */
7041 sc
= select (fd
+ 1, &fdset
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0,
7045 continue; /* Try again. */
7047 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
7048 Also accept select return 0 as an indicator to EAGAIN. */
7049 if (sc
== 0 || errno
== EWOULDBLOCK
)
7052 err
= errno
; /* Other errors are just passed on. */
7055 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
7062 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
7064 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7065 int fd
= process
->outfd
;
7066 ssize_t n
= sys_write (fd
, buf
, sz
);
7068 /* 0 or more bytes written means everything went fine. */
7072 /* Negative bytes written means we got an error in errno.
7073 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7074 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
7075 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
7079 #endif /* HAVE_GNUTLS */