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 */
38 /* must include CRT headers *before* config.h */
73 #define _ANONYMOUS_UNION
74 #define _ANONYMOUS_STRUCT
77 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
78 use a different name to avoid compilation problems. */
79 typedef struct _MEMORY_STATUS_EX
{
82 DWORDLONG ullTotalPhys
;
83 DWORDLONG ullAvailPhys
;
84 DWORDLONG ullTotalPageFile
;
85 DWORDLONG ullAvailPageFile
;
86 DWORDLONG ullTotalVirtual
;
87 DWORDLONG ullAvailVirtual
;
88 DWORDLONG ullAvailExtendedVirtual
;
89 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
99 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
100 /* This either is not in psapi.h or guarded by higher value of
101 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
102 defines it in psapi.h */
103 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
105 DWORD PageFaultCount
;
106 DWORD PeakWorkingSetSize
;
107 DWORD WorkingSetSize
;
108 DWORD QuotaPeakPagedPoolUsage
;
109 DWORD QuotaPagedPoolUsage
;
110 DWORD QuotaPeakNonPagedPoolUsage
;
111 DWORD QuotaNonPagedPoolUsage
;
113 DWORD PeakPagefileUsage
;
115 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
118 #include <winioctl.h>
122 /* MSVC doesn't provide the definition of REPARSE_DATA_BUFFER, except
123 on ntifs.h, which cannot be included because it triggers conflicts
124 with other Windows API headers. So we define it here by hand. */
126 typedef struct _REPARSE_DATA_BUFFER
{
128 USHORT ReparseDataLength
;
132 USHORT SubstituteNameOffset
;
133 USHORT SubstituteNameLength
;
134 USHORT PrintNameOffset
;
135 USHORT PrintNameLength
;
138 } SymbolicLinkReparseBuffer
;
140 USHORT SubstituteNameOffset
;
141 USHORT SubstituteNameLength
;
142 USHORT PrintNameOffset
;
143 USHORT PrintNameLength
;
145 } MountPointReparseBuffer
;
148 } GenericReparseBuffer
;
150 } REPARSE_DATA_BUFFER
, *PREPARSE_DATA_BUFFER
;
154 /* TCP connection support. */
155 #include <sys/socket.h>
178 #include "dispextern.h" /* for xstrcasecmp */
179 #include "coding.h" /* for Vlocale_coding_system */
181 #include "careadlinkat.h"
182 #include "allocator.h"
184 /* For serial_configure and serial_open. */
187 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
188 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
190 Lisp_Object QCloaded_from
;
192 void globals_of_w32 (void);
193 static DWORD
get_rid (PSID
);
194 static int is_symlink (const char *);
195 static char * chase_symlinks (const char *);
196 static int enable_privilege (LPCTSTR
, BOOL
, TOKEN_PRIVILEGES
*);
197 static int restore_privilege (TOKEN_PRIVILEGES
*);
198 static BOOL WINAPI
revert_to_self (void);
201 /* Initialization states.
203 WARNING: If you add any more such variables for additional APIs,
204 you MUST add initialization for them to globals_of_w32
205 below. This is because these variables might get set
206 to non-NULL values during dumping, but the dumped Emacs
207 cannot reuse those values, because it could be run on a
208 different version of the OS, where API addresses are
210 static BOOL g_b_init_is_windows_9x
;
211 static BOOL g_b_init_open_process_token
;
212 static BOOL g_b_init_get_token_information
;
213 static BOOL g_b_init_lookup_account_sid
;
214 static BOOL g_b_init_get_sid_sub_authority
;
215 static BOOL g_b_init_get_sid_sub_authority_count
;
216 static BOOL g_b_init_get_security_info
;
217 static BOOL g_b_init_get_file_security
;
218 static BOOL g_b_init_get_security_descriptor_owner
;
219 static BOOL g_b_init_get_security_descriptor_group
;
220 static BOOL g_b_init_is_valid_sid
;
221 static BOOL g_b_init_create_toolhelp32_snapshot
;
222 static BOOL g_b_init_process32_first
;
223 static BOOL g_b_init_process32_next
;
224 static BOOL g_b_init_open_thread_token
;
225 static BOOL g_b_init_impersonate_self
;
226 static BOOL g_b_init_revert_to_self
;
227 static BOOL g_b_init_get_process_memory_info
;
228 static BOOL g_b_init_get_process_working_set_size
;
229 static BOOL g_b_init_global_memory_status
;
230 static BOOL g_b_init_global_memory_status_ex
;
231 static BOOL g_b_init_get_length_sid
;
232 static BOOL g_b_init_equal_sid
;
233 static BOOL g_b_init_copy_sid
;
234 static BOOL g_b_init_get_native_system_info
;
235 static BOOL g_b_init_get_system_times
;
236 static BOOL g_b_init_create_symbolic_link
;
239 BEGIN: Wrapper functions around OpenProcessToken
240 and other functions in advapi32.dll that are only
241 supported in Windows NT / 2k / XP
243 /* ** Function pointer typedefs ** */
244 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
245 HANDLE ProcessHandle
,
247 PHANDLE TokenHandle
);
248 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
250 TOKEN_INFORMATION_CLASS TokenInformationClass
,
251 LPVOID TokenInformation
,
252 DWORD TokenInformationLength
,
253 PDWORD ReturnLength
);
254 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
255 HANDLE process_handle
,
256 LPFILETIME creation_time
,
257 LPFILETIME exit_time
,
258 LPFILETIME kernel_time
,
259 LPFILETIME user_time
);
261 GetProcessTimes_Proc get_process_times_fn
= NULL
;
264 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
265 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
267 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
268 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
270 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
271 LPCTSTR lpSystemName
,
276 LPDWORD cbDomainName
,
277 PSID_NAME_USE peUse
);
278 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
281 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
283 typedef DWORD (WINAPI
* GetSecurityInfo_Proc
) (
285 SE_OBJECT_TYPE ObjectType
,
286 SECURITY_INFORMATION SecurityInfo
,
291 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
);
292 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
294 SECURITY_INFORMATION RequestedInformation
,
295 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
297 LPDWORD lpnLengthNeeded
);
298 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
299 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
301 LPBOOL lpbOwnerDefaulted
);
302 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
303 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
305 LPBOOL lpbGroupDefaulted
);
306 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
308 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
310 DWORD th32ProcessID
);
311 typedef BOOL (WINAPI
* Process32First_Proc
) (
313 LPPROCESSENTRY32 lppe
);
314 typedef BOOL (WINAPI
* Process32Next_Proc
) (
316 LPPROCESSENTRY32 lppe
);
317 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
321 PHANDLE TokenHandle
);
322 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
323 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
324 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
325 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
327 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
329 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
331 DWORD
* lpMinimumWorkingSetSize
,
332 DWORD
* lpMaximumWorkingSetSize
);
333 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
334 LPMEMORYSTATUS lpBuffer
);
335 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
336 LPMEMORY_STATUS_EX lpBuffer
);
337 typedef BOOL (WINAPI
* CopySid_Proc
) (
338 DWORD nDestinationSidLength
,
339 PSID pDestinationSid
,
341 typedef BOOL (WINAPI
* EqualSid_Proc
) (
344 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
346 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
347 LPSYSTEM_INFO lpSystemInfo
);
348 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
349 LPFILETIME lpIdleTime
,
350 LPFILETIME lpKernelTime
,
351 LPFILETIME lpUserTime
);
352 typedef BOOLEAN (WINAPI
*CreateSymbolicLink_Proc
) (
353 LPTSTR lpSymlinkFileName
,
354 LPTSTR lpTargetFileName
,
357 /* ** A utility function ** */
361 static BOOL s_b_ret
= 0;
362 OSVERSIONINFO os_ver
;
363 if (g_b_init_is_windows_9x
== 0)
365 g_b_init_is_windows_9x
= 1;
366 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
367 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
368 if (GetVersionEx (&os_ver
))
370 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
376 static Lisp_Object
ltime (ULONGLONG
);
378 /* Get total user and system times for get-internal-run-time.
379 Returns a list of integers if the times are provided by the OS
380 (NT derivatives), otherwise it returns the result of current-time. */
382 w32_get_internal_run_time (void)
384 if (get_process_times_fn
)
386 FILETIME create
, exit
, kernel
, user
;
387 HANDLE proc
= GetCurrentProcess ();
388 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
390 LARGE_INTEGER user_int
, kernel_int
, total
;
391 user_int
.LowPart
= user
.dwLowDateTime
;
392 user_int
.HighPart
= user
.dwHighDateTime
;
393 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
394 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
395 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
396 return ltime (total
.QuadPart
);
400 return Fcurrent_time ();
403 /* ** The wrapper functions ** */
406 open_process_token (HANDLE ProcessHandle
,
410 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
411 HMODULE hm_advapi32
= NULL
;
412 if (is_windows_9x () == TRUE
)
416 if (g_b_init_open_process_token
== 0)
418 g_b_init_open_process_token
= 1;
419 hm_advapi32
= LoadLibrary ("Advapi32.dll");
420 s_pfn_Open_Process_Token
=
421 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
423 if (s_pfn_Open_Process_Token
== NULL
)
428 s_pfn_Open_Process_Token (
436 get_token_information (HANDLE TokenHandle
,
437 TOKEN_INFORMATION_CLASS TokenInformationClass
,
438 LPVOID TokenInformation
,
439 DWORD TokenInformationLength
,
442 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
443 HMODULE hm_advapi32
= NULL
;
444 if (is_windows_9x () == TRUE
)
448 if (g_b_init_get_token_information
== 0)
450 g_b_init_get_token_information
= 1;
451 hm_advapi32
= LoadLibrary ("Advapi32.dll");
452 s_pfn_Get_Token_Information
=
453 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
455 if (s_pfn_Get_Token_Information
== NULL
)
460 s_pfn_Get_Token_Information (
462 TokenInformationClass
,
464 TokenInformationLength
,
470 lookup_account_sid (LPCTSTR lpSystemName
,
475 LPDWORD cbDomainName
,
478 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
479 HMODULE hm_advapi32
= NULL
;
480 if (is_windows_9x () == TRUE
)
484 if (g_b_init_lookup_account_sid
== 0)
486 g_b_init_lookup_account_sid
= 1;
487 hm_advapi32
= LoadLibrary ("Advapi32.dll");
488 s_pfn_Lookup_Account_Sid
=
489 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
491 if (s_pfn_Lookup_Account_Sid
== NULL
)
496 s_pfn_Lookup_Account_Sid (
508 get_sid_sub_authority (PSID pSid
, DWORD n
)
510 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
511 static DWORD zero
= 0U;
512 HMODULE hm_advapi32
= NULL
;
513 if (is_windows_9x () == TRUE
)
517 if (g_b_init_get_sid_sub_authority
== 0)
519 g_b_init_get_sid_sub_authority
= 1;
520 hm_advapi32
= LoadLibrary ("Advapi32.dll");
521 s_pfn_Get_Sid_Sub_Authority
=
522 (GetSidSubAuthority_Proc
) GetProcAddress (
523 hm_advapi32
, "GetSidSubAuthority");
525 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
529 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
533 get_sid_sub_authority_count (PSID pSid
)
535 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
536 static UCHAR zero
= 0U;
537 HMODULE hm_advapi32
= NULL
;
538 if (is_windows_9x () == TRUE
)
542 if (g_b_init_get_sid_sub_authority_count
== 0)
544 g_b_init_get_sid_sub_authority_count
= 1;
545 hm_advapi32
= LoadLibrary ("Advapi32.dll");
546 s_pfn_Get_Sid_Sub_Authority_Count
=
547 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
548 hm_advapi32
, "GetSidSubAuthorityCount");
550 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
554 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
558 get_security_info (HANDLE handle
,
559 SE_OBJECT_TYPE ObjectType
,
560 SECURITY_INFORMATION SecurityInfo
,
565 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
)
567 static GetSecurityInfo_Proc s_pfn_Get_Security_Info
= NULL
;
568 HMODULE hm_advapi32
= NULL
;
569 if (is_windows_9x () == TRUE
)
573 if (g_b_init_get_security_info
== 0)
575 g_b_init_get_security_info
= 1;
576 hm_advapi32
= LoadLibrary ("Advapi32.dll");
577 s_pfn_Get_Security_Info
=
578 (GetSecurityInfo_Proc
) GetProcAddress (
579 hm_advapi32
, "GetSecurityInfo");
581 if (s_pfn_Get_Security_Info
== NULL
)
585 return (s_pfn_Get_Security_Info (handle
, ObjectType
, SecurityInfo
,
586 ppsidOwner
, ppsidGroup
, ppDacl
, ppSacl
,
587 ppSecurityDescriptor
));
591 get_file_security (LPCTSTR lpFileName
,
592 SECURITY_INFORMATION RequestedInformation
,
593 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
595 LPDWORD lpnLengthNeeded
)
597 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
598 HMODULE hm_advapi32
= NULL
;
599 if (is_windows_9x () == TRUE
)
603 if (g_b_init_get_file_security
== 0)
605 g_b_init_get_file_security
= 1;
606 hm_advapi32
= LoadLibrary ("Advapi32.dll");
607 s_pfn_Get_File_Security
=
608 (GetFileSecurity_Proc
) GetProcAddress (
609 hm_advapi32
, GetFileSecurity_Name
);
611 if (s_pfn_Get_File_Security
== NULL
)
615 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
616 pSecurityDescriptor
, nLength
,
621 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
623 LPBOOL lpbOwnerDefaulted
)
625 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
626 HMODULE hm_advapi32
= NULL
;
627 if (is_windows_9x () == TRUE
)
631 if (g_b_init_get_security_descriptor_owner
== 0)
633 g_b_init_get_security_descriptor_owner
= 1;
634 hm_advapi32
= LoadLibrary ("Advapi32.dll");
635 s_pfn_Get_Security_Descriptor_Owner
=
636 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
637 hm_advapi32
, "GetSecurityDescriptorOwner");
639 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
643 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
648 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
650 LPBOOL lpbGroupDefaulted
)
652 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
653 HMODULE hm_advapi32
= NULL
;
654 if (is_windows_9x () == TRUE
)
658 if (g_b_init_get_security_descriptor_group
== 0)
660 g_b_init_get_security_descriptor_group
= 1;
661 hm_advapi32
= LoadLibrary ("Advapi32.dll");
662 s_pfn_Get_Security_Descriptor_Group
=
663 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
664 hm_advapi32
, "GetSecurityDescriptorGroup");
666 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
670 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
675 is_valid_sid (PSID sid
)
677 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
678 HMODULE hm_advapi32
= NULL
;
679 if (is_windows_9x () == TRUE
)
683 if (g_b_init_is_valid_sid
== 0)
685 g_b_init_is_valid_sid
= 1;
686 hm_advapi32
= LoadLibrary ("Advapi32.dll");
688 (IsValidSid_Proc
) GetProcAddress (
689 hm_advapi32
, "IsValidSid");
691 if (s_pfn_Is_Valid_Sid
== NULL
)
695 return (s_pfn_Is_Valid_Sid (sid
));
699 equal_sid (PSID sid1
, PSID sid2
)
701 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
702 HMODULE hm_advapi32
= NULL
;
703 if (is_windows_9x () == TRUE
)
707 if (g_b_init_equal_sid
== 0)
709 g_b_init_equal_sid
= 1;
710 hm_advapi32
= LoadLibrary ("Advapi32.dll");
712 (EqualSid_Proc
) GetProcAddress (
713 hm_advapi32
, "EqualSid");
715 if (s_pfn_Equal_Sid
== NULL
)
719 return (s_pfn_Equal_Sid (sid1
, sid2
));
723 get_length_sid (PSID sid
)
725 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
726 HMODULE hm_advapi32
= NULL
;
727 if (is_windows_9x () == TRUE
)
731 if (g_b_init_get_length_sid
== 0)
733 g_b_init_get_length_sid
= 1;
734 hm_advapi32
= LoadLibrary ("Advapi32.dll");
735 s_pfn_Get_Length_Sid
=
736 (GetLengthSid_Proc
) GetProcAddress (
737 hm_advapi32
, "GetLengthSid");
739 if (s_pfn_Get_Length_Sid
== NULL
)
743 return (s_pfn_Get_Length_Sid (sid
));
747 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
749 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
750 HMODULE hm_advapi32
= NULL
;
751 if (is_windows_9x () == TRUE
)
755 if (g_b_init_copy_sid
== 0)
757 g_b_init_copy_sid
= 1;
758 hm_advapi32
= LoadLibrary ("Advapi32.dll");
760 (CopySid_Proc
) GetProcAddress (
761 hm_advapi32
, "CopySid");
763 if (s_pfn_Copy_Sid
== NULL
)
767 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
771 END: Wrapper functions around OpenProcessToken
772 and other functions in advapi32.dll that are only
773 supported in Windows NT / 2k / XP
777 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
779 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
780 if (is_windows_9x () != TRUE
)
782 if (g_b_init_get_native_system_info
== 0)
784 g_b_init_get_native_system_info
= 1;
785 s_pfn_Get_Native_System_Info
=
786 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
787 "GetNativeSystemInfo");
789 if (s_pfn_Get_Native_System_Info
!= NULL
)
790 s_pfn_Get_Native_System_Info (lpSystemInfo
);
793 lpSystemInfo
->dwNumberOfProcessors
= -1;
797 get_system_times (LPFILETIME lpIdleTime
,
798 LPFILETIME lpKernelTime
,
799 LPFILETIME lpUserTime
)
801 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
802 if (is_windows_9x () == TRUE
)
806 if (g_b_init_get_system_times
== 0)
808 g_b_init_get_system_times
= 1;
809 s_pfn_Get_System_times
=
810 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
813 if (s_pfn_Get_System_times
== NULL
)
815 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
818 static BOOLEAN WINAPI
819 create_symbolic_link (LPTSTR lpSymlinkFilename
,
820 LPTSTR lpTargetFileName
,
823 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link
= NULL
;
826 if (is_windows_9x () == TRUE
)
831 if (g_b_init_create_symbolic_link
== 0)
833 g_b_init_create_symbolic_link
= 1;
835 s_pfn_Create_Symbolic_Link
=
836 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
837 "CreateSymbolicLinkW");
839 s_pfn_Create_Symbolic_Link
=
840 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
841 "CreateSymbolicLinkA");
844 if (s_pfn_Create_Symbolic_Link
== NULL
)
850 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
852 /* If we were denied creation of the symlink, try again after
853 enabling the SeCreateSymbolicLinkPrivilege for our process. */
856 TOKEN_PRIVILEGES priv_current
;
858 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME
, TRUE
, &priv_current
))
860 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
862 restore_privilege (&priv_current
);
869 /* Equivalent of strerror for W32 error codes. */
871 w32_strerror (int error_no
)
873 static char buf
[500];
876 error_no
= GetLastError ();
879 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
881 0, /* choose most suitable language */
882 buf
, sizeof (buf
), NULL
))
883 sprintf (buf
, "w32 error %u", error_no
);
887 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
888 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
890 This is called from alloc.c:valid_pointer_p. */
892 w32_valid_pointer_p (void *p
, int size
)
895 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
899 unsigned char *buf
= alloca (size
);
900 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
909 static char startup_dir
[MAXPATHLEN
];
911 /* Get the current working directory. */
916 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
920 /* Emacs doesn't actually change directory itself, it stays in the
921 same directory where it was started. */
922 strcpy (dir
, startup_dir
);
927 /* Emulate getloadavg. */
936 /* Number of processors on this machine. */
937 static unsigned num_of_processors
;
939 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
940 static struct load_sample samples
[16*60];
941 static int first_idx
= -1, last_idx
= -1;
942 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
947 int next_idx
= from
+ 1;
949 if (next_idx
>= max_idx
)
958 int prev_idx
= from
- 1;
961 prev_idx
= max_idx
- 1;
967 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
970 FILETIME ft_idle
, ft_user
, ft_kernel
;
972 /* Initialize the number of processors on this machine. */
973 if (num_of_processors
<= 0)
975 get_native_system_info (&sysinfo
);
976 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
977 if (num_of_processors
<= 0)
979 GetSystemInfo (&sysinfo
);
980 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
982 if (num_of_processors
<= 0)
983 num_of_processors
= 1;
986 /* TODO: Take into account threads that are ready to run, by
987 sampling the "\System\Processor Queue Length" performance
988 counter. The code below accounts only for threads that are
991 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
993 ULARGE_INTEGER uidle
, ukernel
, uuser
;
995 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
996 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
997 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
998 *idle
= uidle
.QuadPart
;
999 *kernel
= ukernel
.QuadPart
;
1000 *user
= uuser
.QuadPart
;
1010 /* Produce the load average for a given time interval, using the
1011 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1012 1-minute, 5-minute, or 15-minute average, respectively. */
1016 double retval
= -1.0;
1019 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
1020 time_t now
= samples
[last_idx
].sample_time
;
1022 if (first_idx
!= last_idx
)
1024 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
1026 tdiff
= difftime (now
, samples
[idx
].sample_time
);
1027 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
1030 samples
[last_idx
].kernel
+ samples
[last_idx
].user
1031 - (samples
[idx
].kernel
+ samples
[idx
].user
);
1032 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
1034 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
1037 if (idx
== first_idx
)
1046 getloadavg (double loadavg
[], int nelem
)
1049 ULONGLONG idle
, kernel
, user
;
1050 time_t now
= time (NULL
);
1052 /* Store another sample. We ignore samples that are less than 1 sec
1054 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
1056 sample_system_load (&idle
, &kernel
, &user
);
1057 last_idx
= buf_next (last_idx
);
1058 samples
[last_idx
].sample_time
= now
;
1059 samples
[last_idx
].idle
= idle
;
1060 samples
[last_idx
].kernel
= kernel
;
1061 samples
[last_idx
].user
= user
;
1062 /* If the buffer has more that 15 min worth of samples, discard
1064 if (first_idx
== -1)
1065 first_idx
= last_idx
;
1066 while (first_idx
!= last_idx
1067 && (difftime (now
, samples
[first_idx
].sample_time
)
1068 >= 15.0*60 + 2*DBL_EPSILON
*now
))
1069 first_idx
= buf_next (first_idx
);
1072 for (elem
= 0; elem
< nelem
; elem
++)
1074 double avg
= getavg (elem
);
1078 loadavg
[elem
] = avg
;
1084 /* Emulate getpwuid, getpwnam and others. */
1086 #define PASSWD_FIELD_SIZE 256
1088 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1089 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1090 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1091 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
1092 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
1094 static struct passwd dflt_passwd
=
1106 static char dflt_group_name
[GNLEN
+1];
1108 static struct group dflt_group
=
1110 /* When group information is not available, we return this as the
1111 group for all files. */
1119 return dflt_passwd
.pw_uid
;
1125 /* I could imagine arguing for checking to see whether the user is
1126 in the Administrators group and returning a UID of 0 for that
1127 case, but I don't know how wise that would be in the long run. */
1134 return dflt_passwd
.pw_gid
;
1144 getpwuid (unsigned uid
)
1146 if (uid
== dflt_passwd
.pw_uid
)
1147 return &dflt_passwd
;
1152 getgrgid (gid_t gid
)
1158 getpwnam (char *name
)
1162 pw
= getpwuid (getuid ());
1166 if (xstrcasecmp (name
, pw
->pw_name
))
1173 init_user_info (void)
1175 /* Find the user's real name by opening the process token and
1176 looking up the name associated with the user-sid in that token.
1178 Use the relative portion of the identifier authority value from
1179 the user-sid as the user id value (same for group id using the
1180 primary group sid from the process token). */
1182 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1183 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1184 DWORD glength
= sizeof (gname
);
1185 HANDLE token
= NULL
;
1186 SID_NAME_USE user_type
;
1187 unsigned char *buf
= NULL
;
1189 TOKEN_USER user_token
;
1190 TOKEN_PRIMARY_GROUP group_token
;
1193 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1196 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1197 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1199 buf
= xmalloc (blen
);
1200 result
= get_token_information (token
, TokenUser
,
1201 (LPVOID
)buf
, blen
, &needed
);
1204 memcpy (&user_token
, buf
, sizeof (user_token
));
1205 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1207 domain
, &dlength
, &user_type
);
1215 strcpy (dflt_passwd
.pw_name
, uname
);
1216 /* Determine a reasonable uid value. */
1217 if (xstrcasecmp ("administrator", uname
) == 0)
1219 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1220 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1224 /* Use the last sub-authority value of the RID, the relative
1225 portion of the SID, as user/group ID. */
1226 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1228 /* Get group id and name. */
1229 result
= get_token_information (token
, TokenPrimaryGroup
,
1230 (LPVOID
)buf
, blen
, &needed
);
1231 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1233 buf
= xrealloc (buf
, blen
= needed
);
1234 result
= get_token_information (token
, TokenPrimaryGroup
,
1235 (LPVOID
)buf
, blen
, &needed
);
1239 memcpy (&group_token
, buf
, sizeof (group_token
));
1240 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1241 dlength
= sizeof (domain
);
1242 /* If we can get at the real Primary Group name, use that.
1243 Otherwise, the default group name was already set to
1244 "None" in globals_of_w32. */
1245 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1246 gname
, &glength
, NULL
, &dlength
,
1248 strcpy (dflt_group_name
, gname
);
1251 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1254 /* If security calls are not supported (presumably because we
1255 are running under Windows 9X), fallback to this: */
1256 else if (GetUserName (uname
, &ulength
))
1258 strcpy (dflt_passwd
.pw_name
, uname
);
1259 if (xstrcasecmp ("administrator", uname
) == 0)
1260 dflt_passwd
.pw_uid
= 0;
1262 dflt_passwd
.pw_uid
= 123;
1263 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1267 strcpy (dflt_passwd
.pw_name
, "unknown");
1268 dflt_passwd
.pw_uid
= 123;
1269 dflt_passwd
.pw_gid
= 123;
1271 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1273 /* Ensure HOME and SHELL are defined. */
1274 if (getenv ("HOME") == NULL
)
1276 if (getenv ("SHELL") == NULL
)
1279 /* Set dir and shell from environment variables. */
1280 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1281 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1285 CloseHandle (token
);
1291 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1292 return ((rand () << 15) | rand ());
1302 /* Normalize filename by converting all path separators to
1303 the specified separator. Also conditionally convert upper
1304 case path name components to lower case. */
1307 normalize_filename (register char *fp
, char path_sep
)
1312 /* Always lower-case drive letters a-z, even if the filesystem
1313 preserves case in filenames.
1314 This is so filenames can be compared by string comparison
1315 functions that are case-sensitive. Even case-preserving filesystems
1316 do not distinguish case in drive letters. */
1317 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
1323 if (NILP (Vw32_downcase_file_names
))
1327 if (*fp
== '/' || *fp
== '\\')
1334 sep
= path_sep
; /* convert to this path separator */
1335 elem
= fp
; /* start of current path element */
1338 if (*fp
>= 'a' && *fp
<= 'z')
1339 elem
= 0; /* don't convert this element */
1341 if (*fp
== 0 || *fp
== ':')
1343 sep
= *fp
; /* restore current separator (or 0) */
1344 *fp
= '/'; /* after conversion of this element */
1347 if (*fp
== '/' || *fp
== '\\')
1349 if (elem
&& elem
!= fp
)
1351 *fp
= 0; /* temporary end of string */
1352 _strlwr (elem
); /* while we convert to lower case */
1354 *fp
= sep
; /* convert (or restore) path separator */
1355 elem
= fp
+ 1; /* next element starts after separator */
1361 /* Destructively turn backslashes into slashes. */
1363 dostounix_filename (register char *p
)
1365 normalize_filename (p
, '/');
1368 /* Destructively turn slashes into backslashes. */
1370 unixtodos_filename (register char *p
)
1372 normalize_filename (p
, '\\');
1375 /* Remove all CR's that are followed by a LF.
1376 (From msdos.c...probably should figure out a way to share it,
1377 although this code isn't going to ever change.) */
1379 crlf_to_lf (register int n
, register unsigned char *buf
)
1381 unsigned char *np
= buf
;
1382 unsigned char *startp
= buf
;
1383 unsigned char *endp
= buf
+ n
;
1387 while (buf
< endp
- 1)
1391 if (*(++buf
) != 0x0a)
1402 /* Parse the root part of file name, if present. Return length and
1403 optionally store pointer to char after root. */
1405 parse_root (char * name
, char ** pPath
)
1407 char * start
= name
;
1412 /* find the root name of the volume if given */
1413 if (isalpha (name
[0]) && name
[1] == ':')
1415 /* skip past drive specifier */
1417 if (IS_DIRECTORY_SEP (name
[0]))
1420 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1426 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1431 if (IS_DIRECTORY_SEP (name
[0]))
1438 return name
- start
;
1441 /* Get long base name for name; name is assumed to be absolute. */
1443 get_long_basename (char * name
, char * buf
, int size
)
1445 WIN32_FIND_DATA find_data
;
1449 /* must be valid filename, no wild cards or other invalid characters */
1450 if (_mbspbrk (name
, "*?|<>\""))
1453 dir_handle
= FindFirstFile (name
, &find_data
);
1454 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1456 if ((len
= strlen (find_data
.cFileName
)) < size
)
1457 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1460 FindClose (dir_handle
);
1465 /* Get long name for file, if possible (assumed to be absolute). */
1467 w32_get_long_filename (char * name
, char * buf
, int size
)
1472 char full
[ MAX_PATH
];
1475 len
= strlen (name
);
1476 if (len
>= MAX_PATH
)
1479 /* Use local copy for destructive modification. */
1480 memcpy (full
, name
, len
+1);
1481 unixtodos_filename (full
);
1483 /* Copy root part verbatim. */
1484 len
= parse_root (full
, &p
);
1485 memcpy (o
, full
, len
);
1490 while (p
!= NULL
&& *p
)
1493 p
= strchr (q
, '\\');
1495 len
= get_long_basename (full
, o
, size
);
1518 is_unc_volume (const char *filename
)
1520 const char *ptr
= filename
;
1522 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1525 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1531 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1533 sigemptyset (sigset_t
*set
)
1540 sigaddset (sigset_t
*set
, int signo
)
1546 sigfillset (sigset_t
*set
)
1552 sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1558 pthread_sigmask (int how
, const sigset_t
*set
, sigset_t
*oset
)
1560 if (sigprocmask (how
, set
, oset
) == -1)
1566 setpgrp (int pid
, int gid
)
1577 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1580 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1583 HKEY hrootkey
= NULL
;
1586 /* Check both the current user and the local machine to see if
1587 we have any resources. */
1589 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1593 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1594 && (lpvalue
= xmalloc (cbData
)) != NULL
1595 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1597 RegCloseKey (hrootkey
);
1603 RegCloseKey (hrootkey
);
1606 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1610 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1611 && (lpvalue
= xmalloc (cbData
)) != NULL
1612 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1614 RegCloseKey (hrootkey
);
1620 RegCloseKey (hrootkey
);
1626 char *get_emacs_configuration (void);
1629 init_environment (char ** argv
)
1631 static const char * const tempdirs
[] = {
1632 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1637 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1639 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1640 temporary files and assume "/tmp" if $TMPDIR is unset, which
1641 will break on DOS/Windows. Refuse to work if we cannot find
1642 a directory, not even "c:/", usable for that purpose. */
1643 for (i
= 0; i
< imax
; i
++)
1645 const char *tmp
= tempdirs
[i
];
1648 tmp
= getenv (tmp
+ 1);
1649 /* Note that `access' can lie to us if the directory resides on a
1650 read-only filesystem, like CD-ROM or a write-protected floppy.
1651 The only way to be really sure is to actually create a file and
1652 see if it succeeds. But I think that's too much to ask. */
1654 /* MSVCRT's _access crashes with D_OK. */
1655 if (tmp
&& sys_access (tmp
, D_OK
) == 0)
1657 char * var
= alloca (strlen (tmp
) + 8);
1658 sprintf (var
, "TMPDIR=%s", tmp
);
1659 _putenv (strdup (var
));
1666 Fcons (build_string ("no usable temporary directories found!!"),
1668 "While setting TMPDIR: ");
1670 /* Check for environment variables and use registry settings if they
1671 don't exist. Fallback on default values where applicable. */
1676 char locale_name
[32];
1677 struct stat ignored
;
1678 char default_home
[MAX_PATH
];
1681 static const struct env_entry
1687 /* If the default value is NULL, we will use the value from the
1688 outside environment or the Registry, but will not push the
1689 variable into the Emacs environment if it is defined neither
1690 in the Registry nor in the outside environment. */
1692 {"PRELOAD_WINSOCK", NULL
},
1693 {"emacs_dir", "C:/emacs"},
1694 {"EMACSLOADPATH", NULL
},
1695 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1696 {"EMACSDATA", NULL
},
1697 {"EMACSPATH", NULL
},
1704 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1706 /* We need to copy dflt_envvars[] and work on the copy because we
1707 don't want the dumped Emacs to inherit the values of
1708 environment variables we saw during dumping (which could be on
1709 a different system). The defaults above must be left intact. */
1710 struct env_entry env_vars
[N_ENV_VARS
];
1712 for (i
= 0; i
< N_ENV_VARS
; i
++)
1713 env_vars
[i
] = dflt_envvars
[i
];
1715 /* For backwards compatibility, check if a .emacs file exists in C:/
1716 If not, then we can try to default to the appdata directory under the
1717 user's profile, which is more likely to be writable. */
1718 if (stat ("C:/.emacs", &ignored
) < 0)
1720 HRESULT profile_result
;
1721 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1722 of Windows 95 and NT4 that have not been updated to include
1724 ShGetFolderPath_fn get_folder_path
;
1725 get_folder_path
= (ShGetFolderPath_fn
)
1726 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1728 if (get_folder_path
!= NULL
)
1730 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1733 /* If we can't get the appdata dir, revert to old behavior. */
1734 if (profile_result
== S_OK
)
1736 env_vars
[0].def_value
= default_home
;
1742 /* Get default locale info and use it for LANG. */
1743 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1744 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1745 locale_name
, sizeof (locale_name
)))
1747 for (i
= 0; i
< N_ENV_VARS
; i
++)
1749 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1751 env_vars
[i
].def_value
= locale_name
;
1757 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1759 /* Treat emacs_dir specially: set it unconditionally based on our
1763 char modname
[MAX_PATH
];
1765 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1767 if ((p
= strrchr (modname
, '\\')) == NULL
)
1771 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1773 char buf
[SET_ENV_BUF_SIZE
];
1776 for (p
= modname
; *p
; p
++)
1777 if (*p
== '\\') *p
= '/';
1779 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1780 _putenv (strdup (buf
));
1782 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1784 /* FIXME: should use substring of get_emacs_configuration ().
1785 But I don't think the Windows build supports alpha, mips etc
1786 anymore, so have taken the easy option for now. */
1787 else if (p
&& xstrcasecmp (p
, "\\i386") == 0)
1790 p
= strrchr (modname
, '\\');
1794 p
= strrchr (modname
, '\\');
1795 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1797 char buf
[SET_ENV_BUF_SIZE
];
1800 for (p
= modname
; *p
; p
++)
1801 if (*p
== '\\') *p
= '/';
1803 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
1804 _putenv (strdup (buf
));
1810 for (i
= 0; i
< N_ENV_VARS
; i
++)
1812 if (!getenv (env_vars
[i
].name
))
1816 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1817 /* Also ignore empty environment variables. */
1821 lpval
= env_vars
[i
].def_value
;
1822 dwType
= REG_EXPAND_SZ
;
1824 if (!strcmp (env_vars
[i
].name
, "HOME") && !appdata
)
1825 Vdelayed_warnings_list
1826 = Fcons (listn (CONSTYPE_HEAP
, 2,
1827 intern ("initialization"),
1828 build_string ("Setting HOME to C:\\ by default is deprecated")),
1829 Vdelayed_warnings_list
);
1834 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1836 if (dwType
== REG_EXPAND_SZ
)
1837 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
1838 else if (dwType
== REG_SZ
)
1839 strcpy (buf1
, lpval
);
1840 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1842 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
1844 _putenv (strdup (buf2
));
1854 /* Rebuild system configuration to reflect invoking system. */
1855 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1857 /* Another special case: on NT, the PATH variable is actually named
1858 "Path" although cmd.exe (perhaps NT itself) arranges for
1859 environment variable lookup and setting to be case insensitive.
1860 However, Emacs assumes a fully case sensitive environment, so we
1861 need to change "Path" to "PATH" to match the expectations of
1862 various elisp packages. We do this by the sneaky method of
1863 modifying the string in the C runtime environ entry.
1865 The same applies to COMSPEC. */
1869 for (envp
= environ
; *envp
; envp
++)
1870 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1871 memcpy (*envp
, "PATH=", 5);
1872 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1873 memcpy (*envp
, "COMSPEC=", 8);
1876 /* Remember the initial working directory for getwd. */
1877 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
1878 Does it matter anywhere in Emacs? */
1879 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1883 static char modname
[MAX_PATH
];
1885 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1890 /* Determine if there is a middle mouse button, to allow parse_button
1891 to decide whether right mouse events should be mouse-2 or
1893 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1898 /* Called from expand-file-name when default-directory is not a string. */
1901 emacs_root_dir (void)
1903 static char root_dir
[FILENAME_MAX
];
1906 p
= getenv ("emacs_dir");
1909 strcpy (root_dir
, p
);
1910 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1911 dostounix_filename (root_dir
);
1915 /* We don't have scripts to automatically determine the system configuration
1916 for Emacs before it's compiled, and we don't want to have to make the
1917 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1921 get_emacs_configuration (void)
1923 char *arch
, *oem
, *os
;
1925 static char configuration_buffer
[32];
1927 /* Determine the processor type. */
1928 switch (get_processor_type ())
1931 #ifdef PROCESSOR_INTEL_386
1932 case PROCESSOR_INTEL_386
:
1933 case PROCESSOR_INTEL_486
:
1934 case PROCESSOR_INTEL_PENTIUM
:
1939 #ifdef PROCESSOR_MIPS_R2000
1940 case PROCESSOR_MIPS_R2000
:
1941 case PROCESSOR_MIPS_R3000
:
1942 case PROCESSOR_MIPS_R4000
:
1947 #ifdef PROCESSOR_ALPHA_21064
1948 case PROCESSOR_ALPHA_21064
:
1958 /* Use the OEM field to reflect the compiler/library combination. */
1960 #define COMPILER_NAME "msvc"
1963 #define COMPILER_NAME "mingw"
1965 #define COMPILER_NAME "unknown"
1968 oem
= COMPILER_NAME
;
1970 switch (osinfo_cache
.dwPlatformId
) {
1971 case VER_PLATFORM_WIN32_NT
:
1973 build_num
= osinfo_cache
.dwBuildNumber
;
1975 case VER_PLATFORM_WIN32_WINDOWS
:
1976 if (osinfo_cache
.dwMinorVersion
== 0) {
1981 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1983 case VER_PLATFORM_WIN32s
:
1984 /* Not supported, should not happen. */
1986 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1994 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1995 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1996 get_w32_major_version (), get_w32_minor_version (), build_num
);
1998 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
2001 return configuration_buffer
;
2005 get_emacs_configuration_options (void)
2007 static char *options_buffer
;
2008 char cv
[32]; /* Enough for COMPILER_VERSION. */
2010 cv
, /* To be filled later. */
2014 #ifdef ENABLE_CHECKING
2015 " --enable-checking",
2017 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2018 with a starting space to save work here. */
2020 " --cflags", USER_CFLAGS
,
2023 " --ldflags", USER_LDFLAGS
,
2030 /* Work out the effective configure options for this build. */
2032 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2035 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2037 #define COMPILER_VERSION ""
2041 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
2042 return "Error: not enough space for compiler version";
2043 cv
[sizeof (cv
) - 1] = '\0';
2045 for (i
= 0; options
[i
]; i
++)
2046 size
+= strlen (options
[i
]);
2048 options_buffer
= xmalloc (size
+ 1);
2049 options_buffer
[0] = '\0';
2051 for (i
= 0; options
[i
]; i
++)
2052 strcat (options_buffer
, options
[i
]);
2054 return options_buffer
;
2058 #include <sys/timeb.h>
2060 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2062 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
2067 tv
->tv_sec
= tb
.time
;
2068 tv
->tv_usec
= tb
.millitm
* 1000L;
2069 /* Implementation note: _ftime sometimes doesn't update the dstflag
2070 according to the new timezone when the system timezone is
2071 changed. We could fix that by using GetSystemTime and
2072 GetTimeZoneInformation, but that doesn't seem necessary, since
2073 Emacs always calls gettimeofday with the 2nd argument NULL (see
2074 current_emacs_time). */
2077 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
2078 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
2082 /* Emulate fdutimens. */
2084 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2085 TIMESPEC[0] and TIMESPEC[1], respectively.
2086 FD must be either negative -- in which case it is ignored --
2087 or a file descriptor that is open on FILE.
2088 If FD is nonnegative, then FILE can be NULL, which means
2089 use just futimes instead of utimes.
2090 If TIMESPEC is null, FAIL.
2091 Return 0 on success, -1 (setting errno) on failure. */
2094 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
2103 if (fd
< 0 && !file
)
2108 ut
.actime
= timespec
[0].tv_sec
;
2109 ut
.modtime
= timespec
[1].tv_sec
;
2111 return _futime (fd
, &ut
);
2113 return _utime (file
, &ut
);
2117 /* ------------------------------------------------------------------------- */
2118 /* IO support and wrapper functions for the Windows API. */
2119 /* ------------------------------------------------------------------------- */
2121 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2122 on network directories, so we handle that case here.
2123 (Ulrich Leodolter, 1/11/95). */
2125 sys_ctime (const time_t *t
)
2127 char *str
= (char *) ctime (t
);
2128 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2131 /* Emulate sleep...we could have done this with a define, but that
2132 would necessitate including windows.h in the files that used it.
2133 This is much easier. */
2135 sys_sleep (int seconds
)
2137 Sleep (seconds
* 1000);
2140 /* Internal MSVC functions for low-level descriptor munging */
2141 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2142 extern int __cdecl
_free_osfhnd (int fd
);
2144 /* parallel array of private info on file handles */
2145 filedesc fd_info
[ MAXDESC
];
2147 typedef struct volume_info_data
{
2148 struct volume_info_data
* next
;
2150 /* time when info was obtained */
2153 /* actual volume info */
2162 /* Global referenced by various functions. */
2163 static volume_info_data volume_info
;
2165 /* Vector to indicate which drives are local and fixed (for which cached
2166 data never expires). */
2167 static BOOL fixed_drives
[26];
2169 /* Consider cached volume information to be stale if older than 10s,
2170 at least for non-local drives. Info for fixed drives is never stale. */
2171 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2172 #define VOLINFO_STILL_VALID( root_dir, info ) \
2173 ( ( isalpha (root_dir[0]) && \
2174 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2175 || GetTickCount () - info->timestamp < 10000 )
2177 /* Cache support functions. */
2179 /* Simple linked list with linear search is sufficient. */
2180 static volume_info_data
*volume_cache
= NULL
;
2182 static volume_info_data
*
2183 lookup_volume_info (char * root_dir
)
2185 volume_info_data
* info
;
2187 for (info
= volume_cache
; info
; info
= info
->next
)
2188 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2194 add_volume_info (char * root_dir
, volume_info_data
* info
)
2196 info
->root_dir
= xstrdup (root_dir
);
2197 info
->next
= volume_cache
;
2198 volume_cache
= info
;
2202 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2203 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2204 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2205 static volume_info_data
*
2206 GetCachedVolumeInformation (char * root_dir
)
2208 volume_info_data
* info
;
2209 char default_root
[ MAX_PATH
];
2211 /* NULL for root_dir means use root from current directory. */
2212 if (root_dir
== NULL
)
2214 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2216 parse_root (default_root
, &root_dir
);
2218 root_dir
= default_root
;
2221 /* Local fixed drives can be cached permanently. Removable drives
2222 cannot be cached permanently, since the volume name and serial
2223 number (if nothing else) can change. Remote drives should be
2224 treated as if they are removable, since there is no sure way to
2225 tell whether they are or not. Also, the UNC association of drive
2226 letters mapped to remote volumes can be changed at any time (even
2227 by other processes) without notice.
2229 As a compromise, so we can benefit from caching info for remote
2230 volumes, we use a simple expiry mechanism to invalidate cache
2231 entries that are more than ten seconds old. */
2234 /* No point doing this, because WNetGetConnection is even slower than
2235 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2236 GetDriveType is about the only call of this type which does not
2237 involve network access, and so is extremely quick). */
2239 /* Map drive letter to UNC if remote. */
2240 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2242 char remote_name
[ 256 ];
2243 char drive
[3] = { root_dir
[0], ':' };
2245 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2247 /* do something */ ;
2251 info
= lookup_volume_info (root_dir
);
2253 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2261 /* Info is not cached, or is stale. */
2262 if (!GetVolumeInformation (root_dir
,
2263 name
, sizeof (name
),
2267 type
, sizeof (type
)))
2270 /* Cache the volume information for future use, overwriting existing
2271 entry if present. */
2274 info
= xmalloc (sizeof (volume_info_data
));
2275 add_volume_info (root_dir
, info
);
2283 info
->name
= xstrdup (name
);
2284 info
->serialnum
= serialnum
;
2285 info
->maxcomp
= maxcomp
;
2286 info
->flags
= flags
;
2287 info
->type
= xstrdup (type
);
2288 info
->timestamp
= GetTickCount ();
2294 /* Get information on the volume where NAME is held; set path pointer to
2295 start of pathname in NAME (past UNC header\volume header if present),
2296 if pPath is non-NULL.
2298 Note: if NAME includes symlinks, the information is for the volume
2299 of the symlink, not of its target. That's because, even though
2300 GetVolumeInformation returns information about the symlink target
2301 of its argument, we only pass the root directory to
2302 GetVolumeInformation, not the full NAME. */
2304 get_volume_info (const char * name
, const char ** pPath
)
2306 char temp
[MAX_PATH
];
2307 char *rootname
= NULL
; /* default to current volume */
2308 volume_info_data
* info
;
2313 /* Find the root name of the volume if given. */
2314 if (isalpha (name
[0]) && name
[1] == ':')
2322 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2329 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2342 info
= GetCachedVolumeInformation (rootname
);
2345 /* Set global referenced by other functions. */
2346 volume_info
= *info
;
2352 /* Determine if volume is FAT format (ie. only supports short 8.3
2353 names); also set path pointer to start of pathname in name, if
2354 pPath is non-NULL. */
2356 is_fat_volume (const char * name
, const char ** pPath
)
2358 if (get_volume_info (name
, pPath
))
2359 return (volume_info
.maxcomp
== 12);
2363 /* Map filename to a valid 8.3 name if necessary.
2364 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2366 map_w32_filename (const char * name
, const char ** pPath
)
2368 static char shortname
[MAX_PATH
];
2369 char * str
= shortname
;
2372 const char * save_name
= name
;
2374 if (strlen (name
) >= MAX_PATH
)
2376 /* Return a filename which will cause callers to fail. */
2377 strcpy (shortname
, "?");
2381 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2383 register int left
= 8; /* maximum number of chars in part */
2384 register int extn
= 0; /* extension added? */
2385 register int dots
= 2; /* maximum number of dots allowed */
2388 *str
++ = *name
++; /* skip past UNC header */
2390 while ((c
= *name
++))
2397 *str
++ = (c
== ':' ? ':' : '\\');
2398 extn
= 0; /* reset extension flags */
2399 dots
= 2; /* max 2 dots */
2400 left
= 8; /* max length 8 for main part */
2405 /* Convert path components of the form .xxx to _xxx,
2406 but leave . and .. as they are. This allows .emacs
2407 to be read as _emacs, for example. */
2411 IS_DIRECTORY_SEP (*name
))
2426 extn
= 1; /* we've got an extension */
2427 left
= 3; /* 3 chars in extension */
2431 /* any embedded dots after the first are converted to _ */
2436 case '#': /* don't lose these, they're important */
2438 str
[-1] = c
; /* replace last character of part */
2443 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2445 dots
= 0; /* started a path component */
2454 strcpy (shortname
, name
);
2455 unixtodos_filename (shortname
);
2459 *pPath
= shortname
+ (path
- save_name
);
2465 is_exec (const char * name
)
2467 char * p
= strrchr (name
, '.');
2470 && (xstrcasecmp (p
, ".exe") == 0 ||
2471 xstrcasecmp (p
, ".com") == 0 ||
2472 xstrcasecmp (p
, ".bat") == 0 ||
2473 xstrcasecmp (p
, ".cmd") == 0));
2476 /* Emulate the Unix directory procedures opendir, closedir,
2477 and readdir. We can't use the procedures supplied in sysdep.c,
2478 so we provide them here. */
2480 struct direct dir_static
; /* simulated directory contents */
2481 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2482 static int dir_is_fat
;
2483 static char dir_pathname
[MAXPATHLEN
+1];
2484 static WIN32_FIND_DATA dir_find_data
;
2486 /* Support shares on a network resource as subdirectories of a read-only
2488 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2489 static HANDLE
open_unc_volume (const char *);
2490 static char *read_unc_volume (HANDLE
, char *, int);
2491 static void close_unc_volume (HANDLE
);
2494 opendir (char *filename
)
2498 /* Opening is done by FindFirstFile. However, a read is inherent to
2499 this operation, so we defer the open until read time. */
2501 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2503 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2506 /* Note: We don't support traversal of UNC volumes via symlinks.
2507 Doing so would mean punishing 99.99% of use cases by resolving
2508 all the possible symlinks in FILENAME, recursively. */
2509 if (is_unc_volume (filename
))
2511 wnet_enum_handle
= open_unc_volume (filename
);
2512 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2516 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2523 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2524 dir_pathname
[MAXPATHLEN
] = '\0';
2525 /* Note: We don't support symlinks to file names on FAT volumes.
2526 Doing so would mean punishing 99.99% of use cases by resolving
2527 all the possible symlinks in FILENAME, recursively. */
2528 dir_is_fat
= is_fat_volume (filename
, NULL
);
2534 closedir (DIR *dirp
)
2536 /* If we have a find-handle open, close it. */
2537 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2539 FindClose (dir_find_handle
);
2540 dir_find_handle
= INVALID_HANDLE_VALUE
;
2542 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2544 close_unc_volume (wnet_enum_handle
);
2545 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2547 xfree ((char *) dirp
);
2553 int downcase
= !NILP (Vw32_downcase_file_names
);
2555 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2557 if (!read_unc_volume (wnet_enum_handle
,
2558 dir_find_data
.cFileName
,
2562 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2563 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2565 char filename
[MAXNAMLEN
+ 3];
2568 strcpy (filename
, dir_pathname
);
2569 ln
= strlen (filename
) - 1;
2570 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2571 strcat (filename
, "\\");
2572 strcat (filename
, "*");
2574 /* Note: No need to resolve symlinks in FILENAME, because
2575 FindFirst opens the directory that is the target of a
2577 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2579 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2584 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2588 /* Emacs never uses this value, so don't bother making it match
2589 value returned by stat(). */
2590 dir_static
.d_ino
= 1;
2592 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2594 /* If the file name in cFileName[] includes `?' characters, it means
2595 the original file name used characters that cannot be represented
2596 by the current ANSI codepage. To avoid total lossage, retrieve
2597 the short 8+3 alias of the long file name. */
2598 if (_mbspbrk (dir_static
.d_name
, "?"))
2600 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2601 downcase
= 1; /* 8+3 aliases are returned in all caps */
2603 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2604 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2605 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2607 /* If the file name in cFileName[] includes `?' characters, it means
2608 the original file name used characters that cannot be represented
2609 by the current ANSI codepage. To avoid total lossage, retrieve
2610 the short 8+3 alias of the long file name. */
2611 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2613 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2614 /* 8+3 aliases are returned in all caps, which could break
2615 various alists that look at filenames' extensions. */
2619 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2620 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2622 _strlwr (dir_static
.d_name
);
2626 for (p
= dir_static
.d_name
; *p
; p
++)
2627 if (*p
>= 'a' && *p
<= 'z')
2630 _strlwr (dir_static
.d_name
);
2637 open_unc_volume (const char *path
)
2643 nr
.dwScope
= RESOURCE_GLOBALNET
;
2644 nr
.dwType
= RESOURCETYPE_DISK
;
2645 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2646 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2647 nr
.lpLocalName
= NULL
;
2648 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2649 nr
.lpComment
= NULL
;
2650 nr
.lpProvider
= NULL
;
2652 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2653 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2655 if (result
== NO_ERROR
)
2658 return INVALID_HANDLE_VALUE
;
2662 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2666 DWORD bufsize
= 512;
2671 buffer
= alloca (bufsize
);
2672 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
2673 if (result
!= NO_ERROR
)
2676 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2677 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2679 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2682 strncpy (readbuf
, ptr
, size
);
2687 close_unc_volume (HANDLE henum
)
2689 if (henum
!= INVALID_HANDLE_VALUE
)
2690 WNetCloseEnum (henum
);
2694 unc_volume_file_attributes (const char *path
)
2699 henum
= open_unc_volume (path
);
2700 if (henum
== INVALID_HANDLE_VALUE
)
2703 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2705 close_unc_volume (henum
);
2710 /* Ensure a network connection is authenticated. */
2712 logon_network_drive (const char *path
)
2714 NETRESOURCE resource
;
2715 char share
[MAX_PATH
];
2720 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
2721 drvtype
= DRIVE_REMOTE
;
2722 else if (path
[0] == '\0' || path
[1] != ':')
2723 drvtype
= GetDriveType (NULL
);
2730 drvtype
= GetDriveType (drive
);
2733 /* Only logon to networked drives. */
2734 if (drvtype
!= DRIVE_REMOTE
)
2738 strncpy (share
, path
, MAX_PATH
);
2739 /* Truncate to just server and share name. */
2740 for (i
= 2; i
< MAX_PATH
; i
++)
2742 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2749 resource
.dwType
= RESOURCETYPE_DISK
;
2750 resource
.lpLocalName
= NULL
;
2751 resource
.lpRemoteName
= share
;
2752 resource
.lpProvider
= NULL
;
2754 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2757 /* Shadow some MSVC runtime functions to map requests for long filenames
2758 to reasonable short names if necessary. This was originally added to
2759 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2763 sys_access (const char * path
, int mode
)
2767 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
2768 newer versions blow up when passed D_OK. */
2769 path
= map_w32_filename (path
, NULL
);
2770 /* If the last element of PATH is a symlink, we need to resolve it
2771 to get the attributes of its target file. Note: any symlinks in
2772 PATH elements other than the last one are transparently resolved
2773 by GetFileAttributes below. */
2774 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
2775 path
= chase_symlinks (path
);
2777 if ((attributes
= GetFileAttributes (path
)) == -1)
2779 DWORD w32err
= GetLastError ();
2783 case ERROR_INVALID_NAME
:
2784 case ERROR_BAD_PATHNAME
:
2785 if (is_unc_volume (path
))
2787 attributes
= unc_volume_file_attributes (path
);
2788 if (attributes
== -1)
2796 case ERROR_FILE_NOT_FOUND
:
2797 case ERROR_BAD_NETPATH
:
2806 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2811 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2816 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2825 sys_chdir (const char * path
)
2827 return _chdir (map_w32_filename (path
, NULL
));
2831 sys_chmod (const char * path
, int mode
)
2833 path
= chase_symlinks (map_w32_filename (path
, NULL
));
2834 return _chmod (path
, mode
);
2838 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2840 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2846 sys_creat (const char * path
, int mode
)
2848 return _creat (map_w32_filename (path
, NULL
), mode
);
2852 sys_fopen (const char * path
, const char * mode
)
2856 const char * mode_save
= mode
;
2858 /* Force all file handles to be non-inheritable. This is necessary to
2859 ensure child processes don't unwittingly inherit handles that might
2860 prevent future file access. */
2864 else if (mode
[0] == 'w' || mode
[0] == 'a')
2865 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2869 /* Only do simplistic option parsing. */
2873 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2876 else if (mode
[0] == 'b')
2881 else if (mode
[0] == 't')
2888 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2892 return _fdopen (fd
, mode_save
);
2895 /* This only works on NTFS volumes, but is useful to have. */
2897 sys_link (const char * old
, const char * new)
2901 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2903 if (old
== NULL
|| new == NULL
)
2909 strcpy (oldname
, map_w32_filename (old
, NULL
));
2910 strcpy (newname
, map_w32_filename (new, NULL
));
2912 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2913 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2914 if (fileh
!= INVALID_HANDLE_VALUE
)
2918 /* Confusingly, the "alternate" stream name field does not apply
2919 when restoring a hard link, and instead contains the actual
2920 stream data for the link (ie. the name of the link to create).
2921 The WIN32_STREAM_ID structure before the cStreamName field is
2922 the stream header, which is then immediately followed by the
2926 WIN32_STREAM_ID wid
;
2927 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2930 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2931 data
.wid
.cStreamName
, MAX_PATH
);
2934 LPVOID context
= NULL
;
2937 data
.wid
.dwStreamId
= BACKUP_LINK
;
2938 data
.wid
.dwStreamAttributes
= 0;
2939 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
2940 data
.wid
.Size
.HighPart
= 0;
2941 data
.wid
.dwStreamNameSize
= 0;
2943 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2944 offsetof (WIN32_STREAM_ID
, cStreamName
)
2945 + data
.wid
.Size
.LowPart
,
2946 &wbytes
, FALSE
, FALSE
, &context
)
2947 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2954 /* Should try mapping GetLastError to errno; for now just
2955 indicate a general error (eg. links not supported). */
2956 errno
= EINVAL
; // perhaps EMLINK?
2960 CloseHandle (fileh
);
2969 sys_mkdir (const char * path
)
2971 return _mkdir (map_w32_filename (path
, NULL
));
2974 /* Because of long name mapping issues, we need to implement this
2975 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2976 a unique name, instead of setting the input template to an empty
2979 Standard algorithm seems to be use pid or tid with a letter on the
2980 front (in place of the 6 X's) and cycle through the letters to find a
2981 unique name. We extend that to allow any reasonable character as the
2982 first of the 6 X's. */
2984 sys_mktemp (char * template)
2988 unsigned uid
= GetCurrentThreadId ();
2989 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2991 if (template == NULL
)
2993 p
= template + strlen (template);
2995 /* replace up to the last 5 X's with uid in decimal */
2996 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2998 p
[0] = '0' + uid
% 10;
3002 if (i
< 0 && p
[0] == 'X')
3007 int save_errno
= errno
;
3008 p
[0] = first_char
[i
];
3009 if (sys_access (template, 0) < 0)
3015 while (++i
< sizeof (first_char
));
3018 /* Template is badly formed or else we can't generate a unique name,
3019 so return empty string */
3025 sys_open (const char * path
, int oflag
, int mode
)
3027 const char* mpath
= map_w32_filename (path
, NULL
);
3028 /* Try to open file without _O_CREAT, to be able to write to hidden
3029 and system files. Force all file handles to be
3031 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3034 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
3038 sys_rename (const char * oldname
, const char * newname
)
3041 char temp
[MAX_PATH
];
3045 /* MoveFile on Windows 95 doesn't correctly change the short file name
3046 alias in a number of circumstances (it is not easy to predict when
3047 just by looking at oldname and newname, unfortunately). In these
3048 cases, renaming through a temporary name avoids the problem.
3050 A second problem on Windows 95 is that renaming through a temp name when
3051 newname is uppercase fails (the final long name ends up in
3052 lowercase, although the short alias might be uppercase) UNLESS the
3053 long temp name is not 8.3.
3055 So, on Windows 95 we always rename through a temp name, and we make sure
3056 the temp name has a long extension to ensure correct renaming. */
3058 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3060 /* volume_info is set indirectly by map_w32_filename. */
3061 oldname_dev
= volume_info
.serialnum
;
3063 if (os_subtype
== OS_9X
)
3069 oldname
= map_w32_filename (oldname
, NULL
);
3070 if ((o
= strrchr (oldname
, '\\')))
3073 o
= (char *) oldname
;
3075 if ((p
= strrchr (temp
, '\\')))
3082 /* Force temp name to require a manufactured 8.3 alias - this
3083 seems to make the second rename work properly. */
3084 sprintf (p
, "_.%s.%u", o
, i
);
3086 result
= rename (oldname
, temp
);
3088 /* This loop must surely terminate! */
3089 while (result
< 0 && errno
== EEXIST
);
3094 /* Emulate Unix behavior - newname is deleted if it already exists
3095 (at least if it is a file; don't do this for directories).
3097 Since we mustn't do this if we are just changing the case of the
3098 file name (we would end up deleting the file we are trying to
3099 rename!), we let rename detect if the destination file already
3100 exists - that way we avoid the possible pitfalls of trying to
3101 determine ourselves whether two names really refer to the same
3102 file, which is not always possible in the general case. (Consider
3103 all the permutations of shared or subst'd drives, etc.) */
3105 newname
= map_w32_filename (newname
, NULL
);
3107 /* volume_info is set indirectly by map_w32_filename. */
3108 newname_dev
= volume_info
.serialnum
;
3110 result
= rename (temp
, newname
);
3114 DWORD w32err
= GetLastError ();
3117 && newname_dev
!= oldname_dev
)
3119 /* The implementation of `rename' on Windows does not return
3120 errno = EXDEV when you are moving a directory to a
3121 different storage device (ex. logical disk). It returns
3122 EACCES instead. So here we handle such situations and
3126 if ((attributes
= GetFileAttributes (temp
)) != -1
3127 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3130 else if (errno
== EEXIST
)
3132 if (_chmod (newname
, 0666) != 0)
3134 if (_unlink (newname
) != 0)
3136 result
= rename (temp
, newname
);
3138 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
3139 && is_symlink (temp
))
3141 /* This is Windows prohibiting the user from creating a
3142 symlink in another place, since that requires
3152 sys_rmdir (const char * path
)
3154 return _rmdir (map_w32_filename (path
, NULL
));
3158 sys_unlink (const char * path
)
3160 path
= map_w32_filename (path
, NULL
);
3162 /* On Unix, unlink works without write permission. */
3163 _chmod (path
, 0666);
3164 return _unlink (path
);
3167 static FILETIME utc_base_ft
;
3168 static ULONGLONG utc_base
; /* In 100ns units */
3169 static int init
= 0;
3171 #define FILETIME_TO_U64(result, ft) \
3173 ULARGE_INTEGER uiTemp; \
3174 uiTemp.LowPart = (ft).dwLowDateTime; \
3175 uiTemp.HighPart = (ft).dwHighDateTime; \
3176 result = uiTemp.QuadPart; \
3180 initialize_utc_base (void)
3182 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3191 st
.wMilliseconds
= 0;
3193 SystemTimeToFileTime (&st
, &utc_base_ft
);
3194 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3198 convert_time (FILETIME ft
)
3204 initialize_utc_base ();
3208 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3211 FILETIME_TO_U64 (tmp
, ft
);
3212 return (time_t) ((tmp
- utc_base
) / 10000000L);
3216 convert_from_time_t (time_t time
, FILETIME
* pft
)
3222 initialize_utc_base ();
3226 /* time in 100ns units since 1-Jan-1601 */
3227 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3228 pft
->dwHighDateTime
= tmp
.HighPart
;
3229 pft
->dwLowDateTime
= tmp
.LowPart
;
3233 /* No reason to keep this; faking inode values either by hashing or even
3234 using the file index from GetInformationByHandle, is not perfect and
3235 so by default Emacs doesn't use the inode values on Windows.
3236 Instead, we now determine file-truename correctly (except for
3237 possible drive aliasing etc). */
3239 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3241 hashval (const unsigned char * str
)
3246 h
= (h
<< 4) + *str
++;
3252 /* Return the hash value of the canonical pathname, excluding the
3253 drive/UNC header, to get a hopefully unique inode number. */
3255 generate_inode_val (const char * name
)
3257 char fullname
[ MAX_PATH
];
3261 /* Get the truly canonical filename, if it exists. (Note: this
3262 doesn't resolve aliasing due to subst commands, or recognize hard
3264 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3267 parse_root (fullname
, &p
);
3268 /* Normal W32 filesystems are still case insensitive. */
3275 static PSECURITY_DESCRIPTOR
3276 get_file_security_desc_by_handle (HANDLE h
)
3278 PSECURITY_DESCRIPTOR psd
= NULL
;
3280 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3281 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3283 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
3284 NULL
, NULL
, NULL
, NULL
, &psd
);
3285 if (err
!= ERROR_SUCCESS
)
3291 static PSECURITY_DESCRIPTOR
3292 get_file_security_desc_by_name (const char *fname
)
3294 PSECURITY_DESCRIPTOR psd
= NULL
;
3296 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3297 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3299 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3301 err
= GetLastError ();
3302 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3306 psd
= xmalloc (sd_len
);
3307 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3319 unsigned n_subauthorities
;
3321 /* Use the last sub-authority value of the RID, the relative
3322 portion of the SID, as user/group ID. */
3323 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3324 if (n_subauthorities
< 1)
3325 return 0; /* the "World" RID */
3326 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3329 /* Caching SID and account values for faster lokup. */
3332 # define FLEXIBLE_ARRAY_MEMBER
3334 # define FLEXIBLE_ARRAY_MEMBER 1
3339 struct w32_id
*next
;
3341 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3344 static struct w32_id
*w32_idlist
;
3347 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3349 struct w32_id
*tail
, *found
;
3351 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3353 if (equal_sid ((PSID
)tail
->sid
, sid
))
3362 strcpy (name
, found
->name
);
3370 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3373 struct w32_id
*new_entry
;
3375 /* We don't want to leave behind stale cache from when Emacs was
3379 sid_len
= get_length_sid (sid
);
3380 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3383 new_entry
->rid
= id
;
3384 strcpy (new_entry
->name
, name
);
3385 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3386 new_entry
->next
= w32_idlist
;
3387 w32_idlist
= new_entry
;
3396 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
3397 unsigned *id
, char *nm
, int what
)
3400 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
3402 SID_NAME_USE ignore
;
3404 DWORD name_len
= sizeof (name
);
3406 DWORD domain_len
= sizeof (domain
);
3412 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3413 else if (what
== GID
)
3414 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3418 if (!result
|| !is_valid_sid (sid
))
3420 else if (!w32_cached_id (sid
, id
, nm
))
3422 /* If FNAME is a UNC, we need to lookup account on the
3423 specified machine. */
3424 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
3425 && fname
[2] != '\0')
3430 for (s
= fname
+ 2, p
= machine
;
3431 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
3437 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
3438 domain
, &domain_len
, &ignore
)
3439 || name_len
> UNLEN
+1)
3443 *id
= get_rid (sid
);
3445 w32_add_to_cache (sid
, *id
, name
);
3452 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
,
3456 int dflt_usr
= 0, dflt_grp
= 0;
3465 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
3467 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
3470 /* Consider files to belong to current user/group, if we cannot get
3471 more accurate information. */
3474 st
->st_uid
= dflt_passwd
.pw_uid
;
3475 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3479 st
->st_gid
= dflt_passwd
.pw_gid
;
3480 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3484 /* Return non-zero if NAME is a potentially slow filesystem. */
3486 is_slow_fs (const char *name
)
3491 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3492 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3493 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3494 devtype
= GetDriveType (NULL
); /* use root of current drive */
3497 /* GetDriveType needs the root directory of the drive. */
3498 strncpy (drive_root
, name
, 2);
3499 drive_root
[2] = '\\';
3500 drive_root
[3] = '\0';
3501 devtype
= GetDriveType (drive_root
);
3503 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3506 /* MSVC stat function can't cope with UNC names and has other bugs, so
3507 replace it with our own. This also allows us to calculate consistent
3508 inode values and owner/group without hacks in the main Emacs code. */
3511 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
3513 char *name
, *save_name
, *r
;
3514 WIN32_FIND_DATA wfd
;
3516 unsigned __int64 fake_inode
= 0;
3519 int rootdir
= FALSE
;
3520 PSECURITY_DESCRIPTOR psd
= NULL
;
3521 int is_a_symlink
= 0;
3522 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
3523 DWORD access_rights
= 0;
3524 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
3525 FILETIME ctime
, atime
, wtime
;
3527 if (path
== NULL
|| buf
== NULL
)
3533 save_name
= name
= (char *) map_w32_filename (path
, &path
);
3534 /* Must be valid filename, no wild cards or other invalid
3535 characters. We use _mbspbrk to support multibyte strings that
3536 might look to strpbrk as if they included literal *, ?, and other
3537 characters mentioned below that are disallowed by Windows
3539 if (_mbspbrk (name
, "*?|<>\""))
3545 /* Remove trailing directory separator, unless name is the root
3546 directory of a drive or UNC volume in which case ensure there
3547 is a trailing separator. */
3548 len
= strlen (name
);
3549 name
= strcpy (alloca (len
+ 2), name
);
3551 /* Avoid a somewhat costly call to is_symlink if the filesystem
3552 doesn't support symlinks. */
3553 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
3554 is_a_symlink
= is_symlink (name
);
3556 /* Plan A: Open the file and get all the necessary information via
3557 the resulting handle. This solves several issues in one blow:
3559 . retrieves attributes for the target of a symlink, if needed
3560 . gets attributes of root directories and symlinks pointing to
3561 root directories, thus avoiding the need for special-casing
3562 these and detecting them by examining the file-name format
3563 . retrieves more accurate attributes (e.g., non-zero size for
3564 some directories, esp. directories that are junction points)
3565 . correctly resolves "c:/..", "/.." and similar file names
3566 . avoids run-time penalties for 99% of use cases
3568 Plan A is always tried first, unless the user asked not to (but
3569 if the file is a symlink and we need to follow links, we try Plan
3570 A even if the user asked not to).
3572 If Plan A fails, we go to Plan B (below), where various
3573 potentially expensive techniques must be used to handle "special"
3574 files such as UNC volumes etc. */
3575 if (!(NILP (Vw32_get_true_file_attributes
)
3576 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3577 /* Following symlinks requires getting the info by handle. */
3578 || (is_a_symlink
&& follow_symlinks
))
3580 BY_HANDLE_FILE_INFORMATION info
;
3582 if (is_a_symlink
&& !follow_symlinks
)
3583 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
3584 /* READ_CONTROL access rights are required to get security info
3585 by handle. But if the OS doesn't support security in the
3586 first place, we don't need to try. */
3587 if (is_windows_9x () != TRUE
)
3588 access_rights
|= READ_CONTROL
;
3590 fh
= CreateFile (name
, access_rights
, 0, NULL
, OPEN_EXISTING
,
3592 /* If CreateFile fails with READ_CONTROL, try again with zero as
3594 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
3595 fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3597 if (fh
== INVALID_HANDLE_VALUE
)
3598 goto no_true_file_attributes
;
3600 /* This is more accurate in terms of getting the correct number
3601 of links, but is quite slow (it is noticeable when Emacs is
3602 making a list of file name completions). */
3603 if (GetFileInformationByHandle (fh
, &info
))
3605 nlinks
= info
.nNumberOfLinks
;
3606 /* Might as well use file index to fake inode values, but this
3607 is not guaranteed to be unique unless we keep a handle open
3608 all the time (even then there are situations where it is
3609 not unique). Reputedly, there are at most 48 bits of info
3610 (on NTFS, presumably less on FAT). */
3611 fake_inode
= info
.nFileIndexHigh
;
3613 fake_inode
+= info
.nFileIndexLow
;
3614 serialnum
= info
.dwVolumeSerialNumber
;
3615 fs_high
= info
.nFileSizeHigh
;
3616 fs_low
= info
.nFileSizeLow
;
3617 ctime
= info
.ftCreationTime
;
3618 atime
= info
.ftLastAccessTime
;
3619 wtime
= info
.ftLastWriteTime
;
3620 fattrs
= info
.dwFileAttributes
;
3624 /* We don't go to Plan B here, because it's not clear that
3625 it's a good idea. The only known use case where
3626 CreateFile succeeds, but GetFileInformationByHandle fails
3627 (with ERROR_INVALID_FUNCTION) is for character devices
3628 such as NUL, PRN, etc. For these, switching to Plan B is
3629 a net loss, because we lose the character device
3630 attribute returned by GetFileType below (FindFirstFile
3631 doesn't set that bit in the attributes), and the other
3632 fields don't make sense for character devices anyway.
3633 Emacs doesn't really care for non-file entities in the
3634 context of l?stat, so neither do we. */
3636 /* w32err is assigned so one could put a breakpoint here and
3637 examine its value, when GetFileInformationByHandle
3639 DWORD w32err
= GetLastError ();
3643 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
3649 /* Test for a symlink before testing for a directory, since
3650 symlinks to directories have the directory bit set, but we
3651 don't want them to appear as directories. */
3652 if (is_a_symlink
&& !follow_symlinks
)
3653 buf
->st_mode
= S_IFLNK
;
3654 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3655 buf
->st_mode
= S_IFDIR
;
3658 DWORD ftype
= GetFileType (fh
);
3662 case FILE_TYPE_DISK
:
3663 buf
->st_mode
= S_IFREG
;
3665 case FILE_TYPE_PIPE
:
3666 buf
->st_mode
= S_IFIFO
;
3668 case FILE_TYPE_CHAR
:
3669 case FILE_TYPE_UNKNOWN
:
3671 buf
->st_mode
= S_IFCHR
;
3674 /* We produce the fallback owner and group data, based on the
3675 current user that runs Emacs, in the following cases:
3677 . this is Windows 9X
3678 . getting security by handle failed, and we need to produce
3679 information for the target of a symlink (this is better
3680 than producing a potentially misleading info about the
3683 If getting security by handle fails, and we don't need to
3684 resolve symlinks, we try getting security by name. */
3685 if (is_windows_9x () != TRUE
)
3686 psd
= get_file_security_desc_by_handle (fh
);
3689 get_file_owner_and_group (psd
, name
, buf
);
3692 else if (is_windows_9x () == TRUE
)
3693 get_file_owner_and_group (NULL
, name
, buf
);
3694 else if (!(is_a_symlink
&& follow_symlinks
))
3696 psd
= get_file_security_desc_by_name (name
);
3697 get_file_owner_and_group (psd
, name
, buf
);
3701 get_file_owner_and_group (NULL
, name
, buf
);
3706 no_true_file_attributes
:
3707 /* Plan B: Either getting a handle on the file failed, or the
3708 caller explicitly asked us to not bother making this
3709 information more accurate.
3711 Implementation note: In Plan B, we never bother to resolve
3712 symlinks, even if we got here because we tried Plan A and
3713 failed. That's because, even if the caller asked for extra
3714 precision by setting Vw32_get_true_file_attributes to t,
3715 resolving symlinks requires acquiring a file handle to the
3716 symlink, which we already know will fail. And if the user
3717 did not ask for extra precision, resolving symlinks will fly
3718 in the face of that request, since the user then wants the
3719 lightweight version of the code. */
3720 rootdir
= (path
>= save_name
+ len
- 1
3721 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
3723 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3724 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
3725 if (IS_DIRECTORY_SEP (r
[0])
3726 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
3729 /* Note: If NAME is a symlink to the root of a UNC volume
3730 (i.e. "\\SERVER"), we will not detect that here, and we will
3731 return data about the symlink as result of FindFirst below.
3732 This is unfortunate, but that marginal use case does not
3733 justify a call to chase_symlinks which would impose a penalty
3734 on all the other use cases. (We get here for symlinks to
3735 roots of UNC volumes because CreateFile above fails for them,
3736 unlike with symlinks to root directories X:\ of drives.) */
3737 if (is_unc_volume (name
))
3739 fattrs
= unc_volume_file_attributes (name
);
3743 ctime
= atime
= wtime
= utc_base_ft
;
3747 if (!IS_DIRECTORY_SEP (name
[len
-1]))
3748 strcat (name
, "\\");
3749 if (GetDriveType (name
) < 2)
3755 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
3756 ctime
= atime
= wtime
= utc_base_ft
;
3760 if (IS_DIRECTORY_SEP (name
[len
-1]))
3763 /* (This is hacky, but helps when doing file completions on
3764 network drives.) Optimize by using information available from
3765 active readdir if possible. */
3766 len
= strlen (dir_pathname
);
3767 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
3769 if (dir_find_handle
!= INVALID_HANDLE_VALUE
3770 && !(is_a_symlink
&& follow_symlinks
)
3771 && strnicmp (save_name
, dir_pathname
, len
) == 0
3772 && IS_DIRECTORY_SEP (name
[len
])
3773 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
3775 /* This was the last entry returned by readdir. */
3776 wfd
= dir_find_data
;
3780 logon_network_drive (name
);
3782 fh
= FindFirstFile (name
, &wfd
);
3783 if (fh
== INVALID_HANDLE_VALUE
)
3790 /* Note: if NAME is a symlink, the information we get from
3791 FindFirstFile is for the symlink, not its target. */
3792 fattrs
= wfd
.dwFileAttributes
;
3793 ctime
= wfd
.ftCreationTime
;
3794 atime
= wfd
.ftLastAccessTime
;
3795 wtime
= wfd
.ftLastWriteTime
;
3796 fs_high
= wfd
.nFileSizeHigh
;
3797 fs_low
= wfd
.nFileSizeLow
;
3800 serialnum
= volume_info
.serialnum
;
3802 if (is_a_symlink
&& !follow_symlinks
)
3803 buf
->st_mode
= S_IFLNK
;
3804 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3805 buf
->st_mode
= S_IFDIR
;
3807 buf
->st_mode
= S_IFREG
;
3809 get_file_owner_and_group (NULL
, name
, buf
);
3813 /* Not sure if there is any point in this. */
3814 if (!NILP (Vw32_generate_fake_inodes
))
3815 fake_inode
= generate_inode_val (name
);
3816 else if (fake_inode
== 0)
3818 /* For want of something better, try to make everything unique. */
3819 static DWORD gen_num
= 0;
3820 fake_inode
= ++gen_num
;
3824 buf
->st_ino
= fake_inode
;
3826 buf
->st_dev
= serialnum
;
3827 buf
->st_rdev
= serialnum
;
3829 buf
->st_size
= fs_high
;
3830 buf
->st_size
<<= 32;
3831 buf
->st_size
+= fs_low
;
3832 buf
->st_nlink
= nlinks
;
3834 /* Convert timestamps to Unix format. */
3835 buf
->st_mtime
= convert_time (wtime
);
3836 buf
->st_atime
= convert_time (atime
);
3837 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3838 buf
->st_ctime
= convert_time (ctime
);
3839 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3841 /* determine rwx permissions */
3842 if (is_a_symlink
&& !follow_symlinks
)
3843 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
3846 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
3847 permission
= S_IREAD
;
3849 permission
= S_IREAD
| S_IWRITE
;
3851 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
3852 permission
|= S_IEXEC
;
3853 else if (is_exec (name
))
3854 permission
|= S_IEXEC
;
3857 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3863 stat (const char * path
, struct stat
* buf
)
3865 return stat_worker (path
, buf
, 1);
3869 lstat (const char * path
, struct stat
* buf
)
3871 return stat_worker (path
, buf
, 0);
3874 /* Provide fstat and utime as well as stat for consistent handling of
3877 fstat (int desc
, struct stat
* buf
)
3879 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3880 BY_HANDLE_FILE_INFORMATION info
;
3881 unsigned __int64 fake_inode
;
3884 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3886 case FILE_TYPE_DISK
:
3887 buf
->st_mode
= S_IFREG
;
3888 if (!GetFileInformationByHandle (fh
, &info
))
3894 case FILE_TYPE_PIPE
:
3895 buf
->st_mode
= S_IFIFO
;
3897 case FILE_TYPE_CHAR
:
3898 case FILE_TYPE_UNKNOWN
:
3900 buf
->st_mode
= S_IFCHR
;
3902 memset (&info
, 0, sizeof (info
));
3903 info
.dwFileAttributes
= 0;
3904 info
.ftCreationTime
= utc_base_ft
;
3905 info
.ftLastAccessTime
= utc_base_ft
;
3906 info
.ftLastWriteTime
= utc_base_ft
;
3909 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3910 buf
->st_mode
= S_IFDIR
;
3912 buf
->st_nlink
= info
.nNumberOfLinks
;
3913 /* Might as well use file index to fake inode values, but this
3914 is not guaranteed to be unique unless we keep a handle open
3915 all the time (even then there are situations where it is
3916 not unique). Reputedly, there are at most 48 bits of info
3917 (on NTFS, presumably less on FAT). */
3918 fake_inode
= info
.nFileIndexHigh
;
3920 fake_inode
+= info
.nFileIndexLow
;
3922 /* MSVC defines _ino_t to be short; other libc's might not. */
3923 if (sizeof (buf
->st_ino
) == 2)
3924 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3926 buf
->st_ino
= fake_inode
;
3928 /* Consider files to belong to current user.
3929 FIXME: this should use GetSecurityInfo API, but it is only
3930 available for _WIN32_WINNT >= 0x501. */
3931 buf
->st_uid
= dflt_passwd
.pw_uid
;
3932 buf
->st_gid
= dflt_passwd
.pw_gid
;
3933 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3934 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3936 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3937 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3939 buf
->st_size
= info
.nFileSizeHigh
;
3940 buf
->st_size
<<= 32;
3941 buf
->st_size
+= info
.nFileSizeLow
;
3943 /* Convert timestamps to Unix format. */
3944 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3945 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3946 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3947 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3948 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3950 /* determine rwx permissions */
3951 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3952 permission
= S_IREAD
;
3954 permission
= S_IREAD
| S_IWRITE
;
3956 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3957 permission
|= S_IEXEC
;
3960 #if 0 /* no way of knowing the filename */
3961 char * p
= strrchr (name
, '.');
3963 (xstrcasecmp (p
, ".exe") == 0 ||
3964 xstrcasecmp (p
, ".com") == 0 ||
3965 xstrcasecmp (p
, ".bat") == 0 ||
3966 xstrcasecmp (p
, ".cmd") == 0))
3967 permission
|= S_IEXEC
;
3971 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3977 utime (const char *name
, struct utimbuf
*times
)
3979 struct utimbuf deftime
;
3986 deftime
.modtime
= deftime
.actime
= time (NULL
);
3990 /* Need write access to set times. */
3991 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3992 0, OPEN_EXISTING
, 0, NULL
);
3995 convert_from_time_t (times
->actime
, &atime
);
3996 convert_from_time_t (times
->modtime
, &mtime
);
3997 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
4014 /* Symlink-related functions. */
4015 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4016 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4020 symlink (char const *filename
, char const *linkname
)
4022 char linkfn
[MAX_PATH
], *tgtfn
;
4024 int dir_access
, filename_ends_in_slash
;
4026 /* Diagnostics follows Posix as much as possible. */
4027 if (filename
== NULL
|| linkname
== NULL
)
4037 if (strlen (filename
) > MAX_PATH
|| strlen (linkname
) > MAX_PATH
)
4039 errno
= ENAMETOOLONG
;
4043 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
4044 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
4050 /* Note: since empty FILENAME was already rejected, we can safely
4051 refer to FILENAME[1]. */
4052 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
4054 /* Non-absolute FILENAME is understood as being relative to
4055 LINKNAME's directory. We need to prepend that directory to
4056 FILENAME to get correct results from sys_access below, since
4057 otherwise it will interpret FILENAME relative to the
4058 directory where the Emacs process runs. Note that
4059 make-symbolic-link always makes sure LINKNAME is a fully
4060 expanded file name. */
4062 char *p
= linkfn
+ strlen (linkfn
);
4064 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
4067 strncpy (tem
, linkfn
, p
- linkfn
);
4068 tem
[p
- linkfn
] = '\0';
4069 strcat (tem
, filename
);
4070 dir_access
= sys_access (tem
, D_OK
);
4073 dir_access
= sys_access (filename
, D_OK
);
4075 /* Since Windows distinguishes between symlinks to directories and
4076 to files, we provide a kludgy feature: if FILENAME doesn't
4077 exist, but ends in a slash, we create a symlink to directory. If
4078 FILENAME exists and is a directory, we always create a symlink to
4080 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
4081 if (dir_access
== 0 || filename_ends_in_slash
)
4082 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
4084 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
4085 if (filename_ends_in_slash
)
4086 tgtfn
[strlen (tgtfn
) - 1] = '\0';
4089 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
4091 /* ENOSYS is set by create_symbolic_link, when it detects that
4092 the OS doesn't support the CreateSymbolicLink API. */
4093 if (errno
!= ENOSYS
)
4095 DWORD w32err
= GetLastError ();
4099 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4100 TGTFN point to the same file name, go figure. */
4102 case ERROR_FILE_EXISTS
:
4105 case ERROR_ACCESS_DENIED
:
4108 case ERROR_FILE_NOT_FOUND
:
4109 case ERROR_PATH_NOT_FOUND
:
4110 case ERROR_BAD_NETPATH
:
4111 case ERROR_INVALID_REPARSE_DATA
:
4114 case ERROR_DIRECTORY
:
4117 case ERROR_PRIVILEGE_NOT_HELD
:
4118 case ERROR_NOT_ALL_ASSIGNED
:
4121 case ERROR_DISK_FULL
:
4134 /* A quick inexpensive test of whether FILENAME identifies a file that
4135 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4136 must already be in the normalized form returned by
4139 Note: for repeated operations on many files, it is best to test
4140 whether the underlying volume actually supports symlinks, by
4141 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4142 avoid the call to this function if it doesn't. That's because the
4143 call to GetFileAttributes takes a non-negligible time, especially
4144 on non-local or removable filesystems. See stat_worker for an
4145 example of how to do that. */
4147 is_symlink (const char *filename
)
4150 WIN32_FIND_DATA wfd
;
4153 attrs
= GetFileAttributes (filename
);
4156 DWORD w32err
= GetLastError ();
4160 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
4162 case ERROR_ACCESS_DENIED
:
4165 case ERROR_FILE_NOT_FOUND
:
4166 case ERROR_PATH_NOT_FOUND
:
4173 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
4175 logon_network_drive (filename
);
4176 fh
= FindFirstFile (filename
, &wfd
);
4177 if (fh
== INVALID_HANDLE_VALUE
)
4180 return (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
4181 && (wfd
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
4184 /* If NAME identifies a symbolic link, copy into BUF the file name of
4185 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4186 null-terminate the target name, even if it fits. Return the number
4187 of bytes copied, or -1 if NAME is not a symlink or any error was
4188 encountered while resolving it. The file name copied into BUF is
4189 encoded in the current ANSI codepage. */
4191 readlink (const char *name
, char *buf
, size_t buf_size
)
4194 TOKEN_PRIVILEGES privs
;
4195 int restore_privs
= 0;
4210 path
= map_w32_filename (name
, NULL
);
4212 if (strlen (path
) > MAX_PATH
)
4214 errno
= ENAMETOOLONG
;
4219 if (is_windows_9x () == TRUE
4220 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
4221 || !is_symlink (path
))
4224 errno
= EINVAL
; /* not a symlink */
4228 /* Done with simple tests, now we're in for some _real_ work. */
4229 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
4231 /* Implementation note: From here and onward, don't return early,
4232 since that will fail to restore the original set of privileges of
4233 the calling thread. */
4235 retval
= -1; /* not too optimistic, are we? */
4237 /* Note: In the next call to CreateFile, we use zero as the 2nd
4238 argument because, when the symlink is a hidden/system file,
4239 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4240 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4241 and directory symlinks. */
4242 sh
= CreateFile (path
, 0, 0, NULL
, OPEN_EXISTING
,
4243 FILE_FLAG_OPEN_REPARSE_POINT
| FILE_FLAG_BACKUP_SEMANTICS
,
4245 if (sh
!= INVALID_HANDLE_VALUE
)
4247 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
4248 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
4251 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
4252 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
4255 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
4259 /* Copy the link target name, in wide characters, fro
4260 reparse_data, then convert it to multibyte encoding in
4261 the current locale's codepage. */
4263 BYTE lname
[MAX_PATH
];
4266 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
4268 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
4269 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
4271 /* According to MSDN, PrintNameLength does not include the
4272 terminating null character. */
4273 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
4274 memcpy (lwname
, lwname_src
, lwname_len
);
4275 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
4277 /* FIXME: Should we use the current file-name coding system
4278 instead of the fixed value of the ANSI codepage? */
4279 lname_len
= WideCharToMultiByte (w32_ansi_code_page
, 0, lwname
, -1,
4280 lname
, MAX_PATH
, NULL
, NULL
);
4283 /* WideCharToMultiByte failed. */
4284 DWORD w32err1
= GetLastError ();
4288 case ERROR_INSUFFICIENT_BUFFER
:
4289 errno
= ENAMETOOLONG
;
4291 case ERROR_INVALID_PARAMETER
:
4294 case ERROR_NO_UNICODE_TRANSLATION
:
4304 size_t size_to_copy
= buf_size
;
4306 BYTE
*pend
= p
+ lname_len
;
4308 /* Normalize like dostounix_filename does, but we don't
4309 want to assume that lname is null-terminated. */
4310 if (*p
&& p
[1] == ':' && *p
>= 'A' && *p
<= 'Z')
4318 /* Testing for null-terminated LNAME is paranoia:
4319 WideCharToMultiByte should always return a
4320 null-terminated string when its 4th argument is -1
4321 and its 3rd argument is null-terminated (which they
4323 if (lname
[lname_len
- 1] == '\0')
4325 if (lname_len
<= buf_size
)
4326 size_to_copy
= lname_len
;
4327 strncpy (buf
, lname
, size_to_copy
);
4329 retval
= size_to_copy
;
4336 /* CreateFile failed. */
4337 DWORD w32err2
= GetLastError ();
4341 case ERROR_FILE_NOT_FOUND
:
4342 case ERROR_PATH_NOT_FOUND
:
4345 case ERROR_ACCESS_DENIED
:
4346 case ERROR_TOO_MANY_OPEN_FILES
:
4356 restore_privilege (&privs
);
4363 /* If FILE is a symlink, return its target (stored in a static
4364 buffer); otherwise return FILE.
4366 This function repeatedly resolves symlinks in the last component of
4367 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4368 until it arrives at a file whose last component is not a symlink,
4369 or some error occurs. It returns the target of the last
4370 successfully resolved symlink in the chain. If it succeeds to
4371 resolve even a single symlink, the value returned is an absolute
4372 file name with backslashes (result of GetFullPathName). By
4373 contrast, if the original FILE is returned, it is unaltered.
4375 Note: This function can set errno even if it succeeds.
4377 Implementation note: we only resolve the last portion ("basename")
4378 of the argument FILE and of each following file in the chain,
4379 disregarding any possible symlinks in its leading directories.
4380 This is because Windows system calls and library functions
4381 transparently resolve symlinks in leading directories and return
4382 correct information, as long as the basename is not a symlink. */
4384 chase_symlinks (const char *file
)
4386 static char target
[MAX_PATH
];
4387 char link
[MAX_PATH
];
4388 ssize_t res
, link_len
;
4391 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
4392 return (char *)file
;
4394 if ((link_len
= GetFullPathName (file
, MAX_PATH
, link
, NULL
)) == 0)
4395 return (char *)file
;
4400 /* Remove trailing slashes, as we want to resolve the last
4401 non-trivial part of the link name. */
4402 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
4403 link
[link_len
--] = '\0';
4405 res
= readlink (link
, target
, MAX_PATH
);
4409 if (!(IS_DEVICE_SEP (target
[1])
4410 || (IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1]))))
4412 /* Target is relative. Append it to the directory part of
4413 the symlink, then copy the result back to target. */
4414 char *p
= link
+ link_len
;
4416 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
4419 strcpy (target
, link
);
4421 /* Resolve any "." and ".." to get a fully-qualified file name
4423 link_len
= GetFullPathName (target
, MAX_PATH
, link
, NULL
);
4425 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
4427 if (loop_count
> 100)
4430 if (target
[0] == '\0') /* not a single call to readlink succeeded */
4431 return (char *)file
;
4435 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
4436 have a fixed max size for file names, so we don't need the kind of
4437 alloc/malloc/realloc dance the gnulib version does. We also don't
4438 support FD-relative symlinks. */
4440 careadlinkat (int fd
, char const *filename
,
4441 char *buffer
, size_t buffer_size
,
4442 struct allocator
const *alloc
,
4443 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
4445 char linkname
[MAX_PATH
];
4454 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
4458 char *retval
= buffer
;
4460 linkname
[link_size
++] = '\0';
4461 if (link_size
> buffer_size
)
4462 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
4464 memcpy (retval
, linkname
, link_size
);
4472 careadlinkatcwd (int fd
, char const *filename
, char *buffer
,
4476 return readlink (filename
, buffer
, buffer_size
);
4480 /* Support for browsing other processes and their attributes. See
4481 process.c for the Lisp bindings. */
4483 /* Helper wrapper functions. */
4485 static HANDLE WINAPI
4486 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
4488 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
4490 if (g_b_init_create_toolhelp32_snapshot
== 0)
4492 g_b_init_create_toolhelp32_snapshot
= 1;
4493 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
4494 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4495 "CreateToolhelp32Snapshot");
4497 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
4499 return INVALID_HANDLE_VALUE
;
4501 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
4505 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
4507 static Process32First_Proc s_pfn_Process32_First
= NULL
;
4509 if (g_b_init_process32_first
== 0)
4511 g_b_init_process32_first
= 1;
4512 s_pfn_Process32_First
= (Process32First_Proc
)
4513 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4516 if (s_pfn_Process32_First
== NULL
)
4520 return (s_pfn_Process32_First (hSnapshot
, lppe
));
4524 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
4526 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
4528 if (g_b_init_process32_next
== 0)
4530 g_b_init_process32_next
= 1;
4531 s_pfn_Process32_Next
= (Process32Next_Proc
)
4532 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4535 if (s_pfn_Process32_Next
== NULL
)
4539 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
4543 open_thread_token (HANDLE ThreadHandle
,
4544 DWORD DesiredAccess
,
4546 PHANDLE TokenHandle
)
4548 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
4549 HMODULE hm_advapi32
= NULL
;
4550 if (is_windows_9x () == TRUE
)
4552 SetLastError (ERROR_NOT_SUPPORTED
);
4555 if (g_b_init_open_thread_token
== 0)
4557 g_b_init_open_thread_token
= 1;
4558 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4559 s_pfn_Open_Thread_Token
=
4560 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
4562 if (s_pfn_Open_Thread_Token
== NULL
)
4564 SetLastError (ERROR_NOT_SUPPORTED
);
4568 s_pfn_Open_Thread_Token (
4577 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
4579 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
4580 HMODULE hm_advapi32
= NULL
;
4581 if (is_windows_9x () == TRUE
)
4585 if (g_b_init_impersonate_self
== 0)
4587 g_b_init_impersonate_self
= 1;
4588 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4589 s_pfn_Impersonate_Self
=
4590 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
4592 if (s_pfn_Impersonate_Self
== NULL
)
4596 return s_pfn_Impersonate_Self (ImpersonationLevel
);
4600 revert_to_self (void)
4602 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
4603 HMODULE hm_advapi32
= NULL
;
4604 if (is_windows_9x () == TRUE
)
4608 if (g_b_init_revert_to_self
== 0)
4610 g_b_init_revert_to_self
= 1;
4611 hm_advapi32
= LoadLibrary ("Advapi32.dll");
4612 s_pfn_Revert_To_Self
=
4613 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
4615 if (s_pfn_Revert_To_Self
== NULL
)
4619 return s_pfn_Revert_To_Self ();
4623 get_process_memory_info (HANDLE h_proc
,
4624 PPROCESS_MEMORY_COUNTERS mem_counters
,
4627 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
4628 HMODULE hm_psapi
= NULL
;
4629 if (is_windows_9x () == TRUE
)
4633 if (g_b_init_get_process_memory_info
== 0)
4635 g_b_init_get_process_memory_info
= 1;
4636 hm_psapi
= LoadLibrary ("Psapi.dll");
4638 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
4639 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
4641 if (s_pfn_Get_Process_Memory_Info
== NULL
)
4645 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
4649 get_process_working_set_size (HANDLE h_proc
,
4653 static GetProcessWorkingSetSize_Proc
4654 s_pfn_Get_Process_Working_Set_Size
= NULL
;
4656 if (is_windows_9x () == TRUE
)
4660 if (g_b_init_get_process_working_set_size
== 0)
4662 g_b_init_get_process_working_set_size
= 1;
4663 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
4664 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4665 "GetProcessWorkingSetSize");
4667 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
4671 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
4675 global_memory_status (MEMORYSTATUS
*buf
)
4677 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
4679 if (is_windows_9x () == TRUE
)
4683 if (g_b_init_global_memory_status
== 0)
4685 g_b_init_global_memory_status
= 1;
4686 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
4687 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4688 "GlobalMemoryStatus");
4690 if (s_pfn_Global_Memory_Status
== NULL
)
4694 return s_pfn_Global_Memory_Status (buf
);
4698 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
4700 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
4702 if (is_windows_9x () == TRUE
)
4706 if (g_b_init_global_memory_status_ex
== 0)
4708 g_b_init_global_memory_status_ex
= 1;
4709 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
4710 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4711 "GlobalMemoryStatusEx");
4713 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
4717 return s_pfn_Global_Memory_Status_Ex (buf
);
4721 list_system_processes (void)
4723 struct gcpro gcpro1
;
4724 Lisp_Object proclist
= Qnil
;
4727 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4729 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4731 PROCESSENTRY32 proc_entry
;
4737 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
4738 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
4739 res
= process32_next (h_snapshot
, &proc_entry
))
4741 proc_id
= proc_entry
.th32ProcessID
;
4742 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
4745 CloseHandle (h_snapshot
);
4747 proclist
= Fnreverse (proclist
);
4754 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
4756 TOKEN_PRIVILEGES priv
;
4757 DWORD priv_size
= sizeof (priv
);
4758 DWORD opriv_size
= sizeof (*old_priv
);
4759 HANDLE h_token
= NULL
;
4760 HANDLE h_thread
= GetCurrentThread ();
4764 res
= open_thread_token (h_thread
,
4765 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4767 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
4769 if (impersonate_self (SecurityImpersonation
))
4770 res
= open_thread_token (h_thread
,
4771 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4776 priv
.PrivilegeCount
= 1;
4777 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
4778 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
4779 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
4780 old_priv
, &opriv_size
)
4781 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4785 CloseHandle (h_token
);
4791 restore_privilege (TOKEN_PRIVILEGES
*priv
)
4793 DWORD priv_size
= sizeof (*priv
);
4794 HANDLE h_token
= NULL
;
4797 if (open_thread_token (GetCurrentThread (),
4798 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
4801 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
4802 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
4806 CloseHandle (h_token
);
4812 ltime (ULONGLONG time_100ns
)
4814 ULONGLONG time_sec
= time_100ns
/ 10000000;
4815 int subsec
= time_100ns
% 10000000;
4816 return list4 (make_number (time_sec
>> 16),
4817 make_number (time_sec
& 0xffff),
4818 make_number (subsec
/ 10),
4819 make_number (subsec
% 10 * 100000));
4822 #define U64_TO_LISP_TIME(time) ltime (time)
4825 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
4826 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
4829 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
4830 ULONGLONG tem1
, tem2
, tem3
, tem
;
4833 || !get_process_times_fn
4834 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
4835 &ft_kernel
, &ft_user
))
4838 GetSystemTimeAsFileTime (&ft_current
);
4840 FILETIME_TO_U64 (tem1
, ft_kernel
);
4841 *stime
= U64_TO_LISP_TIME (tem1
);
4843 FILETIME_TO_U64 (tem2
, ft_user
);
4844 *utime
= U64_TO_LISP_TIME (tem2
);
4847 *ttime
= U64_TO_LISP_TIME (tem3
);
4849 FILETIME_TO_U64 (tem
, ft_creation
);
4850 /* Process no 4 (System) returns zero creation time. */
4853 *ctime
= U64_TO_LISP_TIME (tem
);
4857 FILETIME_TO_U64 (tem3
, ft_current
);
4858 tem
= (tem3
- utc_base
) - tem
;
4860 *etime
= U64_TO_LISP_TIME (tem
);
4864 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
4875 system_process_attributes (Lisp_Object pid
)
4877 struct gcpro gcpro1
, gcpro2
, gcpro3
;
4878 Lisp_Object attrs
= Qnil
;
4879 Lisp_Object cmd_str
, decoded_cmd
, tem
;
4880 HANDLE h_snapshot
, h_proc
;
4883 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
4884 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
4885 DWORD glength
= sizeof (gname
);
4886 HANDLE token
= NULL
;
4887 SID_NAME_USE user_type
;
4888 unsigned char *buf
= NULL
;
4890 TOKEN_USER user_token
;
4891 TOKEN_PRIMARY_GROUP group_token
;
4894 PROCESS_MEMORY_COUNTERS mem
;
4895 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
4896 DWORD minrss
, maxrss
;
4898 MEMORY_STATUS_EX memstex
;
4899 double totphys
= 0.0;
4900 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
4902 BOOL result
= FALSE
;
4904 CHECK_NUMBER_OR_FLOAT (pid
);
4905 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
4907 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
4909 GCPRO3 (attrs
, decoded_cmd
, tem
);
4911 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
4916 pe
.dwSize
= sizeof (PROCESSENTRY32
);
4917 for (res
= process32_first (h_snapshot
, &pe
); res
;
4918 res
= process32_next (h_snapshot
, &pe
))
4920 if (proc_id
== pe
.th32ProcessID
)
4923 decoded_cmd
= build_string ("Idle");
4926 /* Decode the command name from locale-specific
4928 cmd_str
= make_unibyte_string (pe
.szExeFile
,
4929 strlen (pe
.szExeFile
));
4931 code_convert_string_norecord (cmd_str
,
4932 Vlocale_coding_system
, 0);
4934 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
4935 attrs
= Fcons (Fcons (Qppid
,
4936 make_fixnum_or_float (pe
.th32ParentProcessID
)),
4938 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
4940 attrs
= Fcons (Fcons (Qthcount
,
4941 make_fixnum_or_float (pe
.cntThreads
)),
4948 CloseHandle (h_snapshot
);
4957 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4959 /* If we were denied a handle to the process, try again after
4960 enabling the SeDebugPrivilege in our process. */
4963 TOKEN_PRIVILEGES priv_current
;
4965 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
4967 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
4969 restore_privilege (&priv_current
);
4975 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
4978 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
4979 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
4981 buf
= xmalloc (blen
);
4982 result
= get_token_information (token
, TokenUser
,
4983 (LPVOID
)buf
, blen
, &needed
);
4986 memcpy (&user_token
, buf
, sizeof (user_token
));
4987 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
4989 euid
= get_rid (user_token
.User
.Sid
);
4990 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
4995 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
4998 strcpy (uname
, "unknown");
5002 ulength
= strlen (uname
);
5008 /* Determine a reasonable euid and gid values. */
5009 if (xstrcasecmp ("administrator", uname
) == 0)
5011 euid
= 500; /* well-known Administrator uid */
5012 egid
= 513; /* well-known None gid */
5016 /* Get group id and name. */
5017 result
= get_token_information (token
, TokenPrimaryGroup
,
5018 (LPVOID
)buf
, blen
, &needed
);
5019 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5021 buf
= xrealloc (buf
, blen
= needed
);
5022 result
= get_token_information (token
, TokenPrimaryGroup
,
5023 (LPVOID
)buf
, blen
, &needed
);
5027 memcpy (&group_token
, buf
, sizeof (group_token
));
5028 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
5030 egid
= get_rid (group_token
.PrimaryGroup
);
5031 dlength
= sizeof (domain
);
5033 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
5034 gname
, &glength
, NULL
, &dlength
,
5037 w32_add_to_cache (group_token
.PrimaryGroup
,
5041 strcpy (gname
, "None");
5045 glength
= strlen (gname
);
5053 if (!is_windows_9x ())
5055 /* We couldn't open the process token, presumably because of
5056 insufficient access rights. Assume this process is run
5058 strcpy (uname
, "SYSTEM");
5059 strcpy (gname
, "None");
5060 euid
= 18; /* SYSTEM */
5061 egid
= 513; /* None */
5062 glength
= strlen (gname
);
5063 ulength
= strlen (uname
);
5065 /* If we are running under Windows 9X, where security calls are
5066 not supported, we assume all processes are run by the current
5068 else if (GetUserName (uname
, &ulength
))
5070 if (xstrcasecmp ("administrator", uname
) == 0)
5075 strcpy (gname
, "None");
5076 glength
= strlen (gname
);
5077 ulength
= strlen (uname
);
5083 strcpy (uname
, "administrator");
5084 ulength
= strlen (uname
);
5085 strcpy (gname
, "None");
5086 glength
= strlen (gname
);
5089 CloseHandle (token
);
5092 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
5093 tem
= make_unibyte_string (uname
, ulength
);
5094 attrs
= Fcons (Fcons (Quser
,
5095 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5097 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
5098 tem
= make_unibyte_string (gname
, glength
);
5099 attrs
= Fcons (Fcons (Qgroup
,
5100 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5103 if (global_memory_status_ex (&memstex
))
5104 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5105 totphys
= memstex
.ullTotalPhys
/ 1024.0;
5107 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5108 double, so we need to do this for it... */
5110 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
5111 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
5112 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
5114 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
5116 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5117 else if (global_memory_status (&memst
))
5118 totphys
= memst
.dwTotalPhys
/ 1024.0;
5121 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
5124 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
5126 attrs
= Fcons (Fcons (Qmajflt
,
5127 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
5129 attrs
= Fcons (Fcons (Qvsize
,
5130 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
5132 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5134 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5137 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
5139 DWORD rss
= mem_ex
.WorkingSetSize
/ 1024;
5141 attrs
= Fcons (Fcons (Qmajflt
,
5142 make_fixnum_or_float (mem
.PageFaultCount
)),
5144 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5146 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5149 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
5151 DWORD rss
= maxrss
/ 1024;
5153 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
5155 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5158 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
5160 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
5161 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
5162 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
5163 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
5164 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
5165 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
5168 /* FIXME: Retrieve command line by walking the PEB of the process. */
5171 CloseHandle (h_proc
);
5177 /* Wrappers for winsock functions to map between our file descriptors
5178 and winsock's handles; also set h_errno for convenience.
5180 To allow Emacs to run on systems which don't have winsock support
5181 installed, we dynamically link to winsock on startup if present, and
5182 otherwise provide the minimum necessary functionality
5183 (eg. gethostname). */
5185 /* function pointers for relevant socket functions */
5186 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
5187 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
5188 int (PASCAL
*pfn_WSAGetLastError
) (void);
5189 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
5190 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
5191 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
5192 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
5193 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
5194 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
5195 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
5196 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
5197 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
5198 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
5199 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
5200 int (PASCAL
*pfn_WSACleanup
) (void);
5202 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
5203 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
5204 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
5205 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
5206 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
5207 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
5208 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
5209 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
5210 const char * optval
, int optlen
);
5211 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
5212 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
5214 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
5215 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
5216 struct sockaddr
* from
, int * fromlen
);
5217 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
5218 const struct sockaddr
* to
, int tolen
);
5220 /* SetHandleInformation is only needed to make sockets non-inheritable. */
5221 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
5222 #ifndef HANDLE_FLAG_INHERIT
5223 #define HANDLE_FLAG_INHERIT 1
5227 static int winsock_inuse
;
5232 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
5234 /* Not sure what would cause WSAENETDOWN, or even if it can happen
5235 after WSAStartup returns successfully, but it seems reasonable
5236 to allow unloading winsock anyway in that case. */
5237 if (pfn_WSACleanup () == 0 ||
5238 pfn_WSAGetLastError () == WSAENETDOWN
)
5240 if (FreeLibrary (winsock_lib
))
5249 init_winsock (int load_now
)
5251 WSADATA winsockData
;
5253 if (winsock_lib
!= NULL
)
5256 pfn_SetHandleInformation
5257 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
5258 "SetHandleInformation");
5260 winsock_lib
= LoadLibrary ("Ws2_32.dll");
5262 if (winsock_lib
!= NULL
)
5264 /* dynamically link to socket functions */
5266 #define LOAD_PROC(fn) \
5267 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
5270 LOAD_PROC (WSAStartup
);
5271 LOAD_PROC (WSASetLastError
);
5272 LOAD_PROC (WSAGetLastError
);
5273 LOAD_PROC (WSAEventSelect
);
5274 LOAD_PROC (WSACreateEvent
);
5275 LOAD_PROC (WSACloseEvent
);
5278 LOAD_PROC (connect
);
5279 LOAD_PROC (ioctlsocket
);
5282 LOAD_PROC (closesocket
);
5283 LOAD_PROC (shutdown
);
5286 LOAD_PROC (inet_addr
);
5287 LOAD_PROC (gethostname
);
5288 LOAD_PROC (gethostbyname
);
5289 LOAD_PROC (getservbyname
);
5290 LOAD_PROC (getpeername
);
5291 LOAD_PROC (WSACleanup
);
5292 LOAD_PROC (setsockopt
);
5294 LOAD_PROC (getsockname
);
5296 LOAD_PROC (recvfrom
);
5300 /* specify version 1.1 of winsock */
5301 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
5303 if (winsockData
.wVersion
!= 0x101)
5308 /* Report that winsock exists and is usable, but leave
5309 socket functions disabled. I am assuming that calling
5310 WSAStartup does not require any network interaction,
5311 and in particular does not cause or require a dial-up
5312 connection to be established. */
5315 FreeLibrary (winsock_lib
);
5323 FreeLibrary (winsock_lib
);
5333 /* function to set h_errno for compatibility; map winsock error codes to
5334 normal system codes where they overlap (non-overlapping definitions
5335 are already in <sys/socket.h> */
5339 if (winsock_lib
== NULL
)
5342 h_errno
= pfn_WSAGetLastError ();
5346 case WSAEACCES
: h_errno
= EACCES
; break;
5347 case WSAEBADF
: h_errno
= EBADF
; break;
5348 case WSAEFAULT
: h_errno
= EFAULT
; break;
5349 case WSAEINTR
: h_errno
= EINTR
; break;
5350 case WSAEINVAL
: h_errno
= EINVAL
; break;
5351 case WSAEMFILE
: h_errno
= EMFILE
; break;
5352 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
5353 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
5361 if (h_errno
== 0 && winsock_lib
!= NULL
)
5362 pfn_WSASetLastError (0);
5365 /* Extend strerror to handle the winsock-specific error codes. */
5369 } _wsa_errlist
[] = {
5370 {WSAEINTR
, "Interrupted function call"},
5371 {WSAEBADF
, "Bad file descriptor"},
5372 {WSAEACCES
, "Permission denied"},
5373 {WSAEFAULT
, "Bad address"},
5374 {WSAEINVAL
, "Invalid argument"},
5375 {WSAEMFILE
, "Too many open files"},
5377 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
5378 {WSAEINPROGRESS
, "Operation now in progress"},
5379 {WSAEALREADY
, "Operation already in progress"},
5380 {WSAENOTSOCK
, "Socket operation on non-socket"},
5381 {WSAEDESTADDRREQ
, "Destination address required"},
5382 {WSAEMSGSIZE
, "Message too long"},
5383 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
5384 {WSAENOPROTOOPT
, "Bad protocol option"},
5385 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
5386 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
5387 {WSAEOPNOTSUPP
, "Operation not supported"},
5388 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
5389 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
5390 {WSAEADDRINUSE
, "Address already in use"},
5391 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
5392 {WSAENETDOWN
, "Network is down"},
5393 {WSAENETUNREACH
, "Network is unreachable"},
5394 {WSAENETRESET
, "Network dropped connection on reset"},
5395 {WSAECONNABORTED
, "Software caused connection abort"},
5396 {WSAECONNRESET
, "Connection reset by peer"},
5397 {WSAENOBUFS
, "No buffer space available"},
5398 {WSAEISCONN
, "Socket is already connected"},
5399 {WSAENOTCONN
, "Socket is not connected"},
5400 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
5401 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
5402 {WSAETIMEDOUT
, "Connection timed out"},
5403 {WSAECONNREFUSED
, "Connection refused"},
5404 {WSAELOOP
, "Network loop"}, /* not sure */
5405 {WSAENAMETOOLONG
, "Name is too long"},
5406 {WSAEHOSTDOWN
, "Host is down"},
5407 {WSAEHOSTUNREACH
, "No route to host"},
5408 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
5409 {WSAEPROCLIM
, "Too many processes"},
5410 {WSAEUSERS
, "Too many users"}, /* not sure */
5411 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
5412 {WSAESTALE
, "Data is stale"}, /* not sure */
5413 {WSAEREMOTE
, "Remote error"}, /* not sure */
5415 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
5416 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
5417 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
5418 {WSAEDISCON
, "Graceful shutdown in progress"},
5420 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
5421 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
5422 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
5423 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
5424 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
5425 {WSASYSCALLFAILURE
, "System call failure"},
5426 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
5427 {WSATYPE_NOT_FOUND
, "Class type not found"},
5428 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
5429 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
5430 {WSAEREFUSED
, "Operation refused"}, /* not sure */
5433 {WSAHOST_NOT_FOUND
, "Host not found"},
5434 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
5435 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
5436 {WSANO_DATA
, "Valid name, no data record of requested type"},
5442 sys_strerror (int error_no
)
5445 static char unknown_msg
[40];
5447 if (error_no
>= 0 && error_no
< sys_nerr
)
5448 return sys_errlist
[error_no
];
5450 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
5451 if (_wsa_errlist
[i
].errnum
== error_no
)
5452 return _wsa_errlist
[i
].msg
;
5454 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
5458 /* [andrewi 3-May-96] I've had conflicting results using both methods,
5459 but I believe the method of keeping the socket handle separate (and
5460 insuring it is not inheritable) is the correct one. */
5462 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
5464 static int socket_to_fd (SOCKET s
);
5467 sys_socket (int af
, int type
, int protocol
)
5471 if (winsock_lib
== NULL
)
5474 return INVALID_SOCKET
;
5479 /* call the real socket function */
5480 s
= pfn_socket (af
, type
, protocol
);
5482 if (s
!= INVALID_SOCKET
)
5483 return socket_to_fd (s
);
5489 /* Convert a SOCKET to a file descriptor. */
5491 socket_to_fd (SOCKET s
)
5496 /* Although under NT 3.5 _open_osfhandle will accept a socket
5497 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
5498 that does not work under NT 3.1. However, we can get the same
5499 effect by using a backdoor function to replace an existing
5500 descriptor handle with the one we want. */
5502 /* allocate a file descriptor (with appropriate flags) */
5503 fd
= _open ("NUL:", _O_RDWR
);
5506 /* Make a non-inheritable copy of the socket handle. Note
5507 that it is possible that sockets aren't actually kernel
5508 handles, which appears to be the case on Windows 9x when
5509 the MS Proxy winsock client is installed. */
5511 /* Apparently there is a bug in NT 3.51 with some service
5512 packs, which prevents using DuplicateHandle to make a
5513 socket handle non-inheritable (causes WSACleanup to
5514 hang). The work-around is to use SetHandleInformation
5515 instead if it is available and implemented. */
5516 if (pfn_SetHandleInformation
)
5518 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
5522 HANDLE parent
= GetCurrentProcess ();
5523 HANDLE new_s
= INVALID_HANDLE_VALUE
;
5525 if (DuplicateHandle (parent
,
5531 DUPLICATE_SAME_ACCESS
))
5533 /* It is possible that DuplicateHandle succeeds even
5534 though the socket wasn't really a kernel handle,
5535 because a real handle has the same value. So
5536 test whether the new handle really is a socket. */
5537 long nonblocking
= 0;
5538 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
5540 pfn_closesocket (s
);
5545 CloseHandle (new_s
);
5550 fd_info
[fd
].hnd
= (HANDLE
) s
;
5552 /* set our own internal flags */
5553 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
5559 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5561 /* attach child_process to fd_info */
5562 if (fd_info
[ fd
].cp
!= NULL
)
5564 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
5568 fd_info
[ fd
].cp
= cp
;
5571 winsock_inuse
++; /* count open sockets */
5578 pfn_closesocket (s
);
5584 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
5586 if (winsock_lib
== NULL
)
5589 return SOCKET_ERROR
;
5593 if (fd_info
[s
].flags
& FILE_SOCKET
)
5595 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
5596 if (rc
== SOCKET_ERROR
)
5601 return SOCKET_ERROR
;
5605 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
5607 if (winsock_lib
== NULL
)
5610 return SOCKET_ERROR
;
5614 if (fd_info
[s
].flags
& FILE_SOCKET
)
5616 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
5617 if (rc
== SOCKET_ERROR
)
5622 return SOCKET_ERROR
;
5626 sys_htons (u_short hostshort
)
5628 return (winsock_lib
!= NULL
) ?
5629 pfn_htons (hostshort
) : hostshort
;
5633 sys_ntohs (u_short netshort
)
5635 return (winsock_lib
!= NULL
) ?
5636 pfn_ntohs (netshort
) : netshort
;
5640 sys_inet_addr (const char * cp
)
5642 return (winsock_lib
!= NULL
) ?
5643 pfn_inet_addr (cp
) : INADDR_NONE
;
5647 sys_gethostname (char * name
, int namelen
)
5649 if (winsock_lib
!= NULL
)
5650 return pfn_gethostname (name
, namelen
);
5652 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
5653 return !GetComputerName (name
, (DWORD
*)&namelen
);
5656 return SOCKET_ERROR
;
5660 sys_gethostbyname (const char * name
)
5662 struct hostent
* host
;
5664 if (winsock_lib
== NULL
)
5671 host
= pfn_gethostbyname (name
);
5678 sys_getservbyname (const char * name
, const char * proto
)
5680 struct servent
* serv
;
5682 if (winsock_lib
== NULL
)
5689 serv
= pfn_getservbyname (name
, proto
);
5696 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
5698 if (winsock_lib
== NULL
)
5701 return SOCKET_ERROR
;
5705 if (fd_info
[s
].flags
& FILE_SOCKET
)
5707 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
5708 if (rc
== SOCKET_ERROR
)
5713 return SOCKET_ERROR
;
5717 sys_shutdown (int s
, int how
)
5719 if (winsock_lib
== NULL
)
5722 return SOCKET_ERROR
;
5726 if (fd_info
[s
].flags
& FILE_SOCKET
)
5728 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
5729 if (rc
== SOCKET_ERROR
)
5734 return SOCKET_ERROR
;
5738 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
5740 if (winsock_lib
== NULL
)
5743 return SOCKET_ERROR
;
5747 if (fd_info
[s
].flags
& FILE_SOCKET
)
5749 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
5750 (const char *)optval
, optlen
);
5751 if (rc
== SOCKET_ERROR
)
5756 return SOCKET_ERROR
;
5760 sys_listen (int s
, int backlog
)
5762 if (winsock_lib
== NULL
)
5765 return SOCKET_ERROR
;
5769 if (fd_info
[s
].flags
& FILE_SOCKET
)
5771 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
5772 if (rc
== SOCKET_ERROR
)
5775 fd_info
[s
].flags
|= FILE_LISTEN
;
5779 return SOCKET_ERROR
;
5783 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
5785 if (winsock_lib
== NULL
)
5788 return SOCKET_ERROR
;
5792 if (fd_info
[s
].flags
& FILE_SOCKET
)
5794 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
5795 if (rc
== SOCKET_ERROR
)
5800 return SOCKET_ERROR
;
5804 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
5806 if (winsock_lib
== NULL
)
5813 if (fd_info
[s
].flags
& FILE_LISTEN
)
5815 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
5817 if (t
== INVALID_SOCKET
)
5820 fd
= socket_to_fd (t
);
5822 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
5823 ResetEvent (fd_info
[s
].cp
->char_avail
);
5831 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
5832 struct sockaddr
* from
, int * fromlen
)
5834 if (winsock_lib
== NULL
)
5837 return SOCKET_ERROR
;
5841 if (fd_info
[s
].flags
& FILE_SOCKET
)
5843 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
5844 if (rc
== SOCKET_ERROR
)
5849 return SOCKET_ERROR
;
5853 sys_sendto (int s
, const char * buf
, int len
, int flags
,
5854 const struct sockaddr
* to
, int tolen
)
5856 if (winsock_lib
== NULL
)
5859 return SOCKET_ERROR
;
5863 if (fd_info
[s
].flags
& FILE_SOCKET
)
5865 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
5866 if (rc
== SOCKET_ERROR
)
5871 return SOCKET_ERROR
;
5874 /* Windows does not have an fcntl function. Provide an implementation
5875 solely for making sockets non-blocking. */
5877 fcntl (int s
, int cmd
, int options
)
5879 if (winsock_lib
== NULL
)
5886 if (fd_info
[s
].flags
& FILE_SOCKET
)
5888 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
5890 unsigned long nblock
= 1;
5891 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
5892 if (rc
== SOCKET_ERROR
)
5894 /* Keep track of the fact that we set this to non-blocking. */
5895 fd_info
[s
].flags
|= FILE_NDELAY
;
5901 return SOCKET_ERROR
;
5905 return SOCKET_ERROR
;
5909 /* Shadow main io functions: we need to handle pipes and sockets more
5910 intelligently, and implement non-blocking mode as well. */
5923 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
5925 child_process
* cp
= fd_info
[fd
].cp
;
5927 fd_info
[fd
].cp
= NULL
;
5929 if (CHILD_ACTIVE (cp
))
5931 /* if last descriptor to active child_process then cleanup */
5933 for (i
= 0; i
< MAXDESC
; i
++)
5937 if (fd_info
[i
].cp
== cp
)
5942 if (fd_info
[fd
].flags
& FILE_SOCKET
)
5944 if (winsock_lib
== NULL
) emacs_abort ();
5946 pfn_shutdown (SOCK_HANDLE (fd
), 2);
5947 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
5949 winsock_inuse
--; /* count open sockets */
5956 /* Note that sockets do not need special treatment here (at least on
5957 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5958 closesocket is equivalent to CloseHandle, which is to be expected
5959 because socket handles are fully fledged kernel handles. */
5962 if (rc
== 0 && fd
< MAXDESC
)
5963 fd_info
[fd
].flags
= 0;
5974 if (new_fd
>= 0 && new_fd
< MAXDESC
)
5976 /* duplicate our internal info as well */
5977 fd_info
[new_fd
] = fd_info
[fd
];
5983 sys_dup2 (int src
, int dst
)
5987 if (dst
< 0 || dst
>= MAXDESC
)
5993 /* make sure we close the destination first if it's a pipe or socket */
5994 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
5997 rc
= _dup2 (src
, dst
);
6000 /* duplicate our internal info as well */
6001 fd_info
[dst
] = fd_info
[src
];
6006 /* Unix pipe() has only one arg */
6008 sys_pipe (int * phandles
)
6013 /* make pipe handles non-inheritable; when we spawn a child, we
6014 replace the relevant handle with an inheritable one. Also put
6015 pipes into binary mode; we will do text mode translation ourselves
6017 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
6021 /* Protect against overflow, since Windows can open more handles than
6022 our fd_info array has room for. */
6023 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
6025 _close (phandles
[0]);
6026 _close (phandles
[1]);
6031 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
6032 fd_info
[phandles
[0]].flags
= flags
;
6034 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
6035 fd_info
[phandles
[1]].flags
= flags
;
6042 /* Function to do blocking read of one byte, needed to implement
6043 select. It is only allowed on sockets and pipes. */
6045 _sys_read_ahead (int fd
)
6050 if (fd
< 0 || fd
>= MAXDESC
)
6051 return STATUS_READ_ERROR
;
6053 cp
= fd_info
[fd
].cp
;
6055 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6056 return STATUS_READ_ERROR
;
6058 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
6059 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
6061 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
6065 cp
->status
= STATUS_READ_IN_PROGRESS
;
6067 if (fd_info
[fd
].flags
& FILE_PIPE
)
6069 rc
= _read (fd
, &cp
->chr
, sizeof (char));
6071 /* Give subprocess time to buffer some more output for us before
6072 reporting that input is available; we need this because Windows 95
6073 connects DOS programs to pipes by making the pipe appear to be
6074 the normal console stdout - as a result most DOS programs will
6075 write to stdout without buffering, ie. one character at a
6076 time. Even some W32 programs do this - "dir" in a command
6077 shell on NT is very slow if we don't do this. */
6080 int wait
= w32_pipe_read_delay
;
6086 /* Yield remainder of our time slice, effectively giving a
6087 temporary priority boost to the child process. */
6091 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
6093 HANDLE hnd
= fd_info
[fd
].hnd
;
6094 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
6097 /* Configure timeouts for blocking read. */
6098 if (!GetCommTimeouts (hnd
, &ct
))
6099 return STATUS_READ_ERROR
;
6100 ct
.ReadIntervalTimeout
= 0;
6101 ct
.ReadTotalTimeoutMultiplier
= 0;
6102 ct
.ReadTotalTimeoutConstant
= 0;
6103 if (!SetCommTimeouts (hnd
, &ct
))
6104 return STATUS_READ_ERROR
;
6106 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
6108 if (GetLastError () != ERROR_IO_PENDING
)
6109 return STATUS_READ_ERROR
;
6110 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
6111 return STATUS_READ_ERROR
;
6114 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
6116 unsigned long nblock
= 0;
6117 /* We always want this to block, so temporarily disable NDELAY. */
6118 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6119 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6121 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
6123 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6126 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6130 if (rc
== sizeof (char))
6131 cp
->status
= STATUS_READ_SUCCEEDED
;
6133 cp
->status
= STATUS_READ_FAILED
;
6139 _sys_wait_accept (int fd
)
6145 if (fd
< 0 || fd
>= MAXDESC
)
6146 return STATUS_READ_ERROR
;
6148 cp
= fd_info
[fd
].cp
;
6150 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6151 return STATUS_READ_ERROR
;
6153 cp
->status
= STATUS_READ_FAILED
;
6155 hEv
= pfn_WSACreateEvent ();
6156 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
6157 if (rc
!= SOCKET_ERROR
)
6159 rc
= WaitForSingleObject (hEv
, INFINITE
);
6160 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
6161 if (rc
== WAIT_OBJECT_0
)
6162 cp
->status
= STATUS_READ_SUCCEEDED
;
6164 pfn_WSACloseEvent (hEv
);
6170 sys_read (int fd
, char * buffer
, unsigned int count
)
6175 char * orig_buffer
= buffer
;
6183 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
6185 child_process
*cp
= fd_info
[fd
].cp
;
6187 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
6195 /* re-read CR carried over from last read */
6196 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
6198 if (fd_info
[fd
].flags
& FILE_BINARY
) emacs_abort ();
6202 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
6205 /* presence of a child_process structure means we are operating in
6206 non-blocking mode - otherwise we just call _read directly.
6207 Note that the child_process structure might be missing because
6208 reap_subprocess has been called; in this case the pipe is
6209 already broken, so calling _read on it is okay. */
6212 int current_status
= cp
->status
;
6214 switch (current_status
)
6216 case STATUS_READ_FAILED
:
6217 case STATUS_READ_ERROR
:
6218 /* report normal EOF if nothing in buffer */
6220 fd_info
[fd
].flags
|= FILE_AT_EOF
;
6223 case STATUS_READ_READY
:
6224 case STATUS_READ_IN_PROGRESS
:
6225 DebPrint (("sys_read called when read is in progress\n"));
6226 errno
= EWOULDBLOCK
;
6229 case STATUS_READ_SUCCEEDED
:
6230 /* consume read-ahead char */
6231 *buffer
++ = cp
->chr
;
6234 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6235 ResetEvent (cp
->char_avail
);
6237 case STATUS_READ_ACKNOWLEDGED
:
6241 DebPrint (("sys_read: bad status %d\n", current_status
));
6246 if (fd_info
[fd
].flags
& FILE_PIPE
)
6248 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
6249 to_read
= min (waiting
, (DWORD
) count
);
6252 nchars
+= _read (fd
, buffer
, to_read
);
6254 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
6256 HANDLE hnd
= fd_info
[fd
].hnd
;
6257 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
6263 /* Configure timeouts for non-blocking read. */
6264 if (!GetCommTimeouts (hnd
, &ct
))
6269 ct
.ReadIntervalTimeout
= MAXDWORD
;
6270 ct
.ReadTotalTimeoutMultiplier
= 0;
6271 ct
.ReadTotalTimeoutConstant
= 0;
6272 if (!SetCommTimeouts (hnd
, &ct
))
6278 if (!ResetEvent (ovl
->hEvent
))
6283 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
6285 if (GetLastError () != ERROR_IO_PENDING
)
6290 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
6299 else /* FILE_SOCKET */
6301 if (winsock_lib
== NULL
) emacs_abort ();
6303 /* do the equivalent of a non-blocking read */
6304 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
6305 if (waiting
== 0 && nchars
== 0)
6307 h_errno
= errno
= EWOULDBLOCK
;
6313 /* always use binary mode for sockets */
6314 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
6315 if (res
== SOCKET_ERROR
)
6317 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
6318 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
6328 int nread
= _read (fd
, buffer
, count
);
6331 else if (nchars
== 0)
6336 fd_info
[fd
].flags
|= FILE_AT_EOF
;
6337 /* Perform text mode translation if required. */
6338 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
6340 nchars
= crlf_to_lf (nchars
, orig_buffer
);
6341 /* If buffer contains only CR, return that. To be absolutely
6342 sure we should attempt to read the next char, but in
6343 practice a CR to be followed by LF would not appear by
6344 itself in the buffer. */
6345 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
6347 fd_info
[fd
].flags
|= FILE_LAST_CR
;
6353 nchars
= _read (fd
, buffer
, count
);
6358 /* From w32xfns.c */
6359 extern HANDLE interrupt_handle
;
6361 /* For now, don't bother with a non-blocking mode */
6363 sys_write (int fd
, const void * buffer
, unsigned int count
)
6373 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
6375 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
6381 /* Perform text mode translation if required. */
6382 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
6384 char * tmpbuf
= alloca (count
* 2);
6385 unsigned char * src
= (void *)buffer
;
6386 unsigned char * dst
= tmpbuf
;
6391 unsigned char *next
;
6392 /* copy next line or remaining bytes */
6393 next
= _memccpy (dst
, src
, '\n', nbytes
);
6396 /* copied one line ending with '\n' */
6397 int copied
= next
- dst
;
6400 /* insert '\r' before '\n' */
6407 /* copied remaining partial line -> now finished */
6414 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
6416 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
6417 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
6418 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
6421 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
6423 if (GetLastError () != ERROR_IO_PENDING
)
6428 if (detect_input_pending ())
6429 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
6432 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
6433 if (active
== WAIT_OBJECT_0
)
6434 { /* User pressed C-g, cancel write, then leave. Don't bother
6435 cleaning up as we may only get stuck in buggy drivers. */
6436 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
6441 if (active
== WAIT_OBJECT_0
+ 1
6442 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
6449 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
6451 unsigned long nblock
= 0;
6452 if (winsock_lib
== NULL
) emacs_abort ();
6454 /* TODO: implement select() properly so non-blocking I/O works. */
6455 /* For now, make sure the write blocks. */
6456 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6457 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6459 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
6461 /* Set the socket back to non-blocking if it was before,
6462 for other operations that support it. */
6463 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6466 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6469 if (nchars
== SOCKET_ERROR
)
6471 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
6472 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
6478 /* Some networked filesystems don't like too large writes, so
6479 break them into smaller chunks. See the Comments section of
6480 the MSDN documentation of WriteFile for details behind the
6481 choice of the value of CHUNK below. See also the thread
6482 http://thread.gmane.org/gmane.comp.version-control.git/145294
6483 in the git mailing list. */
6484 const unsigned char *p
= buffer
;
6485 const unsigned chunk
= 30 * 1024 * 1024;
6490 unsigned this_chunk
= count
< chunk
? count
: chunk
;
6491 int n
= _write (fd
, p
, this_chunk
);
6499 else if (n
< this_chunk
)
6509 /* The Windows CRT functions are "optimized for speed", so they don't
6510 check for timezone and DST changes if they were last called less
6511 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
6512 all Emacs features that repeatedly call time functions (e.g.,
6513 display-time) are in real danger of missing timezone and DST
6514 changes. Calling tzset before each localtime call fixes that. */
6516 sys_localtime (const time_t *t
)
6519 return localtime (t
);
6524 /* Delayed loading of libraries. */
6526 Lisp_Object Vlibrary_cache
;
6528 /* The argument LIBRARIES is an alist that associates a symbol
6529 LIBRARY_ID, identifying an external DLL library known to Emacs, to
6530 a list of filenames under which the library is usually found. In
6531 most cases, the argument passed as LIBRARIES is the variable
6532 `dynamic-library-alist', which is initialized to a list of common
6533 library names. If the function loads the library successfully, it
6534 returns the handle of the DLL, and records the filename in the
6535 property :loaded-from of LIBRARY_ID; it returns NULL if the library
6536 could not be found, or when it was already loaded (because the
6537 handle is not recorded anywhere, and so is lost after use). It
6538 would be trivial to save the handle too in :loaded-from, but
6539 currently there's no use case for it. */
6541 w32_delayed_load (Lisp_Object libraries
, Lisp_Object library_id
)
6543 HMODULE library_dll
= NULL
;
6545 CHECK_SYMBOL (library_id
);
6547 if (CONSP (libraries
) && NILP (Fassq (library_id
, Vlibrary_cache
)))
6549 Lisp_Object found
= Qnil
;
6550 Lisp_Object dlls
= Fassq (library_id
, libraries
);
6553 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
6555 CHECK_STRING_CAR (dlls
);
6556 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
6558 char name
[MAX_PATH
];
6561 len
= GetModuleFileNameA (library_dll
, name
, sizeof (name
));
6562 found
= Fcons (XCAR (dlls
),
6564 /* Possibly truncated */
6565 ? make_specified_string (name
, -1, len
, 1)
6571 Fput (library_id
, QCloaded_from
, found
);
6579 check_windows_init_file (void)
6581 /* A common indication that Emacs is not installed properly is when
6582 it cannot find the Windows installation file. If this file does
6583 not exist in the expected place, tell the user. */
6585 if (!noninteractive
&& !inhibit_window_system
6586 /* Vload_path is not yet initialized when we are loading
6588 && NILP (Vpurify_flag
))
6590 Lisp_Object init_file
;
6593 init_file
= build_string ("term/w32-win");
6594 fd
= openp (Vload_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
6597 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
6598 char *init_file_name
= SDATA (init_file
);
6599 char *load_path
= SDATA (load_path_print
);
6600 char *buffer
= alloca (1024
6601 + strlen (init_file_name
)
6602 + strlen (load_path
));
6605 "The Emacs Windows initialization file \"%s.el\" "
6606 "could not be found in your Emacs installation. "
6607 "Emacs checked the following directories for this file:\n"
6609 "When Emacs cannot find this file, it usually means that it "
6610 "was not installed properly, or its distribution file was "
6611 "not unpacked properly.\nSee the README.W32 file in the "
6612 "top-level Emacs directory for more information.",
6613 init_file_name
, load_path
);
6616 "Emacs Abort Dialog",
6617 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
6618 /* Use the low-level system abort. */
6631 /* shutdown the socket interface if necessary */
6640 /* Initialize the socket interface now if available and requested by
6641 the user by defining PRELOAD_WINSOCK; otherwise loading will be
6642 delayed until open-network-stream is called (w32-has-winsock can
6643 also be used to dynamically load or reload winsock).
6645 Conveniently, init_environment is called before us, so
6646 PRELOAD_WINSOCK can be set in the registry. */
6648 /* Always initialize this correctly. */
6651 if (getenv ("PRELOAD_WINSOCK") != NULL
)
6652 init_winsock (TRUE
);
6654 /* Initial preparation for subprocess support: replace our standard
6655 handles with non-inheritable versions. */
6658 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
6659 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
6660 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
6662 parent
= GetCurrentProcess ();
6664 /* ignore errors when duplicating and closing; typically the
6665 handles will be invalid when running as a gui program. */
6666 DuplicateHandle (parent
,
6667 GetStdHandle (STD_INPUT_HANDLE
),
6672 DUPLICATE_SAME_ACCESS
);
6674 DuplicateHandle (parent
,
6675 GetStdHandle (STD_OUTPUT_HANDLE
),
6680 DUPLICATE_SAME_ACCESS
);
6682 DuplicateHandle (parent
,
6683 GetStdHandle (STD_ERROR_HANDLE
),
6688 DUPLICATE_SAME_ACCESS
);
6694 if (stdin_save
!= INVALID_HANDLE_VALUE
)
6695 _open_osfhandle ((long) stdin_save
, O_TEXT
);
6697 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
6700 if (stdout_save
!= INVALID_HANDLE_VALUE
)
6701 _open_osfhandle ((long) stdout_save
, O_TEXT
);
6703 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
6706 if (stderr_save
!= INVALID_HANDLE_VALUE
)
6707 _open_osfhandle ((long) stderr_save
, O_TEXT
);
6709 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
6713 /* unfortunately, atexit depends on implementation of malloc */
6714 /* atexit (term_ntproc); */
6715 signal (SIGABRT
, term_ntproc
);
6717 /* determine which drives are fixed, for GetCachedVolumeInformation */
6719 /* GetDriveType must have trailing backslash. */
6720 char drive
[] = "A:\\";
6722 /* Loop over all possible drive letters */
6723 while (*drive
<= 'Z')
6725 /* Record if this drive letter refers to a fixed drive. */
6726 fixed_drives
[DRIVE_INDEX (*drive
)] =
6727 (GetDriveType (drive
) == DRIVE_FIXED
);
6732 /* Reset the volume info cache. */
6733 volume_cache
= NULL
;
6738 shutdown_handler ensures that buffers' autosave files are
6739 up to date when the user logs off, or the system shuts down.
6742 shutdown_handler (DWORD type
)
6744 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
6745 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
6746 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
6747 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
6749 /* Shut down cleanly, making sure autosave files are up to date. */
6750 shut_down_emacs (0, Qnil
);
6753 /* Allow other handlers to handle this signal. */
6758 globals_of_w32 is used to initialize those global variables that
6759 must always be initialized on startup even when the global variable
6760 initialized is non zero (see the function main in emacs.c).
6763 globals_of_w32 (void)
6765 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
6767 get_process_times_fn
= (GetProcessTimes_Proc
)
6768 GetProcAddress (kernel32
, "GetProcessTimes");
6770 DEFSYM (QCloaded_from
, ":loaded-from");
6772 Vlibrary_cache
= Qnil
;
6773 staticpro (&Vlibrary_cache
);
6775 g_b_init_is_windows_9x
= 0;
6776 g_b_init_open_process_token
= 0;
6777 g_b_init_get_token_information
= 0;
6778 g_b_init_lookup_account_sid
= 0;
6779 g_b_init_get_sid_sub_authority
= 0;
6780 g_b_init_get_sid_sub_authority_count
= 0;
6781 g_b_init_get_security_info
= 0;
6782 g_b_init_get_file_security
= 0;
6783 g_b_init_get_security_descriptor_owner
= 0;
6784 g_b_init_get_security_descriptor_group
= 0;
6785 g_b_init_is_valid_sid
= 0;
6786 g_b_init_create_toolhelp32_snapshot
= 0;
6787 g_b_init_process32_first
= 0;
6788 g_b_init_process32_next
= 0;
6789 g_b_init_open_thread_token
= 0;
6790 g_b_init_impersonate_self
= 0;
6791 g_b_init_revert_to_self
= 0;
6792 g_b_init_get_process_memory_info
= 0;
6793 g_b_init_get_process_working_set_size
= 0;
6794 g_b_init_global_memory_status
= 0;
6795 g_b_init_global_memory_status_ex
= 0;
6796 g_b_init_equal_sid
= 0;
6797 g_b_init_copy_sid
= 0;
6798 g_b_init_get_length_sid
= 0;
6799 g_b_init_get_native_system_info
= 0;
6800 g_b_init_get_system_times
= 0;
6801 g_b_init_create_symbolic_link
= 0;
6802 num_of_processors
= 0;
6803 /* The following sets a handler for shutdown notifications for
6804 console apps. This actually applies to Emacs in both console and
6805 GUI modes, since we had to fool windows into thinking emacs is a
6806 console application to get console mode to work. */
6807 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
6809 /* "None" is the default group name on standalone workstations. */
6810 strcpy (dflt_group_name
, "None");
6813 /* For make-serial-process */
6815 serial_open (char *port
)
6821 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
6822 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
6823 if (hnd
== INVALID_HANDLE_VALUE
)
6824 error ("Could not open %s", port
);
6825 fd
= (int) _open_osfhandle ((int) hnd
, 0);
6827 error ("Could not open %s", port
);
6831 error ("Could not create child process");
6833 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6834 fd_info
[ fd
].hnd
= hnd
;
6835 fd_info
[ fd
].flags
|=
6836 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
6837 if (fd_info
[ fd
].cp
!= NULL
)
6839 error ("fd_info[fd = %d] is already in use", fd
);
6841 fd_info
[ fd
].cp
= cp
;
6842 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6843 if (cp
->ovl_read
.hEvent
== NULL
)
6844 error ("Could not create read event");
6845 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
6846 if (cp
->ovl_write
.hEvent
== NULL
)
6847 error ("Could not create write event");
6852 /* For serial-process-configure */
6854 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
6856 Lisp_Object childp2
= Qnil
;
6857 Lisp_Object tem
= Qnil
;
6861 char summary
[4] = "???"; /* This usually becomes "8N1". */
6863 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
6864 error ("Not a serial process");
6865 hnd
= fd_info
[ p
->outfd
].hnd
;
6867 childp2
= Fcopy_sequence (p
->childp
);
6869 /* Initialize timeouts for blocking read and blocking write. */
6870 if (!GetCommTimeouts (hnd
, &ct
))
6871 error ("GetCommTimeouts() failed");
6872 ct
.ReadIntervalTimeout
= 0;
6873 ct
.ReadTotalTimeoutMultiplier
= 0;
6874 ct
.ReadTotalTimeoutConstant
= 0;
6875 ct
.WriteTotalTimeoutMultiplier
= 0;
6876 ct
.WriteTotalTimeoutConstant
= 0;
6877 if (!SetCommTimeouts (hnd
, &ct
))
6878 error ("SetCommTimeouts() failed");
6879 /* Read port attributes and prepare default configuration. */
6880 memset (&dcb
, 0, sizeof (dcb
));
6881 dcb
.DCBlength
= sizeof (DCB
);
6882 if (!GetCommState (hnd
, &dcb
))
6883 error ("GetCommState() failed");
6886 dcb
.fAbortOnError
= FALSE
;
6887 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
6892 /* Configure speed. */
6893 if (!NILP (Fplist_member (contact
, QCspeed
)))
6894 tem
= Fplist_get (contact
, QCspeed
);
6896 tem
= Fplist_get (p
->childp
, QCspeed
);
6898 dcb
.BaudRate
= XINT (tem
);
6899 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
6901 /* Configure bytesize. */
6902 if (!NILP (Fplist_member (contact
, QCbytesize
)))
6903 tem
= Fplist_get (contact
, QCbytesize
);
6905 tem
= Fplist_get (p
->childp
, QCbytesize
);
6907 tem
= make_number (8);
6909 if (XINT (tem
) != 7 && XINT (tem
) != 8)
6910 error (":bytesize must be nil (8), 7, or 8");
6911 dcb
.ByteSize
= XINT (tem
);
6912 summary
[0] = XINT (tem
) + '0';
6913 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
6915 /* Configure parity. */
6916 if (!NILP (Fplist_member (contact
, QCparity
)))
6917 tem
= Fplist_get (contact
, QCparity
);
6919 tem
= Fplist_get (p
->childp
, QCparity
);
6920 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
6921 error (":parity must be nil (no parity), `even', or `odd'");
6922 dcb
.fParity
= FALSE
;
6923 dcb
.Parity
= NOPARITY
;
6924 dcb
.fErrorChar
= FALSE
;
6929 else if (EQ (tem
, Qeven
))
6933 dcb
.Parity
= EVENPARITY
;
6934 dcb
.fErrorChar
= TRUE
;
6936 else if (EQ (tem
, Qodd
))
6940 dcb
.Parity
= ODDPARITY
;
6941 dcb
.fErrorChar
= TRUE
;
6943 childp2
= Fplist_put (childp2
, QCparity
, tem
);
6945 /* Configure stopbits. */
6946 if (!NILP (Fplist_member (contact
, QCstopbits
)))
6947 tem
= Fplist_get (contact
, QCstopbits
);
6949 tem
= Fplist_get (p
->childp
, QCstopbits
);
6951 tem
= make_number (1);
6953 if (XINT (tem
) != 1 && XINT (tem
) != 2)
6954 error (":stopbits must be nil (1 stopbit), 1, or 2");
6955 summary
[2] = XINT (tem
) + '0';
6956 if (XINT (tem
) == 1)
6957 dcb
.StopBits
= ONESTOPBIT
;
6958 else if (XINT (tem
) == 2)
6959 dcb
.StopBits
= TWOSTOPBITS
;
6960 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
6962 /* Configure flowcontrol. */
6963 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
6964 tem
= Fplist_get (contact
, QCflowcontrol
);
6966 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
6967 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
6968 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6969 dcb
.fOutxCtsFlow
= FALSE
;
6970 dcb
.fOutxDsrFlow
= FALSE
;
6971 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
6972 dcb
.fDsrSensitivity
= FALSE
;
6973 dcb
.fTXContinueOnXoff
= FALSE
;
6976 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
6977 dcb
.XonChar
= 17; /* Control-Q */
6978 dcb
.XoffChar
= 19; /* Control-S */
6981 /* Already configured. */
6983 else if (EQ (tem
, Qhw
))
6985 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
6986 dcb
.fOutxCtsFlow
= TRUE
;
6988 else if (EQ (tem
, Qsw
))
6993 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
6995 /* Activate configuration. */
6996 if (!SetCommState (hnd
, &dcb
))
6997 error ("SetCommState() failed");
6999 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
7000 pset_childp (p
, childp2
);
7006 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
7010 struct timeval timeout
;
7011 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7012 int fd
= process
->infd
;
7016 n
= sys_read (fd
, (char*)buf
, sz
);
7023 if (err
== EWOULDBLOCK
)
7025 /* Set a small timeout. */
7027 timeout
.tv_usec
= 0;
7029 FD_SET ((int)fd
, &fdset
);
7031 /* Use select with the timeout to poll the selector. */
7032 sc
= select (fd
+ 1, &fdset
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0,
7036 continue; /* Try again. */
7038 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
7039 Also accept select return 0 as an indicator to EAGAIN. */
7040 if (sc
== 0 || errno
== EWOULDBLOCK
)
7043 err
= errno
; /* Other errors are just passed on. */
7046 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
7053 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
7055 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7056 int fd
= process
->outfd
;
7057 ssize_t n
= sys_write (fd
, buf
, sz
);
7059 /* 0 or more bytes written means everything went fine. */
7063 /* Negative bytes written means we got an error in errno.
7064 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7065 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
7066 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
7070 #endif /* HAVE_GNUTLS */