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
1712 /* If the default value is NULL, we will use the value from the
1713 outside environment or the Registry, but will not push the
1714 variable into the Emacs environment if it is defined neither
1715 in the Registry nor in the outside environment. */
1717 {"PRELOAD_WINSOCK", NULL
},
1718 {"emacs_dir", "C:/emacs"},
1719 {"EMACSLOADPATH", NULL
},
1720 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1721 {"EMACSDATA", NULL
},
1722 {"EMACSPATH", NULL
},
1729 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1731 /* We need to copy dflt_envvars[] and work on the copy because we
1732 don't want the dumped Emacs to inherit the values of
1733 environment variables we saw during dumping (which could be on
1734 a different system). The defaults above must be left intact. */
1735 struct env_entry env_vars
[N_ENV_VARS
];
1737 for (i
= 0; i
< N_ENV_VARS
; i
++)
1738 env_vars
[i
] = dflt_envvars
[i
];
1740 /* For backwards compatibility, check if a .emacs file exists in C:/
1741 If not, then we can try to default to the appdata directory under the
1742 user's profile, which is more likely to be writable. */
1743 if (stat ("C:/.emacs", &ignored
) < 0)
1745 HRESULT profile_result
;
1746 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1747 of Windows 95 and NT4 that have not been updated to include
1749 ShGetFolderPath_fn get_folder_path
;
1750 get_folder_path
= (ShGetFolderPath_fn
)
1751 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1753 if (get_folder_path
!= NULL
)
1755 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1758 /* If we can't get the appdata dir, revert to old behavior. */
1759 if (profile_result
== S_OK
)
1761 env_vars
[0].def_value
= default_home
;
1767 /* Get default locale info and use it for LANG. */
1768 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1769 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1770 locale_name
, sizeof (locale_name
)))
1772 for (i
= 0; i
< N_ENV_VARS
; i
++)
1774 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1776 env_vars
[i
].def_value
= locale_name
;
1782 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1784 /* Treat emacs_dir specially: set it unconditionally based on our
1788 char modname
[MAX_PATH
];
1790 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1792 if ((p
= strrchr (modname
, '\\')) == NULL
)
1796 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1798 char buf
[SET_ENV_BUF_SIZE
];
1801 for (p
= modname
; *p
; p
++)
1802 if (*p
== '\\') *p
= '/';
1804 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1805 _putenv (strdup (buf
));
1807 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1809 /* FIXME: should use substring of get_emacs_configuration ().
1810 But I don't think the Windows build supports alpha, mips etc
1811 anymore, so have taken the easy option for now. */
1812 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1815 p
= strrchr (modname
, '\\');
1819 p
= strrchr (modname
, '\\');
1820 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1822 char buf
[SET_ENV_BUF_SIZE
];
1825 for (p
= modname
; *p
; p
++)
1826 if (*p
== '\\') *p
= '/';
1828 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1829 _putenv (strdup (buf
));
1835 for (i
= 0; i
< N_ENV_VARS
; i
++)
1837 if (!getenv (env_vars
[i
].name
))
1841 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1842 /* Also ignore empty environment variables. */
1846 lpval
= env_vars
[i
].def_value
;
1847 dwType
= REG_EXPAND_SZ
;
1849 if (!strcmp (env_vars
[i
].name
, "HOME") && !appdata
)
1850 Vdelayed_warnings_list
1851 = Fcons (listn (CONSTYPE_HEAP
, 2,
1852 intern ("initialization"),
1853 build_string ("Setting HOME to C:\\ by default is deprecated")),
1854 Vdelayed_warnings_list
);
1859 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1861 if (dwType
== REG_EXPAND_SZ
)
1862 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1863 else if (dwType
== REG_SZ
)
1864 strcpy (buf1
, lpval
);
1865 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1867 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1869 _putenv (strdup (buf2
));
1879 /* Rebuild system configuration to reflect invoking system. */
1880 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1882 /* Another special case: on NT, the PATH variable is actually named
1883 "Path" although cmd.exe (perhaps NT itself) arranges for
1884 environment variable lookup and setting to be case insensitive.
1885 However, Emacs assumes a fully case sensitive environment, so we
1886 need to change "Path" to "PATH" to match the expectations of
1887 various elisp packages. We do this by the sneaky method of
1888 modifying the string in the C runtime environ entry.
1890 The same applies to COMSPEC. */
1894 for (envp
= environ
; *envp
; envp
++)
1895 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1896 memcpy (*envp
, "PATH=", 5);
1897 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1898 memcpy (*envp
, "COMSPEC=", 8);
1901 /* Remember the initial working directory for getwd. */
1902 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
1903 Does it matter anywhere in Emacs? */
1904 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1908 static char modname
[MAX_PATH
];
1910 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1915 /* Determine if there is a middle mouse button, to allow parse_button
1916 to decide whether right mouse events should be mouse-2 or
1918 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1923 /* Called from expand-file-name when default-directory is not a string. */
1926 emacs_root_dir (void)
1928 static char root_dir
[FILENAME_MAX
];
1931 p
= getenv ("emacs_dir");
1934 strcpy (root_dir
, p
);
1935 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1936 dostounix_filename (root_dir
);
1940 /* We don't have scripts to automatically determine the system configuration
1941 for Emacs before it's compiled, and we don't want to have to make the
1942 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1946 get_emacs_configuration (void)
1948 char *arch
, *oem
, *os
;
1950 static char configuration_buffer
[32];
1952 /* Determine the processor type. */
1953 switch (get_processor_type ())
1956 #ifdef PROCESSOR_INTEL_386
1957 case PROCESSOR_INTEL_386
:
1958 case PROCESSOR_INTEL_486
:
1959 case PROCESSOR_INTEL_PENTIUM
:
1964 #ifdef PROCESSOR_MIPS_R2000
1965 case PROCESSOR_MIPS_R2000
:
1966 case PROCESSOR_MIPS_R3000
:
1967 case PROCESSOR_MIPS_R4000
:
1972 #ifdef PROCESSOR_ALPHA_21064
1973 case PROCESSOR_ALPHA_21064
:
1983 /* Use the OEM field to reflect the compiler/library combination. */
1985 #define COMPILER_NAME "msvc"
1988 #define COMPILER_NAME "mingw"
1990 #define COMPILER_NAME "unknown"
1993 oem
= COMPILER_NAME
;
1995 switch (osinfo_cache
.dwPlatformId
) {
1996 case VER_PLATFORM_WIN32_NT
:
1998 build_num
= osinfo_cache
.dwBuildNumber
;
2000 case VER_PLATFORM_WIN32_WINDOWS
:
2001 if (osinfo_cache
.dwMinorVersion
== 0) {
2006 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
2008 case VER_PLATFORM_WIN32s
:
2009 /* Not supported, should not happen. */
2011 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
2019 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
2020 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
2021 get_w32_major_version (), get_w32_minor_version (), build_num
);
2023 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
2026 return configuration_buffer
;
2030 get_emacs_configuration_options (void)
2032 static char *options_buffer
;
2033 char cv
[32]; /* Enough for COMPILER_VERSION. */
2035 cv
, /* To be filled later. */
2039 #ifdef ENABLE_CHECKING
2040 " --enable-checking",
2042 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2043 with a starting space to save work here. */
2045 " --cflags", USER_CFLAGS
,
2048 " --ldflags", USER_LDFLAGS
,
2055 /* Work out the effective configure options for this build. */
2057 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2060 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2062 #define COMPILER_VERSION ""
2066 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
2067 return "Error: not enough space for compiler version";
2068 cv
[sizeof (cv
) - 1] = '\0';
2070 for (i
= 0; options
[i
]; i
++)
2071 size
+= strlen (options
[i
]);
2073 options_buffer
= xmalloc (size
+ 1);
2074 options_buffer
[0] = '\0';
2076 for (i
= 0; options
[i
]; i
++)
2077 strcat (options_buffer
, options
[i
]);
2079 return options_buffer
;
2083 #include <sys/timeb.h>
2085 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2087 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
2092 tv
->tv_sec
= tb
.time
;
2093 tv
->tv_usec
= tb
.millitm
* 1000L;
2094 /* Implementation note: _ftime sometimes doesn't update the dstflag
2095 according to the new timezone when the system timezone is
2096 changed. We could fix that by using GetSystemTime and
2097 GetTimeZoneInformation, but that doesn't seem necessary, since
2098 Emacs always calls gettimeofday with the 2nd argument NULL (see
2099 current_emacs_time). */
2102 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
2103 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
2107 /* Emulate fdutimens. */
2109 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2110 TIMESPEC[0] and TIMESPEC[1], respectively.
2111 FD must be either negative -- in which case it is ignored --
2112 or a file descriptor that is open on FILE.
2113 If FD is nonnegative, then FILE can be NULL, which means
2114 use just futimes instead of utimes.
2115 If TIMESPEC is null, FAIL.
2116 Return 0 on success, -1 (setting errno) on failure. */
2119 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
2128 if (fd
< 0 && !file
)
2133 ut
.actime
= timespec
[0].tv_sec
;
2134 ut
.modtime
= timespec
[1].tv_sec
;
2136 return _futime (fd
, &ut
);
2138 return _utime (file
, &ut
);
2142 /* ------------------------------------------------------------------------- */
2143 /* IO support and wrapper functions for the Windows API. */
2144 /* ------------------------------------------------------------------------- */
2146 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2147 on network directories, so we handle that case here.
2148 (Ulrich Leodolter, 1/11/95). */
2150 sys_ctime (const time_t *t
)
2152 char *str
= (char *) ctime (t
);
2153 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2156 /* Emulate sleep...we could have done this with a define, but that
2157 would necessitate including windows.h in the files that used it.
2158 This is much easier. */
2160 sys_sleep (int seconds
)
2162 Sleep (seconds
* 1000);
2165 /* Internal MSVC functions for low-level descriptor munging */
2166 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2167 extern int __cdecl
_free_osfhnd (int fd
);
2169 /* parallel array of private info on file handles */
2170 filedesc fd_info
[ MAXDESC
];
2172 typedef struct volume_info_data
{
2173 struct volume_info_data
* next
;
2175 /* time when info was obtained */
2178 /* actual volume info */
2187 /* Global referenced by various functions. */
2188 static volume_info_data volume_info
;
2190 /* Vector to indicate which drives are local and fixed (for which cached
2191 data never expires). */
2192 static BOOL fixed_drives
[26];
2194 /* Consider cached volume information to be stale if older than 10s,
2195 at least for non-local drives. Info for fixed drives is never stale. */
2196 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2197 #define VOLINFO_STILL_VALID( root_dir, info ) \
2198 ( ( isalpha (root_dir[0]) && \
2199 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2200 || GetTickCount () - info->timestamp < 10000 )
2202 /* Cache support functions. */
2204 /* Simple linked list with linear search is sufficient. */
2205 static volume_info_data
*volume_cache
= NULL
;
2207 static volume_info_data
*
2208 lookup_volume_info (char * root_dir
)
2210 volume_info_data
* info
;
2212 for (info
= volume_cache
; info
; info
= info
->next
)
2213 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2219 add_volume_info (char * root_dir
, volume_info_data
* info
)
2221 info
->root_dir
= xstrdup (root_dir
);
2222 info
->next
= volume_cache
;
2223 volume_cache
= info
;
2227 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2228 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2229 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2230 static volume_info_data
*
2231 GetCachedVolumeInformation (char * root_dir
)
2233 volume_info_data
* info
;
2234 char default_root
[ MAX_PATH
];
2236 /* NULL for root_dir means use root from current directory. */
2237 if (root_dir
== NULL
)
2239 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2241 parse_root (default_root
, &root_dir
);
2243 root_dir
= default_root
;
2246 /* Local fixed drives can be cached permanently. Removable drives
2247 cannot be cached permanently, since the volume name and serial
2248 number (if nothing else) can change. Remote drives should be
2249 treated as if they are removable, since there is no sure way to
2250 tell whether they are or not. Also, the UNC association of drive
2251 letters mapped to remote volumes can be changed at any time (even
2252 by other processes) without notice.
2254 As a compromise, so we can benefit from caching info for remote
2255 volumes, we use a simple expiry mechanism to invalidate cache
2256 entries that are more than ten seconds old. */
2259 /* No point doing this, because WNetGetConnection is even slower than
2260 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2261 GetDriveType is about the only call of this type which does not
2262 involve network access, and so is extremely quick). */
2264 /* Map drive letter to UNC if remote. */
2265 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2267 char remote_name
[ 256 ];
2268 char drive
[3] = { root_dir
[0], ':' };
2270 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2272 /* do something */ ;
2276 info
= lookup_volume_info (root_dir
);
2278 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2286 /* Info is not cached, or is stale. */
2287 if (!GetVolumeInformation (root_dir
,
2288 name
, sizeof (name
),
2292 type
, sizeof (type
)))
2295 /* Cache the volume information for future use, overwriting existing
2296 entry if present. */
2299 info
= xmalloc (sizeof (volume_info_data
));
2300 add_volume_info (root_dir
, info
);
2308 info
->name
= xstrdup (name
);
2309 info
->serialnum
= serialnum
;
2310 info
->maxcomp
= maxcomp
;
2311 info
->flags
= flags
;
2312 info
->type
= xstrdup (type
);
2313 info
->timestamp
= GetTickCount ();
2319 /* Get information on the volume where NAME is held; set path pointer to
2320 start of pathname in NAME (past UNC header\volume header if present),
2321 if pPath is non-NULL.
2323 Note: if NAME includes symlinks, the information is for the volume
2324 of the symlink, not of its target. That's because, even though
2325 GetVolumeInformation returns information about the symlink target
2326 of its argument, we only pass the root directory to
2327 GetVolumeInformation, not the full NAME. */
2329 get_volume_info (const char * name
, const char ** pPath
)
2331 char temp
[MAX_PATH
];
2332 char *rootname
= NULL
; /* default to current volume */
2333 volume_info_data
* info
;
2338 /* Find the root name of the volume if given. */
2339 if (isalpha (name
[0]) && name
[1] == ':')
2347 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2354 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2367 info
= GetCachedVolumeInformation (rootname
);
2370 /* Set global referenced by other functions. */
2371 volume_info
= *info
;
2377 /* Determine if volume is FAT format (ie. only supports short 8.3
2378 names); also set path pointer to start of pathname in name, if
2379 pPath is non-NULL. */
2381 is_fat_volume (const char * name
, const char ** pPath
)
2383 if (get_volume_info (name
, pPath
))
2384 return (volume_info
.maxcomp
== 12);
2388 /* Map filename to a valid 8.3 name if necessary.
2389 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2391 map_w32_filename (const char * name
, const char ** pPath
)
2393 static char shortname
[MAX_PATH
];
2394 char * str
= shortname
;
2397 const char * save_name
= name
;
2400 if (strlen (name
) >= MAX_PATH
)
2402 /* Return a filename which will cause callers to fail. */
2403 strcpy (shortname
, "?");
2407 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2409 register int left
= 8; /* maximum number of chars in part */
2410 register int extn
= 0; /* extension added? */
2411 register int dots
= 2; /* maximum number of dots allowed */
2414 *str
++ = *name
++; /* skip past UNC header */
2416 while ((c
= *name
++))
2423 *str
++ = (c
== ':' ? ':' : '\\');
2424 extn
= 0; /* reset extension flags */
2425 dots
= 2; /* max 2 dots */
2426 left
= 8; /* max length 8 for main part */
2431 /* Convert path components of the form .xxx to _xxx,
2432 but leave . and .. as they are. This allows .emacs
2433 to be read as _emacs, for example. */
2437 IS_DIRECTORY_SEP (*name
))
2452 extn
= 1; /* we've got an extension */
2453 left
= 3; /* 3 chars in extension */
2457 /* any embedded dots after the first are converted to _ */
2462 case '#': /* don't lose these, they're important */
2464 str
[-1] = c
; /* replace last character of part */
2469 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2471 dots
= 0; /* started a path component */
2480 strcpy (shortname
, name
);
2481 unixtodos_filename (shortname
);
2485 *pPath
= shortname
+ (path
- save_name
);
2491 is_exec (const char * name
)
2493 char * p
= strrchr (name
, '.');
2496 && (xstrcasecmp (p
, ".exe") == 0 ||
2497 xstrcasecmp (p
, ".com") == 0 ||
2498 xstrcasecmp (p
, ".bat") == 0 ||
2499 xstrcasecmp (p
, ".cmd") == 0));
2502 /* Emulate the Unix directory procedures opendir, closedir,
2503 and readdir. We can't use the procedures supplied in sysdep.c,
2504 so we provide them here. */
2506 struct direct dir_static
; /* simulated directory contents */
2507 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2508 static int dir_is_fat
;
2509 static char dir_pathname
[MAXPATHLEN
+1];
2510 static WIN32_FIND_DATA dir_find_data
;
2512 /* Support shares on a network resource as subdirectories of a read-only
2514 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2515 static HANDLE
open_unc_volume (const char *);
2516 static char *read_unc_volume (HANDLE
, char *, int);
2517 static void close_unc_volume (HANDLE
);
2520 opendir (char *filename
)
2524 /* Opening is done by FindFirstFile. However, a read is inherent to
2525 this operation, so we defer the open until read time. */
2527 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2529 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2532 /* Note: We don't support traversal of UNC volumes via symlinks.
2533 Doing so would mean punishing 99.99% of use cases by resolving
2534 all the possible symlinks in FILENAME, recursively. */
2535 if (is_unc_volume (filename
))
2537 wnet_enum_handle
= open_unc_volume (filename
);
2538 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2542 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2549 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2550 dir_pathname
[MAXPATHLEN
] = '\0';
2551 /* Note: We don't support symlinks to file names on FAT volumes.
2552 Doing so would mean punishing 99.99% of use cases by resolving
2553 all the possible symlinks in FILENAME, recursively. */
2554 dir_is_fat
= is_fat_volume (filename
, NULL
);
2560 closedir (DIR *dirp
)
2562 /* If we have a find-handle open, close it. */
2563 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2565 FindClose (dir_find_handle
);
2566 dir_find_handle
= INVALID_HANDLE_VALUE
;
2568 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2570 close_unc_volume (wnet_enum_handle
);
2571 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2573 xfree ((char *) dirp
);
2579 int downcase
= !NILP (Vw32_downcase_file_names
);
2581 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2583 if (!read_unc_volume (wnet_enum_handle
,
2584 dir_find_data
.cFileName
,
2588 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2589 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2591 char filename
[MAXNAMLEN
+ 3];
2594 strcpy (filename
, dir_pathname
);
2595 ln
= strlen (filename
) - 1;
2596 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2597 strcat (filename
, "\\");
2598 strcat (filename
, "*");
2600 /* Note: No need to resolve symlinks in FILENAME, because
2601 FindFirst opens the directory that is the target of a
2603 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2605 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2610 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2614 /* Emacs never uses this value, so don't bother making it match
2615 value returned by stat(). */
2616 dir_static
.d_ino
= 1;
2618 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2620 /* If the file name in cFileName[] includes `?' characters, it means
2621 the original file name used characters that cannot be represented
2622 by the current ANSI codepage. To avoid total lossage, retrieve
2623 the short 8+3 alias of the long file name. */
2624 if (_mbspbrk (dir_static
.d_name
, "?"))
2626 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2627 downcase
= 1; /* 8+3 aliases are returned in all caps */
2629 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2630 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2631 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2633 /* If the file name in cFileName[] includes `?' characters, it means
2634 the original file name used characters that cannot be represented
2635 by the current ANSI codepage. To avoid total lossage, retrieve
2636 the short 8+3 alias of the long file name. */
2637 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2639 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2640 /* 8+3 aliases are returned in all caps, which could break
2641 various alists that look at filenames' extensions. */
2645 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2646 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2648 _strlwr (dir_static
.d_name
);
2652 for (p
= dir_static
.d_name
; *p
; p
++)
2653 if (*p
>= 'a' && *p
<= 'z')
2656 _strlwr (dir_static
.d_name
);
2663 open_unc_volume (const char *path
)
2669 nr
.dwScope
= RESOURCE_GLOBALNET
;
2670 nr
.dwType
= RESOURCETYPE_DISK
;
2671 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2672 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2673 nr
.lpLocalName
= NULL
;
2674 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2675 nr
.lpComment
= NULL
;
2676 nr
.lpProvider
= NULL
;
2678 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2679 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2681 if (result
== NO_ERROR
)
2684 return INVALID_HANDLE_VALUE
;
2688 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2692 DWORD bufsize
= 512;
2697 buffer
= alloca (bufsize
);
2698 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
2699 if (result
!= NO_ERROR
)
2702 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2703 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2705 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2708 strncpy (readbuf
, ptr
, size
);
2713 close_unc_volume (HANDLE henum
)
2715 if (henum
!= INVALID_HANDLE_VALUE
)
2716 WNetCloseEnum (henum
);
2720 unc_volume_file_attributes (const char *path
)
2725 henum
= open_unc_volume (path
);
2726 if (henum
== INVALID_HANDLE_VALUE
)
2729 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2731 close_unc_volume (henum
);
2736 /* Ensure a network connection is authenticated. */
2738 logon_network_drive (const char *path
)
2740 NETRESOURCE resource
;
2741 char share
[MAX_PATH
];
2746 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2747 drvtype
= DRIVE_REMOTE
;
2748 else if (path
[0] == '\0' || path
[1] != ':')
2749 drvtype
= GetDriveType (NULL
);
2756 drvtype
= GetDriveType (drive
);
2759 /* Only logon to networked drives. */
2760 if (drvtype
!= DRIVE_REMOTE
)
2764 strncpy (share
, path
, MAX_PATH
);
2765 /* Truncate to just server and share name. */
2766 for (i
= 2; i
< MAX_PATH
; i
++)
2768 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2775 resource
.dwType
= RESOURCETYPE_DISK
;
2776 resource
.lpLocalName
= NULL
;
2777 resource
.lpRemoteName
= share
;
2778 resource
.lpProvider
= NULL
;
2780 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2783 /* Shadow some MSVC runtime functions to map requests for long filenames
2784 to reasonable short names if necessary. This was originally added to
2785 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2789 sys_access (const char * path
, int mode
)
2793 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
2794 newer versions blow up when passed D_OK. */
2795 path
= map_w32_filename (path
, NULL
);
2796 /* If the last element of PATH is a symlink, we need to resolve it
2797 to get the attributes of its target file. Note: any symlinks in
2798 PATH elements other than the last one are transparently resolved
2799 by GetFileAttributes below. */
2800 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
2801 path
= chase_symlinks (path
);
2803 if ((attributes
= GetFileAttributes (path
)) == -1)
2805 DWORD w32err
= GetLastError ();
2809 case ERROR_INVALID_NAME
:
2810 case ERROR_BAD_PATHNAME
:
2811 if (is_unc_volume (path
))
2813 attributes
= unc_volume_file_attributes (path
);
2814 if (attributes
== -1)
2822 case ERROR_FILE_NOT_FOUND
:
2823 case ERROR_BAD_NETPATH
:
2832 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2837 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2842 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2851 sys_chdir (const char * path
)
2853 return _chdir (map_w32_filename (path
, NULL
));
2857 sys_chmod (const char * path
, int mode
)
2859 path
= chase_symlinks (map_w32_filename (path
, NULL
));
2860 return _chmod (path
, mode
);
2864 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2866 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2872 sys_creat (const char * path
, int mode
)
2874 return _creat (map_w32_filename (path
, NULL
), mode
);
2878 sys_fopen (const char * path
, const char * mode
)
2882 const char * mode_save
= mode
;
2884 /* Force all file handles to be non-inheritable. This is necessary to
2885 ensure child processes don't unwittingly inherit handles that might
2886 prevent future file access. */
2890 else if (mode
[0] == 'w' || mode
[0] == 'a')
2891 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2895 /* Only do simplistic option parsing. */
2899 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2902 else if (mode
[0] == 'b')
2907 else if (mode
[0] == 't')
2914 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2918 return _fdopen (fd
, mode_save
);
2921 /* This only works on NTFS volumes, but is useful to have. */
2923 sys_link (const char * old
, const char * new)
2927 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2929 if (old
== NULL
|| new == NULL
)
2935 strcpy (oldname
, map_w32_filename (old
, NULL
));
2936 strcpy (newname
, map_w32_filename (new, NULL
));
2938 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2939 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2940 if (fileh
!= INVALID_HANDLE_VALUE
)
2944 /* Confusingly, the "alternate" stream name field does not apply
2945 when restoring a hard link, and instead contains the actual
2946 stream data for the link (ie. the name of the link to create).
2947 The WIN32_STREAM_ID structure before the cStreamName field is
2948 the stream header, which is then immediately followed by the
2952 WIN32_STREAM_ID wid
;
2953 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2956 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2957 data
.wid
.cStreamName
, MAX_PATH
);
2960 LPVOID context
= NULL
;
2963 data
.wid
.dwStreamId
= BACKUP_LINK
;
2964 data
.wid
.dwStreamAttributes
= 0;
2965 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2966 data
.wid
.Size
.HighPart
= 0;
2967 data
.wid
.dwStreamNameSize
= 0;
2969 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2970 offsetof (WIN32_STREAM_ID
, cStreamName
)
2971 + data
.wid
.Size
.LowPart
,
2972 &wbytes
, FALSE
, FALSE
, &context
)
2973 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2980 /* Should try mapping GetLastError to errno; for now just
2981 indicate a general error (eg. links not supported). */
2982 errno
= EINVAL
; // perhaps EMLINK?
2986 CloseHandle (fileh
);
2995 sys_mkdir (const char * path
)
2997 return _mkdir (map_w32_filename (path
, NULL
));
3000 /* Because of long name mapping issues, we need to implement this
3001 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
3002 a unique name, instead of setting the input template to an empty
3005 Standard algorithm seems to be use pid or tid with a letter on the
3006 front (in place of the 6 X's) and cycle through the letters to find a
3007 unique name. We extend that to allow any reasonable character as the
3008 first of the 6 X's. */
3010 sys_mktemp (char * template)
3014 unsigned uid
= GetCurrentThreadId ();
3015 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3017 if (template == NULL
)
3019 p
= template + strlen (template);
3021 /* replace up to the last 5 X's with uid in decimal */
3022 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
3024 p
[0] = '0' + uid
% 10;
3028 if (i
< 0 && p
[0] == 'X')
3033 int save_errno
= errno
;
3034 p
[0] = first_char
[i
];
3035 if (sys_access (template, 0) < 0)
3041 while (++i
< sizeof (first_char
));
3044 /* Template is badly formed or else we can't generate a unique name,
3045 so return empty string */
3051 sys_open (const char * path
, int oflag
, int mode
)
3053 const char* mpath
= map_w32_filename (path
, NULL
);
3054 /* Try to open file without _O_CREAT, to be able to write to hidden
3055 and system files. Force all file handles to be
3057 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3060 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
3064 sys_rename (const char * oldname
, const char * newname
)
3067 char temp
[MAX_PATH
];
3071 /* MoveFile on Windows 95 doesn't correctly change the short file name
3072 alias in a number of circumstances (it is not easy to predict when
3073 just by looking at oldname and newname, unfortunately). In these
3074 cases, renaming through a temporary name avoids the problem.
3076 A second problem on Windows 95 is that renaming through a temp name when
3077 newname is uppercase fails (the final long name ends up in
3078 lowercase, although the short alias might be uppercase) UNLESS the
3079 long temp name is not 8.3.
3081 So, on Windows 95 we always rename through a temp name, and we make sure
3082 the temp name has a long extension to ensure correct renaming. */
3084 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3086 /* volume_info is set indirectly by map_w32_filename. */
3087 oldname_dev
= volume_info
.serialnum
;
3089 if (os_subtype
== OS_9X
)
3095 oldname
= map_w32_filename (oldname
, NULL
);
3096 if ((o
= strrchr (oldname
, '\\')))
3099 o
= (char *) oldname
;
3101 if ((p
= strrchr (temp
, '\\')))
3108 /* Force temp name to require a manufactured 8.3 alias - this
3109 seems to make the second rename work properly. */
3110 sprintf (p
, "_.%s.%u", o
, i
);
3112 result
= rename (oldname
, temp
);
3114 /* This loop must surely terminate! */
3115 while (result
< 0 && errno
== EEXIST
);
3120 /* Emulate Unix behavior - newname is deleted if it already exists
3121 (at least if it is a file; don't do this for directories).
3123 Since we mustn't do this if we are just changing the case of the
3124 file name (we would end up deleting the file we are trying to
3125 rename!), we let rename detect if the destination file already
3126 exists - that way we avoid the possible pitfalls of trying to
3127 determine ourselves whether two names really refer to the same
3128 file, which is not always possible in the general case. (Consider
3129 all the permutations of shared or subst'd drives, etc.) */
3131 newname
= map_w32_filename (newname
, NULL
);
3133 /* volume_info is set indirectly by map_w32_filename. */
3134 newname_dev
= volume_info
.serialnum
;
3136 result
= rename (temp
, newname
);
3140 DWORD w32err
= GetLastError ();
3143 && newname_dev
!= oldname_dev
)
3145 /* The implementation of `rename' on Windows does not return
3146 errno = EXDEV when you are moving a directory to a
3147 different storage device (ex. logical disk). It returns
3148 EACCES instead. So here we handle such situations and
3152 if ((attributes
= GetFileAttributes (temp
)) != -1
3153 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3156 else if (errno
== EEXIST
)
3158 if (_chmod (newname
, 0666) != 0)
3160 if (_unlink (newname
) != 0)
3162 result
= rename (temp
, newname
);
3164 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
3165 && is_symlink (temp
))
3167 /* This is Windows prohibiting the user from creating a
3168 symlink in another place, since that requires
3178 sys_rmdir (const char * path
)
3180 return _rmdir (map_w32_filename (path
, NULL
));
3184 sys_unlink (const char * path
)
3186 path
= map_w32_filename (path
, NULL
);
3188 /* On Unix, unlink works without write permission. */
3189 _chmod (path
, 0666);
3190 return _unlink (path
);
3193 static FILETIME utc_base_ft
;
3194 static ULONGLONG utc_base
; /* In 100ns units */
3195 static int init
= 0;
3197 #define FILETIME_TO_U64(result, ft) \
3199 ULARGE_INTEGER uiTemp; \
3200 uiTemp.LowPart = (ft).dwLowDateTime; \
3201 uiTemp.HighPart = (ft).dwHighDateTime; \
3202 result = uiTemp.QuadPart; \
3206 initialize_utc_base (void)
3208 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3217 st
.wMilliseconds
= 0;
3219 SystemTimeToFileTime (&st
, &utc_base_ft
);
3220 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3224 convert_time (FILETIME ft
)
3230 initialize_utc_base ();
3234 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3237 FILETIME_TO_U64 (tmp
, ft
);
3238 return (time_t) ((tmp
- utc_base
) / 10000000L);
3242 convert_from_time_t (time_t time
, FILETIME
* pft
)
3248 initialize_utc_base ();
3252 /* time in 100ns units since 1-Jan-1601 */
3253 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3254 pft
->dwHighDateTime
= tmp
.HighPart
;
3255 pft
->dwLowDateTime
= tmp
.LowPart
;
3259 /* No reason to keep this; faking inode values either by hashing or even
3260 using the file index from GetInformationByHandle, is not perfect and
3261 so by default Emacs doesn't use the inode values on Windows.
3262 Instead, we now determine file-truename correctly (except for
3263 possible drive aliasing etc). */
3265 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3267 hashval (const unsigned char * str
)
3272 h
= (h
<< 4) + *str
++;
3278 /* Return the hash value of the canonical pathname, excluding the
3279 drive/UNC header, to get a hopefully unique inode number. */
3281 generate_inode_val (const char * name
)
3283 char fullname
[ MAX_PATH
];
3287 /* Get the truly canonical filename, if it exists. (Note: this
3288 doesn't resolve aliasing due to subst commands, or recognize hard
3290 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3293 parse_root (fullname
, &p
);
3294 /* Normal W32 filesystems are still case insensitive. */
3301 static PSECURITY_DESCRIPTOR
3302 get_file_security_desc_by_handle (HANDLE h
)
3304 PSECURITY_DESCRIPTOR psd
= NULL
;
3306 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3307 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3309 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
3310 NULL
, NULL
, NULL
, NULL
, &psd
);
3311 if (err
!= ERROR_SUCCESS
)
3317 static PSECURITY_DESCRIPTOR
3318 get_file_security_desc_by_name (const char *fname
)
3320 PSECURITY_DESCRIPTOR psd
= NULL
;
3322 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3323 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3325 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3327 err
= GetLastError ();
3328 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3332 psd
= xmalloc (sd_len
);
3333 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3345 unsigned n_subauthorities
;
3347 /* Use the last sub-authority value of the RID, the relative
3348 portion of the SID, as user/group ID. */
3349 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3350 if (n_subauthorities
< 1)
3351 return 0; /* the "World" RID */
3352 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3355 /* Caching SID and account values for faster lokup. */
3358 # define FLEXIBLE_ARRAY_MEMBER
3360 # define FLEXIBLE_ARRAY_MEMBER 1
3365 struct w32_id
*next
;
3367 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3370 static struct w32_id
*w32_idlist
;
3373 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3375 struct w32_id
*tail
, *found
;
3377 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3379 if (equal_sid ((PSID
)tail
->sid
, sid
))
3388 strcpy (name
, found
->name
);
3396 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3399 struct w32_id
*new_entry
;
3401 /* We don't want to leave behind stale cache from when Emacs was
3405 sid_len
= get_length_sid (sid
);
3406 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3409 new_entry
->rid
= id
;
3410 strcpy (new_entry
->name
, name
);
3411 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3412 new_entry
->next
= w32_idlist
;
3413 w32_idlist
= new_entry
;
3422 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3423 unsigned *id
, char *nm
, int what
)
3426 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3428 SID_NAME_USE ignore
;
3430 DWORD name_len
= sizeof (name
);
3432 DWORD domain_len
= sizeof (domain
);
3438 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3439 else if (what
== GID
)
3440 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3444 if (!result
|| !is_valid_sid (sid
))
3446 else if (!w32_cached_id (sid
, id
, nm
))
3448 /* If FNAME is a UNC, we need to lookup account on the
3449 specified machine. */
3450 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3451 && fname
[2] != '\0')
3456 for (s
= fname
+ 2, p
= machine
;
3457 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3463 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3464 domain
, &domain_len
, &ignore
)
3465 || name_len
> UNLEN
+1)
3469 *id
= get_rid (sid
);
3471 w32_add_to_cache (sid
, *id
, name
);
3478 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3482 int dflt_usr
= 0, dflt_grp
= 0;
3491 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3493 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3496 /* Consider files to belong to current user/group, if we cannot get
3497 more accurate information. */
3500 st
->st_uid
= dflt_passwd
.pw_uid
;
3501 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3505 st
->st_gid
= dflt_passwd
.pw_gid
;
3506 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3510 /* Return non-zero if NAME is a potentially slow filesystem. */
3512 is_slow_fs (const char *name
)
3517 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3518 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3519 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3520 devtype
= GetDriveType (NULL
); /* use root of current drive */
3523 /* GetDriveType needs the root directory of the drive. */
3524 strncpy (drive_root
, name
, 2);
3525 drive_root
[2] = '\\';
3526 drive_root
[3] = '\0';
3527 devtype
= GetDriveType (drive_root
);
3529 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3532 /* MSVC stat function can't cope with UNC names and has other bugs, so
3533 replace it with our own. This also allows us to calculate consistent
3534 inode values and owner/group without hacks in the main Emacs code. */
3537 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
3539 char *name
, *save_name
, *r
;
3540 WIN32_FIND_DATA wfd
;
3542 unsigned __int64 fake_inode
= 0;
3545 int rootdir
= FALSE
;
3546 PSECURITY_DESCRIPTOR psd
= NULL
;
3547 int is_a_symlink
= 0;
3548 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
3549 DWORD access_rights
= 0;
3550 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
3551 FILETIME ctime
, atime
, wtime
;
3553 if (path
== NULL
|| buf
== NULL
)
3559 save_name
= name
= (char *) map_w32_filename (path
, &path
);
3560 /* Must be valid filename, no wild cards or other invalid
3561 characters. We use _mbspbrk to support multibyte strings that
3562 might look to strpbrk as if they included literal *, ?, and other
3563 characters mentioned below that are disallowed by Windows
3565 if (_mbspbrk (name
, "*?|<>\""))
3571 /* Remove trailing directory separator, unless name is the root
3572 directory of a drive or UNC volume in which case ensure there
3573 is a trailing separator. */
3574 len
= strlen (name
);
3575 name
= strcpy (alloca (len
+ 2), name
);
3577 /* Avoid a somewhat costly call to is_symlink if the filesystem
3578 doesn't support symlinks. */
3579 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
3580 is_a_symlink
= is_symlink (name
);
3582 /* Plan A: Open the file and get all the necessary information via
3583 the resulting handle. This solves several issues in one blow:
3585 . retrieves attributes for the target of a symlink, if needed
3586 . gets attributes of root directories and symlinks pointing to
3587 root directories, thus avoiding the need for special-casing
3588 these and detecting them by examining the file-name format
3589 . retrieves more accurate attributes (e.g., non-zero size for
3590 some directories, esp. directories that are junction points)
3591 . correctly resolves "c:/..", "/.." and similar file names
3592 . avoids run-time penalties for 99% of use cases
3594 Plan A is always tried first, unless the user asked not to (but
3595 if the file is a symlink and we need to follow links, we try Plan
3596 A even if the user asked not to).
3598 If Plan A fails, we go to Plan B (below), where various
3599 potentially expensive techniques must be used to handle "special"
3600 files such as UNC volumes etc. */
3601 if (!(NILP (Vw32_get_true_file_attributes
)
3602 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3603 /* Following symlinks requires getting the info by handle. */
3604 || (is_a_symlink
&& follow_symlinks
))
3606 BY_HANDLE_FILE_INFORMATION info
;
3608 if (is_a_symlink
&& !follow_symlinks
)
3609 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
3610 /* READ_CONTROL access rights are required to get security info
3611 by handle. But if the OS doesn't support security in the
3612 first place, we don't need to try. */
3613 if (is_windows_9x () != TRUE
)
3614 access_rights
|= READ_CONTROL
;
3616 fh
= CreateFile (name
, access_rights
, 0, NULL
, OPEN_EXISTING
,
3618 /* If CreateFile fails with READ_CONTROL, try again with zero as
3620 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
3621 fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3623 if (fh
== INVALID_HANDLE_VALUE
)
3624 goto no_true_file_attributes
;
3626 /* This is more accurate in terms of getting the correct number
3627 of links, but is quite slow (it is noticeable when Emacs is
3628 making a list of file name completions). */
3629 if (GetFileInformationByHandle (fh
, &info
))
3631 nlinks
= info
.nNumberOfLinks
;
3632 /* Might as well use file index to fake inode values, but this
3633 is not guaranteed to be unique unless we keep a handle open
3634 all the time (even then there are situations where it is
3635 not unique). Reputedly, there are at most 48 bits of info
3636 (on NTFS, presumably less on FAT). */
3637 fake_inode
= info
.nFileIndexHigh
;
3639 fake_inode
+= info
.nFileIndexLow
;
3640 serialnum
= info
.dwVolumeSerialNumber
;
3641 fs_high
= info
.nFileSizeHigh
;
3642 fs_low
= info
.nFileSizeLow
;
3643 ctime
= info
.ftCreationTime
;
3644 atime
= info
.ftLastAccessTime
;
3645 wtime
= info
.ftLastWriteTime
;
3646 fattrs
= info
.dwFileAttributes
;
3650 /* We don't go to Plan B here, because it's not clear that
3651 it's a good idea. The only known use case where
3652 CreateFile succeeds, but GetFileInformationByHandle fails
3653 (with ERROR_INVALID_FUNCTION) is for character devices
3654 such as NUL, PRN, etc. For these, switching to Plan B is
3655 a net loss, because we lose the character device
3656 attribute returned by GetFileType below (FindFirstFile
3657 doesn't set that bit in the attributes), and the other
3658 fields don't make sense for character devices anyway.
3659 Emacs doesn't really care for non-file entities in the
3660 context of l?stat, so neither do we. */
3662 /* w32err is assigned so one could put a breakpoint here and
3663 examine its value, when GetFileInformationByHandle
3665 DWORD w32err
= GetLastError ();
3669 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
3675 /* Test for a symlink before testing for a directory, since
3676 symlinks to directories have the directory bit set, but we
3677 don't want them to appear as directories. */
3678 if (is_a_symlink
&& !follow_symlinks
)
3679 buf
->st_mode
= S_IFLNK
;
3680 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3681 buf
->st_mode
= S_IFDIR
;
3684 DWORD ftype
= GetFileType (fh
);
3688 case FILE_TYPE_DISK
:
3689 buf
->st_mode
= S_IFREG
;
3691 case FILE_TYPE_PIPE
:
3692 buf
->st_mode
= S_IFIFO
;
3694 case FILE_TYPE_CHAR
:
3695 case FILE_TYPE_UNKNOWN
:
3697 buf
->st_mode
= S_IFCHR
;
3700 /* We produce the fallback owner and group data, based on the
3701 current user that runs Emacs, in the following cases:
3703 . this is Windows 9X
3704 . getting security by handle failed, and we need to produce
3705 information for the target of a symlink (this is better
3706 than producing a potentially misleading info about the
3709 If getting security by handle fails, and we don't need to
3710 resolve symlinks, we try getting security by name. */
3711 if (is_windows_9x () != TRUE
)
3712 psd
= get_file_security_desc_by_handle (fh
);
3715 get_file_owner_and_group (psd
, name
, buf
);
3718 else if (is_windows_9x () == TRUE
)
3719 get_file_owner_and_group (NULL
, name
, buf
);
3720 else if (!(is_a_symlink
&& follow_symlinks
))
3722 psd
= get_file_security_desc_by_name (name
);
3723 get_file_owner_and_group (psd
, name
, buf
);
3727 get_file_owner_and_group (NULL
, name
, buf
);
3732 no_true_file_attributes
:
3733 /* Plan B: Either getting a handle on the file failed, or the
3734 caller explicitly asked us to not bother making this
3735 information more accurate.
3737 Implementation note: In Plan B, we never bother to resolve
3738 symlinks, even if we got here because we tried Plan A and
3739 failed. That's because, even if the caller asked for extra
3740 precision by setting Vw32_get_true_file_attributes to t,
3741 resolving symlinks requires acquiring a file handle to the
3742 symlink, which we already know will fail. And if the user
3743 did not ask for extra precision, resolving symlinks will fly
3744 in the face of that request, since the user then wants the
3745 lightweight version of the code. */
3746 rootdir
= (path
>= save_name
+ len
- 1
3747 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3749 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3750 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3751 if (IS_DIRECTORY_SEP (r
[0])
3752 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3755 /* Note: If NAME is a symlink to the root of a UNC volume
3756 (i.e. "\\SERVER"), we will not detect that here, and we will
3757 return data about the symlink as result of FindFirst below.
3758 This is unfortunate, but that marginal use case does not
3759 justify a call to chase_symlinks which would impose a penalty
3760 on all the other use cases. (We get here for symlinks to
3761 roots of UNC volumes because CreateFile above fails for them,
3762 unlike with symlinks to root directories X:\ of drives.) */
3763 if (is_unc_volume (name
))
3765 fattrs
= unc_volume_file_attributes (name
);
3769 ctime
= atime
= wtime
= utc_base_ft
;
3773 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3774 strcat (name
, "\\");
3775 if (GetDriveType (name
) < 2)
3781 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
3782 ctime
= atime
= wtime
= utc_base_ft
;
3786 if (IS_DIRECTORY_SEP (name
[len
-1]))
3789 /* (This is hacky, but helps when doing file completions on
3790 network drives.) Optimize by using information available from
3791 active readdir if possible. */
3792 len
= strlen (dir_pathname
);
3793 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3795 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3796 && !(is_a_symlink
&& follow_symlinks
)
3797 && strnicmp (save_name
, dir_pathname
, len
) == 0
3798 && IS_DIRECTORY_SEP (name
[len
])
3799 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3801 /* This was the last entry returned by readdir. */
3802 wfd
= dir_find_data
;
3806 logon_network_drive (name
);
3808 fh
= FindFirstFile (name
, &wfd
);
3809 if (fh
== INVALID_HANDLE_VALUE
)
3816 /* Note: if NAME is a symlink, the information we get from
3817 FindFirstFile is for the symlink, not its target. */
3818 fattrs
= wfd
.dwFileAttributes
;
3819 ctime
= wfd
.ftCreationTime
;
3820 atime
= wfd
.ftLastAccessTime
;
3821 wtime
= wfd
.ftLastWriteTime
;
3822 fs_high
= wfd
.nFileSizeHigh
;
3823 fs_low
= wfd
.nFileSizeLow
;
3826 serialnum
= volume_info
.serialnum
;
3828 if (is_a_symlink
&& !follow_symlinks
)
3829 buf
->st_mode
= S_IFLNK
;
3830 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3831 buf
->st_mode
= S_IFDIR
;
3833 buf
->st_mode
= S_IFREG
;
3835 get_file_owner_and_group (NULL
, name
, buf
);
3839 /* Not sure if there is any point in this. */
3840 if (!NILP (Vw32_generate_fake_inodes
))
3841 fake_inode
= generate_inode_val (name
);
3842 else if (fake_inode
== 0)
3844 /* For want of something better, try to make everything unique. */
3845 static DWORD gen_num
= 0;
3846 fake_inode
= ++gen_num
;
3850 buf
->st_ino
= fake_inode
;
3852 buf
->st_dev
= serialnum
;
3853 buf
->st_rdev
= serialnum
;
3855 buf
->st_size
= fs_high
;
3856 buf
->st_size
<<= 32;
3857 buf
->st_size
+= fs_low
;
3858 buf
->st_nlink
= nlinks
;
3860 /* Convert timestamps to Unix format. */
3861 buf
->st_mtime
= convert_time (wtime
);
3862 buf
->st_atime
= convert_time (atime
);
3863 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3864 buf
->st_ctime
= convert_time (ctime
);
3865 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3867 /* determine rwx permissions */
3868 if (is_a_symlink
&& !follow_symlinks
)
3869 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
3872 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
3873 permission
= S_IREAD
;
3875 permission
= S_IREAD
| S_IWRITE
;
3877 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3878 permission
|= S_IEXEC
;
3879 else if (is_exec (name
))
3880 permission
|= S_IEXEC
;
3883 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3889 stat (const char * path
, struct stat
* buf
)
3891 return stat_worker (path
, buf
, 1);
3895 lstat (const char * path
, struct stat
* buf
)
3897 return stat_worker (path
, buf
, 0);
3900 /* Provide fstat and utime as well as stat for consistent handling of
3903 fstat (int desc
, struct stat
* buf
)
3905 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3906 BY_HANDLE_FILE_INFORMATION info
;
3907 unsigned __int64 fake_inode
;
3910 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3912 case FILE_TYPE_DISK
:
3913 buf
->st_mode
= S_IFREG
;
3914 if (!GetFileInformationByHandle (fh
, &info
))
3920 case FILE_TYPE_PIPE
:
3921 buf
->st_mode
= S_IFIFO
;
3923 case FILE_TYPE_CHAR
:
3924 case FILE_TYPE_UNKNOWN
:
3926 buf
->st_mode
= S_IFCHR
;
3928 memset (&info
, 0, sizeof (info
));
3929 info
.dwFileAttributes
= 0;
3930 info
.ftCreationTime
= utc_base_ft
;
3931 info
.ftLastAccessTime
= utc_base_ft
;
3932 info
.ftLastWriteTime
= utc_base_ft
;
3935 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3936 buf
->st_mode
= S_IFDIR
;
3938 buf
->st_nlink
= info
.nNumberOfLinks
;
3939 /* Might as well use file index to fake inode values, but this
3940 is not guaranteed to be unique unless we keep a handle open
3941 all the time (even then there are situations where it is
3942 not unique). Reputedly, there are at most 48 bits of info
3943 (on NTFS, presumably less on FAT). */
3944 fake_inode
= info
.nFileIndexHigh
;
3946 fake_inode
+= info
.nFileIndexLow
;
3948 /* MSVC defines _ino_t to be short; other libc's might not. */
3949 if (sizeof (buf
->st_ino
) == 2)
3950 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3952 buf
->st_ino
= fake_inode
;
3954 /* Consider files to belong to current user.
3955 FIXME: this should use GetSecurityInfo API, but it is only
3956 available for _WIN32_WINNT >= 0x501. */
3957 buf
->st_uid
= dflt_passwd
.pw_uid
;
3958 buf
->st_gid
= dflt_passwd
.pw_gid
;
3959 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3960 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3962 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3963 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3965 buf
->st_size
= info
.nFileSizeHigh
;
3966 buf
->st_size
<<= 32;
3967 buf
->st_size
+= info
.nFileSizeLow
;
3969 /* Convert timestamps to Unix format. */
3970 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3971 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3972 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3973 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3974 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3976 /* determine rwx permissions */
3977 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3978 permission
= S_IREAD
;
3980 permission
= S_IREAD
| S_IWRITE
;
3982 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3983 permission
|= S_IEXEC
;
3986 #if 0 /* no way of knowing the filename */
3987 char * p
= strrchr (name
, '.');
3989 (xstrcasecmp (p
, ".exe") == 0 ||
3990 xstrcasecmp (p
, ".com") == 0 ||
3991 xstrcasecmp (p
, ".bat") == 0 ||
3992 xstrcasecmp (p
, ".cmd") == 0))
3993 permission
|= S_IEXEC
;
3997 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4003 utime (const char *name
, struct utimbuf
*times
)
4005 struct utimbuf deftime
;
4012 deftime
.modtime
= deftime
.actime
= time (NULL
);
4016 /* Need write access to set times. */
4017 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
4018 0, OPEN_EXISTING
, 0, NULL
);
4021 convert_from_time_t (times
->actime
, &atime
);
4022 convert_from_time_t (times
->modtime
, &mtime
);
4023 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
4040 /* Symlink-related functions. */
4041 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4042 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4046 symlink (char const *filename
, char const *linkname
)
4048 char linkfn
[MAX_PATH
], *tgtfn
;
4050 int dir_access
, filename_ends_in_slash
;
4052 /* Diagnostics follows Posix as much as possible. */
4053 if (filename
== NULL
|| linkname
== NULL
)
4063 if (strlen (filename
) > MAX_PATH
|| strlen (linkname
) > MAX_PATH
)
4065 errno
= ENAMETOOLONG
;
4069 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
4070 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
4076 /* Note: since empty FILENAME was already rejected, we can safely
4077 refer to FILENAME[1]. */
4078 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
4080 /* Non-absolute FILENAME is understood as being relative to
4081 LINKNAME's directory. We need to prepend that directory to
4082 FILENAME to get correct results from sys_access below, since
4083 otherwise it will interpret FILENAME relative to the
4084 directory where the Emacs process runs. Note that
4085 make-symbolic-link always makes sure LINKNAME is a fully
4086 expanded file name. */
4088 char *p
= linkfn
+ strlen (linkfn
);
4090 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
4093 strncpy (tem
, linkfn
, p
- linkfn
);
4094 tem
[p
- linkfn
] = '\0';
4095 strcat (tem
, filename
);
4096 dir_access
= sys_access (tem
, D_OK
);
4099 dir_access
= sys_access (filename
, D_OK
);
4101 /* Since Windows distinguishes between symlinks to directories and
4102 to files, we provide a kludgey feature: if FILENAME doesn't
4103 exist, but ends in a slash, we create a symlink to directory. If
4104 FILENAME exists and is a directory, we always create a symlink to
4106 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
4107 if (dir_access
== 0 || filename_ends_in_slash
)
4108 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
4110 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
4111 if (filename_ends_in_slash
)
4112 tgtfn
[strlen (tgtfn
) - 1] = '\0';
4115 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
4117 /* ENOSYS is set by create_symbolic_link, when it detects that
4118 the OS doesn't support the CreateSymbolicLink API. */
4119 if (errno
!= ENOSYS
)
4121 DWORD w32err
= GetLastError ();
4125 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4126 TGTFN point to the same file name, go figure. */
4128 case ERROR_FILE_EXISTS
:
4131 case ERROR_ACCESS_DENIED
:
4134 case ERROR_FILE_NOT_FOUND
:
4135 case ERROR_PATH_NOT_FOUND
:
4136 case ERROR_BAD_NETPATH
:
4137 case ERROR_INVALID_REPARSE_DATA
:
4140 case ERROR_DIRECTORY
:
4143 case ERROR_PRIVILEGE_NOT_HELD
:
4144 case ERROR_NOT_ALL_ASSIGNED
:
4147 case ERROR_DISK_FULL
:
4160 /* A quick inexpensive test of whether FILENAME identifies a file that
4161 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4162 must already be in the normalized form returned by
4165 Note: for repeated operations on many files, it is best to test
4166 whether the underlying volume actually supports symlinks, by
4167 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4168 avoid the call to this function if it doesn't. That's because the
4169 call to GetFileAttributes takes a non-negligible time, expecially
4170 on non-local or removable filesystems. See stat_worker for an
4171 example of how to do that. */
4173 is_symlink (const char *filename
)
4176 WIN32_FIND_DATA wfd
;
4179 attrs
= GetFileAttributes (filename
);
4182 DWORD w32err
= GetLastError ();
4186 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
4188 case ERROR_ACCESS_DENIED
:
4191 case ERROR_FILE_NOT_FOUND
:
4192 case ERROR_PATH_NOT_FOUND
:
4199 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
4201 logon_network_drive (filename
);
4202 fh
= FindFirstFile (filename
, &wfd
);
4203 if (fh
== INVALID_HANDLE_VALUE
)
4206 return (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
4207 && (wfd
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
4210 /* If NAME identifies a symbolic link, copy into BUF the file name of
4211 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4212 null-terminate the target name, even if it fits. Return the number
4213 of bytes copied, or -1 if NAME is not a symlink or any error was
4214 encountered while resolving it. The file name copied into BUF is
4215 encoded in the current ANSI codepage. */
4217 readlink (const char *name
, char *buf
, size_t buf_size
)
4220 TOKEN_PRIVILEGES privs
;
4221 int restore_privs
= 0;
4236 path
= map_w32_filename (name
, NULL
);
4238 if (strlen (path
) > MAX_PATH
)
4240 errno
= ENAMETOOLONG
;
4245 if (is_windows_9x () == TRUE
4246 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
4247 || !is_symlink (path
))
4250 errno
= EINVAL
; /* not a symlink */
4254 /* Done with simple tests, now we're in for some _real_ work. */
4255 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
4257 /* Implementation note: From here and onward, don't return early,
4258 since that will fail to restore the original set of privileges of
4259 the calling thread. */
4261 retval
= -1; /* not too optimistic, are we? */
4263 /* Note: In the next call to CreateFile, we use zero as the 2nd
4264 argument because, when the symlink is a hidden/system file,
4265 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4266 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4267 and directory symlinks. */
4268 sh
= CreateFile (path
, 0, 0, NULL
, OPEN_EXISTING
,
4269 FILE_FLAG_OPEN_REPARSE_POINT
| FILE_FLAG_BACKUP_SEMANTICS
,
4271 if (sh
!= INVALID_HANDLE_VALUE
)
4273 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
4274 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
4277 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
4278 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
4281 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
4285 /* Copy the link target name, in wide characters, fro
4286 reparse_data, then convert it to multibyte encoding in
4287 the current locale's codepage. */
4289 BYTE lname
[MAX_PATH
];
4292 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
4294 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
4295 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
4297 /* According to MSDN, PrintNameLength does not include the
4298 terminating null character. */
4299 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
4300 memcpy (lwname
, lwname_src
, lwname_len
);
4301 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
4303 /* FIXME: Should we use the current file-name coding system
4304 instead of the fixed value of the ANSI codepage? */
4305 lname_len
= WideCharToMultiByte (w32_ansi_code_page
, 0, lwname
, -1,
4306 lname
, MAX_PATH
, NULL
, NULL
);
4309 /* WideCharToMultiByte failed. */
4310 DWORD w32err1
= GetLastError ();
4314 case ERROR_INSUFFICIENT_BUFFER
:
4315 errno
= ENAMETOOLONG
;
4317 case ERROR_INVALID_PARAMETER
:
4320 case ERROR_NO_UNICODE_TRANSLATION
:
4330 size_t size_to_copy
= buf_size
;
4332 BYTE
*pend
= p
+ lname_len
;
4334 /* Normalize like dostounix_filename does, but we don't
4335 want to assume that lname is null-terminated. */
4336 if (*p
&& p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4344 /* Testing for null-terminated LNAME is paranoia:
4345 WideCharToMultiByte should always return a
4346 null-terminated string when its 4th argument is -1
4347 and its 3rd argument is null-terminated (which they
4349 if (lname
[lname_len
- 1] == '\0')
4351 if (lname_len
<= buf_size
)
4352 size_to_copy
= lname_len
;
4353 strncpy (buf
, lname
, size_to_copy
);
4355 retval
= size_to_copy
;
4362 /* CreateFile failed. */
4363 DWORD w32err2
= GetLastError ();
4367 case ERROR_FILE_NOT_FOUND
:
4368 case ERROR_PATH_NOT_FOUND
:
4371 case ERROR_ACCESS_DENIED
:
4372 case ERROR_TOO_MANY_OPEN_FILES
:
4382 restore_privilege (&privs
);
4389 /* If FILE is a symlink, return its target (stored in a static
4390 buffer); otherwise return FILE.
4392 This function repeatedly resolves symlinks in the last component of
4393 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4394 until it arrives at a file whose last component is not a symlink,
4395 or some error occurs. It returns the target of the last
4396 successfully resolved symlink in the chain. If it succeeds to
4397 resolve even a single symlink, the value returned is an absolute
4398 file name with backslashes (result of GetFullPathName). By
4399 contrast, if the original FILE is returned, it is unaltered.
4401 Note: This function can set errno even if it succeeds.
4403 Implementation note: we only resolve the last portion ("basename")
4404 of the argument FILE and of each following file in the chain,
4405 disregarding any possible symlinks in its leading directories.
4406 This is because Windows system calls and library functions
4407 transparently resolve symlinks in leading directories and return
4408 correct information, as long as the basename is not a symlink. */
4410 chase_symlinks (const char *file
)
4412 static char target
[MAX_PATH
];
4413 char link
[MAX_PATH
];
4414 ssize_t res
, link_len
;
4417 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
4418 return (char *)file
;
4420 if ((link_len
= GetFullPathName (file
, MAX_PATH
, link
, NULL
)) == 0)
4421 return (char *)file
;
4426 /* Remove trailing slashes, as we want to resolve the last
4427 non-trivial part of the link name. */
4428 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
4429 link
[link_len
--] = '\0';
4431 res
= readlink (link
, target
, MAX_PATH
);
4435 if (!(IS_DEVICE_SEP (target
[1])
4436 || IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1])))
4438 /* Target is relative. Append it to the directory part of
4439 the symlink, then copy the result back to target. */
4440 char *p
= link
+ link_len
;
4442 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
4445 strcpy (target
, link
);
4447 /* Resolve any "." and ".." to get a fully-qualified file name
4449 link_len
= GetFullPathName (target
, MAX_PATH
, link
, NULL
);
4451 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
4453 if (loop_count
> 100)
4456 if (target
[0] == '\0') /* not a single call to readlink succeeded */
4457 return (char *)file
;
4461 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
4462 have a fixed max size for file names, so we don't need the kind of
4463 alloc/malloc/realloc dance the gnulib version does. We also don't
4464 support FD-relative symlinks. */
4466 careadlinkat (int fd
, char const *filename
,
4467 char *buffer
, size_t buffer_size
,
4468 struct allocator
const *alloc
,
4469 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
4471 char linkname
[MAX_PATH
];
4480 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
4484 char *retval
= buffer
;
4486 linkname
[link_size
++] = '\0';
4487 if (link_size
> buffer_size
)
4488 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
4490 memcpy (retval
, linkname
, link_size
);
4498 careadlinkatcwd (int fd
, char const *filename
, char *buffer
,
4502 return readlink (filename
, buffer
, buffer_size
);
4506 /* Support for browsing other processes and their attributes. See
4507 process.c for the Lisp bindings. */
4509 /* Helper wrapper functions. */
4511 static HANDLE WINAPI
4512 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
4514 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
4516 if (g_b_init_create_toolhelp32_snapshot
== 0)
4518 g_b_init_create_toolhelp32_snapshot
= 1;
4519 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
4520 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4521 "CreateToolhelp32Snapshot");
4523 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
4525 return INVALID_HANDLE_VALUE
;
4527 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
4531 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
4533 static Process32First_Proc s_pfn_Process32_First
= NULL
;
4535 if (g_b_init_process32_first
== 0)
4537 g_b_init_process32_first
= 1;
4538 s_pfn_Process32_First
= (Process32First_Proc
)
4539 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4542 if (s_pfn_Process32_First
== NULL
)
4546 return (s_pfn_Process32_First (hSnapshot
, lppe
));
4550 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
4552 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
4554 if (g_b_init_process32_next
== 0)
4556 g_b_init_process32_next
= 1;
4557 s_pfn_Process32_Next
= (Process32Next_Proc
)
4558 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4561 if (s_pfn_Process32_Next
== NULL
)
4565 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
4569 open_thread_token (HANDLE ThreadHandle
,
4570 DWORD DesiredAccess
,
4572 PHANDLE TokenHandle
)
4574 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
4575 HMODULE hm_advapi32
= NULL
;
4576 if (is_windows_9x () == TRUE
)
4578 SetLastError (ERROR_NOT_SUPPORTED
);
4581 if (g_b_init_open_thread_token
== 0)
4583 g_b_init_open_thread_token
= 1;
4584 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4585 s_pfn_Open_Thread_Token
=
4586 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
4588 if (s_pfn_Open_Thread_Token
== NULL
)
4590 SetLastError (ERROR_NOT_SUPPORTED
);
4594 s_pfn_Open_Thread_Token (
4603 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
4605 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
4606 HMODULE hm_advapi32
= NULL
;
4607 if (is_windows_9x () == TRUE
)
4611 if (g_b_init_impersonate_self
== 0)
4613 g_b_init_impersonate_self
= 1;
4614 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4615 s_pfn_Impersonate_Self
=
4616 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
4618 if (s_pfn_Impersonate_Self
== NULL
)
4622 return s_pfn_Impersonate_Self (ImpersonationLevel
);
4626 revert_to_self (void)
4628 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
4629 HMODULE hm_advapi32
= NULL
;
4630 if (is_windows_9x () == TRUE
)
4634 if (g_b_init_revert_to_self
== 0)
4636 g_b_init_revert_to_self
= 1;
4637 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4638 s_pfn_Revert_To_Self
=
4639 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
4641 if (s_pfn_Revert_To_Self
== NULL
)
4645 return s_pfn_Revert_To_Self ();
4649 get_process_memory_info (HANDLE h_proc
,
4650 PPROCESS_MEMORY_COUNTERS mem_counters
,
4653 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
4654 HMODULE hm_psapi
= NULL
;
4655 if (is_windows_9x () == TRUE
)
4659 if (g_b_init_get_process_memory_info
== 0)
4661 g_b_init_get_process_memory_info
= 1;
4662 hm_psapi
= LoadLibrary ("Psapi.dll");
4664 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
4665 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
4667 if (s_pfn_Get_Process_Memory_Info
== NULL
)
4671 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
4675 get_process_working_set_size (HANDLE h_proc
,
4679 static GetProcessWorkingSetSize_Proc
4680 s_pfn_Get_Process_Working_Set_Size
= NULL
;
4682 if (is_windows_9x () == TRUE
)
4686 if (g_b_init_get_process_working_set_size
== 0)
4688 g_b_init_get_process_working_set_size
= 1;
4689 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
4690 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4691 "GetProcessWorkingSetSize");
4693 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
4697 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
4701 global_memory_status (MEMORYSTATUS
*buf
)
4703 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
4705 if (is_windows_9x () == TRUE
)
4709 if (g_b_init_global_memory_status
== 0)
4711 g_b_init_global_memory_status
= 1;
4712 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
4713 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4714 "GlobalMemoryStatus");
4716 if (s_pfn_Global_Memory_Status
== NULL
)
4720 return s_pfn_Global_Memory_Status (buf
);
4724 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
4726 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
4728 if (is_windows_9x () == TRUE
)
4732 if (g_b_init_global_memory_status_ex
== 0)
4734 g_b_init_global_memory_status_ex
= 1;
4735 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
4736 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4737 "GlobalMemoryStatusEx");
4739 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
4743 return s_pfn_Global_Memory_Status_Ex (buf
);
4747 list_system_processes (void)
4749 struct gcpro gcpro1
;
4750 Lisp_Object proclist
= Qnil
;
4753 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4755 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4757 PROCESSENTRY32 proc_entry
;
4763 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
4764 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
4765 res
= process32_next (h_snapshot
, &proc_entry
))
4767 proc_id
= proc_entry
.th32ProcessID
;
4768 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
4771 CloseHandle (h_snapshot
);
4773 proclist
= Fnreverse (proclist
);
4780 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
4782 TOKEN_PRIVILEGES priv
;
4783 DWORD priv_size
= sizeof (priv
);
4784 DWORD opriv_size
= sizeof (*old_priv
);
4785 HANDLE h_token
= NULL
;
4786 HANDLE h_thread
= GetCurrentThread ();
4790 res
= open_thread_token (h_thread
,
4791 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4793 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
4795 if (impersonate_self (SecurityImpersonation
))
4796 res
= open_thread_token (h_thread
,
4797 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4802 priv
.PrivilegeCount
= 1;
4803 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
4804 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
4805 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
4806 old_priv
, &opriv_size
)
4807 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4811 CloseHandle (h_token
);
4817 restore_privilege (TOKEN_PRIVILEGES
*priv
)
4819 DWORD priv_size
= sizeof (*priv
);
4820 HANDLE h_token
= NULL
;
4823 if (open_thread_token (GetCurrentThread (),
4824 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4827 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
4828 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4832 CloseHandle (h_token
);
4838 ltime (ULONGLONG time_100ns
)
4840 ULONGLONG time_sec
= time_100ns
/ 10000000;
4841 int subsec
= time_100ns
% 10000000;
4842 return list4 (make_number (time_sec
>> 16),
4843 make_number (time_sec
& 0xffff),
4844 make_number (subsec
/ 10),
4845 make_number (subsec
% 10 * 100000));
4848 #define U64_TO_LISP_TIME(time) ltime (time)
4851 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4852 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4855 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4856 ULONGLONG tem1
, tem2
, tem3
, tem
;
4859 || !get_process_times_fn
4860 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4861 &ft_kernel
, &ft_user
))
4864 GetSystemTimeAsFileTime (&ft_current
);
4866 FILETIME_TO_U64 (tem1
, ft_kernel
);
4867 *stime
= U64_TO_LISP_TIME (tem1
);
4869 FILETIME_TO_U64 (tem2
, ft_user
);
4870 *utime
= U64_TO_LISP_TIME (tem2
);
4873 *ttime
= U64_TO_LISP_TIME (tem3
);
4875 FILETIME_TO_U64 (tem
, ft_creation
);
4876 /* Process no 4 (System) returns zero creation time. */
4879 *ctime
= U64_TO_LISP_TIME (tem
);
4883 FILETIME_TO_U64 (tem3
, ft_current
);
4884 tem
= (tem3
- utc_base
) - tem
;
4886 *etime
= U64_TO_LISP_TIME (tem
);
4890 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4901 system_process_attributes (Lisp_Object pid
)
4903 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4904 Lisp_Object attrs
= Qnil
;
4905 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4906 HANDLE h_snapshot
, h_proc
;
4909 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4910 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4911 DWORD glength
= sizeof (gname
);
4912 HANDLE token
= NULL
;
4913 SID_NAME_USE user_type
;
4914 unsigned char *buf
= NULL
;
4916 TOKEN_USER user_token
;
4917 TOKEN_PRIMARY_GROUP group_token
;
4920 PROCESS_MEMORY_COUNTERS mem
;
4921 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4922 DWORD minrss
, maxrss
;
4924 MEMORY_STATUS_EX memstex
;
4925 double totphys
= 0.0;
4926 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4928 BOOL result
= FALSE
;
4930 CHECK_NUMBER_OR_FLOAT (pid
);
4931 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4933 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4935 GCPRO3 (attrs
, decoded_cmd
, tem
);
4937 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4942 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4943 for (res
= process32_first (h_snapshot
, &pe
); res
;
4944 res
= process32_next (h_snapshot
, &pe
))
4946 if (proc_id
== pe
.th32ProcessID
)
4949 decoded_cmd
= build_string ("Idle");
4952 /* Decode the command name from locale-specific
4954 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4955 strlen (pe
.szExeFile
));
4957 code_convert_string_norecord (cmd_str
,
4958 Vlocale_coding_system
, 0);
4960 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4961 attrs
= Fcons (Fcons (Qppid
,
4962 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4964 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4966 attrs
= Fcons (Fcons (Qthcount
,
4967 make_fixnum_or_float (pe
.cntThreads
)),
4974 CloseHandle (h_snapshot
);
4983 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4985 /* If we were denied a handle to the process, try again after
4986 enabling the SeDebugPrivilege in our process. */
4989 TOKEN_PRIVILEGES priv_current
;
4991 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4993 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4995 restore_privilege (&priv_current
);
5001 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
5004 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
5005 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5007 buf
= xmalloc (blen
);
5008 result
= get_token_information (token
, TokenUser
,
5009 (LPVOID
)buf
, blen
, &needed
);
5012 memcpy (&user_token
, buf
, sizeof (user_token
));
5013 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
5015 euid
= get_rid (user_token
.User
.Sid
);
5016 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
5021 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
5024 strcpy (uname
, "unknown");
5028 ulength
= strlen (uname
);
5034 /* Determine a reasonable euid and gid values. */
5035 if (xstrcasecmp ("administrator", uname
) == 0)
5037 euid
= 500; /* well-known Administrator uid */
5038 egid
= 513; /* well-known None gid */
5042 /* Get group id and name. */
5043 result
= get_token_information (token
, TokenPrimaryGroup
,
5044 (LPVOID
)buf
, blen
, &needed
);
5045 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5047 buf
= xrealloc (buf
, blen
= needed
);
5048 result
= get_token_information (token
, TokenPrimaryGroup
,
5049 (LPVOID
)buf
, blen
, &needed
);
5053 memcpy (&group_token
, buf
, sizeof (group_token
));
5054 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
5056 egid
= get_rid (group_token
.PrimaryGroup
);
5057 dlength
= sizeof (domain
);
5059 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
5060 gname
, &glength
, NULL
, &dlength
,
5063 w32_add_to_cache (group_token
.PrimaryGroup
,
5067 strcpy (gname
, "None");
5071 glength
= strlen (gname
);
5079 if (!is_windows_9x ())
5081 /* We couldn't open the process token, presumably because of
5082 insufficient access rights. Assume this process is run
5084 strcpy (uname
, "SYSTEM");
5085 strcpy (gname
, "None");
5086 euid
= 18; /* SYSTEM */
5087 egid
= 513; /* None */
5088 glength
= strlen (gname
);
5089 ulength
= strlen (uname
);
5091 /* If we are running under Windows 9X, where security calls are
5092 not supported, we assume all processes are run by the current
5094 else if (GetUserName (uname
, &ulength
))
5096 if (xstrcasecmp ("administrator", uname
) == 0)
5101 strcpy (gname
, "None");
5102 glength
= strlen (gname
);
5103 ulength
= strlen (uname
);
5109 strcpy (uname
, "administrator");
5110 ulength
= strlen (uname
);
5111 strcpy (gname
, "None");
5112 glength
= strlen (gname
);
5115 CloseHandle (token
);
5118 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
5119 tem
= make_unibyte_string (uname
, ulength
);
5120 attrs
= Fcons (Fcons (Quser
,
5121 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5123 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
5124 tem
= make_unibyte_string (gname
, glength
);
5125 attrs
= Fcons (Fcons (Qgroup
,
5126 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5129 if (global_memory_status_ex (&memstex
))
5130 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5131 totphys
= memstex
.ullTotalPhys
/ 1024.0;
5133 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5134 double, so we need to do this for it... */
5136 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
5137 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
5138 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
5140 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
5142 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5143 else if (global_memory_status (&memst
))
5144 totphys
= memst
.dwTotalPhys
/ 1024.0;
5147 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
5150 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
5152 attrs
= Fcons (Fcons (Qmajflt
,
5153 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
5155 attrs
= Fcons (Fcons (Qvsize
,
5156 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
5158 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5160 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5163 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
5165 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
5167 attrs
= Fcons (Fcons (Qmajflt
,
5168 make_fixnum_or_float (mem
.PageFaultCount
)),
5170 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5172 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5175 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
5177 DWORD rss
= maxrss
/ 1024;
5179 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
5181 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5184 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
5186 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
5187 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
5188 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
5189 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
5190 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
5191 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
5194 /* FIXME: Retrieve command line by walking the PEB of the process. */
5197 CloseHandle (h_proc
);
5203 /* Wrappers for winsock functions to map between our file descriptors
5204 and winsock's handles; also set h_errno for convenience.
5206 To allow Emacs to run on systems which don't have winsock support
5207 installed, we dynamically link to winsock on startup if present, and
5208 otherwise provide the minimum necessary functionality
5209 (eg. gethostname). */
5211 /* function pointers for relevant socket functions */
5212 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
5213 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
5214 int (PASCAL
*pfn_WSAGetLastError
) (void);
5215 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
5216 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
5217 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
5218 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
5219 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
5220 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
5221 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
5222 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
5223 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
5224 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
5225 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
5226 int (PASCAL
*pfn_WSACleanup
) (void);
5228 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
5229 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
5230 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
5231 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
5232 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
5233 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
5234 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
5235 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
5236 const char * optval
, int optlen
);
5237 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
5238 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
5240 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
5241 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
5242 struct sockaddr
* from
, int * fromlen
);
5243 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
5244 const struct sockaddr
* to
, int tolen
);
5246 /* SetHandleInformation is only needed to make sockets non-inheritable. */
5247 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
5248 #ifndef HANDLE_FLAG_INHERIT
5249 #define HANDLE_FLAG_INHERIT 1
5253 static int winsock_inuse
;
5258 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
5260 /* Not sure what would cause WSAENETDOWN, or even if it can happen
5261 after WSAStartup returns successfully, but it seems reasonable
5262 to allow unloading winsock anyway in that case. */
5263 if (pfn_WSACleanup () == 0 ||
5264 pfn_WSAGetLastError () == WSAENETDOWN
)
5266 if (FreeLibrary (winsock_lib
))
5275 init_winsock (int load_now
)
5277 WSADATA winsockData
;
5279 if (winsock_lib
!= NULL
)
5282 pfn_SetHandleInformation
5283 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
5284 "SetHandleInformation");
5286 winsock_lib
= LoadLibrary ("Ws2_32.dll");
5288 if (winsock_lib
!= NULL
)
5290 /* dynamically link to socket functions */
5292 #define LOAD_PROC(fn) \
5293 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
5296 LOAD_PROC (WSAStartup
);
5297 LOAD_PROC (WSASetLastError
);
5298 LOAD_PROC (WSAGetLastError
);
5299 LOAD_PROC (WSAEventSelect
);
5300 LOAD_PROC (WSACreateEvent
);
5301 LOAD_PROC (WSACloseEvent
);
5304 LOAD_PROC (connect
);
5305 LOAD_PROC (ioctlsocket
);
5308 LOAD_PROC (closesocket
);
5309 LOAD_PROC (shutdown
);
5312 LOAD_PROC (inet_addr
);
5313 LOAD_PROC (gethostname
);
5314 LOAD_PROC (gethostbyname
);
5315 LOAD_PROC (getservbyname
);
5316 LOAD_PROC (getpeername
);
5317 LOAD_PROC (WSACleanup
);
5318 LOAD_PROC (setsockopt
);
5320 LOAD_PROC (getsockname
);
5322 LOAD_PROC (recvfrom
);
5326 /* specify version 1.1 of winsock */
5327 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
5329 if (winsockData
.wVersion
!= 0x101)
5334 /* Report that winsock exists and is usable, but leave
5335 socket functions disabled. I am assuming that calling
5336 WSAStartup does not require any network interaction,
5337 and in particular does not cause or require a dial-up
5338 connection to be established. */
5341 FreeLibrary (winsock_lib
);
5349 FreeLibrary (winsock_lib
);
5359 /* function to set h_errno for compatibility; map winsock error codes to
5360 normal system codes where they overlap (non-overlapping definitions
5361 are already in <sys/socket.h> */
5365 if (winsock_lib
== NULL
)
5368 h_errno
= pfn_WSAGetLastError ();
5372 case WSAEACCES
: h_errno
= EACCES
; break;
5373 case WSAEBADF
: h_errno
= EBADF
; break;
5374 case WSAEFAULT
: h_errno
= EFAULT
; break;
5375 case WSAEINTR
: h_errno
= EINTR
; break;
5376 case WSAEINVAL
: h_errno
= EINVAL
; break;
5377 case WSAEMFILE
: h_errno
= EMFILE
; break;
5378 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
5379 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
5387 if (h_errno
== 0 && winsock_lib
!= NULL
)
5388 pfn_WSASetLastError (0);
5391 /* Extend strerror to handle the winsock-specific error codes. */
5395 } _wsa_errlist
[] = {
5396 {WSAEINTR
, "Interrupted function call"},
5397 {WSAEBADF
, "Bad file descriptor"},
5398 {WSAEACCES
, "Permission denied"},
5399 {WSAEFAULT
, "Bad address"},
5400 {WSAEINVAL
, "Invalid argument"},
5401 {WSAEMFILE
, "Too many open files"},
5403 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
5404 {WSAEINPROGRESS
, "Operation now in progress"},
5405 {WSAEALREADY
, "Operation already in progress"},
5406 {WSAENOTSOCK
, "Socket operation on non-socket"},
5407 {WSAEDESTADDRREQ
, "Destination address required"},
5408 {WSAEMSGSIZE
, "Message too long"},
5409 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
5410 {WSAENOPROTOOPT
, "Bad protocol option"},
5411 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
5412 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
5413 {WSAEOPNOTSUPP
, "Operation not supported"},
5414 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
5415 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
5416 {WSAEADDRINUSE
, "Address already in use"},
5417 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
5418 {WSAENETDOWN
, "Network is down"},
5419 {WSAENETUNREACH
, "Network is unreachable"},
5420 {WSAENETRESET
, "Network dropped connection on reset"},
5421 {WSAECONNABORTED
, "Software caused connection abort"},
5422 {WSAECONNRESET
, "Connection reset by peer"},
5423 {WSAENOBUFS
, "No buffer space available"},
5424 {WSAEISCONN
, "Socket is already connected"},
5425 {WSAENOTCONN
, "Socket is not connected"},
5426 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
5427 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
5428 {WSAETIMEDOUT
, "Connection timed out"},
5429 {WSAECONNREFUSED
, "Connection refused"},
5430 {WSAELOOP
, "Network loop"}, /* not sure */
5431 {WSAENAMETOOLONG
, "Name is too long"},
5432 {WSAEHOSTDOWN
, "Host is down"},
5433 {WSAEHOSTUNREACH
, "No route to host"},
5434 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
5435 {WSAEPROCLIM
, "Too many processes"},
5436 {WSAEUSERS
, "Too many users"}, /* not sure */
5437 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
5438 {WSAESTALE
, "Data is stale"}, /* not sure */
5439 {WSAEREMOTE
, "Remote error"}, /* not sure */
5441 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
5442 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
5443 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
5444 {WSAEDISCON
, "Graceful shutdown in progress"},
5446 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
5447 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
5448 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
5449 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
5450 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
5451 {WSASYSCALLFAILURE
, "System call failure"},
5452 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
5453 {WSATYPE_NOT_FOUND
, "Class type not found"},
5454 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
5455 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
5456 {WSAEREFUSED
, "Operation refused"}, /* not sure */
5459 {WSAHOST_NOT_FOUND
, "Host not found"},
5460 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
5461 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
5462 {WSANO_DATA
, "Valid name, no data record of requested type"},
5468 sys_strerror (int error_no
)
5471 static char unknown_msg
[40];
5473 if (error_no
>= 0 && error_no
< sys_nerr
)
5474 return sys_errlist
[error_no
];
5476 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
5477 if (_wsa_errlist
[i
].errnum
== error_no
)
5478 return _wsa_errlist
[i
].msg
;
5480 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
5484 /* [andrewi 3-May-96] I've had conflicting results using both methods,
5485 but I believe the method of keeping the socket handle separate (and
5486 insuring it is not inheritable) is the correct one. */
5488 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
5490 static int socket_to_fd (SOCKET s
);
5493 sys_socket (int af
, int type
, int protocol
)
5497 if (winsock_lib
== NULL
)
5500 return INVALID_SOCKET
;
5505 /* call the real socket function */
5506 s
= pfn_socket (af
, type
, protocol
);
5508 if (s
!= INVALID_SOCKET
)
5509 return socket_to_fd (s
);
5515 /* Convert a SOCKET to a file descriptor. */
5517 socket_to_fd (SOCKET s
)
5522 /* Although under NT 3.5 _open_osfhandle will accept a socket
5523 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
5524 that does not work under NT 3.1. However, we can get the same
5525 effect by using a backdoor function to replace an existing
5526 descriptor handle with the one we want. */
5528 /* allocate a file descriptor (with appropriate flags) */
5529 fd
= _open ("NUL:", _O_RDWR
);
5532 /* Make a non-inheritable copy of the socket handle. Note
5533 that it is possible that sockets aren't actually kernel
5534 handles, which appears to be the case on Windows 9x when
5535 the MS Proxy winsock client is installed. */
5537 /* Apparently there is a bug in NT 3.51 with some service
5538 packs, which prevents using DuplicateHandle to make a
5539 socket handle non-inheritable (causes WSACleanup to
5540 hang). The work-around is to use SetHandleInformation
5541 instead if it is available and implemented. */
5542 if (pfn_SetHandleInformation
)
5544 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
5548 HANDLE parent
= GetCurrentProcess ();
5549 HANDLE new_s
= INVALID_HANDLE_VALUE
;
5551 if (DuplicateHandle (parent
,
5557 DUPLICATE_SAME_ACCESS
))
5559 /* It is possible that DuplicateHandle succeeds even
5560 though the socket wasn't really a kernel handle,
5561 because a real handle has the same value. So
5562 test whether the new handle really is a socket. */
5563 long nonblocking
= 0;
5564 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
5566 pfn_closesocket (s
);
5571 CloseHandle (new_s
);
5576 fd_info
[fd
].hnd
= (HANDLE
) s
;
5578 /* set our own internal flags */
5579 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
5585 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5587 /* attach child_process to fd_info */
5588 if (fd_info
[ fd
].cp
!= NULL
)
5590 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
5594 fd_info
[ fd
].cp
= cp
;
5597 winsock_inuse
++; /* count open sockets */
5604 pfn_closesocket (s
);
5610 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
5612 if (winsock_lib
== NULL
)
5615 return SOCKET_ERROR
;
5619 if (fd_info
[s
].flags
& FILE_SOCKET
)
5621 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
5622 if (rc
== SOCKET_ERROR
)
5627 return SOCKET_ERROR
;
5631 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
5633 if (winsock_lib
== NULL
)
5636 return SOCKET_ERROR
;
5640 if (fd_info
[s
].flags
& FILE_SOCKET
)
5642 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
5643 if (rc
== SOCKET_ERROR
)
5648 return SOCKET_ERROR
;
5652 sys_htons (u_short hostshort
)
5654 return (winsock_lib
!= NULL
) ?
5655 pfn_htons (hostshort
) : hostshort
;
5659 sys_ntohs (u_short netshort
)
5661 return (winsock_lib
!= NULL
) ?
5662 pfn_ntohs (netshort
) : netshort
;
5666 sys_inet_addr (const char * cp
)
5668 return (winsock_lib
!= NULL
) ?
5669 pfn_inet_addr (cp
) : INADDR_NONE
;
5673 sys_gethostname (char * name
, int namelen
)
5675 if (winsock_lib
!= NULL
)
5676 return pfn_gethostname (name
, namelen
);
5678 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
5679 return !GetComputerName (name
, (DWORD
*)&namelen
);
5682 return SOCKET_ERROR
;
5686 sys_gethostbyname (const char * name
)
5688 struct hostent
* host
;
5690 if (winsock_lib
== NULL
)
5697 host
= pfn_gethostbyname (name
);
5704 sys_getservbyname (const char * name
, const char * proto
)
5706 struct servent
* serv
;
5708 if (winsock_lib
== NULL
)
5715 serv
= pfn_getservbyname (name
, proto
);
5722 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
5724 if (winsock_lib
== NULL
)
5727 return SOCKET_ERROR
;
5731 if (fd_info
[s
].flags
& FILE_SOCKET
)
5733 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
5734 if (rc
== SOCKET_ERROR
)
5739 return SOCKET_ERROR
;
5743 sys_shutdown (int s
, int how
)
5745 if (winsock_lib
== NULL
)
5748 return SOCKET_ERROR
;
5752 if (fd_info
[s
].flags
& FILE_SOCKET
)
5754 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
5755 if (rc
== SOCKET_ERROR
)
5760 return SOCKET_ERROR
;
5764 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
5766 if (winsock_lib
== NULL
)
5769 return SOCKET_ERROR
;
5773 if (fd_info
[s
].flags
& FILE_SOCKET
)
5775 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
5776 (const char *)optval
, optlen
);
5777 if (rc
== SOCKET_ERROR
)
5782 return SOCKET_ERROR
;
5786 sys_listen (int s
, int backlog
)
5788 if (winsock_lib
== NULL
)
5791 return SOCKET_ERROR
;
5795 if (fd_info
[s
].flags
& FILE_SOCKET
)
5797 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
5798 if (rc
== SOCKET_ERROR
)
5801 fd_info
[s
].flags
|= FILE_LISTEN
;
5805 return SOCKET_ERROR
;
5809 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
5811 if (winsock_lib
== NULL
)
5814 return SOCKET_ERROR
;
5818 if (fd_info
[s
].flags
& FILE_SOCKET
)
5820 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
5821 if (rc
== SOCKET_ERROR
)
5826 return SOCKET_ERROR
;
5830 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
5832 if (winsock_lib
== NULL
)
5839 if (fd_info
[s
].flags
& FILE_LISTEN
)
5841 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5843 if (t
== INVALID_SOCKET
)
5846 fd
= socket_to_fd (t
);
5848 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5849 ResetEvent (fd_info
[s
].cp
->char_avail
);
5857 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5858 struct sockaddr
* from
, int * fromlen
)
5860 if (winsock_lib
== NULL
)
5863 return SOCKET_ERROR
;
5867 if (fd_info
[s
].flags
& FILE_SOCKET
)
5869 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5870 if (rc
== SOCKET_ERROR
)
5875 return SOCKET_ERROR
;
5879 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5880 const struct sockaddr
* to
, int tolen
)
5882 if (winsock_lib
== NULL
)
5885 return SOCKET_ERROR
;
5889 if (fd_info
[s
].flags
& FILE_SOCKET
)
5891 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5892 if (rc
== SOCKET_ERROR
)
5897 return SOCKET_ERROR
;
5900 /* Windows does not have an fcntl function. Provide an implementation
5901 solely for making sockets non-blocking. */
5903 fcntl (int s
, int cmd
, int options
)
5905 if (winsock_lib
== NULL
)
5912 if (fd_info
[s
].flags
& FILE_SOCKET
)
5914 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5916 unsigned long nblock
= 1;
5917 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5918 if (rc
== SOCKET_ERROR
)
5920 /* Keep track of the fact that we set this to non-blocking. */
5921 fd_info
[s
].flags
|= FILE_NDELAY
;
5927 return SOCKET_ERROR
;
5931 return SOCKET_ERROR
;
5935 /* Shadow main io functions: we need to handle pipes and sockets more
5936 intelligently, and implement non-blocking mode as well. */
5949 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5951 child_process
* cp
= fd_info
[fd
].cp
;
5953 fd_info
[fd
].cp
= NULL
;
5955 if (CHILD_ACTIVE (cp
))
5957 /* if last descriptor to active child_process then cleanup */
5959 for (i
= 0; i
< MAXDESC
; i
++)
5963 if (fd_info
[i
].cp
== cp
)
5968 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5970 if (winsock_lib
== NULL
) abort ();
5972 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5973 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5975 winsock_inuse
--; /* count open sockets */
5982 /* Note that sockets do not need special treatment here (at least on
5983 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5984 closesocket is equivalent to CloseHandle, which is to be expected
5985 because socket handles are fully fledged kernel handles. */
5988 if (rc
== 0 && fd
< MAXDESC
)
5989 fd_info
[fd
].flags
= 0;
6000 if (new_fd
>= 0 && new_fd
< MAXDESC
)
6002 /* duplicate our internal info as well */
6003 fd_info
[new_fd
] = fd_info
[fd
];
6009 sys_dup2 (int src
, int dst
)
6013 if (dst
< 0 || dst
>= MAXDESC
)
6019 /* make sure we close the destination first if it's a pipe or socket */
6020 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
6023 rc
= _dup2 (src
, dst
);
6026 /* duplicate our internal info as well */
6027 fd_info
[dst
] = fd_info
[src
];
6032 /* Unix pipe() has only one arg */
6034 sys_pipe (int * phandles
)
6039 /* make pipe handles non-inheritable; when we spawn a child, we
6040 replace the relevant handle with an inheritable one. Also put
6041 pipes into binary mode; we will do text mode translation ourselves
6043 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
6047 /* Protect against overflow, since Windows can open more handles than
6048 our fd_info array has room for. */
6049 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
6051 _close (phandles
[0]);
6052 _close (phandles
[1]);
6057 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
6058 fd_info
[phandles
[0]].flags
= flags
;
6060 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
6061 fd_info
[phandles
[1]].flags
= flags
;
6068 /* Function to do blocking read of one byte, needed to implement
6069 select. It is only allowed on sockets and pipes. */
6071 _sys_read_ahead (int fd
)
6076 if (fd
< 0 || fd
>= MAXDESC
)
6077 return STATUS_READ_ERROR
;
6079 cp
= fd_info
[fd
].cp
;
6081 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6082 return STATUS_READ_ERROR
;
6084 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
6085 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
6087 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
6091 cp
->status
= STATUS_READ_IN_PROGRESS
;
6093 if (fd_info
[fd
].flags
& FILE_PIPE
)
6095 rc
= _read (fd
, &cp
->chr
, sizeof (char));
6097 /* Give subprocess time to buffer some more output for us before
6098 reporting that input is available; we need this because Windows 95
6099 connects DOS programs to pipes by making the pipe appear to be
6100 the normal console stdout - as a result most DOS programs will
6101 write to stdout without buffering, ie. one character at a
6102 time. Even some W32 programs do this - "dir" in a command
6103 shell on NT is very slow if we don't do this. */
6106 int wait
= w32_pipe_read_delay
;
6112 /* Yield remainder of our time slice, effectively giving a
6113 temporary priority boost to the child process. */
6117 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
6119 HANDLE hnd
= fd_info
[fd
].hnd
;
6120 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
6123 /* Configure timeouts for blocking read. */
6124 if (!GetCommTimeouts (hnd
, &ct
))
6125 return STATUS_READ_ERROR
;
6126 ct
.ReadIntervalTimeout
= 0;
6127 ct
.ReadTotalTimeoutMultiplier
= 0;
6128 ct
.ReadTotalTimeoutConstant
= 0;
6129 if (!SetCommTimeouts (hnd
, &ct
))
6130 return STATUS_READ_ERROR
;
6132 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
6134 if (GetLastError () != ERROR_IO_PENDING
)
6135 return STATUS_READ_ERROR
;
6136 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
6137 return STATUS_READ_ERROR
;
6140 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
6142 unsigned long nblock
= 0;
6143 /* We always want this to block, so temporarily disable NDELAY. */
6144 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6145 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6147 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
6149 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6152 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6156 if (rc
== sizeof (char))
6157 cp
->status
= STATUS_READ_SUCCEEDED
;
6159 cp
->status
= STATUS_READ_FAILED
;
6165 _sys_wait_accept (int fd
)
6171 if (fd
< 0 || fd
>= MAXDESC
)
6172 return STATUS_READ_ERROR
;
6174 cp
= fd_info
[fd
].cp
;
6176 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6177 return STATUS_READ_ERROR
;
6179 cp
->status
= STATUS_READ_FAILED
;
6181 hEv
= pfn_WSACreateEvent ();
6182 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
6183 if (rc
!= SOCKET_ERROR
)
6185 rc
= WaitForSingleObject (hEv
, INFINITE
);
6186 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
6187 if (rc
== WAIT_OBJECT_0
)
6188 cp
->status
= STATUS_READ_SUCCEEDED
;
6190 pfn_WSACloseEvent (hEv
);
6196 sys_read (int fd
, char * buffer
, unsigned int count
)
6201 char * orig_buffer
= buffer
;
6209 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
6211 child_process
*cp
= fd_info
[fd
].cp
;
6213 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
6221 /* re-read CR carried over from last read */
6222 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
6224 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
6228 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
6231 /* presence of a child_process structure means we are operating in
6232 non-blocking mode - otherwise we just call _read directly.
6233 Note that the child_process structure might be missing because
6234 reap_subprocess has been called; in this case the pipe is
6235 already broken, so calling _read on it is okay. */
6238 int current_status
= cp
->status
;
6240 switch (current_status
)
6242 case STATUS_READ_FAILED
:
6243 case STATUS_READ_ERROR
:
6244 /* report normal EOF if nothing in buffer */
6246 fd_info
[fd
].flags
|= FILE_AT_EOF
;
6249 case STATUS_READ_READY
:
6250 case STATUS_READ_IN_PROGRESS
:
6251 DebPrint (("sys_read called when read is in progress\n"));
6252 errno
= EWOULDBLOCK
;
6255 case STATUS_READ_SUCCEEDED
:
6256 /* consume read-ahead char */
6257 *buffer
++ = cp
->chr
;
6260 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6261 ResetEvent (cp
->char_avail
);
6263 case STATUS_READ_ACKNOWLEDGED
:
6267 DebPrint (("sys_read: bad status %d\n", current_status
));
6272 if (fd_info
[fd
].flags
& FILE_PIPE
)
6274 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
6275 to_read
= min (waiting
, (DWORD
) count
);
6278 nchars
+= _read (fd
, buffer
, to_read
);
6280 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
6282 HANDLE hnd
= fd_info
[fd
].hnd
;
6283 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
6289 /* Configure timeouts for non-blocking read. */
6290 if (!GetCommTimeouts (hnd
, &ct
))
6295 ct
.ReadIntervalTimeout
= MAXDWORD
;
6296 ct
.ReadTotalTimeoutMultiplier
= 0;
6297 ct
.ReadTotalTimeoutConstant
= 0;
6298 if (!SetCommTimeouts (hnd
, &ct
))
6304 if (!ResetEvent (ovl
->hEvent
))
6309 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
6311 if (GetLastError () != ERROR_IO_PENDING
)
6316 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
6325 else /* FILE_SOCKET */
6327 if (winsock_lib
== NULL
) abort ();
6329 /* do the equivalent of a non-blocking read */
6330 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
6331 if (waiting
== 0 && nchars
== 0)
6333 h_errno
= errno
= EWOULDBLOCK
;
6339 /* always use binary mode for sockets */
6340 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
6341 if (res
== SOCKET_ERROR
)
6343 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
6344 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
6354 int nread
= _read (fd
, buffer
, count
);
6357 else if (nchars
== 0)
6362 fd_info
[fd
].flags
|= FILE_AT_EOF
;
6363 /* Perform text mode translation if required. */
6364 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
6366 nchars
= crlf_to_lf (nchars
, orig_buffer
);
6367 /* If buffer contains only CR, return that. To be absolutely
6368 sure we should attempt to read the next char, but in
6369 practice a CR to be followed by LF would not appear by
6370 itself in the buffer. */
6371 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
6373 fd_info
[fd
].flags
|= FILE_LAST_CR
;
6379 nchars
= _read (fd
, buffer
, count
);
6384 /* From w32xfns.c */
6385 extern HANDLE interrupt_handle
;
6387 /* For now, don't bother with a non-blocking mode */
6389 sys_write (int fd
, const void * buffer
, unsigned int count
)
6399 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
6401 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
6407 /* Perform text mode translation if required. */
6408 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
6410 char * tmpbuf
= alloca (count
* 2);
6411 unsigned char * src
= (void *)buffer
;
6412 unsigned char * dst
= tmpbuf
;
6417 unsigned char *next
;
6418 /* copy next line or remaining bytes */
6419 next
= _memccpy (dst
, src
, '\n', nbytes
);
6422 /* copied one line ending with '\n' */
6423 int copied
= next
- dst
;
6426 /* insert '\r' before '\n' */
6433 /* copied remaining partial line -> now finished */
6440 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
6442 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
6443 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
6444 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
6447 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
6449 if (GetLastError () != ERROR_IO_PENDING
)
6454 if (detect_input_pending ())
6455 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
6458 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
6459 if (active
== WAIT_OBJECT_0
)
6460 { /* User pressed C-g, cancel write, then leave. Don't bother
6461 cleaning up as we may only get stuck in buggy drivers. */
6462 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
6467 if (active
== WAIT_OBJECT_0
+ 1
6468 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
6475 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
6477 unsigned long nblock
= 0;
6478 if (winsock_lib
== NULL
) abort ();
6480 /* TODO: implement select() properly so non-blocking I/O works. */
6481 /* For now, make sure the write blocks. */
6482 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6483 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6485 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
6487 /* Set the socket back to non-blocking if it was before,
6488 for other operations that support it. */
6489 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6492 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6495 if (nchars
== SOCKET_ERROR
)
6497 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
6498 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
6504 /* Some networked filesystems don't like too large writes, so
6505 break them into smaller chunks. See the Comments section of
6506 the MSDN documentation of WriteFile for details behind the
6507 choice of the value of CHUNK below. See also the thread
6508 http://thread.gmane.org/gmane.comp.version-control.git/145294
6509 in the git mailing list. */
6510 const unsigned char *p
= buffer
;
6511 const unsigned chunk
= 30 * 1024 * 1024;
6516 unsigned this_chunk
= count
< chunk
? count
: chunk
;
6517 int n
= _write (fd
, p
, this_chunk
);
6525 else if (n
< this_chunk
)
6535 /* The Windows CRT functions are "optimized for speed", so they don't
6536 check for timezone and DST changes if they were last called less
6537 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
6538 all Emacs features that repeatedly call time functions (e.g.,
6539 display-time) are in real danger of missing timezone and DST
6540 changes. Calling tzset before each localtime call fixes that. */
6542 sys_localtime (const time_t *t
)
6545 return localtime (t
);
6550 /* Delayed loading of libraries. */
6552 Lisp_Object Vlibrary_cache
;
6554 /* The argument LIBRARIES is an alist that associates a symbol
6555 LIBRARY_ID, identifying an external DLL library known to Emacs, to
6556 a list of filenames under which the library is usually found. In
6557 most cases, the argument passed as LIBRARIES is the variable
6558 `dynamic-library-alist', which is initialized to a list of common
6559 library names. If the function loads the library successfully, it
6560 returns the handle of the DLL, and records the filename in the
6561 property :loaded-from of LIBRARY_ID; it returns NULL if the library
6562 could not be found, or when it was already loaded (because the
6563 handle is not recorded anywhere, and so is lost after use). It
6564 would be trivial to save the handle too in :loaded-from, but
6565 currently there's no use case for it. */
6567 w32_delayed_load (Lisp_Object libraries
, Lisp_Object library_id
)
6569 HMODULE library_dll
= NULL
;
6571 CHECK_SYMBOL (library_id
);
6573 if (CONSP (libraries
) && NILP (Fassq (library_id
, Vlibrary_cache
)))
6575 Lisp_Object found
= Qnil
;
6576 Lisp_Object dlls
= Fassq (library_id
, libraries
);
6579 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
6581 CHECK_STRING_CAR (dlls
);
6582 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
6584 char name
[MAX_PATH
];
6587 len
= GetModuleFileNameA (library_dll
, name
, sizeof (name
));
6588 found
= Fcons (XCAR (dlls
),
6590 /* Possibly truncated */
6591 ? make_specified_string (name
, -1, len
, 1)
6597 Fput (library_id
, QCloaded_from
, found
);
6605 check_windows_init_file (void)
6607 /* A common indication that Emacs is not installed properly is when
6608 it cannot find the Windows installation file. If this file does
6609 not exist in the expected place, tell the user. */
6611 if (!noninteractive
&& !inhibit_window_system
6612 /* Vload_path is not yet initialized when we are loading
6614 && NILP (Vpurify_flag
))
6616 Lisp_Object init_file
;
6619 init_file
= build_string ("term/w32-win");
6620 fd
= openp (Vload_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
6623 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
6624 char *init_file_name
= SDATA (init_file
);
6625 char *load_path
= SDATA (load_path_print
);
6626 char *buffer
= alloca (1024
6627 + strlen (init_file_name
)
6628 + strlen (load_path
));
6631 "The Emacs Windows initialization file \"%s.el\" "
6632 "could not be found in your Emacs installation. "
6633 "Emacs checked the following directories for this file:\n"
6635 "When Emacs cannot find this file, it usually means that it "
6636 "was not installed properly, or its distribution file was "
6637 "not unpacked properly.\nSee the README.W32 file in the "
6638 "top-level Emacs directory for more information.",
6639 init_file_name
, load_path
);
6642 "Emacs Abort Dialog",
6643 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
6644 /* Use the low-level Emacs abort. */
6658 /* shutdown the socket interface if necessary */
6667 /* Initialize the socket interface now if available and requested by
6668 the user by defining PRELOAD_WINSOCK; otherwise loading will be
6669 delayed until open-network-stream is called (w32-has-winsock can
6670 also be used to dynamically load or reload winsock).
6672 Conveniently, init_environment is called before us, so
6673 PRELOAD_WINSOCK can be set in the registry. */
6675 /* Always initialize this correctly. */
6678 if (getenv ("PRELOAD_WINSOCK") != NULL
)
6679 init_winsock (TRUE
);
6681 /* Initial preparation for subprocess support: replace our standard
6682 handles with non-inheritable versions. */
6685 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
6686 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
6687 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
6689 parent
= GetCurrentProcess ();
6691 /* ignore errors when duplicating and closing; typically the
6692 handles will be invalid when running as a gui program. */
6693 DuplicateHandle (parent
,
6694 GetStdHandle (STD_INPUT_HANDLE
),
6699 DUPLICATE_SAME_ACCESS
);
6701 DuplicateHandle (parent
,
6702 GetStdHandle (STD_OUTPUT_HANDLE
),
6707 DUPLICATE_SAME_ACCESS
);
6709 DuplicateHandle (parent
,
6710 GetStdHandle (STD_ERROR_HANDLE
),
6715 DUPLICATE_SAME_ACCESS
);
6721 if (stdin_save
!= INVALID_HANDLE_VALUE
)
6722 _open_osfhandle ((long) stdin_save
, O_TEXT
);
6724 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
6727 if (stdout_save
!= INVALID_HANDLE_VALUE
)
6728 _open_osfhandle ((long) stdout_save
, O_TEXT
);
6730 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
6733 if (stderr_save
!= INVALID_HANDLE_VALUE
)
6734 _open_osfhandle ((long) stderr_save
, O_TEXT
);
6736 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
6740 /* unfortunately, atexit depends on implementation of malloc */
6741 /* atexit (term_ntproc); */
6742 signal (SIGABRT
, term_ntproc
);
6744 /* determine which drives are fixed, for GetCachedVolumeInformation */
6746 /* GetDriveType must have trailing backslash. */
6747 char drive
[] = "A:\\";
6749 /* Loop over all possible drive letters */
6750 while (*drive
<= 'Z')
6752 /* Record if this drive letter refers to a fixed drive. */
6753 fixed_drives
[DRIVE_INDEX (*drive
)] =
6754 (GetDriveType (drive
) == DRIVE_FIXED
);
6759 /* Reset the volume info cache. */
6760 volume_cache
= NULL
;
6765 shutdown_handler ensures that buffers' autosave files are
6766 up to date when the user logs off, or the system shuts down.
6769 shutdown_handler (DWORD type
)
6771 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
6772 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
6773 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
6774 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
6776 /* Shut down cleanly, making sure autosave files are up to date. */
6777 shut_down_emacs (0, 0, Qnil
);
6780 /* Allow other handlers to handle this signal. */
6785 globals_of_w32 is used to initialize those global variables that
6786 must always be initialized on startup even when the global variable
6787 initialized is non zero (see the function main in emacs.c).
6790 globals_of_w32 (void)
6792 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
6794 get_process_times_fn
= (GetProcessTimes_Proc
)
6795 GetProcAddress (kernel32
, "GetProcessTimes");
6797 DEFSYM (QCloaded_from
, ":loaded-from");
6799 Vlibrary_cache
= Qnil
;
6800 staticpro (&Vlibrary_cache
);
6802 g_b_init_is_windows_9x
= 0;
6803 g_b_init_open_process_token
= 0;
6804 g_b_init_get_token_information
= 0;
6805 g_b_init_lookup_account_sid
= 0;
6806 g_b_init_get_sid_sub_authority
= 0;
6807 g_b_init_get_sid_sub_authority_count
= 0;
6808 g_b_init_get_security_info
= 0;
6809 g_b_init_get_file_security
= 0;
6810 g_b_init_get_security_descriptor_owner
= 0;
6811 g_b_init_get_security_descriptor_group
= 0;
6812 g_b_init_is_valid_sid
= 0;
6813 g_b_init_create_toolhelp32_snapshot
= 0;
6814 g_b_init_process32_first
= 0;
6815 g_b_init_process32_next
= 0;
6816 g_b_init_open_thread_token
= 0;
6817 g_b_init_impersonate_self
= 0;
6818 g_b_init_revert_to_self
= 0;
6819 g_b_init_get_process_memory_info
= 0;
6820 g_b_init_get_process_working_set_size
= 0;
6821 g_b_init_global_memory_status
= 0;
6822 g_b_init_global_memory_status_ex
= 0;
6823 g_b_init_equal_sid
= 0;
6824 g_b_init_copy_sid
= 0;
6825 g_b_init_get_length_sid
= 0;
6826 g_b_init_get_native_system_info
= 0;
6827 g_b_init_get_system_times
= 0;
6828 g_b_init_create_symbolic_link
= 0;
6829 num_of_processors
= 0;
6830 /* The following sets a handler for shutdown notifications for
6831 console apps. This actually applies to Emacs in both console and
6832 GUI modes, since we had to fool windows into thinking emacs is a
6833 console application to get console mode to work. */
6834 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
6836 /* "None" is the default group name on standalone workstations. */
6837 strcpy (dflt_group_name
, "None");
6840 /* For make-serial-process */
6842 serial_open (char *port
)
6848 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
6849 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
6850 if (hnd
== INVALID_HANDLE_VALUE
)
6851 error ("Could not open %s", port
);
6852 fd
= (int) _open_osfhandle ((int) hnd
, 0);
6854 error ("Could not open %s", port
);
6858 error ("Could not create child process");
6860 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6861 fd_info
[ fd
].hnd
= hnd
;
6862 fd_info
[ fd
].flags
|=
6863 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
6864 if (fd_info
[ fd
].cp
!= NULL
)
6866 error ("fd_info[fd = %d] is already in use", fd
);
6868 fd_info
[ fd
].cp
= cp
;
6869 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6870 if (cp
->ovl_read
.hEvent
== NULL
)
6871 error ("Could not create read event");
6872 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6873 if (cp
->ovl_write
.hEvent
== NULL
)
6874 error ("Could not create write event");
6879 /* For serial-process-configure */
6881 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
6883 Lisp_Object childp2
= Qnil
;
6884 Lisp_Object tem
= Qnil
;
6888 char summary
[4] = "???"; /* This usually becomes "8N1". */
6890 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6891 error ("Not a serial process");
6892 hnd
= fd_info
[ p
->outfd
].hnd
;
6894 childp2
= Fcopy_sequence (PGET (p
, childp
));
6896 /* Initialize timeouts for blocking read and blocking write. */
6897 if (!GetCommTimeouts (hnd
, &ct
))
6898 error ("GetCommTimeouts() failed");
6899 ct
.ReadIntervalTimeout
= 0;
6900 ct
.ReadTotalTimeoutMultiplier
= 0;
6901 ct
.ReadTotalTimeoutConstant
= 0;
6902 ct
.WriteTotalTimeoutMultiplier
= 0;
6903 ct
.WriteTotalTimeoutConstant
= 0;
6904 if (!SetCommTimeouts (hnd
, &ct
))
6905 error ("SetCommTimeouts() failed");
6906 /* Read port attributes and prepare default configuration. */
6907 memset (&dcb
, 0, sizeof (dcb
));
6908 dcb
.DCBlength
= sizeof (DCB
);
6909 if (!GetCommState (hnd
, &dcb
))
6910 error ("GetCommState() failed");
6913 dcb
.fAbortOnError
= FALSE
;
6914 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6919 /* Configure speed. */
6920 if (!NILP (Fplist_member (contact
, QCspeed
)))
6921 tem
= Fplist_get (contact
, QCspeed
);
6923 tem
= Fplist_get (PGET (p
, childp
), QCspeed
);
6925 dcb
.BaudRate
= XINT (tem
);
6926 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6928 /* Configure bytesize. */
6929 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6930 tem
= Fplist_get (contact
, QCbytesize
);
6932 tem
= Fplist_get (PGET (p
, childp
), QCbytesize
);
6934 tem
= make_number (8);
6936 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6937 error (":bytesize must be nil (8), 7, or 8");
6938 dcb
.ByteSize
= XINT (tem
);
6939 summary
[0] = XINT (tem
) + '0';
6940 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6942 /* Configure parity. */
6943 if (!NILP (Fplist_member (contact
, QCparity
)))
6944 tem
= Fplist_get (contact
, QCparity
);
6946 tem
= Fplist_get (PGET (p
, childp
), QCparity
);
6947 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6948 error (":parity must be nil (no parity), `even', or `odd'");
6949 dcb
.fParity
= FALSE
;
6950 dcb
.Parity
= NOPARITY
;
6951 dcb
.fErrorChar
= FALSE
;
6956 else if (EQ (tem
, Qeven
))
6960 dcb
.Parity
= EVENPARITY
;
6961 dcb
.fErrorChar
= TRUE
;
6963 else if (EQ (tem
, Qodd
))
6967 dcb
.Parity
= ODDPARITY
;
6968 dcb
.fErrorChar
= TRUE
;
6970 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6972 /* Configure stopbits. */
6973 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6974 tem
= Fplist_get (contact
, QCstopbits
);
6976 tem
= Fplist_get (PGET (p
, childp
), QCstopbits
);
6978 tem
= make_number (1);
6980 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6981 error (":stopbits must be nil (1 stopbit), 1, or 2");
6982 summary
[2] = XINT (tem
) + '0';
6983 if (XINT (tem
) == 1)
6984 dcb
.StopBits
= ONESTOPBIT
;
6985 else if (XINT (tem
) == 2)
6986 dcb
.StopBits
= TWOSTOPBITS
;
6987 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6989 /* Configure flowcontrol. */
6990 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6991 tem
= Fplist_get (contact
, QCflowcontrol
);
6993 tem
= Fplist_get (PGET (p
, childp
), QCflowcontrol
);
6994 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6995 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6996 dcb
.fOutxCtsFlow
= FALSE
;
6997 dcb
.fOutxDsrFlow
= FALSE
;
6998 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6999 dcb
.fDsrSensitivity
= FALSE
;
7000 dcb
.fTXContinueOnXoff
= FALSE
;
7003 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
7004 dcb
.XonChar
= 17; /* Control-Q */
7005 dcb
.XoffChar
= 19; /* Control-S */
7008 /* Already configured. */
7010 else if (EQ (tem
, Qhw
))
7012 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
7013 dcb
.fOutxCtsFlow
= TRUE
;
7015 else if (EQ (tem
, Qsw
))
7020 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
7022 /* Activate configuration. */
7023 if (!SetCommState (hnd
, &dcb
))
7024 error ("SetCommState() failed");
7026 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
7027 PSET (p
, childp
, childp2
);
7033 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
7037 struct timeval timeout
;
7038 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7039 int fd
= process
->infd
;
7043 n
= sys_read (fd
, (char*)buf
, sz
);
7050 if (err
== EWOULDBLOCK
)
7052 /* Set a small timeout. */
7054 timeout
.tv_usec
= 0;
7056 FD_SET ((int)fd
, &fdset
);
7058 /* Use select with the timeout to poll the selector. */
7059 sc
= select (fd
+ 1, &fdset
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0,
7063 continue; /* Try again. */
7065 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
7066 Also accept select return 0 as an indicator to EAGAIN. */
7067 if (sc
== 0 || errno
== EWOULDBLOCK
)
7070 err
= errno
; /* Other errors are just passed on. */
7073 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
7080 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
7082 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7083 int fd
= process
->outfd
;
7084 ssize_t n
= sys_write (fd
, buf
, sz
);
7086 /* 0 or more bytes written means everything went fine. */
7090 /* Negative bytes written means we got an error in errno.
7091 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7092 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
7093 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
7097 #endif /* HAVE_GNUTLS */