1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
2 Copyright (C) 1994-1995, 2000-2013 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
23 #include <mingw_time.h>
24 #include <stddef.h> /* for offsetof */
27 #include <float.h> /* for DBL_EPSILON */
34 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
36 #include <sys/utime.h>
39 /* must include CRT headers *before* config.h */
42 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
69 #include "epaths.h" /* for SHELL */
74 /* MinGW64 (_W64) defines these in its _mingw.h. */
75 #if defined(__GNUC__) && !defined(_W64)
76 #define _ANONYMOUS_UNION
77 #define _ANONYMOUS_STRUCT
80 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
81 use a different name to avoid compilation problems. */
82 typedef struct _MEMORY_STATUS_EX
{
85 DWORDLONG ullTotalPhys
;
86 DWORDLONG ullAvailPhys
;
87 DWORDLONG ullTotalPageFile
;
88 DWORDLONG ullAvailPageFile
;
89 DWORDLONG ullTotalVirtual
;
90 DWORDLONG ullAvailVirtual
;
91 DWORDLONG ullAvailExtendedVirtual
;
92 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
94 /* These are here so that GDB would know about these data types. This
95 allows to attach GDB to Emacs when a fatal exception is triggered
96 and Windows pops up the "application needs to be closed" dialog.
97 At that point, _gnu_exception_handler, the top-level exception
98 handler installed by the MinGW startup code, is somewhere on the
99 call-stack of the main thread, so going to that call frame and
100 looking at the argument to _gnu_exception_handler, which is a
101 PEXCEPTION_POINTERS pointer, can reveal the exception code
102 (excptr->ExceptionRecord->ExceptionCode) and the address where the
103 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
104 well as some additional information specific to the exception. */
105 PEXCEPTION_POINTERS excptr
;
106 PEXCEPTION_RECORD excprec
;
112 #include <tlhelp32.h>
117 #if _WIN32_WINNT < 0x0500
118 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
119 /* This either is not in psapi.h or guarded by higher value of
120 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
121 defines it in psapi.h */
122 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
124 DWORD PageFaultCount
;
125 SIZE_T PeakWorkingSetSize
;
126 SIZE_T WorkingSetSize
;
127 SIZE_T QuotaPeakPagedPoolUsage
;
128 SIZE_T QuotaPagedPoolUsage
;
129 SIZE_T QuotaPeakNonPagedPoolUsage
;
130 SIZE_T QuotaNonPagedPoolUsage
;
131 SIZE_T PagefileUsage
;
132 SIZE_T PeakPagefileUsage
;
134 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
138 #include <winioctl.h>
144 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
145 define them by hand if not already defined. */
146 #ifndef SDDL_REVISION_1
147 #define SDDL_REVISION_1 1
148 #endif /* SDDL_REVISION_1 */
150 #if defined(_MSC_VER) || defined(_W64)
151 /* MSVC and MinGW64 don't provide the definition of
152 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
153 which cannot be included because it triggers conflicts with other
154 Windows API headers. So we define it here by hand. */
156 typedef struct _REPARSE_DATA_BUFFER
{
158 USHORT ReparseDataLength
;
162 USHORT SubstituteNameOffset
;
163 USHORT SubstituteNameLength
;
164 USHORT PrintNameOffset
;
165 USHORT PrintNameLength
;
168 } SymbolicLinkReparseBuffer
;
170 USHORT SubstituteNameOffset
;
171 USHORT SubstituteNameLength
;
172 USHORT PrintNameOffset
;
173 USHORT PrintNameLength
;
175 } MountPointReparseBuffer
;
178 } GenericReparseBuffer
;
180 } REPARSE_DATA_BUFFER
, *PREPARSE_DATA_BUFFER
;
182 #ifndef FILE_DEVICE_FILE_SYSTEM
183 #define FILE_DEVICE_FILE_SYSTEM 9
185 #ifndef METHOD_BUFFERED
186 #define METHOD_BUFFERED 0
188 #ifndef FILE_ANY_ACCESS
189 #define FILE_ANY_ACCESS 0x00000000
192 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
194 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
195 #ifndef FSCTL_GET_REPARSE_POINT
196 #define FSCTL_GET_REPARSE_POINT \
197 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
201 /* TCP connection support. */
202 #include <sys/socket.h>
221 #include <iphlpapi.h> /* should be after winsock2.h */
225 #include "w32common.h"
227 #include "w32select.h"
229 #include "dispextern.h" /* for xstrcasecmp */
230 #include "coding.h" /* for Vlocale_coding_system */
232 #include "careadlinkat.h"
233 #include "allocator.h"
235 /* For serial_configure and serial_open. */
238 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
239 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
241 Lisp_Object QCloaded_from
;
243 void globals_of_w32 (void);
244 static DWORD
get_rid (PSID
);
245 static int is_symlink (const char *);
246 static char * chase_symlinks (const char *);
247 static int enable_privilege (LPCTSTR
, BOOL
, TOKEN_PRIVILEGES
*);
248 static int restore_privilege (TOKEN_PRIVILEGES
*);
249 static BOOL WINAPI
revert_to_self (void);
251 extern int sys_access (const char *, int);
252 extern void *e_malloc (size_t);
253 extern int sys_select (int, SELECT_TYPE
*, SELECT_TYPE
*, SELECT_TYPE
*,
254 struct timespec
*, void *);
255 extern int sys_dup (int);
260 /* Initialization states.
262 WARNING: If you add any more such variables for additional APIs,
263 you MUST add initialization for them to globals_of_w32
264 below. This is because these variables might get set
265 to non-NULL values during dumping, but the dumped Emacs
266 cannot reuse those values, because it could be run on a
267 different version of the OS, where API addresses are
269 static BOOL g_b_init_is_windows_9x
;
270 static BOOL g_b_init_open_process_token
;
271 static BOOL g_b_init_get_token_information
;
272 static BOOL g_b_init_lookup_account_sid
;
273 static BOOL g_b_init_get_sid_sub_authority
;
274 static BOOL g_b_init_get_sid_sub_authority_count
;
275 static BOOL g_b_init_get_security_info
;
276 static BOOL g_b_init_get_file_security
;
277 static BOOL g_b_init_get_security_descriptor_owner
;
278 static BOOL g_b_init_get_security_descriptor_group
;
279 static BOOL g_b_init_is_valid_sid
;
280 static BOOL g_b_init_create_toolhelp32_snapshot
;
281 static BOOL g_b_init_process32_first
;
282 static BOOL g_b_init_process32_next
;
283 static BOOL g_b_init_open_thread_token
;
284 static BOOL g_b_init_impersonate_self
;
285 static BOOL g_b_init_revert_to_self
;
286 static BOOL g_b_init_get_process_memory_info
;
287 static BOOL g_b_init_get_process_working_set_size
;
288 static BOOL g_b_init_global_memory_status
;
289 static BOOL g_b_init_global_memory_status_ex
;
290 static BOOL g_b_init_get_length_sid
;
291 static BOOL g_b_init_equal_sid
;
292 static BOOL g_b_init_copy_sid
;
293 static BOOL g_b_init_get_native_system_info
;
294 static BOOL g_b_init_get_system_times
;
295 static BOOL g_b_init_create_symbolic_link
;
296 static BOOL g_b_init_get_security_descriptor_dacl
;
297 static BOOL g_b_init_convert_sd_to_sddl
;
298 static BOOL g_b_init_convert_sddl_to_sd
;
299 static BOOL g_b_init_is_valid_security_descriptor
;
300 static BOOL g_b_init_set_file_security
;
301 static BOOL g_b_init_get_adapters_info
;
304 BEGIN: Wrapper functions around OpenProcessToken
305 and other functions in advapi32.dll that are only
306 supported in Windows NT / 2k / XP
308 /* ** Function pointer typedefs ** */
309 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
310 HANDLE ProcessHandle
,
312 PHANDLE TokenHandle
);
313 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
315 TOKEN_INFORMATION_CLASS TokenInformationClass
,
316 LPVOID TokenInformation
,
317 DWORD TokenInformationLength
,
318 PDWORD ReturnLength
);
319 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
320 HANDLE process_handle
,
321 LPFILETIME creation_time
,
322 LPFILETIME exit_time
,
323 LPFILETIME kernel_time
,
324 LPFILETIME user_time
);
326 GetProcessTimes_Proc get_process_times_fn
= NULL
;
329 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
330 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
331 const char * const SetFileSecurity_Name
= "SetFileSecurityW";
333 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
334 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
335 const char * const SetFileSecurity_Name
= "SetFileSecurityA";
337 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
338 LPCTSTR lpSystemName
,
343 LPDWORD cbDomainName
,
344 PSID_NAME_USE peUse
);
345 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
348 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
350 typedef DWORD (WINAPI
* GetSecurityInfo_Proc
) (
352 SE_OBJECT_TYPE ObjectType
,
353 SECURITY_INFORMATION SecurityInfo
,
358 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
);
359 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
361 SECURITY_INFORMATION RequestedInformation
,
362 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
364 LPDWORD lpnLengthNeeded
);
365 typedef BOOL (WINAPI
*SetFileSecurity_Proc
) (
367 SECURITY_INFORMATION SecurityInformation
,
368 PSECURITY_DESCRIPTOR pSecurityDescriptor
);
369 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
370 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
372 LPBOOL lpbOwnerDefaulted
);
373 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
374 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
376 LPBOOL lpbGroupDefaulted
);
377 typedef BOOL (WINAPI
*GetSecurityDescriptorDacl_Proc
) (
378 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
379 LPBOOL lpbDaclPresent
,
381 LPBOOL lpbDaclDefaulted
);
382 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
384 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
386 DWORD th32ProcessID
);
387 typedef BOOL (WINAPI
* Process32First_Proc
) (
389 LPPROCESSENTRY32 lppe
);
390 typedef BOOL (WINAPI
* Process32Next_Proc
) (
392 LPPROCESSENTRY32 lppe
);
393 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
397 PHANDLE TokenHandle
);
398 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
399 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
400 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
401 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
403 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
405 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
407 PSIZE_T lpMinimumWorkingSetSize
,
408 PSIZE_T lpMaximumWorkingSetSize
);
409 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
410 LPMEMORYSTATUS lpBuffer
);
411 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
412 LPMEMORY_STATUS_EX lpBuffer
);
413 typedef BOOL (WINAPI
* CopySid_Proc
) (
414 DWORD nDestinationSidLength
,
415 PSID pDestinationSid
,
417 typedef BOOL (WINAPI
* EqualSid_Proc
) (
420 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
422 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
423 LPSYSTEM_INFO lpSystemInfo
);
424 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
425 LPFILETIME lpIdleTime
,
426 LPFILETIME lpKernelTime
,
427 LPFILETIME lpUserTime
);
428 typedef BOOLEAN (WINAPI
*CreateSymbolicLink_Proc
) (
429 LPTSTR lpSymlinkFileName
,
430 LPTSTR lpTargetFileName
,
432 typedef BOOL (WINAPI
*ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
) (
433 LPCTSTR StringSecurityDescriptor
,
434 DWORD StringSDRevision
,
435 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
436 PULONG SecurityDescriptorSize
);
437 typedef BOOL (WINAPI
*ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
) (
438 PSECURITY_DESCRIPTOR SecurityDescriptor
,
439 DWORD RequestedStringSDRevision
,
440 SECURITY_INFORMATION SecurityInformation
,
441 LPTSTR
*StringSecurityDescriptor
,
442 PULONG StringSecurityDescriptorLen
);
443 typedef BOOL (WINAPI
*IsValidSecurityDescriptor_Proc
) (PSECURITY_DESCRIPTOR
);
444 typedef DWORD (WINAPI
*GetAdaptersInfo_Proc
) (
445 PIP_ADAPTER_INFO pAdapterInfo
,
448 /* ** A utility function ** */
452 static BOOL s_b_ret
= 0;
453 OSVERSIONINFO os_ver
;
454 if (g_b_init_is_windows_9x
== 0)
456 g_b_init_is_windows_9x
= 1;
457 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
458 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
459 if (GetVersionEx (&os_ver
))
461 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
467 static Lisp_Object
ltime (ULONGLONG
);
469 /* Get total user and system times for get-internal-run-time.
470 Returns a list of integers if the times are provided by the OS
471 (NT derivatives), otherwise it returns the result of current-time. */
473 w32_get_internal_run_time (void)
475 if (get_process_times_fn
)
477 FILETIME create
, exit
, kernel
, user
;
478 HANDLE proc
= GetCurrentProcess ();
479 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
481 LARGE_INTEGER user_int
, kernel_int
, total
;
482 user_int
.LowPart
= user
.dwLowDateTime
;
483 user_int
.HighPart
= user
.dwHighDateTime
;
484 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
485 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
486 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
487 return ltime (total
.QuadPart
);
491 return Fcurrent_time ();
494 /* ** The wrapper functions ** */
497 open_process_token (HANDLE ProcessHandle
,
501 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
502 HMODULE hm_advapi32
= NULL
;
503 if (is_windows_9x () == TRUE
)
507 if (g_b_init_open_process_token
== 0)
509 g_b_init_open_process_token
= 1;
510 hm_advapi32
= LoadLibrary ("Advapi32.dll");
511 s_pfn_Open_Process_Token
=
512 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
514 if (s_pfn_Open_Process_Token
== NULL
)
519 s_pfn_Open_Process_Token (
527 get_token_information (HANDLE TokenHandle
,
528 TOKEN_INFORMATION_CLASS TokenInformationClass
,
529 LPVOID TokenInformation
,
530 DWORD TokenInformationLength
,
533 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
534 HMODULE hm_advapi32
= NULL
;
535 if (is_windows_9x () == TRUE
)
539 if (g_b_init_get_token_information
== 0)
541 g_b_init_get_token_information
= 1;
542 hm_advapi32
= LoadLibrary ("Advapi32.dll");
543 s_pfn_Get_Token_Information
=
544 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
546 if (s_pfn_Get_Token_Information
== NULL
)
551 s_pfn_Get_Token_Information (
553 TokenInformationClass
,
555 TokenInformationLength
,
561 lookup_account_sid (LPCTSTR lpSystemName
,
566 LPDWORD cbDomainName
,
569 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
570 HMODULE hm_advapi32
= NULL
;
571 if (is_windows_9x () == TRUE
)
575 if (g_b_init_lookup_account_sid
== 0)
577 g_b_init_lookup_account_sid
= 1;
578 hm_advapi32
= LoadLibrary ("Advapi32.dll");
579 s_pfn_Lookup_Account_Sid
=
580 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
582 if (s_pfn_Lookup_Account_Sid
== NULL
)
587 s_pfn_Lookup_Account_Sid (
599 get_sid_sub_authority (PSID pSid
, DWORD n
)
601 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
602 static DWORD zero
= 0U;
603 HMODULE hm_advapi32
= NULL
;
604 if (is_windows_9x () == TRUE
)
608 if (g_b_init_get_sid_sub_authority
== 0)
610 g_b_init_get_sid_sub_authority
= 1;
611 hm_advapi32
= LoadLibrary ("Advapi32.dll");
612 s_pfn_Get_Sid_Sub_Authority
=
613 (GetSidSubAuthority_Proc
) GetProcAddress (
614 hm_advapi32
, "GetSidSubAuthority");
616 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
620 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
624 get_sid_sub_authority_count (PSID pSid
)
626 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
627 static UCHAR zero
= 0U;
628 HMODULE hm_advapi32
= NULL
;
629 if (is_windows_9x () == TRUE
)
633 if (g_b_init_get_sid_sub_authority_count
== 0)
635 g_b_init_get_sid_sub_authority_count
= 1;
636 hm_advapi32
= LoadLibrary ("Advapi32.dll");
637 s_pfn_Get_Sid_Sub_Authority_Count
=
638 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
639 hm_advapi32
, "GetSidSubAuthorityCount");
641 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
645 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
649 get_security_info (HANDLE handle
,
650 SE_OBJECT_TYPE ObjectType
,
651 SECURITY_INFORMATION SecurityInfo
,
656 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
)
658 static GetSecurityInfo_Proc s_pfn_Get_Security_Info
= NULL
;
659 HMODULE hm_advapi32
= NULL
;
660 if (is_windows_9x () == TRUE
)
664 if (g_b_init_get_security_info
== 0)
666 g_b_init_get_security_info
= 1;
667 hm_advapi32
= LoadLibrary ("Advapi32.dll");
668 s_pfn_Get_Security_Info
=
669 (GetSecurityInfo_Proc
) GetProcAddress (
670 hm_advapi32
, "GetSecurityInfo");
672 if (s_pfn_Get_Security_Info
== NULL
)
676 return (s_pfn_Get_Security_Info (handle
, ObjectType
, SecurityInfo
,
677 ppsidOwner
, ppsidGroup
, ppDacl
, ppSacl
,
678 ppSecurityDescriptor
));
682 get_file_security (LPCTSTR lpFileName
,
683 SECURITY_INFORMATION RequestedInformation
,
684 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
686 LPDWORD lpnLengthNeeded
)
688 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
689 HMODULE hm_advapi32
= NULL
;
690 if (is_windows_9x () == TRUE
)
695 if (g_b_init_get_file_security
== 0)
697 g_b_init_get_file_security
= 1;
698 hm_advapi32
= LoadLibrary ("Advapi32.dll");
699 s_pfn_Get_File_Security
=
700 (GetFileSecurity_Proc
) GetProcAddress (
701 hm_advapi32
, GetFileSecurity_Name
);
703 if (s_pfn_Get_File_Security
== NULL
)
708 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
709 pSecurityDescriptor
, nLength
,
714 set_file_security (LPCTSTR lpFileName
,
715 SECURITY_INFORMATION SecurityInformation
,
716 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
718 static SetFileSecurity_Proc s_pfn_Set_File_Security
= NULL
;
719 HMODULE hm_advapi32
= NULL
;
720 if (is_windows_9x () == TRUE
)
725 if (g_b_init_set_file_security
== 0)
727 g_b_init_set_file_security
= 1;
728 hm_advapi32
= LoadLibrary ("Advapi32.dll");
729 s_pfn_Set_File_Security
=
730 (SetFileSecurity_Proc
) GetProcAddress (
731 hm_advapi32
, SetFileSecurity_Name
);
733 if (s_pfn_Set_File_Security
== NULL
)
738 return (s_pfn_Set_File_Security (lpFileName
, SecurityInformation
,
739 pSecurityDescriptor
));
743 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
745 LPBOOL lpbOwnerDefaulted
)
747 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
748 HMODULE hm_advapi32
= NULL
;
749 if (is_windows_9x () == TRUE
)
754 if (g_b_init_get_security_descriptor_owner
== 0)
756 g_b_init_get_security_descriptor_owner
= 1;
757 hm_advapi32
= LoadLibrary ("Advapi32.dll");
758 s_pfn_Get_Security_Descriptor_Owner
=
759 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
760 hm_advapi32
, "GetSecurityDescriptorOwner");
762 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
767 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
772 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
774 LPBOOL lpbGroupDefaulted
)
776 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
777 HMODULE hm_advapi32
= NULL
;
778 if (is_windows_9x () == TRUE
)
783 if (g_b_init_get_security_descriptor_group
== 0)
785 g_b_init_get_security_descriptor_group
= 1;
786 hm_advapi32
= LoadLibrary ("Advapi32.dll");
787 s_pfn_Get_Security_Descriptor_Group
=
788 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
789 hm_advapi32
, "GetSecurityDescriptorGroup");
791 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
796 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
801 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
802 LPBOOL lpbDaclPresent
,
804 LPBOOL lpbDaclDefaulted
)
806 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl
= NULL
;
807 HMODULE hm_advapi32
= NULL
;
808 if (is_windows_9x () == TRUE
)
813 if (g_b_init_get_security_descriptor_dacl
== 0)
815 g_b_init_get_security_descriptor_dacl
= 1;
816 hm_advapi32
= LoadLibrary ("Advapi32.dll");
817 s_pfn_Get_Security_Descriptor_Dacl
=
818 (GetSecurityDescriptorDacl_Proc
) GetProcAddress (
819 hm_advapi32
, "GetSecurityDescriptorDacl");
821 if (s_pfn_Get_Security_Descriptor_Dacl
== NULL
)
826 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor
,
827 lpbDaclPresent
, pDacl
,
832 is_valid_sid (PSID sid
)
834 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
835 HMODULE hm_advapi32
= NULL
;
836 if (is_windows_9x () == TRUE
)
840 if (g_b_init_is_valid_sid
== 0)
842 g_b_init_is_valid_sid
= 1;
843 hm_advapi32
= LoadLibrary ("Advapi32.dll");
845 (IsValidSid_Proc
) GetProcAddress (
846 hm_advapi32
, "IsValidSid");
848 if (s_pfn_Is_Valid_Sid
== NULL
)
852 return (s_pfn_Is_Valid_Sid (sid
));
856 equal_sid (PSID sid1
, PSID sid2
)
858 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
859 HMODULE hm_advapi32
= NULL
;
860 if (is_windows_9x () == TRUE
)
864 if (g_b_init_equal_sid
== 0)
866 g_b_init_equal_sid
= 1;
867 hm_advapi32
= LoadLibrary ("Advapi32.dll");
869 (EqualSid_Proc
) GetProcAddress (
870 hm_advapi32
, "EqualSid");
872 if (s_pfn_Equal_Sid
== NULL
)
876 return (s_pfn_Equal_Sid (sid1
, sid2
));
880 get_length_sid (PSID sid
)
882 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
883 HMODULE hm_advapi32
= NULL
;
884 if (is_windows_9x () == TRUE
)
888 if (g_b_init_get_length_sid
== 0)
890 g_b_init_get_length_sid
= 1;
891 hm_advapi32
= LoadLibrary ("Advapi32.dll");
892 s_pfn_Get_Length_Sid
=
893 (GetLengthSid_Proc
) GetProcAddress (
894 hm_advapi32
, "GetLengthSid");
896 if (s_pfn_Get_Length_Sid
== NULL
)
900 return (s_pfn_Get_Length_Sid (sid
));
904 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
906 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
907 HMODULE hm_advapi32
= NULL
;
908 if (is_windows_9x () == TRUE
)
912 if (g_b_init_copy_sid
== 0)
914 g_b_init_copy_sid
= 1;
915 hm_advapi32
= LoadLibrary ("Advapi32.dll");
917 (CopySid_Proc
) GetProcAddress (
918 hm_advapi32
, "CopySid");
920 if (s_pfn_Copy_Sid
== NULL
)
924 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
928 END: Wrapper functions around OpenProcessToken
929 and other functions in advapi32.dll that are only
930 supported in Windows NT / 2k / XP
934 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
936 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
937 if (is_windows_9x () != TRUE
)
939 if (g_b_init_get_native_system_info
== 0)
941 g_b_init_get_native_system_info
= 1;
942 s_pfn_Get_Native_System_Info
=
943 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
944 "GetNativeSystemInfo");
946 if (s_pfn_Get_Native_System_Info
!= NULL
)
947 s_pfn_Get_Native_System_Info (lpSystemInfo
);
950 lpSystemInfo
->dwNumberOfProcessors
= -1;
954 get_system_times (LPFILETIME lpIdleTime
,
955 LPFILETIME lpKernelTime
,
956 LPFILETIME lpUserTime
)
958 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
959 if (is_windows_9x () == TRUE
)
963 if (g_b_init_get_system_times
== 0)
965 g_b_init_get_system_times
= 1;
966 s_pfn_Get_System_times
=
967 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
970 if (s_pfn_Get_System_times
== NULL
)
972 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
975 static BOOLEAN WINAPI
976 create_symbolic_link (LPTSTR lpSymlinkFilename
,
977 LPTSTR lpTargetFileName
,
980 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link
= NULL
;
983 if (is_windows_9x () == TRUE
)
988 if (g_b_init_create_symbolic_link
== 0)
990 g_b_init_create_symbolic_link
= 1;
992 s_pfn_Create_Symbolic_Link
=
993 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
994 "CreateSymbolicLinkW");
996 s_pfn_Create_Symbolic_Link
=
997 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
998 "CreateSymbolicLinkA");
1001 if (s_pfn_Create_Symbolic_Link
== NULL
)
1007 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
1009 /* If we were denied creation of the symlink, try again after
1010 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1013 TOKEN_PRIVILEGES priv_current
;
1015 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME
, TRUE
, &priv_current
))
1017 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
1019 restore_privilege (&priv_current
);
1027 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor
)
1029 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc
= NULL
;
1031 if (is_windows_9x () == TRUE
)
1037 if (g_b_init_is_valid_security_descriptor
== 0)
1039 g_b_init_is_valid_security_descriptor
= 1;
1040 s_pfn_Is_Valid_Security_Descriptor_Proc
=
1041 (IsValidSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1042 "IsValidSecurityDescriptor");
1044 if (s_pfn_Is_Valid_Security_Descriptor_Proc
== NULL
)
1050 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor
);
1054 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor
,
1055 DWORD RequestedStringSDRevision
,
1056 SECURITY_INFORMATION SecurityInformation
,
1057 LPTSTR
*StringSecurityDescriptor
,
1058 PULONG StringSecurityDescriptorLen
)
1060 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL
= NULL
;
1063 if (is_windows_9x () == TRUE
)
1069 if (g_b_init_convert_sd_to_sddl
== 0)
1071 g_b_init_convert_sd_to_sddl
= 1;
1073 s_pfn_Convert_SD_To_SDDL
=
1074 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1075 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1077 s_pfn_Convert_SD_To_SDDL
=
1078 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1079 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1082 if (s_pfn_Convert_SD_To_SDDL
== NULL
)
1088 retval
= s_pfn_Convert_SD_To_SDDL (SecurityDescriptor
,
1089 RequestedStringSDRevision
,
1090 SecurityInformation
,
1091 StringSecurityDescriptor
,
1092 StringSecurityDescriptorLen
);
1098 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor
,
1099 DWORD StringSDRevision
,
1100 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
1101 PULONG SecurityDescriptorSize
)
1103 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD
= NULL
;
1106 if (is_windows_9x () == TRUE
)
1112 if (g_b_init_convert_sddl_to_sd
== 0)
1114 g_b_init_convert_sddl_to_sd
= 1;
1116 s_pfn_Convert_SDDL_To_SD
=
1117 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1118 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1120 s_pfn_Convert_SDDL_To_SD
=
1121 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1122 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1125 if (s_pfn_Convert_SDDL_To_SD
== NULL
)
1131 retval
= s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor
,
1134 SecurityDescriptorSize
);
1140 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo
, PULONG pOutBufLen
)
1142 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info
= NULL
;
1143 HMODULE hm_iphlpapi
= NULL
;
1145 if (is_windows_9x () == TRUE
)
1146 return ERROR_NOT_SUPPORTED
;
1148 if (g_b_init_get_adapters_info
== 0)
1150 g_b_init_get_adapters_info
= 1;
1151 hm_iphlpapi
= LoadLibrary ("Iphlpapi.dll");
1153 s_pfn_Get_Adapters_Info
= (GetAdaptersInfo_Proc
)
1154 GetProcAddress (hm_iphlpapi
, "GetAdaptersInfo");
1156 if (s_pfn_Get_Adapters_Info
== NULL
)
1157 return ERROR_NOT_SUPPORTED
;
1158 return s_pfn_Get_Adapters_Info (pAdapterInfo
, pOutBufLen
);
1163 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1164 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1166 This is called from alloc.c:valid_pointer_p. */
1168 w32_valid_pointer_p (void *p
, int size
)
1171 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
1175 unsigned char *buf
= alloca (size
);
1176 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
1187 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1188 codepage defined by file-name-coding-system. */
1190 /* Current codepage for encoding file names. */
1191 static int file_name_codepage
;
1193 /* Produce a Windows ANSI codepage suitable for encoding file names.
1194 Return the information about that codepage in CP_INFO. */
1196 codepage_for_filenames (CPINFO
*cp_info
)
1198 /* A simple cache to avoid calling GetCPInfo every time we need to
1199 encode/decode a file name. The file-name encoding is not
1200 supposed to be changed too frequently, if ever. */
1201 static Lisp_Object last_file_name_encoding
;
1203 Lisp_Object current_encoding
;
1205 current_encoding
= Vfile_name_coding_system
;
1206 if (NILP (current_encoding
))
1207 current_encoding
= Vdefault_file_name_coding_system
;
1209 if (!EQ (last_file_name_encoding
, current_encoding
))
1211 /* Default to the current ANSI codepage. */
1212 file_name_codepage
= w32_ansi_code_page
;
1214 if (NILP (current_encoding
))
1216 char *cpname
= SDATA (SYMBOL_NAME (current_encoding
));
1217 char *cp
= NULL
, *end
;
1220 if (strncmp (cpname
, "cp", 2) == 0)
1222 else if (strncmp (cpname
, "windows-", 8) == 0)
1228 cpnum
= strtol (cp
, &end
, 10);
1229 if (cpnum
&& *end
== '\0' && end
- cp
>= 2)
1230 file_name_codepage
= cpnum
;
1234 if (!file_name_codepage
)
1235 file_name_codepage
= CP_ACP
; /* CP_ACP = 0, but let's not assume that */
1237 if (!GetCPInfo (file_name_codepage
, &cp
))
1239 file_name_codepage
= CP_ACP
;
1240 if (!GetCPInfo (file_name_codepage
, &cp
))
1247 return file_name_codepage
;
1251 filename_to_utf16 (const char *fn_in
, wchar_t *fn_out
)
1253 int result
= MultiByteToWideChar (CP_UTF8
, MB_ERR_INVALID_CHARS
, fn_in
, -1,
1258 DWORD err
= GetLastError ();
1262 case ERROR_INVALID_FLAGS
:
1263 case ERROR_INVALID_PARAMETER
:
1266 case ERROR_INSUFFICIENT_BUFFER
:
1267 case ERROR_NO_UNICODE_TRANSLATION
:
1278 filename_from_utf16 (const wchar_t *fn_in
, char *fn_out
)
1280 int result
= WideCharToMultiByte (CP_UTF8
, 0, fn_in
, -1,
1281 fn_out
, MAX_UTF8_PATH
, NULL
, NULL
);
1285 DWORD err
= GetLastError ();
1289 case ERROR_INVALID_FLAGS
:
1290 case ERROR_INVALID_PARAMETER
:
1293 case ERROR_INSUFFICIENT_BUFFER
:
1294 case ERROR_NO_UNICODE_TRANSLATION
:
1305 filename_to_ansi (const char *fn_in
, char *fn_out
)
1307 wchar_t fn_utf16
[MAXPATHLEN
];
1309 if (filename_to_utf16 (fn_in
, fn_utf16
) == 0)
1312 int codepage
= codepage_for_filenames (NULL
);
1314 result
= WideCharToMultiByte (codepage
, 0, fn_utf16
, -1,
1315 fn_out
, MAX_UTF8_PATH
, NULL
, NULL
);
1318 DWORD err
= GetLastError ();
1322 case ERROR_INVALID_FLAGS
:
1323 case ERROR_INVALID_PARAMETER
:
1326 case ERROR_INSUFFICIENT_BUFFER
:
1327 case ERROR_NO_UNICODE_TRANSLATION
:
1340 filename_from_ansi (const char *fn_in
, char *fn_out
)
1342 wchar_t fn_utf16
[MAXPATHLEN
];
1343 int codepage
= codepage_for_filenames (NULL
);
1344 int result
= MultiByteToWideChar (codepage
, MB_ERR_INVALID_CHARS
, fn_in
, -1,
1345 fn_utf16
, MAX_PATH
);
1349 DWORD err
= GetLastError ();
1353 case ERROR_INVALID_FLAGS
:
1354 case ERROR_INVALID_PARAMETER
:
1357 case ERROR_INSUFFICIENT_BUFFER
:
1358 case ERROR_NO_UNICODE_TRANSLATION
:
1365 return filename_from_utf16 (fn_utf16
, fn_out
);
1370 /* The directory where we started, in UTF-8. */
1371 static char startup_dir
[MAX_UTF8_PATH
];
1373 /* Get the current working directory. */
1375 getcwd (char *dir
, int dirsize
)
1382 if (dirsize
<= strlen (startup_dir
))
1388 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
1392 /* Emacs doesn't actually change directory itself, it stays in the
1393 same directory where it was started. */
1394 strcpy (dir
, startup_dir
);
1399 /* Emulate getloadavg. */
1401 struct load_sample
{
1408 /* Number of processors on this machine. */
1409 static unsigned num_of_processors
;
1411 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1412 static struct load_sample samples
[16*60];
1413 static int first_idx
= -1, last_idx
= -1;
1414 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
1419 int next_idx
= from
+ 1;
1421 if (next_idx
>= max_idx
)
1430 int prev_idx
= from
- 1;
1433 prev_idx
= max_idx
- 1;
1439 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
1441 SYSTEM_INFO sysinfo
;
1442 FILETIME ft_idle
, ft_user
, ft_kernel
;
1444 /* Initialize the number of processors on this machine. */
1445 if (num_of_processors
<= 0)
1447 get_native_system_info (&sysinfo
);
1448 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1449 if (num_of_processors
<= 0)
1451 GetSystemInfo (&sysinfo
);
1452 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1454 if (num_of_processors
<= 0)
1455 num_of_processors
= 1;
1458 /* TODO: Take into account threads that are ready to run, by
1459 sampling the "\System\Processor Queue Length" performance
1460 counter. The code below accounts only for threads that are
1461 actually running. */
1463 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
1465 ULARGE_INTEGER uidle
, ukernel
, uuser
;
1467 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
1468 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
1469 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
1470 *idle
= uidle
.QuadPart
;
1471 *kernel
= ukernel
.QuadPart
;
1472 *user
= uuser
.QuadPart
;
1482 /* Produce the load average for a given time interval, using the
1483 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1484 1-minute, 5-minute, or 15-minute average, respectively. */
1488 double retval
= -1.0;
1491 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
1492 time_t now
= samples
[last_idx
].sample_time
;
1494 if (first_idx
!= last_idx
)
1496 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
1498 tdiff
= difftime (now
, samples
[idx
].sample_time
);
1499 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
1502 samples
[last_idx
].kernel
+ samples
[last_idx
].user
1503 - (samples
[idx
].kernel
+ samples
[idx
].user
);
1504 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
1506 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
1509 if (idx
== first_idx
)
1518 getloadavg (double loadavg
[], int nelem
)
1521 ULONGLONG idle
, kernel
, user
;
1522 time_t now
= time (NULL
);
1524 /* Store another sample. We ignore samples that are less than 1 sec
1526 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
1528 sample_system_load (&idle
, &kernel
, &user
);
1529 last_idx
= buf_next (last_idx
);
1530 samples
[last_idx
].sample_time
= now
;
1531 samples
[last_idx
].idle
= idle
;
1532 samples
[last_idx
].kernel
= kernel
;
1533 samples
[last_idx
].user
= user
;
1534 /* If the buffer has more that 15 min worth of samples, discard
1536 if (first_idx
== -1)
1537 first_idx
= last_idx
;
1538 while (first_idx
!= last_idx
1539 && (difftime (now
, samples
[first_idx
].sample_time
)
1540 >= 15.0*60 + 2*DBL_EPSILON
*now
))
1541 first_idx
= buf_next (first_idx
);
1544 for (elem
= 0; elem
< nelem
; elem
++)
1546 double avg
= getavg (elem
);
1550 loadavg
[elem
] = avg
;
1556 /* Emulate getpwuid, getpwnam and others. */
1558 #define PASSWD_FIELD_SIZE 256
1560 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1561 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1562 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1563 static char dflt_passwd_dir
[MAX_UTF8_PATH
];
1564 static char dflt_passwd_shell
[MAX_UTF8_PATH
];
1566 static struct passwd dflt_passwd
=
1578 static char dflt_group_name
[GNLEN
+1];
1580 static struct group dflt_group
=
1582 /* When group information is not available, we return this as the
1583 group for all files. */
1591 return dflt_passwd
.pw_uid
;
1597 /* I could imagine arguing for checking to see whether the user is
1598 in the Administrators group and returning a UID of 0 for that
1599 case, but I don't know how wise that would be in the long run. */
1606 return dflt_passwd
.pw_gid
;
1616 getpwuid (unsigned uid
)
1618 if (uid
== dflt_passwd
.pw_uid
)
1619 return &dflt_passwd
;
1624 getgrgid (gid_t gid
)
1630 getpwnam (char *name
)
1634 pw
= getpwuid (getuid ());
1638 if (xstrcasecmp (name
, pw
->pw_name
))
1645 init_user_info (void)
1647 /* Find the user's real name by opening the process token and
1648 looking up the name associated with the user-sid in that token.
1650 Use the relative portion of the identifier authority value from
1651 the user-sid as the user id value (same for group id using the
1652 primary group sid from the process token). */
1654 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1655 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1656 DWORD glength
= sizeof (gname
);
1657 HANDLE token
= NULL
;
1658 SID_NAME_USE user_type
;
1659 unsigned char *buf
= NULL
;
1661 TOKEN_USER user_token
;
1662 TOKEN_PRIMARY_GROUP group_token
;
1665 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1668 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1669 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1671 buf
= xmalloc (blen
);
1672 result
= get_token_information (token
, TokenUser
,
1673 (LPVOID
)buf
, blen
, &needed
);
1676 memcpy (&user_token
, buf
, sizeof (user_token
));
1677 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1679 domain
, &dlength
, &user_type
);
1687 strcpy (dflt_passwd
.pw_name
, uname
);
1688 /* Determine a reasonable uid value. */
1689 if (xstrcasecmp ("administrator", uname
) == 0)
1691 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1692 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1696 /* Use the last sub-authority value of the RID, the relative
1697 portion of the SID, as user/group ID. */
1698 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1700 /* Get group id and name. */
1701 result
= get_token_information (token
, TokenPrimaryGroup
,
1702 (LPVOID
)buf
, blen
, &needed
);
1703 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1705 buf
= xrealloc (buf
, blen
= needed
);
1706 result
= get_token_information (token
, TokenPrimaryGroup
,
1707 (LPVOID
)buf
, blen
, &needed
);
1711 memcpy (&group_token
, buf
, sizeof (group_token
));
1712 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1713 dlength
= sizeof (domain
);
1714 /* If we can get at the real Primary Group name, use that.
1715 Otherwise, the default group name was already set to
1716 "None" in globals_of_w32. */
1717 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1718 gname
, &glength
, NULL
, &dlength
,
1720 strcpy (dflt_group_name
, gname
);
1723 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1726 /* If security calls are not supported (presumably because we
1727 are running under Windows 9X), fallback to this: */
1728 else if (GetUserName (uname
, &ulength
))
1730 strcpy (dflt_passwd
.pw_name
, uname
);
1731 if (xstrcasecmp ("administrator", uname
) == 0)
1732 dflt_passwd
.pw_uid
= 0;
1734 dflt_passwd
.pw_uid
= 123;
1735 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1739 strcpy (dflt_passwd
.pw_name
, "unknown");
1740 dflt_passwd
.pw_uid
= 123;
1741 dflt_passwd
.pw_gid
= 123;
1743 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1745 /* Set dir and shell from environment variables. */
1746 if (w32_unicode_filenames
)
1748 wchar_t *home
= _wgetenv (L
"HOME");
1749 wchar_t *shell
= _wgetenv (L
"SHELL");
1751 /* Ensure HOME and SHELL are defined. */
1756 filename_from_utf16 (home
, dflt_passwd
.pw_dir
);
1757 filename_from_utf16 (shell
, dflt_passwd
.pw_shell
);
1761 char *home
= getenv ("HOME");
1762 char *shell
= getenv ("SHELL");
1768 filename_from_ansi (home
, dflt_passwd
.pw_dir
);
1769 filename_from_ansi (shell
, dflt_passwd
.pw_shell
);
1774 CloseHandle (token
);
1780 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1781 return ((rand () << 15) | rand ());
1790 /* Return the maximum length in bytes of a multibyte character
1791 sequence encoded in the current ANSI codepage. This is required to
1792 correctly walk the encoded file names one character at a time. */
1794 max_filename_mbslen (void)
1798 codepage_for_filenames (&cp_info
);
1799 return cp_info
.MaxCharSize
;
1802 /* Normalize filename by converting all path separators to
1803 the specified separator. Also conditionally convert upper
1804 case path name components to lower case. */
1807 normalize_filename (register char *fp
, char path_sep
, int multibyte
)
1811 int dbcs_p
= max_filename_mbslen () > 1;
1813 /* Multibyte file names are in the Emacs internal representation, so
1814 we can traverse them by bytes with no problems. */
1818 /* Always lower-case drive letters a-z, even if the filesystem
1819 preserves case in filenames.
1820 This is so filenames can be compared by string comparison
1821 functions that are case-sensitive. Even case-preserving filesystems
1822 do not distinguish case in drive letters. */
1824 p2
= CharNextExA (file_name_codepage
, fp
, 0);
1828 if (*p2
== ':' && *fp
>= 'A' && *fp
<= 'Z')
1834 if (multibyte
|| NILP (Vw32_downcase_file_names
))
1838 if (*fp
== '/' || *fp
== '\\')
1843 fp
= CharNextExA (file_name_codepage
, fp
, 0);
1848 sep
= path_sep
; /* convert to this path separator */
1849 elem
= fp
; /* start of current path element */
1852 if (*fp
>= 'a' && *fp
<= 'z')
1853 elem
= 0; /* don't convert this element */
1855 if (*fp
== 0 || *fp
== ':')
1857 sep
= *fp
; /* restore current separator (or 0) */
1858 *fp
= '/'; /* after conversion of this element */
1861 if (*fp
== '/' || *fp
== '\\')
1863 if (elem
&& elem
!= fp
)
1865 *fp
= 0; /* temporary end of string */
1866 _mbslwr (elem
); /* while we convert to lower case */
1868 *fp
= sep
; /* convert (or restore) path separator */
1869 elem
= fp
+ 1; /* next element starts after separator */
1877 fp
= CharNextExA (file_name_codepage
, fp
, 0);
1882 /* Destructively turn backslashes into slashes. MULTIBYTE non-zero
1883 means the file name is a multibyte string in Emacs's internal
1886 dostounix_filename (register char *p
, int multibyte
)
1888 normalize_filename (p
, '/', multibyte
);
1891 /* Destructively turn slashes into backslashes. */
1893 unixtodos_filename (register char *p
)
1895 normalize_filename (p
, '\\', 0);
1898 /* Remove all CR's that are followed by a LF.
1899 (From msdos.c...probably should figure out a way to share it,
1900 although this code isn't going to ever change.) */
1902 crlf_to_lf (register int n
, register unsigned char *buf
)
1904 unsigned char *np
= buf
;
1905 unsigned char *startp
= buf
;
1906 unsigned char *endp
= buf
+ n
;
1910 while (buf
< endp
- 1)
1914 if (*(++buf
) != 0x0a)
1925 /* Parse the root part of file name, if present. Return length and
1926 optionally store pointer to char after root. */
1928 parse_root (char * name
, char ** pPath
)
1930 char * start
= name
;
1935 /* find the root name of the volume if given */
1936 if (isalpha (name
[0]) && name
[1] == ':')
1938 /* skip past drive specifier */
1940 if (IS_DIRECTORY_SEP (name
[0]))
1943 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1946 int dbcs_p
= max_filename_mbslen () > 1;
1951 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1954 name
= CharNextExA (file_name_codepage
, name
, 0);
1959 if (IS_DIRECTORY_SEP (name
[0]))
1966 return name
- start
;
1969 /* Get long base name for name; name is assumed to be absolute. */
1971 get_long_basename (char * name
, char * buf
, int size
)
1973 WIN32_FIND_DATA find_data
;
1977 /* must be valid filename, no wild cards or other invalid characters */
1978 if (_mbspbrk (name
, "*?|<>\""))
1981 dir_handle
= FindFirstFile (name
, &find_data
);
1982 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1984 if ((len
= strlen (find_data
.cFileName
)) < size
)
1985 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1988 FindClose (dir_handle
);
1993 /* Get long name for file, if possible (assumed to be absolute). */
1995 w32_get_long_filename (char * name
, char * buf
, int size
)
2000 char full
[ MAX_PATH
];
2003 len
= strlen (name
);
2004 if (len
>= MAX_PATH
)
2007 /* Use local copy for destructive modification. */
2008 memcpy (full
, name
, len
+1);
2009 unixtodos_filename (full
);
2011 /* Copy root part verbatim. */
2012 len
= parse_root (full
, &p
);
2013 memcpy (o
, full
, len
);
2018 while (p
!= NULL
&& *p
)
2021 p
= _mbschr (q
, '\\');
2023 len
= get_long_basename (full
, o
, size
);
2046 is_unc_volume (const char *filename
)
2048 const char *ptr
= filename
;
2050 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
2053 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
2059 /* Emulate the Posix unsetenv. */
2061 unsetenv (const char *name
)
2067 if (name
== NULL
|| *name
== '\0' || strchr (name
, '=') != NULL
)
2072 name_len
= strlen (name
);
2073 /* MS docs says an environment variable cannot be longer than 32K. */
2074 if (name_len
> 32767)
2079 /* It is safe to use 'alloca' with 32K size, since the stack is at
2080 least 2MB, and we set it to 8MB in the link command line. */
2081 var
= alloca (name_len
+ 2);
2082 strncpy (var
, name
, name_len
);
2083 var
[name_len
++] = '=';
2084 var
[name_len
] = '\0';
2085 return _putenv (var
);
2088 /* MS _putenv doesn't support removing a variable when the argument
2089 does not include the '=' character, so we fix that here. */
2091 sys_putenv (char *str
)
2093 const char *const name_end
= strchr (str
, '=');
2095 if (name_end
== NULL
)
2097 /* Remove the variable from the environment. */
2098 return unsetenv (str
);
2101 return _putenv (str
);
2104 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2107 w32_get_resource (char *key
, LPDWORD lpdwtype
)
2110 HKEY hrootkey
= NULL
;
2113 /* Check both the current user and the local machine to see if
2114 we have any resources. */
2116 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
2120 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
2121 && (lpvalue
= xmalloc (cbData
)) != NULL
2122 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
2124 RegCloseKey (hrootkey
);
2130 RegCloseKey (hrootkey
);
2133 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
2137 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
2138 && (lpvalue
= xmalloc (cbData
)) != NULL
2139 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
2141 RegCloseKey (hrootkey
);
2147 RegCloseKey (hrootkey
);
2153 char *get_emacs_configuration (void);
2156 init_environment (char ** argv
)
2158 static const char * const tempdirs
[] = {
2159 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2164 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
2166 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2167 temporary files and assume "/tmp" if $TMPDIR is unset, which
2168 will break on DOS/Windows. Refuse to work if we cannot find
2169 a directory, not even "c:/", usable for that purpose. */
2170 for (i
= 0; i
< imax
; i
++)
2172 const char *tmp
= tempdirs
[i
];
2175 tmp
= getenv (tmp
+ 1);
2176 /* Note that `access' can lie to us if the directory resides on a
2177 read-only filesystem, like CD-ROM or a write-protected floppy.
2178 The only way to be really sure is to actually create a file and
2179 see if it succeeds. But I think that's too much to ask. */
2181 /* MSVCRT's _access crashes with D_OK. */
2182 if (tmp
&& faccessat (AT_FDCWD
, tmp
, D_OK
, AT_EACCESS
) == 0)
2184 char * var
= alloca (strlen (tmp
) + 8);
2185 sprintf (var
, "TMPDIR=%s", tmp
);
2186 _putenv (strdup (var
));
2193 Fcons (build_string ("no usable temporary directories found!!"),
2195 "While setting TMPDIR: ");
2197 /* Check for environment variables and use registry settings if they
2198 don't exist. Fallback on default values where applicable. */
2203 char locale_name
[32];
2204 char default_home
[MAX_PATH
];
2207 static const struct env_entry
2213 /* If the default value is NULL, we will use the value from the
2214 outside environment or the Registry, but will not push the
2215 variable into the Emacs environment if it is defined neither
2216 in the Registry nor in the outside environment. */
2218 {"PRELOAD_WINSOCK", NULL
},
2219 {"emacs_dir", "C:/emacs"},
2220 {"EMACSLOADPATH", NULL
},
2221 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2222 {"EMACSDATA", NULL
},
2223 {"EMACSPATH", NULL
},
2230 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2232 /* We need to copy dflt_envvars[] and work on the copy because we
2233 don't want the dumped Emacs to inherit the values of
2234 environment variables we saw during dumping (which could be on
2235 a different system). The defaults above must be left intact. */
2236 struct env_entry env_vars
[N_ENV_VARS
];
2238 for (i
= 0; i
< N_ENV_VARS
; i
++)
2239 env_vars
[i
] = dflt_envvars
[i
];
2241 /* For backwards compatibility, check if a .emacs file exists in C:/
2242 If not, then we can try to default to the appdata directory under the
2243 user's profile, which is more likely to be writable. */
2244 if (faccessat (AT_FDCWD
, "C:/.emacs", F_OK
, AT_EACCESS
) != 0)
2246 HRESULT profile_result
;
2247 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2248 of Windows 95 and NT4 that have not been updated to include
2250 ShGetFolderPath_fn get_folder_path
;
2251 get_folder_path
= (ShGetFolderPath_fn
)
2252 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2254 if (get_folder_path
!= NULL
)
2256 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
2259 /* If we can't get the appdata dir, revert to old behavior. */
2260 if (profile_result
== S_OK
)
2262 env_vars
[0].def_value
= default_home
;
2268 /* Get default locale info and use it for LANG. */
2269 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
2270 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
2271 locale_name
, sizeof (locale_name
)))
2273 for (i
= 0; i
< N_ENV_VARS
; i
++)
2275 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
2277 env_vars
[i
].def_value
= locale_name
;
2283 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2285 /* Treat emacs_dir specially: set it unconditionally based on our
2289 char modname
[MAX_PATH
];
2291 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2293 if ((p
= _mbsrchr (modname
, '\\')) == NULL
)
2297 if ((p
= _mbsrchr (modname
, '\\'))
2298 /* From bin means installed Emacs, from src means uninstalled. */
2299 && (xstrcasecmp (p
, "\\bin") == 0 || xstrcasecmp (p
, "\\src") == 0))
2301 char buf
[SET_ENV_BUF_SIZE
];
2302 int within_build_tree
= xstrcasecmp (p
, "\\src") == 0;
2305 for (p
= modname
; *p
; p
= CharNext (p
))
2306 if (*p
== '\\') *p
= '/';
2308 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
2309 _putenv (strdup (buf
));
2310 /* If we are running from the Posix-like build tree, define
2311 SHELL to point to our own cmdproxy. The loop below will
2312 then disregard PATH_EXEC and the default value. */
2313 if (within_build_tree
)
2315 _snprintf (buf
, sizeof (buf
) - 1,
2316 "SHELL=%s/nt/cmdproxy.exe", modname
);
2317 _putenv (strdup (buf
));
2320 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
2322 /* FIXME: should use substring of get_emacs_configuration ().
2323 But I don't think the Windows build supports alpha, mips etc
2324 anymore, so have taken the easy option for now. */
2325 else if (p
&& (xstrcasecmp (p
, "\\i386") == 0
2326 || xstrcasecmp (p
, "\\AMD64") == 0))
2329 p
= _mbsrchr (modname
, '\\');
2333 p
= _mbsrchr (modname
, '\\');
2334 if (p
&& xstrcasecmp (p
, "\\src") == 0)
2336 char buf
[SET_ENV_BUF_SIZE
];
2339 for (p
= modname
; *p
; p
= CharNext (p
))
2340 if (*p
== '\\') *p
= '/';
2342 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
2343 _putenv (strdup (buf
));
2349 for (i
= 0; i
< N_ENV_VARS
; i
++)
2351 if (!getenv (env_vars
[i
].name
))
2354 char bufc
[SET_ENV_BUF_SIZE
];
2356 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
2357 /* Also ignore empty environment variables. */
2362 if (strcmp (env_vars
[i
].name
, "SHELL") == 0)
2364 /* Look for cmdproxy.exe in every directory in
2365 PATH_EXEC. FIXME: This does not find cmdproxy
2366 in nt/ when we run uninstalled. */
2367 char fname
[MAX_PATH
];
2368 const char *pstart
= PATH_EXEC
, *pend
;
2371 pend
= _mbschr (pstart
, ';');
2373 pend
= pstart
+ strlen (pstart
);
2374 /* Be defensive against series of ;;; characters. */
2377 strncpy (fname
, pstart
, pend
- pstart
);
2378 fname
[pend
- pstart
] = '/';
2379 strcpy (&fname
[pend
- pstart
+ 1], "cmdproxy.exe");
2380 ExpandEnvironmentStrings ((LPSTR
) fname
, bufc
,
2382 if (faccessat (AT_FDCWD
, bufc
, F_OK
, AT_EACCESS
)
2396 /* If not found in any directory, use the
2397 default as the last resort. */
2398 lpval
= env_vars
[i
].def_value
;
2399 dwType
= REG_EXPAND_SZ
;
2405 lpval
= env_vars
[i
].def_value
;
2406 dwType
= REG_EXPAND_SZ
;
2408 if (strcmp (env_vars
[i
].name
, "HOME") == 0 && !appdata
)
2409 Vdelayed_warnings_list
2410 = Fcons (listn (CONSTYPE_HEAP
, 2,
2411 intern ("initialization"),
2412 build_string ("Setting HOME to C:\\ by default is deprecated")),
2413 Vdelayed_warnings_list
);
2418 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
2420 if (dwType
== REG_EXPAND_SZ
)
2421 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
2422 else if (dwType
== REG_SZ
)
2423 strcpy (buf1
, lpval
);
2424 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
2426 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
2428 _putenv (strdup (buf2
));
2438 /* Rebuild system configuration to reflect invoking system. */
2439 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
2441 /* Another special case: on NT, the PATH variable is actually named
2442 "Path" although cmd.exe (perhaps NT itself) arranges for
2443 environment variable lookup and setting to be case insensitive.
2444 However, Emacs assumes a fully case sensitive environment, so we
2445 need to change "Path" to "PATH" to match the expectations of
2446 various elisp packages. We do this by the sneaky method of
2447 modifying the string in the C runtime environ entry.
2449 The same applies to COMSPEC. */
2453 for (envp
= environ
; *envp
; envp
++)
2454 if (_strnicmp (*envp
, "PATH=", 5) == 0)
2455 memcpy (*envp
, "PATH=", 5);
2456 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
2457 memcpy (*envp
, "COMSPEC=", 8);
2460 /* Remember the initial working directory for getcwd. */
2461 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2462 Does it matter anywhere in Emacs? */
2463 if (w32_unicode_filenames
)
2465 wchar_t wstartup_dir
[MAX_PATH
];
2467 if (!GetCurrentDirectoryW (MAX_PATH
, wstartup_dir
))
2469 filename_from_utf16 (wstartup_dir
, startup_dir
);
2473 char astartup_dir
[MAX_PATH
];
2475 if (!GetCurrentDirectoryA (MAX_PATH
, astartup_dir
))
2477 filename_from_ansi (astartup_dir
, startup_dir
);
2481 static char modname
[MAX_PATH
];
2483 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2488 /* Determine if there is a middle mouse button, to allow parse_button
2489 to decide whether right mouse events should be mouse-2 or
2491 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
2496 /* Called from expand-file-name when default-directory is not a string. */
2499 emacs_root_dir (void)
2501 static char root_dir
[FILENAME_MAX
];
2504 p
= getenv ("emacs_dir");
2507 strcpy (root_dir
, p
);
2508 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
2509 dostounix_filename (root_dir
, 0);
2513 /* We don't have scripts to automatically determine the system configuration
2514 for Emacs before it's compiled, and we don't want to have to make the
2515 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
2519 get_emacs_configuration (void)
2521 char *arch
, *oem
, *os
;
2523 static char configuration_buffer
[32];
2525 /* Determine the processor type. */
2526 switch (get_processor_type ())
2529 #ifdef PROCESSOR_INTEL_386
2530 case PROCESSOR_INTEL_386
:
2531 case PROCESSOR_INTEL_486
:
2532 case PROCESSOR_INTEL_PENTIUM
:
2540 #ifdef PROCESSOR_AMD_X8664
2541 case PROCESSOR_AMD_X8664
:
2546 #ifdef PROCESSOR_MIPS_R2000
2547 case PROCESSOR_MIPS_R2000
:
2548 case PROCESSOR_MIPS_R3000
:
2549 case PROCESSOR_MIPS_R4000
:
2554 #ifdef PROCESSOR_ALPHA_21064
2555 case PROCESSOR_ALPHA_21064
:
2565 /* Use the OEM field to reflect the compiler/library combination. */
2567 #define COMPILER_NAME "msvc"
2570 #define COMPILER_NAME "mingw"
2572 #define COMPILER_NAME "unknown"
2575 oem
= COMPILER_NAME
;
2577 switch (osinfo_cache
.dwPlatformId
) {
2578 case VER_PLATFORM_WIN32_NT
:
2580 build_num
= osinfo_cache
.dwBuildNumber
;
2582 case VER_PLATFORM_WIN32_WINDOWS
:
2583 if (osinfo_cache
.dwMinorVersion
== 0) {
2588 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
2590 case VER_PLATFORM_WIN32s
:
2591 /* Not supported, should not happen. */
2593 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
2601 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
2602 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
2603 get_w32_major_version (), get_w32_minor_version (), build_num
);
2605 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
2608 return configuration_buffer
;
2612 get_emacs_configuration_options (void)
2614 static char *options_buffer
;
2615 char cv
[32]; /* Enough for COMPILER_VERSION. */
2617 cv
, /* To be filled later. */
2621 #ifdef ENABLE_CHECKING
2622 " --enable-checking",
2624 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2625 with a starting space to save work here. */
2627 " --cflags", USER_CFLAGS
,
2630 " --ldflags", USER_LDFLAGS
,
2637 /* Work out the effective configure options for this build. */
2639 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2642 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2644 #define COMPILER_VERSION ""
2648 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
2649 return "Error: not enough space for compiler version";
2650 cv
[sizeof (cv
) - 1] = '\0';
2652 for (i
= 0; options
[i
]; i
++)
2653 size
+= strlen (options
[i
]);
2655 options_buffer
= xmalloc (size
+ 1);
2656 options_buffer
[0] = '\0';
2658 for (i
= 0; options
[i
]; i
++)
2659 strcat (options_buffer
, options
[i
]);
2661 return options_buffer
;
2665 #include <sys/timeb.h>
2667 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2669 gettimeofday (struct timeval
*__restrict tv
, struct timezone
*__restrict tz
)
2674 tv
->tv_sec
= tb
.time
;
2675 tv
->tv_usec
= tb
.millitm
* 1000L;
2676 /* Implementation note: _ftime sometimes doesn't update the dstflag
2677 according to the new timezone when the system timezone is
2678 changed. We could fix that by using GetSystemTime and
2679 GetTimeZoneInformation, but that doesn't seem necessary, since
2680 Emacs always calls gettimeofday with the 2nd argument NULL (see
2681 current_emacs_time). */
2684 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
2685 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
2690 /* Emulate fdutimens. */
2692 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2693 TIMESPEC[0] and TIMESPEC[1], respectively.
2694 FD must be either negative -- in which case it is ignored --
2695 or a file descriptor that is open on FILE.
2696 If FD is nonnegative, then FILE can be NULL, which means
2697 use just futimes instead of utimes.
2698 If TIMESPEC is null, FAIL.
2699 Return 0 on success, -1 (setting errno) on failure. */
2702 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
2709 if (fd
< 0 && !file
)
2714 /* _futime's prototype defines 2nd arg as having the type 'struct
2715 _utimbuf', while utime needs to accept 'struct utimbuf' for
2716 compatibility with Posix. So we need to use 2 different (but
2717 equivalent) types to avoid compiler warnings, sigh. */
2720 struct _utimbuf _ut
;
2722 _ut
.actime
= timespec
[0].tv_sec
;
2723 _ut
.modtime
= timespec
[1].tv_sec
;
2724 return _futime (fd
, &_ut
);
2730 ut
.actime
= timespec
[0].tv_sec
;
2731 ut
.modtime
= timespec
[1].tv_sec
;
2732 /* Call 'utime', which is implemented below, not the MS library
2733 function, which fails on directories. */
2734 return utime (file
, &ut
);
2739 /* ------------------------------------------------------------------------- */
2740 /* IO support and wrapper functions for the Windows API. */
2741 /* ------------------------------------------------------------------------- */
2743 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2744 on network directories, so we handle that case here.
2745 (Ulrich Leodolter, 1/11/95). */
2747 sys_ctime (const time_t *t
)
2749 char *str
= (char *) ctime (t
);
2750 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2753 /* Emulate sleep...we could have done this with a define, but that
2754 would necessitate including windows.h in the files that used it.
2755 This is much easier. */
2757 sys_sleep (int seconds
)
2759 Sleep (seconds
* 1000);
2762 /* Internal MSVC functions for low-level descriptor munging */
2763 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2764 extern int __cdecl
_free_osfhnd (int fd
);
2766 /* parallel array of private info on file handles */
2767 filedesc fd_info
[ MAXDESC
];
2769 typedef struct volume_info_data
{
2770 struct volume_info_data
* next
;
2772 /* time when info was obtained */
2775 /* actual volume info */
2784 /* Global referenced by various functions. */
2785 static volume_info_data volume_info
;
2787 /* Vector to indicate which drives are local and fixed (for which cached
2788 data never expires). */
2789 static BOOL fixed_drives
[26];
2791 /* Consider cached volume information to be stale if older than 10s,
2792 at least for non-local drives. Info for fixed drives is never stale. */
2793 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2794 #define VOLINFO_STILL_VALID( root_dir, info ) \
2795 ( ( isalpha (root_dir[0]) && \
2796 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2797 || GetTickCount () - info->timestamp < 10000 )
2799 /* Cache support functions. */
2801 /* Simple linked list with linear search is sufficient. */
2802 static volume_info_data
*volume_cache
= NULL
;
2804 static volume_info_data
*
2805 lookup_volume_info (char * root_dir
)
2807 volume_info_data
* info
;
2809 for (info
= volume_cache
; info
; info
= info
->next
)
2810 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2816 add_volume_info (char * root_dir
, volume_info_data
* info
)
2818 info
->root_dir
= xstrdup (root_dir
);
2819 info
->next
= volume_cache
;
2820 volume_cache
= info
;
2824 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2825 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2826 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2827 static volume_info_data
*
2828 GetCachedVolumeInformation (char * root_dir
)
2830 volume_info_data
* info
;
2831 char default_root
[ MAX_PATH
];
2833 /* NULL for root_dir means use root from current directory. */
2834 if (root_dir
== NULL
)
2836 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2838 parse_root (default_root
, &root_dir
);
2840 root_dir
= default_root
;
2843 /* Local fixed drives can be cached permanently. Removable drives
2844 cannot be cached permanently, since the volume name and serial
2845 number (if nothing else) can change. Remote drives should be
2846 treated as if they are removable, since there is no sure way to
2847 tell whether they are or not. Also, the UNC association of drive
2848 letters mapped to remote volumes can be changed at any time (even
2849 by other processes) without notice.
2851 As a compromise, so we can benefit from caching info for remote
2852 volumes, we use a simple expiry mechanism to invalidate cache
2853 entries that are more than ten seconds old. */
2856 /* No point doing this, because WNetGetConnection is even slower than
2857 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2858 GetDriveType is about the only call of this type which does not
2859 involve network access, and so is extremely quick). */
2861 /* Map drive letter to UNC if remote. */
2862 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2864 char remote_name
[ 256 ];
2865 char drive
[3] = { root_dir
[0], ':' };
2867 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2869 /* do something */ ;
2873 info
= lookup_volume_info (root_dir
);
2875 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2883 /* Info is not cached, or is stale. */
2884 if (!GetVolumeInformation (root_dir
,
2885 name
, sizeof (name
),
2889 type
, sizeof (type
)))
2892 /* Cache the volume information for future use, overwriting existing
2893 entry if present. */
2896 info
= xmalloc (sizeof (volume_info_data
));
2897 add_volume_info (root_dir
, info
);
2905 info
->name
= xstrdup (name
);
2906 info
->serialnum
= serialnum
;
2907 info
->maxcomp
= maxcomp
;
2908 info
->flags
= flags
;
2909 info
->type
= xstrdup (type
);
2910 info
->timestamp
= GetTickCount ();
2916 /* Get information on the volume where NAME is held; set path pointer to
2917 start of pathname in NAME (past UNC header\volume header if present),
2918 if pPath is non-NULL.
2920 Note: if NAME includes symlinks, the information is for the volume
2921 of the symlink, not of its target. That's because, even though
2922 GetVolumeInformation returns information about the symlink target
2923 of its argument, we only pass the root directory to
2924 GetVolumeInformation, not the full NAME. */
2926 get_volume_info (const char * name
, const char ** pPath
)
2928 char temp
[MAX_PATH
];
2929 char *rootname
= NULL
; /* default to current volume */
2930 volume_info_data
* info
;
2935 /* Find the root name of the volume if given. */
2936 if (isalpha (name
[0]) && name
[1] == ':')
2944 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2948 int dbcs_p
= max_filename_mbslen () > 1;
2953 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2959 const char *p
= name
;
2961 name
= CharNextExA (file_name_codepage
, name
, 0);
2962 memcpy (str
, p
, name
- p
);
2975 info
= GetCachedVolumeInformation (rootname
);
2978 /* Set global referenced by other functions. */
2979 volume_info
= *info
;
2985 /* Determine if volume is FAT format (ie. only supports short 8.3
2986 names); also set path pointer to start of pathname in name, if
2987 pPath is non-NULL. */
2989 is_fat_volume (const char * name
, const char ** pPath
)
2991 if (get_volume_info (name
, pPath
))
2992 return (volume_info
.maxcomp
== 12);
2996 /* Map filename to a valid 8.3 name if necessary.
2997 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2999 map_w32_filename (const char * name
, const char ** pPath
)
3001 static char shortname
[MAX_PATH
];
3002 char * str
= shortname
;
3005 const char * save_name
= name
;
3007 if (strlen (name
) >= MAX_PATH
)
3009 /* Return a filename which will cause callers to fail. */
3010 strcpy (shortname
, "?");
3014 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
3016 register int left
= 8; /* maximum number of chars in part */
3017 register int extn
= 0; /* extension added? */
3018 register int dots
= 2; /* maximum number of dots allowed */
3021 *str
++ = *name
++; /* skip past UNC header */
3023 while ((c
= *name
++))
3030 *str
++ = (c
== ':' ? ':' : '\\');
3031 extn
= 0; /* reset extension flags */
3032 dots
= 2; /* max 2 dots */
3033 left
= 8; /* max length 8 for main part */
3038 /* Convert path components of the form .xxx to _xxx,
3039 but leave . and .. as they are. This allows .emacs
3040 to be read as _emacs, for example. */
3044 IS_DIRECTORY_SEP (*name
))
3059 extn
= 1; /* we've got an extension */
3060 left
= 3; /* 3 chars in extension */
3064 /* any embedded dots after the first are converted to _ */
3069 case '#': /* don't lose these, they're important */
3071 str
[-1] = c
; /* replace last character of part */
3076 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
3078 dots
= 0; /* started a path component */
3087 strcpy (shortname
, name
);
3088 unixtodos_filename (shortname
);
3092 *pPath
= shortname
+ (path
- save_name
);
3098 is_exec (const char * name
)
3100 char * p
= strrchr (name
, '.');
3103 && (xstrcasecmp (p
, ".exe") == 0 ||
3104 xstrcasecmp (p
, ".com") == 0 ||
3105 xstrcasecmp (p
, ".bat") == 0 ||
3106 xstrcasecmp (p
, ".cmd") == 0));
3109 /* Emulate the Unix directory procedures opendir, closedir,
3110 and readdir. We can't use the procedures supplied in sysdep.c,
3111 so we provide them here. */
3113 struct dirent dir_static
; /* simulated directory contents */
3114 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
3115 static int dir_is_fat
;
3116 static char dir_pathname
[MAXPATHLEN
+1];
3117 static WIN32_FIND_DATA dir_find_data
;
3119 /* Support shares on a network resource as subdirectories of a read-only
3121 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
3122 static HANDLE
open_unc_volume (const char *);
3123 static char *read_unc_volume (HANDLE
, char *, int);
3124 static void close_unc_volume (HANDLE
);
3127 opendir (const char *filename
)
3131 /* Opening is done by FindFirstFile. However, a read is inherent to
3132 this operation, so we defer the open until read time. */
3134 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
3136 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
3139 /* Note: We don't support traversal of UNC volumes via symlinks.
3140 Doing so would mean punishing 99.99% of use cases by resolving
3141 all the possible symlinks in FILENAME, recursively. */
3142 if (is_unc_volume (filename
))
3144 wnet_enum_handle
= open_unc_volume (filename
);
3145 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
3149 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
3156 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
3157 dir_pathname
[MAXPATHLEN
] = '\0';
3158 /* Note: We don't support symlinks to file names on FAT volumes.
3159 Doing so would mean punishing 99.99% of use cases by resolving
3160 all the possible symlinks in FILENAME, recursively. */
3161 dir_is_fat
= is_fat_volume (filename
, NULL
);
3167 closedir (DIR *dirp
)
3169 /* If we have a find-handle open, close it. */
3170 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
3172 FindClose (dir_find_handle
);
3173 dir_find_handle
= INVALID_HANDLE_VALUE
;
3175 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
3177 close_unc_volume (wnet_enum_handle
);
3178 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
3180 xfree ((char *) dirp
);
3186 int downcase
= !NILP (Vw32_downcase_file_names
);
3188 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
3190 if (!read_unc_volume (wnet_enum_handle
,
3191 dir_find_data
.cFileName
,
3195 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3196 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
3198 char filename
[MAXNAMLEN
+ 3];
3200 int dbcs_p
= max_filename_mbslen () > 1;
3202 strcpy (filename
, dir_pathname
);
3203 ln
= strlen (filename
) - 1;
3206 if (!IS_DIRECTORY_SEP (filename
[ln
]))
3207 strcat (filename
, "\\");
3211 char *end
= filename
+ ln
+ 1;
3212 char *last_char
= CharPrevExA (file_name_codepage
, filename
, end
, 0);
3214 if (!IS_DIRECTORY_SEP (*last_char
))
3215 strcat (filename
, "\\");
3217 strcat (filename
, "*");
3219 /* Note: No need to resolve symlinks in FILENAME, because
3220 FindFirst opens the directory that is the target of a
3222 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
3224 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
3229 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
3233 /* Emacs never uses this value, so don't bother making it match
3234 value returned by stat(). */
3235 dir_static
.d_ino
= 1;
3237 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
3239 /* If the file name in cFileName[] includes `?' characters, it means
3240 the original file name used characters that cannot be represented
3241 by the current ANSI codepage. To avoid total lossage, retrieve
3242 the short 8+3 alias of the long file name. */
3243 if (_mbspbrk (dir_static
.d_name
, "?"))
3245 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
3246 downcase
= 1; /* 8+3 aliases are returned in all caps */
3248 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
3249 dir_static
.d_reclen
= sizeof (struct dirent
) - MAXNAMLEN
+ 3 +
3250 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
3252 /* If the file name in cFileName[] includes `?' characters, it means
3253 the original file name used characters that cannot be represented
3254 by the current ANSI codepage. To avoid total lossage, retrieve
3255 the short 8+3 alias of the long file name. */
3256 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
3258 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
3259 /* 8+3 aliases are returned in all caps, which could break
3260 various alists that look at filenames' extensions. */
3264 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
3265 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
3267 _mbslwr (dir_static
.d_name
);
3271 int dbcs_p
= max_filename_mbslen () > 1;
3272 for (p
= dir_static
.d_name
; *p
; )
3274 if (*p
>= 'a' && *p
<= 'z')
3277 p
= CharNextExA (file_name_codepage
, p
, 0);
3282 _mbslwr (dir_static
.d_name
);
3289 open_unc_volume (const char *path
)
3295 nr
.dwScope
= RESOURCE_GLOBALNET
;
3296 nr
.dwType
= RESOURCETYPE_DISK
;
3297 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
3298 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3299 nr
.lpLocalName
= NULL
;
3300 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
3301 nr
.lpComment
= NULL
;
3302 nr
.lpProvider
= NULL
;
3304 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
3305 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
3307 if (result
== NO_ERROR
)
3310 return INVALID_HANDLE_VALUE
;
3314 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
3318 DWORD bufsize
= 512;
3321 int dbcs_p
= max_filename_mbslen () > 1;
3324 buffer
= alloca (bufsize
);
3325 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
3326 if (result
!= NO_ERROR
)
3329 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3330 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
3333 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
3336 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
))
3337 ptr
= CharNextExA (file_name_codepage
, ptr
, 0);
3341 strncpy (readbuf
, ptr
, size
);
3346 close_unc_volume (HANDLE henum
)
3348 if (henum
!= INVALID_HANDLE_VALUE
)
3349 WNetCloseEnum (henum
);
3353 unc_volume_file_attributes (const char *path
)
3358 henum
= open_unc_volume (path
);
3359 if (henum
== INVALID_HANDLE_VALUE
)
3362 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
3364 close_unc_volume (henum
);
3369 /* Ensure a network connection is authenticated. */
3371 logon_network_drive (const char *path
)
3373 NETRESOURCE resource
;
3374 char share
[MAX_PATH
];
3381 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
3382 drvtype
= DRIVE_REMOTE
;
3383 else if (path
[0] == '\0' || path
[1] != ':')
3384 drvtype
= GetDriveType (NULL
);
3391 drvtype
= GetDriveType (drive
);
3394 /* Only logon to networked drives. */
3395 if (drvtype
!= DRIVE_REMOTE
)
3399 strncpy (share
, path
, MAX_PATH
);
3400 /* Truncate to just server and share name. */
3401 dbcs_p
= max_filename_mbslen () > 1;
3402 for (p
= share
+ 2; *p
&& p
< share
+ MAX_PATH
; )
3404 if (IS_DIRECTORY_SEP (*p
) && ++n_slashes
> 3)
3410 p
= CharNextExA (file_name_codepage
, p
, 0);
3415 resource
.dwType
= RESOURCETYPE_DISK
;
3416 resource
.lpLocalName
= NULL
;
3417 resource
.lpRemoteName
= share
;
3418 resource
.lpProvider
= NULL
;
3420 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
3423 /* Emulate faccessat(2). */
3425 faccessat (int dirfd
, const char * path
, int mode
, int flags
)
3429 if (dirfd
!= AT_FDCWD
3430 && !(IS_DIRECTORY_SEP (path
[0])
3431 || IS_DEVICE_SEP (path
[1])))
3437 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3438 newer versions blow up when passed D_OK. */
3439 path
= map_w32_filename (path
, NULL
);
3440 /* If the last element of PATH is a symlink, we need to resolve it
3441 to get the attributes of its target file. Note: any symlinks in
3442 PATH elements other than the last one are transparently resolved
3443 by GetFileAttributes below. */
3444 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0
3445 && (flags
& AT_SYMLINK_NOFOLLOW
) == 0)
3446 path
= chase_symlinks (path
);
3448 if ((attributes
= GetFileAttributes (path
)) == -1)
3450 DWORD w32err
= GetLastError ();
3454 case ERROR_INVALID_NAME
:
3455 case ERROR_BAD_PATHNAME
:
3456 if (is_unc_volume (path
))
3458 attributes
= unc_volume_file_attributes (path
);
3459 if (attributes
== -1)
3467 case ERROR_FILE_NOT_FOUND
:
3468 case ERROR_BAD_NETPATH
:
3477 if ((mode
& X_OK
) != 0
3478 && !(is_exec (path
) || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3483 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3488 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3496 /* Shadow some MSVC runtime functions to map requests for long filenames
3497 to reasonable short names if necessary. This was originally added to
3498 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3502 sys_chdir (const char * path
)
3504 /* FIXME: Temporary. Also, figure out what to do with
3505 map_w32_filename, as the original code did this:
3506 _chdir(map_w32_filename (path, NULL)). */
3507 if (w32_unicode_filenames
)
3509 wchar_t newdir
[MAXPATHLEN
];
3511 if (filename_to_utf16 (path
, newdir
) == 0)
3512 return _wchdir (newdir
);
3517 char newdir
[MAXPATHLEN
];
3519 if (filename_to_ansi (path
, newdir
) == 0)
3520 return _chdir (path
);
3526 sys_chmod (const char * path
, int mode
)
3528 path
= chase_symlinks (map_w32_filename (path
, NULL
));
3529 return _chmod (path
, mode
);
3533 sys_creat (const char * path
, int mode
)
3535 return _creat (map_w32_filename (path
, NULL
), mode
);
3539 sys_fopen (const char * path
, const char * mode
)
3543 const char * mode_save
= mode
;
3545 /* Force all file handles to be non-inheritable. This is necessary to
3546 ensure child processes don't unwittingly inherit handles that might
3547 prevent future file access. */
3551 else if (mode
[0] == 'w' || mode
[0] == 'a')
3552 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
3556 /* Only do simplistic option parsing. */
3560 oflag
&= ~(O_RDONLY
| O_WRONLY
);
3563 else if (mode
[0] == 'b')
3568 else if (mode
[0] == 't')
3575 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
3579 return _fdopen (fd
, mode_save
);
3582 /* This only works on NTFS volumes, but is useful to have. */
3584 sys_link (const char * old
, const char * new)
3588 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
3590 if (old
== NULL
|| new == NULL
)
3596 strcpy (oldname
, map_w32_filename (old
, NULL
));
3597 strcpy (newname
, map_w32_filename (new, NULL
));
3599 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
3600 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
3601 if (fileh
!= INVALID_HANDLE_VALUE
)
3605 /* Confusingly, the "alternate" stream name field does not apply
3606 when restoring a hard link, and instead contains the actual
3607 stream data for the link (ie. the name of the link to create).
3608 The WIN32_STREAM_ID structure before the cStreamName field is
3609 the stream header, which is then immediately followed by the
3613 WIN32_STREAM_ID wid
;
3614 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
3617 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
3618 data
.wid
.cStreamName
, MAX_PATH
);
3621 LPVOID context
= NULL
;
3624 data
.wid
.dwStreamId
= BACKUP_LINK
;
3625 data
.wid
.dwStreamAttributes
= 0;
3626 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
3627 data
.wid
.Size
.HighPart
= 0;
3628 data
.wid
.dwStreamNameSize
= 0;
3630 if (BackupWrite (fileh
, (LPBYTE
)&data
,
3631 offsetof (WIN32_STREAM_ID
, cStreamName
)
3632 + data
.wid
.Size
.LowPart
,
3633 &wbytes
, FALSE
, FALSE
, &context
)
3634 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
3641 /* Should try mapping GetLastError to errno; for now just
3642 indicate a general error (eg. links not supported). */
3643 errno
= EINVAL
; // perhaps EMLINK?
3647 CloseHandle (fileh
);
3656 sys_mkdir (const char * path
)
3658 return _mkdir (map_w32_filename (path
, NULL
));
3662 sys_open (const char * path
, int oflag
, int mode
)
3664 const char* mpath
= map_w32_filename (path
, NULL
);
3667 /* If possible, try to open file without _O_CREAT, to be able to
3668 write to existing hidden and system files. Force all file
3669 handles to be non-inheritable. */
3670 if ((oflag
& (_O_CREAT
| _O_EXCL
)) != (_O_CREAT
| _O_EXCL
))
3671 res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3673 res
= _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
3678 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
3681 Standard algorithm for generating a temporary file name seems to be
3682 use pid or tid with a letter on the front (in place of the 6 X's)
3683 and cycle through the letters to find a unique name. We extend
3684 that to allow any reasonable character as the first of the 6 X's,
3685 so that the number of simultaneously used temporary files will be
3689 mkostemp (char * template, int flags
)
3693 unsigned uid
= GetCurrentThreadId ();
3694 int save_errno
= errno
;
3695 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3698 if (template == NULL
)
3701 p
= template + strlen (template);
3703 /* replace up to the last 5 X's with uid in decimal */
3704 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
3706 p
[0] = '0' + uid
% 10;
3710 if (i
< 0 && p
[0] == 'X')
3715 p
[0] = first_char
[i
];
3716 if ((fd
= sys_open (template,
3717 flags
| _O_CREAT
| _O_EXCL
| _O_RDWR
,
3718 S_IRUSR
| S_IWUSR
)) >= 0
3726 while (++i
< sizeof (first_char
));
3729 /* Template is badly formed or else we can't generate a unique name. */
3734 fchmod (int fd
, mode_t mode
)
3740 sys_rename_replace (const char *oldname
, const char *newname
, BOOL force
)
3743 char temp
[MAX_PATH
];
3747 /* MoveFile on Windows 95 doesn't correctly change the short file name
3748 alias in a number of circumstances (it is not easy to predict when
3749 just by looking at oldname and newname, unfortunately). In these
3750 cases, renaming through a temporary name avoids the problem.
3752 A second problem on Windows 95 is that renaming through a temp name when
3753 newname is uppercase fails (the final long name ends up in
3754 lowercase, although the short alias might be uppercase) UNLESS the
3755 long temp name is not 8.3.
3757 So, on Windows 95 we always rename through a temp name, and we make sure
3758 the temp name has a long extension to ensure correct renaming. */
3760 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3762 /* volume_info is set indirectly by map_w32_filename. */
3763 oldname_dev
= volume_info
.serialnum
;
3765 if (os_subtype
== OS_9X
)
3771 oldname
= map_w32_filename (oldname
, NULL
);
3772 if ((o
= strrchr (oldname
, '\\')))
3775 o
= (char *) oldname
;
3777 if ((p
= strrchr (temp
, '\\')))
3784 /* Force temp name to require a manufactured 8.3 alias - this
3785 seems to make the second rename work properly. */
3786 sprintf (p
, "_.%s.%u", o
, i
);
3788 result
= rename (oldname
, temp
);
3790 /* This loop must surely terminate! */
3791 while (result
< 0 && errno
== EEXIST
);
3796 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3797 (at least if it is a file; don't do this for directories).
3799 Since we mustn't do this if we are just changing the case of the
3800 file name (we would end up deleting the file we are trying to
3801 rename!), we let rename detect if the destination file already
3802 exists - that way we avoid the possible pitfalls of trying to
3803 determine ourselves whether two names really refer to the same
3804 file, which is not always possible in the general case. (Consider
3805 all the permutations of shared or subst'd drives, etc.) */
3807 newname
= map_w32_filename (newname
, NULL
);
3809 /* volume_info is set indirectly by map_w32_filename. */
3810 newname_dev
= volume_info
.serialnum
;
3812 result
= rename (temp
, newname
);
3814 if (result
< 0 && force
)
3816 DWORD w32err
= GetLastError ();
3819 && newname_dev
!= oldname_dev
)
3821 /* The implementation of `rename' on Windows does not return
3822 errno = EXDEV when you are moving a directory to a
3823 different storage device (ex. logical disk). It returns
3824 EACCES instead. So here we handle such situations and
3828 if ((attributes
= GetFileAttributes (temp
)) != -1
3829 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3832 else if (errno
== EEXIST
)
3834 if (_chmod (newname
, 0666) != 0)
3836 if (_unlink (newname
) != 0)
3838 result
= rename (temp
, newname
);
3840 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
3841 && is_symlink (temp
))
3843 /* This is Windows prohibiting the user from creating a
3844 symlink in another place, since that requires
3854 sys_rename (char const *old
, char const *new)
3856 return sys_rename_replace (old
, new, TRUE
);
3860 sys_rmdir (const char * path
)
3862 return _rmdir (map_w32_filename (path
, NULL
));
3866 sys_unlink (const char * path
)
3868 path
= map_w32_filename (path
, NULL
);
3870 /* On Unix, unlink works without write permission. */
3871 _chmod (path
, 0666);
3872 return _unlink (path
);
3875 static FILETIME utc_base_ft
;
3876 static ULONGLONG utc_base
; /* In 100ns units */
3877 static int init
= 0;
3879 #define FILETIME_TO_U64(result, ft) \
3881 ULARGE_INTEGER uiTemp; \
3882 uiTemp.LowPart = (ft).dwLowDateTime; \
3883 uiTemp.HighPart = (ft).dwHighDateTime; \
3884 result = uiTemp.QuadPart; \
3888 initialize_utc_base (void)
3890 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3899 st
.wMilliseconds
= 0;
3901 SystemTimeToFileTime (&st
, &utc_base_ft
);
3902 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3906 convert_time (FILETIME ft
)
3912 initialize_utc_base ();
3916 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3919 FILETIME_TO_U64 (tmp
, ft
);
3920 return (time_t) ((tmp
- utc_base
) / 10000000L);
3924 convert_from_time_t (time_t time
, FILETIME
* pft
)
3930 initialize_utc_base ();
3934 /* time in 100ns units since 1-Jan-1601 */
3935 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3936 pft
->dwHighDateTime
= tmp
.HighPart
;
3937 pft
->dwLowDateTime
= tmp
.LowPart
;
3941 /* No reason to keep this; faking inode values either by hashing or even
3942 using the file index from GetInformationByHandle, is not perfect and
3943 so by default Emacs doesn't use the inode values on Windows.
3944 Instead, we now determine file-truename correctly (except for
3945 possible drive aliasing etc). */
3947 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3949 hashval (const unsigned char * str
)
3954 h
= (h
<< 4) + *str
++;
3960 /* Return the hash value of the canonical pathname, excluding the
3961 drive/UNC header, to get a hopefully unique inode number. */
3963 generate_inode_val (const char * name
)
3965 char fullname
[ MAX_PATH
];
3969 /* Get the truly canonical filename, if it exists. (Note: this
3970 doesn't resolve aliasing due to subst commands, or recognize hard
3972 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3975 parse_root (fullname
, &p
);
3976 /* Normal W32 filesystems are still case insensitive. */
3983 static PSECURITY_DESCRIPTOR
3984 get_file_security_desc_by_handle (HANDLE h
)
3986 PSECURITY_DESCRIPTOR psd
= NULL
;
3988 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3989 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3991 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
3992 NULL
, NULL
, NULL
, NULL
, &psd
);
3993 if (err
!= ERROR_SUCCESS
)
3999 static PSECURITY_DESCRIPTOR
4000 get_file_security_desc_by_name (const char *fname
)
4002 PSECURITY_DESCRIPTOR psd
= NULL
;
4004 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
4005 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
4007 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
4009 err
= GetLastError ();
4010 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
4014 psd
= xmalloc (sd_len
);
4015 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
4027 unsigned n_subauthorities
;
4029 /* Use the last sub-authority value of the RID, the relative
4030 portion of the SID, as user/group ID. */
4031 n_subauthorities
= *get_sid_sub_authority_count (sid
);
4032 if (n_subauthorities
< 1)
4033 return 0; /* the "World" RID */
4034 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
4037 /* Caching SID and account values for faster lokup. */
4041 struct w32_id
*next
;
4043 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
4046 static struct w32_id
*w32_idlist
;
4049 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
4051 struct w32_id
*tail
, *found
;
4053 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
4055 if (equal_sid ((PSID
)tail
->sid
, sid
))
4064 strcpy (name
, found
->name
);
4072 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
4075 struct w32_id
*new_entry
;
4077 /* We don't want to leave behind stale cache from when Emacs was
4081 sid_len
= get_length_sid (sid
);
4082 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
4085 new_entry
->rid
= id
;
4086 strcpy (new_entry
->name
, name
);
4087 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
4088 new_entry
->next
= w32_idlist
;
4089 w32_idlist
= new_entry
;
4098 get_name_and_id (PSECURITY_DESCRIPTOR psd
, unsigned *id
, char *nm
, int what
)
4102 SID_NAME_USE ignore
;
4104 DWORD name_len
= sizeof (name
);
4106 DWORD domain_len
= sizeof (domain
);
4111 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
4112 else if (what
== GID
)
4113 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
4117 if (!result
|| !is_valid_sid (sid
))
4119 else if (!w32_cached_id (sid
, id
, nm
))
4121 if (!lookup_account_sid (NULL
, sid
, name
, &name_len
,
4122 domain
, &domain_len
, &ignore
)
4123 || name_len
> UNLEN
+1)
4127 *id
= get_rid (sid
);
4129 w32_add_to_cache (sid
, *id
, name
);
4136 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
, struct stat
*st
)
4138 int dflt_usr
= 0, dflt_grp
= 0;
4147 if (get_name_and_id (psd
, &st
->st_uid
, st
->st_uname
, UID
))
4149 if (get_name_and_id (psd
, &st
->st_gid
, st
->st_gname
, GID
))
4152 /* Consider files to belong to current user/group, if we cannot get
4153 more accurate information. */
4156 st
->st_uid
= dflt_passwd
.pw_uid
;
4157 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
4161 st
->st_gid
= dflt_passwd
.pw_gid
;
4162 strcpy (st
->st_gname
, dflt_group
.gr_name
);
4166 /* Return non-zero if NAME is a potentially slow filesystem. */
4168 is_slow_fs (const char *name
)
4173 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
4174 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
4175 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
4176 devtype
= GetDriveType (NULL
); /* use root of current drive */
4179 /* GetDriveType needs the root directory of the drive. */
4180 strncpy (drive_root
, name
, 2);
4181 drive_root
[2] = '\\';
4182 drive_root
[3] = '\0';
4183 devtype
= GetDriveType (drive_root
);
4185 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
4188 /* If this is non-zero, the caller wants accurate information about
4189 file's owner and group, which could be expensive to get. */
4190 int w32_stat_get_owner_group
;
4192 /* MSVC stat function can't cope with UNC names and has other bugs, so
4193 replace it with our own. This also allows us to calculate consistent
4194 inode values and owner/group without hacks in the main Emacs code. */
4197 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
4199 char *name
, *save_name
, *r
;
4200 WIN32_FIND_DATA wfd
;
4202 unsigned __int64 fake_inode
= 0;
4205 int rootdir
= FALSE
;
4206 PSECURITY_DESCRIPTOR psd
= NULL
;
4207 int is_a_symlink
= 0;
4208 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
4209 DWORD access_rights
= 0;
4210 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
4211 FILETIME ctime
, atime
, wtime
;
4214 if (path
== NULL
|| buf
== NULL
)
4220 save_name
= name
= (char *) map_w32_filename (path
, &path
);
4221 /* Must be valid filename, no wild cards or other invalid
4222 characters. We use _mbspbrk to support multibyte strings that
4223 might look to strpbrk as if they included literal *, ?, and other
4224 characters mentioned below that are disallowed by Windows
4226 if (_mbspbrk (name
, "*?|<>\""))
4232 /* Remove trailing directory separator, unless name is the root
4233 directory of a drive or UNC volume in which case ensure there
4234 is a trailing separator. */
4235 len
= strlen (name
);
4236 name
= strcpy (alloca (len
+ 2), name
);
4238 /* Avoid a somewhat costly call to is_symlink if the filesystem
4239 doesn't support symlinks. */
4240 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
4241 is_a_symlink
= is_symlink (name
);
4243 /* Plan A: Open the file and get all the necessary information via
4244 the resulting handle. This solves several issues in one blow:
4246 . retrieves attributes for the target of a symlink, if needed
4247 . gets attributes of root directories and symlinks pointing to
4248 root directories, thus avoiding the need for special-casing
4249 these and detecting them by examining the file-name format
4250 . retrieves more accurate attributes (e.g., non-zero size for
4251 some directories, esp. directories that are junction points)
4252 . correctly resolves "c:/..", "/.." and similar file names
4253 . avoids run-time penalties for 99% of use cases
4255 Plan A is always tried first, unless the user asked not to (but
4256 if the file is a symlink and we need to follow links, we try Plan
4257 A even if the user asked not to).
4259 If Plan A fails, we go to Plan B (below), where various
4260 potentially expensive techniques must be used to handle "special"
4261 files such as UNC volumes etc. */
4262 if (!(NILP (Vw32_get_true_file_attributes
)
4263 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
4264 /* Following symlinks requires getting the info by handle. */
4265 || (is_a_symlink
&& follow_symlinks
))
4267 BY_HANDLE_FILE_INFORMATION info
;
4269 if (is_a_symlink
&& !follow_symlinks
)
4270 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
4271 /* READ_CONTROL access rights are required to get security info
4272 by handle. But if the OS doesn't support security in the
4273 first place, we don't need to try. */
4274 if (is_windows_9x () != TRUE
)
4275 access_rights
|= READ_CONTROL
;
4277 fh
= CreateFile (name
, access_rights
, 0, NULL
, OPEN_EXISTING
,
4279 /* If CreateFile fails with READ_CONTROL, try again with zero as
4281 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
4282 fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
4284 if (fh
== INVALID_HANDLE_VALUE
)
4285 goto no_true_file_attributes
;
4287 /* This is more accurate in terms of getting the correct number
4288 of links, but is quite slow (it is noticeable when Emacs is
4289 making a list of file name completions). */
4290 if (GetFileInformationByHandle (fh
, &info
))
4292 nlinks
= info
.nNumberOfLinks
;
4293 /* Might as well use file index to fake inode values, but this
4294 is not guaranteed to be unique unless we keep a handle open
4295 all the time (even then there are situations where it is
4296 not unique). Reputedly, there are at most 48 bits of info
4297 (on NTFS, presumably less on FAT). */
4298 fake_inode
= info
.nFileIndexHigh
;
4300 fake_inode
+= info
.nFileIndexLow
;
4301 serialnum
= info
.dwVolumeSerialNumber
;
4302 fs_high
= info
.nFileSizeHigh
;
4303 fs_low
= info
.nFileSizeLow
;
4304 ctime
= info
.ftCreationTime
;
4305 atime
= info
.ftLastAccessTime
;
4306 wtime
= info
.ftLastWriteTime
;
4307 fattrs
= info
.dwFileAttributes
;
4311 /* We don't go to Plan B here, because it's not clear that
4312 it's a good idea. The only known use case where
4313 CreateFile succeeds, but GetFileInformationByHandle fails
4314 (with ERROR_INVALID_FUNCTION) is for character devices
4315 such as NUL, PRN, etc. For these, switching to Plan B is
4316 a net loss, because we lose the character device
4317 attribute returned by GetFileType below (FindFirstFile
4318 doesn't set that bit in the attributes), and the other
4319 fields don't make sense for character devices anyway.
4320 Emacs doesn't really care for non-file entities in the
4321 context of l?stat, so neither do we. */
4323 /* w32err is assigned so one could put a breakpoint here and
4324 examine its value, when GetFileInformationByHandle
4326 DWORD w32err
= GetLastError ();
4330 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
4336 /* Test for a symlink before testing for a directory, since
4337 symlinks to directories have the directory bit set, but we
4338 don't want them to appear as directories. */
4339 if (is_a_symlink
&& !follow_symlinks
)
4340 buf
->st_mode
= S_IFLNK
;
4341 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4342 buf
->st_mode
= S_IFDIR
;
4345 DWORD ftype
= GetFileType (fh
);
4349 case FILE_TYPE_DISK
:
4350 buf
->st_mode
= S_IFREG
;
4352 case FILE_TYPE_PIPE
:
4353 buf
->st_mode
= S_IFIFO
;
4355 case FILE_TYPE_CHAR
:
4356 case FILE_TYPE_UNKNOWN
:
4358 buf
->st_mode
= S_IFCHR
;
4361 /* We produce the fallback owner and group data, based on the
4362 current user that runs Emacs, in the following cases:
4364 . caller didn't request owner and group info
4365 . this is Windows 9X
4366 . getting security by handle failed, and we need to produce
4367 information for the target of a symlink (this is better
4368 than producing a potentially misleading info about the
4371 If getting security by handle fails, and we don't need to
4372 resolve symlinks, we try getting security by name. */
4373 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4374 get_file_owner_and_group (NULL
, buf
);
4377 psd
= get_file_security_desc_by_handle (fh
);
4380 get_file_owner_and_group (psd
, buf
);
4383 else if (!(is_a_symlink
&& follow_symlinks
))
4385 psd
= get_file_security_desc_by_name (name
);
4386 get_file_owner_and_group (psd
, buf
);
4390 get_file_owner_and_group (NULL
, buf
);
4396 no_true_file_attributes
:
4397 /* Plan B: Either getting a handle on the file failed, or the
4398 caller explicitly asked us to not bother making this
4399 information more accurate.
4401 Implementation note: In Plan B, we never bother to resolve
4402 symlinks, even if we got here because we tried Plan A and
4403 failed. That's because, even if the caller asked for extra
4404 precision by setting Vw32_get_true_file_attributes to t,
4405 resolving symlinks requires acquiring a file handle to the
4406 symlink, which we already know will fail. And if the user
4407 did not ask for extra precision, resolving symlinks will fly
4408 in the face of that request, since the user then wants the
4409 lightweight version of the code. */
4410 dbcs_p
= max_filename_mbslen () > 1;
4411 rootdir
= (path
>= save_name
+ len
- 1
4412 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
4414 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4415 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
4416 if (IS_DIRECTORY_SEP (r
[0])
4417 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
4420 /* Note: If NAME is a symlink to the root of a UNC volume
4421 (i.e. "\\SERVER"), we will not detect that here, and we will
4422 return data about the symlink as result of FindFirst below.
4423 This is unfortunate, but that marginal use case does not
4424 justify a call to chase_symlinks which would impose a penalty
4425 on all the other use cases. (We get here for symlinks to
4426 roots of UNC volumes because CreateFile above fails for them,
4427 unlike with symlinks to root directories X:\ of drives.) */
4428 if (is_unc_volume (name
))
4430 fattrs
= unc_volume_file_attributes (name
);
4434 ctime
= atime
= wtime
= utc_base_ft
;
4440 if (!IS_DIRECTORY_SEP (name
[len
-1]))
4441 strcat (name
, "\\");
4445 char *end
= name
+ len
;
4446 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4448 if (!IS_DIRECTORY_SEP (*n
))
4449 strcat (name
, "\\");
4451 if (GetDriveType (name
) < 2)
4457 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
4458 ctime
= atime
= wtime
= utc_base_ft
;
4464 if (IS_DIRECTORY_SEP (name
[len
-1]))
4469 char *end
= name
+ len
;
4470 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4472 if (IS_DIRECTORY_SEP (*n
))
4476 /* (This is hacky, but helps when doing file completions on
4477 network drives.) Optimize by using information available from
4478 active readdir if possible. */
4479 len
= strlen (dir_pathname
);
4482 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
4487 char *end
= dir_pathname
+ len
;
4488 char *n
= CharPrevExA (file_name_codepage
, dir_pathname
, end
, 0);
4490 if (IS_DIRECTORY_SEP (*n
))
4493 if (dir_find_handle
!= INVALID_HANDLE_VALUE
4494 && !(is_a_symlink
&& follow_symlinks
)
4495 && strnicmp (save_name
, dir_pathname
, len
) == 0
4496 && IS_DIRECTORY_SEP (name
[len
])
4497 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
4499 /* This was the last entry returned by readdir. */
4500 wfd
= dir_find_data
;
4504 logon_network_drive (name
);
4506 fh
= FindFirstFile (name
, &wfd
);
4507 if (fh
== INVALID_HANDLE_VALUE
)
4514 /* Note: if NAME is a symlink, the information we get from
4515 FindFirstFile is for the symlink, not its target. */
4516 fattrs
= wfd
.dwFileAttributes
;
4517 ctime
= wfd
.ftCreationTime
;
4518 atime
= wfd
.ftLastAccessTime
;
4519 wtime
= wfd
.ftLastWriteTime
;
4520 fs_high
= wfd
.nFileSizeHigh
;
4521 fs_low
= wfd
.nFileSizeLow
;
4524 serialnum
= volume_info
.serialnum
;
4526 if (is_a_symlink
&& !follow_symlinks
)
4527 buf
->st_mode
= S_IFLNK
;
4528 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4529 buf
->st_mode
= S_IFDIR
;
4531 buf
->st_mode
= S_IFREG
;
4533 get_file_owner_and_group (NULL
, buf
);
4537 /* Not sure if there is any point in this. */
4538 if (!NILP (Vw32_generate_fake_inodes
))
4539 fake_inode
= generate_inode_val (name
);
4540 else if (fake_inode
== 0)
4542 /* For want of something better, try to make everything unique. */
4543 static DWORD gen_num
= 0;
4544 fake_inode
= ++gen_num
;
4548 buf
->st_ino
= fake_inode
;
4550 buf
->st_dev
= serialnum
;
4551 buf
->st_rdev
= serialnum
;
4553 buf
->st_size
= fs_high
;
4554 buf
->st_size
<<= 32;
4555 buf
->st_size
+= fs_low
;
4556 buf
->st_nlink
= nlinks
;
4558 /* Convert timestamps to Unix format. */
4559 buf
->st_mtime
= convert_time (wtime
);
4560 buf
->st_atime
= convert_time (atime
);
4561 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4562 buf
->st_ctime
= convert_time (ctime
);
4563 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4565 /* determine rwx permissions */
4566 if (is_a_symlink
&& !follow_symlinks
)
4567 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
4570 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
4571 permission
= S_IREAD
;
4573 permission
= S_IREAD
| S_IWRITE
;
4575 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4576 permission
|= S_IEXEC
;
4577 else if (is_exec (name
))
4578 permission
|= S_IEXEC
;
4581 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4587 stat (const char * path
, struct stat
* buf
)
4589 return stat_worker (path
, buf
, 1);
4593 lstat (const char * path
, struct stat
* buf
)
4595 return stat_worker (path
, buf
, 0);
4599 fstatat (int fd
, char const *name
, struct stat
*st
, int flags
)
4601 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4602 This is good enough for the current usage in Emacs, but is fragile.
4604 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4605 Gnulib does this and can serve as a model. */
4606 char fullname
[MAX_PATH
];
4610 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
4613 errno
= ENAMETOOLONG
;
4619 return stat_worker (name
, st
, ! (flags
& AT_SYMLINK_NOFOLLOW
));
4622 /* Provide fstat and utime as well as stat for consistent handling of
4625 fstat (int desc
, struct stat
* buf
)
4627 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
4628 BY_HANDLE_FILE_INFORMATION info
;
4629 unsigned __int64 fake_inode
;
4632 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
4634 case FILE_TYPE_DISK
:
4635 buf
->st_mode
= S_IFREG
;
4636 if (!GetFileInformationByHandle (fh
, &info
))
4642 case FILE_TYPE_PIPE
:
4643 buf
->st_mode
= S_IFIFO
;
4645 case FILE_TYPE_CHAR
:
4646 case FILE_TYPE_UNKNOWN
:
4648 buf
->st_mode
= S_IFCHR
;
4650 memset (&info
, 0, sizeof (info
));
4651 info
.dwFileAttributes
= 0;
4652 info
.ftCreationTime
= utc_base_ft
;
4653 info
.ftLastAccessTime
= utc_base_ft
;
4654 info
.ftLastWriteTime
= utc_base_ft
;
4657 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4658 buf
->st_mode
= S_IFDIR
;
4660 buf
->st_nlink
= info
.nNumberOfLinks
;
4661 /* Might as well use file index to fake inode values, but this
4662 is not guaranteed to be unique unless we keep a handle open
4663 all the time (even then there are situations where it is
4664 not unique). Reputedly, there are at most 48 bits of info
4665 (on NTFS, presumably less on FAT). */
4666 fake_inode
= info
.nFileIndexHigh
;
4668 fake_inode
+= info
.nFileIndexLow
;
4670 /* MSVC defines _ino_t to be short; other libc's might not. */
4671 if (sizeof (buf
->st_ino
) == 2)
4672 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
4674 buf
->st_ino
= fake_inode
;
4676 /* If the caller so requested, get the true file owner and group.
4677 Otherwise, consider the file to belong to the current user. */
4678 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4679 get_file_owner_and_group (NULL
, buf
);
4682 PSECURITY_DESCRIPTOR psd
= NULL
;
4684 psd
= get_file_security_desc_by_handle (fh
);
4687 get_file_owner_and_group (psd
, buf
);
4691 get_file_owner_and_group (NULL
, buf
);
4694 buf
->st_dev
= info
.dwVolumeSerialNumber
;
4695 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
4697 buf
->st_size
= info
.nFileSizeHigh
;
4698 buf
->st_size
<<= 32;
4699 buf
->st_size
+= info
.nFileSizeLow
;
4701 /* Convert timestamps to Unix format. */
4702 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
4703 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
4704 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4705 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
4706 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4708 /* determine rwx permissions */
4709 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
4710 permission
= S_IREAD
;
4712 permission
= S_IREAD
| S_IWRITE
;
4714 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4715 permission
|= S_IEXEC
;
4718 #if 0 /* no way of knowing the filename */
4719 char * p
= strrchr (name
, '.');
4721 (xstrcasecmp (p
, ".exe") == 0 ||
4722 xstrcasecmp (p
, ".com") == 0 ||
4723 xstrcasecmp (p
, ".bat") == 0 ||
4724 xstrcasecmp (p
, ".cmd") == 0))
4725 permission
|= S_IEXEC
;
4729 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4734 /* A version of 'utime' which handles directories as well as
4738 utime (const char *name
, struct utimbuf
*times
)
4740 struct utimbuf deftime
;
4747 deftime
.modtime
= deftime
.actime
= time (NULL
);
4751 /* Need write access to set times. */
4752 fh
= CreateFile (name
, FILE_WRITE_ATTRIBUTES
,
4753 /* If NAME specifies a directory, FILE_SHARE_DELETE
4754 allows other processes to delete files inside it,
4755 while we have the directory open. */
4756 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
4757 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
4758 if (fh
!= INVALID_HANDLE_VALUE
)
4760 convert_from_time_t (times
->actime
, &atime
);
4761 convert_from_time_t (times
->modtime
, &mtime
);
4762 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
4779 /* Symlink-related functions. */
4780 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4781 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4785 symlink (char const *filename
, char const *linkname
)
4787 char linkfn
[MAX_PATH
], *tgtfn
;
4789 int dir_access
, filename_ends_in_slash
;
4792 /* Diagnostics follows Posix as much as possible. */
4793 if (filename
== NULL
|| linkname
== NULL
)
4803 if (strlen (filename
) > MAX_PATH
|| strlen (linkname
) > MAX_PATH
)
4805 errno
= ENAMETOOLONG
;
4809 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
4810 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
4816 dbcs_p
= max_filename_mbslen () > 1;
4818 /* Note: since empty FILENAME was already rejected, we can safely
4819 refer to FILENAME[1]. */
4820 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
4822 /* Non-absolute FILENAME is understood as being relative to
4823 LINKNAME's directory. We need to prepend that directory to
4824 FILENAME to get correct results from faccessat below, since
4825 otherwise it will interpret FILENAME relative to the
4826 directory where the Emacs process runs. Note that
4827 make-symbolic-link always makes sure LINKNAME is a fully
4828 expanded file name. */
4830 char *p
= linkfn
+ strlen (linkfn
);
4834 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
4839 char *p1
= CharPrevExA (file_name_codepage
, linkfn
, p
, 0);
4841 while (p
> linkfn
&& !IS_ANY_SEP (*p1
))
4844 p1
= CharPrevExA (file_name_codepage
, linkfn
, p1
, 0);
4848 strncpy (tem
, linkfn
, p
- linkfn
);
4849 tem
[p
- linkfn
] = '\0';
4850 strcat (tem
, filename
);
4851 dir_access
= faccessat (AT_FDCWD
, tem
, D_OK
, AT_EACCESS
);
4854 dir_access
= faccessat (AT_FDCWD
, filename
, D_OK
, AT_EACCESS
);
4856 /* Since Windows distinguishes between symlinks to directories and
4857 to files, we provide a kludgy feature: if FILENAME doesn't
4858 exist, but ends in a slash, we create a symlink to directory. If
4859 FILENAME exists and is a directory, we always create a symlink to
4862 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
4865 const char *end
= filename
+ strlen (filename
);
4866 const char *n
= CharPrevExA (file_name_codepage
, filename
, end
, 0);
4868 filename_ends_in_slash
= IS_DIRECTORY_SEP (*n
);
4870 if (dir_access
== 0 || filename_ends_in_slash
)
4871 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
4873 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
4874 if (filename_ends_in_slash
)
4875 tgtfn
[strlen (tgtfn
) - 1] = '\0';
4878 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
4880 /* ENOSYS is set by create_symbolic_link, when it detects that
4881 the OS doesn't support the CreateSymbolicLink API. */
4882 if (errno
!= ENOSYS
)
4884 DWORD w32err
= GetLastError ();
4888 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4889 TGTFN point to the same file name, go figure. */
4891 case ERROR_FILE_EXISTS
:
4894 case ERROR_ACCESS_DENIED
:
4897 case ERROR_FILE_NOT_FOUND
:
4898 case ERROR_PATH_NOT_FOUND
:
4899 case ERROR_BAD_NETPATH
:
4900 case ERROR_INVALID_REPARSE_DATA
:
4903 case ERROR_DIRECTORY
:
4906 case ERROR_PRIVILEGE_NOT_HELD
:
4907 case ERROR_NOT_ALL_ASSIGNED
:
4910 case ERROR_DISK_FULL
:
4923 /* A quick inexpensive test of whether FILENAME identifies a file that
4924 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4925 must already be in the normalized form returned by
4928 Note: for repeated operations on many files, it is best to test
4929 whether the underlying volume actually supports symlinks, by
4930 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4931 avoid the call to this function if it doesn't. That's because the
4932 call to GetFileAttributes takes a non-negligible time, especially
4933 on non-local or removable filesystems. See stat_worker for an
4934 example of how to do that. */
4936 is_symlink (const char *filename
)
4939 WIN32_FIND_DATA wfd
;
4942 attrs
= GetFileAttributes (filename
);
4945 DWORD w32err
= GetLastError ();
4949 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
4951 case ERROR_ACCESS_DENIED
:
4954 case ERROR_FILE_NOT_FOUND
:
4955 case ERROR_PATH_NOT_FOUND
:
4962 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
4964 logon_network_drive (filename
);
4965 fh
= FindFirstFile (filename
, &wfd
);
4966 if (fh
== INVALID_HANDLE_VALUE
)
4969 return (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
4970 && (wfd
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
4973 /* If NAME identifies a symbolic link, copy into BUF the file name of
4974 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4975 null-terminate the target name, even if it fits. Return the number
4976 of bytes copied, or -1 if NAME is not a symlink or any error was
4977 encountered while resolving it. The file name copied into BUF is
4978 encoded in the current ANSI codepage. */
4980 readlink (const char *name
, char *buf
, size_t buf_size
)
4983 TOKEN_PRIVILEGES privs
;
4984 int restore_privs
= 0;
4999 path
= map_w32_filename (name
, NULL
);
5001 if (strlen (path
) > MAX_PATH
)
5003 errno
= ENAMETOOLONG
;
5008 if (is_windows_9x () == TRUE
5009 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
5010 || !is_symlink (path
))
5013 errno
= EINVAL
; /* not a symlink */
5017 /* Done with simple tests, now we're in for some _real_ work. */
5018 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
5020 /* Implementation note: From here and onward, don't return early,
5021 since that will fail to restore the original set of privileges of
5022 the calling thread. */
5024 retval
= -1; /* not too optimistic, are we? */
5026 /* Note: In the next call to CreateFile, we use zero as the 2nd
5027 argument because, when the symlink is a hidden/system file,
5028 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5029 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5030 and directory symlinks. */
5031 sh
= CreateFile (path
, 0, 0, NULL
, OPEN_EXISTING
,
5032 FILE_FLAG_OPEN_REPARSE_POINT
| FILE_FLAG_BACKUP_SEMANTICS
,
5034 if (sh
!= INVALID_HANDLE_VALUE
)
5036 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
5037 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
5040 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
5041 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
5044 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
5048 /* Copy the link target name, in wide characters, from
5049 reparse_data, then convert it to multibyte encoding in
5050 the current locale's codepage. */
5052 BYTE lname
[MAX_PATH
];
5055 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
5057 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
5058 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
5059 /* This updates file_name_codepage which we need below. */
5060 int dbcs_p
= max_filename_mbslen () > 1;
5062 /* According to MSDN, PrintNameLength does not include the
5063 terminating null character. */
5064 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
5065 memcpy (lwname
, lwname_src
, lwname_len
);
5066 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
5068 lname_len
= WideCharToMultiByte (file_name_codepage
, 0, lwname
, -1,
5069 lname
, MAX_PATH
, NULL
, NULL
);
5072 /* WideCharToMultiByte failed. */
5073 DWORD w32err1
= GetLastError ();
5077 case ERROR_INSUFFICIENT_BUFFER
:
5078 errno
= ENAMETOOLONG
;
5080 case ERROR_INVALID_PARAMETER
:
5083 case ERROR_NO_UNICODE_TRANSLATION
:
5093 size_t size_to_copy
= buf_size
;
5094 BYTE
*p
= lname
, *p2
;
5095 BYTE
*pend
= p
+ lname_len
;
5097 /* Normalize like dostounix_filename does, but we don't
5098 want to assume that lname is null-terminated. */
5100 p2
= CharNextExA (file_name_codepage
, p
, 0);
5103 if (*p
&& *p2
== ':' && *p
>= 'A' && *p
<= 'Z')
5114 p
= CharNextExA (file_name_codepage
, p
, 0);
5115 /* CharNextExA doesn't advance at null character. */
5122 /* Testing for null-terminated LNAME is paranoia:
5123 WideCharToMultiByte should always return a
5124 null-terminated string when its 4th argument is -1
5125 and its 3rd argument is null-terminated (which they
5127 if (lname
[lname_len
- 1] == '\0')
5129 if (lname_len
<= buf_size
)
5130 size_to_copy
= lname_len
;
5131 strncpy (buf
, lname
, size_to_copy
);
5133 retval
= size_to_copy
;
5140 /* CreateFile failed. */
5141 DWORD w32err2
= GetLastError ();
5145 case ERROR_FILE_NOT_FOUND
:
5146 case ERROR_PATH_NOT_FOUND
:
5149 case ERROR_ACCESS_DENIED
:
5150 case ERROR_TOO_MANY_OPEN_FILES
:
5160 restore_privilege (&privs
);
5168 readlinkat (int fd
, char const *name
, char *buffer
,
5171 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5172 as in fstatat. FIXME: Add proper support for readlinkat. */
5173 char fullname
[MAX_PATH
];
5177 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
5180 errno
= ENAMETOOLONG
;
5186 return readlink (name
, buffer
, buffer_size
);
5189 /* If FILE is a symlink, return its target (stored in a static
5190 buffer); otherwise return FILE.
5192 This function repeatedly resolves symlinks in the last component of
5193 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5194 until it arrives at a file whose last component is not a symlink,
5195 or some error occurs. It returns the target of the last
5196 successfully resolved symlink in the chain. If it succeeds to
5197 resolve even a single symlink, the value returned is an absolute
5198 file name with backslashes (result of GetFullPathName). By
5199 contrast, if the original FILE is returned, it is unaltered.
5201 Note: This function can set errno even if it succeeds.
5203 Implementation note: we only resolve the last portion ("basename")
5204 of the argument FILE and of each following file in the chain,
5205 disregarding any possible symlinks in its leading directories.
5206 This is because Windows system calls and library functions
5207 transparently resolve symlinks in leading directories and return
5208 correct information, as long as the basename is not a symlink. */
5210 chase_symlinks (const char *file
)
5212 static char target
[MAX_PATH
];
5213 char link
[MAX_PATH
];
5214 ssize_t res
, link_len
;
5218 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
5219 return (char *)file
;
5221 if ((link_len
= GetFullPathName (file
, MAX_PATH
, link
, NULL
)) == 0)
5222 return (char *)file
;
5224 dbcs_p
= max_filename_mbslen () > 1;
5228 /* Remove trailing slashes, as we want to resolve the last
5229 non-trivial part of the link name. */
5232 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
5233 link
[link_len
--] = '\0';
5235 else if (link_len
> 3)
5237 char *n
= CharPrevExA (file_name_codepage
, link
, link
+ link_len
, 0);
5239 while (n
>= link
+ 2 && IS_DIRECTORY_SEP (*n
))
5242 n
= CharPrevExA (file_name_codepage
, link
, n
, 0);
5246 res
= readlink (link
, target
, MAX_PATH
);
5250 if (!(IS_DEVICE_SEP (target
[1])
5251 || (IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1]))))
5253 /* Target is relative. Append it to the directory part of
5254 the symlink, then copy the result back to target. */
5255 char *p
= link
+ link_len
;
5259 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
5264 char *p1
= CharPrevExA (file_name_codepage
, link
, p
, 0);
5266 while (p
> link
&& !IS_ANY_SEP (*p1
))
5269 p1
= CharPrevExA (file_name_codepage
, link
, p1
, 0);
5273 strcpy (target
, link
);
5275 /* Resolve any "." and ".." to get a fully-qualified file name
5277 link_len
= GetFullPathName (target
, MAX_PATH
, link
, NULL
);
5279 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
5281 if (loop_count
> 100)
5284 if (target
[0] == '\0') /* not a single call to readlink succeeded */
5285 return (char *)file
;
5290 /* Posix ACL emulation. */
5293 acl_valid (acl_t acl
)
5295 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR
)acl
) ? 0 : -1;
5299 acl_to_text (acl_t acl
, ssize_t
*size
)
5302 SECURITY_INFORMATION flags
=
5303 OWNER_SECURITY_INFORMATION
|
5304 GROUP_SECURITY_INFORMATION
|
5305 DACL_SECURITY_INFORMATION
;
5306 char *retval
= NULL
;
5312 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR
)acl
, SDDL_REVISION_1
, flags
, &str_acl
, &local_size
))
5315 /* We don't want to mix heaps, so we duplicate the string in our
5316 heap and free the one allocated by the API. */
5317 retval
= xstrdup (str_acl
);
5320 LocalFree (str_acl
);
5322 else if (errno
!= ENOTSUP
)
5329 acl_from_text (const char *acl_str
)
5331 PSECURITY_DESCRIPTOR psd
, retval
= NULL
;
5337 if (convert_sddl_to_sd (acl_str
, SDDL_REVISION_1
, &psd
, &sd_size
))
5340 retval
= xmalloc (sd_size
);
5341 memcpy (retval
, psd
, sd_size
);
5344 else if (errno
!= ENOTSUP
)
5351 acl_free (void *ptr
)
5358 acl_get_file (const char *fname
, acl_type_t type
)
5360 PSECURITY_DESCRIPTOR psd
= NULL
;
5361 const char *filename
;
5363 if (type
== ACL_TYPE_ACCESS
)
5366 SECURITY_INFORMATION si
=
5367 OWNER_SECURITY_INFORMATION
|
5368 GROUP_SECURITY_INFORMATION
|
5369 DACL_SECURITY_INFORMATION
;
5372 filename
= map_w32_filename (fname
, NULL
);
5373 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5374 fname
= chase_symlinks (filename
);
5379 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
)
5380 && errno
!= ENOTSUP
)
5382 err
= GetLastError ();
5383 if (err
== ERROR_INSUFFICIENT_BUFFER
)
5385 psd
= xmalloc (sd_len
);
5386 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
5393 else if (err
== ERROR_FILE_NOT_FOUND
5394 || err
== ERROR_PATH_NOT_FOUND
)
5402 else if (type
!= ACL_TYPE_DEFAULT
)
5409 acl_set_file (const char *fname
, acl_type_t type
, acl_t acl
)
5411 TOKEN_PRIVILEGES old1
, old2
;
5413 int st
= 0, retval
= -1;
5414 SECURITY_INFORMATION flags
= 0;
5420 const char *filename
;
5422 if (acl_valid (acl
) != 0
5423 || (type
!= ACL_TYPE_DEFAULT
&& type
!= ACL_TYPE_ACCESS
))
5429 if (type
== ACL_TYPE_DEFAULT
)
5435 filename
= map_w32_filename (fname
, NULL
);
5436 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5437 fname
= chase_symlinks (filename
);
5441 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5443 flags
|= OWNER_SECURITY_INFORMATION
;
5444 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5446 flags
|= GROUP_SECURITY_INFORMATION
;
5447 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR
)acl
, &dacl_present
,
5450 flags
|= DACL_SECURITY_INFORMATION
;
5454 /* According to KB-245153, setting the owner will succeed if either:
5455 (1) the caller is the user who will be the new owner, and has the
5456 SE_TAKE_OWNERSHIP privilege, or
5457 (2) the caller has the SE_RESTORE privilege, in which case she can
5458 set any valid user or group as the owner
5460 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5461 privileges, and disregard any failures in obtaining them. If
5462 these privileges cannot be obtained, and do not already exist in
5463 the calling thread's security token, this function could fail
5465 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME
, TRUE
, &old1
))
5467 if (enable_privilege (SE_RESTORE_NAME
, TRUE
, &old2
))
5472 if (!set_file_security ((char *)fname
, flags
, (PSECURITY_DESCRIPTOR
)acl
))
5474 err
= GetLastError ();
5476 if (errno
== ENOTSUP
)
5478 else if (err
== ERROR_INVALID_OWNER
5479 || err
== ERROR_NOT_ALL_ASSIGNED
5480 || err
== ERROR_ACCESS_DENIED
)
5482 /* Maybe the requested ACL and the one the file already has
5483 are identical, in which case we can silently ignore the
5484 failure. (And no, Windows doesn't.) */
5485 acl_t current_acl
= acl_get_file (fname
, ACL_TYPE_ACCESS
);
5490 char *acl_from
= acl_to_text (current_acl
, NULL
);
5491 char *acl_to
= acl_to_text (acl
, NULL
);
5493 if (acl_from
&& acl_to
&& xstrcasecmp (acl_from
, acl_to
) == 0)
5499 acl_free (acl_from
);
5502 acl_free (current_acl
);
5505 else if (err
== ERROR_FILE_NOT_FOUND
|| err
== ERROR_PATH_NOT_FOUND
)
5519 restore_privilege (&old2
);
5520 restore_privilege (&old1
);
5528 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5529 have a fixed max size for file names, so we don't need the kind of
5530 alloc/malloc/realloc dance the gnulib version does. We also don't
5531 support FD-relative symlinks. */
5533 careadlinkat (int fd
, char const *filename
,
5534 char *buffer
, size_t buffer_size
,
5535 struct allocator
const *alloc
,
5536 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
5538 char linkname
[MAX_PATH
];
5541 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
5545 char *retval
= buffer
;
5547 linkname
[link_size
++] = '\0';
5548 if (link_size
> buffer_size
)
5549 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
5551 memcpy (retval
, linkname
, link_size
);
5559 /* Support for browsing other processes and their attributes. See
5560 process.c for the Lisp bindings. */
5562 /* Helper wrapper functions. */
5564 static HANDLE WINAPI
5565 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
5567 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
5569 if (g_b_init_create_toolhelp32_snapshot
== 0)
5571 g_b_init_create_toolhelp32_snapshot
= 1;
5572 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
5573 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5574 "CreateToolhelp32Snapshot");
5576 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
5578 return INVALID_HANDLE_VALUE
;
5580 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
5584 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5586 static Process32First_Proc s_pfn_Process32_First
= NULL
;
5588 if (g_b_init_process32_first
== 0)
5590 g_b_init_process32_first
= 1;
5591 s_pfn_Process32_First
= (Process32First_Proc
)
5592 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5595 if (s_pfn_Process32_First
== NULL
)
5599 return (s_pfn_Process32_First (hSnapshot
, lppe
));
5603 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5605 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
5607 if (g_b_init_process32_next
== 0)
5609 g_b_init_process32_next
= 1;
5610 s_pfn_Process32_Next
= (Process32Next_Proc
)
5611 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5614 if (s_pfn_Process32_Next
== NULL
)
5618 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
5622 open_thread_token (HANDLE ThreadHandle
,
5623 DWORD DesiredAccess
,
5625 PHANDLE TokenHandle
)
5627 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
5628 HMODULE hm_advapi32
= NULL
;
5629 if (is_windows_9x () == TRUE
)
5631 SetLastError (ERROR_NOT_SUPPORTED
);
5634 if (g_b_init_open_thread_token
== 0)
5636 g_b_init_open_thread_token
= 1;
5637 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5638 s_pfn_Open_Thread_Token
=
5639 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
5641 if (s_pfn_Open_Thread_Token
== NULL
)
5643 SetLastError (ERROR_NOT_SUPPORTED
);
5647 s_pfn_Open_Thread_Token (
5656 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
5658 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
5659 HMODULE hm_advapi32
= NULL
;
5660 if (is_windows_9x () == TRUE
)
5664 if (g_b_init_impersonate_self
== 0)
5666 g_b_init_impersonate_self
= 1;
5667 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5668 s_pfn_Impersonate_Self
=
5669 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
5671 if (s_pfn_Impersonate_Self
== NULL
)
5675 return s_pfn_Impersonate_Self (ImpersonationLevel
);
5679 revert_to_self (void)
5681 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
5682 HMODULE hm_advapi32
= NULL
;
5683 if (is_windows_9x () == TRUE
)
5687 if (g_b_init_revert_to_self
== 0)
5689 g_b_init_revert_to_self
= 1;
5690 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5691 s_pfn_Revert_To_Self
=
5692 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
5694 if (s_pfn_Revert_To_Self
== NULL
)
5698 return s_pfn_Revert_To_Self ();
5702 get_process_memory_info (HANDLE h_proc
,
5703 PPROCESS_MEMORY_COUNTERS mem_counters
,
5706 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
5707 HMODULE hm_psapi
= NULL
;
5708 if (is_windows_9x () == TRUE
)
5712 if (g_b_init_get_process_memory_info
== 0)
5714 g_b_init_get_process_memory_info
= 1;
5715 hm_psapi
= LoadLibrary ("Psapi.dll");
5717 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
5718 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
5720 if (s_pfn_Get_Process_Memory_Info
== NULL
)
5724 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
5728 get_process_working_set_size (HANDLE h_proc
,
5732 static GetProcessWorkingSetSize_Proc
5733 s_pfn_Get_Process_Working_Set_Size
= NULL
;
5735 if (is_windows_9x () == TRUE
)
5739 if (g_b_init_get_process_working_set_size
== 0)
5741 g_b_init_get_process_working_set_size
= 1;
5742 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
5743 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5744 "GetProcessWorkingSetSize");
5746 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
5750 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
5754 global_memory_status (MEMORYSTATUS
*buf
)
5756 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
5758 if (is_windows_9x () == TRUE
)
5762 if (g_b_init_global_memory_status
== 0)
5764 g_b_init_global_memory_status
= 1;
5765 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
5766 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5767 "GlobalMemoryStatus");
5769 if (s_pfn_Global_Memory_Status
== NULL
)
5773 return s_pfn_Global_Memory_Status (buf
);
5777 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
5779 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
5781 if (is_windows_9x () == TRUE
)
5785 if (g_b_init_global_memory_status_ex
== 0)
5787 g_b_init_global_memory_status_ex
= 1;
5788 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
5789 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5790 "GlobalMemoryStatusEx");
5792 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
5796 return s_pfn_Global_Memory_Status_Ex (buf
);
5800 list_system_processes (void)
5802 struct gcpro gcpro1
;
5803 Lisp_Object proclist
= Qnil
;
5806 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
5808 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
5810 PROCESSENTRY32 proc_entry
;
5816 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
5817 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
5818 res
= process32_next (h_snapshot
, &proc_entry
))
5820 proc_id
= proc_entry
.th32ProcessID
;
5821 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
5824 CloseHandle (h_snapshot
);
5826 proclist
= Fnreverse (proclist
);
5833 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
5835 TOKEN_PRIVILEGES priv
;
5836 DWORD priv_size
= sizeof (priv
);
5837 DWORD opriv_size
= sizeof (*old_priv
);
5838 HANDLE h_token
= NULL
;
5839 HANDLE h_thread
= GetCurrentThread ();
5843 res
= open_thread_token (h_thread
,
5844 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5846 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
5848 if (impersonate_self (SecurityImpersonation
))
5849 res
= open_thread_token (h_thread
,
5850 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5855 priv
.PrivilegeCount
= 1;
5856 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
5857 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
5858 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
5859 old_priv
, &opriv_size
)
5860 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
5864 CloseHandle (h_token
);
5870 restore_privilege (TOKEN_PRIVILEGES
*priv
)
5872 DWORD priv_size
= sizeof (*priv
);
5873 HANDLE h_token
= NULL
;
5876 if (open_thread_token (GetCurrentThread (),
5877 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5880 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
5881 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
5885 CloseHandle (h_token
);
5891 ltime (ULONGLONG time_100ns
)
5893 ULONGLONG time_sec
= time_100ns
/ 10000000;
5894 int subsec
= time_100ns
% 10000000;
5895 return list4i (time_sec
>> 16, time_sec
& 0xffff,
5896 subsec
/ 10, subsec
% 10 * 100000);
5899 #define U64_TO_LISP_TIME(time) ltime (time)
5902 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
5903 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
5906 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
5907 ULONGLONG tem1
, tem2
, tem3
, tem
;
5910 || !get_process_times_fn
5911 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
5912 &ft_kernel
, &ft_user
))
5915 GetSystemTimeAsFileTime (&ft_current
);
5917 FILETIME_TO_U64 (tem1
, ft_kernel
);
5918 *stime
= U64_TO_LISP_TIME (tem1
);
5920 FILETIME_TO_U64 (tem2
, ft_user
);
5921 *utime
= U64_TO_LISP_TIME (tem2
);
5924 *ttime
= U64_TO_LISP_TIME (tem3
);
5926 FILETIME_TO_U64 (tem
, ft_creation
);
5927 /* Process no 4 (System) returns zero creation time. */
5930 *ctime
= U64_TO_LISP_TIME (tem
);
5934 FILETIME_TO_U64 (tem3
, ft_current
);
5935 tem
= (tem3
- utc_base
) - tem
;
5937 *etime
= U64_TO_LISP_TIME (tem
);
5941 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
5952 system_process_attributes (Lisp_Object pid
)
5954 struct gcpro gcpro1
, gcpro2
, gcpro3
;
5955 Lisp_Object attrs
= Qnil
;
5956 Lisp_Object cmd_str
, decoded_cmd
, tem
;
5957 HANDLE h_snapshot
, h_proc
;
5960 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
5961 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
5962 DWORD glength
= sizeof (gname
);
5963 HANDLE token
= NULL
;
5964 SID_NAME_USE user_type
;
5965 unsigned char *buf
= NULL
;
5967 TOKEN_USER user_token
;
5968 TOKEN_PRIMARY_GROUP group_token
;
5971 PROCESS_MEMORY_COUNTERS mem
;
5972 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
5973 SIZE_T minrss
, maxrss
;
5975 MEMORY_STATUS_EX memstex
;
5976 double totphys
= 0.0;
5977 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
5979 BOOL result
= FALSE
;
5981 CHECK_NUMBER_OR_FLOAT (pid
);
5982 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
5984 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
5986 GCPRO3 (attrs
, decoded_cmd
, tem
);
5988 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
5993 pe
.dwSize
= sizeof (PROCESSENTRY32
);
5994 for (res
= process32_first (h_snapshot
, &pe
); res
;
5995 res
= process32_next (h_snapshot
, &pe
))
5997 if (proc_id
== pe
.th32ProcessID
)
6000 decoded_cmd
= build_string ("Idle");
6003 /* Decode the command name from locale-specific
6005 cmd_str
= build_unibyte_string (pe
.szExeFile
);
6008 code_convert_string_norecord (cmd_str
,
6009 Vlocale_coding_system
, 0);
6011 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
6012 attrs
= Fcons (Fcons (Qppid
,
6013 make_fixnum_or_float (pe
.th32ParentProcessID
)),
6015 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
6017 attrs
= Fcons (Fcons (Qthcount
,
6018 make_fixnum_or_float (pe
.cntThreads
)),
6025 CloseHandle (h_snapshot
);
6034 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
6036 /* If we were denied a handle to the process, try again after
6037 enabling the SeDebugPrivilege in our process. */
6040 TOKEN_PRIVILEGES priv_current
;
6042 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
6044 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
6046 restore_privilege (&priv_current
);
6052 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
6055 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
6056 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
6058 buf
= xmalloc (blen
);
6059 result
= get_token_information (token
, TokenUser
,
6060 (LPVOID
)buf
, blen
, &needed
);
6063 memcpy (&user_token
, buf
, sizeof (user_token
));
6064 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
6066 euid
= get_rid (user_token
.User
.Sid
);
6067 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
6072 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
6075 strcpy (uname
, "unknown");
6079 ulength
= strlen (uname
);
6085 /* Determine a reasonable euid and gid values. */
6086 if (xstrcasecmp ("administrator", uname
) == 0)
6088 euid
= 500; /* well-known Administrator uid */
6089 egid
= 513; /* well-known None gid */
6093 /* Get group id and name. */
6094 result
= get_token_information (token
, TokenPrimaryGroup
,
6095 (LPVOID
)buf
, blen
, &needed
);
6096 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
6098 buf
= xrealloc (buf
, blen
= needed
);
6099 result
= get_token_information (token
, TokenPrimaryGroup
,
6100 (LPVOID
)buf
, blen
, &needed
);
6104 memcpy (&group_token
, buf
, sizeof (group_token
));
6105 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
6107 egid
= get_rid (group_token
.PrimaryGroup
);
6108 dlength
= sizeof (domain
);
6110 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
6111 gname
, &glength
, NULL
, &dlength
,
6114 w32_add_to_cache (group_token
.PrimaryGroup
,
6118 strcpy (gname
, "None");
6122 glength
= strlen (gname
);
6130 if (!is_windows_9x ())
6132 /* We couldn't open the process token, presumably because of
6133 insufficient access rights. Assume this process is run
6135 strcpy (uname
, "SYSTEM");
6136 strcpy (gname
, "None");
6137 euid
= 18; /* SYSTEM */
6138 egid
= 513; /* None */
6139 glength
= strlen (gname
);
6140 ulength
= strlen (uname
);
6142 /* If we are running under Windows 9X, where security calls are
6143 not supported, we assume all processes are run by the current
6145 else if (GetUserName (uname
, &ulength
))
6147 if (xstrcasecmp ("administrator", uname
) == 0)
6152 strcpy (gname
, "None");
6153 glength
= strlen (gname
);
6154 ulength
= strlen (uname
);
6160 strcpy (uname
, "administrator");
6161 ulength
= strlen (uname
);
6162 strcpy (gname
, "None");
6163 glength
= strlen (gname
);
6166 CloseHandle (token
);
6169 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
6170 tem
= make_unibyte_string (uname
, ulength
);
6171 attrs
= Fcons (Fcons (Quser
,
6172 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
6174 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
6175 tem
= make_unibyte_string (gname
, glength
);
6176 attrs
= Fcons (Fcons (Qgroup
,
6177 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
6180 if (global_memory_status_ex (&memstex
))
6181 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6182 totphys
= memstex
.ullTotalPhys
/ 1024.0;
6184 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6185 double, so we need to do this for it... */
6187 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
6188 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
6189 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
6191 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
6193 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6194 else if (global_memory_status (&memst
))
6195 totphys
= memst
.dwTotalPhys
/ 1024.0;
6198 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
6201 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
6203 attrs
= Fcons (Fcons (Qmajflt
,
6204 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
6206 attrs
= Fcons (Fcons (Qvsize
,
6207 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
6209 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
6211 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6214 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
6216 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
6218 attrs
= Fcons (Fcons (Qmajflt
,
6219 make_fixnum_or_float (mem
.PageFaultCount
)),
6221 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
6223 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6226 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
6228 DWORD rss
= maxrss
/ 1024;
6230 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
6232 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6235 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
6237 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
6238 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
6239 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
6240 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
6241 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
6242 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
6245 /* FIXME: Retrieve command line by walking the PEB of the process. */
6248 CloseHandle (h_proc
);
6254 /* Wrappers for winsock functions to map between our file descriptors
6255 and winsock's handles; also set h_errno for convenience.
6257 To allow Emacs to run on systems which don't have winsock support
6258 installed, we dynamically link to winsock on startup if present, and
6259 otherwise provide the minimum necessary functionality
6260 (eg. gethostname). */
6262 /* function pointers for relevant socket functions */
6263 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
6264 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
6265 int (PASCAL
*pfn_WSAGetLastError
) (void);
6266 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
6267 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
6268 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
6269 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
6270 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6271 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6272 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
6273 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
6274 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
6275 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
6276 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
6277 int (PASCAL
*pfn_WSACleanup
) (void);
6279 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
6280 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
6281 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
6282 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
6283 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
6284 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
6285 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
6286 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
6287 const char * optval
, int optlen
);
6288 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
6289 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
6291 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
6292 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
6293 struct sockaddr
* from
, int * fromlen
);
6294 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
6295 const struct sockaddr
* to
, int tolen
);
6297 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6298 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
6299 #ifndef HANDLE_FLAG_INHERIT
6300 #define HANDLE_FLAG_INHERIT 1
6304 static int winsock_inuse
;
6309 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
6311 release_listen_threads ();
6312 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6313 after WSAStartup returns successfully, but it seems reasonable
6314 to allow unloading winsock anyway in that case. */
6315 if (pfn_WSACleanup () == 0 ||
6316 pfn_WSAGetLastError () == WSAENETDOWN
)
6318 if (FreeLibrary (winsock_lib
))
6327 init_winsock (int load_now
)
6329 WSADATA winsockData
;
6331 if (winsock_lib
!= NULL
)
6334 pfn_SetHandleInformation
6335 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6336 "SetHandleInformation");
6338 winsock_lib
= LoadLibrary ("Ws2_32.dll");
6340 if (winsock_lib
!= NULL
)
6342 /* dynamically link to socket functions */
6344 #define LOAD_PROC(fn) \
6345 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6348 LOAD_PROC (WSAStartup
);
6349 LOAD_PROC (WSASetLastError
);
6350 LOAD_PROC (WSAGetLastError
);
6351 LOAD_PROC (WSAEventSelect
);
6352 LOAD_PROC (WSACreateEvent
);
6353 LOAD_PROC (WSACloseEvent
);
6356 LOAD_PROC (connect
);
6357 LOAD_PROC (ioctlsocket
);
6360 LOAD_PROC (closesocket
);
6361 LOAD_PROC (shutdown
);
6364 LOAD_PROC (inet_addr
);
6365 LOAD_PROC (gethostname
);
6366 LOAD_PROC (gethostbyname
);
6367 LOAD_PROC (getservbyname
);
6368 LOAD_PROC (getpeername
);
6369 LOAD_PROC (WSACleanup
);
6370 LOAD_PROC (setsockopt
);
6372 LOAD_PROC (getsockname
);
6374 LOAD_PROC (recvfrom
);
6378 /* specify version 1.1 of winsock */
6379 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
6381 if (winsockData
.wVersion
!= 0x101)
6386 /* Report that winsock exists and is usable, but leave
6387 socket functions disabled. I am assuming that calling
6388 WSAStartup does not require any network interaction,
6389 and in particular does not cause or require a dial-up
6390 connection to be established. */
6393 FreeLibrary (winsock_lib
);
6401 FreeLibrary (winsock_lib
);
6411 /* Function to map winsock error codes to errno codes for those errno
6412 code defined in errno.h (errno values not defined by errno.h are
6413 already in nt/inc/sys/socket.h). */
6420 if (winsock_lib
== NULL
)
6423 wsa_err
= pfn_WSAGetLastError ();
6427 case WSAEACCES
: errno
= EACCES
; break;
6428 case WSAEBADF
: errno
= EBADF
; break;
6429 case WSAEFAULT
: errno
= EFAULT
; break;
6430 case WSAEINTR
: errno
= EINTR
; break;
6431 case WSAEINVAL
: errno
= EINVAL
; break;
6432 case WSAEMFILE
: errno
= EMFILE
; break;
6433 case WSAENAMETOOLONG
: errno
= ENAMETOOLONG
; break;
6434 case WSAENOTEMPTY
: errno
= ENOTEMPTY
; break;
6435 default: errno
= wsa_err
; break;
6443 if (winsock_lib
!= NULL
)
6444 pfn_WSASetLastError (0);
6447 /* Extend strerror to handle the winsock-specific error codes. */
6451 } _wsa_errlist
[] = {
6452 {WSAEINTR
, "Interrupted function call"},
6453 {WSAEBADF
, "Bad file descriptor"},
6454 {WSAEACCES
, "Permission denied"},
6455 {WSAEFAULT
, "Bad address"},
6456 {WSAEINVAL
, "Invalid argument"},
6457 {WSAEMFILE
, "Too many open files"},
6459 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
6460 {WSAEINPROGRESS
, "Operation now in progress"},
6461 {WSAEALREADY
, "Operation already in progress"},
6462 {WSAENOTSOCK
, "Socket operation on non-socket"},
6463 {WSAEDESTADDRREQ
, "Destination address required"},
6464 {WSAEMSGSIZE
, "Message too long"},
6465 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
6466 {WSAENOPROTOOPT
, "Bad protocol option"},
6467 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
6468 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
6469 {WSAEOPNOTSUPP
, "Operation not supported"},
6470 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
6471 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
6472 {WSAEADDRINUSE
, "Address already in use"},
6473 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
6474 {WSAENETDOWN
, "Network is down"},
6475 {WSAENETUNREACH
, "Network is unreachable"},
6476 {WSAENETRESET
, "Network dropped connection on reset"},
6477 {WSAECONNABORTED
, "Software caused connection abort"},
6478 {WSAECONNRESET
, "Connection reset by peer"},
6479 {WSAENOBUFS
, "No buffer space available"},
6480 {WSAEISCONN
, "Socket is already connected"},
6481 {WSAENOTCONN
, "Socket is not connected"},
6482 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
6483 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
6484 {WSAETIMEDOUT
, "Connection timed out"},
6485 {WSAECONNREFUSED
, "Connection refused"},
6486 {WSAELOOP
, "Network loop"}, /* not sure */
6487 {WSAENAMETOOLONG
, "Name is too long"},
6488 {WSAEHOSTDOWN
, "Host is down"},
6489 {WSAEHOSTUNREACH
, "No route to host"},
6490 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
6491 {WSAEPROCLIM
, "Too many processes"},
6492 {WSAEUSERS
, "Too many users"}, /* not sure */
6493 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
6494 {WSAESTALE
, "Data is stale"}, /* not sure */
6495 {WSAEREMOTE
, "Remote error"}, /* not sure */
6497 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
6498 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
6499 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
6500 {WSAEDISCON
, "Graceful shutdown in progress"},
6502 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
6503 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
6504 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
6505 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
6506 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
6507 {WSASYSCALLFAILURE
, "System call failure"},
6508 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
6509 {WSATYPE_NOT_FOUND
, "Class type not found"},
6510 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
6511 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
6512 {WSAEREFUSED
, "Operation refused"}, /* not sure */
6515 {WSAHOST_NOT_FOUND
, "Host not found"},
6516 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
6517 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
6518 {WSANO_DATA
, "Valid name, no data record of requested type"},
6524 sys_strerror (int error_no
)
6527 static char unknown_msg
[40];
6529 if (error_no
>= 0 && error_no
< sys_nerr
)
6530 return sys_errlist
[error_no
];
6532 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
6533 if (_wsa_errlist
[i
].errnum
== error_no
)
6534 return _wsa_errlist
[i
].msg
;
6536 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
6540 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6541 but I believe the method of keeping the socket handle separate (and
6542 insuring it is not inheritable) is the correct one. */
6544 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6546 static int socket_to_fd (SOCKET s
);
6549 sys_socket (int af
, int type
, int protocol
)
6553 if (winsock_lib
== NULL
)
6556 return INVALID_SOCKET
;
6561 /* call the real socket function */
6562 s
= pfn_socket (af
, type
, protocol
);
6564 if (s
!= INVALID_SOCKET
)
6565 return socket_to_fd (s
);
6571 /* Convert a SOCKET to a file descriptor. */
6573 socket_to_fd (SOCKET s
)
6578 /* Although under NT 3.5 _open_osfhandle will accept a socket
6579 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6580 that does not work under NT 3.1. However, we can get the same
6581 effect by using a backdoor function to replace an existing
6582 descriptor handle with the one we want. */
6584 /* allocate a file descriptor (with appropriate flags) */
6585 fd
= _open ("NUL:", _O_RDWR
);
6588 /* Make a non-inheritable copy of the socket handle. Note
6589 that it is possible that sockets aren't actually kernel
6590 handles, which appears to be the case on Windows 9x when
6591 the MS Proxy winsock client is installed. */
6593 /* Apparently there is a bug in NT 3.51 with some service
6594 packs, which prevents using DuplicateHandle to make a
6595 socket handle non-inheritable (causes WSACleanup to
6596 hang). The work-around is to use SetHandleInformation
6597 instead if it is available and implemented. */
6598 if (pfn_SetHandleInformation
)
6600 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
6604 HANDLE parent
= GetCurrentProcess ();
6605 HANDLE new_s
= INVALID_HANDLE_VALUE
;
6607 if (DuplicateHandle (parent
,
6613 DUPLICATE_SAME_ACCESS
))
6615 /* It is possible that DuplicateHandle succeeds even
6616 though the socket wasn't really a kernel handle,
6617 because a real handle has the same value. So
6618 test whether the new handle really is a socket. */
6619 long nonblocking
= 0;
6620 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
6622 pfn_closesocket (s
);
6627 CloseHandle (new_s
);
6632 eassert (fd
< MAXDESC
);
6633 fd_info
[fd
].hnd
= (HANDLE
) s
;
6635 /* set our own internal flags */
6636 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
6642 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6644 /* attach child_process to fd_info */
6645 if (fd_info
[ fd
].cp
!= NULL
)
6647 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
6651 fd_info
[ fd
].cp
= cp
;
6654 winsock_inuse
++; /* count open sockets */
6662 pfn_closesocket (s
);
6668 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
6670 if (winsock_lib
== NULL
)
6673 return SOCKET_ERROR
;
6677 if (fd_info
[s
].flags
& FILE_SOCKET
)
6679 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
6680 if (rc
== SOCKET_ERROR
)
6685 return SOCKET_ERROR
;
6689 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
6691 if (winsock_lib
== NULL
)
6694 return SOCKET_ERROR
;
6698 if (fd_info
[s
].flags
& FILE_SOCKET
)
6700 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
6701 if (rc
== SOCKET_ERROR
)
6706 return SOCKET_ERROR
;
6710 sys_htons (u_short hostshort
)
6712 return (winsock_lib
!= NULL
) ?
6713 pfn_htons (hostshort
) : hostshort
;
6717 sys_ntohs (u_short netshort
)
6719 return (winsock_lib
!= NULL
) ?
6720 pfn_ntohs (netshort
) : netshort
;
6724 sys_inet_addr (const char * cp
)
6726 return (winsock_lib
!= NULL
) ?
6727 pfn_inet_addr (cp
) : INADDR_NONE
;
6731 sys_gethostname (char * name
, int namelen
)
6733 if (winsock_lib
!= NULL
)
6738 retval
= pfn_gethostname (name
, namelen
);
6739 if (retval
== SOCKET_ERROR
)
6744 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
6745 return !GetComputerName (name
, (DWORD
*)&namelen
);
6748 return SOCKET_ERROR
;
6752 sys_gethostbyname (const char * name
)
6754 struct hostent
* host
;
6755 int h_err
= h_errno
;
6757 if (winsock_lib
== NULL
)
6759 h_errno
= NO_RECOVERY
;
6765 host
= pfn_gethostbyname (name
);
6777 sys_getservbyname (const char * name
, const char * proto
)
6779 struct servent
* serv
;
6781 if (winsock_lib
== NULL
)
6788 serv
= pfn_getservbyname (name
, proto
);
6795 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
6797 if (winsock_lib
== NULL
)
6800 return SOCKET_ERROR
;
6804 if (fd_info
[s
].flags
& FILE_SOCKET
)
6806 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
6807 if (rc
== SOCKET_ERROR
)
6812 return SOCKET_ERROR
;
6816 sys_shutdown (int s
, int how
)
6818 if (winsock_lib
== NULL
)
6821 return SOCKET_ERROR
;
6825 if (fd_info
[s
].flags
& FILE_SOCKET
)
6827 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
6828 if (rc
== SOCKET_ERROR
)
6833 return SOCKET_ERROR
;
6837 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
6839 if (winsock_lib
== NULL
)
6842 return SOCKET_ERROR
;
6846 if (fd_info
[s
].flags
& FILE_SOCKET
)
6848 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
6849 (const char *)optval
, optlen
);
6850 if (rc
== SOCKET_ERROR
)
6855 return SOCKET_ERROR
;
6859 sys_listen (int s
, int backlog
)
6861 if (winsock_lib
== NULL
)
6864 return SOCKET_ERROR
;
6868 if (fd_info
[s
].flags
& FILE_SOCKET
)
6870 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
6871 if (rc
== SOCKET_ERROR
)
6874 fd_info
[s
].flags
|= FILE_LISTEN
;
6878 return SOCKET_ERROR
;
6882 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
6884 if (winsock_lib
== NULL
)
6887 return SOCKET_ERROR
;
6891 if (fd_info
[s
].flags
& FILE_SOCKET
)
6893 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
6894 if (rc
== SOCKET_ERROR
)
6899 return SOCKET_ERROR
;
6903 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
6905 if (winsock_lib
== NULL
)
6912 if (fd_info
[s
].flags
& FILE_LISTEN
)
6914 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
6916 if (t
== INVALID_SOCKET
)
6919 fd
= socket_to_fd (t
);
6923 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6924 ResetEvent (fd_info
[s
].cp
->char_avail
);
6933 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
6934 struct sockaddr
* from
, int * fromlen
)
6936 if (winsock_lib
== NULL
)
6939 return SOCKET_ERROR
;
6943 if (fd_info
[s
].flags
& FILE_SOCKET
)
6945 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
6946 if (rc
== SOCKET_ERROR
)
6951 return SOCKET_ERROR
;
6955 sys_sendto (int s
, const char * buf
, int len
, int flags
,
6956 const struct sockaddr
* to
, int tolen
)
6958 if (winsock_lib
== NULL
)
6961 return SOCKET_ERROR
;
6965 if (fd_info
[s
].flags
& FILE_SOCKET
)
6967 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
6968 if (rc
== SOCKET_ERROR
)
6973 return SOCKET_ERROR
;
6976 /* Windows does not have an fcntl function. Provide an implementation
6977 good enough for Emacs. */
6979 fcntl (int s
, int cmd
, int options
)
6981 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
6982 invoked in a context where fd1 is closed and all descriptors less
6983 than fd1 are open, so sys_dup is an adequate implementation. */
6984 if (cmd
== F_DUPFD_CLOEXEC
)
6987 if (winsock_lib
== NULL
)
6994 if (fd_info
[s
].flags
& FILE_SOCKET
)
6996 if (cmd
== F_SETFL
&& options
== O_NONBLOCK
)
6998 unsigned long nblock
= 1;
6999 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
7000 if (rc
== SOCKET_ERROR
)
7002 /* Keep track of the fact that we set this to non-blocking. */
7003 fd_info
[s
].flags
|= FILE_NDELAY
;
7009 return SOCKET_ERROR
;
7013 return SOCKET_ERROR
;
7017 /* Shadow main io functions: we need to handle pipes and sockets more
7018 intelligently, and implement non-blocking mode as well. */
7031 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
7033 child_process
* cp
= fd_info
[fd
].cp
;
7035 fd_info
[fd
].cp
= NULL
;
7037 if (CHILD_ACTIVE (cp
))
7039 /* if last descriptor to active child_process then cleanup */
7041 for (i
= 0; i
< MAXDESC
; i
++)
7045 if (fd_info
[i
].cp
== cp
)
7050 if (fd_info
[fd
].flags
& FILE_SOCKET
)
7052 if (winsock_lib
== NULL
) emacs_abort ();
7054 pfn_shutdown (SOCK_HANDLE (fd
), 2);
7055 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
7057 winsock_inuse
--; /* count open sockets */
7059 /* If the process handle is NULL, it's either a socket
7060 or serial connection, or a subprocess that was
7061 already reaped by reap_subprocess, but whose
7062 resources were not yet freed, because its output was
7063 not fully read yet by the time it was reaped. (This
7064 usually happens with async subprocesses whose output
7065 is being read by Emacs.) Otherwise, this process was
7066 not reaped yet, so we set its FD to a negative value
7067 to make sure sys_select will eventually get to
7068 calling the SIGCHLD handler for it, which will then
7069 invoke waitpid and reap_subprocess. */
7070 if (cp
->procinfo
.hProcess
== NULL
)
7078 if (fd
>= 0 && fd
< MAXDESC
)
7079 fd_info
[fd
].flags
= 0;
7081 /* Note that sockets do not need special treatment here (at least on
7082 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7083 closesocket is equivalent to CloseHandle, which is to be expected
7084 because socket handles are fully fledged kernel handles. */
7096 if (new_fd
>= 0 && new_fd
< MAXDESC
)
7098 /* duplicate our internal info as well */
7099 fd_info
[new_fd
] = fd_info
[fd
];
7105 sys_dup2 (int src
, int dst
)
7109 if (dst
< 0 || dst
>= MAXDESC
)
7115 /* make sure we close the destination first if it's a pipe or socket */
7116 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
7119 rc
= _dup2 (src
, dst
);
7122 /* duplicate our internal info as well */
7123 fd_info
[dst
] = fd_info
[src
];
7129 pipe2 (int * phandles
, int pipe2_flags
)
7134 eassert (pipe2_flags
== O_CLOEXEC
);
7136 /* make pipe handles non-inheritable; when we spawn a child, we
7137 replace the relevant handle with an inheritable one. Also put
7138 pipes into binary mode; we will do text mode translation ourselves
7140 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
7144 /* Protect against overflow, since Windows can open more handles than
7145 our fd_info array has room for. */
7146 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
7148 _close (phandles
[0]);
7149 _close (phandles
[1]);
7155 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
7156 fd_info
[phandles
[0]].flags
= flags
;
7158 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
7159 fd_info
[phandles
[1]].flags
= flags
;
7166 /* Function to do blocking read of one byte, needed to implement
7167 select. It is only allowed on communication ports, sockets, or
7170 _sys_read_ahead (int fd
)
7175 if (fd
< 0 || fd
>= MAXDESC
)
7176 return STATUS_READ_ERROR
;
7178 cp
= fd_info
[fd
].cp
;
7180 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7181 return STATUS_READ_ERROR
;
7183 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
7184 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
7186 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
7190 cp
->status
= STATUS_READ_IN_PROGRESS
;
7192 if (fd_info
[fd
].flags
& FILE_PIPE
)
7194 rc
= _read (fd
, &cp
->chr
, sizeof (char));
7196 /* Give subprocess time to buffer some more output for us before
7197 reporting that input is available; we need this because Windows 95
7198 connects DOS programs to pipes by making the pipe appear to be
7199 the normal console stdout - as a result most DOS programs will
7200 write to stdout without buffering, ie. one character at a
7201 time. Even some W32 programs do this - "dir" in a command
7202 shell on NT is very slow if we don't do this. */
7205 int wait
= w32_pipe_read_delay
;
7211 /* Yield remainder of our time slice, effectively giving a
7212 temporary priority boost to the child process. */
7216 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7218 HANDLE hnd
= fd_info
[fd
].hnd
;
7219 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7222 /* Configure timeouts for blocking read. */
7223 if (!GetCommTimeouts (hnd
, &ct
))
7225 cp
->status
= STATUS_READ_ERROR
;
7226 return STATUS_READ_ERROR
;
7228 ct
.ReadIntervalTimeout
= 0;
7229 ct
.ReadTotalTimeoutMultiplier
= 0;
7230 ct
.ReadTotalTimeoutConstant
= 0;
7231 if (!SetCommTimeouts (hnd
, &ct
))
7233 cp
->status
= STATUS_READ_ERROR
;
7234 return STATUS_READ_ERROR
;
7237 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
7239 if (GetLastError () != ERROR_IO_PENDING
)
7241 cp
->status
= STATUS_READ_ERROR
;
7242 return STATUS_READ_ERROR
;
7244 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7246 cp
->status
= STATUS_READ_ERROR
;
7247 return STATUS_READ_ERROR
;
7251 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
7253 unsigned long nblock
= 0;
7254 /* We always want this to block, so temporarily disable NDELAY. */
7255 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7256 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7258 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
7260 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7263 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7267 if (rc
== sizeof (char))
7268 cp
->status
= STATUS_READ_SUCCEEDED
;
7270 cp
->status
= STATUS_READ_FAILED
;
7276 _sys_wait_accept (int fd
)
7282 if (fd
< 0 || fd
>= MAXDESC
)
7283 return STATUS_READ_ERROR
;
7285 cp
= fd_info
[fd
].cp
;
7287 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7288 return STATUS_READ_ERROR
;
7290 cp
->status
= STATUS_READ_FAILED
;
7292 hEv
= pfn_WSACreateEvent ();
7293 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
7294 if (rc
!= SOCKET_ERROR
)
7297 rc
= WaitForSingleObject (hEv
, 500);
7299 } while (rc
== WAIT_TIMEOUT
7300 && cp
->status
!= STATUS_READ_ERROR
7302 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
7303 if (rc
== WAIT_OBJECT_0
)
7304 cp
->status
= STATUS_READ_SUCCEEDED
;
7306 pfn_WSACloseEvent (hEv
);
7312 sys_read (int fd
, char * buffer
, unsigned int count
)
7317 char * orig_buffer
= buffer
;
7325 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7327 child_process
*cp
= fd_info
[fd
].cp
;
7329 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
7337 /* re-read CR carried over from last read */
7338 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
7340 if (fd_info
[fd
].flags
& FILE_BINARY
) emacs_abort ();
7344 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
7347 /* presence of a child_process structure means we are operating in
7348 non-blocking mode - otherwise we just call _read directly.
7349 Note that the child_process structure might be missing because
7350 reap_subprocess has been called; in this case the pipe is
7351 already broken, so calling _read on it is okay. */
7354 int current_status
= cp
->status
;
7356 switch (current_status
)
7358 case STATUS_READ_FAILED
:
7359 case STATUS_READ_ERROR
:
7360 /* report normal EOF if nothing in buffer */
7362 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7365 case STATUS_READ_READY
:
7366 case STATUS_READ_IN_PROGRESS
:
7367 DebPrint (("sys_read called when read is in progress\n"));
7368 errno
= EWOULDBLOCK
;
7371 case STATUS_READ_SUCCEEDED
:
7372 /* consume read-ahead char */
7373 *buffer
++ = cp
->chr
;
7376 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7377 ResetEvent (cp
->char_avail
);
7379 case STATUS_READ_ACKNOWLEDGED
:
7383 DebPrint (("sys_read: bad status %d\n", current_status
));
7388 if (fd_info
[fd
].flags
& FILE_PIPE
)
7390 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
7391 to_read
= min (waiting
, (DWORD
) count
);
7394 nchars
+= _read (fd
, buffer
, to_read
);
7396 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7398 HANDLE hnd
= fd_info
[fd
].hnd
;
7399 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7405 /* Configure timeouts for non-blocking read. */
7406 if (!GetCommTimeouts (hnd
, &ct
))
7411 ct
.ReadIntervalTimeout
= MAXDWORD
;
7412 ct
.ReadTotalTimeoutMultiplier
= 0;
7413 ct
.ReadTotalTimeoutConstant
= 0;
7414 if (!SetCommTimeouts (hnd
, &ct
))
7420 if (!ResetEvent (ovl
->hEvent
))
7425 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
7427 if (GetLastError () != ERROR_IO_PENDING
)
7432 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7441 else /* FILE_SOCKET */
7443 if (winsock_lib
== NULL
) emacs_abort ();
7445 /* do the equivalent of a non-blocking read */
7446 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
7447 if (waiting
== 0 && nchars
== 0)
7449 errno
= EWOULDBLOCK
;
7455 /* always use binary mode for sockets */
7456 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
7457 if (res
== SOCKET_ERROR
)
7459 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7460 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7470 int nread
= _read (fd
, buffer
, count
);
7473 else if (nchars
== 0)
7478 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7479 /* Perform text mode translation if required. */
7480 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7482 nchars
= crlf_to_lf (nchars
, orig_buffer
);
7483 /* If buffer contains only CR, return that. To be absolutely
7484 sure we should attempt to read the next char, but in
7485 practice a CR to be followed by LF would not appear by
7486 itself in the buffer. */
7487 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
7489 fd_info
[fd
].flags
|= FILE_LAST_CR
;
7495 nchars
= _read (fd
, buffer
, count
);
7500 /* From w32xfns.c */
7501 extern HANDLE interrupt_handle
;
7503 /* For now, don't bother with a non-blocking mode */
7505 sys_write (int fd
, const void * buffer
, unsigned int count
)
7515 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7517 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
7523 /* Perform text mode translation if required. */
7524 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7526 char * tmpbuf
= alloca (count
* 2);
7527 unsigned char * src
= (void *)buffer
;
7528 unsigned char * dst
= tmpbuf
;
7533 unsigned char *next
;
7534 /* copy next line or remaining bytes */
7535 next
= _memccpy (dst
, src
, '\n', nbytes
);
7538 /* copied one line ending with '\n' */
7539 int copied
= next
- dst
;
7542 /* insert '\r' before '\n' */
7549 /* copied remaining partial line -> now finished */
7556 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
7558 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
7559 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
7560 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
7563 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
7565 if (GetLastError () != ERROR_IO_PENDING
)
7570 if (detect_input_pending ())
7571 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
7574 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
7575 if (active
== WAIT_OBJECT_0
)
7576 { /* User pressed C-g, cancel write, then leave. Don't bother
7577 cleaning up as we may only get stuck in buggy drivers. */
7578 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
7583 if (active
== WAIT_OBJECT_0
+ 1
7584 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
7591 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
7593 unsigned long nblock
= 0;
7594 if (winsock_lib
== NULL
) emacs_abort ();
7596 /* TODO: implement select() properly so non-blocking I/O works. */
7597 /* For now, make sure the write blocks. */
7598 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7599 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7601 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
7603 /* Set the socket back to non-blocking if it was before,
7604 for other operations that support it. */
7605 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7608 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7611 if (nchars
== SOCKET_ERROR
)
7613 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7614 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7620 /* Some networked filesystems don't like too large writes, so
7621 break them into smaller chunks. See the Comments section of
7622 the MSDN documentation of WriteFile for details behind the
7623 choice of the value of CHUNK below. See also the thread
7624 http://thread.gmane.org/gmane.comp.version-control.git/145294
7625 in the git mailing list. */
7626 const unsigned char *p
= buffer
;
7627 const unsigned chunk
= 30 * 1024 * 1024;
7632 unsigned this_chunk
= count
< chunk
? count
: chunk
;
7633 int n
= _write (fd
, p
, this_chunk
);
7641 else if (n
< this_chunk
)
7652 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
7654 extern Lisp_Object
conv_sockaddr_to_lisp (struct sockaddr
*, int);
7656 /* Return information about network interface IFNAME, or about all
7657 interfaces (if IFNAME is nil). */
7659 network_interface_get_info (Lisp_Object ifname
)
7661 ULONG ainfo_len
= sizeof (IP_ADAPTER_INFO
);
7662 IP_ADAPTER_INFO
*adapter
, *ainfo
= xmalloc (ainfo_len
);
7663 DWORD retval
= get_adapters_info (ainfo
, &ainfo_len
);
7664 Lisp_Object res
= Qnil
;
7666 if (retval
== ERROR_BUFFER_OVERFLOW
)
7668 ainfo
= xrealloc (ainfo
, ainfo_len
);
7669 retval
= get_adapters_info (ainfo
, &ainfo_len
);
7672 if (retval
== ERROR_SUCCESS
)
7674 int eth_count
= 0, tr_count
= 0, fddi_count
= 0, ppp_count
= 0;
7675 int sl_count
= 0, wlan_count
= 0, lo_count
= 0, ifx_count
= 0;
7677 struct sockaddr_in sa
;
7679 /* For the below, we need some winsock functions, so make sure
7680 the winsock DLL is loaded. If we cannot successfully load
7681 it, they will have no use of the information we provide,
7683 if (!winsock_lib
&& !init_winsock (1))
7686 for (adapter
= ainfo
; adapter
; adapter
= adapter
->Next
)
7688 char namebuf
[MAX_ADAPTER_NAME_LENGTH
+ 4];
7690 /* Present Unix-compatible interface names, instead of the
7691 Windows names, which are really GUIDs not readable by
7693 static const char *ifmt
[] = {
7694 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
7709 switch (adapter
->Type
)
7711 case MIB_IF_TYPE_ETHERNET
:
7712 /* Windows before Vista reports wireless adapters as
7713 Ethernet. Work around by looking at the Description
7715 if (strstr (adapter
->Description
, "Wireless "))
7718 if_num
= wlan_count
++;
7722 ifmt_idx
= ETHERNET
;
7723 if_num
= eth_count
++;
7726 case MIB_IF_TYPE_TOKENRING
:
7727 ifmt_idx
= TOKENRING
;
7728 if_num
= tr_count
++;
7730 case MIB_IF_TYPE_FDDI
:
7732 if_num
= fddi_count
++;
7734 case MIB_IF_TYPE_PPP
:
7736 if_num
= ppp_count
++;
7738 case MIB_IF_TYPE_SLIP
:
7740 if_num
= sl_count
++;
7742 case IF_TYPE_IEEE80211
:
7744 if_num
= wlan_count
++;
7746 case MIB_IF_TYPE_LOOPBACK
:
7749 ifmt_idx
= LOOPBACK
;
7750 if_num
= lo_count
++;
7756 ifmt_idx
= OTHER_IF
;
7757 if_num
= ifx_count
++;
7760 if (ifmt_idx
== NONE
)
7762 sprintf (namebuf
, ifmt
[ifmt_idx
], if_num
);
7764 sa
.sin_family
= AF_INET
;
7765 ip_addr
= sys_inet_addr (adapter
->IpAddressList
.IpAddress
.String
);
7766 if (ip_addr
== INADDR_NONE
)
7768 /* Bogus address, skip this interface. */
7771 sa
.sin_addr
.s_addr
= ip_addr
;
7774 res
= Fcons (Fcons (build_string (namebuf
),
7775 conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7776 sizeof (struct sockaddr
))),
7778 else if (strcmp (namebuf
, SSDATA (ifname
)) == 0)
7780 Lisp_Object hwaddr
= Fmake_vector (make_number (6), Qnil
);
7781 register struct Lisp_Vector
*p
= XVECTOR (hwaddr
);
7782 Lisp_Object flags
= Qnil
;
7786 /* Flags. We guess most of them by type, since the
7787 Windows flags are different and hard to get by. */
7788 flags
= Fcons (intern ("up"), flags
);
7789 if (ifmt_idx
== ETHERNET
|| ifmt_idx
== WLAN
)
7791 flags
= Fcons (intern ("broadcast"), flags
);
7792 flags
= Fcons (intern ("multicast"), flags
);
7794 flags
= Fcons (intern ("running"), flags
);
7795 if (ifmt_idx
== PPP
)
7797 flags
= Fcons (intern ("pointopoint"), flags
);
7798 flags
= Fcons (intern ("noarp"), flags
);
7800 if (adapter
->HaveWins
)
7801 flags
= Fcons (intern ("WINS"), flags
);
7802 if (adapter
->DhcpEnabled
)
7803 flags
= Fcons (intern ("dynamic"), flags
);
7805 res
= Fcons (flags
, res
);
7807 /* Hardware address and its family. */
7808 for (n
= 0; n
< adapter
->AddressLength
; n
++)
7809 p
->u
.contents
[n
] = make_number ((int) adapter
->Address
[n
]);
7810 /* Windows does not support AF_LINK or AF_PACKET family
7811 of addresses. Use an arbitrary family number that is
7812 identical to what GNU/Linux returns. */
7813 res
= Fcons (Fcons (make_number (1), hwaddr
), res
);
7816 sa
.sin_family
= AF_INET
;
7817 net_mask
= sys_inet_addr (adapter
->IpAddressList
.IpMask
.String
);
7818 if (net_mask
!= INADDR_NONE
)
7820 sa
.sin_addr
.s_addr
= net_mask
;
7822 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7823 sizeof (struct sockaddr
)),
7827 res
= Fcons (Qnil
, res
);
7829 sa
.sin_family
= AF_INET
;
7830 if (ip_addr
!= INADDR_NONE
)
7832 /* Broadcast address is only reported by
7833 GetAdaptersAddresses, which is of limited
7834 availability. Generate it on our own. */
7835 u_long bcast_addr
= (ip_addr
& net_mask
) | ~net_mask
;
7837 sa
.sin_addr
.s_addr
= bcast_addr
;
7839 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7840 sizeof (struct sockaddr
)),
7844 sa
.sin_addr
.s_addr
= ip_addr
;
7846 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7847 sizeof (struct sockaddr
)),
7851 res
= Fcons (Qnil
, Fcons (Qnil
, res
));
7854 /* GetAdaptersInfo is documented to not report loopback
7855 interfaces, so we generate one out of thin air. */
7858 sa
.sin_family
= AF_INET
;
7862 sa
.sin_addr
.s_addr
= sys_inet_addr ("127.0.0.1");
7863 res
= Fcons (Fcons (build_string ("lo"),
7864 conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7865 sizeof (struct sockaddr
))),
7868 else if (strcmp (SSDATA (ifname
), "lo") == 0)
7870 res
= Fcons (Fcons (intern ("running"),
7871 Fcons (intern ("loopback"),
7872 Fcons (intern ("up"), Qnil
))), Qnil
);
7873 /* 772 is what 3 different GNU/Linux systems report for
7874 the loopback interface. */
7875 res
= Fcons (Fcons (make_number (772),
7876 Fmake_vector (make_number (6),
7879 sa
.sin_addr
.s_addr
= sys_inet_addr ("255.0.0.0");
7880 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7881 sizeof (struct sockaddr
)),
7883 sa
.sin_addr
.s_addr
= sys_inet_addr ("0.0.0.0");
7884 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7885 sizeof (struct sockaddr
)),
7887 sa
.sin_addr
.s_addr
= sys_inet_addr ("127.0.0.1");
7888 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
7889 sizeof (struct sockaddr
)),
7902 network_interface_list (void)
7904 return network_interface_get_info (Qnil
);
7908 network_interface_info (Lisp_Object ifname
)
7910 return network_interface_get_info (ifname
);
7914 /* The Windows CRT functions are "optimized for speed", so they don't
7915 check for timezone and DST changes if they were last called less
7916 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
7917 all Emacs features that repeatedly call time functions (e.g.,
7918 display-time) are in real danger of missing timezone and DST
7919 changes. Calling tzset before each localtime call fixes that. */
7921 sys_localtime (const time_t *t
)
7924 return localtime (t
);
7929 /* Try loading LIBRARY_ID from the file(s) specified in
7930 Vdynamic_library_alist. If the library is loaded successfully,
7931 return the handle of the DLL, and record the filename in the
7932 property :loaded-from of LIBRARY_ID. If the library could not be
7933 found, or when it was already loaded (because the handle is not
7934 recorded anywhere, and so is lost after use), return NULL.
7936 We could also save the handle in :loaded-from, but currently
7937 there's no use case for it. */
7939 w32_delayed_load (Lisp_Object library_id
)
7941 HMODULE library_dll
= NULL
;
7943 CHECK_SYMBOL (library_id
);
7945 if (CONSP (Vdynamic_library_alist
)
7946 && NILP (Fassq (library_id
, Vlibrary_cache
)))
7948 Lisp_Object found
= Qnil
;
7949 Lisp_Object dlls
= Fassq (library_id
, Vdynamic_library_alist
);
7952 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
7954 CHECK_STRING_CAR (dlls
);
7955 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
7957 char name
[MAX_PATH
];
7960 len
= GetModuleFileNameA (library_dll
, name
, sizeof (name
));
7961 found
= Fcons (XCAR (dlls
),
7963 /* Possibly truncated */
7964 ? make_specified_string (name
, -1, len
, 1)
7970 Fput (library_id
, QCloaded_from
, found
);
7978 check_windows_init_file (void)
7980 /* A common indication that Emacs is not installed properly is when
7981 it cannot find the Windows installation file. If this file does
7982 not exist in the expected place, tell the user. */
7984 if (!noninteractive
&& !inhibit_window_system
7985 /* Vload_path is not yet initialized when we are loading
7987 && NILP (Vpurify_flag
))
7989 Lisp_Object init_file
;
7992 init_file
= build_string ("term/w32-win");
7993 fd
= openp (Vload_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
7996 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
7997 char *init_file_name
= SDATA (init_file
);
7998 char *load_path
= SDATA (load_path_print
);
7999 char *buffer
= alloca (1024
8000 + strlen (init_file_name
)
8001 + strlen (load_path
));
8004 "The Emacs Windows initialization file \"%s.el\" "
8005 "could not be found in your Emacs installation. "
8006 "Emacs checked the following directories for this file:\n"
8008 "When Emacs cannot find this file, it usually means that it "
8009 "was not installed properly, or its distribution file was "
8010 "not unpacked properly.\nSee the README.W32 file in the "
8011 "top-level Emacs directory for more information.",
8012 init_file_name
, load_path
);
8015 "Emacs Abort Dialog",
8016 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
8017 /* Use the low-level system abort. */
8028 term_ntproc (int ignored
)
8034 /* shutdown the socket interface if necessary */
8041 init_ntproc (int dumping
)
8043 sigset_t initial_mask
= 0;
8045 /* Initialize the socket interface now if available and requested by
8046 the user by defining PRELOAD_WINSOCK; otherwise loading will be
8047 delayed until open-network-stream is called (w32-has-winsock can
8048 also be used to dynamically load or reload winsock).
8050 Conveniently, init_environment is called before us, so
8051 PRELOAD_WINSOCK can be set in the registry. */
8053 /* Always initialize this correctly. */
8056 if (getenv ("PRELOAD_WINSOCK") != NULL
)
8057 init_winsock (TRUE
);
8059 /* Initial preparation for subprocess support: replace our standard
8060 handles with non-inheritable versions. */
8063 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
8064 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
8065 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
8067 parent
= GetCurrentProcess ();
8069 /* ignore errors when duplicating and closing; typically the
8070 handles will be invalid when running as a gui program. */
8071 DuplicateHandle (parent
,
8072 GetStdHandle (STD_INPUT_HANDLE
),
8077 DUPLICATE_SAME_ACCESS
);
8079 DuplicateHandle (parent
,
8080 GetStdHandle (STD_OUTPUT_HANDLE
),
8085 DUPLICATE_SAME_ACCESS
);
8087 DuplicateHandle (parent
,
8088 GetStdHandle (STD_ERROR_HANDLE
),
8093 DUPLICATE_SAME_ACCESS
);
8099 if (stdin_save
!= INVALID_HANDLE_VALUE
)
8100 _open_osfhandle ((intptr_t) stdin_save
, O_TEXT
);
8102 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
8105 if (stdout_save
!= INVALID_HANDLE_VALUE
)
8106 _open_osfhandle ((intptr_t) stdout_save
, O_TEXT
);
8108 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
8111 if (stderr_save
!= INVALID_HANDLE_VALUE
)
8112 _open_osfhandle ((intptr_t) stderr_save
, O_TEXT
);
8114 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
8118 /* unfortunately, atexit depends on implementation of malloc */
8119 /* atexit (term_ntproc); */
8122 /* Make sure we start with all signals unblocked. */
8123 sigprocmask (SIG_SETMASK
, &initial_mask
, NULL
);
8124 signal (SIGABRT
, term_ntproc
);
8128 /* determine which drives are fixed, for GetCachedVolumeInformation */
8130 /* GetDriveType must have trailing backslash. */
8131 char drive
[] = "A:\\";
8133 /* Loop over all possible drive letters */
8134 while (*drive
<= 'Z')
8136 /* Record if this drive letter refers to a fixed drive. */
8137 fixed_drives
[DRIVE_INDEX (*drive
)] =
8138 (GetDriveType (drive
) == DRIVE_FIXED
);
8143 /* Reset the volume info cache. */
8144 volume_cache
= NULL
;
8149 shutdown_handler ensures that buffers' autosave files are
8150 up to date when the user logs off, or the system shuts down.
8153 shutdown_handler (DWORD type
)
8155 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
8156 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
8157 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
8158 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
8160 /* Shut down cleanly, making sure autosave files are up to date. */
8161 shut_down_emacs (0, Qnil
);
8164 /* Allow other handlers to handle this signal. */
8169 globals_of_w32 is used to initialize those global variables that
8170 must always be initialized on startup even when the global variable
8171 initialized is non zero (see the function main in emacs.c).
8174 globals_of_w32 (void)
8176 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
8178 get_process_times_fn
= (GetProcessTimes_Proc
)
8179 GetProcAddress (kernel32
, "GetProcessTimes");
8181 DEFSYM (QCloaded_from
, ":loaded-from");
8183 g_b_init_is_windows_9x
= 0;
8184 g_b_init_open_process_token
= 0;
8185 g_b_init_get_token_information
= 0;
8186 g_b_init_lookup_account_sid
= 0;
8187 g_b_init_get_sid_sub_authority
= 0;
8188 g_b_init_get_sid_sub_authority_count
= 0;
8189 g_b_init_get_security_info
= 0;
8190 g_b_init_get_file_security
= 0;
8191 g_b_init_get_security_descriptor_owner
= 0;
8192 g_b_init_get_security_descriptor_group
= 0;
8193 g_b_init_is_valid_sid
= 0;
8194 g_b_init_create_toolhelp32_snapshot
= 0;
8195 g_b_init_process32_first
= 0;
8196 g_b_init_process32_next
= 0;
8197 g_b_init_open_thread_token
= 0;
8198 g_b_init_impersonate_self
= 0;
8199 g_b_init_revert_to_self
= 0;
8200 g_b_init_get_process_memory_info
= 0;
8201 g_b_init_get_process_working_set_size
= 0;
8202 g_b_init_global_memory_status
= 0;
8203 g_b_init_global_memory_status_ex
= 0;
8204 g_b_init_equal_sid
= 0;
8205 g_b_init_copy_sid
= 0;
8206 g_b_init_get_length_sid
= 0;
8207 g_b_init_get_native_system_info
= 0;
8208 g_b_init_get_system_times
= 0;
8209 g_b_init_create_symbolic_link
= 0;
8210 g_b_init_get_security_descriptor_dacl
= 0;
8211 g_b_init_convert_sd_to_sddl
= 0;
8212 g_b_init_convert_sddl_to_sd
= 0;
8213 g_b_init_is_valid_security_descriptor
= 0;
8214 g_b_init_set_file_security
= 0;
8215 g_b_init_get_adapters_info
= 0;
8216 num_of_processors
= 0;
8217 /* The following sets a handler for shutdown notifications for
8218 console apps. This actually applies to Emacs in both console and
8219 GUI modes, since we had to fool windows into thinking emacs is a
8220 console application to get console mode to work. */
8221 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
8223 /* "None" is the default group name on standalone workstations. */
8224 strcpy (dflt_group_name
, "None");
8226 /* Reset, in case it has some value inherited from dump time. */
8227 w32_stat_get_owner_group
= 0;
8229 /* If w32_unicode_filenames is non-zero, we will be using Unicode
8230 (a.k.a. "wide") APIs to invoke functions that accept file
8232 if (is_windows_9x ())
8233 w32_unicode_filenames
= 0;
8235 w32_unicode_filenames
= 1;
8238 /* For make-serial-process */
8240 serial_open (Lisp_Object port_obj
)
8242 char *port
= SSDATA (port_obj
);
8247 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
8248 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
8249 if (hnd
== INVALID_HANDLE_VALUE
)
8250 error ("Could not open %s", port
);
8251 fd
= (int) _open_osfhandle ((intptr_t) hnd
, 0);
8253 error ("Could not open %s", port
);
8257 error ("Could not create child process");
8259 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
8260 fd_info
[ fd
].hnd
= hnd
;
8261 fd_info
[ fd
].flags
|=
8262 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
8263 if (fd_info
[ fd
].cp
!= NULL
)
8265 error ("fd_info[fd = %d] is already in use", fd
);
8267 fd_info
[ fd
].cp
= cp
;
8268 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
8269 if (cp
->ovl_read
.hEvent
== NULL
)
8270 error ("Could not create read event");
8271 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
8272 if (cp
->ovl_write
.hEvent
== NULL
)
8273 error ("Could not create write event");
8278 /* For serial-process-configure */
8280 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
8282 Lisp_Object childp2
= Qnil
;
8283 Lisp_Object tem
= Qnil
;
8287 char summary
[4] = "???"; /* This usually becomes "8N1". */
8289 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
8290 error ("Not a serial process");
8291 hnd
= fd_info
[ p
->outfd
].hnd
;
8293 childp2
= Fcopy_sequence (p
->childp
);
8295 /* Initialize timeouts for blocking read and blocking write. */
8296 if (!GetCommTimeouts (hnd
, &ct
))
8297 error ("GetCommTimeouts() failed");
8298 ct
.ReadIntervalTimeout
= 0;
8299 ct
.ReadTotalTimeoutMultiplier
= 0;
8300 ct
.ReadTotalTimeoutConstant
= 0;
8301 ct
.WriteTotalTimeoutMultiplier
= 0;
8302 ct
.WriteTotalTimeoutConstant
= 0;
8303 if (!SetCommTimeouts (hnd
, &ct
))
8304 error ("SetCommTimeouts() failed");
8305 /* Read port attributes and prepare default configuration. */
8306 memset (&dcb
, 0, sizeof (dcb
));
8307 dcb
.DCBlength
= sizeof (DCB
);
8308 if (!GetCommState (hnd
, &dcb
))
8309 error ("GetCommState() failed");
8312 dcb
.fAbortOnError
= FALSE
;
8313 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
8318 /* Configure speed. */
8319 if (!NILP (Fplist_member (contact
, QCspeed
)))
8320 tem
= Fplist_get (contact
, QCspeed
);
8322 tem
= Fplist_get (p
->childp
, QCspeed
);
8324 dcb
.BaudRate
= XINT (tem
);
8325 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
8327 /* Configure bytesize. */
8328 if (!NILP (Fplist_member (contact
, QCbytesize
)))
8329 tem
= Fplist_get (contact
, QCbytesize
);
8331 tem
= Fplist_get (p
->childp
, QCbytesize
);
8333 tem
= make_number (8);
8335 if (XINT (tem
) != 7 && XINT (tem
) != 8)
8336 error (":bytesize must be nil (8), 7, or 8");
8337 dcb
.ByteSize
= XINT (tem
);
8338 summary
[0] = XINT (tem
) + '0';
8339 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
8341 /* Configure parity. */
8342 if (!NILP (Fplist_member (contact
, QCparity
)))
8343 tem
= Fplist_get (contact
, QCparity
);
8345 tem
= Fplist_get (p
->childp
, QCparity
);
8346 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
8347 error (":parity must be nil (no parity), `even', or `odd'");
8348 dcb
.fParity
= FALSE
;
8349 dcb
.Parity
= NOPARITY
;
8350 dcb
.fErrorChar
= FALSE
;
8355 else if (EQ (tem
, Qeven
))
8359 dcb
.Parity
= EVENPARITY
;
8360 dcb
.fErrorChar
= TRUE
;
8362 else if (EQ (tem
, Qodd
))
8366 dcb
.Parity
= ODDPARITY
;
8367 dcb
.fErrorChar
= TRUE
;
8369 childp2
= Fplist_put (childp2
, QCparity
, tem
);
8371 /* Configure stopbits. */
8372 if (!NILP (Fplist_member (contact
, QCstopbits
)))
8373 tem
= Fplist_get (contact
, QCstopbits
);
8375 tem
= Fplist_get (p
->childp
, QCstopbits
);
8377 tem
= make_number (1);
8379 if (XINT (tem
) != 1 && XINT (tem
) != 2)
8380 error (":stopbits must be nil (1 stopbit), 1, or 2");
8381 summary
[2] = XINT (tem
) + '0';
8382 if (XINT (tem
) == 1)
8383 dcb
.StopBits
= ONESTOPBIT
;
8384 else if (XINT (tem
) == 2)
8385 dcb
.StopBits
= TWOSTOPBITS
;
8386 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
8388 /* Configure flowcontrol. */
8389 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
8390 tem
= Fplist_get (contact
, QCflowcontrol
);
8392 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
8393 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
8394 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
8395 dcb
.fOutxCtsFlow
= FALSE
;
8396 dcb
.fOutxDsrFlow
= FALSE
;
8397 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
8398 dcb
.fDsrSensitivity
= FALSE
;
8399 dcb
.fTXContinueOnXoff
= FALSE
;
8402 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
8403 dcb
.XonChar
= 17; /* Control-Q */
8404 dcb
.XoffChar
= 19; /* Control-S */
8407 /* Already configured. */
8409 else if (EQ (tem
, Qhw
))
8411 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
8412 dcb
.fOutxCtsFlow
= TRUE
;
8414 else if (EQ (tem
, Qsw
))
8419 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
8421 /* Activate configuration. */
8422 if (!SetCommState (hnd
, &dcb
))
8423 error ("SetCommState() failed");
8425 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
8426 pset_childp (p
, childp2
);
8432 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
8436 struct timespec timeout
;
8437 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
8438 int fd
= process
->infd
;
8440 n
= sys_read (fd
, (char*)buf
, sz
);
8447 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8448 if (err
== EWOULDBLOCK
)
8451 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
8457 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
8459 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
8460 int fd
= process
->outfd
;
8461 ssize_t n
= sys_write (fd
, buf
, sz
);
8463 /* 0 or more bytes written means everything went fine. */
8467 /* Negative bytes written means we got an error in errno.
8468 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8469 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
8470 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
8474 #endif /* HAVE_GNUTLS */