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>
34 #include <mbstring.h> /* for _mbspbrk */
39 /* must include CRT headers *before* config.h */
74 #define _ANONYMOUS_UNION
75 #define _ANONYMOUS_STRUCT
78 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
79 use a different name to avoid compilation problems. */
80 typedef struct _MEMORY_STATUS_EX
{
83 DWORDLONG ullTotalPhys
;
84 DWORDLONG ullAvailPhys
;
85 DWORDLONG ullTotalPageFile
;
86 DWORDLONG ullAvailPageFile
;
87 DWORDLONG ullTotalVirtual
;
88 DWORDLONG ullAvailVirtual
;
89 DWORDLONG ullAvailExtendedVirtual
;
90 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
100 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
101 /* This either is not in psapi.h or guarded by higher value of
102 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
103 defines it in psapi.h */
104 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
106 DWORD PageFaultCount
;
107 DWORD PeakWorkingSetSize
;
108 DWORD WorkingSetSize
;
109 DWORD QuotaPeakPagedPoolUsage
;
110 DWORD QuotaPagedPoolUsage
;
111 DWORD QuotaPeakNonPagedPoolUsage
;
112 DWORD QuotaNonPagedPoolUsage
;
114 DWORD PeakPagefileUsage
;
116 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
119 #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
);
870 /* Equivalent of strerror for W32 error codes. */
872 w32_strerror (int error_no
)
874 static char buf
[500];
877 error_no
= GetLastError ();
880 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
882 0, /* choose most suitable language */
883 buf
, sizeof (buf
), NULL
))
884 sprintf (buf
, "w32 error %u", error_no
);
888 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
889 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
891 This is called from alloc.c:valid_pointer_p. */
893 w32_valid_pointer_p (void *p
, int size
)
896 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
900 unsigned char *buf
= alloca (size
);
901 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
910 static char startup_dir
[MAXPATHLEN
];
912 /* Get the current working directory. */
917 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
921 /* Emacs doesn't actually change directory itself, it stays in the
922 same directory where it was started. */
923 strcpy (dir
, startup_dir
);
928 /* Emulate getloadavg. */
937 /* Number of processors on this machine. */
938 static unsigned num_of_processors
;
940 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
941 static struct load_sample samples
[16*60];
942 static int first_idx
= -1, last_idx
= -1;
943 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
948 int next_idx
= from
+ 1;
950 if (next_idx
>= max_idx
)
959 int prev_idx
= from
- 1;
962 prev_idx
= max_idx
- 1;
968 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
971 FILETIME ft_idle
, ft_user
, ft_kernel
;
973 /* Initialize the number of processors on this machine. */
974 if (num_of_processors
<= 0)
976 get_native_system_info (&sysinfo
);
977 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
978 if (num_of_processors
<= 0)
980 GetSystemInfo (&sysinfo
);
981 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
983 if (num_of_processors
<= 0)
984 num_of_processors
= 1;
987 /* TODO: Take into account threads that are ready to run, by
988 sampling the "\System\Processor Queue Length" performance
989 counter. The code below accounts only for threads that are
992 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
994 ULARGE_INTEGER uidle
, ukernel
, uuser
;
996 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
997 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
998 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
999 *idle
= uidle
.QuadPart
;
1000 *kernel
= ukernel
.QuadPart
;
1001 *user
= uuser
.QuadPart
;
1011 /* Produce the load average for a given time interval, using the
1012 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1013 1-minute, 5-minute, or 15-minute average, respectively. */
1017 double retval
= -1.0;
1020 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
1021 time_t now
= samples
[last_idx
].sample_time
;
1023 if (first_idx
!= last_idx
)
1025 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
1027 tdiff
= difftime (now
, samples
[idx
].sample_time
);
1028 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
1031 samples
[last_idx
].kernel
+ samples
[last_idx
].user
1032 - (samples
[idx
].kernel
+ samples
[idx
].user
);
1033 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
1035 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
1038 if (idx
== first_idx
)
1047 getloadavg (double loadavg
[], int nelem
)
1050 ULONGLONG idle
, kernel
, user
;
1051 time_t now
= time (NULL
);
1053 /* Store another sample. We ignore samples that are less than 1 sec
1055 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
1057 sample_system_load (&idle
, &kernel
, &user
);
1058 last_idx
= buf_next (last_idx
);
1059 samples
[last_idx
].sample_time
= now
;
1060 samples
[last_idx
].idle
= idle
;
1061 samples
[last_idx
].kernel
= kernel
;
1062 samples
[last_idx
].user
= user
;
1063 /* If the buffer has more that 15 min worth of samples, discard
1065 if (first_idx
== -1)
1066 first_idx
= last_idx
;
1067 while (first_idx
!= last_idx
1068 && (difftime (now
, samples
[first_idx
].sample_time
)
1069 >= 15.0*60 + 2*DBL_EPSILON
*now
))
1070 first_idx
= buf_next (first_idx
);
1073 for (elem
= 0; elem
< nelem
; elem
++)
1075 double avg
= getavg (elem
);
1079 loadavg
[elem
] = avg
;
1085 /* Emulate getpwuid, getpwnam and others. */
1087 #define PASSWD_FIELD_SIZE 256
1089 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1090 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1091 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1092 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
1093 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
1095 static struct passwd dflt_passwd
=
1107 static char dflt_group_name
[GNLEN
+1];
1109 static struct group dflt_group
=
1111 /* When group information is not available, we return this as the
1112 group for all files. */
1120 return dflt_passwd
.pw_uid
;
1126 /* I could imagine arguing for checking to see whether the user is
1127 in the Administrators group and returning a UID of 0 for that
1128 case, but I don't know how wise that would be in the long run. */
1135 return dflt_passwd
.pw_gid
;
1145 getpwuid (unsigned uid
)
1147 if (uid
== dflt_passwd
.pw_uid
)
1148 return &dflt_passwd
;
1153 getgrgid (gid_t gid
)
1159 getpwnam (char *name
)
1163 pw
= getpwuid (getuid ());
1167 if (xstrcasecmp (name
, pw
->pw_name
))
1174 init_user_info (void)
1176 /* Find the user's real name by opening the process token and
1177 looking up the name associated with the user-sid in that token.
1179 Use the relative portion of the identifier authority value from
1180 the user-sid as the user id value (same for group id using the
1181 primary group sid from the process token). */
1183 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1184 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1185 DWORD glength
= sizeof (gname
);
1186 HANDLE token
= NULL
;
1187 SID_NAME_USE user_type
;
1188 unsigned char *buf
= NULL
;
1190 TOKEN_USER user_token
;
1191 TOKEN_PRIMARY_GROUP group_token
;
1194 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1197 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1198 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1200 buf
= xmalloc (blen
);
1201 result
= get_token_information (token
, TokenUser
,
1202 (LPVOID
)buf
, blen
, &needed
);
1205 memcpy (&user_token
, buf
, sizeof (user_token
));
1206 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1208 domain
, &dlength
, &user_type
);
1216 strcpy (dflt_passwd
.pw_name
, uname
);
1217 /* Determine a reasonable uid value. */
1218 if (xstrcasecmp ("administrator", uname
) == 0)
1220 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1221 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1225 /* Use the last sub-authority value of the RID, the relative
1226 portion of the SID, as user/group ID. */
1227 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1229 /* Get group id and name. */
1230 result
= get_token_information (token
, TokenPrimaryGroup
,
1231 (LPVOID
)buf
, blen
, &needed
);
1232 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1234 buf
= xrealloc (buf
, blen
= needed
);
1235 result
= get_token_information (token
, TokenPrimaryGroup
,
1236 (LPVOID
)buf
, blen
, &needed
);
1240 memcpy (&group_token
, buf
, sizeof (group_token
));
1241 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1242 dlength
= sizeof (domain
);
1243 /* If we can get at the real Primary Group name, use that.
1244 Otherwise, the default group name was already set to
1245 "None" in globals_of_w32. */
1246 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1247 gname
, &glength
, NULL
, &dlength
,
1249 strcpy (dflt_group_name
, gname
);
1252 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1255 /* If security calls are not supported (presumably because we
1256 are running under Windows 9X), fallback to this: */
1257 else if (GetUserName (uname
, &ulength
))
1259 strcpy (dflt_passwd
.pw_name
, uname
);
1260 if (xstrcasecmp ("administrator", uname
) == 0)
1261 dflt_passwd
.pw_uid
= 0;
1263 dflt_passwd
.pw_uid
= 123;
1264 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1268 strcpy (dflt_passwd
.pw_name
, "unknown");
1269 dflt_passwd
.pw_uid
= 123;
1270 dflt_passwd
.pw_gid
= 123;
1272 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1274 /* Ensure HOME and SHELL are defined. */
1275 if (getenv ("HOME") == NULL
)
1277 if (getenv ("SHELL") == NULL
)
1280 /* Set dir and shell from environment variables. */
1281 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1282 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1286 CloseHandle (token
);
1292 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1293 return ((rand () << 15) | rand ());
1303 /* Normalize filename by converting all path separators to
1304 the specified separator. Also conditionally convert upper
1305 case path name components to lower case. */
1308 normalize_filename (register char *fp
, char path_sep
)
1313 /* Always lower-case drive letters a-z, even if the filesystem
1314 preserves case in filenames.
1315 This is so filenames can be compared by string comparison
1316 functions that are case-sensitive. Even case-preserving filesystems
1317 do not distinguish case in drive letters. */
1318 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1324 if (NILP (Vw32_downcase_file_names
))
1328 if (*fp
== '/' || *fp
== '\\')
1335 sep
= path_sep
; /* convert to this path separator */
1336 elem
= fp
; /* start of current path element */
1339 if (*fp
>= 'a' && *fp
<= 'z')
1340 elem
= 0; /* don't convert this element */
1342 if (*fp
== 0 || *fp
== ':')
1344 sep
= *fp
; /* restore current separator (or 0) */
1345 *fp
= '/'; /* after conversion of this element */
1348 if (*fp
== '/' || *fp
== '\\')
1350 if (elem
&& elem
!= fp
)
1352 *fp
= 0; /* temporary end of string */
1353 _strlwr (elem
); /* while we convert to lower case */
1355 *fp
= sep
; /* convert (or restore) path separator */
1356 elem
= fp
+ 1; /* next element starts after separator */
1362 /* Destructively turn backslashes into slashes. */
1364 dostounix_filename (register char *p
)
1366 normalize_filename (p
, '/');
1369 /* Destructively turn slashes into backslashes. */
1371 unixtodos_filename (register char *p
)
1373 normalize_filename (p
, '\\');
1376 /* Remove all CR's that are followed by a LF.
1377 (From msdos.c...probably should figure out a way to share it,
1378 although this code isn't going to ever change.) */
1380 crlf_to_lf (register int n
, register unsigned char *buf
)
1382 unsigned char *np
= buf
;
1383 unsigned char *startp
= buf
;
1384 unsigned char *endp
= buf
+ n
;
1388 while (buf
< endp
- 1)
1392 if (*(++buf
) != 0x0a)
1403 /* Parse the root part of file name, if present. Return length and
1404 optionally store pointer to char after root. */
1406 parse_root (char * name
, char ** pPath
)
1408 char * start
= name
;
1413 /* find the root name of the volume if given */
1414 if (isalpha (name
[0]) && name
[1] == ':')
1416 /* skip past drive specifier */
1418 if (IS_DIRECTORY_SEP (name
[0]))
1421 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1427 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1432 if (IS_DIRECTORY_SEP (name
[0]))
1439 return name
- start
;
1442 /* Get long base name for name; name is assumed to be absolute. */
1444 get_long_basename (char * name
, char * buf
, int size
)
1446 WIN32_FIND_DATA find_data
;
1450 /* must be valid filename, no wild cards or other invalid characters */
1451 if (_mbspbrk (name
, "*?|<>\""))
1454 dir_handle
= FindFirstFile (name
, &find_data
);
1455 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1457 if ((len
= strlen (find_data
.cFileName
)) < size
)
1458 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1461 FindClose (dir_handle
);
1466 /* Get long name for file, if possible (assumed to be absolute). */
1468 w32_get_long_filename (char * name
, char * buf
, int size
)
1473 char full
[ MAX_PATH
];
1476 len
= strlen (name
);
1477 if (len
>= MAX_PATH
)
1480 /* Use local copy for destructive modification. */
1481 memcpy (full
, name
, len
+1);
1482 unixtodos_filename (full
);
1484 /* Copy root part verbatim. */
1485 len
= parse_root (full
, &p
);
1486 memcpy (o
, full
, len
);
1491 while (p
!= NULL
&& *p
)
1494 p
= strchr (q
, '\\');
1496 len
= get_long_basename (full
, o
, size
);
1519 is_unc_volume (const char *filename
)
1521 const char *ptr
= filename
;
1523 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1526 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1532 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1535 sigsetmask (int signal_mask
)
1553 sigunblock (int sig
)
1559 sigemptyset (sigset_t
*set
)
1565 sigaddset (sigset_t
*set
, int signo
)
1571 sigfillset (sigset_t
*set
)
1577 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1583 pthread_sigmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1585 if (sigprocmask (how
, set
, oset
) == -1)
1591 setpgrp (int pid
, int gid
)
1602 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1605 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1608 HKEY hrootkey
= NULL
;
1611 /* Check both the current user and the local machine to see if
1612 we have any resources. */
1614 if (RegOpenKeyEx (HKEY_CURRENT_USER
, 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
);
1631 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1635 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1636 && (lpvalue
= xmalloc (cbData
)) != NULL
1637 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1639 RegCloseKey (hrootkey
);
1645 RegCloseKey (hrootkey
);
1651 char *get_emacs_configuration (void);
1654 init_environment (char ** argv
)
1656 static const char * const tempdirs
[] = {
1657 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1662 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1664 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1665 temporary files and assume "/tmp" if $TMPDIR is unset, which
1666 will break on DOS/Windows. Refuse to work if we cannot find
1667 a directory, not even "c:/", usable for that purpose. */
1668 for (i
= 0; i
< imax
; i
++)
1670 const char *tmp
= tempdirs
[i
];
1673 tmp
= getenv (tmp
+ 1);
1674 /* Note that `access' can lie to us if the directory resides on a
1675 read-only filesystem, like CD-ROM or a write-protected floppy.
1676 The only way to be really sure is to actually create a file and
1677 see if it succeeds. But I think that's too much to ask. */
1679 /* MSVCRT's _access crashes with D_OK. */
1680 if (tmp
&& sys_access (tmp
, D_OK
) == 0)
1682 char * var
= alloca (strlen (tmp
) + 8);
1683 sprintf (var
, "TMPDIR=%s", tmp
);
1684 _putenv (strdup (var
));
1691 Fcons (build_string ("no usable temporary directories found!!"),
1693 "While setting TMPDIR: ");
1695 /* Check for environment variables and use registry settings if they
1696 don't exist. Fallback on default values where applicable. */
1701 char locale_name
[32];
1702 struct stat ignored
;
1703 char default_home
[MAX_PATH
];
1706 static const struct env_entry
1713 {"PRELOAD_WINSOCK", NULL
},
1714 {"emacs_dir", "C:/emacs"},
1715 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1716 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1717 {"EMACSDATA", "%emacs_dir%/etc"},
1718 {"EMACSPATH", "%emacs_dir%/bin"},
1719 /* We no longer set INFOPATH because Info-default-directory-list
1721 /* {"INFOPATH", "%emacs_dir%/info"}, */
1722 {"EMACSDOC", "%emacs_dir%/etc"},
1727 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1729 /* We need to copy dflt_envvars[] and work on the copy because we
1730 don't want the dumped Emacs to inherit the values of
1731 environment variables we saw during dumping (which could be on
1732 a different system). The defaults above must be left intact. */
1733 struct env_entry env_vars
[N_ENV_VARS
];
1735 for (i
= 0; i
< N_ENV_VARS
; i
++)
1736 env_vars
[i
] = dflt_envvars
[i
];
1738 /* For backwards compatibility, check if a .emacs file exists in C:/
1739 If not, then we can try to default to the appdata directory under the
1740 user's profile, which is more likely to be writable. */
1741 if (stat ("C:/.emacs", &ignored
) < 0)
1743 HRESULT profile_result
;
1744 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1745 of Windows 95 and NT4 that have not been updated to include
1747 ShGetFolderPath_fn get_folder_path
;
1748 get_folder_path
= (ShGetFolderPath_fn
)
1749 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1751 if (get_folder_path
!= NULL
)
1753 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1756 /* If we can't get the appdata dir, revert to old behavior. */
1757 if (profile_result
== S_OK
)
1759 env_vars
[0].def_value
= default_home
;
1765 /* Get default locale info and use it for LANG. */
1766 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1767 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1768 locale_name
, sizeof (locale_name
)))
1770 for (i
= 0; i
< N_ENV_VARS
; i
++)
1772 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1774 env_vars
[i
].def_value
= locale_name
;
1780 /* When Emacs is invoked with --no-site-lisp, we must remove the
1781 site-lisp directories from the default value of EMACSLOADPATH.
1782 This assumes that the site-lisp entries are at the front, and
1783 that additional entries do exist. */
1786 for (i
= 0; i
< N_ENV_VARS
; i
++)
1788 if (strcmp (env_vars
[i
].name
, "EMACSLOADPATH") == 0)
1791 while ((site
= strstr (env_vars
[i
].def_value
, "site-lisp")))
1792 env_vars
[i
].def_value
= strchr (site
, ';') + 1;
1798 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1800 /* Treat emacs_dir specially: set it unconditionally based on our
1801 location, if it appears that we are running from the bin subdir
1802 of a standard installation. */
1805 char modname
[MAX_PATH
];
1807 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1809 if ((p
= strrchr (modname
, '\\')) == NULL
)
1813 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1815 char buf
[SET_ENV_BUF_SIZE
];
1818 for (p
= modname
; *p
; p
++)
1819 if (*p
== '\\') *p
= '/';
1821 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1822 _putenv (strdup (buf
));
1824 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1826 /* FIXME: should use substring of get_emacs_configuration ().
1827 But I don't think the Windows build supports alpha, mips etc
1828 anymore, so have taken the easy option for now. */
1829 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1832 p
= strrchr (modname
, '\\');
1836 p
= strrchr (modname
, '\\');
1837 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1839 char buf
[SET_ENV_BUF_SIZE
];
1842 for (p
= modname
; *p
; p
++)
1843 if (*p
== '\\') *p
= '/';
1845 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1846 _putenv (strdup (buf
));
1852 for (i
= 0; i
< N_ENV_VARS
; i
++)
1854 if (!getenv (env_vars
[i
].name
))
1858 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1859 /* Also ignore empty environment variables. */
1863 lpval
= env_vars
[i
].def_value
;
1864 dwType
= REG_EXPAND_SZ
;
1866 if (!strcmp (env_vars
[i
].name
, "HOME") && !appdata
)
1867 Vdelayed_warnings_list
1868 = Fcons (listn (CONSTYPE_HEAP
, 2,
1869 intern ("initialization"),
1870 build_string ("Setting HOME to C:\\ by default is deprecated")),
1871 Vdelayed_warnings_list
);
1876 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1878 if (dwType
== REG_EXPAND_SZ
)
1879 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1880 else if (dwType
== REG_SZ
)
1881 strcpy (buf1
, lpval
);
1882 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1884 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1886 _putenv (strdup (buf2
));
1896 /* Rebuild system configuration to reflect invoking system. */
1897 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1899 /* Another special case: on NT, the PATH variable is actually named
1900 "Path" although cmd.exe (perhaps NT itself) arranges for
1901 environment variable lookup and setting to be case insensitive.
1902 However, Emacs assumes a fully case sensitive environment, so we
1903 need to change "Path" to "PATH" to match the expectations of
1904 various elisp packages. We do this by the sneaky method of
1905 modifying the string in the C runtime environ entry.
1907 The same applies to COMSPEC. */
1911 for (envp
= environ
; *envp
; envp
++)
1912 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1913 memcpy (*envp
, "PATH=", 5);
1914 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1915 memcpy (*envp
, "COMSPEC=", 8);
1918 /* Remember the initial working directory for getwd. */
1919 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
1920 Does it matter anywhere in Emacs? */
1921 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1925 static char modname
[MAX_PATH
];
1927 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1932 /* Determine if there is a middle mouse button, to allow parse_button
1933 to decide whether right mouse events should be mouse-2 or
1935 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1940 /* Called from expand-file-name when default-directory is not a string. */
1943 emacs_root_dir (void)
1945 static char root_dir
[FILENAME_MAX
];
1948 p
= getenv ("emacs_dir");
1951 strcpy (root_dir
, p
);
1952 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1953 dostounix_filename (root_dir
);
1957 /* We don't have scripts to automatically determine the system configuration
1958 for Emacs before it's compiled, and we don't want to have to make the
1959 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1963 get_emacs_configuration (void)
1965 char *arch
, *oem
, *os
;
1967 static char configuration_buffer
[32];
1969 /* Determine the processor type. */
1970 switch (get_processor_type ())
1973 #ifdef PROCESSOR_INTEL_386
1974 case PROCESSOR_INTEL_386
:
1975 case PROCESSOR_INTEL_486
:
1976 case PROCESSOR_INTEL_PENTIUM
:
1981 #ifdef PROCESSOR_MIPS_R2000
1982 case PROCESSOR_MIPS_R2000
:
1983 case PROCESSOR_MIPS_R3000
:
1984 case PROCESSOR_MIPS_R4000
:
1989 #ifdef PROCESSOR_ALPHA_21064
1990 case PROCESSOR_ALPHA_21064
:
2000 /* Use the OEM field to reflect the compiler/library combination. */
2002 #define COMPILER_NAME "msvc"
2005 #define COMPILER_NAME "mingw"
2007 #define COMPILER_NAME "unknown"
2010 oem
= COMPILER_NAME
;
2012 switch (osinfo_cache
.dwPlatformId
) {
2013 case VER_PLATFORM_WIN32_NT
:
2015 build_num
= osinfo_cache
.dwBuildNumber
;
2017 case VER_PLATFORM_WIN32_WINDOWS
:
2018 if (osinfo_cache
.dwMinorVersion
== 0) {
2023 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
2025 case VER_PLATFORM_WIN32s
:
2026 /* Not supported, should not happen. */
2028 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
2036 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
2037 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
2038 get_w32_major_version (), get_w32_minor_version (), build_num
);
2040 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
2043 return configuration_buffer
;
2047 get_emacs_configuration_options (void)
2049 static char *options_buffer
;
2050 char cv
[32]; /* Enough for COMPILER_VERSION. */
2052 cv
, /* To be filled later. */
2056 #ifdef ENABLE_CHECKING
2057 " --enable-checking",
2059 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2060 with a starting space to save work here. */
2062 " --cflags", USER_CFLAGS
,
2065 " --ldflags", USER_LDFLAGS
,
2072 /* Work out the effective configure options for this build. */
2074 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2077 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2079 #define COMPILER_VERSION ""
2083 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
2084 return "Error: not enough space for compiler version";
2085 cv
[sizeof (cv
) - 1] = '\0';
2087 for (i
= 0; options
[i
]; i
++)
2088 size
+= strlen (options
[i
]);
2090 options_buffer
= xmalloc (size
+ 1);
2091 options_buffer
[0] = '\0';
2093 for (i
= 0; options
[i
]; i
++)
2094 strcat (options_buffer
, options
[i
]);
2096 return options_buffer
;
2100 #include <sys/timeb.h>
2102 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2104 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
2109 tv
->tv_sec
= tb
.time
;
2110 tv
->tv_usec
= tb
.millitm
* 1000L;
2111 /* Implementation note: _ftime sometimes doesn't update the dstflag
2112 according to the new timezone when the system timezone is
2113 changed. We could fix that by using GetSystemTime and
2114 GetTimeZoneInformation, but that doesn't seem necessary, since
2115 Emacs always calls gettimeofday with the 2nd argument NULL (see
2116 current_emacs_time). */
2119 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
2120 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
2124 /* Emulate fdutimens. */
2126 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2127 TIMESPEC[0] and TIMESPEC[1], respectively.
2128 FD must be either negative -- in which case it is ignored --
2129 or a file descriptor that is open on FILE.
2130 If FD is nonnegative, then FILE can be NULL, which means
2131 use just futimes instead of utimes.
2132 If TIMESPEC is null, FAIL.
2133 Return 0 on success, -1 (setting errno) on failure. */
2136 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
2145 if (fd
< 0 && !file
)
2150 ut
.actime
= timespec
[0].tv_sec
;
2151 ut
.modtime
= timespec
[1].tv_sec
;
2153 return _futime (fd
, &ut
);
2155 return _utime (file
, &ut
);
2159 /* ------------------------------------------------------------------------- */
2160 /* IO support and wrapper functions for the Windows API. */
2161 /* ------------------------------------------------------------------------- */
2163 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2164 on network directories, so we handle that case here.
2165 (Ulrich Leodolter, 1/11/95). */
2167 sys_ctime (const time_t *t
)
2169 char *str
= (char *) ctime (t
);
2170 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2173 /* Emulate sleep...we could have done this with a define, but that
2174 would necessitate including windows.h in the files that used it.
2175 This is much easier. */
2177 sys_sleep (int seconds
)
2179 Sleep (seconds
* 1000);
2182 /* Internal MSVC functions for low-level descriptor munging */
2183 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2184 extern int __cdecl
_free_osfhnd (int fd
);
2186 /* parallel array of private info on file handles */
2187 filedesc fd_info
[ MAXDESC
];
2189 typedef struct volume_info_data
{
2190 struct volume_info_data
* next
;
2192 /* time when info was obtained */
2195 /* actual volume info */
2204 /* Global referenced by various functions. */
2205 static volume_info_data volume_info
;
2207 /* Vector to indicate which drives are local and fixed (for which cached
2208 data never expires). */
2209 static BOOL fixed_drives
[26];
2211 /* Consider cached volume information to be stale if older than 10s,
2212 at least for non-local drives. Info for fixed drives is never stale. */
2213 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2214 #define VOLINFO_STILL_VALID( root_dir, info ) \
2215 ( ( isalpha (root_dir[0]) && \
2216 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2217 || GetTickCount () - info->timestamp < 10000 )
2219 /* Cache support functions. */
2221 /* Simple linked list with linear search is sufficient. */
2222 static volume_info_data
*volume_cache
= NULL
;
2224 static volume_info_data
*
2225 lookup_volume_info (char * root_dir
)
2227 volume_info_data
* info
;
2229 for (info
= volume_cache
; info
; info
= info
->next
)
2230 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2236 add_volume_info (char * root_dir
, volume_info_data
* info
)
2238 info
->root_dir
= xstrdup (root_dir
);
2239 info
->next
= volume_cache
;
2240 volume_cache
= info
;
2244 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2245 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2246 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2247 static volume_info_data
*
2248 GetCachedVolumeInformation (char * root_dir
)
2250 volume_info_data
* info
;
2251 char default_root
[ MAX_PATH
];
2253 /* NULL for root_dir means use root from current directory. */
2254 if (root_dir
== NULL
)
2256 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2258 parse_root (default_root
, &root_dir
);
2260 root_dir
= default_root
;
2263 /* Local fixed drives can be cached permanently. Removable drives
2264 cannot be cached permanently, since the volume name and serial
2265 number (if nothing else) can change. Remote drives should be
2266 treated as if they are removable, since there is no sure way to
2267 tell whether they are or not. Also, the UNC association of drive
2268 letters mapped to remote volumes can be changed at any time (even
2269 by other processes) without notice.
2271 As a compromise, so we can benefit from caching info for remote
2272 volumes, we use a simple expiry mechanism to invalidate cache
2273 entries that are more than ten seconds old. */
2276 /* No point doing this, because WNetGetConnection is even slower than
2277 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2278 GetDriveType is about the only call of this type which does not
2279 involve network access, and so is extremely quick). */
2281 /* Map drive letter to UNC if remote. */
2282 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2284 char remote_name
[ 256 ];
2285 char drive
[3] = { root_dir
[0], ':' };
2287 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2289 /* do something */ ;
2293 info
= lookup_volume_info (root_dir
);
2295 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2303 /* Info is not cached, or is stale. */
2304 if (!GetVolumeInformation (root_dir
,
2305 name
, sizeof (name
),
2309 type
, sizeof (type
)))
2312 /* Cache the volume information for future use, overwriting existing
2313 entry if present. */
2316 info
= xmalloc (sizeof (volume_info_data
));
2317 add_volume_info (root_dir
, info
);
2325 info
->name
= xstrdup (name
);
2326 info
->serialnum
= serialnum
;
2327 info
->maxcomp
= maxcomp
;
2328 info
->flags
= flags
;
2329 info
->type
= xstrdup (type
);
2330 info
->timestamp
= GetTickCount ();
2336 /* Get information on the volume where NAME is held; set path pointer to
2337 start of pathname in NAME (past UNC header\volume header if present),
2338 if pPath is non-NULL.
2340 Note: if NAME includes symlinks, the information is for the volume
2341 of the symlink, not of its target. That's because, even though
2342 GetVolumeInformation returns information about the symlink target
2343 of its argument, we only pass the root directory to
2344 GetVolumeInformation, not the full NAME. */
2346 get_volume_info (const char * name
, const char ** pPath
)
2348 char temp
[MAX_PATH
];
2349 char *rootname
= NULL
; /* default to current volume */
2350 volume_info_data
* info
;
2355 /* Find the root name of the volume if given. */
2356 if (isalpha (name
[0]) && name
[1] == ':')
2364 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2371 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2384 info
= GetCachedVolumeInformation (rootname
);
2387 /* Set global referenced by other functions. */
2388 volume_info
= *info
;
2394 /* Determine if volume is FAT format (ie. only supports short 8.3
2395 names); also set path pointer to start of pathname in name, if
2396 pPath is non-NULL. */
2398 is_fat_volume (const char * name
, const char ** pPath
)
2400 if (get_volume_info (name
, pPath
))
2401 return (volume_info
.maxcomp
== 12);
2405 /* Map filename to a valid 8.3 name if necessary.
2406 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2408 map_w32_filename (const char * name
, const char ** pPath
)
2410 static char shortname
[MAX_PATH
];
2411 char * str
= shortname
;
2414 const char * save_name
= name
;
2417 if (strlen (name
) >= MAX_PATH
)
2419 /* Return a filename which will cause callers to fail. */
2420 strcpy (shortname
, "?");
2424 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2426 register int left
= 8; /* maximum number of chars in part */
2427 register int extn
= 0; /* extension added? */
2428 register int dots
= 2; /* maximum number of dots allowed */
2431 *str
++ = *name
++; /* skip past UNC header */
2433 while ((c
= *name
++))
2440 *str
++ = (c
== ':' ? ':' : '\\');
2441 extn
= 0; /* reset extension flags */
2442 dots
= 2; /* max 2 dots */
2443 left
= 8; /* max length 8 for main part */
2448 /* Convert path components of the form .xxx to _xxx,
2449 but leave . and .. as they are. This allows .emacs
2450 to be read as _emacs, for example. */
2454 IS_DIRECTORY_SEP (*name
))
2469 extn
= 1; /* we've got an extension */
2470 left
= 3; /* 3 chars in extension */
2474 /* any embedded dots after the first are converted to _ */
2479 case '#': /* don't lose these, they're important */
2481 str
[-1] = c
; /* replace last character of part */
2486 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2488 dots
= 0; /* started a path component */
2497 strcpy (shortname
, name
);
2498 unixtodos_filename (shortname
);
2502 *pPath
= shortname
+ (path
- save_name
);
2508 is_exec (const char * name
)
2510 char * p
= strrchr (name
, '.');
2513 && (xstrcasecmp (p
, ".exe") == 0 ||
2514 xstrcasecmp (p
, ".com") == 0 ||
2515 xstrcasecmp (p
, ".bat") == 0 ||
2516 xstrcasecmp (p
, ".cmd") == 0));
2519 /* Emulate the Unix directory procedures opendir, closedir,
2520 and readdir. We can't use the procedures supplied in sysdep.c,
2521 so we provide them here. */
2523 struct direct dir_static
; /* simulated directory contents */
2524 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2525 static int dir_is_fat
;
2526 static char dir_pathname
[MAXPATHLEN
+1];
2527 static WIN32_FIND_DATA dir_find_data
;
2529 /* Support shares on a network resource as subdirectories of a read-only
2531 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2532 static HANDLE
open_unc_volume (const char *);
2533 static char *read_unc_volume (HANDLE
, char *, int);
2534 static void close_unc_volume (HANDLE
);
2537 opendir (char *filename
)
2541 /* Opening is done by FindFirstFile. However, a read is inherent to
2542 this operation, so we defer the open until read time. */
2544 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2546 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2549 /* Note: We don't support traversal of UNC volumes via symlinks.
2550 Doing so would mean punishing 99.99% of use cases by resolving
2551 all the possible symlinks in FILENAME, recursively. */
2552 if (is_unc_volume (filename
))
2554 wnet_enum_handle
= open_unc_volume (filename
);
2555 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2559 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2566 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2567 dir_pathname
[MAXPATHLEN
] = '\0';
2568 /* Note: We don't support symlinks to file names on FAT volumes.
2569 Doing so would mean punishing 99.99% of use cases by resolving
2570 all the possible symlinks in FILENAME, recursively. */
2571 dir_is_fat
= is_fat_volume (filename
, NULL
);
2577 closedir (DIR *dirp
)
2579 /* If we have a find-handle open, close it. */
2580 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2582 FindClose (dir_find_handle
);
2583 dir_find_handle
= INVALID_HANDLE_VALUE
;
2585 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2587 close_unc_volume (wnet_enum_handle
);
2588 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2590 xfree ((char *) dirp
);
2596 int downcase
= !NILP (Vw32_downcase_file_names
);
2598 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2600 if (!read_unc_volume (wnet_enum_handle
,
2601 dir_find_data
.cFileName
,
2605 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2606 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2608 char filename
[MAXNAMLEN
+ 3];
2611 strcpy (filename
, dir_pathname
);
2612 ln
= strlen (filename
) - 1;
2613 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2614 strcat (filename
, "\\");
2615 strcat (filename
, "*");
2617 /* Note: No need to resolve symlinks in FILENAME, because
2618 FindFirst opens the directory that is the target of a
2620 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2622 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2627 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2631 /* Emacs never uses this value, so don't bother making it match
2632 value returned by stat(). */
2633 dir_static
.d_ino
= 1;
2635 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2637 /* If the file name in cFileName[] includes `?' characters, it means
2638 the original file name used characters that cannot be represented
2639 by the current ANSI codepage. To avoid total lossage, retrieve
2640 the short 8+3 alias of the long file name. */
2641 if (_mbspbrk (dir_static
.d_name
, "?"))
2643 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2644 downcase
= 1; /* 8+3 aliases are returned in all caps */
2646 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2647 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2648 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2650 /* If the file name in cFileName[] includes `?' characters, it means
2651 the original file name used characters that cannot be represented
2652 by the current ANSI codepage. To avoid total lossage, retrieve
2653 the short 8+3 alias of the long file name. */
2654 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2656 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2657 /* 8+3 aliases are returned in all caps, which could break
2658 various alists that look at filenames' extensions. */
2662 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2663 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2665 _strlwr (dir_static
.d_name
);
2669 for (p
= dir_static
.d_name
; *p
; p
++)
2670 if (*p
>= 'a' && *p
<= 'z')
2673 _strlwr (dir_static
.d_name
);
2680 open_unc_volume (const char *path
)
2686 nr
.dwScope
= RESOURCE_GLOBALNET
;
2687 nr
.dwType
= RESOURCETYPE_DISK
;
2688 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2689 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2690 nr
.lpLocalName
= NULL
;
2691 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2692 nr
.lpComment
= NULL
;
2693 nr
.lpProvider
= NULL
;
2695 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2696 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2698 if (result
== NO_ERROR
)
2701 return INVALID_HANDLE_VALUE
;
2705 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2709 DWORD bufsize
= 512;
2714 buffer
= alloca (bufsize
);
2715 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
2716 if (result
!= NO_ERROR
)
2719 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2720 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2722 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2725 strncpy (readbuf
, ptr
, size
);
2730 close_unc_volume (HANDLE henum
)
2732 if (henum
!= INVALID_HANDLE_VALUE
)
2733 WNetCloseEnum (henum
);
2737 unc_volume_file_attributes (const char *path
)
2742 henum
= open_unc_volume (path
);
2743 if (henum
== INVALID_HANDLE_VALUE
)
2746 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2748 close_unc_volume (henum
);
2753 /* Ensure a network connection is authenticated. */
2755 logon_network_drive (const char *path
)
2757 NETRESOURCE resource
;
2758 char share
[MAX_PATH
];
2763 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2764 drvtype
= DRIVE_REMOTE
;
2765 else if (path
[0] == '\0' || path
[1] != ':')
2766 drvtype
= GetDriveType (NULL
);
2773 drvtype
= GetDriveType (drive
);
2776 /* Only logon to networked drives. */
2777 if (drvtype
!= DRIVE_REMOTE
)
2781 strncpy (share
, path
, MAX_PATH
);
2782 /* Truncate to just server and share name. */
2783 for (i
= 2; i
< MAX_PATH
; i
++)
2785 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2792 resource
.dwType
= RESOURCETYPE_DISK
;
2793 resource
.lpLocalName
= NULL
;
2794 resource
.lpRemoteName
= share
;
2795 resource
.lpProvider
= NULL
;
2797 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2800 /* Shadow some MSVC runtime functions to map requests for long filenames
2801 to reasonable short names if necessary. This was originally added to
2802 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2806 sys_access (const char * path
, int mode
)
2810 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
2811 newer versions blow up when passed D_OK. */
2812 path
= map_w32_filename (path
, NULL
);
2813 /* If the last element of PATH is a symlink, we need to resolve it
2814 to get the attributes of its target file. Note: any symlinks in
2815 PATH elements other than the last one are transparently resolved
2816 by GetFileAttributes below. */
2817 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
2818 path
= chase_symlinks (path
);
2820 if ((attributes
= GetFileAttributes (path
)) == -1)
2822 DWORD w32err
= GetLastError ();
2826 case ERROR_INVALID_NAME
:
2827 case ERROR_BAD_PATHNAME
:
2828 if (is_unc_volume (path
))
2830 attributes
= unc_volume_file_attributes (path
);
2831 if (attributes
== -1)
2839 case ERROR_FILE_NOT_FOUND
:
2840 case ERROR_BAD_NETPATH
:
2849 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2854 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2859 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2868 sys_chdir (const char * path
)
2870 return _chdir (map_w32_filename (path
, NULL
));
2874 sys_chmod (const char * path
, int mode
)
2876 path
= chase_symlinks (map_w32_filename (path
, NULL
));
2877 return _chmod (path
, mode
);
2881 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2883 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2889 sys_creat (const char * path
, int mode
)
2891 return _creat (map_w32_filename (path
, NULL
), mode
);
2895 sys_fopen (const char * path
, const char * mode
)
2899 const char * mode_save
= mode
;
2901 /* Force all file handles to be non-inheritable. This is necessary to
2902 ensure child processes don't unwittingly inherit handles that might
2903 prevent future file access. */
2907 else if (mode
[0] == 'w' || mode
[0] == 'a')
2908 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2912 /* Only do simplistic option parsing. */
2916 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2919 else if (mode
[0] == 'b')
2924 else if (mode
[0] == 't')
2931 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2935 return _fdopen (fd
, mode_save
);
2938 /* This only works on NTFS volumes, but is useful to have. */
2940 sys_link (const char * old
, const char * new)
2944 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2946 if (old
== NULL
|| new == NULL
)
2952 strcpy (oldname
, map_w32_filename (old
, NULL
));
2953 strcpy (newname
, map_w32_filename (new, NULL
));
2955 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2956 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2957 if (fileh
!= INVALID_HANDLE_VALUE
)
2961 /* Confusingly, the "alternate" stream name field does not apply
2962 when restoring a hard link, and instead contains the actual
2963 stream data for the link (ie. the name of the link to create).
2964 The WIN32_STREAM_ID structure before the cStreamName field is
2965 the stream header, which is then immediately followed by the
2969 WIN32_STREAM_ID wid
;
2970 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2973 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2974 data
.wid
.cStreamName
, MAX_PATH
);
2977 LPVOID context
= NULL
;
2980 data
.wid
.dwStreamId
= BACKUP_LINK
;
2981 data
.wid
.dwStreamAttributes
= 0;
2982 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2983 data
.wid
.Size
.HighPart
= 0;
2984 data
.wid
.dwStreamNameSize
= 0;
2986 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2987 offsetof (WIN32_STREAM_ID
, cStreamName
)
2988 + data
.wid
.Size
.LowPart
,
2989 &wbytes
, FALSE
, FALSE
, &context
)
2990 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2997 /* Should try mapping GetLastError to errno; for now just
2998 indicate a general error (eg. links not supported). */
2999 errno
= EINVAL
; // perhaps EMLINK?
3003 CloseHandle (fileh
);
3012 sys_mkdir (const char * path
)
3014 return _mkdir (map_w32_filename (path
, NULL
));
3017 /* Because of long name mapping issues, we need to implement this
3018 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
3019 a unique name, instead of setting the input template to an empty
3022 Standard algorithm seems to be use pid or tid with a letter on the
3023 front (in place of the 6 X's) and cycle through the letters to find a
3024 unique name. We extend that to allow any reasonable character as the
3025 first of the 6 X's. */
3027 sys_mktemp (char * template)
3031 unsigned uid
= GetCurrentThreadId ();
3032 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3034 if (template == NULL
)
3036 p
= template + strlen (template);
3038 /* replace up to the last 5 X's with uid in decimal */
3039 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
3041 p
[0] = '0' + uid
% 10;
3045 if (i
< 0 && p
[0] == 'X')
3050 int save_errno
= errno
;
3051 p
[0] = first_char
[i
];
3052 if (sys_access (template, 0) < 0)
3058 while (++i
< sizeof (first_char
));
3061 /* Template is badly formed or else we can't generate a unique name,
3062 so return empty string */
3068 sys_open (const char * path
, int oflag
, int mode
)
3070 const char* mpath
= map_w32_filename (path
, NULL
);
3071 /* Try to open file without _O_CREAT, to be able to write to hidden
3072 and system files. Force all file handles to be
3074 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3077 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
3081 sys_rename (const char * oldname
, const char * newname
)
3084 char temp
[MAX_PATH
];
3088 /* MoveFile on Windows 95 doesn't correctly change the short file name
3089 alias in a number of circumstances (it is not easy to predict when
3090 just by looking at oldname and newname, unfortunately). In these
3091 cases, renaming through a temporary name avoids the problem.
3093 A second problem on Windows 95 is that renaming through a temp name when
3094 newname is uppercase fails (the final long name ends up in
3095 lowercase, although the short alias might be uppercase) UNLESS the
3096 long temp name is not 8.3.
3098 So, on Windows 95 we always rename through a temp name, and we make sure
3099 the temp name has a long extension to ensure correct renaming. */
3101 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3103 /* volume_info is set indirectly by map_w32_filename. */
3104 oldname_dev
= volume_info
.serialnum
;
3106 if (os_subtype
== OS_9X
)
3112 oldname
= map_w32_filename (oldname
, NULL
);
3113 if ((o
= strrchr (oldname
, '\\')))
3116 o
= (char *) oldname
;
3118 if ((p
= strrchr (temp
, '\\')))
3125 /* Force temp name to require a manufactured 8.3 alias - this
3126 seems to make the second rename work properly. */
3127 sprintf (p
, "_.%s.%u", o
, i
);
3129 result
= rename (oldname
, temp
);
3131 /* This loop must surely terminate! */
3132 while (result
< 0 && errno
== EEXIST
);
3137 /* Emulate Unix behavior - newname is deleted if it already exists
3138 (at least if it is a file; don't do this for directories).
3140 Since we mustn't do this if we are just changing the case of the
3141 file name (we would end up deleting the file we are trying to
3142 rename!), we let rename detect if the destination file already
3143 exists - that way we avoid the possible pitfalls of trying to
3144 determine ourselves whether two names really refer to the same
3145 file, which is not always possible in the general case. (Consider
3146 all the permutations of shared or subst'd drives, etc.) */
3148 newname
= map_w32_filename (newname
, NULL
);
3150 /* volume_info is set indirectly by map_w32_filename. */
3151 newname_dev
= volume_info
.serialnum
;
3153 result
= rename (temp
, newname
);
3157 DWORD w32err
= GetLastError ();
3160 && newname_dev
!= oldname_dev
)
3162 /* The implementation of `rename' on Windows does not return
3163 errno = EXDEV when you are moving a directory to a
3164 different storage device (ex. logical disk). It returns
3165 EACCES instead. So here we handle such situations and
3169 if ((attributes
= GetFileAttributes (temp
)) != -1
3170 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3173 else if (errno
== EEXIST
)
3175 if (_chmod (newname
, 0666) != 0)
3177 if (_unlink (newname
) != 0)
3179 result
= rename (temp
, newname
);
3181 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
3182 && is_symlink (temp
))
3184 /* This is Windows prohibiting the user from creating a
3185 symlink in another place, since that requires
3195 sys_rmdir (const char * path
)
3197 return _rmdir (map_w32_filename (path
, NULL
));
3201 sys_unlink (const char * path
)
3203 path
= map_w32_filename (path
, NULL
);
3205 /* On Unix, unlink works without write permission. */
3206 _chmod (path
, 0666);
3207 return _unlink (path
);
3210 static FILETIME utc_base_ft
;
3211 static ULONGLONG utc_base
; /* In 100ns units */
3212 static int init
= 0;
3214 #define FILETIME_TO_U64(result, ft) \
3216 ULARGE_INTEGER uiTemp; \
3217 uiTemp.LowPart = (ft).dwLowDateTime; \
3218 uiTemp.HighPart = (ft).dwHighDateTime; \
3219 result = uiTemp.QuadPart; \
3223 initialize_utc_base (void)
3225 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3234 st
.wMilliseconds
= 0;
3236 SystemTimeToFileTime (&st
, &utc_base_ft
);
3237 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3241 convert_time (FILETIME ft
)
3247 initialize_utc_base ();
3251 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3254 FILETIME_TO_U64 (tmp
, ft
);
3255 return (time_t) ((tmp
- utc_base
) / 10000000L);
3259 convert_from_time_t (time_t time
, FILETIME
* pft
)
3265 initialize_utc_base ();
3269 /* time in 100ns units since 1-Jan-1601 */
3270 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3271 pft
->dwHighDateTime
= tmp
.HighPart
;
3272 pft
->dwLowDateTime
= tmp
.LowPart
;
3276 /* No reason to keep this; faking inode values either by hashing or even
3277 using the file index from GetInformationByHandle, is not perfect and
3278 so by default Emacs doesn't use the inode values on Windows.
3279 Instead, we now determine file-truename correctly (except for
3280 possible drive aliasing etc). */
3282 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3284 hashval (const unsigned char * str
)
3289 h
= (h
<< 4) + *str
++;
3295 /* Return the hash value of the canonical pathname, excluding the
3296 drive/UNC header, to get a hopefully unique inode number. */
3298 generate_inode_val (const char * name
)
3300 char fullname
[ MAX_PATH
];
3304 /* Get the truly canonical filename, if it exists. (Note: this
3305 doesn't resolve aliasing due to subst commands, or recognize hard
3307 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3310 parse_root (fullname
, &p
);
3311 /* Normal W32 filesystems are still case insensitive. */
3318 static PSECURITY_DESCRIPTOR
3319 get_file_security_desc_by_handle (HANDLE h
)
3321 PSECURITY_DESCRIPTOR psd
= NULL
;
3323 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3324 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3326 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
3327 NULL
, NULL
, NULL
, NULL
, &psd
);
3328 if (err
!= ERROR_SUCCESS
)
3334 static PSECURITY_DESCRIPTOR
3335 get_file_security_desc_by_name (const char *fname
)
3337 PSECURITY_DESCRIPTOR psd
= NULL
;
3339 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3340 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3342 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3344 err
= GetLastError ();
3345 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3349 psd
= xmalloc (sd_len
);
3350 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3362 unsigned n_subauthorities
;
3364 /* Use the last sub-authority value of the RID, the relative
3365 portion of the SID, as user/group ID. */
3366 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3367 if (n_subauthorities
< 1)
3368 return 0; /* the "World" RID */
3369 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3372 /* Caching SID and account values for faster lokup. */
3375 # define FLEXIBLE_ARRAY_MEMBER
3377 # define FLEXIBLE_ARRAY_MEMBER 1
3382 struct w32_id
*next
;
3384 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3387 static struct w32_id
*w32_idlist
;
3390 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3392 struct w32_id
*tail
, *found
;
3394 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3396 if (equal_sid ((PSID
)tail
->sid
, sid
))
3405 strcpy (name
, found
->name
);
3413 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3416 struct w32_id
*new_entry
;
3418 /* We don't want to leave behind stale cache from when Emacs was
3422 sid_len
= get_length_sid (sid
);
3423 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3426 new_entry
->rid
= id
;
3427 strcpy (new_entry
->name
, name
);
3428 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3429 new_entry
->next
= w32_idlist
;
3430 w32_idlist
= new_entry
;
3439 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3440 unsigned *id
, char *nm
, int what
)
3443 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3445 SID_NAME_USE ignore
;
3447 DWORD name_len
= sizeof (name
);
3449 DWORD domain_len
= sizeof (domain
);
3455 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3456 else if (what
== GID
)
3457 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3461 if (!result
|| !is_valid_sid (sid
))
3463 else if (!w32_cached_id (sid
, id
, nm
))
3465 /* If FNAME is a UNC, we need to lookup account on the
3466 specified machine. */
3467 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3468 && fname
[2] != '\0')
3473 for (s
= fname
+ 2, p
= machine
;
3474 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3480 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3481 domain
, &domain_len
, &ignore
)
3482 || name_len
> UNLEN
+1)
3486 *id
= get_rid (sid
);
3488 w32_add_to_cache (sid
, *id
, name
);
3495 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3499 int dflt_usr
= 0, dflt_grp
= 0;
3508 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3510 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3513 /* Consider files to belong to current user/group, if we cannot get
3514 more accurate information. */
3517 st
->st_uid
= dflt_passwd
.pw_uid
;
3518 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3522 st
->st_gid
= dflt_passwd
.pw_gid
;
3523 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3527 /* Return non-zero if NAME is a potentially slow filesystem. */
3529 is_slow_fs (const char *name
)
3534 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3535 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3536 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3537 devtype
= GetDriveType (NULL
); /* use root of current drive */
3540 /* GetDriveType needs the root directory of the drive. */
3541 strncpy (drive_root
, name
, 2);
3542 drive_root
[2] = '\\';
3543 drive_root
[3] = '\0';
3544 devtype
= GetDriveType (drive_root
);
3546 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3549 /* MSVC stat function can't cope with UNC names and has other bugs, so
3550 replace it with our own. This also allows us to calculate consistent
3551 inode values and owner/group without hacks in the main Emacs code. */
3554 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
3556 char *name
, *save_name
, *r
;
3557 WIN32_FIND_DATA wfd
;
3559 unsigned __int64 fake_inode
= 0;
3562 int rootdir
= FALSE
;
3563 PSECURITY_DESCRIPTOR psd
= NULL
;
3564 int is_a_symlink
= 0;
3565 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
3566 DWORD access_rights
= 0;
3567 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
3568 FILETIME ctime
, atime
, wtime
;
3570 if (path
== NULL
|| buf
== NULL
)
3576 save_name
= name
= (char *) map_w32_filename (path
, &path
);
3577 /* Must be valid filename, no wild cards or other invalid
3578 characters. We use _mbspbrk to support multibyte strings that
3579 might look to strpbrk as if they included literal *, ?, and other
3580 characters mentioned below that are disallowed by Windows
3582 if (_mbspbrk (name
, "*?|<>\""))
3588 /* Remove trailing directory separator, unless name is the root
3589 directory of a drive or UNC volume in which case ensure there
3590 is a trailing separator. */
3591 len
= strlen (name
);
3592 name
= strcpy (alloca (len
+ 2), name
);
3594 /* Avoid a somewhat costly call to is_symlink if the filesystem
3595 doesn't support symlinks. */
3596 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
3597 is_a_symlink
= is_symlink (name
);
3599 /* Plan A: Open the file and get all the necessary information via
3600 the resulting handle. This solves several issues in one blow:
3602 . retrieves attributes for the target of a symlink, if needed
3603 . gets attributes of root directories and symlinks pointing to
3604 root directories, thus avoiding the need for special-casing
3605 these and detecting them by examining the file-name format
3606 . retrieves more accurate attributes (e.g., non-zero size for
3607 some directories, esp. directories that are junction points)
3608 . correctly resolves "c:/..", "/.." and similar file names
3609 . avoids run-time penalties for 99% of use cases
3611 Plan A is always tried first, unless the user asked not to (but
3612 if the file is a symlink and we need to follow links, we try Plan
3613 A even if the user asked not to).
3615 If Plan A fails, we go to Plan B (below), where various
3616 potentially expensive techniques must be used to handle "special"
3617 files such as UNC volumes etc. */
3618 if (!(NILP (Vw32_get_true_file_attributes
)
3619 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3620 /* Following symlinks requires getting the info by handle. */
3621 || (is_a_symlink
&& follow_symlinks
))
3623 BY_HANDLE_FILE_INFORMATION info
;
3625 if (is_a_symlink
&& !follow_symlinks
)
3626 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
3627 /* READ_CONTROL access rights are required to get security info
3628 by handle. But if the OS doesn't support security in the
3629 first place, we don't need to try. */
3630 if (is_windows_9x () != TRUE
)
3631 access_rights
|= READ_CONTROL
;
3633 fh
= CreateFile (name
, access_rights
, 0, NULL
, OPEN_EXISTING
,
3635 /* If CreateFile fails with READ_CONTROL, try again with zero as
3637 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
3638 fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3640 if (fh
== INVALID_HANDLE_VALUE
)
3641 goto no_true_file_attributes
;
3643 /* This is more accurate in terms of getting the correct number
3644 of links, but is quite slow (it is noticeable when Emacs is
3645 making a list of file name completions). */
3646 if (GetFileInformationByHandle (fh
, &info
))
3648 nlinks
= info
.nNumberOfLinks
;
3649 /* Might as well use file index to fake inode values, but this
3650 is not guaranteed to be unique unless we keep a handle open
3651 all the time (even then there are situations where it is
3652 not unique). Reputedly, there are at most 48 bits of info
3653 (on NTFS, presumably less on FAT). */
3654 fake_inode
= info
.nFileIndexHigh
;
3656 fake_inode
+= info
.nFileIndexLow
;
3657 serialnum
= info
.dwVolumeSerialNumber
;
3658 fs_high
= info
.nFileSizeHigh
;
3659 fs_low
= info
.nFileSizeLow
;
3660 ctime
= info
.ftCreationTime
;
3661 atime
= info
.ftLastAccessTime
;
3662 wtime
= info
.ftLastWriteTime
;
3663 fattrs
= info
.dwFileAttributes
;
3667 /* We don't go to Plan B here, because it's not clear that
3668 it's a good idea. The only known use case where
3669 CreateFile succeeds, but GetFileInformationByHandle fails
3670 (with ERROR_INVALID_FUNCTION) is for character devices
3671 such as NUL, PRN, etc. For these, switching to Plan B is
3672 a net loss, because we lose the character device
3673 attribute returned by GetFileType below (FindFirstFile
3674 doesn't set that bit in the attributes), and the other
3675 fields don't make sense for character devices anyway.
3676 Emacs doesn't really care for non-file entities in the
3677 context of l?stat, so neither do we. */
3679 /* w32err is assigned so one could put a breakpoint here and
3680 examine its value, when GetFileInformationByHandle
3682 DWORD w32err
= GetLastError ();
3686 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
3692 /* Test for a symlink before testing for a directory, since
3693 symlinks to directories have the directory bit set, but we
3694 don't want them to appear as directories. */
3695 if (is_a_symlink
&& !follow_symlinks
)
3696 buf
->st_mode
= S_IFLNK
;
3697 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3698 buf
->st_mode
= S_IFDIR
;
3701 DWORD ftype
= GetFileType (fh
);
3705 case FILE_TYPE_DISK
:
3706 buf
->st_mode
= S_IFREG
;
3708 case FILE_TYPE_PIPE
:
3709 buf
->st_mode
= S_IFIFO
;
3711 case FILE_TYPE_CHAR
:
3712 case FILE_TYPE_UNKNOWN
:
3714 buf
->st_mode
= S_IFCHR
;
3717 /* We produce the fallback owner and group data, based on the
3718 current user that runs Emacs, in the following cases:
3720 . this is Windows 9X
3721 . getting security by handle failed, and we need to produce
3722 information for the target of a symlink (this is better
3723 than producing a potentially misleading info about the
3726 If getting security by handle fails, and we don't need to
3727 resolve symlinks, we try getting security by name. */
3728 if (is_windows_9x () != TRUE
)
3729 psd
= get_file_security_desc_by_handle (fh
);
3732 get_file_owner_and_group (psd
, name
, buf
);
3735 else if (is_windows_9x () == TRUE
)
3736 get_file_owner_and_group (NULL
, name
, buf
);
3737 else if (!(is_a_symlink
&& follow_symlinks
))
3739 psd
= get_file_security_desc_by_name (name
);
3740 get_file_owner_and_group (psd
, name
, buf
);
3744 get_file_owner_and_group (NULL
, name
, buf
);
3749 no_true_file_attributes
:
3750 /* Plan B: Either getting a handle on the file failed, or the
3751 caller explicitly asked us to not bother making this
3752 information more accurate.
3754 Implementation note: In Plan B, we never bother to resolve
3755 symlinks, even if we got here because we tried Plan A and
3756 failed. That's because, even if the caller asked for extra
3757 precision by setting Vw32_get_true_file_attributes to t,
3758 resolving symlinks requires acquiring a file handle to the
3759 symlink, which we already know will fail. And if the user
3760 did not ask for extra precision, resolving symlinks will fly
3761 in the face of that request, since the user then wants the
3762 lightweight version of the code. */
3763 rootdir
= (path
>= save_name
+ len
- 1
3764 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3766 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3767 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3768 if (IS_DIRECTORY_SEP (r
[0])
3769 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3772 /* Note: If NAME is a symlink to the root of a UNC volume
3773 (i.e. "\\SERVER"), we will not detect that here, and we will
3774 return data about the symlink as result of FindFirst below.
3775 This is unfortunate, but that marginal use case does not
3776 justify a call to chase_symlinks which would impose a penalty
3777 on all the other use cases. (We get here for symlinks to
3778 roots of UNC volumes because CreateFile above fails for them,
3779 unlike with symlinks to root directories X:\ of drives.) */
3780 if (is_unc_volume (name
))
3782 fattrs
= unc_volume_file_attributes (name
);
3786 ctime
= atime
= wtime
= utc_base_ft
;
3790 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3791 strcat (name
, "\\");
3792 if (GetDriveType (name
) < 2)
3798 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
3799 ctime
= atime
= wtime
= utc_base_ft
;
3803 if (IS_DIRECTORY_SEP (name
[len
-1]))
3806 /* (This is hacky, but helps when doing file completions on
3807 network drives.) Optimize by using information available from
3808 active readdir if possible. */
3809 len
= strlen (dir_pathname
);
3810 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3812 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3813 && !(is_a_symlink
&& follow_symlinks
)
3814 && strnicmp (save_name
, dir_pathname
, len
) == 0
3815 && IS_DIRECTORY_SEP (name
[len
])
3816 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3818 /* This was the last entry returned by readdir. */
3819 wfd
= dir_find_data
;
3823 logon_network_drive (name
);
3825 fh
= FindFirstFile (name
, &wfd
);
3826 if (fh
== INVALID_HANDLE_VALUE
)
3833 /* Note: if NAME is a symlink, the information we get from
3834 FindFirstFile is for the symlink, not its target. */
3835 fattrs
= wfd
.dwFileAttributes
;
3836 ctime
= wfd
.ftCreationTime
;
3837 atime
= wfd
.ftLastAccessTime
;
3838 wtime
= wfd
.ftLastWriteTime
;
3839 fs_high
= wfd
.nFileSizeHigh
;
3840 fs_low
= wfd
.nFileSizeLow
;
3843 serialnum
= volume_info
.serialnum
;
3845 if (is_a_symlink
&& !follow_symlinks
)
3846 buf
->st_mode
= S_IFLNK
;
3847 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3848 buf
->st_mode
= S_IFDIR
;
3850 buf
->st_mode
= S_IFREG
;
3852 get_file_owner_and_group (NULL
, name
, buf
);
3856 /* Not sure if there is any point in this. */
3857 if (!NILP (Vw32_generate_fake_inodes
))
3858 fake_inode
= generate_inode_val (name
);
3859 else if (fake_inode
== 0)
3861 /* For want of something better, try to make everything unique. */
3862 static DWORD gen_num
= 0;
3863 fake_inode
= ++gen_num
;
3867 buf
->st_ino
= fake_inode
;
3869 buf
->st_dev
= serialnum
;
3870 buf
->st_rdev
= serialnum
;
3872 buf
->st_size
= fs_high
;
3873 buf
->st_size
<<= 32;
3874 buf
->st_size
+= fs_low
;
3875 buf
->st_nlink
= nlinks
;
3877 /* Convert timestamps to Unix format. */
3878 buf
->st_mtime
= convert_time (wtime
);
3879 buf
->st_atime
= convert_time (atime
);
3880 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3881 buf
->st_ctime
= convert_time (ctime
);
3882 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3884 /* determine rwx permissions */
3885 if (is_a_symlink
&& !follow_symlinks
)
3886 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
3889 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
3890 permission
= S_IREAD
;
3892 permission
= S_IREAD
| S_IWRITE
;
3894 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3895 permission
|= S_IEXEC
;
3896 else if (is_exec (name
))
3897 permission
|= S_IEXEC
;
3900 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3906 stat (const char * path
, struct stat
* buf
)
3908 return stat_worker (path
, buf
, 1);
3912 lstat (const char * path
, struct stat
* buf
)
3914 return stat_worker (path
, buf
, 0);
3917 /* Provide fstat and utime as well as stat for consistent handling of
3920 fstat (int desc
, struct stat
* buf
)
3922 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3923 BY_HANDLE_FILE_INFORMATION info
;
3924 unsigned __int64 fake_inode
;
3927 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3929 case FILE_TYPE_DISK
:
3930 buf
->st_mode
= S_IFREG
;
3931 if (!GetFileInformationByHandle (fh
, &info
))
3937 case FILE_TYPE_PIPE
:
3938 buf
->st_mode
= S_IFIFO
;
3940 case FILE_TYPE_CHAR
:
3941 case FILE_TYPE_UNKNOWN
:
3943 buf
->st_mode
= S_IFCHR
;
3945 memset (&info
, 0, sizeof (info
));
3946 info
.dwFileAttributes
= 0;
3947 info
.ftCreationTime
= utc_base_ft
;
3948 info
.ftLastAccessTime
= utc_base_ft
;
3949 info
.ftLastWriteTime
= utc_base_ft
;
3952 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3953 buf
->st_mode
= S_IFDIR
;
3955 buf
->st_nlink
= info
.nNumberOfLinks
;
3956 /* Might as well use file index to fake inode values, but this
3957 is not guaranteed to be unique unless we keep a handle open
3958 all the time (even then there are situations where it is
3959 not unique). Reputedly, there are at most 48 bits of info
3960 (on NTFS, presumably less on FAT). */
3961 fake_inode
= info
.nFileIndexHigh
;
3963 fake_inode
+= info
.nFileIndexLow
;
3965 /* MSVC defines _ino_t to be short; other libc's might not. */
3966 if (sizeof (buf
->st_ino
) == 2)
3967 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3969 buf
->st_ino
= fake_inode
;
3971 /* Consider files to belong to current user.
3972 FIXME: this should use GetSecurityInfo API, but it is only
3973 available for _WIN32_WINNT >= 0x501. */
3974 buf
->st_uid
= dflt_passwd
.pw_uid
;
3975 buf
->st_gid
= dflt_passwd
.pw_gid
;
3976 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3977 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3979 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3980 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3982 buf
->st_size
= info
.nFileSizeHigh
;
3983 buf
->st_size
<<= 32;
3984 buf
->st_size
+= info
.nFileSizeLow
;
3986 /* Convert timestamps to Unix format. */
3987 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3988 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3989 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3990 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3991 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3993 /* determine rwx permissions */
3994 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3995 permission
= S_IREAD
;
3997 permission
= S_IREAD
| S_IWRITE
;
3999 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4000 permission
|= S_IEXEC
;
4003 #if 0 /* no way of knowing the filename */
4004 char * p
= strrchr (name
, '.');
4006 (xstrcasecmp (p
, ".exe") == 0 ||
4007 xstrcasecmp (p
, ".com") == 0 ||
4008 xstrcasecmp (p
, ".bat") == 0 ||
4009 xstrcasecmp (p
, ".cmd") == 0))
4010 permission
|= S_IEXEC
;
4014 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4020 utime (const char *name
, struct utimbuf
*times
)
4022 struct utimbuf deftime
;
4029 deftime
.modtime
= deftime
.actime
= time (NULL
);
4033 /* Need write access to set times. */
4034 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
4035 0, OPEN_EXISTING
, 0, NULL
);
4038 convert_from_time_t (times
->actime
, &atime
);
4039 convert_from_time_t (times
->modtime
, &mtime
);
4040 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
4057 /* Symlink-related functions. */
4058 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4059 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4063 symlink (char const *filename
, char const *linkname
)
4065 char linkfn
[MAX_PATH
], *tgtfn
;
4067 int dir_access
, filename_ends_in_slash
;
4069 /* Diagnostics follows Posix as much as possible. */
4070 if (filename
== NULL
|| linkname
== NULL
)
4080 if (strlen (filename
) > MAX_PATH
|| strlen (linkname
) > MAX_PATH
)
4082 errno
= ENAMETOOLONG
;
4086 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
4087 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
4093 /* Note: since empty FILENAME was already rejected, we can safely
4094 refer to FILENAME[1]. */
4095 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
4097 /* Non-absolute FILENAME is understood as being relative to
4098 LINKNAME's directory. We need to prepend that directory to
4099 FILENAME to get correct results from sys_access below, since
4100 otherwise it will interpret FILENAME relative to the
4101 directory where the Emacs process runs. Note that
4102 make-symbolic-link always makes sure LINKNAME is a fully
4103 expanded file name. */
4105 char *p
= linkfn
+ strlen (linkfn
);
4107 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
4110 strncpy (tem
, linkfn
, p
- linkfn
);
4111 tem
[p
- linkfn
] = '\0';
4112 strcat (tem
, filename
);
4113 dir_access
= sys_access (tem
, D_OK
);
4116 dir_access
= sys_access (filename
, D_OK
);
4118 /* Since Windows distinguishes between symlinks to directories and
4119 to files, we provide a kludgey feature: if FILENAME doesn't
4120 exist, but ends in a slash, we create a symlink to directory. If
4121 FILENAME exists and is a directory, we always create a symlink to
4123 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
4124 if (dir_access
== 0 || filename_ends_in_slash
)
4125 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
4127 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
4128 if (filename_ends_in_slash
)
4129 tgtfn
[strlen (tgtfn
) - 1] = '\0';
4132 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
4134 /* ENOSYS is set by create_symbolic_link, when it detects that
4135 the OS doesn't support the CreateSymbolicLink API. */
4136 if (errno
!= ENOSYS
)
4138 DWORD w32err
= GetLastError ();
4142 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4143 TGTFN point to the same file name, go figure. */
4145 case ERROR_FILE_EXISTS
:
4148 case ERROR_ACCESS_DENIED
:
4151 case ERROR_FILE_NOT_FOUND
:
4152 case ERROR_PATH_NOT_FOUND
:
4153 case ERROR_BAD_NETPATH
:
4154 case ERROR_INVALID_REPARSE_DATA
:
4157 case ERROR_DIRECTORY
:
4160 case ERROR_PRIVILEGE_NOT_HELD
:
4161 case ERROR_NOT_ALL_ASSIGNED
:
4164 case ERROR_DISK_FULL
:
4177 /* A quick inexpensive test of whether FILENAME identifies a file that
4178 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4179 must already be in the normalized form returned by
4182 Note: for repeated operations on many files, it is best to test
4183 whether the underlying volume actually supports symlinks, by
4184 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4185 avoid the call to this function if it doesn't. That's because the
4186 call to GetFileAttributes takes a non-negligible time, expecially
4187 on non-local or removable filesystems. See stat_worker for an
4188 example of how to do that. */
4190 is_symlink (const char *filename
)
4193 WIN32_FIND_DATA wfd
;
4196 attrs
= GetFileAttributes (filename
);
4199 DWORD w32err
= GetLastError ();
4203 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
4205 case ERROR_ACCESS_DENIED
:
4208 case ERROR_FILE_NOT_FOUND
:
4209 case ERROR_PATH_NOT_FOUND
:
4216 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
4218 logon_network_drive (filename
);
4219 fh
= FindFirstFile (filename
, &wfd
);
4220 if (fh
== INVALID_HANDLE_VALUE
)
4223 return (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
4224 && (wfd
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
4227 /* If NAME identifies a symbolic link, copy into BUF the file name of
4228 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4229 null-terminate the target name, even if it fits. Return the number
4230 of bytes copied, or -1 if NAME is not a symlink or any error was
4231 encountered while resolving it. The file name copied into BUF is
4232 encoded in the current ANSI codepage. */
4234 readlink (const char *name
, char *buf
, size_t buf_size
)
4237 TOKEN_PRIVILEGES privs
;
4238 int restore_privs
= 0;
4253 path
= map_w32_filename (name
, NULL
);
4255 if (strlen (path
) > MAX_PATH
)
4257 errno
= ENAMETOOLONG
;
4262 if (is_windows_9x () == TRUE
4263 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
4264 || !is_symlink (path
))
4267 errno
= EINVAL
; /* not a symlink */
4271 /* Done with simple tests, now we're in for some _real_ work. */
4272 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
4274 /* Implementation note: From here and onward, don't return early,
4275 since that will fail to restore the original set of privileges of
4276 the calling thread. */
4278 retval
= -1; /* not too optimistic, are we? */
4280 /* Note: In the next call to CreateFile, we use zero as the 2nd
4281 argument because, when the symlink is a hidden/system file,
4282 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4283 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4284 and directory symlinks. */
4285 sh
= CreateFile (path
, 0, 0, NULL
, OPEN_EXISTING
,
4286 FILE_FLAG_OPEN_REPARSE_POINT
| FILE_FLAG_BACKUP_SEMANTICS
,
4288 if (sh
!= INVALID_HANDLE_VALUE
)
4290 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
4291 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
4294 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
4295 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
4298 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
4302 /* Copy the link target name, in wide characters, fro
4303 reparse_data, then convert it to multibyte encoding in
4304 the current locale's codepage. */
4306 BYTE lname
[MAX_PATH
];
4309 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
4311 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
4312 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
4314 /* According to MSDN, PrintNameLength does not include the
4315 terminating null character. */
4316 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
4317 memcpy (lwname
, lwname_src
, lwname_len
);
4318 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
4320 /* FIXME: Should we use the current file-name coding system
4321 instead of the fixed value of the ANSI codepage? */
4322 lname_len
= WideCharToMultiByte (w32_ansi_code_page
, 0, lwname
, -1,
4323 lname
, MAX_PATH
, NULL
, NULL
);
4326 /* WideCharToMultiByte failed. */
4327 DWORD w32err1
= GetLastError ();
4331 case ERROR_INSUFFICIENT_BUFFER
:
4332 errno
= ENAMETOOLONG
;
4334 case ERROR_INVALID_PARAMETER
:
4337 case ERROR_NO_UNICODE_TRANSLATION
:
4347 size_t size_to_copy
= buf_size
;
4349 BYTE
*pend
= p
+ lname_len
;
4351 /* Normalize like dostounix_filename does, but we don't
4352 want to assume that lname is null-terminated. */
4353 if (*p
&& p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4361 /* Testing for null-terminated LNAME is paranoia:
4362 WideCharToMultiByte should always return a
4363 null-terminated string when its 4th argument is -1
4364 and its 3rd argument is null-terminated (which they
4366 if (lname
[lname_len
- 1] == '\0')
4368 if (lname_len
<= buf_size
)
4369 size_to_copy
= lname_len
;
4370 strncpy (buf
, lname
, size_to_copy
);
4372 retval
= size_to_copy
;
4379 /* CreateFile failed. */
4380 DWORD w32err2
= GetLastError ();
4384 case ERROR_FILE_NOT_FOUND
:
4385 case ERROR_PATH_NOT_FOUND
:
4388 case ERROR_ACCESS_DENIED
:
4389 case ERROR_TOO_MANY_OPEN_FILES
:
4399 restore_privilege (&privs
);
4406 /* If FILE is a symlink, return its target (stored in a static
4407 buffer); otherwise return FILE.
4409 This function repeatedly resolves symlinks in the last component of
4410 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4411 until it arrives at a file whose last component is not a symlink,
4412 or some error occurs. It returns the target of the last
4413 successfully resolved symlink in the chain. If it succeeds to
4414 resolve even a single symlink, the value returned is an absolute
4415 file name with backslashes (result of GetFullPathName). By
4416 contrast, if the original FILE is returned, it is unaltered.
4418 Note: This function can set errno even if it succeeds.
4420 Implementation note: we only resolve the last portion ("basename")
4421 of the argument FILE and of each following file in the chain,
4422 disregarding any possible symlinks in its leading directories.
4423 This is because Windows system calls and library functions
4424 transparently resolve symlinks in leading directories and return
4425 correct information, as long as the basename is not a symlink. */
4427 chase_symlinks (const char *file
)
4429 static char target
[MAX_PATH
];
4430 char link
[MAX_PATH
];
4431 ssize_t res
, link_len
;
4434 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
4435 return (char *)file
;
4437 if ((link_len
= GetFullPathName (file
, MAX_PATH
, link
, NULL
)) == 0)
4438 return (char *)file
;
4443 /* Remove trailing slashes, as we want to resolve the last
4444 non-trivial part of the link name. */
4445 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
4446 link
[link_len
--] = '\0';
4448 res
= readlink (link
, target
, MAX_PATH
);
4452 if (!(IS_DEVICE_SEP (target
[1])
4453 || IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1])))
4455 /* Target is relative. Append it to the directory part of
4456 the symlink, then copy the result back to target. */
4457 char *p
= link
+ link_len
;
4459 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
4462 strcpy (target
, link
);
4464 /* Resolve any "." and ".." to get a fully-qualified file name
4466 link_len
= GetFullPathName (target
, MAX_PATH
, link
, NULL
);
4468 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
4470 if (loop_count
> 100)
4473 if (target
[0] == '\0') /* not a single call to readlink succeeded */
4474 return (char *)file
;
4478 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
4479 have a fixed max size for file names, so we don't need the kind of
4480 alloc/malloc/realloc dance the gnulib version does. We also don't
4481 support FD-relative symlinks. */
4483 careadlinkat (int fd
, char const *filename
,
4484 char *buffer
, size_t buffer_size
,
4485 struct allocator
const *alloc
,
4486 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
4488 char linkname
[MAX_PATH
];
4497 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
4501 char *retval
= buffer
;
4503 linkname
[link_size
++] = '\0';
4504 if (link_size
> buffer_size
)
4505 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
4507 memcpy (retval
, linkname
, link_size
);
4515 careadlinkatcwd (int fd
, char const *filename
, char *buffer
,
4519 return readlink (filename
, buffer
, buffer_size
);
4523 /* Support for browsing other processes and their attributes. See
4524 process.c for the Lisp bindings. */
4526 /* Helper wrapper functions. */
4528 static HANDLE WINAPI
4529 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
4531 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
4533 if (g_b_init_create_toolhelp32_snapshot
== 0)
4535 g_b_init_create_toolhelp32_snapshot
= 1;
4536 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
4537 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4538 "CreateToolhelp32Snapshot");
4540 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
4542 return INVALID_HANDLE_VALUE
;
4544 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
4548 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
4550 static Process32First_Proc s_pfn_Process32_First
= NULL
;
4552 if (g_b_init_process32_first
== 0)
4554 g_b_init_process32_first
= 1;
4555 s_pfn_Process32_First
= (Process32First_Proc
)
4556 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4559 if (s_pfn_Process32_First
== NULL
)
4563 return (s_pfn_Process32_First (hSnapshot
, lppe
));
4567 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
4569 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
4571 if (g_b_init_process32_next
== 0)
4573 g_b_init_process32_next
= 1;
4574 s_pfn_Process32_Next
= (Process32Next_Proc
)
4575 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4578 if (s_pfn_Process32_Next
== NULL
)
4582 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
4586 open_thread_token (HANDLE ThreadHandle
,
4587 DWORD DesiredAccess
,
4589 PHANDLE TokenHandle
)
4591 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
4592 HMODULE hm_advapi32
= NULL
;
4593 if (is_windows_9x () == TRUE
)
4595 SetLastError (ERROR_NOT_SUPPORTED
);
4598 if (g_b_init_open_thread_token
== 0)
4600 g_b_init_open_thread_token
= 1;
4601 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4602 s_pfn_Open_Thread_Token
=
4603 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
4605 if (s_pfn_Open_Thread_Token
== NULL
)
4607 SetLastError (ERROR_NOT_SUPPORTED
);
4611 s_pfn_Open_Thread_Token (
4620 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
4622 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
4623 HMODULE hm_advapi32
= NULL
;
4624 if (is_windows_9x () == TRUE
)
4628 if (g_b_init_impersonate_self
== 0)
4630 g_b_init_impersonate_self
= 1;
4631 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4632 s_pfn_Impersonate_Self
=
4633 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
4635 if (s_pfn_Impersonate_Self
== NULL
)
4639 return s_pfn_Impersonate_Self (ImpersonationLevel
);
4643 revert_to_self (void)
4645 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
4646 HMODULE hm_advapi32
= NULL
;
4647 if (is_windows_9x () == TRUE
)
4651 if (g_b_init_revert_to_self
== 0)
4653 g_b_init_revert_to_self
= 1;
4654 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4655 s_pfn_Revert_To_Self
=
4656 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
4658 if (s_pfn_Revert_To_Self
== NULL
)
4662 return s_pfn_Revert_To_Self ();
4666 get_process_memory_info (HANDLE h_proc
,
4667 PPROCESS_MEMORY_COUNTERS mem_counters
,
4670 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
4671 HMODULE hm_psapi
= NULL
;
4672 if (is_windows_9x () == TRUE
)
4676 if (g_b_init_get_process_memory_info
== 0)
4678 g_b_init_get_process_memory_info
= 1;
4679 hm_psapi
= LoadLibrary ("Psapi.dll");
4681 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
4682 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
4684 if (s_pfn_Get_Process_Memory_Info
== NULL
)
4688 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
4692 get_process_working_set_size (HANDLE h_proc
,
4696 static GetProcessWorkingSetSize_Proc
4697 s_pfn_Get_Process_Working_Set_Size
= NULL
;
4699 if (is_windows_9x () == TRUE
)
4703 if (g_b_init_get_process_working_set_size
== 0)
4705 g_b_init_get_process_working_set_size
= 1;
4706 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
4707 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4708 "GetProcessWorkingSetSize");
4710 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
4714 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
4718 global_memory_status (MEMORYSTATUS
*buf
)
4720 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
4722 if (is_windows_9x () == TRUE
)
4726 if (g_b_init_global_memory_status
== 0)
4728 g_b_init_global_memory_status
= 1;
4729 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
4730 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4731 "GlobalMemoryStatus");
4733 if (s_pfn_Global_Memory_Status
== NULL
)
4737 return s_pfn_Global_Memory_Status (buf
);
4741 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
4743 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
4745 if (is_windows_9x () == TRUE
)
4749 if (g_b_init_global_memory_status_ex
== 0)
4751 g_b_init_global_memory_status_ex
= 1;
4752 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
4753 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4754 "GlobalMemoryStatusEx");
4756 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
4760 return s_pfn_Global_Memory_Status_Ex (buf
);
4764 list_system_processes (void)
4766 struct gcpro gcpro1
;
4767 Lisp_Object proclist
= Qnil
;
4770 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4772 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4774 PROCESSENTRY32 proc_entry
;
4780 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
4781 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
4782 res
= process32_next (h_snapshot
, &proc_entry
))
4784 proc_id
= proc_entry
.th32ProcessID
;
4785 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
4788 CloseHandle (h_snapshot
);
4790 proclist
= Fnreverse (proclist
);
4797 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
4799 TOKEN_PRIVILEGES priv
;
4800 DWORD priv_size
= sizeof (priv
);
4801 DWORD opriv_size
= sizeof (*old_priv
);
4802 HANDLE h_token
= NULL
;
4803 HANDLE h_thread
= GetCurrentThread ();
4807 res
= open_thread_token (h_thread
,
4808 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4810 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
4812 if (impersonate_self (SecurityImpersonation
))
4813 res
= open_thread_token (h_thread
,
4814 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4819 priv
.PrivilegeCount
= 1;
4820 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
4821 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
4822 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
4823 old_priv
, &opriv_size
)
4824 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4828 CloseHandle (h_token
);
4834 restore_privilege (TOKEN_PRIVILEGES
*priv
)
4836 DWORD priv_size
= sizeof (*priv
);
4837 HANDLE h_token
= NULL
;
4840 if (open_thread_token (GetCurrentThread (),
4841 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4844 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
4845 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4849 CloseHandle (h_token
);
4855 ltime (ULONGLONG time_100ns
)
4857 ULONGLONG time_sec
= time_100ns
/ 10000000;
4858 int subsec
= time_100ns
% 10000000;
4859 return list4 (make_number (time_sec
>> 16),
4860 make_number (time_sec
& 0xffff),
4861 make_number (subsec
/ 10),
4862 make_number (subsec
% 10 * 100000));
4865 #define U64_TO_LISP_TIME(time) ltime (time)
4868 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4869 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4872 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4873 ULONGLONG tem1
, tem2
, tem3
, tem
;
4876 || !get_process_times_fn
4877 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4878 &ft_kernel
, &ft_user
))
4881 GetSystemTimeAsFileTime (&ft_current
);
4883 FILETIME_TO_U64 (tem1
, ft_kernel
);
4884 *stime
= U64_TO_LISP_TIME (tem1
);
4886 FILETIME_TO_U64 (tem2
, ft_user
);
4887 *utime
= U64_TO_LISP_TIME (tem2
);
4890 *ttime
= U64_TO_LISP_TIME (tem3
);
4892 FILETIME_TO_U64 (tem
, ft_creation
);
4893 /* Process no 4 (System) returns zero creation time. */
4896 *ctime
= U64_TO_LISP_TIME (tem
);
4900 FILETIME_TO_U64 (tem3
, ft_current
);
4901 tem
= (tem3
- utc_base
) - tem
;
4903 *etime
= U64_TO_LISP_TIME (tem
);
4907 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4918 system_process_attributes (Lisp_Object pid
)
4920 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4921 Lisp_Object attrs
= Qnil
;
4922 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4923 HANDLE h_snapshot
, h_proc
;
4926 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4927 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4928 DWORD glength
= sizeof (gname
);
4929 HANDLE token
= NULL
;
4930 SID_NAME_USE user_type
;
4931 unsigned char *buf
= NULL
;
4933 TOKEN_USER user_token
;
4934 TOKEN_PRIMARY_GROUP group_token
;
4937 PROCESS_MEMORY_COUNTERS mem
;
4938 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4939 DWORD minrss
, maxrss
;
4941 MEMORY_STATUS_EX memstex
;
4942 double totphys
= 0.0;
4943 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4945 BOOL result
= FALSE
;
4947 CHECK_NUMBER_OR_FLOAT (pid
);
4948 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4950 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4952 GCPRO3 (attrs
, decoded_cmd
, tem
);
4954 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4959 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4960 for (res
= process32_first (h_snapshot
, &pe
); res
;
4961 res
= process32_next (h_snapshot
, &pe
))
4963 if (proc_id
== pe
.th32ProcessID
)
4966 decoded_cmd
= build_string ("Idle");
4969 /* Decode the command name from locale-specific
4971 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4972 strlen (pe
.szExeFile
));
4974 code_convert_string_norecord (cmd_str
,
4975 Vlocale_coding_system
, 0);
4977 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4978 attrs
= Fcons (Fcons (Qppid
,
4979 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4981 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4983 attrs
= Fcons (Fcons (Qthcount
,
4984 make_fixnum_or_float (pe
.cntThreads
)),
4991 CloseHandle (h_snapshot
);
5000 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
5002 /* If we were denied a handle to the process, try again after
5003 enabling the SeDebugPrivilege in our process. */
5006 TOKEN_PRIVILEGES priv_current
;
5008 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
5010 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
5012 restore_privilege (&priv_current
);
5018 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
5021 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
5022 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5024 buf
= xmalloc (blen
);
5025 result
= get_token_information (token
, TokenUser
,
5026 (LPVOID
)buf
, blen
, &needed
);
5029 memcpy (&user_token
, buf
, sizeof (user_token
));
5030 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
5032 euid
= get_rid (user_token
.User
.Sid
);
5033 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
5038 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
5041 strcpy (uname
, "unknown");
5045 ulength
= strlen (uname
);
5051 /* Determine a reasonable euid and gid values. */
5052 if (xstrcasecmp ("administrator", uname
) == 0)
5054 euid
= 500; /* well-known Administrator uid */
5055 egid
= 513; /* well-known None gid */
5059 /* Get group id and name. */
5060 result
= get_token_information (token
, TokenPrimaryGroup
,
5061 (LPVOID
)buf
, blen
, &needed
);
5062 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5064 buf
= xrealloc (buf
, blen
= needed
);
5065 result
= get_token_information (token
, TokenPrimaryGroup
,
5066 (LPVOID
)buf
, blen
, &needed
);
5070 memcpy (&group_token
, buf
, sizeof (group_token
));
5071 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
5073 egid
= get_rid (group_token
.PrimaryGroup
);
5074 dlength
= sizeof (domain
);
5076 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
5077 gname
, &glength
, NULL
, &dlength
,
5080 w32_add_to_cache (group_token
.PrimaryGroup
,
5084 strcpy (gname
, "None");
5088 glength
= strlen (gname
);
5096 if (!is_windows_9x ())
5098 /* We couldn't open the process token, presumably because of
5099 insufficient access rights. Assume this process is run
5101 strcpy (uname
, "SYSTEM");
5102 strcpy (gname
, "None");
5103 euid
= 18; /* SYSTEM */
5104 egid
= 513; /* None */
5105 glength
= strlen (gname
);
5106 ulength
= strlen (uname
);
5108 /* If we are running under Windows 9X, where security calls are
5109 not supported, we assume all processes are run by the current
5111 else if (GetUserName (uname
, &ulength
))
5113 if (xstrcasecmp ("administrator", uname
) == 0)
5118 strcpy (gname
, "None");
5119 glength
= strlen (gname
);
5120 ulength
= strlen (uname
);
5126 strcpy (uname
, "administrator");
5127 ulength
= strlen (uname
);
5128 strcpy (gname
, "None");
5129 glength
= strlen (gname
);
5132 CloseHandle (token
);
5135 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
5136 tem
= make_unibyte_string (uname
, ulength
);
5137 attrs
= Fcons (Fcons (Quser
,
5138 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5140 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
5141 tem
= make_unibyte_string (gname
, glength
);
5142 attrs
= Fcons (Fcons (Qgroup
,
5143 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5146 if (global_memory_status_ex (&memstex
))
5147 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5148 totphys
= memstex
.ullTotalPhys
/ 1024.0;
5150 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5151 double, so we need to do this for it... */
5153 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
5154 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
5155 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
5157 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
5159 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5160 else if (global_memory_status (&memst
))
5161 totphys
= memst
.dwTotalPhys
/ 1024.0;
5164 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
5167 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
5169 attrs
= Fcons (Fcons (Qmajflt
,
5170 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
5172 attrs
= Fcons (Fcons (Qvsize
,
5173 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
5175 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5177 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5180 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
5182 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
5184 attrs
= Fcons (Fcons (Qmajflt
,
5185 make_fixnum_or_float (mem
.PageFaultCount
)),
5187 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5189 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5192 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
5194 DWORD rss
= maxrss
/ 1024;
5196 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
5198 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5201 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
5203 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
5204 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
5205 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
5206 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
5207 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
5208 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
5211 /* FIXME: Retrieve command line by walking the PEB of the process. */
5214 CloseHandle (h_proc
);
5220 /* Wrappers for winsock functions to map between our file descriptors
5221 and winsock's handles; also set h_errno for convenience.
5223 To allow Emacs to run on systems which don't have winsock support
5224 installed, we dynamically link to winsock on startup if present, and
5225 otherwise provide the minimum necessary functionality
5226 (eg. gethostname). */
5228 /* function pointers for relevant socket functions */
5229 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
5230 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
5231 int (PASCAL
*pfn_WSAGetLastError
) (void);
5232 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
5233 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
5234 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
5235 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
5236 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
5237 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
5238 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
5239 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
5240 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
5241 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
5242 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
5243 int (PASCAL
*pfn_WSACleanup
) (void);
5245 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
5246 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
5247 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
5248 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
5249 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
5250 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
5251 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
5252 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
5253 const char * optval
, int optlen
);
5254 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
5255 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
5257 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
5258 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
5259 struct sockaddr
* from
, int * fromlen
);
5260 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
5261 const struct sockaddr
* to
, int tolen
);
5263 /* SetHandleInformation is only needed to make sockets non-inheritable. */
5264 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
5265 #ifndef HANDLE_FLAG_INHERIT
5266 #define HANDLE_FLAG_INHERIT 1
5270 static int winsock_inuse
;
5275 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
5277 /* Not sure what would cause WSAENETDOWN, or even if it can happen
5278 after WSAStartup returns successfully, but it seems reasonable
5279 to allow unloading winsock anyway in that case. */
5280 if (pfn_WSACleanup () == 0 ||
5281 pfn_WSAGetLastError () == WSAENETDOWN
)
5283 if (FreeLibrary (winsock_lib
))
5292 init_winsock (int load_now
)
5294 WSADATA winsockData
;
5296 if (winsock_lib
!= NULL
)
5299 pfn_SetHandleInformation
5300 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
5301 "SetHandleInformation");
5303 winsock_lib
= LoadLibrary ("Ws2_32.dll");
5305 if (winsock_lib
!= NULL
)
5307 /* dynamically link to socket functions */
5309 #define LOAD_PROC(fn) \
5310 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
5313 LOAD_PROC (WSAStartup
);
5314 LOAD_PROC (WSASetLastError
);
5315 LOAD_PROC (WSAGetLastError
);
5316 LOAD_PROC (WSAEventSelect
);
5317 LOAD_PROC (WSACreateEvent
);
5318 LOAD_PROC (WSACloseEvent
);
5321 LOAD_PROC (connect
);
5322 LOAD_PROC (ioctlsocket
);
5325 LOAD_PROC (closesocket
);
5326 LOAD_PROC (shutdown
);
5329 LOAD_PROC (inet_addr
);
5330 LOAD_PROC (gethostname
);
5331 LOAD_PROC (gethostbyname
);
5332 LOAD_PROC (getservbyname
);
5333 LOAD_PROC (getpeername
);
5334 LOAD_PROC (WSACleanup
);
5335 LOAD_PROC (setsockopt
);
5337 LOAD_PROC (getsockname
);
5339 LOAD_PROC (recvfrom
);
5343 /* specify version 1.1 of winsock */
5344 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
5346 if (winsockData
.wVersion
!= 0x101)
5351 /* Report that winsock exists and is usable, but leave
5352 socket functions disabled. I am assuming that calling
5353 WSAStartup does not require any network interaction,
5354 and in particular does not cause or require a dial-up
5355 connection to be established. */
5358 FreeLibrary (winsock_lib
);
5366 FreeLibrary (winsock_lib
);
5376 /* function to set h_errno for compatibility; map winsock error codes to
5377 normal system codes where they overlap (non-overlapping definitions
5378 are already in <sys/socket.h> */
5382 if (winsock_lib
== NULL
)
5385 h_errno
= pfn_WSAGetLastError ();
5389 case WSAEACCES
: h_errno
= EACCES
; break;
5390 case WSAEBADF
: h_errno
= EBADF
; break;
5391 case WSAEFAULT
: h_errno
= EFAULT
; break;
5392 case WSAEINTR
: h_errno
= EINTR
; break;
5393 case WSAEINVAL
: h_errno
= EINVAL
; break;
5394 case WSAEMFILE
: h_errno
= EMFILE
; break;
5395 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
5396 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
5404 if (h_errno
== 0 && winsock_lib
!= NULL
)
5405 pfn_WSASetLastError (0);
5408 /* Extend strerror to handle the winsock-specific error codes. */
5412 } _wsa_errlist
[] = {
5413 {WSAEINTR
, "Interrupted function call"},
5414 {WSAEBADF
, "Bad file descriptor"},
5415 {WSAEACCES
, "Permission denied"},
5416 {WSAEFAULT
, "Bad address"},
5417 {WSAEINVAL
, "Invalid argument"},
5418 {WSAEMFILE
, "Too many open files"},
5420 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
5421 {WSAEINPROGRESS
, "Operation now in progress"},
5422 {WSAEALREADY
, "Operation already in progress"},
5423 {WSAENOTSOCK
, "Socket operation on non-socket"},
5424 {WSAEDESTADDRREQ
, "Destination address required"},
5425 {WSAEMSGSIZE
, "Message too long"},
5426 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
5427 {WSAENOPROTOOPT
, "Bad protocol option"},
5428 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
5429 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
5430 {WSAEOPNOTSUPP
, "Operation not supported"},
5431 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
5432 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
5433 {WSAEADDRINUSE
, "Address already in use"},
5434 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
5435 {WSAENETDOWN
, "Network is down"},
5436 {WSAENETUNREACH
, "Network is unreachable"},
5437 {WSAENETRESET
, "Network dropped connection on reset"},
5438 {WSAECONNABORTED
, "Software caused connection abort"},
5439 {WSAECONNRESET
, "Connection reset by peer"},
5440 {WSAENOBUFS
, "No buffer space available"},
5441 {WSAEISCONN
, "Socket is already connected"},
5442 {WSAENOTCONN
, "Socket is not connected"},
5443 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
5444 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
5445 {WSAETIMEDOUT
, "Connection timed out"},
5446 {WSAECONNREFUSED
, "Connection refused"},
5447 {WSAELOOP
, "Network loop"}, /* not sure */
5448 {WSAENAMETOOLONG
, "Name is too long"},
5449 {WSAEHOSTDOWN
, "Host is down"},
5450 {WSAEHOSTUNREACH
, "No route to host"},
5451 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
5452 {WSAEPROCLIM
, "Too many processes"},
5453 {WSAEUSERS
, "Too many users"}, /* not sure */
5454 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
5455 {WSAESTALE
, "Data is stale"}, /* not sure */
5456 {WSAEREMOTE
, "Remote error"}, /* not sure */
5458 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
5459 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
5460 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
5461 {WSAEDISCON
, "Graceful shutdown in progress"},
5463 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
5464 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
5465 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
5466 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
5467 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
5468 {WSASYSCALLFAILURE
, "System call failure"},
5469 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
5470 {WSATYPE_NOT_FOUND
, "Class type not found"},
5471 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
5472 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
5473 {WSAEREFUSED
, "Operation refused"}, /* not sure */
5476 {WSAHOST_NOT_FOUND
, "Host not found"},
5477 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
5478 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
5479 {WSANO_DATA
, "Valid name, no data record of requested type"},
5485 sys_strerror (int error_no
)
5488 static char unknown_msg
[40];
5490 if (error_no
>= 0 && error_no
< sys_nerr
)
5491 return sys_errlist
[error_no
];
5493 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
5494 if (_wsa_errlist
[i
].errnum
== error_no
)
5495 return _wsa_errlist
[i
].msg
;
5497 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
5501 /* [andrewi 3-May-96] I've had conflicting results using both methods,
5502 but I believe the method of keeping the socket handle separate (and
5503 insuring it is not inheritable) is the correct one. */
5505 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
5507 static int socket_to_fd (SOCKET s
);
5510 sys_socket (int af
, int type
, int protocol
)
5514 if (winsock_lib
== NULL
)
5517 return INVALID_SOCKET
;
5522 /* call the real socket function */
5523 s
= pfn_socket (af
, type
, protocol
);
5525 if (s
!= INVALID_SOCKET
)
5526 return socket_to_fd (s
);
5532 /* Convert a SOCKET to a file descriptor. */
5534 socket_to_fd (SOCKET s
)
5539 /* Although under NT 3.5 _open_osfhandle will accept a socket
5540 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
5541 that does not work under NT 3.1. However, we can get the same
5542 effect by using a backdoor function to replace an existing
5543 descriptor handle with the one we want. */
5545 /* allocate a file descriptor (with appropriate flags) */
5546 fd
= _open ("NUL:", _O_RDWR
);
5549 /* Make a non-inheritable copy of the socket handle. Note
5550 that it is possible that sockets aren't actually kernel
5551 handles, which appears to be the case on Windows 9x when
5552 the MS Proxy winsock client is installed. */
5554 /* Apparently there is a bug in NT 3.51 with some service
5555 packs, which prevents using DuplicateHandle to make a
5556 socket handle non-inheritable (causes WSACleanup to
5557 hang). The work-around is to use SetHandleInformation
5558 instead if it is available and implemented. */
5559 if (pfn_SetHandleInformation
)
5561 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
5565 HANDLE parent
= GetCurrentProcess ();
5566 HANDLE new_s
= INVALID_HANDLE_VALUE
;
5568 if (DuplicateHandle (parent
,
5574 DUPLICATE_SAME_ACCESS
))
5576 /* It is possible that DuplicateHandle succeeds even
5577 though the socket wasn't really a kernel handle,
5578 because a real handle has the same value. So
5579 test whether the new handle really is a socket. */
5580 long nonblocking
= 0;
5581 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
5583 pfn_closesocket (s
);
5588 CloseHandle (new_s
);
5593 fd_info
[fd
].hnd
= (HANDLE
) s
;
5595 /* set our own internal flags */
5596 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
5602 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5604 /* attach child_process to fd_info */
5605 if (fd_info
[ fd
].cp
!= NULL
)
5607 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
5611 fd_info
[ fd
].cp
= cp
;
5614 winsock_inuse
++; /* count open sockets */
5621 pfn_closesocket (s
);
5627 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
5629 if (winsock_lib
== NULL
)
5632 return SOCKET_ERROR
;
5636 if (fd_info
[s
].flags
& FILE_SOCKET
)
5638 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
5639 if (rc
== SOCKET_ERROR
)
5644 return SOCKET_ERROR
;
5648 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
5650 if (winsock_lib
== NULL
)
5653 return SOCKET_ERROR
;
5657 if (fd_info
[s
].flags
& FILE_SOCKET
)
5659 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
5660 if (rc
== SOCKET_ERROR
)
5665 return SOCKET_ERROR
;
5669 sys_htons (u_short hostshort
)
5671 return (winsock_lib
!= NULL
) ?
5672 pfn_htons (hostshort
) : hostshort
;
5676 sys_ntohs (u_short netshort
)
5678 return (winsock_lib
!= NULL
) ?
5679 pfn_ntohs (netshort
) : netshort
;
5683 sys_inet_addr (const char * cp
)
5685 return (winsock_lib
!= NULL
) ?
5686 pfn_inet_addr (cp
) : INADDR_NONE
;
5690 sys_gethostname (char * name
, int namelen
)
5692 if (winsock_lib
!= NULL
)
5693 return pfn_gethostname (name
, namelen
);
5695 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
5696 return !GetComputerName (name
, (DWORD
*)&namelen
);
5699 return SOCKET_ERROR
;
5703 sys_gethostbyname (const char * name
)
5705 struct hostent
* host
;
5707 if (winsock_lib
== NULL
)
5714 host
= pfn_gethostbyname (name
);
5721 sys_getservbyname (const char * name
, const char * proto
)
5723 struct servent
* serv
;
5725 if (winsock_lib
== NULL
)
5732 serv
= pfn_getservbyname (name
, proto
);
5739 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
5741 if (winsock_lib
== NULL
)
5744 return SOCKET_ERROR
;
5748 if (fd_info
[s
].flags
& FILE_SOCKET
)
5750 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
5751 if (rc
== SOCKET_ERROR
)
5756 return SOCKET_ERROR
;
5760 sys_shutdown (int s
, int how
)
5762 if (winsock_lib
== NULL
)
5765 return SOCKET_ERROR
;
5769 if (fd_info
[s
].flags
& FILE_SOCKET
)
5771 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
5772 if (rc
== SOCKET_ERROR
)
5777 return SOCKET_ERROR
;
5781 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
5783 if (winsock_lib
== NULL
)
5786 return SOCKET_ERROR
;
5790 if (fd_info
[s
].flags
& FILE_SOCKET
)
5792 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
5793 (const char *)optval
, optlen
);
5794 if (rc
== SOCKET_ERROR
)
5799 return SOCKET_ERROR
;
5803 sys_listen (int s
, int backlog
)
5805 if (winsock_lib
== NULL
)
5808 return SOCKET_ERROR
;
5812 if (fd_info
[s
].flags
& FILE_SOCKET
)
5814 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
5815 if (rc
== SOCKET_ERROR
)
5818 fd_info
[s
].flags
|= FILE_LISTEN
;
5822 return SOCKET_ERROR
;
5826 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
5828 if (winsock_lib
== NULL
)
5831 return SOCKET_ERROR
;
5835 if (fd_info
[s
].flags
& FILE_SOCKET
)
5837 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
5838 if (rc
== SOCKET_ERROR
)
5843 return SOCKET_ERROR
;
5847 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
5849 if (winsock_lib
== NULL
)
5856 if (fd_info
[s
].flags
& FILE_LISTEN
)
5858 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5860 if (t
== INVALID_SOCKET
)
5863 fd
= socket_to_fd (t
);
5865 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5866 ResetEvent (fd_info
[s
].cp
->char_avail
);
5874 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5875 struct sockaddr
* from
, int * fromlen
)
5877 if (winsock_lib
== NULL
)
5880 return SOCKET_ERROR
;
5884 if (fd_info
[s
].flags
& FILE_SOCKET
)
5886 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5887 if (rc
== SOCKET_ERROR
)
5892 return SOCKET_ERROR
;
5896 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5897 const struct sockaddr
* to
, int tolen
)
5899 if (winsock_lib
== NULL
)
5902 return SOCKET_ERROR
;
5906 if (fd_info
[s
].flags
& FILE_SOCKET
)
5908 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5909 if (rc
== SOCKET_ERROR
)
5914 return SOCKET_ERROR
;
5917 /* Windows does not have an fcntl function. Provide an implementation
5918 solely for making sockets non-blocking. */
5920 fcntl (int s
, int cmd
, int options
)
5922 if (winsock_lib
== NULL
)
5929 if (fd_info
[s
].flags
& FILE_SOCKET
)
5931 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5933 unsigned long nblock
= 1;
5934 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5935 if (rc
== SOCKET_ERROR
)
5937 /* Keep track of the fact that we set this to non-blocking. */
5938 fd_info
[s
].flags
|= FILE_NDELAY
;
5944 return SOCKET_ERROR
;
5948 return SOCKET_ERROR
;
5952 /* Shadow main io functions: we need to handle pipes and sockets more
5953 intelligently, and implement non-blocking mode as well. */
5966 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5968 child_process
* cp
= fd_info
[fd
].cp
;
5970 fd_info
[fd
].cp
= NULL
;
5972 if (CHILD_ACTIVE (cp
))
5974 /* if last descriptor to active child_process then cleanup */
5976 for (i
= 0; i
< MAXDESC
; i
++)
5980 if (fd_info
[i
].cp
== cp
)
5985 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5987 if (winsock_lib
== NULL
) abort ();
5989 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5990 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5992 winsock_inuse
--; /* count open sockets */
5999 /* Note that sockets do not need special treatment here (at least on
6000 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
6001 closesocket is equivalent to CloseHandle, which is to be expected
6002 because socket handles are fully fledged kernel handles. */
6005 if (rc
== 0 && fd
< MAXDESC
)
6006 fd_info
[fd
].flags
= 0;
6017 if (new_fd
>= 0 && new_fd
< MAXDESC
)
6019 /* duplicate our internal info as well */
6020 fd_info
[new_fd
] = fd_info
[fd
];
6026 sys_dup2 (int src
, int dst
)
6030 if (dst
< 0 || dst
>= MAXDESC
)
6036 /* make sure we close the destination first if it's a pipe or socket */
6037 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
6040 rc
= _dup2 (src
, dst
);
6043 /* duplicate our internal info as well */
6044 fd_info
[dst
] = fd_info
[src
];
6049 /* Unix pipe() has only one arg */
6051 sys_pipe (int * phandles
)
6056 /* make pipe handles non-inheritable; when we spawn a child, we
6057 replace the relevant handle with an inheritable one. Also put
6058 pipes into binary mode; we will do text mode translation ourselves
6060 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
6064 /* Protect against overflow, since Windows can open more handles than
6065 our fd_info array has room for. */
6066 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
6068 _close (phandles
[0]);
6069 _close (phandles
[1]);
6074 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
6075 fd_info
[phandles
[0]].flags
= flags
;
6077 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
6078 fd_info
[phandles
[1]].flags
= flags
;
6085 /* Function to do blocking read of one byte, needed to implement
6086 select. It is only allowed on sockets and pipes. */
6088 _sys_read_ahead (int fd
)
6093 if (fd
< 0 || fd
>= MAXDESC
)
6094 return STATUS_READ_ERROR
;
6096 cp
= fd_info
[fd
].cp
;
6098 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6099 return STATUS_READ_ERROR
;
6101 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
6102 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
6104 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
6108 cp
->status
= STATUS_READ_IN_PROGRESS
;
6110 if (fd_info
[fd
].flags
& FILE_PIPE
)
6112 rc
= _read (fd
, &cp
->chr
, sizeof (char));
6114 /* Give subprocess time to buffer some more output for us before
6115 reporting that input is available; we need this because Windows 95
6116 connects DOS programs to pipes by making the pipe appear to be
6117 the normal console stdout - as a result most DOS programs will
6118 write to stdout without buffering, ie. one character at a
6119 time. Even some W32 programs do this - "dir" in a command
6120 shell on NT is very slow if we don't do this. */
6123 int wait
= w32_pipe_read_delay
;
6129 /* Yield remainder of our time slice, effectively giving a
6130 temporary priority boost to the child process. */
6134 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
6136 HANDLE hnd
= fd_info
[fd
].hnd
;
6137 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
6140 /* Configure timeouts for blocking read. */
6141 if (!GetCommTimeouts (hnd
, &ct
))
6142 return STATUS_READ_ERROR
;
6143 ct
.ReadIntervalTimeout
= 0;
6144 ct
.ReadTotalTimeoutMultiplier
= 0;
6145 ct
.ReadTotalTimeoutConstant
= 0;
6146 if (!SetCommTimeouts (hnd
, &ct
))
6147 return STATUS_READ_ERROR
;
6149 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
6151 if (GetLastError () != ERROR_IO_PENDING
)
6152 return STATUS_READ_ERROR
;
6153 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
6154 return STATUS_READ_ERROR
;
6157 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
6159 unsigned long nblock
= 0;
6160 /* We always want this to block, so temporarily disable NDELAY. */
6161 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6162 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6164 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
6166 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6169 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6173 if (rc
== sizeof (char))
6174 cp
->status
= STATUS_READ_SUCCEEDED
;
6176 cp
->status
= STATUS_READ_FAILED
;
6182 _sys_wait_accept (int fd
)
6188 if (fd
< 0 || fd
>= MAXDESC
)
6189 return STATUS_READ_ERROR
;
6191 cp
= fd_info
[fd
].cp
;
6193 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6194 return STATUS_READ_ERROR
;
6196 cp
->status
= STATUS_READ_FAILED
;
6198 hEv
= pfn_WSACreateEvent ();
6199 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
6200 if (rc
!= SOCKET_ERROR
)
6202 rc
= WaitForSingleObject (hEv
, INFINITE
);
6203 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
6204 if (rc
== WAIT_OBJECT_0
)
6205 cp
->status
= STATUS_READ_SUCCEEDED
;
6207 pfn_WSACloseEvent (hEv
);
6213 sys_read (int fd
, char * buffer
, unsigned int count
)
6218 char * orig_buffer
= buffer
;
6226 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
6228 child_process
*cp
= fd_info
[fd
].cp
;
6230 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
6238 /* re-read CR carried over from last read */
6239 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
6241 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
6245 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
6248 /* presence of a child_process structure means we are operating in
6249 non-blocking mode - otherwise we just call _read directly.
6250 Note that the child_process structure might be missing because
6251 reap_subprocess has been called; in this case the pipe is
6252 already broken, so calling _read on it is okay. */
6255 int current_status
= cp
->status
;
6257 switch (current_status
)
6259 case STATUS_READ_FAILED
:
6260 case STATUS_READ_ERROR
:
6261 /* report normal EOF if nothing in buffer */
6263 fd_info
[fd
].flags
|= FILE_AT_EOF
;
6266 case STATUS_READ_READY
:
6267 case STATUS_READ_IN_PROGRESS
:
6268 DebPrint (("sys_read called when read is in progress\n"));
6269 errno
= EWOULDBLOCK
;
6272 case STATUS_READ_SUCCEEDED
:
6273 /* consume read-ahead char */
6274 *buffer
++ = cp
->chr
;
6277 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6278 ResetEvent (cp
->char_avail
);
6280 case STATUS_READ_ACKNOWLEDGED
:
6284 DebPrint (("sys_read: bad status %d\n", current_status
));
6289 if (fd_info
[fd
].flags
& FILE_PIPE
)
6291 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
6292 to_read
= min (waiting
, (DWORD
) count
);
6295 nchars
+= _read (fd
, buffer
, to_read
);
6297 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
6299 HANDLE hnd
= fd_info
[fd
].hnd
;
6300 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
6306 /* Configure timeouts for non-blocking read. */
6307 if (!GetCommTimeouts (hnd
, &ct
))
6312 ct
.ReadIntervalTimeout
= MAXDWORD
;
6313 ct
.ReadTotalTimeoutMultiplier
= 0;
6314 ct
.ReadTotalTimeoutConstant
= 0;
6315 if (!SetCommTimeouts (hnd
, &ct
))
6321 if (!ResetEvent (ovl
->hEvent
))
6326 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
6328 if (GetLastError () != ERROR_IO_PENDING
)
6333 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
6342 else /* FILE_SOCKET */
6344 if (winsock_lib
== NULL
) abort ();
6346 /* do the equivalent of a non-blocking read */
6347 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
6348 if (waiting
== 0 && nchars
== 0)
6350 h_errno
= errno
= EWOULDBLOCK
;
6356 /* always use binary mode for sockets */
6357 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
6358 if (res
== SOCKET_ERROR
)
6360 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
6361 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
6371 int nread
= _read (fd
, buffer
, count
);
6374 else if (nchars
== 0)
6379 fd_info
[fd
].flags
|= FILE_AT_EOF
;
6380 /* Perform text mode translation if required. */
6381 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
6383 nchars
= crlf_to_lf (nchars
, orig_buffer
);
6384 /* If buffer contains only CR, return that. To be absolutely
6385 sure we should attempt to read the next char, but in
6386 practice a CR to be followed by LF would not appear by
6387 itself in the buffer. */
6388 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
6390 fd_info
[fd
].flags
|= FILE_LAST_CR
;
6396 nchars
= _read (fd
, buffer
, count
);
6401 /* From w32xfns.c */
6402 extern HANDLE interrupt_handle
;
6404 /* For now, don't bother with a non-blocking mode */
6406 sys_write (int fd
, const void * buffer
, unsigned int count
)
6416 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
6418 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
6424 /* Perform text mode translation if required. */
6425 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
6427 char * tmpbuf
= alloca (count
* 2);
6428 unsigned char * src
= (void *)buffer
;
6429 unsigned char * dst
= tmpbuf
;
6434 unsigned char *next
;
6435 /* copy next line or remaining bytes */
6436 next
= _memccpy (dst
, src
, '\n', nbytes
);
6439 /* copied one line ending with '\n' */
6440 int copied
= next
- dst
;
6443 /* insert '\r' before '\n' */
6450 /* copied remaining partial line -> now finished */
6457 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
6459 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
6460 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
6461 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
6464 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
6466 if (GetLastError () != ERROR_IO_PENDING
)
6471 if (detect_input_pending ())
6472 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
6475 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
6476 if (active
== WAIT_OBJECT_0
)
6477 { /* User pressed C-g, cancel write, then leave. Don't bother
6478 cleaning up as we may only get stuck in buggy drivers. */
6479 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
6484 if (active
== WAIT_OBJECT_0
+ 1
6485 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
6492 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
6494 unsigned long nblock
= 0;
6495 if (winsock_lib
== NULL
) abort ();
6497 /* TODO: implement select() properly so non-blocking I/O works. */
6498 /* For now, make sure the write blocks. */
6499 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6500 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6502 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
6504 /* Set the socket back to non-blocking if it was before,
6505 for other operations that support it. */
6506 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6509 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6512 if (nchars
== SOCKET_ERROR
)
6514 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
6515 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
6521 /* Some networked filesystems don't like too large writes, so
6522 break them into smaller chunks. See the Comments section of
6523 the MSDN documentation of WriteFile for details behind the
6524 choice of the value of CHUNK below. See also the thread
6525 http://thread.gmane.org/gmane.comp.version-control.git/145294
6526 in the git mailing list. */
6527 const unsigned char *p
= buffer
;
6528 const unsigned chunk
= 30 * 1024 * 1024;
6533 unsigned this_chunk
= count
< chunk
? count
: chunk
;
6534 int n
= _write (fd
, p
, this_chunk
);
6542 else if (n
< this_chunk
)
6552 /* The Windows CRT functions are "optimized for speed", so they don't
6553 check for timezone and DST changes if they were last called less
6554 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
6555 all Emacs features that repeatedly call time functions (e.g.,
6556 display-time) are in real danger of missing timezone and DST
6557 changes. Calling tzset before each localtime call fixes that. */
6559 sys_localtime (const time_t *t
)
6562 return localtime (t
);
6567 /* Delayed loading of libraries. */
6569 Lisp_Object Vlibrary_cache
;
6571 /* The argument LIBRARIES is an alist that associates a symbol
6572 LIBRARY_ID, identifying an external DLL library known to Emacs, to
6573 a list of filenames under which the library is usually found. In
6574 most cases, the argument passed as LIBRARIES is the variable
6575 `dynamic-library-alist', which is initialized to a list of common
6576 library names. If the function loads the library successfully, it
6577 returns the handle of the DLL, and records the filename in the
6578 property :loaded-from of LIBRARY_ID; it returns NULL if the library
6579 could not be found, or when it was already loaded (because the
6580 handle is not recorded anywhere, and so is lost after use). It
6581 would be trivial to save the handle too in :loaded-from, but
6582 currently there's no use case for it. */
6584 w32_delayed_load (Lisp_Object libraries
, Lisp_Object library_id
)
6586 HMODULE library_dll
= NULL
;
6588 CHECK_SYMBOL (library_id
);
6590 if (CONSP (libraries
) && NILP (Fassq (library_id
, Vlibrary_cache
)))
6592 Lisp_Object found
= Qnil
;
6593 Lisp_Object dlls
= Fassq (library_id
, libraries
);
6596 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
6598 CHECK_STRING_CAR (dlls
);
6599 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
6601 char name
[MAX_PATH
];
6604 len
= GetModuleFileNameA (library_dll
, name
, sizeof (name
));
6605 found
= Fcons (XCAR (dlls
),
6607 /* Possibly truncated */
6608 ? make_specified_string (name
, -1, len
, 1)
6614 Fput (library_id
, QCloaded_from
, found
);
6622 check_windows_init_file (void)
6624 /* A common indication that Emacs is not installed properly is when
6625 it cannot find the Windows installation file. If this file does
6626 not exist in the expected place, tell the user. */
6628 if (!noninteractive
&& !inhibit_window_system
6629 /* Vload_path is not yet initialized when we are loading
6631 && NILP (Vpurify_flag
))
6633 Lisp_Object objs
[2];
6634 Lisp_Object full_load_path
;
6635 Lisp_Object init_file
;
6638 objs
[0] = Vload_path
;
6639 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
6640 full_load_path
= Fappend (2, objs
);
6641 init_file
= build_string ("term/w32-win");
6642 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
6645 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
6646 char *init_file_name
= SDATA (init_file
);
6647 char *load_path
= SDATA (load_path_print
);
6648 char *buffer
= alloca (1024
6649 + strlen (init_file_name
)
6650 + strlen (load_path
));
6653 "The Emacs Windows initialization file \"%s.el\" "
6654 "could not be found in your Emacs installation. "
6655 "Emacs checked the following directories for this file:\n"
6657 "When Emacs cannot find this file, it usually means that it "
6658 "was not installed properly, or its distribution file was "
6659 "not unpacked properly.\nSee the README.W32 file in the "
6660 "top-level Emacs directory for more information.",
6661 init_file_name
, load_path
);
6664 "Emacs Abort Dialog",
6665 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
6666 /* Use the low-level Emacs abort. */
6680 /* shutdown the socket interface if necessary */
6689 /* Initialize the socket interface now if available and requested by
6690 the user by defining PRELOAD_WINSOCK; otherwise loading will be
6691 delayed until open-network-stream is called (w32-has-winsock can
6692 also be used to dynamically load or reload winsock).
6694 Conveniently, init_environment is called before us, so
6695 PRELOAD_WINSOCK can be set in the registry. */
6697 /* Always initialize this correctly. */
6700 if (getenv ("PRELOAD_WINSOCK") != NULL
)
6701 init_winsock (TRUE
);
6703 /* Initial preparation for subprocess support: replace our standard
6704 handles with non-inheritable versions. */
6707 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
6708 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
6709 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
6711 parent
= GetCurrentProcess ();
6713 /* ignore errors when duplicating and closing; typically the
6714 handles will be invalid when running as a gui program. */
6715 DuplicateHandle (parent
,
6716 GetStdHandle (STD_INPUT_HANDLE
),
6721 DUPLICATE_SAME_ACCESS
);
6723 DuplicateHandle (parent
,
6724 GetStdHandle (STD_OUTPUT_HANDLE
),
6729 DUPLICATE_SAME_ACCESS
);
6731 DuplicateHandle (parent
,
6732 GetStdHandle (STD_ERROR_HANDLE
),
6737 DUPLICATE_SAME_ACCESS
);
6743 if (stdin_save
!= INVALID_HANDLE_VALUE
)
6744 _open_osfhandle ((long) stdin_save
, O_TEXT
);
6746 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
6749 if (stdout_save
!= INVALID_HANDLE_VALUE
)
6750 _open_osfhandle ((long) stdout_save
, O_TEXT
);
6752 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
6755 if (stderr_save
!= INVALID_HANDLE_VALUE
)
6756 _open_osfhandle ((long) stderr_save
, O_TEXT
);
6758 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
6762 /* unfortunately, atexit depends on implementation of malloc */
6763 /* atexit (term_ntproc); */
6764 signal (SIGABRT
, term_ntproc
);
6766 /* determine which drives are fixed, for GetCachedVolumeInformation */
6768 /* GetDriveType must have trailing backslash. */
6769 char drive
[] = "A:\\";
6771 /* Loop over all possible drive letters */
6772 while (*drive
<= 'Z')
6774 /* Record if this drive letter refers to a fixed drive. */
6775 fixed_drives
[DRIVE_INDEX (*drive
)] =
6776 (GetDriveType (drive
) == DRIVE_FIXED
);
6781 /* Reset the volume info cache. */
6782 volume_cache
= NULL
;
6785 /* Check to see if Emacs has been installed correctly. */
6786 check_windows_init_file ();
6790 shutdown_handler ensures that buffers' autosave files are
6791 up to date when the user logs off, or the system shuts down.
6794 shutdown_handler (DWORD type
)
6796 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
6797 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
6798 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
6799 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
6801 /* Shut down cleanly, making sure autosave files are up to date. */
6802 shut_down_emacs (0, 0, Qnil
);
6805 /* Allow other handlers to handle this signal. */
6810 globals_of_w32 is used to initialize those global variables that
6811 must always be initialized on startup even when the global variable
6812 initialized is non zero (see the function main in emacs.c).
6815 globals_of_w32 (void)
6817 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
6819 get_process_times_fn
= (GetProcessTimes_Proc
)
6820 GetProcAddress (kernel32
, "GetProcessTimes");
6822 DEFSYM (QCloaded_from
, ":loaded-from");
6824 Vlibrary_cache
= Qnil
;
6825 staticpro (&Vlibrary_cache
);
6827 g_b_init_is_windows_9x
= 0;
6828 g_b_init_open_process_token
= 0;
6829 g_b_init_get_token_information
= 0;
6830 g_b_init_lookup_account_sid
= 0;
6831 g_b_init_get_sid_sub_authority
= 0;
6832 g_b_init_get_sid_sub_authority_count
= 0;
6833 g_b_init_get_security_info
= 0;
6834 g_b_init_get_file_security
= 0;
6835 g_b_init_get_security_descriptor_owner
= 0;
6836 g_b_init_get_security_descriptor_group
= 0;
6837 g_b_init_is_valid_sid
= 0;
6838 g_b_init_create_toolhelp32_snapshot
= 0;
6839 g_b_init_process32_first
= 0;
6840 g_b_init_process32_next
= 0;
6841 g_b_init_open_thread_token
= 0;
6842 g_b_init_impersonate_self
= 0;
6843 g_b_init_revert_to_self
= 0;
6844 g_b_init_get_process_memory_info
= 0;
6845 g_b_init_get_process_working_set_size
= 0;
6846 g_b_init_global_memory_status
= 0;
6847 g_b_init_global_memory_status_ex
= 0;
6848 g_b_init_equal_sid
= 0;
6849 g_b_init_copy_sid
= 0;
6850 g_b_init_get_length_sid
= 0;
6851 g_b_init_get_native_system_info
= 0;
6852 g_b_init_get_system_times
= 0;
6853 g_b_init_create_symbolic_link
= 0;
6854 num_of_processors
= 0;
6855 /* The following sets a handler for shutdown notifications for
6856 console apps. This actually applies to Emacs in both console and
6857 GUI modes, since we had to fool windows into thinking emacs is a
6858 console application to get console mode to work. */
6859 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
6861 /* "None" is the default group name on standalone workstations. */
6862 strcpy (dflt_group_name
, "None");
6865 /* For make-serial-process */
6867 serial_open (char *port
)
6873 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
6874 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
6875 if (hnd
== INVALID_HANDLE_VALUE
)
6876 error ("Could not open %s", port
);
6877 fd
= (int) _open_osfhandle ((int) hnd
, 0);
6879 error ("Could not open %s", port
);
6883 error ("Could not create child process");
6885 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6886 fd_info
[ fd
].hnd
= hnd
;
6887 fd_info
[ fd
].flags
|=
6888 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
6889 if (fd_info
[ fd
].cp
!= NULL
)
6891 error ("fd_info[fd = %d] is already in use", fd
);
6893 fd_info
[ fd
].cp
= cp
;
6894 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6895 if (cp
->ovl_read
.hEvent
== NULL
)
6896 error ("Could not create read event");
6897 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6898 if (cp
->ovl_write
.hEvent
== NULL
)
6899 error ("Could not create write event");
6904 /* For serial-process-configure */
6906 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
6908 Lisp_Object childp2
= Qnil
;
6909 Lisp_Object tem
= Qnil
;
6913 char summary
[4] = "???"; /* This usually becomes "8N1". */
6915 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6916 error ("Not a serial process");
6917 hnd
= fd_info
[ p
->outfd
].hnd
;
6919 childp2
= Fcopy_sequence (PVAR (p
, childp
));
6921 /* Initialize timeouts for blocking read and blocking write. */
6922 if (!GetCommTimeouts (hnd
, &ct
))
6923 error ("GetCommTimeouts() failed");
6924 ct
.ReadIntervalTimeout
= 0;
6925 ct
.ReadTotalTimeoutMultiplier
= 0;
6926 ct
.ReadTotalTimeoutConstant
= 0;
6927 ct
.WriteTotalTimeoutMultiplier
= 0;
6928 ct
.WriteTotalTimeoutConstant
= 0;
6929 if (!SetCommTimeouts (hnd
, &ct
))
6930 error ("SetCommTimeouts() failed");
6931 /* Read port attributes and prepare default configuration. */
6932 memset (&dcb
, 0, sizeof (dcb
));
6933 dcb
.DCBlength
= sizeof (DCB
);
6934 if (!GetCommState (hnd
, &dcb
))
6935 error ("GetCommState() failed");
6938 dcb
.fAbortOnError
= FALSE
;
6939 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6944 /* Configure speed. */
6945 if (!NILP (Fplist_member (contact
, QCspeed
)))
6946 tem
= Fplist_get (contact
, QCspeed
);
6948 tem
= Fplist_get (PVAR (p
, childp
), QCspeed
);
6950 dcb
.BaudRate
= XINT (tem
);
6951 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6953 /* Configure bytesize. */
6954 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6955 tem
= Fplist_get (contact
, QCbytesize
);
6957 tem
= Fplist_get (PVAR (p
, childp
), QCbytesize
);
6959 tem
= make_number (8);
6961 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6962 error (":bytesize must be nil (8), 7, or 8");
6963 dcb
.ByteSize
= XINT (tem
);
6964 summary
[0] = XINT (tem
) + '0';
6965 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6967 /* Configure parity. */
6968 if (!NILP (Fplist_member (contact
, QCparity
)))
6969 tem
= Fplist_get (contact
, QCparity
);
6971 tem
= Fplist_get (PVAR (p
, childp
), QCparity
);
6972 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6973 error (":parity must be nil (no parity), `even', or `odd'");
6974 dcb
.fParity
= FALSE
;
6975 dcb
.Parity
= NOPARITY
;
6976 dcb
.fErrorChar
= FALSE
;
6981 else if (EQ (tem
, Qeven
))
6985 dcb
.Parity
= EVENPARITY
;
6986 dcb
.fErrorChar
= TRUE
;
6988 else if (EQ (tem
, Qodd
))
6992 dcb
.Parity
= ODDPARITY
;
6993 dcb
.fErrorChar
= TRUE
;
6995 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6997 /* Configure stopbits. */
6998 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6999 tem
= Fplist_get (contact
, QCstopbits
);
7001 tem
= Fplist_get (PVAR (p
, childp
), QCstopbits
);
7003 tem
= make_number (1);
7005 if (XINT (tem
) != 1 && XINT (tem
) != 2)
7006 error (":stopbits must be nil (1 stopbit), 1, or 2");
7007 summary
[2] = XINT (tem
) + '0';
7008 if (XINT (tem
) == 1)
7009 dcb
.StopBits
= ONESTOPBIT
;
7010 else if (XINT (tem
) == 2)
7011 dcb
.StopBits
= TWOSTOPBITS
;
7012 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
7014 /* Configure flowcontrol. */
7015 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
7016 tem
= Fplist_get (contact
, QCflowcontrol
);
7018 tem
= Fplist_get (PVAR (p
, childp
), QCflowcontrol
);
7019 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
7020 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
7021 dcb
.fOutxCtsFlow
= FALSE
;
7022 dcb
.fOutxDsrFlow
= FALSE
;
7023 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
7024 dcb
.fDsrSensitivity
= FALSE
;
7025 dcb
.fTXContinueOnXoff
= FALSE
;
7028 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
7029 dcb
.XonChar
= 17; /* Control-Q */
7030 dcb
.XoffChar
= 19; /* Control-S */
7033 /* Already configured. */
7035 else if (EQ (tem
, Qhw
))
7037 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
7038 dcb
.fOutxCtsFlow
= TRUE
;
7040 else if (EQ (tem
, Qsw
))
7045 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
7047 /* Activate configuration. */
7048 if (!SetCommState (hnd
, &dcb
))
7049 error ("SetCommState() failed");
7051 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
7052 PVAR (p
, childp
) = childp2
;
7058 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
7062 struct timeval timeout
;
7063 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7064 int fd
= process
->infd
;
7068 n
= sys_read (fd
, (char*)buf
, sz
);
7075 if (err
== EWOULDBLOCK
)
7077 /* Set a small timeout. */
7079 timeout
.tv_usec
= 0;
7081 FD_SET ((int)fd
, &fdset
);
7083 /* Use select with the timeout to poll the selector. */
7084 sc
= select (fd
+ 1, &fdset
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0,
7088 continue; /* Try again. */
7090 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
7091 Also accept select return 0 as an indicator to EAGAIN. */
7092 if (sc
== 0 || errno
== EWOULDBLOCK
)
7095 err
= errno
; /* Other errors are just passed on. */
7098 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
7105 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
7107 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7108 int fd
= process
->outfd
;
7109 ssize_t n
= sys_write (fd
, buf
, sz
);
7111 /* 0 or more bytes written means everything went fine. */
7115 /* Negative bytes written means we got an error in errno.
7116 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7117 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
7118 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
7122 #endif /* HAVE_GNUTLS */