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 static 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_w
;
277 static BOOL g_b_init_get_file_security_a
;
278 static BOOL g_b_init_get_security_descriptor_owner
;
279 static BOOL g_b_init_get_security_descriptor_group
;
280 static BOOL g_b_init_is_valid_sid
;
281 static BOOL g_b_init_create_toolhelp32_snapshot
;
282 static BOOL g_b_init_process32_first
;
283 static BOOL g_b_init_process32_next
;
284 static BOOL g_b_init_open_thread_token
;
285 static BOOL g_b_init_impersonate_self
;
286 static BOOL g_b_init_revert_to_self
;
287 static BOOL g_b_init_get_process_memory_info
;
288 static BOOL g_b_init_get_process_working_set_size
;
289 static BOOL g_b_init_global_memory_status
;
290 static BOOL g_b_init_global_memory_status_ex
;
291 static BOOL g_b_init_get_length_sid
;
292 static BOOL g_b_init_equal_sid
;
293 static BOOL g_b_init_copy_sid
;
294 static BOOL g_b_init_get_native_system_info
;
295 static BOOL g_b_init_get_system_times
;
296 static BOOL g_b_init_create_symbolic_link_w
;
297 static BOOL g_b_init_create_symbolic_link_a
;
298 static BOOL g_b_init_get_security_descriptor_dacl
;
299 static BOOL g_b_init_convert_sd_to_sddl
;
300 static BOOL g_b_init_convert_sddl_to_sd
;
301 static BOOL g_b_init_is_valid_security_descriptor
;
302 static BOOL g_b_init_set_file_security
;
303 static BOOL g_b_init_get_adapters_info
;
306 BEGIN: Wrapper functions around OpenProcessToken
307 and other functions in advapi32.dll that are only
308 supported in Windows NT / 2k / XP
310 /* ** Function pointer typedefs ** */
311 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
312 HANDLE ProcessHandle
,
314 PHANDLE TokenHandle
);
315 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
317 TOKEN_INFORMATION_CLASS TokenInformationClass
,
318 LPVOID TokenInformation
,
319 DWORD TokenInformationLength
,
320 PDWORD ReturnLength
);
321 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
322 HANDLE process_handle
,
323 LPFILETIME creation_time
,
324 LPFILETIME exit_time
,
325 LPFILETIME kernel_time
,
326 LPFILETIME user_time
);
328 GetProcessTimes_Proc get_process_times_fn
= NULL
;
331 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
333 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
335 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
336 LPCTSTR lpSystemName
,
341 LPDWORD cbDomainName
,
342 PSID_NAME_USE peUse
);
343 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
346 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
348 typedef DWORD (WINAPI
* GetSecurityInfo_Proc
) (
350 SE_OBJECT_TYPE ObjectType
,
351 SECURITY_INFORMATION SecurityInfo
,
356 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
);
357 typedef BOOL (WINAPI
* GetFileSecurityW_Proc
) (
359 SECURITY_INFORMATION RequestedInformation
,
360 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
362 LPDWORD lpnLengthNeeded
);
363 typedef BOOL (WINAPI
* GetFileSecurityA_Proc
) (
365 SECURITY_INFORMATION RequestedInformation
,
366 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
368 LPDWORD lpnLengthNeeded
);
369 typedef BOOL (WINAPI
*SetFileSecurity_Proc
) (
371 SECURITY_INFORMATION SecurityInformation
,
372 PSECURITY_DESCRIPTOR pSecurityDescriptor
);
373 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
374 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
376 LPBOOL lpbOwnerDefaulted
);
377 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
378 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
380 LPBOOL lpbGroupDefaulted
);
381 typedef BOOL (WINAPI
*GetSecurityDescriptorDacl_Proc
) (
382 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
383 LPBOOL lpbDaclPresent
,
385 LPBOOL lpbDaclDefaulted
);
386 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
388 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
390 DWORD th32ProcessID
);
391 typedef BOOL (WINAPI
* Process32First_Proc
) (
393 LPPROCESSENTRY32 lppe
);
394 typedef BOOL (WINAPI
* Process32Next_Proc
) (
396 LPPROCESSENTRY32 lppe
);
397 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
401 PHANDLE TokenHandle
);
402 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
403 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
404 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
405 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
407 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
409 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
411 PSIZE_T lpMinimumWorkingSetSize
,
412 PSIZE_T lpMaximumWorkingSetSize
);
413 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
414 LPMEMORYSTATUS lpBuffer
);
415 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
416 LPMEMORY_STATUS_EX lpBuffer
);
417 typedef BOOL (WINAPI
* CopySid_Proc
) (
418 DWORD nDestinationSidLength
,
419 PSID pDestinationSid
,
421 typedef BOOL (WINAPI
* EqualSid_Proc
) (
424 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
426 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
427 LPSYSTEM_INFO lpSystemInfo
);
428 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
429 LPFILETIME lpIdleTime
,
430 LPFILETIME lpKernelTime
,
431 LPFILETIME lpUserTime
);
432 typedef BOOLEAN (WINAPI
*CreateSymbolicLinkW_Proc
) (
433 LPCWSTR lpSymlinkFileName
,
434 LPCWSTR lpTargetFileName
,
436 typedef BOOLEAN (WINAPI
*CreateSymbolicLinkA_Proc
) (
437 LPCSTR lpSymlinkFileName
,
438 LPCSTR lpTargetFileName
,
440 typedef BOOL (WINAPI
*ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
) (
441 LPCTSTR StringSecurityDescriptor
,
442 DWORD StringSDRevision
,
443 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
444 PULONG SecurityDescriptorSize
);
445 typedef BOOL (WINAPI
*ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
) (
446 PSECURITY_DESCRIPTOR SecurityDescriptor
,
447 DWORD RequestedStringSDRevision
,
448 SECURITY_INFORMATION SecurityInformation
,
449 LPTSTR
*StringSecurityDescriptor
,
450 PULONG StringSecurityDescriptorLen
);
451 typedef BOOL (WINAPI
*IsValidSecurityDescriptor_Proc
) (PSECURITY_DESCRIPTOR
);
452 typedef DWORD (WINAPI
*GetAdaptersInfo_Proc
) (
453 PIP_ADAPTER_INFO pAdapterInfo
,
456 /* ** A utility function ** */
460 static BOOL s_b_ret
= 0;
461 OSVERSIONINFO os_ver
;
462 if (g_b_init_is_windows_9x
== 0)
464 g_b_init_is_windows_9x
= 1;
465 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
466 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
467 if (GetVersionEx (&os_ver
))
469 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
475 static Lisp_Object
ltime (ULONGLONG
);
477 /* Get total user and system times for get-internal-run-time.
478 Returns a list of integers if the times are provided by the OS
479 (NT derivatives), otherwise it returns the result of current-time. */
481 w32_get_internal_run_time (void)
483 if (get_process_times_fn
)
485 FILETIME create
, exit
, kernel
, user
;
486 HANDLE proc
= GetCurrentProcess ();
487 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
489 LARGE_INTEGER user_int
, kernel_int
, total
;
490 user_int
.LowPart
= user
.dwLowDateTime
;
491 user_int
.HighPart
= user
.dwHighDateTime
;
492 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
493 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
494 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
495 return ltime (total
.QuadPart
);
499 return Fcurrent_time ();
502 /* ** The wrapper functions ** */
505 open_process_token (HANDLE ProcessHandle
,
509 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
510 HMODULE hm_advapi32
= NULL
;
511 if (is_windows_9x () == TRUE
)
515 if (g_b_init_open_process_token
== 0)
517 g_b_init_open_process_token
= 1;
518 hm_advapi32
= LoadLibrary ("Advapi32.dll");
519 s_pfn_Open_Process_Token
=
520 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
522 if (s_pfn_Open_Process_Token
== NULL
)
527 s_pfn_Open_Process_Token (
535 get_token_information (HANDLE TokenHandle
,
536 TOKEN_INFORMATION_CLASS TokenInformationClass
,
537 LPVOID TokenInformation
,
538 DWORD TokenInformationLength
,
541 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
542 HMODULE hm_advapi32
= NULL
;
543 if (is_windows_9x () == TRUE
)
547 if (g_b_init_get_token_information
== 0)
549 g_b_init_get_token_information
= 1;
550 hm_advapi32
= LoadLibrary ("Advapi32.dll");
551 s_pfn_Get_Token_Information
=
552 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
554 if (s_pfn_Get_Token_Information
== NULL
)
559 s_pfn_Get_Token_Information (
561 TokenInformationClass
,
563 TokenInformationLength
,
569 lookup_account_sid (LPCTSTR lpSystemName
,
574 LPDWORD cbDomainName
,
577 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
578 HMODULE hm_advapi32
= NULL
;
579 if (is_windows_9x () == TRUE
)
583 if (g_b_init_lookup_account_sid
== 0)
585 g_b_init_lookup_account_sid
= 1;
586 hm_advapi32
= LoadLibrary ("Advapi32.dll");
587 s_pfn_Lookup_Account_Sid
=
588 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
590 if (s_pfn_Lookup_Account_Sid
== NULL
)
595 s_pfn_Lookup_Account_Sid (
607 get_sid_sub_authority (PSID pSid
, DWORD n
)
609 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
610 static DWORD zero
= 0U;
611 HMODULE hm_advapi32
= NULL
;
612 if (is_windows_9x () == TRUE
)
616 if (g_b_init_get_sid_sub_authority
== 0)
618 g_b_init_get_sid_sub_authority
= 1;
619 hm_advapi32
= LoadLibrary ("Advapi32.dll");
620 s_pfn_Get_Sid_Sub_Authority
=
621 (GetSidSubAuthority_Proc
) GetProcAddress (
622 hm_advapi32
, "GetSidSubAuthority");
624 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
628 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
632 get_sid_sub_authority_count (PSID pSid
)
634 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
635 static UCHAR zero
= 0U;
636 HMODULE hm_advapi32
= NULL
;
637 if (is_windows_9x () == TRUE
)
641 if (g_b_init_get_sid_sub_authority_count
== 0)
643 g_b_init_get_sid_sub_authority_count
= 1;
644 hm_advapi32
= LoadLibrary ("Advapi32.dll");
645 s_pfn_Get_Sid_Sub_Authority_Count
=
646 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
647 hm_advapi32
, "GetSidSubAuthorityCount");
649 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
653 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
657 get_security_info (HANDLE handle
,
658 SE_OBJECT_TYPE ObjectType
,
659 SECURITY_INFORMATION SecurityInfo
,
664 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
)
666 static GetSecurityInfo_Proc s_pfn_Get_Security_Info
= NULL
;
667 HMODULE hm_advapi32
= NULL
;
668 if (is_windows_9x () == TRUE
)
672 if (g_b_init_get_security_info
== 0)
674 g_b_init_get_security_info
= 1;
675 hm_advapi32
= LoadLibrary ("Advapi32.dll");
676 s_pfn_Get_Security_Info
=
677 (GetSecurityInfo_Proc
) GetProcAddress (
678 hm_advapi32
, "GetSecurityInfo");
680 if (s_pfn_Get_Security_Info
== NULL
)
684 return (s_pfn_Get_Security_Info (handle
, ObjectType
, SecurityInfo
,
685 ppsidOwner
, ppsidGroup
, ppDacl
, ppSacl
,
686 ppSecurityDescriptor
));
689 static int filename_to_ansi (const char *, char *);
690 static int filename_to_utf16 (const char *, wchar_t *);
693 get_file_security (const char *lpFileName
,
694 SECURITY_INFORMATION RequestedInformation
,
695 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
697 LPDWORD lpnLengthNeeded
)
699 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA
= NULL
;
700 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW
= NULL
;
701 HMODULE hm_advapi32
= NULL
;
702 if (is_windows_9x () == TRUE
)
707 if (w32_unicode_filenames
)
709 wchar_t filename_w
[MAX_PATH
];
711 if (g_b_init_get_file_security_w
== 0)
713 g_b_init_get_file_security_w
= 1;
714 hm_advapi32
= LoadLibrary ("Advapi32.dll");
715 s_pfn_Get_File_SecurityW
=
716 (GetFileSecurityW_Proc
) GetProcAddress (hm_advapi32
,
719 if (s_pfn_Get_File_SecurityW
== NULL
)
724 filename_to_utf16 (lpFileName
, filename_w
);
725 return (s_pfn_Get_File_SecurityW (filename_w
, RequestedInformation
,
726 pSecurityDescriptor
, nLength
,
731 char filename_a
[MAX_PATH
];
733 if (g_b_init_get_file_security_a
== 0)
735 g_b_init_get_file_security_a
= 1;
736 hm_advapi32
= LoadLibrary ("Advapi32.dll");
737 s_pfn_Get_File_SecurityA
=
738 (GetFileSecurityA_Proc
) GetProcAddress (hm_advapi32
,
741 if (s_pfn_Get_File_SecurityA
== NULL
)
746 filename_to_ansi (lpFileName
, filename_a
);
747 return (s_pfn_Get_File_SecurityA (filename_a
, RequestedInformation
,
748 pSecurityDescriptor
, nLength
,
754 set_file_security (LPCTSTR lpFileName
,
755 SECURITY_INFORMATION SecurityInformation
,
756 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
758 static SetFileSecurity_Proc s_pfn_Set_File_Security
= NULL
;
759 HMODULE hm_advapi32
= NULL
;
760 if (is_windows_9x () == TRUE
)
765 if (g_b_init_set_file_security
== 0)
767 g_b_init_set_file_security
= 1;
768 hm_advapi32
= LoadLibrary ("Advapi32.dll");
769 s_pfn_Set_File_Security
=
770 (SetFileSecurity_Proc
) GetProcAddress (
771 hm_advapi32
, "SetFileSecurityA");
773 if (s_pfn_Set_File_Security
== NULL
)
778 return (s_pfn_Set_File_Security (lpFileName
, SecurityInformation
,
779 pSecurityDescriptor
));
783 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
785 LPBOOL lpbOwnerDefaulted
)
787 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
788 HMODULE hm_advapi32
= NULL
;
789 if (is_windows_9x () == TRUE
)
794 if (g_b_init_get_security_descriptor_owner
== 0)
796 g_b_init_get_security_descriptor_owner
= 1;
797 hm_advapi32
= LoadLibrary ("Advapi32.dll");
798 s_pfn_Get_Security_Descriptor_Owner
=
799 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
800 hm_advapi32
, "GetSecurityDescriptorOwner");
802 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
807 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
812 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
814 LPBOOL lpbGroupDefaulted
)
816 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
817 HMODULE hm_advapi32
= NULL
;
818 if (is_windows_9x () == TRUE
)
823 if (g_b_init_get_security_descriptor_group
== 0)
825 g_b_init_get_security_descriptor_group
= 1;
826 hm_advapi32
= LoadLibrary ("Advapi32.dll");
827 s_pfn_Get_Security_Descriptor_Group
=
828 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
829 hm_advapi32
, "GetSecurityDescriptorGroup");
831 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
836 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
841 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
842 LPBOOL lpbDaclPresent
,
844 LPBOOL lpbDaclDefaulted
)
846 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl
= NULL
;
847 HMODULE hm_advapi32
= NULL
;
848 if (is_windows_9x () == TRUE
)
853 if (g_b_init_get_security_descriptor_dacl
== 0)
855 g_b_init_get_security_descriptor_dacl
= 1;
856 hm_advapi32
= LoadLibrary ("Advapi32.dll");
857 s_pfn_Get_Security_Descriptor_Dacl
=
858 (GetSecurityDescriptorDacl_Proc
) GetProcAddress (
859 hm_advapi32
, "GetSecurityDescriptorDacl");
861 if (s_pfn_Get_Security_Descriptor_Dacl
== NULL
)
866 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor
,
867 lpbDaclPresent
, pDacl
,
872 is_valid_sid (PSID sid
)
874 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
875 HMODULE hm_advapi32
= NULL
;
876 if (is_windows_9x () == TRUE
)
880 if (g_b_init_is_valid_sid
== 0)
882 g_b_init_is_valid_sid
= 1;
883 hm_advapi32
= LoadLibrary ("Advapi32.dll");
885 (IsValidSid_Proc
) GetProcAddress (
886 hm_advapi32
, "IsValidSid");
888 if (s_pfn_Is_Valid_Sid
== NULL
)
892 return (s_pfn_Is_Valid_Sid (sid
));
896 equal_sid (PSID sid1
, PSID sid2
)
898 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
899 HMODULE hm_advapi32
= NULL
;
900 if (is_windows_9x () == TRUE
)
904 if (g_b_init_equal_sid
== 0)
906 g_b_init_equal_sid
= 1;
907 hm_advapi32
= LoadLibrary ("Advapi32.dll");
909 (EqualSid_Proc
) GetProcAddress (
910 hm_advapi32
, "EqualSid");
912 if (s_pfn_Equal_Sid
== NULL
)
916 return (s_pfn_Equal_Sid (sid1
, sid2
));
920 get_length_sid (PSID sid
)
922 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
923 HMODULE hm_advapi32
= NULL
;
924 if (is_windows_9x () == TRUE
)
928 if (g_b_init_get_length_sid
== 0)
930 g_b_init_get_length_sid
= 1;
931 hm_advapi32
= LoadLibrary ("Advapi32.dll");
932 s_pfn_Get_Length_Sid
=
933 (GetLengthSid_Proc
) GetProcAddress (
934 hm_advapi32
, "GetLengthSid");
936 if (s_pfn_Get_Length_Sid
== NULL
)
940 return (s_pfn_Get_Length_Sid (sid
));
944 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
946 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
947 HMODULE hm_advapi32
= NULL
;
948 if (is_windows_9x () == TRUE
)
952 if (g_b_init_copy_sid
== 0)
954 g_b_init_copy_sid
= 1;
955 hm_advapi32
= LoadLibrary ("Advapi32.dll");
957 (CopySid_Proc
) GetProcAddress (
958 hm_advapi32
, "CopySid");
960 if (s_pfn_Copy_Sid
== NULL
)
964 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
968 END: Wrapper functions around OpenProcessToken
969 and other functions in advapi32.dll that are only
970 supported in Windows NT / 2k / XP
974 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
976 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
977 if (is_windows_9x () != TRUE
)
979 if (g_b_init_get_native_system_info
== 0)
981 g_b_init_get_native_system_info
= 1;
982 s_pfn_Get_Native_System_Info
=
983 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
984 "GetNativeSystemInfo");
986 if (s_pfn_Get_Native_System_Info
!= NULL
)
987 s_pfn_Get_Native_System_Info (lpSystemInfo
);
990 lpSystemInfo
->dwNumberOfProcessors
= -1;
994 get_system_times (LPFILETIME lpIdleTime
,
995 LPFILETIME lpKernelTime
,
996 LPFILETIME lpUserTime
)
998 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
999 if (is_windows_9x () == TRUE
)
1003 if (g_b_init_get_system_times
== 0)
1005 g_b_init_get_system_times
= 1;
1006 s_pfn_Get_System_times
=
1007 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1010 if (s_pfn_Get_System_times
== NULL
)
1012 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
1015 static BOOLEAN WINAPI
1016 create_symbolic_link (LPCSTR lpSymlinkFilename
,
1017 LPCSTR lpTargetFileName
,
1020 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW
= NULL
;
1021 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA
= NULL
;
1024 if (is_windows_9x () == TRUE
)
1029 if (w32_unicode_filenames
)
1031 wchar_t symfn_w
[MAX_PATH
], tgtfn_w
[MAX_PATH
];
1033 if (g_b_init_create_symbolic_link_w
== 0)
1035 g_b_init_create_symbolic_link_w
= 1;
1036 s_pfn_Create_Symbolic_LinkW
=
1037 (CreateSymbolicLinkW_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1038 "CreateSymbolicLinkW");
1040 if (s_pfn_Create_Symbolic_LinkW
== NULL
)
1046 filename_to_utf16 (lpSymlinkFilename
, symfn_w
);
1047 filename_to_utf16 (lpTargetFileName
, tgtfn_w
);
1048 retval
= s_pfn_Create_Symbolic_LinkW (symfn_w
, tgtfn_w
, dwFlags
);
1049 /* If we were denied creation of the symlink, try again after
1050 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1053 TOKEN_PRIVILEGES priv_current
;
1055 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME
, TRUE
,
1058 retval
= s_pfn_Create_Symbolic_LinkW (symfn_w
, tgtfn_w
, dwFlags
);
1059 restore_privilege (&priv_current
);
1066 char symfn_a
[MAX_PATH
], tgtfn_a
[MAX_PATH
];
1068 if (g_b_init_create_symbolic_link_a
== 0)
1070 g_b_init_create_symbolic_link_a
= 1;
1071 s_pfn_Create_Symbolic_LinkA
=
1072 (CreateSymbolicLinkA_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1073 "CreateSymbolicLinkA");
1075 if (s_pfn_Create_Symbolic_LinkA
== NULL
)
1081 filename_to_ansi (lpSymlinkFilename
, symfn_a
);
1082 filename_to_ansi (lpTargetFileName
, tgtfn_a
);
1083 retval
= s_pfn_Create_Symbolic_LinkA (symfn_a
, tgtfn_a
, dwFlags
);
1084 /* If we were denied creation of the symlink, try again after
1085 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1088 TOKEN_PRIVILEGES priv_current
;
1090 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME
, TRUE
,
1093 retval
= s_pfn_Create_Symbolic_LinkA (symfn_a
, tgtfn_a
, dwFlags
);
1094 restore_privilege (&priv_current
);
1103 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor
)
1105 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc
= NULL
;
1107 if (is_windows_9x () == TRUE
)
1113 if (g_b_init_is_valid_security_descriptor
== 0)
1115 g_b_init_is_valid_security_descriptor
= 1;
1116 s_pfn_Is_Valid_Security_Descriptor_Proc
=
1117 (IsValidSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1118 "IsValidSecurityDescriptor");
1120 if (s_pfn_Is_Valid_Security_Descriptor_Proc
== NULL
)
1126 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor
);
1130 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor
,
1131 DWORD RequestedStringSDRevision
,
1132 SECURITY_INFORMATION SecurityInformation
,
1133 LPTSTR
*StringSecurityDescriptor
,
1134 PULONG StringSecurityDescriptorLen
)
1136 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL
= NULL
;
1139 if (is_windows_9x () == TRUE
)
1145 if (g_b_init_convert_sd_to_sddl
== 0)
1147 g_b_init_convert_sd_to_sddl
= 1;
1149 s_pfn_Convert_SD_To_SDDL
=
1150 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1151 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1153 s_pfn_Convert_SD_To_SDDL
=
1154 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1155 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1158 if (s_pfn_Convert_SD_To_SDDL
== NULL
)
1164 retval
= s_pfn_Convert_SD_To_SDDL (SecurityDescriptor
,
1165 RequestedStringSDRevision
,
1166 SecurityInformation
,
1167 StringSecurityDescriptor
,
1168 StringSecurityDescriptorLen
);
1174 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor
,
1175 DWORD StringSDRevision
,
1176 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
1177 PULONG SecurityDescriptorSize
)
1179 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD
= NULL
;
1182 if (is_windows_9x () == TRUE
)
1188 if (g_b_init_convert_sddl_to_sd
== 0)
1190 g_b_init_convert_sddl_to_sd
= 1;
1192 s_pfn_Convert_SDDL_To_SD
=
1193 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1194 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1196 s_pfn_Convert_SDDL_To_SD
=
1197 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1198 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1201 if (s_pfn_Convert_SDDL_To_SD
== NULL
)
1207 retval
= s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor
,
1210 SecurityDescriptorSize
);
1216 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo
, PULONG pOutBufLen
)
1218 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info
= NULL
;
1219 HMODULE hm_iphlpapi
= NULL
;
1221 if (is_windows_9x () == TRUE
)
1222 return ERROR_NOT_SUPPORTED
;
1224 if (g_b_init_get_adapters_info
== 0)
1226 g_b_init_get_adapters_info
= 1;
1227 hm_iphlpapi
= LoadLibrary ("Iphlpapi.dll");
1229 s_pfn_Get_Adapters_Info
= (GetAdaptersInfo_Proc
)
1230 GetProcAddress (hm_iphlpapi
, "GetAdaptersInfo");
1232 if (s_pfn_Get_Adapters_Info
== NULL
)
1233 return ERROR_NOT_SUPPORTED
;
1234 return s_pfn_Get_Adapters_Info (pAdapterInfo
, pOutBufLen
);
1239 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1240 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1242 This is called from alloc.c:valid_pointer_p. */
1244 w32_valid_pointer_p (void *p
, int size
)
1247 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
1251 unsigned char *buf
= alloca (size
);
1252 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
1263 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1264 codepage defined by file-name-coding-system. */
1266 /* Current codepage for encoding file names. */
1267 static int file_name_codepage
;
1269 /* Produce a Windows ANSI codepage suitable for encoding file names.
1270 Return the information about that codepage in CP_INFO. */
1272 codepage_for_filenames (CPINFO
*cp_info
)
1274 /* A simple cache to avoid calling GetCPInfo every time we need to
1275 encode/decode a file name. The file-name encoding is not
1276 supposed to be changed too frequently, if ever. */
1277 static Lisp_Object last_file_name_encoding
;
1279 Lisp_Object current_encoding
;
1281 current_encoding
= Vfile_name_coding_system
;
1282 if (NILP (current_encoding
))
1283 current_encoding
= Vdefault_file_name_coding_system
;
1285 if (!EQ (last_file_name_encoding
, current_encoding
))
1287 /* Default to the current ANSI codepage. */
1288 file_name_codepage
= w32_ansi_code_page
;
1290 if (NILP (current_encoding
))
1292 char *cpname
= SDATA (SYMBOL_NAME (current_encoding
));
1293 char *cp
= NULL
, *end
;
1296 if (strncmp (cpname
, "cp", 2) == 0)
1298 else if (strncmp (cpname
, "windows-", 8) == 0)
1304 cpnum
= strtol (cp
, &end
, 10);
1305 if (cpnum
&& *end
== '\0' && end
- cp
>= 2)
1306 file_name_codepage
= cpnum
;
1310 if (!file_name_codepage
)
1311 file_name_codepage
= CP_ACP
; /* CP_ACP = 0, but let's not assume that */
1313 if (!GetCPInfo (file_name_codepage
, &cp
))
1315 file_name_codepage
= CP_ACP
;
1316 if (!GetCPInfo (file_name_codepage
, &cp
))
1323 return file_name_codepage
;
1327 filename_to_utf16 (const char *fn_in
, wchar_t *fn_out
)
1329 int result
= MultiByteToWideChar (CP_UTF8
, MB_ERR_INVALID_CHARS
, fn_in
, -1,
1334 DWORD err
= GetLastError ();
1338 case ERROR_INVALID_FLAGS
:
1339 case ERROR_INVALID_PARAMETER
:
1342 case ERROR_INSUFFICIENT_BUFFER
:
1343 case ERROR_NO_UNICODE_TRANSLATION
:
1354 filename_from_utf16 (const wchar_t *fn_in
, char *fn_out
)
1356 int result
= WideCharToMultiByte (CP_UTF8
, 0, fn_in
, -1,
1357 fn_out
, MAX_UTF8_PATH
, NULL
, NULL
);
1361 DWORD err
= GetLastError ();
1365 case ERROR_INVALID_FLAGS
:
1366 case ERROR_INVALID_PARAMETER
:
1369 case ERROR_INSUFFICIENT_BUFFER
:
1370 case ERROR_NO_UNICODE_TRANSLATION
:
1381 filename_to_ansi (const char *fn_in
, char *fn_out
)
1383 wchar_t fn_utf16
[MAX_PATH
];
1385 if (filename_to_utf16 (fn_in
, fn_utf16
) == 0)
1388 int codepage
= codepage_for_filenames (NULL
);
1390 result
= WideCharToMultiByte (codepage
, 0, fn_utf16
, -1,
1391 fn_out
, MAX_PATH
, NULL
, NULL
);
1394 DWORD err
= GetLastError ();
1398 case ERROR_INVALID_FLAGS
:
1399 case ERROR_INVALID_PARAMETER
:
1402 case ERROR_INSUFFICIENT_BUFFER
:
1403 case ERROR_NO_UNICODE_TRANSLATION
:
1416 filename_from_ansi (const char *fn_in
, char *fn_out
)
1418 wchar_t fn_utf16
[MAX_PATH
];
1419 int codepage
= codepage_for_filenames (NULL
);
1420 int result
= MultiByteToWideChar (codepage
, MB_ERR_INVALID_CHARS
, fn_in
, -1,
1421 fn_utf16
, MAX_PATH
);
1425 DWORD err
= GetLastError ();
1429 case ERROR_INVALID_FLAGS
:
1430 case ERROR_INVALID_PARAMETER
:
1433 case ERROR_INSUFFICIENT_BUFFER
:
1434 case ERROR_NO_UNICODE_TRANSLATION
:
1441 return filename_from_utf16 (fn_utf16
, fn_out
);
1446 /* The directory where we started, in UTF-8. */
1447 static char startup_dir
[MAX_UTF8_PATH
];
1449 /* Get the current working directory. */
1451 getcwd (char *dir
, int dirsize
)
1458 if (dirsize
<= strlen (startup_dir
))
1464 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
1468 /* Emacs doesn't actually change directory itself, it stays in the
1469 same directory where it was started. */
1470 strcpy (dir
, startup_dir
);
1475 /* Emulate getloadavg. */
1477 struct load_sample
{
1484 /* Number of processors on this machine. */
1485 static unsigned num_of_processors
;
1487 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1488 static struct load_sample samples
[16*60];
1489 static int first_idx
= -1, last_idx
= -1;
1490 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
1495 int next_idx
= from
+ 1;
1497 if (next_idx
>= max_idx
)
1506 int prev_idx
= from
- 1;
1509 prev_idx
= max_idx
- 1;
1515 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
1517 SYSTEM_INFO sysinfo
;
1518 FILETIME ft_idle
, ft_user
, ft_kernel
;
1520 /* Initialize the number of processors on this machine. */
1521 if (num_of_processors
<= 0)
1523 get_native_system_info (&sysinfo
);
1524 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1525 if (num_of_processors
<= 0)
1527 GetSystemInfo (&sysinfo
);
1528 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1530 if (num_of_processors
<= 0)
1531 num_of_processors
= 1;
1534 /* TODO: Take into account threads that are ready to run, by
1535 sampling the "\System\Processor Queue Length" performance
1536 counter. The code below accounts only for threads that are
1537 actually running. */
1539 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
1541 ULARGE_INTEGER uidle
, ukernel
, uuser
;
1543 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
1544 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
1545 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
1546 *idle
= uidle
.QuadPart
;
1547 *kernel
= ukernel
.QuadPart
;
1548 *user
= uuser
.QuadPart
;
1558 /* Produce the load average for a given time interval, using the
1559 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1560 1-minute, 5-minute, or 15-minute average, respectively. */
1564 double retval
= -1.0;
1567 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
1568 time_t now
= samples
[last_idx
].sample_time
;
1570 if (first_idx
!= last_idx
)
1572 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
1574 tdiff
= difftime (now
, samples
[idx
].sample_time
);
1575 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
1578 samples
[last_idx
].kernel
+ samples
[last_idx
].user
1579 - (samples
[idx
].kernel
+ samples
[idx
].user
);
1580 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
1582 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
1585 if (idx
== first_idx
)
1594 getloadavg (double loadavg
[], int nelem
)
1597 ULONGLONG idle
, kernel
, user
;
1598 time_t now
= time (NULL
);
1600 /* Store another sample. We ignore samples that are less than 1 sec
1602 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
1604 sample_system_load (&idle
, &kernel
, &user
);
1605 last_idx
= buf_next (last_idx
);
1606 samples
[last_idx
].sample_time
= now
;
1607 samples
[last_idx
].idle
= idle
;
1608 samples
[last_idx
].kernel
= kernel
;
1609 samples
[last_idx
].user
= user
;
1610 /* If the buffer has more that 15 min worth of samples, discard
1612 if (first_idx
== -1)
1613 first_idx
= last_idx
;
1614 while (first_idx
!= last_idx
1615 && (difftime (now
, samples
[first_idx
].sample_time
)
1616 >= 15.0*60 + 2*DBL_EPSILON
*now
))
1617 first_idx
= buf_next (first_idx
);
1620 for (elem
= 0; elem
< nelem
; elem
++)
1622 double avg
= getavg (elem
);
1626 loadavg
[elem
] = avg
;
1632 /* Emulate getpwuid, getpwnam and others. */
1634 #define PASSWD_FIELD_SIZE 256
1636 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1637 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1638 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1639 static char dflt_passwd_dir
[MAX_UTF8_PATH
];
1640 static char dflt_passwd_shell
[MAX_UTF8_PATH
];
1642 static struct passwd dflt_passwd
=
1654 static char dflt_group_name
[GNLEN
+1];
1656 static struct group dflt_group
=
1658 /* When group information is not available, we return this as the
1659 group for all files. */
1667 return dflt_passwd
.pw_uid
;
1673 /* I could imagine arguing for checking to see whether the user is
1674 in the Administrators group and returning a UID of 0 for that
1675 case, but I don't know how wise that would be in the long run. */
1682 return dflt_passwd
.pw_gid
;
1692 getpwuid (unsigned uid
)
1694 if (uid
== dflt_passwd
.pw_uid
)
1695 return &dflt_passwd
;
1700 getgrgid (gid_t gid
)
1706 getpwnam (char *name
)
1710 pw
= getpwuid (getuid ());
1714 if (xstrcasecmp (name
, pw
->pw_name
))
1721 init_user_info (void)
1723 /* Find the user's real name by opening the process token and
1724 looking up the name associated with the user-sid in that token.
1726 Use the relative portion of the identifier authority value from
1727 the user-sid as the user id value (same for group id using the
1728 primary group sid from the process token). */
1730 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1731 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1732 DWORD glength
= sizeof (gname
);
1733 HANDLE token
= NULL
;
1734 SID_NAME_USE user_type
;
1735 unsigned char *buf
= NULL
;
1737 TOKEN_USER user_token
;
1738 TOKEN_PRIMARY_GROUP group_token
;
1741 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1744 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1745 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1747 buf
= xmalloc (blen
);
1748 result
= get_token_information (token
, TokenUser
,
1749 (LPVOID
)buf
, blen
, &needed
);
1752 memcpy (&user_token
, buf
, sizeof (user_token
));
1753 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1755 domain
, &dlength
, &user_type
);
1763 strcpy (dflt_passwd
.pw_name
, uname
);
1764 /* Determine a reasonable uid value. */
1765 if (xstrcasecmp ("administrator", uname
) == 0)
1767 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1768 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1772 /* Use the last sub-authority value of the RID, the relative
1773 portion of the SID, as user/group ID. */
1774 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1776 /* Get group id and name. */
1777 result
= get_token_information (token
, TokenPrimaryGroup
,
1778 (LPVOID
)buf
, blen
, &needed
);
1779 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1781 buf
= xrealloc (buf
, blen
= needed
);
1782 result
= get_token_information (token
, TokenPrimaryGroup
,
1783 (LPVOID
)buf
, blen
, &needed
);
1787 memcpy (&group_token
, buf
, sizeof (group_token
));
1788 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1789 dlength
= sizeof (domain
);
1790 /* If we can get at the real Primary Group name, use that.
1791 Otherwise, the default group name was already set to
1792 "None" in globals_of_w32. */
1793 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1794 gname
, &glength
, NULL
, &dlength
,
1796 strcpy (dflt_group_name
, gname
);
1799 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1802 /* If security calls are not supported (presumably because we
1803 are running under Windows 9X), fallback to this: */
1804 else if (GetUserName (uname
, &ulength
))
1806 strcpy (dflt_passwd
.pw_name
, uname
);
1807 if (xstrcasecmp ("administrator", uname
) == 0)
1808 dflt_passwd
.pw_uid
= 0;
1810 dflt_passwd
.pw_uid
= 123;
1811 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1815 strcpy (dflt_passwd
.pw_name
, "unknown");
1816 dflt_passwd
.pw_uid
= 123;
1817 dflt_passwd
.pw_gid
= 123;
1819 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1821 /* Set dir and shell from environment variables. */
1822 if (w32_unicode_filenames
)
1824 wchar_t *home
= _wgetenv (L
"HOME");
1825 wchar_t *shell
= _wgetenv (L
"SHELL");
1827 /* Ensure HOME and SHELL are defined. */
1832 filename_from_utf16 (home
, dflt_passwd
.pw_dir
);
1833 filename_from_utf16 (shell
, dflt_passwd
.pw_shell
);
1837 char *home
= getenv ("HOME");
1838 char *shell
= getenv ("SHELL");
1844 filename_from_ansi (home
, dflt_passwd
.pw_dir
);
1845 filename_from_ansi (shell
, dflt_passwd
.pw_shell
);
1850 CloseHandle (token
);
1856 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1857 return ((rand () << 15) | rand ());
1866 /* Return the maximum length in bytes of a multibyte character
1867 sequence encoded in the current ANSI codepage. This is required to
1868 correctly walk the encoded file names one character at a time. */
1870 max_filename_mbslen (void)
1874 codepage_for_filenames (&cp_info
);
1875 return cp_info
.MaxCharSize
;
1878 /* Normalize filename by converting in-place all of its path
1879 separators to the separator specified by PATH_SEP. */
1882 normalize_filename (register char *fp
, char path_sep
)
1886 /* Always lower-case drive letters a-z, even if the filesystem
1887 preserves case in filenames.
1888 This is so filenames can be compared by string comparison
1889 functions that are case-sensitive. Even case-preserving filesystems
1890 do not distinguish case in drive letters. */
1893 if (*p2
== ':' && *fp
>= 'A' && *fp
<= 'Z')
1901 if (*fp
== '/' || *fp
== '\\')
1907 /* Destructively turn backslashes into slashes. */
1909 dostounix_filename (register char *p
)
1911 normalize_filename (p
, '/');
1914 /* Destructively turn slashes into backslashes. */
1916 unixtodos_filename (register char *p
)
1918 normalize_filename (p
, '\\');
1921 /* Remove all CR's that are followed by a LF.
1922 (From msdos.c...probably should figure out a way to share it,
1923 although this code isn't going to ever change.) */
1925 crlf_to_lf (register int n
, register unsigned char *buf
)
1927 unsigned char *np
= buf
;
1928 unsigned char *startp
= buf
;
1929 unsigned char *endp
= buf
+ n
;
1933 while (buf
< endp
- 1)
1937 if (*(++buf
) != 0x0a)
1948 /* Parse the root part of file name, if present. Return length and
1949 optionally store pointer to char after root. */
1951 parse_root (const char * name
, const char ** pPath
)
1953 const char * start
= name
;
1958 /* find the root name of the volume if given */
1959 if (isalpha (name
[0]) && name
[1] == ':')
1961 /* skip past drive specifier */
1963 if (IS_DIRECTORY_SEP (name
[0]))
1966 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1973 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1978 if (IS_DIRECTORY_SEP (name
[0]))
1985 return name
- start
;
1988 /* Get long base name for name; name is assumed to be absolute. */
1990 get_long_basename (char * name
, char * buf
, int size
)
1993 char fname_utf8
[MAX_UTF8_PATH
];
1997 /* Must be valid filename, no wild cards or other invalid characters. */
1998 if (strpbrk (name
, "*?|<>\""))
2001 if (w32_unicode_filenames
)
2003 wchar_t fname_utf16
[MAX_PATH
];
2004 WIN32_FIND_DATAW find_data_wide
;
2006 filename_to_utf16 (name
, fname_utf16
);
2007 dir_handle
= FindFirstFileW (fname_utf16
, &find_data_wide
);
2008 if (dir_handle
!= INVALID_HANDLE_VALUE
)
2009 cstatus
= filename_from_utf16 (find_data_wide
.cFileName
, fname_utf8
);
2013 char fname_ansi
[MAX_PATH
];
2014 WIN32_FIND_DATAA find_data_ansi
;
2016 filename_to_ansi (name
, fname_ansi
);
2017 dir_handle
= FindFirstFileA (fname_ansi
, &find_data_ansi
);
2018 if (dir_handle
!= INVALID_HANDLE_VALUE
)
2019 cstatus
= filename_from_ansi (find_data_ansi
.cFileName
, fname_utf8
);
2022 if (cstatus
== 0 && (len
= strlen (fname_utf8
)) < size
)
2023 memcpy (buf
, fname_utf8
, len
+ 1);
2027 if (dir_handle
!= INVALID_HANDLE_VALUE
)
2028 FindClose (dir_handle
);
2033 /* Get long name for file, if possible (assumed to be absolute). */
2035 w32_get_long_filename (char * name
, char * buf
, int size
)
2040 char full
[ MAX_UTF8_PATH
];
2043 len
= strlen (name
);
2044 if (len
>= MAX_UTF8_PATH
)
2047 /* Use local copy for destructive modification. */
2048 memcpy (full
, name
, len
+1);
2049 unixtodos_filename (full
);
2051 /* Copy root part verbatim. */
2052 len
= parse_root (full
, (const char **)&p
);
2053 memcpy (o
, full
, len
);
2058 while (p
!= NULL
&& *p
)
2061 p
= strchr (q
, '\\');
2063 len
= get_long_basename (full
, o
, size
);
2086 w32_get_short_filename (char * name
, char * buf
, int size
)
2088 if (w32_unicode_filenames
)
2090 wchar_t name_utf16
[MAX_PATH
], short_name
[MAX_PATH
];
2091 unsigned int retval
;
2093 filename_to_utf16 (name
, name_utf16
);
2094 retval
= GetShortPathNameW (name_utf16
, short_name
, size
);
2095 if (retval
&& retval
< size
)
2096 filename_from_utf16 (short_name
, buf
);
2101 char name_ansi
[MAX_PATH
];
2103 filename_to_ansi (name
, name_ansi
);
2104 return GetShortPathNameA (name_ansi
, buf
, size
);
2109 is_unc_volume (const char *filename
)
2111 const char *ptr
= filename
;
2113 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
2116 if (strpbrk (ptr
+ 2, "*?|<>\"\\/"))
2122 /* Emulate the Posix unsetenv. */
2124 unsetenv (const char *name
)
2130 if (name
== NULL
|| *name
== '\0' || strchr (name
, '=') != NULL
)
2135 name_len
= strlen (name
);
2136 /* MS docs says an environment variable cannot be longer than 32K. */
2137 if (name_len
> 32767)
2142 /* It is safe to use 'alloca' with 32K size, since the stack is at
2143 least 2MB, and we set it to 8MB in the link command line. */
2144 var
= alloca (name_len
+ 2);
2145 strncpy (var
, name
, name_len
);
2146 var
[name_len
++] = '=';
2147 var
[name_len
] = '\0';
2148 return _putenv (var
);
2151 /* MS _putenv doesn't support removing a variable when the argument
2152 does not include the '=' character, so we fix that here. */
2154 sys_putenv (char *str
)
2156 const char *const name_end
= strchr (str
, '=');
2158 if (name_end
== NULL
)
2160 /* Remove the variable from the environment. */
2161 return unsetenv (str
);
2164 return _putenv (str
);
2167 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2170 w32_get_resource (char *key
, LPDWORD lpdwtype
)
2173 HKEY hrootkey
= NULL
;
2176 /* Check both the current user and the local machine to see if
2177 we have any resources. */
2179 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
2183 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
2184 && (lpvalue
= xmalloc (cbData
)) != NULL
2185 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
2187 RegCloseKey (hrootkey
);
2193 RegCloseKey (hrootkey
);
2196 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
2200 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
2201 && (lpvalue
= xmalloc (cbData
)) != NULL
2202 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
2204 RegCloseKey (hrootkey
);
2210 RegCloseKey (hrootkey
);
2217 init_environment (char ** argv
)
2219 static const char * const tempdirs
[] = {
2220 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2225 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
2227 /* Implementation note: This function explicitly works with ANSI
2228 file names, not with UTF-8 encoded file names. This is because
2229 this function pushes variables into the Emacs's environment, and
2230 the environment variables are always assumed to be in the
2231 locale-specific encoding. Do NOT call any functions that accept
2232 UTF-8 file names from this function! */
2234 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2235 temporary files and assume "/tmp" if $TMPDIR is unset, which
2236 will break on DOS/Windows. Refuse to work if we cannot find
2237 a directory, not even "c:/", usable for that purpose. */
2238 for (i
= 0; i
< imax
; i
++)
2240 const char *tmp
= tempdirs
[i
];
2243 tmp
= getenv (tmp
+ 1);
2244 /* Note that `access' can lie to us if the directory resides on a
2245 read-only filesystem, like CD-ROM or a write-protected floppy.
2246 The only way to be really sure is to actually create a file and
2247 see if it succeeds. But I think that's too much to ask. */
2249 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2250 if (tmp
&& sys_access (tmp
, D_OK
) == 0)
2252 char * var
= alloca (strlen (tmp
) + 8);
2253 sprintf (var
, "TMPDIR=%s", tmp
);
2254 _putenv (strdup (var
));
2261 Fcons (build_string ("no usable temporary directories found!!"),
2263 "While setting TMPDIR: ");
2265 /* Check for environment variables and use registry settings if they
2266 don't exist. Fallback on default values where applicable. */
2271 char locale_name
[32];
2272 char default_home
[MAX_PATH
];
2275 static const struct env_entry
2281 /* If the default value is NULL, we will use the value from the
2282 outside environment or the Registry, but will not push the
2283 variable into the Emacs environment if it is defined neither
2284 in the Registry nor in the outside environment. */
2286 {"PRELOAD_WINSOCK", NULL
},
2287 {"emacs_dir", "C:/emacs"},
2288 {"EMACSLOADPATH", NULL
},
2289 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2290 {"EMACSDATA", NULL
},
2291 {"EMACSPATH", NULL
},
2298 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2300 /* We need to copy dflt_envvars[] and work on the copy because we
2301 don't want the dumped Emacs to inherit the values of
2302 environment variables we saw during dumping (which could be on
2303 a different system). The defaults above must be left intact. */
2304 struct env_entry env_vars
[N_ENV_VARS
];
2306 for (i
= 0; i
< N_ENV_VARS
; i
++)
2307 env_vars
[i
] = dflt_envvars
[i
];
2309 /* For backwards compatibility, check if a .emacs file exists in C:/
2310 If not, then we can try to default to the appdata directory under the
2311 user's profile, which is more likely to be writable. */
2312 if (sys_access ("C:/.emacs", F_OK
) != 0)
2314 HRESULT profile_result
;
2315 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2316 of Windows 95 and NT4 that have not been updated to include
2318 ShGetFolderPath_fn get_folder_path
;
2319 get_folder_path
= (ShGetFolderPath_fn
)
2320 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2322 if (get_folder_path
!= NULL
)
2324 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
2327 /* If we can't get the appdata dir, revert to old behavior. */
2328 if (profile_result
== S_OK
)
2330 env_vars
[0].def_value
= default_home
;
2336 /* Get default locale info and use it for LANG. */
2337 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
2338 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
2339 locale_name
, sizeof (locale_name
)))
2341 for (i
= 0; i
< N_ENV_VARS
; i
++)
2343 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
2345 env_vars
[i
].def_value
= locale_name
;
2351 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2353 /* Treat emacs_dir specially: set it unconditionally based on our
2357 char modname
[MAX_PATH
];
2359 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2361 if ((p
= _mbsrchr (modname
, '\\')) == NULL
)
2365 if ((p
= _mbsrchr (modname
, '\\'))
2366 /* From bin means installed Emacs, from src means uninstalled. */
2367 && (xstrcasecmp (p
, "\\bin") == 0 || xstrcasecmp (p
, "\\src") == 0))
2369 char buf
[SET_ENV_BUF_SIZE
];
2370 int within_build_tree
= xstrcasecmp (p
, "\\src") == 0;
2373 for (p
= modname
; *p
; p
= CharNext (p
))
2374 if (*p
== '\\') *p
= '/';
2376 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
2377 _putenv (strdup (buf
));
2378 /* If we are running from the Posix-like build tree, define
2379 SHELL to point to our own cmdproxy. The loop below will
2380 then disregard PATH_EXEC and the default value. */
2381 if (within_build_tree
)
2383 _snprintf (buf
, sizeof (buf
) - 1,
2384 "SHELL=%s/nt/cmdproxy.exe", modname
);
2385 _putenv (strdup (buf
));
2390 for (i
= 0; i
< N_ENV_VARS
; i
++)
2392 if (!getenv (env_vars
[i
].name
))
2395 char bufc
[SET_ENV_BUF_SIZE
];
2397 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
2398 /* Also ignore empty environment variables. */
2403 if (strcmp (env_vars
[i
].name
, "SHELL") == 0)
2405 /* Look for cmdproxy.exe in every directory in
2406 PATH_EXEC. FIXME: This does not find cmdproxy
2407 in nt/ when we run uninstalled. */
2408 char fname
[MAX_PATH
];
2409 const char *pstart
= PATH_EXEC
, *pend
;
2412 pend
= _mbschr (pstart
, ';');
2414 pend
= pstart
+ strlen (pstart
);
2415 /* Be defensive against series of ;;; characters. */
2418 strncpy (fname
, pstart
, pend
- pstart
);
2419 fname
[pend
- pstart
] = '/';
2420 strcpy (&fname
[pend
- pstart
+ 1], "cmdproxy.exe");
2421 ExpandEnvironmentStrings ((LPSTR
) fname
, bufc
,
2423 if (sys_access (bufc
, F_OK
) == 0)
2436 /* If not found in any directory, use the
2437 default as the last resort. */
2438 lpval
= env_vars
[i
].def_value
;
2439 dwType
= REG_EXPAND_SZ
;
2445 lpval
= env_vars
[i
].def_value
;
2446 dwType
= REG_EXPAND_SZ
;
2448 if (strcmp (env_vars
[i
].name
, "HOME") == 0 && !appdata
)
2449 Vdelayed_warnings_list
2450 = Fcons (listn (CONSTYPE_HEAP
, 2,
2451 intern ("initialization"),
2452 build_string ("Setting HOME to C:\\ by default is deprecated")),
2453 Vdelayed_warnings_list
);
2458 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
2460 if (dwType
== REG_EXPAND_SZ
)
2461 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
2462 else if (dwType
== REG_SZ
)
2463 strcpy (buf1
, lpval
);
2464 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
2466 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
2468 _putenv (strdup (buf2
));
2478 /* Rebuild system configuration to reflect invoking system. */
2479 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
2481 /* Another special case: on NT, the PATH variable is actually named
2482 "Path" although cmd.exe (perhaps NT itself) arranges for
2483 environment variable lookup and setting to be case insensitive.
2484 However, Emacs assumes a fully case sensitive environment, so we
2485 need to change "Path" to "PATH" to match the expectations of
2486 various elisp packages. We do this by the sneaky method of
2487 modifying the string in the C runtime environ entry.
2489 The same applies to COMSPEC. */
2493 for (envp
= environ
; *envp
; envp
++)
2494 if (_strnicmp (*envp
, "PATH=", 5) == 0)
2495 memcpy (*envp
, "PATH=", 5);
2496 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
2497 memcpy (*envp
, "COMSPEC=", 8);
2500 /* Remember the initial working directory for getcwd. */
2501 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2502 Does it matter anywhere in Emacs? */
2503 if (w32_unicode_filenames
)
2505 wchar_t wstartup_dir
[MAX_PATH
];
2507 if (!GetCurrentDirectoryW (MAX_PATH
, wstartup_dir
))
2509 filename_from_utf16 (wstartup_dir
, startup_dir
);
2513 char astartup_dir
[MAX_PATH
];
2515 if (!GetCurrentDirectoryA (MAX_PATH
, astartup_dir
))
2517 filename_from_ansi (astartup_dir
, startup_dir
);
2521 static char modname
[MAX_PATH
];
2523 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2528 /* Determine if there is a middle mouse button, to allow parse_button
2529 to decide whether right mouse events should be mouse-2 or
2531 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
2536 /* Called from expand-file-name when default-directory is not a string. */
2539 emacs_root_dir (void)
2541 static char root_dir
[MAX_UTF8_PATH
];
2544 p
= getenv ("emacs_dir");
2547 filename_from_ansi (p
, root_dir
);
2548 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
2549 dostounix_filename (root_dir
);
2553 #include <sys/timeb.h>
2555 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2557 gettimeofday (struct timeval
*__restrict tv
, struct timezone
*__restrict tz
)
2562 tv
->tv_sec
= tb
.time
;
2563 tv
->tv_usec
= tb
.millitm
* 1000L;
2564 /* Implementation note: _ftime sometimes doesn't update the dstflag
2565 according to the new timezone when the system timezone is
2566 changed. We could fix that by using GetSystemTime and
2567 GetTimeZoneInformation, but that doesn't seem necessary, since
2568 Emacs always calls gettimeofday with the 2nd argument NULL (see
2569 current_emacs_time). */
2572 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
2573 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
2578 /* Emulate fdutimens. */
2580 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2581 TIMESPEC[0] and TIMESPEC[1], respectively.
2582 FD must be either negative -- in which case it is ignored --
2583 or a file descriptor that is open on FILE.
2584 If FD is nonnegative, then FILE can be NULL, which means
2585 use just futimes instead of utimes.
2586 If TIMESPEC is null, FAIL.
2587 Return 0 on success, -1 (setting errno) on failure. */
2590 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
2597 if (fd
< 0 && !file
)
2602 /* _futime's prototype defines 2nd arg as having the type 'struct
2603 _utimbuf', while utime needs to accept 'struct utimbuf' for
2604 compatibility with Posix. So we need to use 2 different (but
2605 equivalent) types to avoid compiler warnings, sigh. */
2608 struct _utimbuf _ut
;
2610 _ut
.actime
= timespec
[0].tv_sec
;
2611 _ut
.modtime
= timespec
[1].tv_sec
;
2612 return _futime (fd
, &_ut
);
2618 ut
.actime
= timespec
[0].tv_sec
;
2619 ut
.modtime
= timespec
[1].tv_sec
;
2620 /* Call 'utime', which is implemented below, not the MS library
2621 function, which fails on directories. */
2622 return utime (file
, &ut
);
2627 /* ------------------------------------------------------------------------- */
2628 /* IO support and wrapper functions for the Windows API. */
2629 /* ------------------------------------------------------------------------- */
2631 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2632 on network directories, so we handle that case here.
2633 (Ulrich Leodolter, 1/11/95). */
2635 sys_ctime (const time_t *t
)
2637 char *str
= (char *) ctime (t
);
2638 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2641 /* Emulate sleep...we could have done this with a define, but that
2642 would necessitate including windows.h in the files that used it.
2643 This is much easier. */
2645 sys_sleep (int seconds
)
2647 Sleep (seconds
* 1000);
2650 /* Internal MSVC functions for low-level descriptor munging */
2651 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2652 extern int __cdecl
_free_osfhnd (int fd
);
2654 /* parallel array of private info on file handles */
2655 filedesc fd_info
[ MAXDESC
];
2657 typedef struct volume_info_data
{
2658 struct volume_info_data
* next
;
2660 /* time when info was obtained */
2663 /* actual volume info */
2672 /* Global referenced by various functions. */
2673 static volume_info_data volume_info
;
2675 /* Vector to indicate which drives are local and fixed (for which cached
2676 data never expires). */
2677 static BOOL fixed_drives
[26];
2679 /* Consider cached volume information to be stale if older than 10s,
2680 at least for non-local drives. Info for fixed drives is never stale. */
2681 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2682 #define VOLINFO_STILL_VALID( root_dir, info ) \
2683 ( ( isalpha (root_dir[0]) && \
2684 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2685 || GetTickCount () - info->timestamp < 10000 )
2687 /* Cache support functions. */
2689 /* Simple linked list with linear search is sufficient. */
2690 static volume_info_data
*volume_cache
= NULL
;
2692 static volume_info_data
*
2693 lookup_volume_info (char * root_dir
)
2695 volume_info_data
* info
;
2697 for (info
= volume_cache
; info
; info
= info
->next
)
2698 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2704 add_volume_info (char * root_dir
, volume_info_data
* info
)
2706 info
->root_dir
= xstrdup (root_dir
);
2707 unixtodos_filename (info
->root_dir
);
2708 info
->next
= volume_cache
;
2709 volume_cache
= info
;
2713 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2714 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2715 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2716 static volume_info_data
*
2717 GetCachedVolumeInformation (char * root_dir
)
2719 volume_info_data
* info
;
2720 char default_root
[ MAX_UTF8_PATH
];
2721 char name
[MAX_PATH
+1];
2722 char type
[MAX_PATH
+1];
2724 /* NULL for root_dir means use root from current directory. */
2725 if (root_dir
== NULL
)
2727 if (w32_unicode_filenames
)
2729 wchar_t curdirw
[MAX_PATH
];
2731 if (GetCurrentDirectoryW (MAX_PATH
, curdirw
) == 0)
2733 filename_from_utf16 (curdirw
, default_root
);
2737 char curdira
[MAX_PATH
];
2739 if (GetCurrentDirectoryA (MAX_PATH
, curdira
) == 0)
2741 filename_from_ansi (curdira
, default_root
);
2743 parse_root (default_root
, (const char **)&root_dir
);
2745 root_dir
= default_root
;
2748 /* Local fixed drives can be cached permanently. Removable drives
2749 cannot be cached permanently, since the volume name and serial
2750 number (if nothing else) can change. Remote drives should be
2751 treated as if they are removable, since there is no sure way to
2752 tell whether they are or not. Also, the UNC association of drive
2753 letters mapped to remote volumes can be changed at any time (even
2754 by other processes) without notice.
2756 As a compromise, so we can benefit from caching info for remote
2757 volumes, we use a simple expiry mechanism to invalidate cache
2758 entries that are more than ten seconds old. */
2761 /* No point doing this, because WNetGetConnection is even slower than
2762 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2763 GetDriveType is about the only call of this type which does not
2764 involve network access, and so is extremely quick). */
2766 /* Map drive letter to UNC if remote. */
2767 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2769 char remote_name
[ 256 ];
2770 char drive
[3] = { root_dir
[0], ':' };
2772 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2774 /* do something */ ;
2778 info
= lookup_volume_info (root_dir
);
2780 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2786 /* Info is not cached, or is stale. */
2787 if (w32_unicode_filenames
)
2789 wchar_t root_w
[MAX_PATH
];
2790 wchar_t name_w
[MAX_PATH
+1];
2791 wchar_t type_w
[MAX_PATH
+1];
2793 filename_to_utf16 (root_dir
, root_w
);
2794 if (!GetVolumeInformationW (root_w
,
2795 name_w
, sizeof (name_w
),
2799 type_w
, sizeof (type_w
)))
2801 /* Hmm... not really 100% correct, as these 2 are not file
2803 filename_from_utf16 (name_w
, name
);
2804 filename_from_utf16 (type_w
, type
);
2808 char root_a
[MAX_PATH
];
2809 char name_a
[MAX_PATH
+1];
2810 char type_a
[MAX_PATH
+1];
2812 filename_to_ansi (root_dir
, root_a
);
2813 if (!GetVolumeInformationA (root_a
,
2814 name_a
, sizeof (name_a
),
2818 type_a
, sizeof (type_a
)))
2820 filename_from_ansi (name_a
, name
);
2821 filename_from_ansi (type_a
, type
);
2824 /* Cache the volume information for future use, overwriting existing
2825 entry if present. */
2828 info
= xmalloc (sizeof (volume_info_data
));
2829 add_volume_info (root_dir
, info
);
2837 info
->name
= xstrdup (name
);
2838 unixtodos_filename (info
->name
);
2839 info
->serialnum
= serialnum
;
2840 info
->maxcomp
= maxcomp
;
2841 info
->flags
= flags
;
2842 info
->type
= xstrdup (type
);
2843 info
->timestamp
= GetTickCount ();
2849 /* Get information on the volume where NAME is held; set path pointer to
2850 start of pathname in NAME (past UNC header\volume header if present),
2851 if pPath is non-NULL.
2853 Note: if NAME includes symlinks, the information is for the volume
2854 of the symlink, not of its target. That's because, even though
2855 GetVolumeInformation returns information about the symlink target
2856 of its argument, we only pass the root directory to
2857 GetVolumeInformation, not the full NAME. */
2859 get_volume_info (const char * name
, const char ** pPath
)
2861 char temp
[MAX_UTF8_PATH
];
2862 char *rootname
= NULL
; /* default to current volume */
2863 volume_info_data
* info
;
2864 int root_len
= parse_root (name
, pPath
);
2869 /* Copy the root name of the volume, if given. */
2872 strncpy (temp
, name
, root_len
);
2873 temp
[root_len
] = '\0';
2874 unixtodos_filename (temp
);
2878 info
= GetCachedVolumeInformation (rootname
);
2881 /* Set global referenced by other functions. */
2882 volume_info
= *info
;
2888 /* Determine if volume is FAT format (ie. only supports short 8.3
2889 names); also set path pointer to start of pathname in name, if
2890 pPath is non-NULL. */
2892 is_fat_volume (const char * name
, const char ** pPath
)
2894 if (get_volume_info (name
, pPath
))
2895 return (volume_info
.maxcomp
== 12);
2899 /* Convert all slashes in a filename to backslashes, and map filename
2900 to a valid 8.3 name if necessary. The result is a pointer to a
2901 static buffer, so CAVEAT EMPTOR! */
2903 map_w32_filename (const char * name
, const char ** pPath
)
2905 static char shortname
[MAX_UTF8_PATH
];
2906 char * str
= shortname
;
2909 const char * save_name
= name
;
2911 if (strlen (name
) >= sizeof (shortname
))
2913 /* Return a filename which will cause callers to fail. */
2914 strcpy (shortname
, "?");
2918 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2920 register int left
= 8; /* maximum number of chars in part */
2921 register int extn
= 0; /* extension added? */
2922 register int dots
= 2; /* maximum number of dots allowed */
2925 *str
++ = *name
++; /* skip past UNC header */
2927 while ((c
= *name
++))
2934 *str
++ = (c
== ':' ? ':' : '\\');
2935 extn
= 0; /* reset extension flags */
2936 dots
= 2; /* max 2 dots */
2937 left
= 8; /* max length 8 for main part */
2942 /* Convert path components of the form .xxx to _xxx,
2943 but leave . and .. as they are. This allows .emacs
2944 to be read as _emacs, for example. */
2948 IS_DIRECTORY_SEP (*name
))
2963 extn
= 1; /* we've got an extension */
2964 left
= 3; /* 3 chars in extension */
2968 /* any embedded dots after the first are converted to _ */
2973 case '#': /* don't lose these, they're important */
2975 str
[-1] = c
; /* replace last character of part */
2978 if ( left
&& 'A' <= c
&& c
<= 'Z' )
2980 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2982 dots
= 0; /* started a path component */
2991 strcpy (shortname
, name
);
2992 unixtodos_filename (shortname
);
2996 *pPath
= shortname
+ (path
- save_name
);
3002 is_exec (const char * name
)
3004 char * p
= strrchr (name
, '.');
3007 && (xstrcasecmp (p
, ".exe") == 0 ||
3008 xstrcasecmp (p
, ".com") == 0 ||
3009 xstrcasecmp (p
, ".bat") == 0 ||
3010 xstrcasecmp (p
, ".cmd") == 0));
3013 /* Emulate the Unix directory procedures opendir, closedir, and
3014 readdir. We rename them to sys_* names because some versions of
3015 MinGW startup code call opendir and readdir to glob wildcards, and
3016 the code that calls them doesn't grok UTF-8 encoded file names we
3017 produce in dirent->d_name[]. */
3019 struct dirent dir_static
; /* simulated directory contents */
3020 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
3021 static int dir_is_fat
;
3022 static char dir_pathname
[MAX_UTF8_PATH
];
3023 static WIN32_FIND_DATAW dir_find_data_w
;
3024 static WIN32_FIND_DATAA dir_find_data_a
;
3025 #define DIR_FIND_DATA_W 1
3026 #define DIR_FIND_DATA_A 2
3027 static int last_dir_find_data
= -1;
3029 /* Support shares on a network resource as subdirectories of a read-only
3031 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
3032 static HANDLE
open_unc_volume (const char *);
3033 static void *read_unc_volume (HANDLE
, wchar_t *, char *, int);
3034 static void close_unc_volume (HANDLE
);
3037 sys_opendir (const char *filename
)
3041 /* Opening is done by FindFirstFile. However, a read is inherent to
3042 this operation, so we defer the open until read time. */
3044 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
3046 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
3049 /* Note: We don't support traversal of UNC volumes via symlinks.
3050 Doing so would mean punishing 99.99% of use cases by resolving
3051 all the possible symlinks in FILENAME, recursively. */
3052 if (is_unc_volume (filename
))
3054 wnet_enum_handle
= open_unc_volume (filename
);
3055 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
3059 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
3066 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAX_UTF8_PATH
- 1);
3067 dir_pathname
[MAX_UTF8_PATH
- 1] = '\0';
3068 /* Note: We don't support symlinks to file names on FAT volumes.
3069 Doing so would mean punishing 99.99% of use cases by resolving
3070 all the possible symlinks in FILENAME, recursively. */
3071 dir_is_fat
= is_fat_volume (filename
, NULL
);
3077 sys_closedir (DIR *dirp
)
3079 /* If we have a find-handle open, close it. */
3080 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
3082 FindClose (dir_find_handle
);
3083 dir_find_handle
= INVALID_HANDLE_VALUE
;
3085 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
3087 close_unc_volume (wnet_enum_handle
);
3088 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
3090 xfree ((char *) dirp
);
3094 sys_readdir (DIR *dirp
)
3096 int downcase
= !NILP (Vw32_downcase_file_names
);
3098 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
3100 if (!read_unc_volume (wnet_enum_handle
,
3101 dir_find_data_w
.cFileName
,
3102 dir_find_data_a
.cFileName
,
3106 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3107 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
3109 char filename
[MAX_UTF8_PATH
+ 2];
3112 strcpy (filename
, dir_pathname
);
3113 ln
= strlen (filename
) - 1;
3114 if (!IS_DIRECTORY_SEP (filename
[ln
]))
3115 strcat (filename
, "\\");
3116 strcat (filename
, "*");
3118 /* Note: No need to resolve symlinks in FILENAME, because
3119 FindFirst opens the directory that is the target of a
3121 if (w32_unicode_filenames
)
3123 wchar_t fnw
[MAX_PATH
];
3125 filename_to_utf16 (filename
, fnw
);
3126 dir_find_handle
= FindFirstFileW (fnw
, &dir_find_data_w
);
3132 filename_to_ansi (filename
, fna
);
3133 /* If FILENAME is not representable by the current ANSI
3134 codepage, we don't want FindFirstFileA to interpret the
3135 '?' characters as a wildcard. */
3136 if (_mbspbrk (fna
, "?"))
3137 dir_find_handle
= INVALID_HANDLE_VALUE
;
3139 dir_find_handle
= FindFirstFileA (fna
, &dir_find_data_a
);
3142 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
3145 else if (w32_unicode_filenames
)
3147 if (!FindNextFileW (dir_find_handle
, &dir_find_data_w
))
3152 if (!FindNextFileA (dir_find_handle
, &dir_find_data_a
))
3156 /* Emacs never uses this value, so don't bother making it match
3157 value returned by stat(). */
3158 dir_static
.d_ino
= 1;
3160 if (w32_unicode_filenames
)
3162 if (downcase
|| dir_is_fat
)
3164 wchar_t tem
[MAX_PATH
];
3166 wcscpy (tem
, dir_find_data_w
.cFileName
);
3168 filename_from_utf16 (tem
, dir_static
.d_name
);
3171 filename_from_utf16 (dir_find_data_w
.cFileName
, dir_static
.d_name
);
3172 last_dir_find_data
= DIR_FIND_DATA_W
;
3178 /* If the file name in cFileName[] includes `?' characters, it
3179 means the original file name used characters that cannot be
3180 represented by the current ANSI codepage. To avoid total
3181 lossage, retrieve the short 8+3 alias of the long file
3183 if (_mbspbrk (dir_find_data_a
.cFileName
, "?"))
3185 strcpy (tem
, dir_find_data_a
.cAlternateFileName
);
3186 /* 8+3 aliases are returned in all caps, which could break
3187 various alists that look at filenames' extensions. */
3190 else if (downcase
|| dir_is_fat
)
3191 strcpy (tem
, dir_find_data_a
.cFileName
);
3193 filename_from_ansi (dir_find_data_a
.cFileName
, dir_static
.d_name
);
3194 if (downcase
|| dir_is_fat
)
3197 filename_from_ansi (tem
, dir_static
.d_name
);
3199 last_dir_find_data
= DIR_FIND_DATA_A
;
3202 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
3203 dir_static
.d_reclen
= sizeof (struct dirent
) - MAX_UTF8_PATH
+ 3 +
3204 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
3210 open_unc_volume (const char *path
)
3212 const char *fn
= map_w32_filename (path
, NULL
);
3216 if (w32_unicode_filenames
)
3219 wchar_t fnw
[MAX_PATH
];
3221 nrw
.dwScope
= RESOURCE_GLOBALNET
;
3222 nrw
.dwType
= RESOURCETYPE_DISK
;
3223 nrw
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
3224 nrw
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3225 nrw
.lpLocalName
= NULL
;
3226 filename_to_utf16 (fn
, fnw
);
3227 nrw
.lpRemoteName
= fnw
;
3228 nrw
.lpComment
= NULL
;
3229 nrw
.lpProvider
= NULL
;
3231 result
= WNetOpenEnumW (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
3232 RESOURCEUSAGE_CONNECTABLE
, &nrw
, &henum
);
3239 nra
.dwScope
= RESOURCE_GLOBALNET
;
3240 nra
.dwType
= RESOURCETYPE_DISK
;
3241 nra
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
3242 nra
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3243 nra
.lpLocalName
= NULL
;
3244 filename_to_ansi (fn
, fna
);
3245 nra
.lpRemoteName
= fna
;
3246 nra
.lpComment
= NULL
;
3247 nra
.lpProvider
= NULL
;
3249 result
= WNetOpenEnumA (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
3250 RESOURCEUSAGE_CONNECTABLE
, &nra
, &henum
);
3252 if (result
== NO_ERROR
)
3255 return INVALID_HANDLE_VALUE
;
3259 read_unc_volume (HANDLE henum
, wchar_t *fname_w
, char *fname_a
, int size
)
3264 DWORD bufsize
= 512;
3268 if (w32_unicode_filenames
)
3273 buffer
= alloca (bufsize
);
3274 result
= WNetEnumResourceW (henum
, &count
, buffer
, &bufsize
);
3275 if (result
!= NO_ERROR
)
3277 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3278 ptrw
= ((LPNETRESOURCEW
) buffer
)->lpRemoteName
;
3280 while (*ptrw
&& *ptrw
!= L
'/' && *ptrw
!= L
'\\') ptrw
++;
3282 wcsncpy (fname_w
, ptrw
, size
);
3287 int dbcs_p
= max_filename_mbslen () > 1;
3290 buffer
= alloca (bufsize
);
3291 result
= WNetEnumResourceA (henum
, &count
, buffer
, &bufsize
);
3292 if (result
!= NO_ERROR
)
3294 ptra
= ((LPNETRESOURCEA
) buffer
)->lpRemoteName
;
3297 while (*ptra
&& !IS_DIRECTORY_SEP (*ptra
)) ptra
++;
3300 while (*ptra
&& !IS_DIRECTORY_SEP (*ptra
))
3301 ptra
= CharNextExA (file_name_codepage
, ptra
, 0);
3304 strncpy (fname_a
, ptra
, size
);
3312 close_unc_volume (HANDLE henum
)
3314 if (henum
!= INVALID_HANDLE_VALUE
)
3315 WNetCloseEnum (henum
);
3319 unc_volume_file_attributes (const char *path
)
3324 henum
= open_unc_volume (path
);
3325 if (henum
== INVALID_HANDLE_VALUE
)
3328 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
3330 close_unc_volume (henum
);
3335 /* Ensure a network connection is authenticated. */
3337 logon_network_drive (const char *path
)
3339 char share
[MAX_UTF8_PATH
];
3346 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
3347 drvtype
= DRIVE_REMOTE
;
3348 else if (path
[0] == '\0' || path
[1] != ':')
3349 drvtype
= GetDriveType (NULL
);
3356 drvtype
= GetDriveType (drive
);
3359 /* Only logon to networked drives. */
3360 if (drvtype
!= DRIVE_REMOTE
)
3364 strncpy (share
, path
, MAX_UTF8_PATH
);
3365 /* Truncate to just server and share name. */
3366 for (p
= share
+ 2; *p
&& p
< share
+ MAX_UTF8_PATH
; p
++)
3368 if (IS_DIRECTORY_SEP (*p
) && ++n_slashes
> 3)
3375 if (w32_unicode_filenames
)
3377 NETRESOURCEW resourcew
;
3378 wchar_t share_w
[MAX_PATH
];
3380 resourcew
.dwScope
= RESOURCE_GLOBALNET
;
3381 resourcew
.dwType
= RESOURCETYPE_DISK
;
3382 resourcew
.dwDisplayType
= RESOURCEDISPLAYTYPE_SHARE
;
3383 resourcew
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3384 resourcew
.lpLocalName
= NULL
;
3385 filename_to_utf16 (share
, share_w
);
3386 resourcew
.lpRemoteName
= share_w
;
3387 resourcew
.lpProvider
= NULL
;
3389 val
= WNetAddConnection2W (&resourcew
, NULL
, NULL
, CONNECT_INTERACTIVE
);
3393 NETRESOURCEA resourcea
;
3394 char share_a
[MAX_PATH
];
3396 resourcea
.dwScope
= RESOURCE_GLOBALNET
;
3397 resourcea
.dwType
= RESOURCETYPE_DISK
;
3398 resourcea
.dwDisplayType
= RESOURCEDISPLAYTYPE_SHARE
;
3399 resourcea
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3400 resourcea
.lpLocalName
= NULL
;
3401 filename_to_ansi (share
, share_a
);
3402 resourcea
.lpRemoteName
= share_a
;
3403 resourcea
.lpProvider
= NULL
;
3405 val
= WNetAddConnection2A (&resourcea
, NULL
, NULL
, CONNECT_INTERACTIVE
);
3411 case ERROR_ALREADY_ASSIGNED
:
3413 case ERROR_ACCESS_DENIED
:
3414 case ERROR_LOGON_FAILURE
:
3420 case ERROR_BAD_NET_NAME
:
3421 case ERROR_NO_NET_OR_BAD_PATH
:
3422 case ERROR_NO_NETWORK
:
3423 case ERROR_CANCELLED
:
3430 /* Emulate faccessat(2). */
3432 faccessat (int dirfd
, const char * path
, int mode
, int flags
)
3436 if (dirfd
!= AT_FDCWD
3437 && !(IS_DIRECTORY_SEP (path
[0])
3438 || IS_DEVICE_SEP (path
[1])))
3444 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3445 newer versions blow up when passed D_OK. */
3446 path
= map_w32_filename (path
, NULL
);
3447 /* If the last element of PATH is a symlink, we need to resolve it
3448 to get the attributes of its target file. Note: any symlinks in
3449 PATH elements other than the last one are transparently resolved
3450 by GetFileAttributes below. */
3451 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0
3452 && (flags
& AT_SYMLINK_NOFOLLOW
) == 0)
3453 path
= chase_symlinks (path
);
3455 if (w32_unicode_filenames
)
3457 wchar_t path_w
[MAX_PATH
];
3459 filename_to_utf16 (path
, path_w
);
3460 attributes
= GetFileAttributesW (path_w
);
3464 char path_a
[MAX_PATH
];
3466 filename_to_ansi (path
, path_a
);
3467 attributes
= GetFileAttributesA (path_a
);
3470 if (attributes
== -1)
3472 DWORD w32err
= GetLastError ();
3476 case ERROR_INVALID_NAME
:
3477 case ERROR_BAD_PATHNAME
:
3478 if (is_unc_volume (path
))
3480 attributes
= unc_volume_file_attributes (path
);
3481 if (attributes
== -1)
3489 case ERROR_FILE_NOT_FOUND
:
3490 case ERROR_BAD_NETPATH
:
3499 if ((mode
& X_OK
) != 0
3500 && !(is_exec (path
) || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3505 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3510 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3518 /* A version of 'access' to be used locally with file names in
3519 locale-specific encoding. Does not resolve symlinks and does not
3520 support file names on FAT12 and FAT16 volumes, but that's OK, since
3521 we only invoke this function for files inside the Emacs source or
3522 installation tree, on directories (so any symlinks should have the
3523 directory bit set), and on short file names such as "C:/.emacs". */
3525 sys_access (const char *fname
, int mode
)
3527 char fname_copy
[MAX_PATH
], *p
;
3530 strcpy (fname_copy
, fname
);
3531 /* Do the equivalent of unixtodos_filename. */
3532 for (p
= fname_copy
; *p
; p
= CharNext (p
))
3536 if ((attributes
= GetFileAttributesA (fname_copy
)) == -1)
3538 DWORD w32err
= GetLastError ();
3542 case ERROR_INVALID_NAME
:
3543 case ERROR_BAD_PATHNAME
:
3544 case ERROR_FILE_NOT_FOUND
:
3545 case ERROR_BAD_NETPATH
:
3554 if ((mode
& X_OK
) != 0
3555 && !(is_exec (fname_copy
)
3556 || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3561 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3566 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3574 /* Shadow some MSVC runtime functions to map requests for long filenames
3575 to reasonable short names if necessary. This was originally added to
3576 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3580 sys_chdir (const char * path
)
3582 path
= map_w32_filename (path
, NULL
);
3583 if (w32_unicode_filenames
)
3585 wchar_t newdir_w
[MAX_PATH
];
3587 if (filename_to_utf16 (path
, newdir_w
) == 0)
3588 return _wchdir (newdir_w
);
3593 char newdir_a
[MAX_PATH
];
3595 if (filename_to_ansi (path
, newdir_a
) == 0)
3596 return _chdir (newdir_a
);
3602 sys_chmod (const char * path
, int mode
)
3604 path
= chase_symlinks (map_w32_filename (path
, NULL
));
3605 if (w32_unicode_filenames
)
3607 wchar_t path_w
[MAX_PATH
];
3609 filename_to_utf16 (path
, path_w
);
3610 return _wchmod (path_w
, mode
);
3614 char path_a
[MAX_PATH
];
3616 filename_to_ansi (path
, path_a
);
3617 return _chmod (path_a
, mode
);
3622 sys_creat (const char * path
, int mode
)
3624 path
= map_w32_filename (path
, NULL
);
3625 if (w32_unicode_filenames
)
3627 wchar_t path_w
[MAX_PATH
];
3629 filename_to_utf16 (path
, path_w
);
3630 return _wcreat (path_w
, mode
);
3634 char path_a
[MAX_PATH
];
3636 filename_to_ansi (path
, path_a
);
3637 return _creat (path_a
, mode
);
3642 sys_fopen (const char * path
, const char * mode
)
3646 const char * mode_save
= mode
;
3648 /* Force all file handles to be non-inheritable. This is necessary to
3649 ensure child processes don't unwittingly inherit handles that might
3650 prevent future file access. */
3654 else if (mode
[0] == 'w' || mode
[0] == 'a')
3655 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
3659 /* Only do simplistic option parsing. */
3663 oflag
&= ~(O_RDONLY
| O_WRONLY
);
3666 else if (mode
[0] == 'b')
3671 else if (mode
[0] == 't')
3678 path
= map_w32_filename (path
, NULL
);
3679 if (w32_unicode_filenames
)
3681 wchar_t path_w
[MAX_PATH
];
3683 filename_to_utf16 (path
, path_w
);
3684 fd
= _wopen (path_w
, oflag
| _O_NOINHERIT
, 0644);
3688 char path_a
[MAX_PATH
];
3690 filename_to_ansi (path
, path_a
);
3691 fd
= _open (path_a
, oflag
| _O_NOINHERIT
, 0644);
3696 return _fdopen (fd
, mode_save
);
3699 /* This only works on NTFS volumes, but is useful to have. */
3701 sys_link (const char * old
, const char * new)
3705 char oldname
[MAX_UTF8_PATH
], newname
[MAX_UTF8_PATH
];
3706 wchar_t oldname_w
[MAX_PATH
];
3707 char oldname_a
[MAX_PATH
];
3709 if (old
== NULL
|| new == NULL
)
3715 strcpy (oldname
, map_w32_filename (old
, NULL
));
3716 strcpy (newname
, map_w32_filename (new, NULL
));
3718 if (w32_unicode_filenames
)
3720 filename_to_utf16 (oldname
, oldname_w
);
3721 fileh
= CreateFileW (oldname_w
, 0, 0, NULL
, OPEN_EXISTING
,
3722 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
3726 filename_to_ansi (oldname
, oldname_a
);
3727 fileh
= CreateFileA (oldname_a
, 0, 0, NULL
, OPEN_EXISTING
,
3728 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
3730 if (fileh
!= INVALID_HANDLE_VALUE
)
3734 /* Confusingly, the "alternate" stream name field does not apply
3735 when restoring a hard link, and instead contains the actual
3736 stream data for the link (ie. the name of the link to create).
3737 The WIN32_STREAM_ID structure before the cStreamName field is
3738 the stream header, which is then immediately followed by the
3742 WIN32_STREAM_ID wid
;
3743 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
3746 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
3747 indicates that flag is unsupported for CP_UTF8, and OTOH says
3748 it is the default anyway. */
3749 wlen
= MultiByteToWideChar (CP_UTF8
, 0, newname
, -1,
3750 data
.wid
.cStreamName
, MAX_PATH
);
3753 LPVOID context
= NULL
;
3756 data
.wid
.dwStreamId
= BACKUP_LINK
;
3757 data
.wid
.dwStreamAttributes
= 0;
3758 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
3759 data
.wid
.Size
.HighPart
= 0;
3760 data
.wid
.dwStreamNameSize
= 0;
3762 if (BackupWrite (fileh
, (LPBYTE
)&data
,
3763 offsetof (WIN32_STREAM_ID
, cStreamName
)
3764 + data
.wid
.Size
.LowPart
,
3765 &wbytes
, FALSE
, FALSE
, &context
)
3766 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
3773 DWORD err
= GetLastError ();
3778 case ERROR_ACCESS_DENIED
:
3779 /* This is what happens when OLDNAME is a directory,
3780 since Windows doesn't support hard links to
3781 directories. Posix says to set errno to EPERM in
3783 if (w32_unicode_filenames
)
3784 attributes
= GetFileAttributesW (oldname_w
);
3786 attributes
= GetFileAttributesA (oldname_a
);
3787 if (attributes
!= -1
3788 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0)
3790 else if (attributes
== -1
3791 && is_unc_volume (oldname
)
3792 && unc_volume_file_attributes (oldname
) != -1)
3797 case ERROR_TOO_MANY_LINKS
:
3800 case ERROR_NOT_SAME_DEVICE
:
3810 CloseHandle (fileh
);
3819 sys_mkdir (const char * path
)
3821 path
= map_w32_filename (path
, NULL
);
3823 if (w32_unicode_filenames
)
3825 wchar_t path_w
[MAX_PATH
];
3827 filename_to_utf16 (path
, path_w
);
3828 return _wmkdir (path_w
);
3832 char path_a
[MAX_PATH
];
3834 filename_to_ansi (path
, path_a
);
3835 return _mkdir (path_a
);
3840 sys_open (const char * path
, int oflag
, int mode
)
3842 const char* mpath
= map_w32_filename (path
, NULL
);
3845 if (w32_unicode_filenames
)
3847 wchar_t mpath_w
[MAX_PATH
];
3849 filename_to_utf16 (mpath
, mpath_w
);
3850 /* If possible, try to open file without _O_CREAT, to be able to
3851 write to existing hidden and system files. Force all file
3852 handles to be non-inheritable. */
3853 if ((oflag
& (_O_CREAT
| _O_EXCL
)) != (_O_CREAT
| _O_EXCL
))
3854 res
= _wopen (mpath_w
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3856 res
= _wopen (mpath_w
, oflag
| _O_NOINHERIT
, mode
);
3860 char mpath_a
[MAX_PATH
];
3862 filename_to_ansi (mpath
, mpath_a
);
3863 if ((oflag
& (_O_CREAT
| _O_EXCL
)) != (_O_CREAT
| _O_EXCL
))
3864 res
= _open (mpath_a
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3866 res
= _open (mpath_a
, oflag
| _O_NOINHERIT
, mode
);
3872 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
3875 Standard algorithm for generating a temporary file name seems to be
3876 use pid or tid with a letter on the front (in place of the 6 X's)
3877 and cycle through the letters to find a unique name. We extend
3878 that to allow any reasonable character as the first of the 6 X's,
3879 so that the number of simultaneously used temporary files will be
3883 mkostemp (char * template, int flags
)
3887 unsigned uid
= GetCurrentThreadId ();
3888 int save_errno
= errno
;
3889 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3892 if (template == NULL
)
3895 p
= template + strlen (template);
3897 /* replace up to the last 5 X's with uid in decimal */
3898 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
3900 p
[0] = '0' + uid
% 10;
3904 if (i
< 0 && p
[0] == 'X')
3909 p
[0] = first_char
[i
];
3910 if ((fd
= sys_open (template,
3911 flags
| _O_CREAT
| _O_EXCL
| _O_RDWR
,
3912 S_IRUSR
| S_IWUSR
)) >= 0
3920 while (++i
< sizeof (first_char
));
3923 /* Template is badly formed or else we can't generate a unique name. */
3928 fchmod (int fd
, mode_t mode
)
3934 sys_rename_replace (const char *oldname
, const char *newname
, BOOL force
)
3937 char temp
[MAX_UTF8_PATH
], temp_a
[MAX_PATH
];;
3940 bool have_temp_a
= false;
3942 /* MoveFile on Windows 95 doesn't correctly change the short file name
3943 alias in a number of circumstances (it is not easy to predict when
3944 just by looking at oldname and newname, unfortunately). In these
3945 cases, renaming through a temporary name avoids the problem.
3947 A second problem on Windows 95 is that renaming through a temp name when
3948 newname is uppercase fails (the final long name ends up in
3949 lowercase, although the short alias might be uppercase) UNLESS the
3950 long temp name is not 8.3.
3952 So, on Windows 95 we always rename through a temp name, and we make sure
3953 the temp name has a long extension to ensure correct renaming. */
3955 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3957 /* volume_info is set indirectly by map_w32_filename. */
3958 oldname_dev
= volume_info
.serialnum
;
3960 if (os_subtype
== OS_9X
)
3965 char oldname_a
[MAX_PATH
];
3967 oldname
= map_w32_filename (oldname
, NULL
);
3968 filename_to_ansi (oldname
, oldname_a
);
3969 filename_to_ansi (temp
, temp_a
);
3970 if ((o
= strrchr (oldname_a
, '\\')))
3973 o
= (char *) oldname_a
;
3975 if ((p
= strrchr (temp_a
, '\\')))
3982 /* Force temp name to require a manufactured 8.3 alias - this
3983 seems to make the second rename work properly. */
3984 sprintf (p
, "_.%s.%u", o
, i
);
3986 result
= rename (oldname_a
, temp_a
);
3988 /* This loop must surely terminate! */
3989 while (result
< 0 && errno
== EEXIST
);
3995 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3996 (at least if it is a file; don't do this for directories).
3998 Since we mustn't do this if we are just changing the case of the
3999 file name (we would end up deleting the file we are trying to
4000 rename!), we let rename detect if the destination file already
4001 exists - that way we avoid the possible pitfalls of trying to
4002 determine ourselves whether two names really refer to the same
4003 file, which is not always possible in the general case. (Consider
4004 all the permutations of shared or subst'd drives, etc.) */
4006 newname
= map_w32_filename (newname
, NULL
);
4008 /* volume_info is set indirectly by map_w32_filename. */
4009 newname_dev
= volume_info
.serialnum
;
4011 if (w32_unicode_filenames
)
4013 wchar_t temp_w
[MAX_PATH
], newname_w
[MAX_PATH
];
4015 filename_to_utf16 (temp
, temp_w
);
4016 filename_to_utf16 (newname
, newname_w
);
4017 result
= _wrename (temp_w
, newname_w
);
4018 if (result
< 0 && force
)
4020 DWORD w32err
= GetLastError ();
4023 && newname_dev
!= oldname_dev
)
4025 /* The implementation of `rename' on Windows does not return
4026 errno = EXDEV when you are moving a directory to a
4027 different storage device (ex. logical disk). It returns
4028 EACCES instead. So here we handle such situations and
4032 if ((attributes
= GetFileAttributesW (temp_w
)) != -1
4033 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
4036 else if (errno
== EEXIST
)
4038 if (_wchmod (newname_w
, 0666) != 0)
4040 if (_wunlink (newname_w
) != 0)
4042 result
= _wrename (temp_w
, newname_w
);
4044 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
4045 && is_symlink (temp
))
4047 /* This is Windows prohibiting the user from creating a
4048 symlink in another place, since that requires
4056 char newname_a
[MAX_PATH
];
4059 filename_to_ansi (temp
, temp_a
);
4060 filename_to_ansi (newname
, newname_a
);
4061 result
= rename (temp_a
, newname_a
);
4062 if (result
< 0 && force
)
4064 DWORD w32err
= GetLastError ();
4067 && newname_dev
!= oldname_dev
)
4071 if ((attributes
= GetFileAttributesA (temp_a
)) != -1
4072 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
4075 else if (errno
== EEXIST
)
4077 if (_chmod (newname_a
, 0666) != 0)
4079 if (_unlink (newname_a
) != 0)
4081 result
= rename (temp_a
, newname_a
);
4083 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
4084 && is_symlink (temp
))
4093 sys_rename (char const *old
, char const *new)
4095 return sys_rename_replace (old
, new, TRUE
);
4099 sys_rmdir (const char * path
)
4101 path
= map_w32_filename (path
, NULL
);
4103 if (w32_unicode_filenames
)
4105 wchar_t path_w
[MAX_PATH
];
4107 filename_to_utf16 (path
, path_w
);
4108 return _wrmdir (path_w
);
4112 char path_a
[MAX_PATH
];
4114 filename_to_ansi (path
, path_a
);
4115 return _rmdir (path_a
);
4120 sys_unlink (const char * path
)
4122 path
= map_w32_filename (path
, NULL
);
4124 if (w32_unicode_filenames
)
4126 wchar_t path_w
[MAX_PATH
];
4128 filename_to_utf16 (path
, path_w
);
4129 /* On Unix, unlink works without write permission. */
4130 _wchmod (path_w
, 0666);
4131 return _wunlink (path_w
);
4135 char path_a
[MAX_PATH
];
4137 filename_to_ansi (path
, path_a
);
4138 _chmod (path_a
, 0666);
4139 return _unlink (path_a
);
4143 static FILETIME utc_base_ft
;
4144 static ULONGLONG utc_base
; /* In 100ns units */
4145 static int init
= 0;
4147 #define FILETIME_TO_U64(result, ft) \
4149 ULARGE_INTEGER uiTemp; \
4150 uiTemp.LowPart = (ft).dwLowDateTime; \
4151 uiTemp.HighPart = (ft).dwHighDateTime; \
4152 result = uiTemp.QuadPart; \
4156 initialize_utc_base (void)
4158 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4167 st
.wMilliseconds
= 0;
4169 SystemTimeToFileTime (&st
, &utc_base_ft
);
4170 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
4174 convert_time (FILETIME ft
)
4180 initialize_utc_base ();
4184 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
4187 FILETIME_TO_U64 (tmp
, ft
);
4188 return (time_t) ((tmp
- utc_base
) / 10000000L);
4192 convert_from_time_t (time_t time
, FILETIME
* pft
)
4198 initialize_utc_base ();
4202 /* time in 100ns units since 1-Jan-1601 */
4203 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
4204 pft
->dwHighDateTime
= tmp
.HighPart
;
4205 pft
->dwLowDateTime
= tmp
.LowPart
;
4208 static PSECURITY_DESCRIPTOR
4209 get_file_security_desc_by_handle (HANDLE h
)
4211 PSECURITY_DESCRIPTOR psd
= NULL
;
4213 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
4214 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
4216 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
4217 NULL
, NULL
, NULL
, NULL
, &psd
);
4218 if (err
!= ERROR_SUCCESS
)
4224 static PSECURITY_DESCRIPTOR
4225 get_file_security_desc_by_name (const char *fname
)
4227 PSECURITY_DESCRIPTOR psd
= NULL
;
4229 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
4230 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
4232 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
4234 err
= GetLastError ();
4235 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
4239 psd
= xmalloc (sd_len
);
4240 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
4252 unsigned n_subauthorities
;
4254 /* Use the last sub-authority value of the RID, the relative
4255 portion of the SID, as user/group ID. */
4256 n_subauthorities
= *get_sid_sub_authority_count (sid
);
4257 if (n_subauthorities
< 1)
4258 return 0; /* the "World" RID */
4259 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
4262 /* Caching SID and account values for faster lokup. */
4266 struct w32_id
*next
;
4268 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
4271 static struct w32_id
*w32_idlist
;
4274 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
4276 struct w32_id
*tail
, *found
;
4278 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
4280 if (equal_sid ((PSID
)tail
->sid
, sid
))
4289 strcpy (name
, found
->name
);
4297 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
4300 struct w32_id
*new_entry
;
4302 /* We don't want to leave behind stale cache from when Emacs was
4306 sid_len
= get_length_sid (sid
);
4307 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
4310 new_entry
->rid
= id
;
4311 strcpy (new_entry
->name
, name
);
4312 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
4313 new_entry
->next
= w32_idlist
;
4314 w32_idlist
= new_entry
;
4323 get_name_and_id (PSECURITY_DESCRIPTOR psd
, unsigned *id
, char *nm
, int what
)
4327 SID_NAME_USE ignore
;
4329 DWORD name_len
= sizeof (name
);
4331 DWORD domain_len
= sizeof (domain
);
4336 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
4337 else if (what
== GID
)
4338 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
4342 if (!result
|| !is_valid_sid (sid
))
4344 else if (!w32_cached_id (sid
, id
, nm
))
4346 if (!lookup_account_sid (NULL
, sid
, name
, &name_len
,
4347 domain
, &domain_len
, &ignore
)
4348 || name_len
> UNLEN
+1)
4352 *id
= get_rid (sid
);
4354 w32_add_to_cache (sid
, *id
, name
);
4361 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
, struct stat
*st
)
4363 int dflt_usr
= 0, dflt_grp
= 0;
4372 if (get_name_and_id (psd
, &st
->st_uid
, st
->st_uname
, UID
))
4374 if (get_name_and_id (psd
, &st
->st_gid
, st
->st_gname
, GID
))
4377 /* Consider files to belong to current user/group, if we cannot get
4378 more accurate information. */
4381 st
->st_uid
= dflt_passwd
.pw_uid
;
4382 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
4386 st
->st_gid
= dflt_passwd
.pw_gid
;
4387 strcpy (st
->st_gname
, dflt_group
.gr_name
);
4391 /* Return non-zero if NAME is a potentially slow filesystem. */
4393 is_slow_fs (const char *name
)
4398 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
4399 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
4400 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
4401 devtype
= GetDriveType (NULL
); /* use root of current drive */
4404 /* GetDriveType needs the root directory of the drive. */
4405 strncpy (drive_root
, name
, 2);
4406 drive_root
[2] = '\\';
4407 drive_root
[3] = '\0';
4408 devtype
= GetDriveType (drive_root
);
4410 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
4413 /* If this is non-zero, the caller wants accurate information about
4414 file's owner and group, which could be expensive to get. dired.c
4415 uses this flag when needed for the job at hand. */
4416 int w32_stat_get_owner_group
;
4418 /* MSVC stat function can't cope with UNC names and has other bugs, so
4419 replace it with our own. This also allows us to calculate consistent
4420 inode values and owner/group without hacks in the main Emacs code,
4421 and support file names encoded in UTF-8. */
4424 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
4426 char *name
, *save_name
, *r
;
4427 WIN32_FIND_DATAW wfd_w
;
4428 WIN32_FIND_DATAA wfd_a
;
4430 unsigned __int64 fake_inode
= 0;
4433 int rootdir
= FALSE
;
4434 PSECURITY_DESCRIPTOR psd
= NULL
;
4435 int is_a_symlink
= 0;
4436 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
4437 DWORD access_rights
= 0;
4438 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
4439 FILETIME ctime
, atime
, wtime
;
4440 wchar_t name_w
[MAX_PATH
];
4441 char name_a
[MAX_PATH
];
4443 if (path
== NULL
|| buf
== NULL
)
4449 save_name
= name
= (char *) map_w32_filename (path
, &path
);
4450 /* Must be valid filename, no wild cards or other invalid
4452 if (strpbrk (name
, "*?|<>\""))
4458 /* Remove trailing directory separator, unless name is the root
4459 directory of a drive or UNC volume in which case ensure there
4460 is a trailing separator. */
4461 len
= strlen (name
);
4462 name
= strcpy (alloca (len
+ 2), name
);
4464 /* Avoid a somewhat costly call to is_symlink if the filesystem
4465 doesn't support symlinks. */
4466 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
4467 is_a_symlink
= is_symlink (name
);
4469 /* Plan A: Open the file and get all the necessary information via
4470 the resulting handle. This solves several issues in one blow:
4472 . retrieves attributes for the target of a symlink, if needed
4473 . gets attributes of root directories and symlinks pointing to
4474 root directories, thus avoiding the need for special-casing
4475 these and detecting them by examining the file-name format
4476 . retrieves more accurate attributes (e.g., non-zero size for
4477 some directories, esp. directories that are junction points)
4478 . correctly resolves "c:/..", "/.." and similar file names
4479 . avoids run-time penalties for 99% of use cases
4481 Plan A is always tried first, unless the user asked not to (but
4482 if the file is a symlink and we need to follow links, we try Plan
4483 A even if the user asked not to).
4485 If Plan A fails, we go to Plan B (below), where various
4486 potentially expensive techniques must be used to handle "special"
4487 files such as UNC volumes etc. */
4488 if (!(NILP (Vw32_get_true_file_attributes
)
4489 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
4490 /* Following symlinks requires getting the info by handle. */
4491 || (is_a_symlink
&& follow_symlinks
))
4493 BY_HANDLE_FILE_INFORMATION info
;
4495 if (is_a_symlink
&& !follow_symlinks
)
4496 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
4497 /* READ_CONTROL access rights are required to get security info
4498 by handle. But if the OS doesn't support security in the
4499 first place, we don't need to try. */
4500 if (is_windows_9x () != TRUE
)
4501 access_rights
|= READ_CONTROL
;
4503 if (w32_unicode_filenames
)
4505 filename_to_utf16 (name
, name_w
);
4506 fh
= CreateFileW (name_w
, access_rights
, 0, NULL
, OPEN_EXISTING
,
4508 /* If CreateFile fails with READ_CONTROL, try again with
4509 zero as access rights. */
4510 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
4511 fh
= CreateFileW (name_w
, 0, 0, NULL
, OPEN_EXISTING
,
4516 filename_to_ansi (name
, name_a
);
4517 fh
= CreateFileA (name_a
, access_rights
, 0, NULL
, OPEN_EXISTING
,
4519 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
4520 fh
= CreateFileA (name_a
, 0, 0, NULL
, OPEN_EXISTING
,
4523 if (fh
== INVALID_HANDLE_VALUE
)
4524 goto no_true_file_attributes
;
4526 /* This is more accurate in terms of getting the correct number
4527 of links, but is quite slow (it is noticeable when Emacs is
4528 making a list of file name completions). */
4529 if (GetFileInformationByHandle (fh
, &info
))
4531 nlinks
= info
.nNumberOfLinks
;
4532 /* Might as well use file index to fake inode values, but this
4533 is not guaranteed to be unique unless we keep a handle open
4534 all the time (even then there are situations where it is
4535 not unique). Reputedly, there are at most 48 bits of info
4536 (on NTFS, presumably less on FAT). */
4537 fake_inode
= info
.nFileIndexHigh
;
4539 fake_inode
+= info
.nFileIndexLow
;
4540 serialnum
= info
.dwVolumeSerialNumber
;
4541 fs_high
= info
.nFileSizeHigh
;
4542 fs_low
= info
.nFileSizeLow
;
4543 ctime
= info
.ftCreationTime
;
4544 atime
= info
.ftLastAccessTime
;
4545 wtime
= info
.ftLastWriteTime
;
4546 fattrs
= info
.dwFileAttributes
;
4550 /* We don't go to Plan B here, because it's not clear that
4551 it's a good idea. The only known use case where
4552 CreateFile succeeds, but GetFileInformationByHandle fails
4553 (with ERROR_INVALID_FUNCTION) is for character devices
4554 such as NUL, PRN, etc. For these, switching to Plan B is
4555 a net loss, because we lose the character device
4556 attribute returned by GetFileType below (FindFirstFile
4557 doesn't set that bit in the attributes), and the other
4558 fields don't make sense for character devices anyway.
4559 Emacs doesn't really care for non-file entities in the
4560 context of l?stat, so neither do we. */
4562 /* w32err is assigned so one could put a breakpoint here and
4563 examine its value, when GetFileInformationByHandle
4565 DWORD w32err
= GetLastError ();
4569 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
4575 /* Test for a symlink before testing for a directory, since
4576 symlinks to directories have the directory bit set, but we
4577 don't want them to appear as directories. */
4578 if (is_a_symlink
&& !follow_symlinks
)
4579 buf
->st_mode
= S_IFLNK
;
4580 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4581 buf
->st_mode
= S_IFDIR
;
4584 DWORD ftype
= GetFileType (fh
);
4588 case FILE_TYPE_DISK
:
4589 buf
->st_mode
= S_IFREG
;
4591 case FILE_TYPE_PIPE
:
4592 buf
->st_mode
= S_IFIFO
;
4594 case FILE_TYPE_CHAR
:
4595 case FILE_TYPE_UNKNOWN
:
4597 buf
->st_mode
= S_IFCHR
;
4600 /* We produce the fallback owner and group data, based on the
4601 current user that runs Emacs, in the following cases:
4603 . caller didn't request owner and group info
4604 . this is Windows 9X
4605 . getting security by handle failed, and we need to produce
4606 information for the target of a symlink (this is better
4607 than producing a potentially misleading info about the
4610 If getting security by handle fails, and we don't need to
4611 resolve symlinks, we try getting security by name. */
4612 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4613 get_file_owner_and_group (NULL
, buf
);
4616 psd
= get_file_security_desc_by_handle (fh
);
4619 get_file_owner_and_group (psd
, buf
);
4622 else if (!(is_a_symlink
&& follow_symlinks
))
4624 psd
= get_file_security_desc_by_name (name
);
4625 get_file_owner_and_group (psd
, buf
);
4629 get_file_owner_and_group (NULL
, buf
);
4635 no_true_file_attributes
:
4636 /* Plan B: Either getting a handle on the file failed, or the
4637 caller explicitly asked us to not bother making this
4638 information more accurate.
4640 Implementation note: In Plan B, we never bother to resolve
4641 symlinks, even if we got here because we tried Plan A and
4642 failed. That's because, even if the caller asked for extra
4643 precision by setting Vw32_get_true_file_attributes to t,
4644 resolving symlinks requires acquiring a file handle to the
4645 symlink, which we already know will fail. And if the user
4646 did not ask for extra precision, resolving symlinks will fly
4647 in the face of that request, since the user then wants the
4648 lightweight version of the code. */
4649 rootdir
= (path
>= save_name
+ len
- 1
4650 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
4652 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4653 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
4654 if (IS_DIRECTORY_SEP (r
[0])
4655 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
4658 /* Note: If NAME is a symlink to the root of a UNC volume
4659 (i.e. "\\SERVER"), we will not detect that here, and we will
4660 return data about the symlink as result of FindFirst below.
4661 This is unfortunate, but that marginal use case does not
4662 justify a call to chase_symlinks which would impose a penalty
4663 on all the other use cases. (We get here for symlinks to
4664 roots of UNC volumes because CreateFile above fails for them,
4665 unlike with symlinks to root directories X:\ of drives.) */
4666 if (is_unc_volume (name
))
4668 fattrs
= unc_volume_file_attributes (name
);
4672 ctime
= atime
= wtime
= utc_base_ft
;
4676 if (!IS_DIRECTORY_SEP (name
[len
-1]))
4677 strcat (name
, "\\");
4678 if (GetDriveType (name
) < 2)
4684 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
4685 ctime
= atime
= wtime
= utc_base_ft
;
4691 if (IS_DIRECTORY_SEP (name
[len
-1]))
4694 /* (This is hacky, but helps when doing file completions on
4695 network drives.) Optimize by using information available from
4696 active readdir if possible. */
4697 len
= strlen (dir_pathname
);
4698 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
4700 if (dir_find_handle
!= INVALID_HANDLE_VALUE
4701 && last_dir_find_data
!= -1
4702 && !(is_a_symlink
&& follow_symlinks
)
4703 /* The 2 file-name comparisons below support only ASCII
4704 characters, and will lose (compare not equal) when
4705 the file names include non-ASCII charcaters that are
4706 the same but for the case. However, doing this
4707 properly involves: (a) converting both file names to
4708 UTF-16, (b) lower-casing both names using CharLowerW,
4709 and (c) comparing the results; this would be quite a
4710 bit slower, whereas Plan B is for users who want
4711 lightweight albeit inaccurate version of 'stat'. */
4712 && c_strncasecmp (save_name
, dir_pathname
, len
) == 0
4713 && IS_DIRECTORY_SEP (name
[len
])
4714 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
4716 have_wfd
= last_dir_find_data
;
4717 /* This was the last entry returned by readdir. */
4718 if (last_dir_find_data
== DIR_FIND_DATA_W
)
4719 wfd_w
= dir_find_data_w
;
4721 wfd_a
= dir_find_data_a
;
4725 logon_network_drive (name
);
4727 if (w32_unicode_filenames
)
4729 filename_to_utf16 (name
, name_w
);
4730 fh
= FindFirstFileW (name_w
, &wfd_w
);
4731 have_wfd
= DIR_FIND_DATA_W
;
4735 filename_to_ansi (name
, name_a
);
4736 /* If NAME includes characters not representable by
4737 the current ANSI codepage, filename_to_ansi
4738 usually replaces them with a '?'. We don't want
4739 to let FindFirstFileA interpret those as widlcards,
4740 and "succeed", returning us data from some random
4741 file in the same directory. */
4742 if (_mbspbrk (name_a
, "?"))
4743 fh
= INVALID_HANDLE_VALUE
;
4745 fh
= FindFirstFileA (name_a
, &wfd_a
);
4746 have_wfd
= DIR_FIND_DATA_A
;
4748 if (fh
== INVALID_HANDLE_VALUE
)
4755 /* Note: if NAME is a symlink, the information we get from
4756 FindFirstFile is for the symlink, not its target. */
4757 if (have_wfd
== DIR_FIND_DATA_W
)
4759 fattrs
= wfd_w
.dwFileAttributes
;
4760 ctime
= wfd_w
.ftCreationTime
;
4761 atime
= wfd_w
.ftLastAccessTime
;
4762 wtime
= wfd_w
.ftLastWriteTime
;
4763 fs_high
= wfd_w
.nFileSizeHigh
;
4764 fs_low
= wfd_w
.nFileSizeLow
;
4768 fattrs
= wfd_a
.dwFileAttributes
;
4769 ctime
= wfd_a
.ftCreationTime
;
4770 atime
= wfd_a
.ftLastAccessTime
;
4771 wtime
= wfd_a
.ftLastWriteTime
;
4772 fs_high
= wfd_a
.nFileSizeHigh
;
4773 fs_low
= wfd_a
.nFileSizeLow
;
4777 serialnum
= volume_info
.serialnum
;
4779 if (is_a_symlink
&& !follow_symlinks
)
4780 buf
->st_mode
= S_IFLNK
;
4781 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4782 buf
->st_mode
= S_IFDIR
;
4784 buf
->st_mode
= S_IFREG
;
4786 get_file_owner_and_group (NULL
, buf
);
4789 buf
->st_ino
= fake_inode
;
4791 buf
->st_dev
= serialnum
;
4792 buf
->st_rdev
= serialnum
;
4794 buf
->st_size
= fs_high
;
4795 buf
->st_size
<<= 32;
4796 buf
->st_size
+= fs_low
;
4797 buf
->st_nlink
= nlinks
;
4799 /* Convert timestamps to Unix format. */
4800 buf
->st_mtime
= convert_time (wtime
);
4801 buf
->st_atime
= convert_time (atime
);
4802 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4803 buf
->st_ctime
= convert_time (ctime
);
4804 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4806 /* determine rwx permissions */
4807 if (is_a_symlink
&& !follow_symlinks
)
4808 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
4811 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
4812 permission
= S_IREAD
;
4814 permission
= S_IREAD
| S_IWRITE
;
4816 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4817 permission
|= S_IEXEC
;
4818 else if (is_exec (name
))
4819 permission
|= S_IEXEC
;
4822 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4828 stat (const char * path
, struct stat
* buf
)
4830 return stat_worker (path
, buf
, 1);
4834 lstat (const char * path
, struct stat
* buf
)
4836 return stat_worker (path
, buf
, 0);
4840 fstatat (int fd
, char const *name
, struct stat
*st
, int flags
)
4842 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4843 This is good enough for the current usage in Emacs, but is fragile.
4845 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4846 Gnulib does this and can serve as a model. */
4847 char fullname
[MAX_UTF8_PATH
];
4851 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
4854 errno
= ENAMETOOLONG
;
4860 return stat_worker (name
, st
, ! (flags
& AT_SYMLINK_NOFOLLOW
));
4863 /* Provide fstat and utime as well as stat for consistent handling of
4866 fstat (int desc
, struct stat
* buf
)
4868 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
4869 BY_HANDLE_FILE_INFORMATION info
;
4870 unsigned __int64 fake_inode
;
4873 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
4875 case FILE_TYPE_DISK
:
4876 buf
->st_mode
= S_IFREG
;
4877 if (!GetFileInformationByHandle (fh
, &info
))
4883 case FILE_TYPE_PIPE
:
4884 buf
->st_mode
= S_IFIFO
;
4886 case FILE_TYPE_CHAR
:
4887 case FILE_TYPE_UNKNOWN
:
4889 buf
->st_mode
= S_IFCHR
;
4891 memset (&info
, 0, sizeof (info
));
4892 info
.dwFileAttributes
= 0;
4893 info
.ftCreationTime
= utc_base_ft
;
4894 info
.ftLastAccessTime
= utc_base_ft
;
4895 info
.ftLastWriteTime
= utc_base_ft
;
4898 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4899 buf
->st_mode
= S_IFDIR
;
4901 buf
->st_nlink
= info
.nNumberOfLinks
;
4902 /* Might as well use file index to fake inode values, but this
4903 is not guaranteed to be unique unless we keep a handle open
4904 all the time (even then there are situations where it is
4905 not unique). Reputedly, there are at most 48 bits of info
4906 (on NTFS, presumably less on FAT). */
4907 fake_inode
= info
.nFileIndexHigh
;
4909 fake_inode
+= info
.nFileIndexLow
;
4911 /* MSVC defines _ino_t to be short; other libc's might not. */
4912 if (sizeof (buf
->st_ino
) == 2)
4913 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
4915 buf
->st_ino
= fake_inode
;
4917 /* If the caller so requested, get the true file owner and group.
4918 Otherwise, consider the file to belong to the current user. */
4919 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4920 get_file_owner_and_group (NULL
, buf
);
4923 PSECURITY_DESCRIPTOR psd
= NULL
;
4925 psd
= get_file_security_desc_by_handle (fh
);
4928 get_file_owner_and_group (psd
, buf
);
4932 get_file_owner_and_group (NULL
, buf
);
4935 buf
->st_dev
= info
.dwVolumeSerialNumber
;
4936 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
4938 buf
->st_size
= info
.nFileSizeHigh
;
4939 buf
->st_size
<<= 32;
4940 buf
->st_size
+= info
.nFileSizeLow
;
4942 /* Convert timestamps to Unix format. */
4943 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
4944 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
4945 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4946 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
4947 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4949 /* determine rwx permissions */
4950 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
4951 permission
= S_IREAD
;
4953 permission
= S_IREAD
| S_IWRITE
;
4955 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4956 permission
|= S_IEXEC
;
4959 #if 0 /* no way of knowing the filename */
4960 char * p
= strrchr (name
, '.');
4962 (xstrcasecmp (p
, ".exe") == 0 ||
4963 xstrcasecmp (p
, ".com") == 0 ||
4964 xstrcasecmp (p
, ".bat") == 0 ||
4965 xstrcasecmp (p
, ".cmd") == 0))
4966 permission
|= S_IEXEC
;
4970 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4975 /* A version of 'utime' which handles directories as well as
4979 utime (const char *name
, struct utimbuf
*times
)
4981 struct utimbuf deftime
;
4988 deftime
.modtime
= deftime
.actime
= time (NULL
);
4992 if (w32_unicode_filenames
)
4994 wchar_t name_utf16
[MAX_PATH
];
4996 if (filename_to_utf16 (name
, name_utf16
) != 0)
4997 return -1; /* errno set by filename_to_utf16 */
4999 /* Need write access to set times. */
5000 fh
= CreateFileW (name_utf16
, FILE_WRITE_ATTRIBUTES
,
5001 /* If NAME specifies a directory, FILE_SHARE_DELETE
5002 allows other processes to delete files inside it,
5003 while we have the directory open. */
5004 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
5005 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
5009 char name_ansi
[MAX_PATH
];
5011 if (filename_to_ansi (name
, name_ansi
) != 0)
5012 return -1; /* errno set by filename_to_ansi */
5014 fh
= CreateFileA (name_ansi
, FILE_WRITE_ATTRIBUTES
,
5015 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
5016 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
5018 if (fh
!= INVALID_HANDLE_VALUE
)
5020 convert_from_time_t (times
->actime
, &atime
);
5021 convert_from_time_t (times
->modtime
, &mtime
);
5022 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
5032 DWORD err
= GetLastError ();
5036 case ERROR_FILE_NOT_FOUND
:
5037 case ERROR_PATH_NOT_FOUND
:
5038 case ERROR_INVALID_DRIVE
:
5039 case ERROR_BAD_NETPATH
:
5040 case ERROR_DEV_NOT_EXIST
:
5041 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5042 file name includes ?s, i.e. translation to ANSI failed. */
5043 case ERROR_INVALID_NAME
:
5046 case ERROR_TOO_MANY_OPEN_FILES
:
5049 case ERROR_ACCESS_DENIED
:
5050 case ERROR_SHARING_VIOLATION
:
5063 /* Symlink-related functions. */
5064 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5065 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5069 symlink (char const *filename
, char const *linkname
)
5071 char linkfn
[MAX_UTF8_PATH
], *tgtfn
;
5073 int dir_access
, filename_ends_in_slash
;
5075 /* Diagnostics follows Posix as much as possible. */
5076 if (filename
== NULL
|| linkname
== NULL
)
5086 if (strlen (filename
) > MAX_UTF8_PATH
|| strlen (linkname
) > MAX_UTF8_PATH
)
5088 errno
= ENAMETOOLONG
;
5092 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
5093 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
5099 /* Note: since empty FILENAME was already rejected, we can safely
5100 refer to FILENAME[1]. */
5101 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
5103 /* Non-absolute FILENAME is understood as being relative to
5104 LINKNAME's directory. We need to prepend that directory to
5105 FILENAME to get correct results from faccessat below, since
5106 otherwise it will interpret FILENAME relative to the
5107 directory where the Emacs process runs. Note that
5108 make-symbolic-link always makes sure LINKNAME is a fully
5109 expanded file name. */
5110 char tem
[MAX_UTF8_PATH
];
5111 char *p
= linkfn
+ strlen (linkfn
);
5113 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
5116 strncpy (tem
, linkfn
, p
- linkfn
);
5117 tem
[p
- linkfn
] = '\0';
5118 strcat (tem
, filename
);
5119 dir_access
= faccessat (AT_FDCWD
, tem
, D_OK
, AT_EACCESS
);
5122 dir_access
= faccessat (AT_FDCWD
, filename
, D_OK
, AT_EACCESS
);
5124 /* Since Windows distinguishes between symlinks to directories and
5125 to files, we provide a kludgy feature: if FILENAME doesn't
5126 exist, but ends in a slash, we create a symlink to directory. If
5127 FILENAME exists and is a directory, we always create a symlink to
5129 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
5130 if (dir_access
== 0 || filename_ends_in_slash
)
5131 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
5133 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
5134 if (filename_ends_in_slash
)
5135 tgtfn
[strlen (tgtfn
) - 1] = '\0';
5138 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
5140 /* ENOSYS is set by create_symbolic_link, when it detects that
5141 the OS doesn't support the CreateSymbolicLink API. */
5142 if (errno
!= ENOSYS
)
5144 DWORD w32err
= GetLastError ();
5148 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5149 TGTFN point to the same file name, go figure. */
5151 case ERROR_FILE_EXISTS
:
5154 case ERROR_ACCESS_DENIED
:
5157 case ERROR_FILE_NOT_FOUND
:
5158 case ERROR_PATH_NOT_FOUND
:
5159 case ERROR_BAD_NETPATH
:
5160 case ERROR_INVALID_REPARSE_DATA
:
5163 case ERROR_DIRECTORY
:
5166 case ERROR_PRIVILEGE_NOT_HELD
:
5167 case ERROR_NOT_ALL_ASSIGNED
:
5170 case ERROR_DISK_FULL
:
5183 /* A quick inexpensive test of whether FILENAME identifies a file that
5184 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5185 must already be in the normalized form returned by
5188 Note: for repeated operations on many files, it is best to test
5189 whether the underlying volume actually supports symlinks, by
5190 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5191 avoid the call to this function if it doesn't. That's because the
5192 call to GetFileAttributes takes a non-negligible time, especially
5193 on non-local or removable filesystems. See stat_worker for an
5194 example of how to do that. */
5196 is_symlink (const char *filename
)
5199 wchar_t filename_w
[MAX_PATH
];
5200 char filename_a
[MAX_PATH
];
5201 WIN32_FIND_DATAW wfdw
;
5202 WIN32_FIND_DATAA wfda
;
5204 int attrs_mean_symlink
;
5206 if (w32_unicode_filenames
)
5208 filename_to_utf16 (filename
, filename_w
);
5209 attrs
= GetFileAttributesW (filename_w
);
5213 filename_to_ansi (filename
, filename_a
);
5214 attrs
= GetFileAttributesA (filename_a
);
5218 DWORD w32err
= GetLastError ();
5222 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
5224 case ERROR_ACCESS_DENIED
:
5227 case ERROR_FILE_NOT_FOUND
:
5228 case ERROR_PATH_NOT_FOUND
:
5235 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
5237 logon_network_drive (filename
);
5238 if (w32_unicode_filenames
)
5240 fh
= FindFirstFileW (filename_w
, &wfdw
);
5241 attrs_mean_symlink
=
5242 (wfdw
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
5243 && (wfdw
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
5245 else if (_mbspbrk (filename_a
, "?"))
5247 /* filename_to_ansi failed to convert the file name. */
5253 fh
= FindFirstFileA (filename_a
, &wfda
);
5254 attrs_mean_symlink
=
5255 (wfda
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
5256 && (wfda
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
5258 if (fh
== INVALID_HANDLE_VALUE
)
5261 return attrs_mean_symlink
;
5264 /* If NAME identifies a symbolic link, copy into BUF the file name of
5265 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5266 null-terminate the target name, even if it fits. Return the number
5267 of bytes copied, or -1 if NAME is not a symlink or any error was
5268 encountered while resolving it. The file name copied into BUF is
5269 encoded in the current ANSI codepage. */
5271 readlink (const char *name
, char *buf
, size_t buf_size
)
5274 TOKEN_PRIVILEGES privs
;
5275 int restore_privs
= 0;
5278 char resolved
[MAX_UTF8_PATH
];
5291 path
= map_w32_filename (name
, NULL
);
5293 if (strlen (path
) > MAX_UTF8_PATH
)
5295 errno
= ENAMETOOLONG
;
5300 if (is_windows_9x () == TRUE
5301 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
5302 || !is_symlink (path
))
5305 errno
= EINVAL
; /* not a symlink */
5309 /* Done with simple tests, now we're in for some _real_ work. */
5310 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
5312 /* Implementation note: From here and onward, don't return early,
5313 since that will fail to restore the original set of privileges of
5314 the calling thread. */
5316 retval
= -1; /* not too optimistic, are we? */
5318 /* Note: In the next call to CreateFile, we use zero as the 2nd
5319 argument because, when the symlink is a hidden/system file,
5320 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5321 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5322 and directory symlinks. */
5323 if (w32_unicode_filenames
)
5325 wchar_t path_w
[MAX_PATH
];
5327 filename_to_utf16 (path
, path_w
);
5328 sh
= CreateFileW (path_w
, 0, 0, NULL
, OPEN_EXISTING
,
5329 FILE_FLAG_OPEN_REPARSE_POINT
5330 | FILE_FLAG_BACKUP_SEMANTICS
,
5335 char path_a
[MAX_PATH
];
5337 filename_to_ansi (path
, path_a
);
5338 sh
= CreateFileA (path_a
, 0, 0, NULL
, OPEN_EXISTING
,
5339 FILE_FLAG_OPEN_REPARSE_POINT
5340 | FILE_FLAG_BACKUP_SEMANTICS
,
5343 if (sh
!= INVALID_HANDLE_VALUE
)
5345 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
5346 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
5349 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
5350 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
5353 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
5357 /* Copy the link target name, in wide characters, from
5358 reparse_data, then convert it to multibyte encoding in
5359 the current locale's codepage. */
5363 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
5365 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
5366 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
5367 size_t size_to_copy
= buf_size
;
5369 /* According to MSDN, PrintNameLength does not include the
5370 terminating null character. */
5371 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
5372 memcpy (lwname
, lwname_src
, lwname_len
);
5373 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
5374 filename_from_utf16 (lwname
, resolved
);
5375 dostounix_filename (resolved
);
5376 lname_size
= strlen (resolved
) + 1;
5377 if (lname_size
<= buf_size
)
5378 size_to_copy
= lname_size
;
5379 strncpy (buf
, resolved
, size_to_copy
);
5381 retval
= size_to_copy
;
5387 /* CreateFile failed. */
5388 DWORD w32err2
= GetLastError ();
5392 case ERROR_FILE_NOT_FOUND
:
5393 case ERROR_PATH_NOT_FOUND
:
5396 case ERROR_ACCESS_DENIED
:
5397 case ERROR_TOO_MANY_OPEN_FILES
:
5407 restore_privilege (&privs
);
5415 readlinkat (int fd
, char const *name
, char *buffer
,
5418 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5419 as in fstatat. FIXME: Add proper support for readlinkat. */
5420 char fullname
[MAX_UTF8_PATH
];
5424 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
5427 errno
= ENAMETOOLONG
;
5433 return readlink (name
, buffer
, buffer_size
);
5436 /* If FILE is a symlink, return its target (stored in a static
5437 buffer); otherwise return FILE.
5439 This function repeatedly resolves symlinks in the last component of
5440 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5441 until it arrives at a file whose last component is not a symlink,
5442 or some error occurs. It returns the target of the last
5443 successfully resolved symlink in the chain. If it succeeds to
5444 resolve even a single symlink, the value returned is an absolute
5445 file name with backslashes (result of GetFullPathName). By
5446 contrast, if the original FILE is returned, it is unaltered.
5448 Note: This function can set errno even if it succeeds.
5450 Implementation note: we only resolve the last portion ("basename")
5451 of the argument FILE and of each following file in the chain,
5452 disregarding any possible symlinks in its leading directories.
5453 This is because Windows system calls and library functions
5454 transparently resolve symlinks in leading directories and return
5455 correct information, as long as the basename is not a symlink. */
5457 chase_symlinks (const char *file
)
5459 static char target
[MAX_UTF8_PATH
];
5460 char link
[MAX_UTF8_PATH
];
5461 wchar_t target_w
[MAX_PATH
], link_w
[MAX_PATH
];
5462 char target_a
[MAX_PATH
], link_a
[MAX_PATH
];
5463 ssize_t res
, link_len
;
5466 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
5467 return (char *)file
;
5469 if (w32_unicode_filenames
)
5471 wchar_t file_w
[MAX_PATH
];
5473 filename_to_utf16 (file
, file_w
);
5474 if (GetFullPathNameW (file_w
, MAX_PATH
, link_w
, NULL
) == 0)
5475 return (char *)file
;
5476 filename_from_utf16 (link_w
, link
);
5480 char file_a
[MAX_PATH
];
5482 filename_to_ansi (file
, file_a
);
5483 if (GetFullPathNameA (file_a
, MAX_PATH
, link_a
, NULL
) == 0)
5484 return (char *)file
;
5485 filename_from_ansi (link_a
, link
);
5487 link_len
= strlen (link
);
5492 /* Remove trailing slashes, as we want to resolve the last
5493 non-trivial part of the link name. */
5494 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
5495 link
[link_len
--] = '\0';
5497 res
= readlink (link
, target
, MAX_UTF8_PATH
);
5501 if (!(IS_DEVICE_SEP (target
[1])
5502 || (IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1]))))
5504 /* Target is relative. Append it to the directory part of
5505 the symlink, then copy the result back to target. */
5506 char *p
= link
+ link_len
;
5508 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
5511 strcpy (target
, link
);
5513 /* Resolve any "." and ".." to get a fully-qualified file name
5515 if (w32_unicode_filenames
)
5517 filename_to_utf16 (target
, target_w
);
5518 link_len
= GetFullPathNameW (target_w
, MAX_PATH
, link_w
, NULL
);
5520 filename_from_utf16 (link_w
, link
);
5524 filename_to_ansi (target
, target_a
);
5525 link_len
= GetFullPathNameA (target_a
, MAX_PATH
, link_a
, NULL
);
5527 filename_from_ansi (link_a
, link
);
5529 link_len
= strlen (link
);
5531 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
5533 if (loop_count
> 100)
5536 if (target
[0] == '\0') /* not a single call to readlink succeeded */
5537 return (char *)file
;
5542 /* Posix ACL emulation. */
5545 acl_valid (acl_t acl
)
5547 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR
)acl
) ? 0 : -1;
5551 acl_to_text (acl_t acl
, ssize_t
*size
)
5554 SECURITY_INFORMATION flags
=
5555 OWNER_SECURITY_INFORMATION
|
5556 GROUP_SECURITY_INFORMATION
|
5557 DACL_SECURITY_INFORMATION
;
5558 char *retval
= NULL
;
5564 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR
)acl
, SDDL_REVISION_1
, flags
, &str_acl
, &local_size
))
5567 /* We don't want to mix heaps, so we duplicate the string in our
5568 heap and free the one allocated by the API. */
5569 retval
= xstrdup (str_acl
);
5572 LocalFree (str_acl
);
5574 else if (errno
!= ENOTSUP
)
5581 acl_from_text (const char *acl_str
)
5583 PSECURITY_DESCRIPTOR psd
, retval
= NULL
;
5589 if (convert_sddl_to_sd (acl_str
, SDDL_REVISION_1
, &psd
, &sd_size
))
5592 retval
= xmalloc (sd_size
);
5593 memcpy (retval
, psd
, sd_size
);
5596 else if (errno
!= ENOTSUP
)
5603 acl_free (void *ptr
)
5610 acl_get_file (const char *fname
, acl_type_t type
)
5612 PSECURITY_DESCRIPTOR psd
= NULL
;
5613 const char *filename
;
5615 if (type
== ACL_TYPE_ACCESS
)
5618 SECURITY_INFORMATION si
=
5619 OWNER_SECURITY_INFORMATION
|
5620 GROUP_SECURITY_INFORMATION
|
5621 DACL_SECURITY_INFORMATION
;
5624 filename
= map_w32_filename (fname
, NULL
);
5625 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5626 fname
= chase_symlinks (filename
);
5631 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
)
5632 && errno
!= ENOTSUP
)
5634 err
= GetLastError ();
5635 if (err
== ERROR_INSUFFICIENT_BUFFER
)
5637 psd
= xmalloc (sd_len
);
5638 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
5645 else if (err
== ERROR_FILE_NOT_FOUND
5646 || err
== ERROR_PATH_NOT_FOUND
)
5654 else if (type
!= ACL_TYPE_DEFAULT
)
5661 acl_set_file (const char *fname
, acl_type_t type
, acl_t acl
)
5663 TOKEN_PRIVILEGES old1
, old2
;
5665 int st
= 0, retval
= -1;
5666 SECURITY_INFORMATION flags
= 0;
5672 const char *filename
;
5674 if (acl_valid (acl
) != 0
5675 || (type
!= ACL_TYPE_DEFAULT
&& type
!= ACL_TYPE_ACCESS
))
5681 if (type
== ACL_TYPE_DEFAULT
)
5687 filename
= map_w32_filename (fname
, NULL
);
5688 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5689 fname
= chase_symlinks (filename
);
5693 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5695 flags
|= OWNER_SECURITY_INFORMATION
;
5696 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5698 flags
|= GROUP_SECURITY_INFORMATION
;
5699 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR
)acl
, &dacl_present
,
5702 flags
|= DACL_SECURITY_INFORMATION
;
5706 /* According to KB-245153, setting the owner will succeed if either:
5707 (1) the caller is the user who will be the new owner, and has the
5708 SE_TAKE_OWNERSHIP privilege, or
5709 (2) the caller has the SE_RESTORE privilege, in which case she can
5710 set any valid user or group as the owner
5712 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5713 privileges, and disregard any failures in obtaining them. If
5714 these privileges cannot be obtained, and do not already exist in
5715 the calling thread's security token, this function could fail
5717 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME
, TRUE
, &old1
))
5719 if (enable_privilege (SE_RESTORE_NAME
, TRUE
, &old2
))
5724 if (!set_file_security ((char *)fname
, flags
, (PSECURITY_DESCRIPTOR
)acl
))
5726 err
= GetLastError ();
5728 if (errno
== ENOTSUP
)
5730 else if (err
== ERROR_INVALID_OWNER
5731 || err
== ERROR_NOT_ALL_ASSIGNED
5732 || err
== ERROR_ACCESS_DENIED
)
5734 /* Maybe the requested ACL and the one the file already has
5735 are identical, in which case we can silently ignore the
5736 failure. (And no, Windows doesn't.) */
5737 acl_t current_acl
= acl_get_file (fname
, ACL_TYPE_ACCESS
);
5742 char *acl_from
= acl_to_text (current_acl
, NULL
);
5743 char *acl_to
= acl_to_text (acl
, NULL
);
5745 if (acl_from
&& acl_to
&& xstrcasecmp (acl_from
, acl_to
) == 0)
5751 acl_free (acl_from
);
5754 acl_free (current_acl
);
5757 else if (err
== ERROR_FILE_NOT_FOUND
|| err
== ERROR_PATH_NOT_FOUND
)
5771 restore_privilege (&old2
);
5772 restore_privilege (&old1
);
5780 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5781 have a fixed max size for file names, so we don't need the kind of
5782 alloc/malloc/realloc dance the gnulib version does. We also don't
5783 support FD-relative symlinks. */
5785 careadlinkat (int fd
, char const *filename
,
5786 char *buffer
, size_t buffer_size
,
5787 struct allocator
const *alloc
,
5788 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
5790 char linkname
[MAX_UTF8_PATH
];
5793 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
5797 char *retval
= buffer
;
5799 linkname
[link_size
++] = '\0';
5800 if (link_size
> buffer_size
)
5801 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
5803 memcpy (retval
, linkname
, link_size
);
5811 /* Support for browsing other processes and their attributes. See
5812 process.c for the Lisp bindings. */
5814 /* Helper wrapper functions. */
5816 static HANDLE WINAPI
5817 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
5819 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
5821 if (g_b_init_create_toolhelp32_snapshot
== 0)
5823 g_b_init_create_toolhelp32_snapshot
= 1;
5824 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
5825 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5826 "CreateToolhelp32Snapshot");
5828 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
5830 return INVALID_HANDLE_VALUE
;
5832 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
5836 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5838 static Process32First_Proc s_pfn_Process32_First
= NULL
;
5840 if (g_b_init_process32_first
== 0)
5842 g_b_init_process32_first
= 1;
5843 s_pfn_Process32_First
= (Process32First_Proc
)
5844 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5847 if (s_pfn_Process32_First
== NULL
)
5851 return (s_pfn_Process32_First (hSnapshot
, lppe
));
5855 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5857 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
5859 if (g_b_init_process32_next
== 0)
5861 g_b_init_process32_next
= 1;
5862 s_pfn_Process32_Next
= (Process32Next_Proc
)
5863 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5866 if (s_pfn_Process32_Next
== NULL
)
5870 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
5874 open_thread_token (HANDLE ThreadHandle
,
5875 DWORD DesiredAccess
,
5877 PHANDLE TokenHandle
)
5879 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
5880 HMODULE hm_advapi32
= NULL
;
5881 if (is_windows_9x () == TRUE
)
5883 SetLastError (ERROR_NOT_SUPPORTED
);
5886 if (g_b_init_open_thread_token
== 0)
5888 g_b_init_open_thread_token
= 1;
5889 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5890 s_pfn_Open_Thread_Token
=
5891 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
5893 if (s_pfn_Open_Thread_Token
== NULL
)
5895 SetLastError (ERROR_NOT_SUPPORTED
);
5899 s_pfn_Open_Thread_Token (
5908 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
5910 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
5911 HMODULE hm_advapi32
= NULL
;
5912 if (is_windows_9x () == TRUE
)
5916 if (g_b_init_impersonate_self
== 0)
5918 g_b_init_impersonate_self
= 1;
5919 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5920 s_pfn_Impersonate_Self
=
5921 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
5923 if (s_pfn_Impersonate_Self
== NULL
)
5927 return s_pfn_Impersonate_Self (ImpersonationLevel
);
5931 revert_to_self (void)
5933 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
5934 HMODULE hm_advapi32
= NULL
;
5935 if (is_windows_9x () == TRUE
)
5939 if (g_b_init_revert_to_self
== 0)
5941 g_b_init_revert_to_self
= 1;
5942 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5943 s_pfn_Revert_To_Self
=
5944 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
5946 if (s_pfn_Revert_To_Self
== NULL
)
5950 return s_pfn_Revert_To_Self ();
5954 get_process_memory_info (HANDLE h_proc
,
5955 PPROCESS_MEMORY_COUNTERS mem_counters
,
5958 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
5959 HMODULE hm_psapi
= NULL
;
5960 if (is_windows_9x () == TRUE
)
5964 if (g_b_init_get_process_memory_info
== 0)
5966 g_b_init_get_process_memory_info
= 1;
5967 hm_psapi
= LoadLibrary ("Psapi.dll");
5969 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
5970 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
5972 if (s_pfn_Get_Process_Memory_Info
== NULL
)
5976 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
5980 get_process_working_set_size (HANDLE h_proc
,
5984 static GetProcessWorkingSetSize_Proc
5985 s_pfn_Get_Process_Working_Set_Size
= NULL
;
5987 if (is_windows_9x () == TRUE
)
5991 if (g_b_init_get_process_working_set_size
== 0)
5993 g_b_init_get_process_working_set_size
= 1;
5994 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
5995 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5996 "GetProcessWorkingSetSize");
5998 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
6002 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
6006 global_memory_status (MEMORYSTATUS
*buf
)
6008 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
6010 if (is_windows_9x () == TRUE
)
6014 if (g_b_init_global_memory_status
== 0)
6016 g_b_init_global_memory_status
= 1;
6017 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
6018 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6019 "GlobalMemoryStatus");
6021 if (s_pfn_Global_Memory_Status
== NULL
)
6025 return s_pfn_Global_Memory_Status (buf
);
6029 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
6031 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
6033 if (is_windows_9x () == TRUE
)
6037 if (g_b_init_global_memory_status_ex
== 0)
6039 g_b_init_global_memory_status_ex
= 1;
6040 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
6041 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6042 "GlobalMemoryStatusEx");
6044 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
6048 return s_pfn_Global_Memory_Status_Ex (buf
);
6052 list_system_processes (void)
6054 struct gcpro gcpro1
;
6055 Lisp_Object proclist
= Qnil
;
6058 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
6060 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
6062 PROCESSENTRY32 proc_entry
;
6068 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
6069 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
6070 res
= process32_next (h_snapshot
, &proc_entry
))
6072 proc_id
= proc_entry
.th32ProcessID
;
6073 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
6076 CloseHandle (h_snapshot
);
6078 proclist
= Fnreverse (proclist
);
6085 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
6087 TOKEN_PRIVILEGES priv
;
6088 DWORD priv_size
= sizeof (priv
);
6089 DWORD opriv_size
= sizeof (*old_priv
);
6090 HANDLE h_token
= NULL
;
6091 HANDLE h_thread
= GetCurrentThread ();
6095 res
= open_thread_token (h_thread
,
6096 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
6098 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
6100 if (impersonate_self (SecurityImpersonation
))
6101 res
= open_thread_token (h_thread
,
6102 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
6107 priv
.PrivilegeCount
= 1;
6108 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
6109 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
6110 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
6111 old_priv
, &opriv_size
)
6112 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
6116 CloseHandle (h_token
);
6122 restore_privilege (TOKEN_PRIVILEGES
*priv
)
6124 DWORD priv_size
= sizeof (*priv
);
6125 HANDLE h_token
= NULL
;
6128 if (open_thread_token (GetCurrentThread (),
6129 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
6132 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
6133 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
6137 CloseHandle (h_token
);
6143 ltime (ULONGLONG time_100ns
)
6145 ULONGLONG time_sec
= time_100ns
/ 10000000;
6146 int subsec
= time_100ns
% 10000000;
6147 return list4i (time_sec
>> 16, time_sec
& 0xffff,
6148 subsec
/ 10, subsec
% 10 * 100000);
6151 #define U64_TO_LISP_TIME(time) ltime (time)
6154 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
6155 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
6158 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
6159 ULONGLONG tem1
, tem2
, tem3
, tem
;
6162 || !get_process_times_fn
6163 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
6164 &ft_kernel
, &ft_user
))
6167 GetSystemTimeAsFileTime (&ft_current
);
6169 FILETIME_TO_U64 (tem1
, ft_kernel
);
6170 *stime
= U64_TO_LISP_TIME (tem1
);
6172 FILETIME_TO_U64 (tem2
, ft_user
);
6173 *utime
= U64_TO_LISP_TIME (tem2
);
6176 *ttime
= U64_TO_LISP_TIME (tem3
);
6178 FILETIME_TO_U64 (tem
, ft_creation
);
6179 /* Process no 4 (System) returns zero creation time. */
6182 *ctime
= U64_TO_LISP_TIME (tem
);
6186 FILETIME_TO_U64 (tem3
, ft_current
);
6187 tem
= (tem3
- utc_base
) - tem
;
6189 *etime
= U64_TO_LISP_TIME (tem
);
6193 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
6204 system_process_attributes (Lisp_Object pid
)
6206 struct gcpro gcpro1
, gcpro2
, gcpro3
;
6207 Lisp_Object attrs
= Qnil
;
6208 Lisp_Object cmd_str
, decoded_cmd
, tem
;
6209 HANDLE h_snapshot
, h_proc
;
6212 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
6213 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
6214 DWORD glength
= sizeof (gname
);
6215 HANDLE token
= NULL
;
6216 SID_NAME_USE user_type
;
6217 unsigned char *buf
= NULL
;
6219 TOKEN_USER user_token
;
6220 TOKEN_PRIMARY_GROUP group_token
;
6223 PROCESS_MEMORY_COUNTERS mem
;
6224 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
6225 SIZE_T minrss
, maxrss
;
6227 MEMORY_STATUS_EX memstex
;
6228 double totphys
= 0.0;
6229 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
6231 BOOL result
= FALSE
;
6233 CHECK_NUMBER_OR_FLOAT (pid
);
6234 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
6236 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
6238 GCPRO3 (attrs
, decoded_cmd
, tem
);
6240 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
6245 pe
.dwSize
= sizeof (PROCESSENTRY32
);
6246 for (res
= process32_first (h_snapshot
, &pe
); res
;
6247 res
= process32_next (h_snapshot
, &pe
))
6249 if (proc_id
== pe
.th32ProcessID
)
6252 decoded_cmd
= build_string ("Idle");
6255 /* Decode the command name from locale-specific
6257 cmd_str
= build_unibyte_string (pe
.szExeFile
);
6260 code_convert_string_norecord (cmd_str
,
6261 Vlocale_coding_system
, 0);
6263 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
6264 attrs
= Fcons (Fcons (Qppid
,
6265 make_fixnum_or_float (pe
.th32ParentProcessID
)),
6267 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
6269 attrs
= Fcons (Fcons (Qthcount
,
6270 make_fixnum_or_float (pe
.cntThreads
)),
6277 CloseHandle (h_snapshot
);
6286 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
6288 /* If we were denied a handle to the process, try again after
6289 enabling the SeDebugPrivilege in our process. */
6292 TOKEN_PRIVILEGES priv_current
;
6294 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
6296 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
6298 restore_privilege (&priv_current
);
6304 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
6307 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
6308 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
6310 buf
= xmalloc (blen
);
6311 result
= get_token_information (token
, TokenUser
,
6312 (LPVOID
)buf
, blen
, &needed
);
6315 memcpy (&user_token
, buf
, sizeof (user_token
));
6316 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
6318 euid
= get_rid (user_token
.User
.Sid
);
6319 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
6324 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
6327 strcpy (uname
, "unknown");
6331 ulength
= strlen (uname
);
6337 /* Determine a reasonable euid and gid values. */
6338 if (xstrcasecmp ("administrator", uname
) == 0)
6340 euid
= 500; /* well-known Administrator uid */
6341 egid
= 513; /* well-known None gid */
6345 /* Get group id and name. */
6346 result
= get_token_information (token
, TokenPrimaryGroup
,
6347 (LPVOID
)buf
, blen
, &needed
);
6348 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
6350 buf
= xrealloc (buf
, blen
= needed
);
6351 result
= get_token_information (token
, TokenPrimaryGroup
,
6352 (LPVOID
)buf
, blen
, &needed
);
6356 memcpy (&group_token
, buf
, sizeof (group_token
));
6357 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
6359 egid
= get_rid (group_token
.PrimaryGroup
);
6360 dlength
= sizeof (domain
);
6362 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
6363 gname
, &glength
, NULL
, &dlength
,
6366 w32_add_to_cache (group_token
.PrimaryGroup
,
6370 strcpy (gname
, "None");
6374 glength
= strlen (gname
);
6382 if (!is_windows_9x ())
6384 /* We couldn't open the process token, presumably because of
6385 insufficient access rights. Assume this process is run
6387 strcpy (uname
, "SYSTEM");
6388 strcpy (gname
, "None");
6389 euid
= 18; /* SYSTEM */
6390 egid
= 513; /* None */
6391 glength
= strlen (gname
);
6392 ulength
= strlen (uname
);
6394 /* If we are running under Windows 9X, where security calls are
6395 not supported, we assume all processes are run by the current
6397 else if (GetUserName (uname
, &ulength
))
6399 if (xstrcasecmp ("administrator", uname
) == 0)
6404 strcpy (gname
, "None");
6405 glength
= strlen (gname
);
6406 ulength
= strlen (uname
);
6412 strcpy (uname
, "administrator");
6413 ulength
= strlen (uname
);
6414 strcpy (gname
, "None");
6415 glength
= strlen (gname
);
6418 CloseHandle (token
);
6421 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
6422 tem
= make_unibyte_string (uname
, ulength
);
6423 attrs
= Fcons (Fcons (Quser
,
6424 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
6426 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
6427 tem
= make_unibyte_string (gname
, glength
);
6428 attrs
= Fcons (Fcons (Qgroup
,
6429 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
6432 if (global_memory_status_ex (&memstex
))
6433 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6434 totphys
= memstex
.ullTotalPhys
/ 1024.0;
6436 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6437 double, so we need to do this for it... */
6439 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
6440 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
6441 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
6443 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
6445 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6446 else if (global_memory_status (&memst
))
6447 totphys
= memst
.dwTotalPhys
/ 1024.0;
6450 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
6453 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
6455 attrs
= Fcons (Fcons (Qmajflt
,
6456 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
6458 attrs
= Fcons (Fcons (Qvsize
,
6459 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
6461 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
6463 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6466 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
6468 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
6470 attrs
= Fcons (Fcons (Qmajflt
,
6471 make_fixnum_or_float (mem
.PageFaultCount
)),
6473 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
6475 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6478 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
6480 DWORD rss
= maxrss
/ 1024;
6482 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
6484 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6487 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
6489 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
6490 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
6491 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
6492 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
6493 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
6494 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
6497 /* FIXME: Retrieve command line by walking the PEB of the process. */
6500 CloseHandle (h_proc
);
6506 /* Wrappers for winsock functions to map between our file descriptors
6507 and winsock's handles; also set h_errno for convenience.
6509 To allow Emacs to run on systems which don't have winsock support
6510 installed, we dynamically link to winsock on startup if present, and
6511 otherwise provide the minimum necessary functionality
6512 (eg. gethostname). */
6514 /* function pointers for relevant socket functions */
6515 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
6516 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
6517 int (PASCAL
*pfn_WSAGetLastError
) (void);
6518 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
6519 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
6520 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
6521 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
6522 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6523 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6524 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
6525 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
6526 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
6527 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
6528 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
6529 int (PASCAL
*pfn_WSACleanup
) (void);
6531 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
6532 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
6533 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
6534 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
6535 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
6536 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
6537 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
6538 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
6539 const char * optval
, int optlen
);
6540 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
6541 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
6543 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
6544 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
6545 struct sockaddr
* from
, int * fromlen
);
6546 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
6547 const struct sockaddr
* to
, int tolen
);
6549 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6550 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
6551 #ifndef HANDLE_FLAG_INHERIT
6552 #define HANDLE_FLAG_INHERIT 1
6556 static int winsock_inuse
;
6561 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
6563 release_listen_threads ();
6564 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6565 after WSAStartup returns successfully, but it seems reasonable
6566 to allow unloading winsock anyway in that case. */
6567 if (pfn_WSACleanup () == 0 ||
6568 pfn_WSAGetLastError () == WSAENETDOWN
)
6570 if (FreeLibrary (winsock_lib
))
6579 init_winsock (int load_now
)
6581 WSADATA winsockData
;
6583 if (winsock_lib
!= NULL
)
6586 pfn_SetHandleInformation
6587 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6588 "SetHandleInformation");
6590 winsock_lib
= LoadLibrary ("Ws2_32.dll");
6592 if (winsock_lib
!= NULL
)
6594 /* dynamically link to socket functions */
6596 #define LOAD_PROC(fn) \
6597 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6600 LOAD_PROC (WSAStartup
);
6601 LOAD_PROC (WSASetLastError
);
6602 LOAD_PROC (WSAGetLastError
);
6603 LOAD_PROC (WSAEventSelect
);
6604 LOAD_PROC (WSACreateEvent
);
6605 LOAD_PROC (WSACloseEvent
);
6608 LOAD_PROC (connect
);
6609 LOAD_PROC (ioctlsocket
);
6612 LOAD_PROC (closesocket
);
6613 LOAD_PROC (shutdown
);
6616 LOAD_PROC (inet_addr
);
6617 LOAD_PROC (gethostname
);
6618 LOAD_PROC (gethostbyname
);
6619 LOAD_PROC (getservbyname
);
6620 LOAD_PROC (getpeername
);
6621 LOAD_PROC (WSACleanup
);
6622 LOAD_PROC (setsockopt
);
6624 LOAD_PROC (getsockname
);
6626 LOAD_PROC (recvfrom
);
6630 /* specify version 1.1 of winsock */
6631 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
6633 if (winsockData
.wVersion
!= 0x101)
6638 /* Report that winsock exists and is usable, but leave
6639 socket functions disabled. I am assuming that calling
6640 WSAStartup does not require any network interaction,
6641 and in particular does not cause or require a dial-up
6642 connection to be established. */
6645 FreeLibrary (winsock_lib
);
6653 FreeLibrary (winsock_lib
);
6663 /* Function to map winsock error codes to errno codes for those errno
6664 code defined in errno.h (errno values not defined by errno.h are
6665 already in nt/inc/sys/socket.h). */
6672 if (winsock_lib
== NULL
)
6675 wsa_err
= pfn_WSAGetLastError ();
6679 case WSAEACCES
: errno
= EACCES
; break;
6680 case WSAEBADF
: errno
= EBADF
; break;
6681 case WSAEFAULT
: errno
= EFAULT
; break;
6682 case WSAEINTR
: errno
= EINTR
; break;
6683 case WSAEINVAL
: errno
= EINVAL
; break;
6684 case WSAEMFILE
: errno
= EMFILE
; break;
6685 case WSAENAMETOOLONG
: errno
= ENAMETOOLONG
; break;
6686 case WSAENOTEMPTY
: errno
= ENOTEMPTY
; break;
6687 default: errno
= wsa_err
; break;
6695 if (winsock_lib
!= NULL
)
6696 pfn_WSASetLastError (0);
6699 /* Extend strerror to handle the winsock-specific error codes. */
6703 } _wsa_errlist
[] = {
6704 {WSAEINTR
, "Interrupted function call"},
6705 {WSAEBADF
, "Bad file descriptor"},
6706 {WSAEACCES
, "Permission denied"},
6707 {WSAEFAULT
, "Bad address"},
6708 {WSAEINVAL
, "Invalid argument"},
6709 {WSAEMFILE
, "Too many open files"},
6711 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
6712 {WSAEINPROGRESS
, "Operation now in progress"},
6713 {WSAEALREADY
, "Operation already in progress"},
6714 {WSAENOTSOCK
, "Socket operation on non-socket"},
6715 {WSAEDESTADDRREQ
, "Destination address required"},
6716 {WSAEMSGSIZE
, "Message too long"},
6717 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
6718 {WSAENOPROTOOPT
, "Bad protocol option"},
6719 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
6720 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
6721 {WSAEOPNOTSUPP
, "Operation not supported"},
6722 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
6723 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
6724 {WSAEADDRINUSE
, "Address already in use"},
6725 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
6726 {WSAENETDOWN
, "Network is down"},
6727 {WSAENETUNREACH
, "Network is unreachable"},
6728 {WSAENETRESET
, "Network dropped connection on reset"},
6729 {WSAECONNABORTED
, "Software caused connection abort"},
6730 {WSAECONNRESET
, "Connection reset by peer"},
6731 {WSAENOBUFS
, "No buffer space available"},
6732 {WSAEISCONN
, "Socket is already connected"},
6733 {WSAENOTCONN
, "Socket is not connected"},
6734 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
6735 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
6736 {WSAETIMEDOUT
, "Connection timed out"},
6737 {WSAECONNREFUSED
, "Connection refused"},
6738 {WSAELOOP
, "Network loop"}, /* not sure */
6739 {WSAENAMETOOLONG
, "Name is too long"},
6740 {WSAEHOSTDOWN
, "Host is down"},
6741 {WSAEHOSTUNREACH
, "No route to host"},
6742 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
6743 {WSAEPROCLIM
, "Too many processes"},
6744 {WSAEUSERS
, "Too many users"}, /* not sure */
6745 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
6746 {WSAESTALE
, "Data is stale"}, /* not sure */
6747 {WSAEREMOTE
, "Remote error"}, /* not sure */
6749 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
6750 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
6751 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
6752 {WSAEDISCON
, "Graceful shutdown in progress"},
6754 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
6755 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
6756 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
6757 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
6758 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
6759 {WSASYSCALLFAILURE
, "System call failure"},
6760 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
6761 {WSATYPE_NOT_FOUND
, "Class type not found"},
6762 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
6763 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
6764 {WSAEREFUSED
, "Operation refused"}, /* not sure */
6767 {WSAHOST_NOT_FOUND
, "Host not found"},
6768 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
6769 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
6770 {WSANO_DATA
, "Valid name, no data record of requested type"},
6776 sys_strerror (int error_no
)
6779 static char unknown_msg
[40];
6781 if (error_no
>= 0 && error_no
< sys_nerr
)
6782 return sys_errlist
[error_no
];
6784 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
6785 if (_wsa_errlist
[i
].errnum
== error_no
)
6786 return _wsa_errlist
[i
].msg
;
6788 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
6792 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6793 but I believe the method of keeping the socket handle separate (and
6794 insuring it is not inheritable) is the correct one. */
6796 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6798 static int socket_to_fd (SOCKET s
);
6801 sys_socket (int af
, int type
, int protocol
)
6805 if (winsock_lib
== NULL
)
6808 return INVALID_SOCKET
;
6813 /* call the real socket function */
6814 s
= pfn_socket (af
, type
, protocol
);
6816 if (s
!= INVALID_SOCKET
)
6817 return socket_to_fd (s
);
6823 /* Convert a SOCKET to a file descriptor. */
6825 socket_to_fd (SOCKET s
)
6830 /* Although under NT 3.5 _open_osfhandle will accept a socket
6831 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6832 that does not work under NT 3.1. However, we can get the same
6833 effect by using a backdoor function to replace an existing
6834 descriptor handle with the one we want. */
6836 /* allocate a file descriptor (with appropriate flags) */
6837 fd
= _open ("NUL:", _O_RDWR
);
6840 /* Make a non-inheritable copy of the socket handle. Note
6841 that it is possible that sockets aren't actually kernel
6842 handles, which appears to be the case on Windows 9x when
6843 the MS Proxy winsock client is installed. */
6845 /* Apparently there is a bug in NT 3.51 with some service
6846 packs, which prevents using DuplicateHandle to make a
6847 socket handle non-inheritable (causes WSACleanup to
6848 hang). The work-around is to use SetHandleInformation
6849 instead if it is available and implemented. */
6850 if (pfn_SetHandleInformation
)
6852 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
6856 HANDLE parent
= GetCurrentProcess ();
6857 HANDLE new_s
= INVALID_HANDLE_VALUE
;
6859 if (DuplicateHandle (parent
,
6865 DUPLICATE_SAME_ACCESS
))
6867 /* It is possible that DuplicateHandle succeeds even
6868 though the socket wasn't really a kernel handle,
6869 because a real handle has the same value. So
6870 test whether the new handle really is a socket. */
6871 long nonblocking
= 0;
6872 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
6874 pfn_closesocket (s
);
6879 CloseHandle (new_s
);
6884 eassert (fd
< MAXDESC
);
6885 fd_info
[fd
].hnd
= (HANDLE
) s
;
6887 /* set our own internal flags */
6888 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
6894 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6896 /* attach child_process to fd_info */
6897 if (fd_info
[ fd
].cp
!= NULL
)
6899 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
6903 fd_info
[ fd
].cp
= cp
;
6906 winsock_inuse
++; /* count open sockets */
6914 pfn_closesocket (s
);
6920 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
6922 if (winsock_lib
== NULL
)
6925 return SOCKET_ERROR
;
6929 if (fd_info
[s
].flags
& FILE_SOCKET
)
6931 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
6932 if (rc
== SOCKET_ERROR
)
6937 return SOCKET_ERROR
;
6941 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
6943 if (winsock_lib
== NULL
)
6946 return SOCKET_ERROR
;
6950 if (fd_info
[s
].flags
& FILE_SOCKET
)
6952 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
6953 if (rc
== SOCKET_ERROR
)
6958 return SOCKET_ERROR
;
6962 sys_htons (u_short hostshort
)
6964 return (winsock_lib
!= NULL
) ?
6965 pfn_htons (hostshort
) : hostshort
;
6969 sys_ntohs (u_short netshort
)
6971 return (winsock_lib
!= NULL
) ?
6972 pfn_ntohs (netshort
) : netshort
;
6976 sys_inet_addr (const char * cp
)
6978 return (winsock_lib
!= NULL
) ?
6979 pfn_inet_addr (cp
) : INADDR_NONE
;
6983 sys_gethostname (char * name
, int namelen
)
6985 if (winsock_lib
!= NULL
)
6990 retval
= pfn_gethostname (name
, namelen
);
6991 if (retval
== SOCKET_ERROR
)
6996 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
6997 return !GetComputerName (name
, (DWORD
*)&namelen
);
7000 return SOCKET_ERROR
;
7004 sys_gethostbyname (const char * name
)
7006 struct hostent
* host
;
7007 int h_err
= h_errno
;
7009 if (winsock_lib
== NULL
)
7011 h_errno
= NO_RECOVERY
;
7017 host
= pfn_gethostbyname (name
);
7029 sys_getservbyname (const char * name
, const char * proto
)
7031 struct servent
* serv
;
7033 if (winsock_lib
== NULL
)
7040 serv
= pfn_getservbyname (name
, proto
);
7047 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
7049 if (winsock_lib
== NULL
)
7052 return SOCKET_ERROR
;
7056 if (fd_info
[s
].flags
& FILE_SOCKET
)
7058 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
7059 if (rc
== SOCKET_ERROR
)
7064 return SOCKET_ERROR
;
7068 sys_shutdown (int s
, int how
)
7070 if (winsock_lib
== NULL
)
7073 return SOCKET_ERROR
;
7077 if (fd_info
[s
].flags
& FILE_SOCKET
)
7079 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
7080 if (rc
== SOCKET_ERROR
)
7085 return SOCKET_ERROR
;
7089 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
7091 if (winsock_lib
== NULL
)
7094 return SOCKET_ERROR
;
7098 if (fd_info
[s
].flags
& FILE_SOCKET
)
7100 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
7101 (const char *)optval
, optlen
);
7102 if (rc
== SOCKET_ERROR
)
7107 return SOCKET_ERROR
;
7111 sys_listen (int s
, int backlog
)
7113 if (winsock_lib
== NULL
)
7116 return SOCKET_ERROR
;
7120 if (fd_info
[s
].flags
& FILE_SOCKET
)
7122 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
7123 if (rc
== SOCKET_ERROR
)
7126 fd_info
[s
].flags
|= FILE_LISTEN
;
7130 return SOCKET_ERROR
;
7134 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
7136 if (winsock_lib
== NULL
)
7139 return SOCKET_ERROR
;
7143 if (fd_info
[s
].flags
& FILE_SOCKET
)
7145 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
7146 if (rc
== SOCKET_ERROR
)
7151 return SOCKET_ERROR
;
7155 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
7157 if (winsock_lib
== NULL
)
7164 if (fd_info
[s
].flags
& FILE_LISTEN
)
7166 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
7168 if (t
== INVALID_SOCKET
)
7171 fd
= socket_to_fd (t
);
7175 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7176 ResetEvent (fd_info
[s
].cp
->char_avail
);
7185 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
7186 struct sockaddr
* from
, int * fromlen
)
7188 if (winsock_lib
== NULL
)
7191 return SOCKET_ERROR
;
7195 if (fd_info
[s
].flags
& FILE_SOCKET
)
7197 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
7198 if (rc
== SOCKET_ERROR
)
7203 return SOCKET_ERROR
;
7207 sys_sendto (int s
, const char * buf
, int len
, int flags
,
7208 const struct sockaddr
* to
, int tolen
)
7210 if (winsock_lib
== NULL
)
7213 return SOCKET_ERROR
;
7217 if (fd_info
[s
].flags
& FILE_SOCKET
)
7219 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
7220 if (rc
== SOCKET_ERROR
)
7225 return SOCKET_ERROR
;
7228 /* Windows does not have an fcntl function. Provide an implementation
7229 good enough for Emacs. */
7231 fcntl (int s
, int cmd
, int options
)
7233 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
7234 invoked in a context where fd1 is closed and all descriptors less
7235 than fd1 are open, so sys_dup is an adequate implementation. */
7236 if (cmd
== F_DUPFD_CLOEXEC
)
7239 if (winsock_lib
== NULL
)
7246 if (fd_info
[s
].flags
& FILE_SOCKET
)
7248 if (cmd
== F_SETFL
&& options
== O_NONBLOCK
)
7250 unsigned long nblock
= 1;
7251 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
7252 if (rc
== SOCKET_ERROR
)
7254 /* Keep track of the fact that we set this to non-blocking. */
7255 fd_info
[s
].flags
|= FILE_NDELAY
;
7261 return SOCKET_ERROR
;
7265 return SOCKET_ERROR
;
7269 /* Shadow main io functions: we need to handle pipes and sockets more
7270 intelligently, and implement non-blocking mode as well. */
7283 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
7285 child_process
* cp
= fd_info
[fd
].cp
;
7287 fd_info
[fd
].cp
= NULL
;
7289 if (CHILD_ACTIVE (cp
))
7291 /* if last descriptor to active child_process then cleanup */
7293 for (i
= 0; i
< MAXDESC
; i
++)
7297 if (fd_info
[i
].cp
== cp
)
7302 if (fd_info
[fd
].flags
& FILE_SOCKET
)
7304 if (winsock_lib
== NULL
) emacs_abort ();
7306 pfn_shutdown (SOCK_HANDLE (fd
), 2);
7307 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
7309 winsock_inuse
--; /* count open sockets */
7311 /* If the process handle is NULL, it's either a socket
7312 or serial connection, or a subprocess that was
7313 already reaped by reap_subprocess, but whose
7314 resources were not yet freed, because its output was
7315 not fully read yet by the time it was reaped. (This
7316 usually happens with async subprocesses whose output
7317 is being read by Emacs.) Otherwise, this process was
7318 not reaped yet, so we set its FD to a negative value
7319 to make sure sys_select will eventually get to
7320 calling the SIGCHLD handler for it, which will then
7321 invoke waitpid and reap_subprocess. */
7322 if (cp
->procinfo
.hProcess
== NULL
)
7330 if (fd
>= 0 && fd
< MAXDESC
)
7331 fd_info
[fd
].flags
= 0;
7333 /* Note that sockets do not need special treatment here (at least on
7334 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7335 closesocket is equivalent to CloseHandle, which is to be expected
7336 because socket handles are fully fledged kernel handles. */
7348 if (new_fd
>= 0 && new_fd
< MAXDESC
)
7350 /* duplicate our internal info as well */
7351 fd_info
[new_fd
] = fd_info
[fd
];
7357 sys_dup2 (int src
, int dst
)
7361 if (dst
< 0 || dst
>= MAXDESC
)
7367 /* make sure we close the destination first if it's a pipe or socket */
7368 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
7371 rc
= _dup2 (src
, dst
);
7374 /* duplicate our internal info as well */
7375 fd_info
[dst
] = fd_info
[src
];
7381 pipe2 (int * phandles
, int pipe2_flags
)
7386 eassert (pipe2_flags
== O_CLOEXEC
);
7388 /* make pipe handles non-inheritable; when we spawn a child, we
7389 replace the relevant handle with an inheritable one. Also put
7390 pipes into binary mode; we will do text mode translation ourselves
7392 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
7396 /* Protect against overflow, since Windows can open more handles than
7397 our fd_info array has room for. */
7398 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
7400 _close (phandles
[0]);
7401 _close (phandles
[1]);
7407 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
7408 fd_info
[phandles
[0]].flags
= flags
;
7410 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
7411 fd_info
[phandles
[1]].flags
= flags
;
7418 /* Function to do blocking read of one byte, needed to implement
7419 select. It is only allowed on communication ports, sockets, or
7422 _sys_read_ahead (int fd
)
7427 if (fd
< 0 || fd
>= MAXDESC
)
7428 return STATUS_READ_ERROR
;
7430 cp
= fd_info
[fd
].cp
;
7432 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7433 return STATUS_READ_ERROR
;
7435 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
7436 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
7438 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
7442 cp
->status
= STATUS_READ_IN_PROGRESS
;
7444 if (fd_info
[fd
].flags
& FILE_PIPE
)
7446 rc
= _read (fd
, &cp
->chr
, sizeof (char));
7448 /* Give subprocess time to buffer some more output for us before
7449 reporting that input is available; we need this because Windows 95
7450 connects DOS programs to pipes by making the pipe appear to be
7451 the normal console stdout - as a result most DOS programs will
7452 write to stdout without buffering, ie. one character at a
7453 time. Even some W32 programs do this - "dir" in a command
7454 shell on NT is very slow if we don't do this. */
7457 int wait
= w32_pipe_read_delay
;
7463 /* Yield remainder of our time slice, effectively giving a
7464 temporary priority boost to the child process. */
7468 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7470 HANDLE hnd
= fd_info
[fd
].hnd
;
7471 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7474 /* Configure timeouts for blocking read. */
7475 if (!GetCommTimeouts (hnd
, &ct
))
7477 cp
->status
= STATUS_READ_ERROR
;
7478 return STATUS_READ_ERROR
;
7480 ct
.ReadIntervalTimeout
= 0;
7481 ct
.ReadTotalTimeoutMultiplier
= 0;
7482 ct
.ReadTotalTimeoutConstant
= 0;
7483 if (!SetCommTimeouts (hnd
, &ct
))
7485 cp
->status
= STATUS_READ_ERROR
;
7486 return STATUS_READ_ERROR
;
7489 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
7491 if (GetLastError () != ERROR_IO_PENDING
)
7493 cp
->status
= STATUS_READ_ERROR
;
7494 return STATUS_READ_ERROR
;
7496 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7498 cp
->status
= STATUS_READ_ERROR
;
7499 return STATUS_READ_ERROR
;
7503 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
7505 unsigned long nblock
= 0;
7506 /* We always want this to block, so temporarily disable NDELAY. */
7507 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7508 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7510 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
7512 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7515 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7519 if (rc
== sizeof (char))
7520 cp
->status
= STATUS_READ_SUCCEEDED
;
7522 cp
->status
= STATUS_READ_FAILED
;
7528 _sys_wait_accept (int fd
)
7534 if (fd
< 0 || fd
>= MAXDESC
)
7535 return STATUS_READ_ERROR
;
7537 cp
= fd_info
[fd
].cp
;
7539 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7540 return STATUS_READ_ERROR
;
7542 cp
->status
= STATUS_READ_FAILED
;
7544 hEv
= pfn_WSACreateEvent ();
7545 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
7546 if (rc
!= SOCKET_ERROR
)
7549 rc
= WaitForSingleObject (hEv
, 500);
7551 } while (rc
== WAIT_TIMEOUT
7552 && cp
->status
!= STATUS_READ_ERROR
7554 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
7555 if (rc
== WAIT_OBJECT_0
)
7556 cp
->status
= STATUS_READ_SUCCEEDED
;
7558 pfn_WSACloseEvent (hEv
);
7564 sys_read (int fd
, char * buffer
, unsigned int count
)
7569 char * orig_buffer
= buffer
;
7577 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7579 child_process
*cp
= fd_info
[fd
].cp
;
7581 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
7589 /* re-read CR carried over from last read */
7590 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
7592 if (fd_info
[fd
].flags
& FILE_BINARY
) emacs_abort ();
7596 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
7599 /* presence of a child_process structure means we are operating in
7600 non-blocking mode - otherwise we just call _read directly.
7601 Note that the child_process structure might be missing because
7602 reap_subprocess has been called; in this case the pipe is
7603 already broken, so calling _read on it is okay. */
7606 int current_status
= cp
->status
;
7608 switch (current_status
)
7610 case STATUS_READ_FAILED
:
7611 case STATUS_READ_ERROR
:
7612 /* report normal EOF if nothing in buffer */
7614 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7617 case STATUS_READ_READY
:
7618 case STATUS_READ_IN_PROGRESS
:
7619 DebPrint (("sys_read called when read is in progress\n"));
7620 errno
= EWOULDBLOCK
;
7623 case STATUS_READ_SUCCEEDED
:
7624 /* consume read-ahead char */
7625 *buffer
++ = cp
->chr
;
7628 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7629 ResetEvent (cp
->char_avail
);
7631 case STATUS_READ_ACKNOWLEDGED
:
7635 DebPrint (("sys_read: bad status %d\n", current_status
));
7640 if (fd_info
[fd
].flags
& FILE_PIPE
)
7642 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
7643 to_read
= min (waiting
, (DWORD
) count
);
7646 nchars
+= _read (fd
, buffer
, to_read
);
7648 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7650 HANDLE hnd
= fd_info
[fd
].hnd
;
7651 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7657 /* Configure timeouts for non-blocking read. */
7658 if (!GetCommTimeouts (hnd
, &ct
))
7663 ct
.ReadIntervalTimeout
= MAXDWORD
;
7664 ct
.ReadTotalTimeoutMultiplier
= 0;
7665 ct
.ReadTotalTimeoutConstant
= 0;
7666 if (!SetCommTimeouts (hnd
, &ct
))
7672 if (!ResetEvent (ovl
->hEvent
))
7677 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
7679 if (GetLastError () != ERROR_IO_PENDING
)
7684 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7693 else /* FILE_SOCKET */
7695 if (winsock_lib
== NULL
) emacs_abort ();
7697 /* do the equivalent of a non-blocking read */
7698 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
7699 if (waiting
== 0 && nchars
== 0)
7701 errno
= EWOULDBLOCK
;
7707 /* always use binary mode for sockets */
7708 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
7709 if (res
== SOCKET_ERROR
)
7711 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7712 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7722 int nread
= _read (fd
, buffer
, count
);
7725 else if (nchars
== 0)
7730 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7731 /* Perform text mode translation if required. */
7732 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7734 nchars
= crlf_to_lf (nchars
, orig_buffer
);
7735 /* If buffer contains only CR, return that. To be absolutely
7736 sure we should attempt to read the next char, but in
7737 practice a CR to be followed by LF would not appear by
7738 itself in the buffer. */
7739 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
7741 fd_info
[fd
].flags
|= FILE_LAST_CR
;
7747 nchars
= _read (fd
, buffer
, count
);
7752 /* From w32xfns.c */
7753 extern HANDLE interrupt_handle
;
7755 /* For now, don't bother with a non-blocking mode */
7757 sys_write (int fd
, const void * buffer
, unsigned int count
)
7767 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7769 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
7775 /* Perform text mode translation if required. */
7776 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7778 char * tmpbuf
= alloca (count
* 2);
7779 unsigned char * src
= (void *)buffer
;
7780 unsigned char * dst
= tmpbuf
;
7785 unsigned char *next
;
7786 /* copy next line or remaining bytes */
7787 next
= _memccpy (dst
, src
, '\n', nbytes
);
7790 /* copied one line ending with '\n' */
7791 int copied
= next
- dst
;
7794 /* insert '\r' before '\n' */
7801 /* copied remaining partial line -> now finished */
7808 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
7810 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
7811 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
7812 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
7815 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
7817 if (GetLastError () != ERROR_IO_PENDING
)
7822 if (detect_input_pending ())
7823 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
7826 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
7827 if (active
== WAIT_OBJECT_0
)
7828 { /* User pressed C-g, cancel write, then leave. Don't bother
7829 cleaning up as we may only get stuck in buggy drivers. */
7830 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
7835 if (active
== WAIT_OBJECT_0
+ 1
7836 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
7843 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
7845 unsigned long nblock
= 0;
7846 if (winsock_lib
== NULL
) emacs_abort ();
7848 /* TODO: implement select() properly so non-blocking I/O works. */
7849 /* For now, make sure the write blocks. */
7850 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7851 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7853 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
7855 /* Set the socket back to non-blocking if it was before,
7856 for other operations that support it. */
7857 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7860 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7863 if (nchars
== SOCKET_ERROR
)
7865 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7866 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7872 /* Some networked filesystems don't like too large writes, so
7873 break them into smaller chunks. See the Comments section of
7874 the MSDN documentation of WriteFile for details behind the
7875 choice of the value of CHUNK below. See also the thread
7876 http://thread.gmane.org/gmane.comp.version-control.git/145294
7877 in the git mailing list. */
7878 const unsigned char *p
= buffer
;
7879 const unsigned chunk
= 30 * 1024 * 1024;
7884 unsigned this_chunk
= count
< chunk
? count
: chunk
;
7885 int n
= _write (fd
, p
, this_chunk
);
7893 else if (n
< this_chunk
)
7904 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
7906 extern Lisp_Object
conv_sockaddr_to_lisp (struct sockaddr
*, int);
7908 /* Return information about network interface IFNAME, or about all
7909 interfaces (if IFNAME is nil). */
7911 network_interface_get_info (Lisp_Object ifname
)
7913 ULONG ainfo_len
= sizeof (IP_ADAPTER_INFO
);
7914 IP_ADAPTER_INFO
*adapter
, *ainfo
= xmalloc (ainfo_len
);
7915 DWORD retval
= get_adapters_info (ainfo
, &ainfo_len
);
7916 Lisp_Object res
= Qnil
;
7918 if (retval
== ERROR_BUFFER_OVERFLOW
)
7920 ainfo
= xrealloc (ainfo
, ainfo_len
);
7921 retval
= get_adapters_info (ainfo
, &ainfo_len
);
7924 if (retval
== ERROR_SUCCESS
)
7926 int eth_count
= 0, tr_count
= 0, fddi_count
= 0, ppp_count
= 0;
7927 int sl_count
= 0, wlan_count
= 0, lo_count
= 0, ifx_count
= 0;
7929 struct sockaddr_in sa
;
7931 /* For the below, we need some winsock functions, so make sure
7932 the winsock DLL is loaded. If we cannot successfully load
7933 it, they will have no use of the information we provide,
7935 if (!winsock_lib
&& !init_winsock (1))
7938 for (adapter
= ainfo
; adapter
; adapter
= adapter
->Next
)
7940 char namebuf
[MAX_ADAPTER_NAME_LENGTH
+ 4];
7942 /* Present Unix-compatible interface names, instead of the
7943 Windows names, which are really GUIDs not readable by
7945 static const char *ifmt
[] = {
7946 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
7961 switch (adapter
->Type
)
7963 case MIB_IF_TYPE_ETHERNET
:
7964 /* Windows before Vista reports wireless adapters as
7965 Ethernet. Work around by looking at the Description
7967 if (strstr (adapter
->Description
, "Wireless "))
7970 if_num
= wlan_count
++;
7974 ifmt_idx
= ETHERNET
;
7975 if_num
= eth_count
++;
7978 case MIB_IF_TYPE_TOKENRING
:
7979 ifmt_idx
= TOKENRING
;
7980 if_num
= tr_count
++;
7982 case MIB_IF_TYPE_FDDI
:
7984 if_num
= fddi_count
++;
7986 case MIB_IF_TYPE_PPP
:
7988 if_num
= ppp_count
++;
7990 case MIB_IF_TYPE_SLIP
:
7992 if_num
= sl_count
++;
7994 case IF_TYPE_IEEE80211
:
7996 if_num
= wlan_count
++;
7998 case MIB_IF_TYPE_LOOPBACK
:
8001 ifmt_idx
= LOOPBACK
;
8002 if_num
= lo_count
++;
8008 ifmt_idx
= OTHER_IF
;
8009 if_num
= ifx_count
++;
8012 if (ifmt_idx
== NONE
)
8014 sprintf (namebuf
, ifmt
[ifmt_idx
], if_num
);
8016 sa
.sin_family
= AF_INET
;
8017 ip_addr
= sys_inet_addr (adapter
->IpAddressList
.IpAddress
.String
);
8018 if (ip_addr
== INADDR_NONE
)
8020 /* Bogus address, skip this interface. */
8023 sa
.sin_addr
.s_addr
= ip_addr
;
8026 res
= Fcons (Fcons (build_string (namebuf
),
8027 conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8028 sizeof (struct sockaddr
))),
8030 else if (strcmp (namebuf
, SSDATA (ifname
)) == 0)
8032 Lisp_Object hwaddr
= Fmake_vector (make_number (6), Qnil
);
8033 register struct Lisp_Vector
*p
= XVECTOR (hwaddr
);
8034 Lisp_Object flags
= Qnil
;
8038 /* Flags. We guess most of them by type, since the
8039 Windows flags are different and hard to get by. */
8040 flags
= Fcons (intern ("up"), flags
);
8041 if (ifmt_idx
== ETHERNET
|| ifmt_idx
== WLAN
)
8043 flags
= Fcons (intern ("broadcast"), flags
);
8044 flags
= Fcons (intern ("multicast"), flags
);
8046 flags
= Fcons (intern ("running"), flags
);
8047 if (ifmt_idx
== PPP
)
8049 flags
= Fcons (intern ("pointopoint"), flags
);
8050 flags
= Fcons (intern ("noarp"), flags
);
8052 if (adapter
->HaveWins
)
8053 flags
= Fcons (intern ("WINS"), flags
);
8054 if (adapter
->DhcpEnabled
)
8055 flags
= Fcons (intern ("dynamic"), flags
);
8057 res
= Fcons (flags
, res
);
8059 /* Hardware address and its family. */
8060 for (n
= 0; n
< adapter
->AddressLength
; n
++)
8061 p
->contents
[n
] = make_number ((int) adapter
->Address
[n
]);
8062 /* Windows does not support AF_LINK or AF_PACKET family
8063 of addresses. Use an arbitrary family number that is
8064 identical to what GNU/Linux returns. */
8065 res
= Fcons (Fcons (make_number (1), hwaddr
), res
);
8068 sa
.sin_family
= AF_INET
;
8069 net_mask
= sys_inet_addr (adapter
->IpAddressList
.IpMask
.String
);
8070 if (net_mask
!= INADDR_NONE
)
8072 sa
.sin_addr
.s_addr
= net_mask
;
8074 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8075 sizeof (struct sockaddr
)),
8079 res
= Fcons (Qnil
, res
);
8081 sa
.sin_family
= AF_INET
;
8082 if (ip_addr
!= INADDR_NONE
)
8084 /* Broadcast address is only reported by
8085 GetAdaptersAddresses, which is of limited
8086 availability. Generate it on our own. */
8087 u_long bcast_addr
= (ip_addr
& net_mask
) | ~net_mask
;
8089 sa
.sin_addr
.s_addr
= bcast_addr
;
8091 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8092 sizeof (struct sockaddr
)),
8096 sa
.sin_addr
.s_addr
= ip_addr
;
8098 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8099 sizeof (struct sockaddr
)),
8103 res
= Fcons (Qnil
, Fcons (Qnil
, res
));
8106 /* GetAdaptersInfo is documented to not report loopback
8107 interfaces, so we generate one out of thin air. */
8110 sa
.sin_family
= AF_INET
;
8114 sa
.sin_addr
.s_addr
= sys_inet_addr ("127.0.0.1");
8115 res
= Fcons (Fcons (build_string ("lo"),
8116 conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8117 sizeof (struct sockaddr
))),
8120 else if (strcmp (SSDATA (ifname
), "lo") == 0)
8122 res
= Fcons (Fcons (intern ("running"),
8123 Fcons (intern ("loopback"),
8124 Fcons (intern ("up"), Qnil
))), Qnil
);
8125 /* 772 is what 3 different GNU/Linux systems report for
8126 the loopback interface. */
8127 res
= Fcons (Fcons (make_number (772),
8128 Fmake_vector (make_number (6),
8131 sa
.sin_addr
.s_addr
= sys_inet_addr ("255.0.0.0");
8132 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8133 sizeof (struct sockaddr
)),
8135 sa
.sin_addr
.s_addr
= sys_inet_addr ("0.0.0.0");
8136 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8137 sizeof (struct sockaddr
)),
8139 sa
.sin_addr
.s_addr
= sys_inet_addr ("127.0.0.1");
8140 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8141 sizeof (struct sockaddr
)),
8154 network_interface_list (void)
8156 return network_interface_get_info (Qnil
);
8160 network_interface_info (Lisp_Object ifname
)
8162 return network_interface_get_info (ifname
);
8166 /* The Windows CRT functions are "optimized for speed", so they don't
8167 check for timezone and DST changes if they were last called less
8168 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
8169 all Emacs features that repeatedly call time functions (e.g.,
8170 display-time) are in real danger of missing timezone and DST
8171 changes. Calling tzset before each localtime call fixes that. */
8173 sys_localtime (const time_t *t
)
8176 return localtime (t
);
8181 /* Try loading LIBRARY_ID from the file(s) specified in
8182 Vdynamic_library_alist. If the library is loaded successfully,
8183 return the handle of the DLL, and record the filename in the
8184 property :loaded-from of LIBRARY_ID. If the library could not be
8185 found, or when it was already loaded (because the handle is not
8186 recorded anywhere, and so is lost after use), return NULL.
8188 We could also save the handle in :loaded-from, but currently
8189 there's no use case for it. */
8191 w32_delayed_load (Lisp_Object library_id
)
8193 HMODULE dll_handle
= NULL
;
8195 CHECK_SYMBOL (library_id
);
8197 if (CONSP (Vdynamic_library_alist
)
8198 && NILP (Fassq (library_id
, Vlibrary_cache
)))
8200 Lisp_Object found
= Qnil
;
8201 Lisp_Object dlls
= Fassq (library_id
, Vdynamic_library_alist
);
8204 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
8206 Lisp_Object dll
= XCAR (dlls
);
8207 char name
[MAX_UTF8_PATH
];
8211 dll
= ENCODE_FILE (dll
);
8212 if (w32_unicode_filenames
)
8214 wchar_t name_w
[MAX_PATH
];
8216 filename_to_utf16 (SSDATA (dll
), name_w
);
8217 dll_handle
= LoadLibraryW (name_w
);
8220 res
= GetModuleFileNameW (dll_handle
, name_w
,
8223 filename_from_utf16 (name_w
, name
);
8228 char name_a
[MAX_PATH
];
8230 filename_to_ansi (SSDATA (dll
), name_a
);
8231 dll_handle
= LoadLibraryA (name_a
);
8234 res
= GetModuleFileNameA (dll_handle
, name_a
,
8237 filename_from_ansi (name_a
, name
);
8242 ptrdiff_t len
= strlen (name
);
8245 /* Possibly truncated */
8246 ? make_specified_string (name
, -1, len
, 1)
8252 Fput (library_id
, QCloaded_from
, found
);
8260 check_windows_init_file (void)
8262 /* A common indication that Emacs is not installed properly is when
8263 it cannot find the Windows installation file. If this file does
8264 not exist in the expected place, tell the user. */
8266 if (!noninteractive
&& !inhibit_window_system
8267 /* Vload_path is not yet initialized when we are loading
8269 && NILP (Vpurify_flag
))
8271 Lisp_Object init_file
;
8274 /* Implementation note: this function runs early during Emacs
8275 startup, before startup.el is run. So Vload_path is still in
8276 its initial unibyte form, holding ANSI-encoded file names.
8277 That is why we never bother to ENCODE_FILE here, nor use wide
8278 APIs for file names: we will never get UTF-8 encoded file
8280 init_file
= build_string ("term/w32-win");
8281 fd
= openp (Vload_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
8284 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
8285 char *init_file_name
= SDATA (init_file
);
8286 char *load_path
= SDATA (load_path_print
);
8287 char *buffer
= alloca (1024
8288 + strlen (init_file_name
)
8289 + strlen (load_path
));
8292 "The Emacs Windows initialization file \"%s.el\" "
8293 "could not be found in your Emacs installation. "
8294 "Emacs checked the following directories for this file:\n"
8296 "When Emacs cannot find this file, it usually means that it "
8297 "was not installed properly, or its distribution file was "
8298 "not unpacked properly.\nSee the README.W32 file in the "
8299 "top-level Emacs directory for more information.",
8300 init_file_name
, load_path
);
8303 "Emacs Abort Dialog",
8304 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
8305 /* Use the low-level system abort. */
8316 term_ntproc (int ignored
)
8322 /* shutdown the socket interface if necessary */
8329 init_ntproc (int dumping
)
8331 sigset_t initial_mask
= 0;
8333 /* Initialize the socket interface now if available and requested by
8334 the user by defining PRELOAD_WINSOCK; otherwise loading will be
8335 delayed until open-network-stream is called (w32-has-winsock can
8336 also be used to dynamically load or reload winsock).
8338 Conveniently, init_environment is called before us, so
8339 PRELOAD_WINSOCK can be set in the registry. */
8341 /* Always initialize this correctly. */
8344 if (getenv ("PRELOAD_WINSOCK") != NULL
)
8345 init_winsock (TRUE
);
8347 /* Initial preparation for subprocess support: replace our standard
8348 handles with non-inheritable versions. */
8351 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
8352 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
8353 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
8355 parent
= GetCurrentProcess ();
8357 /* ignore errors when duplicating and closing; typically the
8358 handles will be invalid when running as a gui program. */
8359 DuplicateHandle (parent
,
8360 GetStdHandle (STD_INPUT_HANDLE
),
8365 DUPLICATE_SAME_ACCESS
);
8367 DuplicateHandle (parent
,
8368 GetStdHandle (STD_OUTPUT_HANDLE
),
8373 DUPLICATE_SAME_ACCESS
);
8375 DuplicateHandle (parent
,
8376 GetStdHandle (STD_ERROR_HANDLE
),
8381 DUPLICATE_SAME_ACCESS
);
8387 if (stdin_save
!= INVALID_HANDLE_VALUE
)
8388 _open_osfhandle ((intptr_t) stdin_save
, O_TEXT
);
8390 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
8393 if (stdout_save
!= INVALID_HANDLE_VALUE
)
8394 _open_osfhandle ((intptr_t) stdout_save
, O_TEXT
);
8396 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
8399 if (stderr_save
!= INVALID_HANDLE_VALUE
)
8400 _open_osfhandle ((intptr_t) stderr_save
, O_TEXT
);
8402 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
8406 /* unfortunately, atexit depends on implementation of malloc */
8407 /* atexit (term_ntproc); */
8410 /* Make sure we start with all signals unblocked. */
8411 sigprocmask (SIG_SETMASK
, &initial_mask
, NULL
);
8412 signal (SIGABRT
, term_ntproc
);
8416 /* determine which drives are fixed, for GetCachedVolumeInformation */
8418 /* GetDriveType must have trailing backslash. */
8419 char drive
[] = "A:\\";
8421 /* Loop over all possible drive letters */
8422 while (*drive
<= 'Z')
8424 /* Record if this drive letter refers to a fixed drive. */
8425 fixed_drives
[DRIVE_INDEX (*drive
)] =
8426 (GetDriveType (drive
) == DRIVE_FIXED
);
8431 /* Reset the volume info cache. */
8432 volume_cache
= NULL
;
8437 shutdown_handler ensures that buffers' autosave files are
8438 up to date when the user logs off, or the system shuts down.
8441 shutdown_handler (DWORD type
)
8443 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
8444 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
8445 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
8446 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
8448 /* Shut down cleanly, making sure autosave files are up to date. */
8449 shut_down_emacs (0, Qnil
);
8452 /* Allow other handlers to handle this signal. */
8457 globals_of_w32 is used to initialize those global variables that
8458 must always be initialized on startup even when the global variable
8459 initialized is non zero (see the function main in emacs.c).
8462 globals_of_w32 (void)
8464 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
8466 get_process_times_fn
= (GetProcessTimes_Proc
)
8467 GetProcAddress (kernel32
, "GetProcessTimes");
8469 DEFSYM (QCloaded_from
, ":loaded-from");
8471 g_b_init_is_windows_9x
= 0;
8472 g_b_init_open_process_token
= 0;
8473 g_b_init_get_token_information
= 0;
8474 g_b_init_lookup_account_sid
= 0;
8475 g_b_init_get_sid_sub_authority
= 0;
8476 g_b_init_get_sid_sub_authority_count
= 0;
8477 g_b_init_get_security_info
= 0;
8478 g_b_init_get_file_security_w
= 0;
8479 g_b_init_get_file_security_a
= 0;
8480 g_b_init_get_security_descriptor_owner
= 0;
8481 g_b_init_get_security_descriptor_group
= 0;
8482 g_b_init_is_valid_sid
= 0;
8483 g_b_init_create_toolhelp32_snapshot
= 0;
8484 g_b_init_process32_first
= 0;
8485 g_b_init_process32_next
= 0;
8486 g_b_init_open_thread_token
= 0;
8487 g_b_init_impersonate_self
= 0;
8488 g_b_init_revert_to_self
= 0;
8489 g_b_init_get_process_memory_info
= 0;
8490 g_b_init_get_process_working_set_size
= 0;
8491 g_b_init_global_memory_status
= 0;
8492 g_b_init_global_memory_status_ex
= 0;
8493 g_b_init_equal_sid
= 0;
8494 g_b_init_copy_sid
= 0;
8495 g_b_init_get_length_sid
= 0;
8496 g_b_init_get_native_system_info
= 0;
8497 g_b_init_get_system_times
= 0;
8498 g_b_init_create_symbolic_link_w
= 0;
8499 g_b_init_create_symbolic_link_a
= 0;
8500 g_b_init_get_security_descriptor_dacl
= 0;
8501 g_b_init_convert_sd_to_sddl
= 0;
8502 g_b_init_convert_sddl_to_sd
= 0;
8503 g_b_init_is_valid_security_descriptor
= 0;
8504 g_b_init_set_file_security
= 0;
8505 g_b_init_get_adapters_info
= 0;
8506 num_of_processors
= 0;
8507 /* The following sets a handler for shutdown notifications for
8508 console apps. This actually applies to Emacs in both console and
8509 GUI modes, since we had to fool windows into thinking emacs is a
8510 console application to get console mode to work. */
8511 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
8513 /* "None" is the default group name on standalone workstations. */
8514 strcpy (dflt_group_name
, "None");
8516 /* Reset, in case it has some value inherited from dump time. */
8517 w32_stat_get_owner_group
= 0;
8519 /* If w32_unicode_filenames is non-zero, we will be using Unicode
8520 (a.k.a. "wide") APIs to invoke functions that accept file
8522 if (is_windows_9x ())
8523 w32_unicode_filenames
= 0;
8525 w32_unicode_filenames
= 1;
8528 /* For make-serial-process */
8530 serial_open (Lisp_Object port_obj
)
8532 char *port
= SSDATA (port_obj
);
8537 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
8538 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
8539 if (hnd
== INVALID_HANDLE_VALUE
)
8540 error ("Could not open %s", port
);
8541 fd
= (int) _open_osfhandle ((intptr_t) hnd
, 0);
8543 error ("Could not open %s", port
);
8547 error ("Could not create child process");
8549 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
8550 fd_info
[ fd
].hnd
= hnd
;
8551 fd_info
[ fd
].flags
|=
8552 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
8553 if (fd_info
[ fd
].cp
!= NULL
)
8555 error ("fd_info[fd = %d] is already in use", fd
);
8557 fd_info
[ fd
].cp
= cp
;
8558 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
8559 if (cp
->ovl_read
.hEvent
== NULL
)
8560 error ("Could not create read event");
8561 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
8562 if (cp
->ovl_write
.hEvent
== NULL
)
8563 error ("Could not create write event");
8568 /* For serial-process-configure */
8570 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
8572 Lisp_Object childp2
= Qnil
;
8573 Lisp_Object tem
= Qnil
;
8577 char summary
[4] = "???"; /* This usually becomes "8N1". */
8579 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
8580 error ("Not a serial process");
8581 hnd
= fd_info
[ p
->outfd
].hnd
;
8583 childp2
= Fcopy_sequence (p
->childp
);
8585 /* Initialize timeouts for blocking read and blocking write. */
8586 if (!GetCommTimeouts (hnd
, &ct
))
8587 error ("GetCommTimeouts() failed");
8588 ct
.ReadIntervalTimeout
= 0;
8589 ct
.ReadTotalTimeoutMultiplier
= 0;
8590 ct
.ReadTotalTimeoutConstant
= 0;
8591 ct
.WriteTotalTimeoutMultiplier
= 0;
8592 ct
.WriteTotalTimeoutConstant
= 0;
8593 if (!SetCommTimeouts (hnd
, &ct
))
8594 error ("SetCommTimeouts() failed");
8595 /* Read port attributes and prepare default configuration. */
8596 memset (&dcb
, 0, sizeof (dcb
));
8597 dcb
.DCBlength
= sizeof (DCB
);
8598 if (!GetCommState (hnd
, &dcb
))
8599 error ("GetCommState() failed");
8602 dcb
.fAbortOnError
= FALSE
;
8603 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
8608 /* Configure speed. */
8609 if (!NILP (Fplist_member (contact
, QCspeed
)))
8610 tem
= Fplist_get (contact
, QCspeed
);
8612 tem
= Fplist_get (p
->childp
, QCspeed
);
8614 dcb
.BaudRate
= XINT (tem
);
8615 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
8617 /* Configure bytesize. */
8618 if (!NILP (Fplist_member (contact
, QCbytesize
)))
8619 tem
= Fplist_get (contact
, QCbytesize
);
8621 tem
= Fplist_get (p
->childp
, QCbytesize
);
8623 tem
= make_number (8);
8625 if (XINT (tem
) != 7 && XINT (tem
) != 8)
8626 error (":bytesize must be nil (8), 7, or 8");
8627 dcb
.ByteSize
= XINT (tem
);
8628 summary
[0] = XINT (tem
) + '0';
8629 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
8631 /* Configure parity. */
8632 if (!NILP (Fplist_member (contact
, QCparity
)))
8633 tem
= Fplist_get (contact
, QCparity
);
8635 tem
= Fplist_get (p
->childp
, QCparity
);
8636 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
8637 error (":parity must be nil (no parity), `even', or `odd'");
8638 dcb
.fParity
= FALSE
;
8639 dcb
.Parity
= NOPARITY
;
8640 dcb
.fErrorChar
= FALSE
;
8645 else if (EQ (tem
, Qeven
))
8649 dcb
.Parity
= EVENPARITY
;
8650 dcb
.fErrorChar
= TRUE
;
8652 else if (EQ (tem
, Qodd
))
8656 dcb
.Parity
= ODDPARITY
;
8657 dcb
.fErrorChar
= TRUE
;
8659 childp2
= Fplist_put (childp2
, QCparity
, tem
);
8661 /* Configure stopbits. */
8662 if (!NILP (Fplist_member (contact
, QCstopbits
)))
8663 tem
= Fplist_get (contact
, QCstopbits
);
8665 tem
= Fplist_get (p
->childp
, QCstopbits
);
8667 tem
= make_number (1);
8669 if (XINT (tem
) != 1 && XINT (tem
) != 2)
8670 error (":stopbits must be nil (1 stopbit), 1, or 2");
8671 summary
[2] = XINT (tem
) + '0';
8672 if (XINT (tem
) == 1)
8673 dcb
.StopBits
= ONESTOPBIT
;
8674 else if (XINT (tem
) == 2)
8675 dcb
.StopBits
= TWOSTOPBITS
;
8676 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
8678 /* Configure flowcontrol. */
8679 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
8680 tem
= Fplist_get (contact
, QCflowcontrol
);
8682 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
8683 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
8684 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
8685 dcb
.fOutxCtsFlow
= FALSE
;
8686 dcb
.fOutxDsrFlow
= FALSE
;
8687 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
8688 dcb
.fDsrSensitivity
= FALSE
;
8689 dcb
.fTXContinueOnXoff
= FALSE
;
8692 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
8693 dcb
.XonChar
= 17; /* Control-Q */
8694 dcb
.XoffChar
= 19; /* Control-S */
8697 /* Already configured. */
8699 else if (EQ (tem
, Qhw
))
8701 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
8702 dcb
.fOutxCtsFlow
= TRUE
;
8704 else if (EQ (tem
, Qsw
))
8709 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
8711 /* Activate configuration. */
8712 if (!SetCommState (hnd
, &dcb
))
8713 error ("SetCommState() failed");
8715 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
8716 pset_childp (p
, childp2
);
8722 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
8726 struct timespec timeout
;
8727 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
8728 int fd
= process
->infd
;
8730 n
= sys_read (fd
, (char*)buf
, sz
);
8737 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8738 if (err
== EWOULDBLOCK
)
8741 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
8747 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
8749 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
8750 int fd
= process
->outfd
;
8751 ssize_t n
= sys_write (fd
, buf
, sz
);
8753 /* 0 or more bytes written means everything went fine. */
8757 /* Negative bytes written means we got an error in errno.
8758 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8759 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
8760 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
8764 #endif /* HAVE_GNUTLS */