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_w
;
303 static BOOL g_b_init_set_file_security_a
;
304 static BOOL g_b_init_get_adapters_info
;
307 BEGIN: Wrapper functions around OpenProcessToken
308 and other functions in advapi32.dll that are only
309 supported in Windows NT / 2k / XP
311 /* ** Function pointer typedefs ** */
312 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
313 HANDLE ProcessHandle
,
315 PHANDLE TokenHandle
);
316 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
318 TOKEN_INFORMATION_CLASS TokenInformationClass
,
319 LPVOID TokenInformation
,
320 DWORD TokenInformationLength
,
321 PDWORD ReturnLength
);
322 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
323 HANDLE process_handle
,
324 LPFILETIME creation_time
,
325 LPFILETIME exit_time
,
326 LPFILETIME kernel_time
,
327 LPFILETIME user_time
);
329 GetProcessTimes_Proc get_process_times_fn
= NULL
;
332 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
334 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
336 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
337 LPCTSTR lpSystemName
,
342 LPDWORD cbDomainName
,
343 PSID_NAME_USE peUse
);
344 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
347 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
349 typedef DWORD (WINAPI
* GetSecurityInfo_Proc
) (
351 SE_OBJECT_TYPE ObjectType
,
352 SECURITY_INFORMATION SecurityInfo
,
357 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
);
358 typedef BOOL (WINAPI
* GetFileSecurityW_Proc
) (
360 SECURITY_INFORMATION RequestedInformation
,
361 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
363 LPDWORD lpnLengthNeeded
);
364 typedef BOOL (WINAPI
* GetFileSecurityA_Proc
) (
366 SECURITY_INFORMATION RequestedInformation
,
367 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
369 LPDWORD lpnLengthNeeded
);
370 typedef BOOL (WINAPI
*SetFileSecurityW_Proc
) (
372 SECURITY_INFORMATION SecurityInformation
,
373 PSECURITY_DESCRIPTOR pSecurityDescriptor
);
374 typedef BOOL (WINAPI
*SetFileSecurityA_Proc
) (
376 SECURITY_INFORMATION SecurityInformation
,
377 PSECURITY_DESCRIPTOR pSecurityDescriptor
);
378 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
379 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
381 LPBOOL lpbOwnerDefaulted
);
382 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
383 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
385 LPBOOL lpbGroupDefaulted
);
386 typedef BOOL (WINAPI
*GetSecurityDescriptorDacl_Proc
) (
387 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
388 LPBOOL lpbDaclPresent
,
390 LPBOOL lpbDaclDefaulted
);
391 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
393 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
395 DWORD th32ProcessID
);
396 typedef BOOL (WINAPI
* Process32First_Proc
) (
398 LPPROCESSENTRY32 lppe
);
399 typedef BOOL (WINAPI
* Process32Next_Proc
) (
401 LPPROCESSENTRY32 lppe
);
402 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
406 PHANDLE TokenHandle
);
407 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
408 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
409 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
410 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
412 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
414 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
416 PSIZE_T lpMinimumWorkingSetSize
,
417 PSIZE_T lpMaximumWorkingSetSize
);
418 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
419 LPMEMORYSTATUS lpBuffer
);
420 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
421 LPMEMORY_STATUS_EX lpBuffer
);
422 typedef BOOL (WINAPI
* CopySid_Proc
) (
423 DWORD nDestinationSidLength
,
424 PSID pDestinationSid
,
426 typedef BOOL (WINAPI
* EqualSid_Proc
) (
429 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
431 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
432 LPSYSTEM_INFO lpSystemInfo
);
433 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
434 LPFILETIME lpIdleTime
,
435 LPFILETIME lpKernelTime
,
436 LPFILETIME lpUserTime
);
437 typedef BOOLEAN (WINAPI
*CreateSymbolicLinkW_Proc
) (
438 LPCWSTR lpSymlinkFileName
,
439 LPCWSTR lpTargetFileName
,
441 typedef BOOLEAN (WINAPI
*CreateSymbolicLinkA_Proc
) (
442 LPCSTR lpSymlinkFileName
,
443 LPCSTR lpTargetFileName
,
445 typedef BOOL (WINAPI
*ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
) (
446 LPCTSTR StringSecurityDescriptor
,
447 DWORD StringSDRevision
,
448 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
449 PULONG SecurityDescriptorSize
);
450 typedef BOOL (WINAPI
*ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
) (
451 PSECURITY_DESCRIPTOR SecurityDescriptor
,
452 DWORD RequestedStringSDRevision
,
453 SECURITY_INFORMATION SecurityInformation
,
454 LPTSTR
*StringSecurityDescriptor
,
455 PULONG StringSecurityDescriptorLen
);
456 typedef BOOL (WINAPI
*IsValidSecurityDescriptor_Proc
) (PSECURITY_DESCRIPTOR
);
457 typedef DWORD (WINAPI
*GetAdaptersInfo_Proc
) (
458 PIP_ADAPTER_INFO pAdapterInfo
,
461 /* ** A utility function ** */
465 static BOOL s_b_ret
= 0;
466 OSVERSIONINFO os_ver
;
467 if (g_b_init_is_windows_9x
== 0)
469 g_b_init_is_windows_9x
= 1;
470 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
471 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
472 if (GetVersionEx (&os_ver
))
474 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
480 static Lisp_Object
ltime (ULONGLONG
);
482 /* Get total user and system times for get-internal-run-time.
483 Returns a list of integers if the times are provided by the OS
484 (NT derivatives), otherwise it returns the result of current-time. */
486 w32_get_internal_run_time (void)
488 if (get_process_times_fn
)
490 FILETIME create
, exit
, kernel
, user
;
491 HANDLE proc
= GetCurrentProcess ();
492 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
494 LARGE_INTEGER user_int
, kernel_int
, total
;
495 user_int
.LowPart
= user
.dwLowDateTime
;
496 user_int
.HighPart
= user
.dwHighDateTime
;
497 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
498 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
499 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
500 return ltime (total
.QuadPart
);
504 return Fcurrent_time ();
507 /* ** The wrapper functions ** */
510 open_process_token (HANDLE ProcessHandle
,
514 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
515 HMODULE hm_advapi32
= NULL
;
516 if (is_windows_9x () == TRUE
)
520 if (g_b_init_open_process_token
== 0)
522 g_b_init_open_process_token
= 1;
523 hm_advapi32
= LoadLibrary ("Advapi32.dll");
524 s_pfn_Open_Process_Token
=
525 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
527 if (s_pfn_Open_Process_Token
== NULL
)
532 s_pfn_Open_Process_Token (
540 get_token_information (HANDLE TokenHandle
,
541 TOKEN_INFORMATION_CLASS TokenInformationClass
,
542 LPVOID TokenInformation
,
543 DWORD TokenInformationLength
,
546 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
547 HMODULE hm_advapi32
= NULL
;
548 if (is_windows_9x () == TRUE
)
552 if (g_b_init_get_token_information
== 0)
554 g_b_init_get_token_information
= 1;
555 hm_advapi32
= LoadLibrary ("Advapi32.dll");
556 s_pfn_Get_Token_Information
=
557 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
559 if (s_pfn_Get_Token_Information
== NULL
)
564 s_pfn_Get_Token_Information (
566 TokenInformationClass
,
568 TokenInformationLength
,
574 lookup_account_sid (LPCTSTR lpSystemName
,
579 LPDWORD cbDomainName
,
582 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
583 HMODULE hm_advapi32
= NULL
;
584 if (is_windows_9x () == TRUE
)
588 if (g_b_init_lookup_account_sid
== 0)
590 g_b_init_lookup_account_sid
= 1;
591 hm_advapi32
= LoadLibrary ("Advapi32.dll");
592 s_pfn_Lookup_Account_Sid
=
593 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
595 if (s_pfn_Lookup_Account_Sid
== NULL
)
600 s_pfn_Lookup_Account_Sid (
612 get_sid_sub_authority (PSID pSid
, DWORD n
)
614 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
615 static DWORD zero
= 0U;
616 HMODULE hm_advapi32
= NULL
;
617 if (is_windows_9x () == TRUE
)
621 if (g_b_init_get_sid_sub_authority
== 0)
623 g_b_init_get_sid_sub_authority
= 1;
624 hm_advapi32
= LoadLibrary ("Advapi32.dll");
625 s_pfn_Get_Sid_Sub_Authority
=
626 (GetSidSubAuthority_Proc
) GetProcAddress (
627 hm_advapi32
, "GetSidSubAuthority");
629 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
633 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
637 get_sid_sub_authority_count (PSID pSid
)
639 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
640 static UCHAR zero
= 0U;
641 HMODULE hm_advapi32
= NULL
;
642 if (is_windows_9x () == TRUE
)
646 if (g_b_init_get_sid_sub_authority_count
== 0)
648 g_b_init_get_sid_sub_authority_count
= 1;
649 hm_advapi32
= LoadLibrary ("Advapi32.dll");
650 s_pfn_Get_Sid_Sub_Authority_Count
=
651 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
652 hm_advapi32
, "GetSidSubAuthorityCount");
654 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
658 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
662 get_security_info (HANDLE handle
,
663 SE_OBJECT_TYPE ObjectType
,
664 SECURITY_INFORMATION SecurityInfo
,
669 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
)
671 static GetSecurityInfo_Proc s_pfn_Get_Security_Info
= NULL
;
672 HMODULE hm_advapi32
= NULL
;
673 if (is_windows_9x () == TRUE
)
677 if (g_b_init_get_security_info
== 0)
679 g_b_init_get_security_info
= 1;
680 hm_advapi32
= LoadLibrary ("Advapi32.dll");
681 s_pfn_Get_Security_Info
=
682 (GetSecurityInfo_Proc
) GetProcAddress (
683 hm_advapi32
, "GetSecurityInfo");
685 if (s_pfn_Get_Security_Info
== NULL
)
689 return (s_pfn_Get_Security_Info (handle
, ObjectType
, SecurityInfo
,
690 ppsidOwner
, ppsidGroup
, ppDacl
, ppSacl
,
691 ppSecurityDescriptor
));
694 static int filename_to_ansi (const char *, char *);
695 static int filename_to_utf16 (const char *, wchar_t *);
698 get_file_security (const char *lpFileName
,
699 SECURITY_INFORMATION RequestedInformation
,
700 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
702 LPDWORD lpnLengthNeeded
)
704 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA
= NULL
;
705 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW
= NULL
;
706 HMODULE hm_advapi32
= NULL
;
707 if (is_windows_9x () == TRUE
)
712 if (w32_unicode_filenames
)
714 wchar_t filename_w
[MAX_PATH
];
716 if (g_b_init_get_file_security_w
== 0)
718 g_b_init_get_file_security_w
= 1;
719 hm_advapi32
= LoadLibrary ("Advapi32.dll");
720 s_pfn_Get_File_SecurityW
=
721 (GetFileSecurityW_Proc
) GetProcAddress (hm_advapi32
,
724 if (s_pfn_Get_File_SecurityW
== NULL
)
729 filename_to_utf16 (lpFileName
, filename_w
);
730 return (s_pfn_Get_File_SecurityW (filename_w
, RequestedInformation
,
731 pSecurityDescriptor
, nLength
,
736 char filename_a
[MAX_PATH
];
738 if (g_b_init_get_file_security_a
== 0)
740 g_b_init_get_file_security_a
= 1;
741 hm_advapi32
= LoadLibrary ("Advapi32.dll");
742 s_pfn_Get_File_SecurityA
=
743 (GetFileSecurityA_Proc
) GetProcAddress (hm_advapi32
,
746 if (s_pfn_Get_File_SecurityA
== NULL
)
751 filename_to_ansi (lpFileName
, filename_a
);
752 return (s_pfn_Get_File_SecurityA (filename_a
, RequestedInformation
,
753 pSecurityDescriptor
, nLength
,
759 set_file_security (const char *lpFileName
,
760 SECURITY_INFORMATION SecurityInformation
,
761 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
763 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW
= NULL
;
764 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA
= NULL
;
765 HMODULE hm_advapi32
= NULL
;
766 if (is_windows_9x () == TRUE
)
771 if (w32_unicode_filenames
)
773 wchar_t filename_w
[MAX_PATH
];
775 if (g_b_init_set_file_security_w
== 0)
777 g_b_init_set_file_security_w
= 1;
778 hm_advapi32
= LoadLibrary ("Advapi32.dll");
779 s_pfn_Set_File_SecurityW
=
780 (SetFileSecurityW_Proc
) GetProcAddress (hm_advapi32
,
783 if (s_pfn_Set_File_SecurityW
== NULL
)
788 filename_to_utf16 (lpFileName
, filename_w
);
789 return (s_pfn_Set_File_SecurityW (filename_w
, SecurityInformation
,
790 pSecurityDescriptor
));
794 char filename_a
[MAX_PATH
];
796 if (g_b_init_set_file_security_a
== 0)
798 g_b_init_set_file_security_a
= 1;
799 hm_advapi32
= LoadLibrary ("Advapi32.dll");
800 s_pfn_Set_File_SecurityA
=
801 (SetFileSecurityA_Proc
) GetProcAddress (hm_advapi32
,
804 if (s_pfn_Set_File_SecurityA
== NULL
)
809 filename_to_ansi (lpFileName
, filename_a
);
810 return (s_pfn_Set_File_SecurityA (filename_a
, SecurityInformation
,
811 pSecurityDescriptor
));
816 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
818 LPBOOL lpbOwnerDefaulted
)
820 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
821 HMODULE hm_advapi32
= NULL
;
822 if (is_windows_9x () == TRUE
)
827 if (g_b_init_get_security_descriptor_owner
== 0)
829 g_b_init_get_security_descriptor_owner
= 1;
830 hm_advapi32
= LoadLibrary ("Advapi32.dll");
831 s_pfn_Get_Security_Descriptor_Owner
=
832 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
833 hm_advapi32
, "GetSecurityDescriptorOwner");
835 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
840 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
845 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
847 LPBOOL lpbGroupDefaulted
)
849 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
850 HMODULE hm_advapi32
= NULL
;
851 if (is_windows_9x () == TRUE
)
856 if (g_b_init_get_security_descriptor_group
== 0)
858 g_b_init_get_security_descriptor_group
= 1;
859 hm_advapi32
= LoadLibrary ("Advapi32.dll");
860 s_pfn_Get_Security_Descriptor_Group
=
861 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
862 hm_advapi32
, "GetSecurityDescriptorGroup");
864 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
869 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
874 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
875 LPBOOL lpbDaclPresent
,
877 LPBOOL lpbDaclDefaulted
)
879 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl
= NULL
;
880 HMODULE hm_advapi32
= NULL
;
881 if (is_windows_9x () == TRUE
)
886 if (g_b_init_get_security_descriptor_dacl
== 0)
888 g_b_init_get_security_descriptor_dacl
= 1;
889 hm_advapi32
= LoadLibrary ("Advapi32.dll");
890 s_pfn_Get_Security_Descriptor_Dacl
=
891 (GetSecurityDescriptorDacl_Proc
) GetProcAddress (
892 hm_advapi32
, "GetSecurityDescriptorDacl");
894 if (s_pfn_Get_Security_Descriptor_Dacl
== NULL
)
899 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor
,
900 lpbDaclPresent
, pDacl
,
905 is_valid_sid (PSID sid
)
907 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
908 HMODULE hm_advapi32
= NULL
;
909 if (is_windows_9x () == TRUE
)
913 if (g_b_init_is_valid_sid
== 0)
915 g_b_init_is_valid_sid
= 1;
916 hm_advapi32
= LoadLibrary ("Advapi32.dll");
918 (IsValidSid_Proc
) GetProcAddress (
919 hm_advapi32
, "IsValidSid");
921 if (s_pfn_Is_Valid_Sid
== NULL
)
925 return (s_pfn_Is_Valid_Sid (sid
));
929 equal_sid (PSID sid1
, PSID sid2
)
931 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
932 HMODULE hm_advapi32
= NULL
;
933 if (is_windows_9x () == TRUE
)
937 if (g_b_init_equal_sid
== 0)
939 g_b_init_equal_sid
= 1;
940 hm_advapi32
= LoadLibrary ("Advapi32.dll");
942 (EqualSid_Proc
) GetProcAddress (
943 hm_advapi32
, "EqualSid");
945 if (s_pfn_Equal_Sid
== NULL
)
949 return (s_pfn_Equal_Sid (sid1
, sid2
));
953 get_length_sid (PSID sid
)
955 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
956 HMODULE hm_advapi32
= NULL
;
957 if (is_windows_9x () == TRUE
)
961 if (g_b_init_get_length_sid
== 0)
963 g_b_init_get_length_sid
= 1;
964 hm_advapi32
= LoadLibrary ("Advapi32.dll");
965 s_pfn_Get_Length_Sid
=
966 (GetLengthSid_Proc
) GetProcAddress (
967 hm_advapi32
, "GetLengthSid");
969 if (s_pfn_Get_Length_Sid
== NULL
)
973 return (s_pfn_Get_Length_Sid (sid
));
977 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
979 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
980 HMODULE hm_advapi32
= NULL
;
981 if (is_windows_9x () == TRUE
)
985 if (g_b_init_copy_sid
== 0)
987 g_b_init_copy_sid
= 1;
988 hm_advapi32
= LoadLibrary ("Advapi32.dll");
990 (CopySid_Proc
) GetProcAddress (
991 hm_advapi32
, "CopySid");
993 if (s_pfn_Copy_Sid
== NULL
)
997 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
1001 END: Wrapper functions around OpenProcessToken
1002 and other functions in advapi32.dll that are only
1003 supported in Windows NT / 2k / XP
1007 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
1009 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
1010 if (is_windows_9x () != TRUE
)
1012 if (g_b_init_get_native_system_info
== 0)
1014 g_b_init_get_native_system_info
= 1;
1015 s_pfn_Get_Native_System_Info
=
1016 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1017 "GetNativeSystemInfo");
1019 if (s_pfn_Get_Native_System_Info
!= NULL
)
1020 s_pfn_Get_Native_System_Info (lpSystemInfo
);
1023 lpSystemInfo
->dwNumberOfProcessors
= -1;
1027 get_system_times (LPFILETIME lpIdleTime
,
1028 LPFILETIME lpKernelTime
,
1029 LPFILETIME lpUserTime
)
1031 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
1032 if (is_windows_9x () == TRUE
)
1036 if (g_b_init_get_system_times
== 0)
1038 g_b_init_get_system_times
= 1;
1039 s_pfn_Get_System_times
=
1040 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1043 if (s_pfn_Get_System_times
== NULL
)
1045 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
1048 static BOOLEAN WINAPI
1049 create_symbolic_link (LPCSTR lpSymlinkFilename
,
1050 LPCSTR lpTargetFileName
,
1053 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW
= NULL
;
1054 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA
= NULL
;
1057 if (is_windows_9x () == TRUE
)
1062 if (w32_unicode_filenames
)
1064 wchar_t symfn_w
[MAX_PATH
], tgtfn_w
[MAX_PATH
];
1066 if (g_b_init_create_symbolic_link_w
== 0)
1068 g_b_init_create_symbolic_link_w
= 1;
1069 s_pfn_Create_Symbolic_LinkW
=
1070 (CreateSymbolicLinkW_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1071 "CreateSymbolicLinkW");
1073 if (s_pfn_Create_Symbolic_LinkW
== NULL
)
1079 filename_to_utf16 (lpSymlinkFilename
, symfn_w
);
1080 filename_to_utf16 (lpTargetFileName
, tgtfn_w
);
1081 retval
= s_pfn_Create_Symbolic_LinkW (symfn_w
, tgtfn_w
, dwFlags
);
1082 /* If we were denied creation of the symlink, try again after
1083 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1086 TOKEN_PRIVILEGES priv_current
;
1088 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME
, TRUE
,
1091 retval
= s_pfn_Create_Symbolic_LinkW (symfn_w
, tgtfn_w
, dwFlags
);
1092 restore_privilege (&priv_current
);
1099 char symfn_a
[MAX_PATH
], tgtfn_a
[MAX_PATH
];
1101 if (g_b_init_create_symbolic_link_a
== 0)
1103 g_b_init_create_symbolic_link_a
= 1;
1104 s_pfn_Create_Symbolic_LinkA
=
1105 (CreateSymbolicLinkA_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1106 "CreateSymbolicLinkA");
1108 if (s_pfn_Create_Symbolic_LinkA
== NULL
)
1114 filename_to_ansi (lpSymlinkFilename
, symfn_a
);
1115 filename_to_ansi (lpTargetFileName
, tgtfn_a
);
1116 retval
= s_pfn_Create_Symbolic_LinkA (symfn_a
, tgtfn_a
, dwFlags
);
1117 /* If we were denied creation of the symlink, try again after
1118 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1121 TOKEN_PRIVILEGES priv_current
;
1123 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME
, TRUE
,
1126 retval
= s_pfn_Create_Symbolic_LinkA (symfn_a
, tgtfn_a
, dwFlags
);
1127 restore_privilege (&priv_current
);
1136 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor
)
1138 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc
= NULL
;
1140 if (is_windows_9x () == TRUE
)
1146 if (g_b_init_is_valid_security_descriptor
== 0)
1148 g_b_init_is_valid_security_descriptor
= 1;
1149 s_pfn_Is_Valid_Security_Descriptor_Proc
=
1150 (IsValidSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1151 "IsValidSecurityDescriptor");
1153 if (s_pfn_Is_Valid_Security_Descriptor_Proc
== NULL
)
1159 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor
);
1163 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor
,
1164 DWORD RequestedStringSDRevision
,
1165 SECURITY_INFORMATION SecurityInformation
,
1166 LPTSTR
*StringSecurityDescriptor
,
1167 PULONG StringSecurityDescriptorLen
)
1169 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL
= NULL
;
1172 if (is_windows_9x () == TRUE
)
1178 if (g_b_init_convert_sd_to_sddl
== 0)
1180 g_b_init_convert_sd_to_sddl
= 1;
1182 s_pfn_Convert_SD_To_SDDL
=
1183 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1184 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1186 s_pfn_Convert_SD_To_SDDL
=
1187 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1188 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1191 if (s_pfn_Convert_SD_To_SDDL
== NULL
)
1197 retval
= s_pfn_Convert_SD_To_SDDL (SecurityDescriptor
,
1198 RequestedStringSDRevision
,
1199 SecurityInformation
,
1200 StringSecurityDescriptor
,
1201 StringSecurityDescriptorLen
);
1207 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor
,
1208 DWORD StringSDRevision
,
1209 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
1210 PULONG SecurityDescriptorSize
)
1212 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD
= NULL
;
1215 if (is_windows_9x () == TRUE
)
1221 if (g_b_init_convert_sddl_to_sd
== 0)
1223 g_b_init_convert_sddl_to_sd
= 1;
1225 s_pfn_Convert_SDDL_To_SD
=
1226 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1227 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1229 s_pfn_Convert_SDDL_To_SD
=
1230 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1231 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1234 if (s_pfn_Convert_SDDL_To_SD
== NULL
)
1240 retval
= s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor
,
1243 SecurityDescriptorSize
);
1249 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo
, PULONG pOutBufLen
)
1251 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info
= NULL
;
1252 HMODULE hm_iphlpapi
= NULL
;
1254 if (is_windows_9x () == TRUE
)
1255 return ERROR_NOT_SUPPORTED
;
1257 if (g_b_init_get_adapters_info
== 0)
1259 g_b_init_get_adapters_info
= 1;
1260 hm_iphlpapi
= LoadLibrary ("Iphlpapi.dll");
1262 s_pfn_Get_Adapters_Info
= (GetAdaptersInfo_Proc
)
1263 GetProcAddress (hm_iphlpapi
, "GetAdaptersInfo");
1265 if (s_pfn_Get_Adapters_Info
== NULL
)
1266 return ERROR_NOT_SUPPORTED
;
1267 return s_pfn_Get_Adapters_Info (pAdapterInfo
, pOutBufLen
);
1272 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1273 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1275 This is called from alloc.c:valid_pointer_p. */
1277 w32_valid_pointer_p (void *p
, int size
)
1280 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
1284 unsigned char *buf
= alloca (size
);
1285 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
1296 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1297 codepage defined by file-name-coding-system. */
1299 /* Current codepage for encoding file names. */
1300 static int file_name_codepage
;
1302 /* Produce a Windows ANSI codepage suitable for encoding file names.
1303 Return the information about that codepage in CP_INFO. */
1305 codepage_for_filenames (CPINFO
*cp_info
)
1307 /* A simple cache to avoid calling GetCPInfo every time we need to
1308 encode/decode a file name. The file-name encoding is not
1309 supposed to be changed too frequently, if ever. */
1310 static Lisp_Object last_file_name_encoding
;
1312 Lisp_Object current_encoding
;
1314 current_encoding
= Vfile_name_coding_system
;
1315 if (NILP (current_encoding
))
1316 current_encoding
= Vdefault_file_name_coding_system
;
1318 if (!EQ (last_file_name_encoding
, current_encoding
))
1320 /* Default to the current ANSI codepage. */
1321 file_name_codepage
= w32_ansi_code_page
;
1323 if (NILP (current_encoding
))
1325 char *cpname
= SDATA (SYMBOL_NAME (current_encoding
));
1326 char *cp
= NULL
, *end
;
1329 if (strncmp (cpname
, "cp", 2) == 0)
1331 else if (strncmp (cpname
, "windows-", 8) == 0)
1337 cpnum
= strtol (cp
, &end
, 10);
1338 if (cpnum
&& *end
== '\0' && end
- cp
>= 2)
1339 file_name_codepage
= cpnum
;
1343 if (!file_name_codepage
)
1344 file_name_codepage
= CP_ACP
; /* CP_ACP = 0, but let's not assume that */
1346 if (!GetCPInfo (file_name_codepage
, &cp
))
1348 file_name_codepage
= CP_ACP
;
1349 if (!GetCPInfo (file_name_codepage
, &cp
))
1356 return file_name_codepage
;
1360 filename_to_utf16 (const char *fn_in
, wchar_t *fn_out
)
1362 int result
= MultiByteToWideChar (CP_UTF8
, MB_ERR_INVALID_CHARS
, fn_in
, -1,
1367 DWORD err
= GetLastError ();
1371 case ERROR_INVALID_FLAGS
:
1372 case ERROR_INVALID_PARAMETER
:
1375 case ERROR_INSUFFICIENT_BUFFER
:
1376 case ERROR_NO_UNICODE_TRANSLATION
:
1387 filename_from_utf16 (const wchar_t *fn_in
, char *fn_out
)
1389 int result
= WideCharToMultiByte (CP_UTF8
, 0, fn_in
, -1,
1390 fn_out
, MAX_UTF8_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
:
1414 filename_to_ansi (const char *fn_in
, char *fn_out
)
1416 wchar_t fn_utf16
[MAX_PATH
];
1418 if (filename_to_utf16 (fn_in
, fn_utf16
) == 0)
1421 int codepage
= codepage_for_filenames (NULL
);
1423 result
= WideCharToMultiByte (codepage
, 0, fn_utf16
, -1,
1424 fn_out
, MAX_PATH
, NULL
, NULL
);
1427 DWORD err
= GetLastError ();
1431 case ERROR_INVALID_FLAGS
:
1432 case ERROR_INVALID_PARAMETER
:
1435 case ERROR_INSUFFICIENT_BUFFER
:
1436 case ERROR_NO_UNICODE_TRANSLATION
:
1449 filename_from_ansi (const char *fn_in
, char *fn_out
)
1451 wchar_t fn_utf16
[MAX_PATH
];
1452 int codepage
= codepage_for_filenames (NULL
);
1453 int result
= MultiByteToWideChar (codepage
, MB_ERR_INVALID_CHARS
, fn_in
, -1,
1454 fn_utf16
, MAX_PATH
);
1458 DWORD err
= GetLastError ();
1462 case ERROR_INVALID_FLAGS
:
1463 case ERROR_INVALID_PARAMETER
:
1466 case ERROR_INSUFFICIENT_BUFFER
:
1467 case ERROR_NO_UNICODE_TRANSLATION
:
1474 return filename_from_utf16 (fn_utf16
, fn_out
);
1479 /* The directory where we started, in UTF-8. */
1480 static char startup_dir
[MAX_UTF8_PATH
];
1482 /* Get the current working directory. */
1484 getcwd (char *dir
, int dirsize
)
1491 if (dirsize
<= strlen (startup_dir
))
1497 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
1501 /* Emacs doesn't actually change directory itself, it stays in the
1502 same directory where it was started. */
1503 strcpy (dir
, startup_dir
);
1508 /* Emulate getloadavg. */
1510 struct load_sample
{
1517 /* Number of processors on this machine. */
1518 static unsigned num_of_processors
;
1520 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1521 static struct load_sample samples
[16*60];
1522 static int first_idx
= -1, last_idx
= -1;
1523 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
1528 int next_idx
= from
+ 1;
1530 if (next_idx
>= max_idx
)
1539 int prev_idx
= from
- 1;
1542 prev_idx
= max_idx
- 1;
1548 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
1550 SYSTEM_INFO sysinfo
;
1551 FILETIME ft_idle
, ft_user
, ft_kernel
;
1553 /* Initialize the number of processors on this machine. */
1554 if (num_of_processors
<= 0)
1556 get_native_system_info (&sysinfo
);
1557 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1558 if (num_of_processors
<= 0)
1560 GetSystemInfo (&sysinfo
);
1561 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1563 if (num_of_processors
<= 0)
1564 num_of_processors
= 1;
1567 /* TODO: Take into account threads that are ready to run, by
1568 sampling the "\System\Processor Queue Length" performance
1569 counter. The code below accounts only for threads that are
1570 actually running. */
1572 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
1574 ULARGE_INTEGER uidle
, ukernel
, uuser
;
1576 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
1577 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
1578 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
1579 *idle
= uidle
.QuadPart
;
1580 *kernel
= ukernel
.QuadPart
;
1581 *user
= uuser
.QuadPart
;
1591 /* Produce the load average for a given time interval, using the
1592 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1593 1-minute, 5-minute, or 15-minute average, respectively. */
1597 double retval
= -1.0;
1600 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
1601 time_t now
= samples
[last_idx
].sample_time
;
1603 if (first_idx
!= last_idx
)
1605 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
1607 tdiff
= difftime (now
, samples
[idx
].sample_time
);
1608 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
1611 samples
[last_idx
].kernel
+ samples
[last_idx
].user
1612 - (samples
[idx
].kernel
+ samples
[idx
].user
);
1613 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
1615 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
1618 if (idx
== first_idx
)
1627 getloadavg (double loadavg
[], int nelem
)
1630 ULONGLONG idle
, kernel
, user
;
1631 time_t now
= time (NULL
);
1633 /* Store another sample. We ignore samples that are less than 1 sec
1635 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
1637 sample_system_load (&idle
, &kernel
, &user
);
1638 last_idx
= buf_next (last_idx
);
1639 samples
[last_idx
].sample_time
= now
;
1640 samples
[last_idx
].idle
= idle
;
1641 samples
[last_idx
].kernel
= kernel
;
1642 samples
[last_idx
].user
= user
;
1643 /* If the buffer has more that 15 min worth of samples, discard
1645 if (first_idx
== -1)
1646 first_idx
= last_idx
;
1647 while (first_idx
!= last_idx
1648 && (difftime (now
, samples
[first_idx
].sample_time
)
1649 >= 15.0*60 + 2*DBL_EPSILON
*now
))
1650 first_idx
= buf_next (first_idx
);
1653 for (elem
= 0; elem
< nelem
; elem
++)
1655 double avg
= getavg (elem
);
1659 loadavg
[elem
] = avg
;
1665 /* Emulate getpwuid, getpwnam and others. */
1667 #define PASSWD_FIELD_SIZE 256
1669 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1670 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1671 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1672 static char dflt_passwd_dir
[MAX_UTF8_PATH
];
1673 static char dflt_passwd_shell
[MAX_UTF8_PATH
];
1675 static struct passwd dflt_passwd
=
1687 static char dflt_group_name
[GNLEN
+1];
1689 static struct group dflt_group
=
1691 /* When group information is not available, we return this as the
1692 group for all files. */
1700 return dflt_passwd
.pw_uid
;
1706 /* I could imagine arguing for checking to see whether the user is
1707 in the Administrators group and returning a UID of 0 for that
1708 case, but I don't know how wise that would be in the long run. */
1715 return dflt_passwd
.pw_gid
;
1725 getpwuid (unsigned uid
)
1727 if (uid
== dflt_passwd
.pw_uid
)
1728 return &dflt_passwd
;
1733 getgrgid (gid_t gid
)
1739 getpwnam (char *name
)
1743 pw
= getpwuid (getuid ());
1747 if (xstrcasecmp (name
, pw
->pw_name
))
1754 init_user_info (void)
1756 /* Find the user's real name by opening the process token and
1757 looking up the name associated with the user-sid in that token.
1759 Use the relative portion of the identifier authority value from
1760 the user-sid as the user id value (same for group id using the
1761 primary group sid from the process token). */
1763 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1764 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1765 DWORD glength
= sizeof (gname
);
1766 HANDLE token
= NULL
;
1767 SID_NAME_USE user_type
;
1768 unsigned char *buf
= NULL
;
1770 TOKEN_USER user_token
;
1771 TOKEN_PRIMARY_GROUP group_token
;
1774 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1777 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1778 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1780 buf
= xmalloc (blen
);
1781 result
= get_token_information (token
, TokenUser
,
1782 (LPVOID
)buf
, blen
, &needed
);
1785 memcpy (&user_token
, buf
, sizeof (user_token
));
1786 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1788 domain
, &dlength
, &user_type
);
1796 strcpy (dflt_passwd
.pw_name
, uname
);
1797 /* Determine a reasonable uid value. */
1798 if (xstrcasecmp ("administrator", uname
) == 0)
1800 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1801 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1805 /* Use the last sub-authority value of the RID, the relative
1806 portion of the SID, as user/group ID. */
1807 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1809 /* Get group id and name. */
1810 result
= get_token_information (token
, TokenPrimaryGroup
,
1811 (LPVOID
)buf
, blen
, &needed
);
1812 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1814 buf
= xrealloc (buf
, blen
= needed
);
1815 result
= get_token_information (token
, TokenPrimaryGroup
,
1816 (LPVOID
)buf
, blen
, &needed
);
1820 memcpy (&group_token
, buf
, sizeof (group_token
));
1821 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1822 dlength
= sizeof (domain
);
1823 /* If we can get at the real Primary Group name, use that.
1824 Otherwise, the default group name was already set to
1825 "None" in globals_of_w32. */
1826 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1827 gname
, &glength
, NULL
, &dlength
,
1829 strcpy (dflt_group_name
, gname
);
1832 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1835 /* If security calls are not supported (presumably because we
1836 are running under Windows 9X), fallback to this: */
1837 else if (GetUserName (uname
, &ulength
))
1839 strcpy (dflt_passwd
.pw_name
, uname
);
1840 if (xstrcasecmp ("administrator", uname
) == 0)
1841 dflt_passwd
.pw_uid
= 0;
1843 dflt_passwd
.pw_uid
= 123;
1844 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1848 strcpy (dflt_passwd
.pw_name
, "unknown");
1849 dflt_passwd
.pw_uid
= 123;
1850 dflt_passwd
.pw_gid
= 123;
1852 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1854 /* Set dir and shell from environment variables. */
1855 if (w32_unicode_filenames
)
1857 wchar_t *home
= _wgetenv (L
"HOME");
1858 wchar_t *shell
= _wgetenv (L
"SHELL");
1860 /* Ensure HOME and SHELL are defined. */
1865 filename_from_utf16 (home
, dflt_passwd
.pw_dir
);
1866 filename_from_utf16 (shell
, dflt_passwd
.pw_shell
);
1870 char *home
= getenv ("HOME");
1871 char *shell
= getenv ("SHELL");
1877 filename_from_ansi (home
, dflt_passwd
.pw_dir
);
1878 filename_from_ansi (shell
, dflt_passwd
.pw_shell
);
1883 CloseHandle (token
);
1889 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1890 return ((rand () << 15) | rand ());
1899 /* Return the maximum length in bytes of a multibyte character
1900 sequence encoded in the current ANSI codepage. This is required to
1901 correctly walk the encoded file names one character at a time. */
1903 max_filename_mbslen (void)
1907 codepage_for_filenames (&cp_info
);
1908 return cp_info
.MaxCharSize
;
1911 /* Normalize filename by converting in-place all of its path
1912 separators to the separator specified by PATH_SEP. */
1915 normalize_filename (register char *fp
, char path_sep
)
1919 /* Always lower-case drive letters a-z, even if the filesystem
1920 preserves case in filenames.
1921 This is so filenames can be compared by string comparison
1922 functions that are case-sensitive. Even case-preserving filesystems
1923 do not distinguish case in drive letters. */
1926 if (*p2
== ':' && *fp
>= 'A' && *fp
<= 'Z')
1934 if (*fp
== '/' || *fp
== '\\')
1940 /* Destructively turn backslashes into slashes. */
1942 dostounix_filename (register char *p
)
1944 normalize_filename (p
, '/');
1947 /* Destructively turn slashes into backslashes. */
1949 unixtodos_filename (register char *p
)
1951 normalize_filename (p
, '\\');
1954 /* Remove all CR's that are followed by a LF.
1955 (From msdos.c...probably should figure out a way to share it,
1956 although this code isn't going to ever change.) */
1958 crlf_to_lf (register int n
, register unsigned char *buf
)
1960 unsigned char *np
= buf
;
1961 unsigned char *startp
= buf
;
1962 unsigned char *endp
= buf
+ n
;
1966 while (buf
< endp
- 1)
1970 if (*(++buf
) != 0x0a)
1981 /* Parse the root part of file name, if present. Return length and
1982 optionally store pointer to char after root. */
1984 parse_root (const char * name
, const char ** pPath
)
1986 const char * start
= name
;
1991 /* find the root name of the volume if given */
1992 if (isalpha (name
[0]) && name
[1] == ':')
1994 /* skip past drive specifier */
1996 if (IS_DIRECTORY_SEP (name
[0]))
1999 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2006 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2011 if (IS_DIRECTORY_SEP (name
[0]))
2018 return name
- start
;
2021 /* Get long base name for name; name is assumed to be absolute. */
2023 get_long_basename (char * name
, char * buf
, int size
)
2026 char fname_utf8
[MAX_UTF8_PATH
];
2030 /* Must be valid filename, no wild cards or other invalid characters. */
2031 if (strpbrk (name
, "*?|<>\""))
2034 if (w32_unicode_filenames
)
2036 wchar_t fname_utf16
[MAX_PATH
];
2037 WIN32_FIND_DATAW find_data_wide
;
2039 filename_to_utf16 (name
, fname_utf16
);
2040 dir_handle
= FindFirstFileW (fname_utf16
, &find_data_wide
);
2041 if (dir_handle
!= INVALID_HANDLE_VALUE
)
2042 cstatus
= filename_from_utf16 (find_data_wide
.cFileName
, fname_utf8
);
2046 char fname_ansi
[MAX_PATH
];
2047 WIN32_FIND_DATAA find_data_ansi
;
2049 filename_to_ansi (name
, fname_ansi
);
2050 dir_handle
= FindFirstFileA (fname_ansi
, &find_data_ansi
);
2051 if (dir_handle
!= INVALID_HANDLE_VALUE
)
2052 cstatus
= filename_from_ansi (find_data_ansi
.cFileName
, fname_utf8
);
2055 if (cstatus
== 0 && (len
= strlen (fname_utf8
)) < size
)
2056 memcpy (buf
, fname_utf8
, len
+ 1);
2060 if (dir_handle
!= INVALID_HANDLE_VALUE
)
2061 FindClose (dir_handle
);
2066 /* Get long name for file, if possible (assumed to be absolute). */
2068 w32_get_long_filename (char * name
, char * buf
, int size
)
2073 char full
[ MAX_UTF8_PATH
];
2076 len
= strlen (name
);
2077 if (len
>= MAX_UTF8_PATH
)
2080 /* Use local copy for destructive modification. */
2081 memcpy (full
, name
, len
+1);
2082 unixtodos_filename (full
);
2084 /* Copy root part verbatim. */
2085 len
= parse_root (full
, (const char **)&p
);
2086 memcpy (o
, full
, len
);
2091 while (p
!= NULL
&& *p
)
2094 p
= strchr (q
, '\\');
2096 len
= get_long_basename (full
, o
, size
);
2119 w32_get_short_filename (char * name
, char * buf
, int size
)
2121 if (w32_unicode_filenames
)
2123 wchar_t name_utf16
[MAX_PATH
], short_name
[MAX_PATH
];
2124 unsigned int retval
;
2126 filename_to_utf16 (name
, name_utf16
);
2127 retval
= GetShortPathNameW (name_utf16
, short_name
, size
);
2128 if (retval
&& retval
< size
)
2129 filename_from_utf16 (short_name
, buf
);
2134 char name_ansi
[MAX_PATH
];
2136 filename_to_ansi (name
, name_ansi
);
2137 return GetShortPathNameA (name_ansi
, buf
, size
);
2142 is_unc_volume (const char *filename
)
2144 const char *ptr
= filename
;
2146 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
2149 if (strpbrk (ptr
+ 2, "*?|<>\"\\/"))
2155 /* Emulate the Posix unsetenv. */
2157 unsetenv (const char *name
)
2163 if (name
== NULL
|| *name
== '\0' || strchr (name
, '=') != NULL
)
2168 name_len
= strlen (name
);
2169 /* MS docs says an environment variable cannot be longer than 32K. */
2170 if (name_len
> 32767)
2175 /* It is safe to use 'alloca' with 32K size, since the stack is at
2176 least 2MB, and we set it to 8MB in the link command line. */
2177 var
= alloca (name_len
+ 2);
2178 strncpy (var
, name
, name_len
);
2179 var
[name_len
++] = '=';
2180 var
[name_len
] = '\0';
2181 return _putenv (var
);
2184 /* MS _putenv doesn't support removing a variable when the argument
2185 does not include the '=' character, so we fix that here. */
2187 sys_putenv (char *str
)
2189 const char *const name_end
= strchr (str
, '=');
2191 if (name_end
== NULL
)
2193 /* Remove the variable from the environment. */
2194 return unsetenv (str
);
2197 return _putenv (str
);
2200 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2203 w32_get_resource (char *key
, LPDWORD lpdwtype
)
2206 HKEY hrootkey
= NULL
;
2209 /* Check both the current user and the local machine to see if
2210 we have any resources. */
2212 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
2216 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
2217 && (lpvalue
= xmalloc (cbData
)) != NULL
2218 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
2220 RegCloseKey (hrootkey
);
2226 RegCloseKey (hrootkey
);
2229 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
2233 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
2234 && (lpvalue
= xmalloc (cbData
)) != NULL
2235 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
2237 RegCloseKey (hrootkey
);
2243 RegCloseKey (hrootkey
);
2250 init_environment (char ** argv
)
2252 static const char * const tempdirs
[] = {
2253 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2258 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
2260 /* Implementation note: This function explicitly works with ANSI
2261 file names, not with UTF-8 encoded file names. This is because
2262 this function pushes variables into the Emacs's environment, and
2263 the environment variables are always assumed to be in the
2264 locale-specific encoding. Do NOT call any functions that accept
2265 UTF-8 file names from this function! */
2267 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2268 temporary files and assume "/tmp" if $TMPDIR is unset, which
2269 will break on DOS/Windows. Refuse to work if we cannot find
2270 a directory, not even "c:/", usable for that purpose. */
2271 for (i
= 0; i
< imax
; i
++)
2273 const char *tmp
= tempdirs
[i
];
2276 tmp
= getenv (tmp
+ 1);
2277 /* Note that `access' can lie to us if the directory resides on a
2278 read-only filesystem, like CD-ROM or a write-protected floppy.
2279 The only way to be really sure is to actually create a file and
2280 see if it succeeds. But I think that's too much to ask. */
2282 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2283 if (tmp
&& sys_access (tmp
, D_OK
) == 0)
2285 char * var
= alloca (strlen (tmp
) + 8);
2286 sprintf (var
, "TMPDIR=%s", tmp
);
2287 _putenv (strdup (var
));
2294 Fcons (build_string ("no usable temporary directories found!!"),
2296 "While setting TMPDIR: ");
2298 /* Check for environment variables and use registry settings if they
2299 don't exist. Fallback on default values where applicable. */
2304 char locale_name
[32];
2305 char default_home
[MAX_PATH
];
2308 static const struct env_entry
2314 /* If the default value is NULL, we will use the value from the
2315 outside environment or the Registry, but will not push the
2316 variable into the Emacs environment if it is defined neither
2317 in the Registry nor in the outside environment. */
2319 {"PRELOAD_WINSOCK", NULL
},
2320 {"emacs_dir", "C:/emacs"},
2321 {"EMACSLOADPATH", NULL
},
2322 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2323 {"EMACSDATA", NULL
},
2324 {"EMACSPATH", NULL
},
2331 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2333 /* We need to copy dflt_envvars[] and work on the copy because we
2334 don't want the dumped Emacs to inherit the values of
2335 environment variables we saw during dumping (which could be on
2336 a different system). The defaults above must be left intact. */
2337 struct env_entry env_vars
[N_ENV_VARS
];
2339 for (i
= 0; i
< N_ENV_VARS
; i
++)
2340 env_vars
[i
] = dflt_envvars
[i
];
2342 /* For backwards compatibility, check if a .emacs file exists in C:/
2343 If not, then we can try to default to the appdata directory under the
2344 user's profile, which is more likely to be writable. */
2345 if (sys_access ("C:/.emacs", F_OK
) != 0)
2347 HRESULT profile_result
;
2348 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2349 of Windows 95 and NT4 that have not been updated to include
2351 ShGetFolderPath_fn get_folder_path
;
2352 get_folder_path
= (ShGetFolderPath_fn
)
2353 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2355 if (get_folder_path
!= NULL
)
2357 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
2360 /* If we can't get the appdata dir, revert to old behavior. */
2361 if (profile_result
== S_OK
)
2363 env_vars
[0].def_value
= default_home
;
2369 /* Get default locale info and use it for LANG. */
2370 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
2371 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
2372 locale_name
, sizeof (locale_name
)))
2374 for (i
= 0; i
< N_ENV_VARS
; i
++)
2376 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
2378 env_vars
[i
].def_value
= locale_name
;
2384 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2386 /* Treat emacs_dir specially: set it unconditionally based on our
2390 char modname
[MAX_PATH
];
2392 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2394 if ((p
= _mbsrchr (modname
, '\\')) == NULL
)
2398 if ((p
= _mbsrchr (modname
, '\\'))
2399 /* From bin means installed Emacs, from src means uninstalled. */
2400 && (xstrcasecmp (p
, "\\bin") == 0 || xstrcasecmp (p
, "\\src") == 0))
2402 char buf
[SET_ENV_BUF_SIZE
];
2403 int within_build_tree
= xstrcasecmp (p
, "\\src") == 0;
2406 for (p
= modname
; *p
; p
= CharNext (p
))
2407 if (*p
== '\\') *p
= '/';
2409 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
2410 _putenv (strdup (buf
));
2411 /* If we are running from the Posix-like build tree, define
2412 SHELL to point to our own cmdproxy. The loop below will
2413 then disregard PATH_EXEC and the default value. */
2414 if (within_build_tree
)
2416 _snprintf (buf
, sizeof (buf
) - 1,
2417 "SHELL=%s/nt/cmdproxy.exe", modname
);
2418 _putenv (strdup (buf
));
2423 for (i
= 0; i
< N_ENV_VARS
; i
++)
2425 if (!getenv (env_vars
[i
].name
))
2428 char bufc
[SET_ENV_BUF_SIZE
];
2430 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
2431 /* Also ignore empty environment variables. */
2436 if (strcmp (env_vars
[i
].name
, "SHELL") == 0)
2438 /* Look for cmdproxy.exe in every directory in
2439 PATH_EXEC. FIXME: This does not find cmdproxy
2440 in nt/ when we run uninstalled. */
2441 char fname
[MAX_PATH
];
2442 const char *pstart
= PATH_EXEC
, *pend
;
2445 pend
= _mbschr (pstart
, ';');
2447 pend
= pstart
+ strlen (pstart
);
2448 /* Be defensive against series of ;;; characters. */
2451 strncpy (fname
, pstart
, pend
- pstart
);
2452 fname
[pend
- pstart
] = '/';
2453 strcpy (&fname
[pend
- pstart
+ 1], "cmdproxy.exe");
2454 ExpandEnvironmentStrings ((LPSTR
) fname
, bufc
,
2456 if (sys_access (bufc
, F_OK
) == 0)
2469 /* If not found in any directory, use the
2470 default as the last resort. */
2471 lpval
= env_vars
[i
].def_value
;
2472 dwType
= REG_EXPAND_SZ
;
2478 lpval
= env_vars
[i
].def_value
;
2479 dwType
= REG_EXPAND_SZ
;
2481 if (strcmp (env_vars
[i
].name
, "HOME") == 0 && !appdata
)
2482 Vdelayed_warnings_list
2483 = Fcons (listn (CONSTYPE_HEAP
, 2,
2484 intern ("initialization"),
2485 build_string ("Setting HOME to C:\\ by default is deprecated")),
2486 Vdelayed_warnings_list
);
2491 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
2493 if (dwType
== REG_EXPAND_SZ
)
2494 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
2495 else if (dwType
== REG_SZ
)
2496 strcpy (buf1
, lpval
);
2497 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
2499 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
2501 _putenv (strdup (buf2
));
2511 /* Rebuild system configuration to reflect invoking system. */
2512 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
2514 /* Another special case: on NT, the PATH variable is actually named
2515 "Path" although cmd.exe (perhaps NT itself) arranges for
2516 environment variable lookup and setting to be case insensitive.
2517 However, Emacs assumes a fully case sensitive environment, so we
2518 need to change "Path" to "PATH" to match the expectations of
2519 various elisp packages. We do this by the sneaky method of
2520 modifying the string in the C runtime environ entry.
2522 The same applies to COMSPEC. */
2526 for (envp
= environ
; *envp
; envp
++)
2527 if (_strnicmp (*envp
, "PATH=", 5) == 0)
2528 memcpy (*envp
, "PATH=", 5);
2529 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
2530 memcpy (*envp
, "COMSPEC=", 8);
2533 /* Remember the initial working directory for getcwd. */
2534 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2535 Does it matter anywhere in Emacs? */
2536 if (w32_unicode_filenames
)
2538 wchar_t wstartup_dir
[MAX_PATH
];
2540 if (!GetCurrentDirectoryW (MAX_PATH
, wstartup_dir
))
2542 filename_from_utf16 (wstartup_dir
, startup_dir
);
2546 char astartup_dir
[MAX_PATH
];
2548 if (!GetCurrentDirectoryA (MAX_PATH
, astartup_dir
))
2550 filename_from_ansi (astartup_dir
, startup_dir
);
2554 static char modname
[MAX_PATH
];
2556 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2561 /* Determine if there is a middle mouse button, to allow parse_button
2562 to decide whether right mouse events should be mouse-2 or
2564 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
2569 /* Called from expand-file-name when default-directory is not a string. */
2572 emacs_root_dir (void)
2574 static char root_dir
[MAX_UTF8_PATH
];
2577 p
= getenv ("emacs_dir");
2580 filename_from_ansi (p
, root_dir
);
2581 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
2582 dostounix_filename (root_dir
);
2586 #include <sys/timeb.h>
2588 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2590 gettimeofday (struct timeval
*__restrict tv
, struct timezone
*__restrict tz
)
2595 tv
->tv_sec
= tb
.time
;
2596 tv
->tv_usec
= tb
.millitm
* 1000L;
2597 /* Implementation note: _ftime sometimes doesn't update the dstflag
2598 according to the new timezone when the system timezone is
2599 changed. We could fix that by using GetSystemTime and
2600 GetTimeZoneInformation, but that doesn't seem necessary, since
2601 Emacs always calls gettimeofday with the 2nd argument NULL (see
2602 current_emacs_time). */
2605 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
2606 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
2611 /* Emulate fdutimens. */
2613 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2614 TIMESPEC[0] and TIMESPEC[1], respectively.
2615 FD must be either negative -- in which case it is ignored --
2616 or a file descriptor that is open on FILE.
2617 If FD is nonnegative, then FILE can be NULL, which means
2618 use just futimes instead of utimes.
2619 If TIMESPEC is null, FAIL.
2620 Return 0 on success, -1 (setting errno) on failure. */
2623 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
2630 if (fd
< 0 && !file
)
2635 /* _futime's prototype defines 2nd arg as having the type 'struct
2636 _utimbuf', while utime needs to accept 'struct utimbuf' for
2637 compatibility with Posix. So we need to use 2 different (but
2638 equivalent) types to avoid compiler warnings, sigh. */
2641 struct _utimbuf _ut
;
2643 _ut
.actime
= timespec
[0].tv_sec
;
2644 _ut
.modtime
= timespec
[1].tv_sec
;
2645 return _futime (fd
, &_ut
);
2651 ut
.actime
= timespec
[0].tv_sec
;
2652 ut
.modtime
= timespec
[1].tv_sec
;
2653 /* Call 'utime', which is implemented below, not the MS library
2654 function, which fails on directories. */
2655 return utime (file
, &ut
);
2660 /* ------------------------------------------------------------------------- */
2661 /* IO support and wrapper functions for the Windows API. */
2662 /* ------------------------------------------------------------------------- */
2664 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2665 on network directories, so we handle that case here.
2666 (Ulrich Leodolter, 1/11/95). */
2668 sys_ctime (const time_t *t
)
2670 char *str
= (char *) ctime (t
);
2671 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2674 /* Emulate sleep...we could have done this with a define, but that
2675 would necessitate including windows.h in the files that used it.
2676 This is much easier. */
2678 sys_sleep (int seconds
)
2680 Sleep (seconds
* 1000);
2683 /* Internal MSVC functions for low-level descriptor munging */
2684 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2685 extern int __cdecl
_free_osfhnd (int fd
);
2687 /* parallel array of private info on file handles */
2688 filedesc fd_info
[ MAXDESC
];
2690 typedef struct volume_info_data
{
2691 struct volume_info_data
* next
;
2693 /* time when info was obtained */
2696 /* actual volume info */
2705 /* Global referenced by various functions. */
2706 static volume_info_data volume_info
;
2708 /* Vector to indicate which drives are local and fixed (for which cached
2709 data never expires). */
2710 static BOOL fixed_drives
[26];
2712 /* Consider cached volume information to be stale if older than 10s,
2713 at least for non-local drives. Info for fixed drives is never stale. */
2714 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2715 #define VOLINFO_STILL_VALID( root_dir, info ) \
2716 ( ( isalpha (root_dir[0]) && \
2717 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2718 || GetTickCount () - info->timestamp < 10000 )
2720 /* Cache support functions. */
2722 /* Simple linked list with linear search is sufficient. */
2723 static volume_info_data
*volume_cache
= NULL
;
2725 static volume_info_data
*
2726 lookup_volume_info (char * root_dir
)
2728 volume_info_data
* info
;
2730 for (info
= volume_cache
; info
; info
= info
->next
)
2731 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2737 add_volume_info (char * root_dir
, volume_info_data
* info
)
2739 info
->root_dir
= xstrdup (root_dir
);
2740 unixtodos_filename (info
->root_dir
);
2741 info
->next
= volume_cache
;
2742 volume_cache
= info
;
2746 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2747 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2748 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2749 static volume_info_data
*
2750 GetCachedVolumeInformation (char * root_dir
)
2752 volume_info_data
* info
;
2753 char default_root
[ MAX_UTF8_PATH
];
2754 char name
[MAX_PATH
+1];
2755 char type
[MAX_PATH
+1];
2757 /* NULL for root_dir means use root from current directory. */
2758 if (root_dir
== NULL
)
2760 if (w32_unicode_filenames
)
2762 wchar_t curdirw
[MAX_PATH
];
2764 if (GetCurrentDirectoryW (MAX_PATH
, curdirw
) == 0)
2766 filename_from_utf16 (curdirw
, default_root
);
2770 char curdira
[MAX_PATH
];
2772 if (GetCurrentDirectoryA (MAX_PATH
, curdira
) == 0)
2774 filename_from_ansi (curdira
, default_root
);
2776 parse_root (default_root
, (const char **)&root_dir
);
2778 root_dir
= default_root
;
2781 /* Local fixed drives can be cached permanently. Removable drives
2782 cannot be cached permanently, since the volume name and serial
2783 number (if nothing else) can change. Remote drives should be
2784 treated as if they are removable, since there is no sure way to
2785 tell whether they are or not. Also, the UNC association of drive
2786 letters mapped to remote volumes can be changed at any time (even
2787 by other processes) without notice.
2789 As a compromise, so we can benefit from caching info for remote
2790 volumes, we use a simple expiry mechanism to invalidate cache
2791 entries that are more than ten seconds old. */
2794 /* No point doing this, because WNetGetConnection is even slower than
2795 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2796 GetDriveType is about the only call of this type which does not
2797 involve network access, and so is extremely quick). */
2799 /* Map drive letter to UNC if remote. */
2800 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2802 char remote_name
[ 256 ];
2803 char drive
[3] = { root_dir
[0], ':' };
2805 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2807 /* do something */ ;
2811 info
= lookup_volume_info (root_dir
);
2813 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2819 /* Info is not cached, or is stale. */
2820 if (w32_unicode_filenames
)
2822 wchar_t root_w
[MAX_PATH
];
2823 wchar_t name_w
[MAX_PATH
+1];
2824 wchar_t type_w
[MAX_PATH
+1];
2826 filename_to_utf16 (root_dir
, root_w
);
2827 if (!GetVolumeInformationW (root_w
,
2828 name_w
, sizeof (name_w
),
2832 type_w
, sizeof (type_w
)))
2834 /* Hmm... not really 100% correct, as these 2 are not file
2836 filename_from_utf16 (name_w
, name
);
2837 filename_from_utf16 (type_w
, type
);
2841 char root_a
[MAX_PATH
];
2842 char name_a
[MAX_PATH
+1];
2843 char type_a
[MAX_PATH
+1];
2845 filename_to_ansi (root_dir
, root_a
);
2846 if (!GetVolumeInformationA (root_a
,
2847 name_a
, sizeof (name_a
),
2851 type_a
, sizeof (type_a
)))
2853 filename_from_ansi (name_a
, name
);
2854 filename_from_ansi (type_a
, type
);
2857 /* Cache the volume information for future use, overwriting existing
2858 entry if present. */
2861 info
= xmalloc (sizeof (volume_info_data
));
2862 add_volume_info (root_dir
, info
);
2870 info
->name
= xstrdup (name
);
2871 unixtodos_filename (info
->name
);
2872 info
->serialnum
= serialnum
;
2873 info
->maxcomp
= maxcomp
;
2874 info
->flags
= flags
;
2875 info
->type
= xstrdup (type
);
2876 info
->timestamp
= GetTickCount ();
2882 /* Get information on the volume where NAME is held; set path pointer to
2883 start of pathname in NAME (past UNC header\volume header if present),
2884 if pPath is non-NULL.
2886 Note: if NAME includes symlinks, the information is for the volume
2887 of the symlink, not of its target. That's because, even though
2888 GetVolumeInformation returns information about the symlink target
2889 of its argument, we only pass the root directory to
2890 GetVolumeInformation, not the full NAME. */
2892 get_volume_info (const char * name
, const char ** pPath
)
2894 char temp
[MAX_UTF8_PATH
];
2895 char *rootname
= NULL
; /* default to current volume */
2896 volume_info_data
* info
;
2897 int root_len
= parse_root (name
, pPath
);
2902 /* Copy the root name of the volume, if given. */
2905 strncpy (temp
, name
, root_len
);
2906 temp
[root_len
] = '\0';
2907 unixtodos_filename (temp
);
2911 info
= GetCachedVolumeInformation (rootname
);
2914 /* Set global referenced by other functions. */
2915 volume_info
= *info
;
2921 /* Determine if volume is FAT format (ie. only supports short 8.3
2922 names); also set path pointer to start of pathname in name, if
2923 pPath is non-NULL. */
2925 is_fat_volume (const char * name
, const char ** pPath
)
2927 if (get_volume_info (name
, pPath
))
2928 return (volume_info
.maxcomp
== 12);
2932 /* Convert all slashes in a filename to backslashes, and map filename
2933 to a valid 8.3 name if necessary. The result is a pointer to a
2934 static buffer, so CAVEAT EMPTOR! */
2936 map_w32_filename (const char * name
, const char ** pPath
)
2938 static char shortname
[MAX_UTF8_PATH
];
2939 char * str
= shortname
;
2942 const char * save_name
= name
;
2944 if (strlen (name
) >= sizeof (shortname
))
2946 /* Return a filename which will cause callers to fail. */
2947 strcpy (shortname
, "?");
2951 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2953 register int left
= 8; /* maximum number of chars in part */
2954 register int extn
= 0; /* extension added? */
2955 register int dots
= 2; /* maximum number of dots allowed */
2958 *str
++ = *name
++; /* skip past UNC header */
2960 while ((c
= *name
++))
2967 *str
++ = (c
== ':' ? ':' : '\\');
2968 extn
= 0; /* reset extension flags */
2969 dots
= 2; /* max 2 dots */
2970 left
= 8; /* max length 8 for main part */
2975 /* Convert path components of the form .xxx to _xxx,
2976 but leave . and .. as they are. This allows .emacs
2977 to be read as _emacs, for example. */
2981 IS_DIRECTORY_SEP (*name
))
2996 extn
= 1; /* we've got an extension */
2997 left
= 3; /* 3 chars in extension */
3001 /* any embedded dots after the first are converted to _ */
3006 case '#': /* don't lose these, they're important */
3008 str
[-1] = c
; /* replace last character of part */
3011 if ( left
&& 'A' <= c
&& c
<= 'Z' )
3013 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
3015 dots
= 0; /* started a path component */
3024 strcpy (shortname
, name
);
3025 unixtodos_filename (shortname
);
3029 *pPath
= shortname
+ (path
- save_name
);
3035 is_exec (const char * name
)
3037 char * p
= strrchr (name
, '.');
3040 && (xstrcasecmp (p
, ".exe") == 0 ||
3041 xstrcasecmp (p
, ".com") == 0 ||
3042 xstrcasecmp (p
, ".bat") == 0 ||
3043 xstrcasecmp (p
, ".cmd") == 0));
3046 /* Emulate the Unix directory procedures opendir, closedir, and
3047 readdir. We rename them to sys_* names because some versions of
3048 MinGW startup code call opendir and readdir to glob wildcards, and
3049 the code that calls them doesn't grok UTF-8 encoded file names we
3050 produce in dirent->d_name[]. */
3052 struct dirent dir_static
; /* simulated directory contents */
3053 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
3054 static int dir_is_fat
;
3055 static char dir_pathname
[MAX_UTF8_PATH
];
3056 static WIN32_FIND_DATAW dir_find_data_w
;
3057 static WIN32_FIND_DATAA dir_find_data_a
;
3058 #define DIR_FIND_DATA_W 1
3059 #define DIR_FIND_DATA_A 2
3060 static int last_dir_find_data
= -1;
3062 /* Support shares on a network resource as subdirectories of a read-only
3064 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
3065 static HANDLE
open_unc_volume (const char *);
3066 static void *read_unc_volume (HANDLE
, wchar_t *, char *, int);
3067 static void close_unc_volume (HANDLE
);
3070 sys_opendir (const char *filename
)
3074 /* Opening is done by FindFirstFile. However, a read is inherent to
3075 this operation, so we defer the open until read time. */
3077 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
3079 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
3082 /* Note: We don't support traversal of UNC volumes via symlinks.
3083 Doing so would mean punishing 99.99% of use cases by resolving
3084 all the possible symlinks in FILENAME, recursively. */
3085 if (is_unc_volume (filename
))
3087 wnet_enum_handle
= open_unc_volume (filename
);
3088 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
3092 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
3099 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAX_UTF8_PATH
- 1);
3100 dir_pathname
[MAX_UTF8_PATH
- 1] = '\0';
3101 /* Note: We don't support symlinks to file names on FAT volumes.
3102 Doing so would mean punishing 99.99% of use cases by resolving
3103 all the possible symlinks in FILENAME, recursively. */
3104 dir_is_fat
= is_fat_volume (filename
, NULL
);
3110 sys_closedir (DIR *dirp
)
3112 /* If we have a find-handle open, close it. */
3113 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
3115 FindClose (dir_find_handle
);
3116 dir_find_handle
= INVALID_HANDLE_VALUE
;
3118 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
3120 close_unc_volume (wnet_enum_handle
);
3121 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
3123 xfree ((char *) dirp
);
3127 sys_readdir (DIR *dirp
)
3129 int downcase
= !NILP (Vw32_downcase_file_names
);
3131 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
3133 if (!read_unc_volume (wnet_enum_handle
,
3134 dir_find_data_w
.cFileName
,
3135 dir_find_data_a
.cFileName
,
3139 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3140 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
3142 char filename
[MAX_UTF8_PATH
+ 2];
3145 strcpy (filename
, dir_pathname
);
3146 ln
= strlen (filename
) - 1;
3147 if (!IS_DIRECTORY_SEP (filename
[ln
]))
3148 strcat (filename
, "\\");
3149 strcat (filename
, "*");
3151 /* Note: No need to resolve symlinks in FILENAME, because
3152 FindFirst opens the directory that is the target of a
3154 if (w32_unicode_filenames
)
3156 wchar_t fnw
[MAX_PATH
];
3158 filename_to_utf16 (filename
, fnw
);
3159 dir_find_handle
= FindFirstFileW (fnw
, &dir_find_data_w
);
3165 filename_to_ansi (filename
, fna
);
3166 /* If FILENAME is not representable by the current ANSI
3167 codepage, we don't want FindFirstFileA to interpret the
3168 '?' characters as a wildcard. */
3169 if (_mbspbrk (fna
, "?"))
3170 dir_find_handle
= INVALID_HANDLE_VALUE
;
3172 dir_find_handle
= FindFirstFileA (fna
, &dir_find_data_a
);
3175 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
3178 else if (w32_unicode_filenames
)
3180 if (!FindNextFileW (dir_find_handle
, &dir_find_data_w
))
3185 if (!FindNextFileA (dir_find_handle
, &dir_find_data_a
))
3189 /* Emacs never uses this value, so don't bother making it match
3190 value returned by stat(). */
3191 dir_static
.d_ino
= 1;
3193 if (w32_unicode_filenames
)
3195 if (downcase
|| dir_is_fat
)
3197 wchar_t tem
[MAX_PATH
];
3199 wcscpy (tem
, dir_find_data_w
.cFileName
);
3201 filename_from_utf16 (tem
, dir_static
.d_name
);
3204 filename_from_utf16 (dir_find_data_w
.cFileName
, dir_static
.d_name
);
3205 last_dir_find_data
= DIR_FIND_DATA_W
;
3211 /* If the file name in cFileName[] includes `?' characters, it
3212 means the original file name used characters that cannot be
3213 represented by the current ANSI codepage. To avoid total
3214 lossage, retrieve the short 8+3 alias of the long file
3216 if (_mbspbrk (dir_find_data_a
.cFileName
, "?"))
3218 strcpy (tem
, dir_find_data_a
.cAlternateFileName
);
3219 /* 8+3 aliases are returned in all caps, which could break
3220 various alists that look at filenames' extensions. */
3223 else if (downcase
|| dir_is_fat
)
3224 strcpy (tem
, dir_find_data_a
.cFileName
);
3226 filename_from_ansi (dir_find_data_a
.cFileName
, dir_static
.d_name
);
3227 if (downcase
|| dir_is_fat
)
3230 filename_from_ansi (tem
, dir_static
.d_name
);
3232 last_dir_find_data
= DIR_FIND_DATA_A
;
3235 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
3236 dir_static
.d_reclen
= sizeof (struct dirent
) - MAX_UTF8_PATH
+ 3 +
3237 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
3243 open_unc_volume (const char *path
)
3245 const char *fn
= map_w32_filename (path
, NULL
);
3249 if (w32_unicode_filenames
)
3252 wchar_t fnw
[MAX_PATH
];
3254 nrw
.dwScope
= RESOURCE_GLOBALNET
;
3255 nrw
.dwType
= RESOURCETYPE_DISK
;
3256 nrw
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
3257 nrw
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3258 nrw
.lpLocalName
= NULL
;
3259 filename_to_utf16 (fn
, fnw
);
3260 nrw
.lpRemoteName
= fnw
;
3261 nrw
.lpComment
= NULL
;
3262 nrw
.lpProvider
= NULL
;
3264 result
= WNetOpenEnumW (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
3265 RESOURCEUSAGE_CONNECTABLE
, &nrw
, &henum
);
3272 nra
.dwScope
= RESOURCE_GLOBALNET
;
3273 nra
.dwType
= RESOURCETYPE_DISK
;
3274 nra
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
3275 nra
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3276 nra
.lpLocalName
= NULL
;
3277 filename_to_ansi (fn
, fna
);
3278 nra
.lpRemoteName
= fna
;
3279 nra
.lpComment
= NULL
;
3280 nra
.lpProvider
= NULL
;
3282 result
= WNetOpenEnumA (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
3283 RESOURCEUSAGE_CONNECTABLE
, &nra
, &henum
);
3285 if (result
== NO_ERROR
)
3288 return INVALID_HANDLE_VALUE
;
3292 read_unc_volume (HANDLE henum
, wchar_t *fname_w
, char *fname_a
, int size
)
3297 DWORD bufsize
= 512;
3301 if (w32_unicode_filenames
)
3306 buffer
= alloca (bufsize
);
3307 result
= WNetEnumResourceW (henum
, &count
, buffer
, &bufsize
);
3308 if (result
!= NO_ERROR
)
3310 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3311 ptrw
= ((LPNETRESOURCEW
) buffer
)->lpRemoteName
;
3313 while (*ptrw
&& *ptrw
!= L
'/' && *ptrw
!= L
'\\') ptrw
++;
3315 wcsncpy (fname_w
, ptrw
, size
);
3320 int dbcs_p
= max_filename_mbslen () > 1;
3323 buffer
= alloca (bufsize
);
3324 result
= WNetEnumResourceA (henum
, &count
, buffer
, &bufsize
);
3325 if (result
!= NO_ERROR
)
3327 ptra
= ((LPNETRESOURCEA
) buffer
)->lpRemoteName
;
3330 while (*ptra
&& !IS_DIRECTORY_SEP (*ptra
)) ptra
++;
3333 while (*ptra
&& !IS_DIRECTORY_SEP (*ptra
))
3334 ptra
= CharNextExA (file_name_codepage
, ptra
, 0);
3337 strncpy (fname_a
, ptra
, size
);
3345 close_unc_volume (HANDLE henum
)
3347 if (henum
!= INVALID_HANDLE_VALUE
)
3348 WNetCloseEnum (henum
);
3352 unc_volume_file_attributes (const char *path
)
3357 henum
= open_unc_volume (path
);
3358 if (henum
== INVALID_HANDLE_VALUE
)
3361 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
3363 close_unc_volume (henum
);
3368 /* Ensure a network connection is authenticated. */
3370 logon_network_drive (const char *path
)
3372 char share
[MAX_UTF8_PATH
];
3379 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
3380 drvtype
= DRIVE_REMOTE
;
3381 else if (path
[0] == '\0' || path
[1] != ':')
3382 drvtype
= GetDriveType (NULL
);
3389 drvtype
= GetDriveType (drive
);
3392 /* Only logon to networked drives. */
3393 if (drvtype
!= DRIVE_REMOTE
)
3397 strncpy (share
, path
, MAX_UTF8_PATH
);
3398 /* Truncate to just server and share name. */
3399 for (p
= share
+ 2; *p
&& p
< share
+ MAX_UTF8_PATH
; p
++)
3401 if (IS_DIRECTORY_SEP (*p
) && ++n_slashes
> 3)
3408 if (w32_unicode_filenames
)
3410 NETRESOURCEW resourcew
;
3411 wchar_t share_w
[MAX_PATH
];
3413 resourcew
.dwScope
= RESOURCE_GLOBALNET
;
3414 resourcew
.dwType
= RESOURCETYPE_DISK
;
3415 resourcew
.dwDisplayType
= RESOURCEDISPLAYTYPE_SHARE
;
3416 resourcew
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3417 resourcew
.lpLocalName
= NULL
;
3418 filename_to_utf16 (share
, share_w
);
3419 resourcew
.lpRemoteName
= share_w
;
3420 resourcew
.lpProvider
= NULL
;
3422 val
= WNetAddConnection2W (&resourcew
, NULL
, NULL
, CONNECT_INTERACTIVE
);
3426 NETRESOURCEA resourcea
;
3427 char share_a
[MAX_PATH
];
3429 resourcea
.dwScope
= RESOURCE_GLOBALNET
;
3430 resourcea
.dwType
= RESOURCETYPE_DISK
;
3431 resourcea
.dwDisplayType
= RESOURCEDISPLAYTYPE_SHARE
;
3432 resourcea
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3433 resourcea
.lpLocalName
= NULL
;
3434 filename_to_ansi (share
, share_a
);
3435 resourcea
.lpRemoteName
= share_a
;
3436 resourcea
.lpProvider
= NULL
;
3438 val
= WNetAddConnection2A (&resourcea
, NULL
, NULL
, CONNECT_INTERACTIVE
);
3444 case ERROR_ALREADY_ASSIGNED
:
3446 case ERROR_ACCESS_DENIED
:
3447 case ERROR_LOGON_FAILURE
:
3453 case ERROR_BAD_NET_NAME
:
3454 case ERROR_NO_NET_OR_BAD_PATH
:
3455 case ERROR_NO_NETWORK
:
3456 case ERROR_CANCELLED
:
3463 /* Emulate faccessat(2). */
3465 faccessat (int dirfd
, const char * path
, int mode
, int flags
)
3469 if (dirfd
!= AT_FDCWD
3470 && !(IS_DIRECTORY_SEP (path
[0])
3471 || IS_DEVICE_SEP (path
[1])))
3477 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3478 newer versions blow up when passed D_OK. */
3479 path
= map_w32_filename (path
, NULL
);
3480 /* If the last element of PATH is a symlink, we need to resolve it
3481 to get the attributes of its target file. Note: any symlinks in
3482 PATH elements other than the last one are transparently resolved
3483 by GetFileAttributes below. */
3484 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0
3485 && (flags
& AT_SYMLINK_NOFOLLOW
) == 0)
3486 path
= chase_symlinks (path
);
3488 if (w32_unicode_filenames
)
3490 wchar_t path_w
[MAX_PATH
];
3492 filename_to_utf16 (path
, path_w
);
3493 attributes
= GetFileAttributesW (path_w
);
3497 char path_a
[MAX_PATH
];
3499 filename_to_ansi (path
, path_a
);
3500 attributes
= GetFileAttributesA (path_a
);
3503 if (attributes
== -1)
3505 DWORD w32err
= GetLastError ();
3509 case ERROR_INVALID_NAME
:
3510 case ERROR_BAD_PATHNAME
:
3511 if (is_unc_volume (path
))
3513 attributes
= unc_volume_file_attributes (path
);
3514 if (attributes
== -1)
3522 case ERROR_FILE_NOT_FOUND
:
3523 case ERROR_BAD_NETPATH
:
3532 if ((mode
& X_OK
) != 0
3533 && !(is_exec (path
) || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3538 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3543 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3551 /* A version of 'access' to be used locally with file names in
3552 locale-specific encoding. Does not resolve symlinks and does not
3553 support file names on FAT12 and FAT16 volumes, but that's OK, since
3554 we only invoke this function for files inside the Emacs source or
3555 installation tree, on directories (so any symlinks should have the
3556 directory bit set), and on short file names such as "C:/.emacs". */
3558 sys_access (const char *fname
, int mode
)
3560 char fname_copy
[MAX_PATH
], *p
;
3563 strcpy (fname_copy
, fname
);
3564 /* Do the equivalent of unixtodos_filename. */
3565 for (p
= fname_copy
; *p
; p
= CharNext (p
))
3569 if ((attributes
= GetFileAttributesA (fname_copy
)) == -1)
3571 DWORD w32err
= GetLastError ();
3575 case ERROR_INVALID_NAME
:
3576 case ERROR_BAD_PATHNAME
:
3577 case ERROR_FILE_NOT_FOUND
:
3578 case ERROR_BAD_NETPATH
:
3587 if ((mode
& X_OK
) != 0
3588 && !(is_exec (fname_copy
)
3589 || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3594 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3599 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3607 /* Shadow some MSVC runtime functions to map requests for long filenames
3608 to reasonable short names if necessary. This was originally added to
3609 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3613 sys_chdir (const char * path
)
3615 path
= map_w32_filename (path
, NULL
);
3616 if (w32_unicode_filenames
)
3618 wchar_t newdir_w
[MAX_PATH
];
3620 if (filename_to_utf16 (path
, newdir_w
) == 0)
3621 return _wchdir (newdir_w
);
3626 char newdir_a
[MAX_PATH
];
3628 if (filename_to_ansi (path
, newdir_a
) == 0)
3629 return _chdir (newdir_a
);
3635 sys_chmod (const char * path
, int mode
)
3637 path
= chase_symlinks (map_w32_filename (path
, NULL
));
3638 if (w32_unicode_filenames
)
3640 wchar_t path_w
[MAX_PATH
];
3642 filename_to_utf16 (path
, path_w
);
3643 return _wchmod (path_w
, mode
);
3647 char path_a
[MAX_PATH
];
3649 filename_to_ansi (path
, path_a
);
3650 return _chmod (path_a
, mode
);
3655 sys_creat (const char * path
, int mode
)
3657 path
= map_w32_filename (path
, NULL
);
3658 if (w32_unicode_filenames
)
3660 wchar_t path_w
[MAX_PATH
];
3662 filename_to_utf16 (path
, path_w
);
3663 return _wcreat (path_w
, mode
);
3667 char path_a
[MAX_PATH
];
3669 filename_to_ansi (path
, path_a
);
3670 return _creat (path_a
, mode
);
3675 sys_fopen (const char * path
, const char * mode
)
3679 const char * mode_save
= mode
;
3681 /* Force all file handles to be non-inheritable. This is necessary to
3682 ensure child processes don't unwittingly inherit handles that might
3683 prevent future file access. */
3687 else if (mode
[0] == 'w' || mode
[0] == 'a')
3688 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
3692 /* Only do simplistic option parsing. */
3696 oflag
&= ~(O_RDONLY
| O_WRONLY
);
3699 else if (mode
[0] == 'b')
3704 else if (mode
[0] == 't')
3711 path
= map_w32_filename (path
, NULL
);
3712 if (w32_unicode_filenames
)
3714 wchar_t path_w
[MAX_PATH
];
3716 filename_to_utf16 (path
, path_w
);
3717 fd
= _wopen (path_w
, oflag
| _O_NOINHERIT
, 0644);
3721 char path_a
[MAX_PATH
];
3723 filename_to_ansi (path
, path_a
);
3724 fd
= _open (path_a
, oflag
| _O_NOINHERIT
, 0644);
3729 return _fdopen (fd
, mode_save
);
3732 /* This only works on NTFS volumes, but is useful to have. */
3734 sys_link (const char * old
, const char * new)
3738 char oldname
[MAX_UTF8_PATH
], newname
[MAX_UTF8_PATH
];
3739 wchar_t oldname_w
[MAX_PATH
];
3740 char oldname_a
[MAX_PATH
];
3742 if (old
== NULL
|| new == NULL
)
3748 strcpy (oldname
, map_w32_filename (old
, NULL
));
3749 strcpy (newname
, map_w32_filename (new, NULL
));
3751 if (w32_unicode_filenames
)
3753 filename_to_utf16 (oldname
, oldname_w
);
3754 fileh
= CreateFileW (oldname_w
, 0, 0, NULL
, OPEN_EXISTING
,
3755 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
3759 filename_to_ansi (oldname
, oldname_a
);
3760 fileh
= CreateFileA (oldname_a
, 0, 0, NULL
, OPEN_EXISTING
,
3761 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
3763 if (fileh
!= INVALID_HANDLE_VALUE
)
3767 /* Confusingly, the "alternate" stream name field does not apply
3768 when restoring a hard link, and instead contains the actual
3769 stream data for the link (ie. the name of the link to create).
3770 The WIN32_STREAM_ID structure before the cStreamName field is
3771 the stream header, which is then immediately followed by the
3775 WIN32_STREAM_ID wid
;
3776 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
3779 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
3780 indicates that flag is unsupported for CP_UTF8, and OTOH says
3781 it is the default anyway. */
3782 wlen
= MultiByteToWideChar (CP_UTF8
, 0, newname
, -1,
3783 data
.wid
.cStreamName
, MAX_PATH
);
3786 LPVOID context
= NULL
;
3789 data
.wid
.dwStreamId
= BACKUP_LINK
;
3790 data
.wid
.dwStreamAttributes
= 0;
3791 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
3792 data
.wid
.Size
.HighPart
= 0;
3793 data
.wid
.dwStreamNameSize
= 0;
3795 if (BackupWrite (fileh
, (LPBYTE
)&data
,
3796 offsetof (WIN32_STREAM_ID
, cStreamName
)
3797 + data
.wid
.Size
.LowPart
,
3798 &wbytes
, FALSE
, FALSE
, &context
)
3799 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
3806 DWORD err
= GetLastError ();
3811 case ERROR_ACCESS_DENIED
:
3812 /* This is what happens when OLDNAME is a directory,
3813 since Windows doesn't support hard links to
3814 directories. Posix says to set errno to EPERM in
3816 if (w32_unicode_filenames
)
3817 attributes
= GetFileAttributesW (oldname_w
);
3819 attributes
= GetFileAttributesA (oldname_a
);
3820 if (attributes
!= -1
3821 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0)
3823 else if (attributes
== -1
3824 && is_unc_volume (oldname
)
3825 && unc_volume_file_attributes (oldname
) != -1)
3830 case ERROR_TOO_MANY_LINKS
:
3833 case ERROR_NOT_SAME_DEVICE
:
3843 CloseHandle (fileh
);
3852 sys_mkdir (const char * path
)
3854 path
= map_w32_filename (path
, NULL
);
3856 if (w32_unicode_filenames
)
3858 wchar_t path_w
[MAX_PATH
];
3860 filename_to_utf16 (path
, path_w
);
3861 return _wmkdir (path_w
);
3865 char path_a
[MAX_PATH
];
3867 filename_to_ansi (path
, path_a
);
3868 return _mkdir (path_a
);
3873 sys_open (const char * path
, int oflag
, int mode
)
3875 const char* mpath
= map_w32_filename (path
, NULL
);
3878 if (w32_unicode_filenames
)
3880 wchar_t mpath_w
[MAX_PATH
];
3882 filename_to_utf16 (mpath
, mpath_w
);
3883 /* If possible, try to open file without _O_CREAT, to be able to
3884 write to existing hidden and system files. Force all file
3885 handles to be non-inheritable. */
3886 if ((oflag
& (_O_CREAT
| _O_EXCL
)) != (_O_CREAT
| _O_EXCL
))
3887 res
= _wopen (mpath_w
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3889 res
= _wopen (mpath_w
, oflag
| _O_NOINHERIT
, mode
);
3893 char mpath_a
[MAX_PATH
];
3895 filename_to_ansi (mpath
, mpath_a
);
3896 if ((oflag
& (_O_CREAT
| _O_EXCL
)) != (_O_CREAT
| _O_EXCL
))
3897 res
= _open (mpath_a
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3899 res
= _open (mpath_a
, oflag
| _O_NOINHERIT
, mode
);
3905 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
3908 Standard algorithm for generating a temporary file name seems to be
3909 use pid or tid with a letter on the front (in place of the 6 X's)
3910 and cycle through the letters to find a unique name. We extend
3911 that to allow any reasonable character as the first of the 6 X's,
3912 so that the number of simultaneously used temporary files will be
3916 mkostemp (char * template, int flags
)
3920 unsigned uid
= GetCurrentThreadId ();
3921 int save_errno
= errno
;
3922 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3925 if (template == NULL
)
3928 p
= template + strlen (template);
3930 /* replace up to the last 5 X's with uid in decimal */
3931 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
3933 p
[0] = '0' + uid
% 10;
3937 if (i
< 0 && p
[0] == 'X')
3942 p
[0] = first_char
[i
];
3943 if ((fd
= sys_open (template,
3944 flags
| _O_CREAT
| _O_EXCL
| _O_RDWR
,
3945 S_IRUSR
| S_IWUSR
)) >= 0
3953 while (++i
< sizeof (first_char
));
3956 /* Template is badly formed or else we can't generate a unique name. */
3961 fchmod (int fd
, mode_t mode
)
3967 sys_rename_replace (const char *oldname
, const char *newname
, BOOL force
)
3970 char temp
[MAX_UTF8_PATH
], temp_a
[MAX_PATH
];;
3973 bool have_temp_a
= false;
3975 /* MoveFile on Windows 95 doesn't correctly change the short file name
3976 alias in a number of circumstances (it is not easy to predict when
3977 just by looking at oldname and newname, unfortunately). In these
3978 cases, renaming through a temporary name avoids the problem.
3980 A second problem on Windows 95 is that renaming through a temp name when
3981 newname is uppercase fails (the final long name ends up in
3982 lowercase, although the short alias might be uppercase) UNLESS the
3983 long temp name is not 8.3.
3985 So, on Windows 95 we always rename through a temp name, and we make sure
3986 the temp name has a long extension to ensure correct renaming. */
3988 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3990 /* volume_info is set indirectly by map_w32_filename. */
3991 oldname_dev
= volume_info
.serialnum
;
3993 if (os_subtype
== OS_9X
)
3998 char oldname_a
[MAX_PATH
];
4000 oldname
= map_w32_filename (oldname
, NULL
);
4001 filename_to_ansi (oldname
, oldname_a
);
4002 filename_to_ansi (temp
, temp_a
);
4003 if ((o
= strrchr (oldname_a
, '\\')))
4006 o
= (char *) oldname_a
;
4008 if ((p
= strrchr (temp_a
, '\\')))
4015 /* Force temp name to require a manufactured 8.3 alias - this
4016 seems to make the second rename work properly. */
4017 sprintf (p
, "_.%s.%u", o
, i
);
4019 result
= rename (oldname_a
, temp_a
);
4021 /* This loop must surely terminate! */
4022 while (result
< 0 && errno
== EEXIST
);
4028 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4029 (at least if it is a file; don't do this for directories).
4031 Since we mustn't do this if we are just changing the case of the
4032 file name (we would end up deleting the file we are trying to
4033 rename!), we let rename detect if the destination file already
4034 exists - that way we avoid the possible pitfalls of trying to
4035 determine ourselves whether two names really refer to the same
4036 file, which is not always possible in the general case. (Consider
4037 all the permutations of shared or subst'd drives, etc.) */
4039 newname
= map_w32_filename (newname
, NULL
);
4041 /* volume_info is set indirectly by map_w32_filename. */
4042 newname_dev
= volume_info
.serialnum
;
4044 if (w32_unicode_filenames
)
4046 wchar_t temp_w
[MAX_PATH
], newname_w
[MAX_PATH
];
4048 filename_to_utf16 (temp
, temp_w
);
4049 filename_to_utf16 (newname
, newname_w
);
4050 result
= _wrename (temp_w
, newname_w
);
4051 if (result
< 0 && force
)
4053 DWORD w32err
= GetLastError ();
4056 && newname_dev
!= oldname_dev
)
4058 /* The implementation of `rename' on Windows does not return
4059 errno = EXDEV when you are moving a directory to a
4060 different storage device (ex. logical disk). It returns
4061 EACCES instead. So here we handle such situations and
4065 if ((attributes
= GetFileAttributesW (temp_w
)) != -1
4066 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
4069 else if (errno
== EEXIST
)
4071 if (_wchmod (newname_w
, 0666) != 0)
4073 if (_wunlink (newname_w
) != 0)
4075 result
= _wrename (temp_w
, newname_w
);
4077 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
4078 && is_symlink (temp
))
4080 /* This is Windows prohibiting the user from creating a
4081 symlink in another place, since that requires
4089 char newname_a
[MAX_PATH
];
4092 filename_to_ansi (temp
, temp_a
);
4093 filename_to_ansi (newname
, newname_a
);
4094 result
= rename (temp_a
, newname_a
);
4095 if (result
< 0 && force
)
4097 DWORD w32err
= GetLastError ();
4100 && newname_dev
!= oldname_dev
)
4104 if ((attributes
= GetFileAttributesA (temp_a
)) != -1
4105 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
4108 else if (errno
== EEXIST
)
4110 if (_chmod (newname_a
, 0666) != 0)
4112 if (_unlink (newname_a
) != 0)
4114 result
= rename (temp_a
, newname_a
);
4116 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
4117 && is_symlink (temp
))
4126 sys_rename (char const *old
, char const *new)
4128 return sys_rename_replace (old
, new, TRUE
);
4132 sys_rmdir (const char * path
)
4134 path
= map_w32_filename (path
, NULL
);
4136 if (w32_unicode_filenames
)
4138 wchar_t path_w
[MAX_PATH
];
4140 filename_to_utf16 (path
, path_w
);
4141 return _wrmdir (path_w
);
4145 char path_a
[MAX_PATH
];
4147 filename_to_ansi (path
, path_a
);
4148 return _rmdir (path_a
);
4153 sys_unlink (const char * path
)
4155 path
= map_w32_filename (path
, NULL
);
4157 if (w32_unicode_filenames
)
4159 wchar_t path_w
[MAX_PATH
];
4161 filename_to_utf16 (path
, path_w
);
4162 /* On Unix, unlink works without write permission. */
4163 _wchmod (path_w
, 0666);
4164 return _wunlink (path_w
);
4168 char path_a
[MAX_PATH
];
4170 filename_to_ansi (path
, path_a
);
4171 _chmod (path_a
, 0666);
4172 return _unlink (path_a
);
4176 static FILETIME utc_base_ft
;
4177 static ULONGLONG utc_base
; /* In 100ns units */
4178 static int init
= 0;
4180 #define FILETIME_TO_U64(result, ft) \
4182 ULARGE_INTEGER uiTemp; \
4183 uiTemp.LowPart = (ft).dwLowDateTime; \
4184 uiTemp.HighPart = (ft).dwHighDateTime; \
4185 result = uiTemp.QuadPart; \
4189 initialize_utc_base (void)
4191 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4200 st
.wMilliseconds
= 0;
4202 SystemTimeToFileTime (&st
, &utc_base_ft
);
4203 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
4207 convert_time (FILETIME ft
)
4213 initialize_utc_base ();
4217 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
4220 FILETIME_TO_U64 (tmp
, ft
);
4221 return (time_t) ((tmp
- utc_base
) / 10000000L);
4225 convert_from_time_t (time_t time
, FILETIME
* pft
)
4231 initialize_utc_base ();
4235 /* time in 100ns units since 1-Jan-1601 */
4236 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
4237 pft
->dwHighDateTime
= tmp
.HighPart
;
4238 pft
->dwLowDateTime
= tmp
.LowPart
;
4241 static PSECURITY_DESCRIPTOR
4242 get_file_security_desc_by_handle (HANDLE h
)
4244 PSECURITY_DESCRIPTOR psd
= NULL
;
4246 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
4247 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
4249 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
4250 NULL
, NULL
, NULL
, NULL
, &psd
);
4251 if (err
!= ERROR_SUCCESS
)
4257 static PSECURITY_DESCRIPTOR
4258 get_file_security_desc_by_name (const char *fname
)
4260 PSECURITY_DESCRIPTOR psd
= NULL
;
4262 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
4263 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
4265 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
4267 err
= GetLastError ();
4268 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
4272 psd
= xmalloc (sd_len
);
4273 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
4285 unsigned n_subauthorities
;
4287 /* Use the last sub-authority value of the RID, the relative
4288 portion of the SID, as user/group ID. */
4289 n_subauthorities
= *get_sid_sub_authority_count (sid
);
4290 if (n_subauthorities
< 1)
4291 return 0; /* the "World" RID */
4292 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
4295 /* Caching SID and account values for faster lokup. */
4299 struct w32_id
*next
;
4301 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
4304 static struct w32_id
*w32_idlist
;
4307 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
4309 struct w32_id
*tail
, *found
;
4311 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
4313 if (equal_sid ((PSID
)tail
->sid
, sid
))
4322 strcpy (name
, found
->name
);
4330 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
4333 struct w32_id
*new_entry
;
4335 /* We don't want to leave behind stale cache from when Emacs was
4339 sid_len
= get_length_sid (sid
);
4340 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
4343 new_entry
->rid
= id
;
4344 strcpy (new_entry
->name
, name
);
4345 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
4346 new_entry
->next
= w32_idlist
;
4347 w32_idlist
= new_entry
;
4356 get_name_and_id (PSECURITY_DESCRIPTOR psd
, unsigned *id
, char *nm
, int what
)
4360 SID_NAME_USE ignore
;
4362 DWORD name_len
= sizeof (name
);
4364 DWORD domain_len
= sizeof (domain
);
4369 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
4370 else if (what
== GID
)
4371 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
4375 if (!result
|| !is_valid_sid (sid
))
4377 else if (!w32_cached_id (sid
, id
, nm
))
4379 if (!lookup_account_sid (NULL
, sid
, name
, &name_len
,
4380 domain
, &domain_len
, &ignore
)
4381 || name_len
> UNLEN
+1)
4385 *id
= get_rid (sid
);
4387 w32_add_to_cache (sid
, *id
, name
);
4394 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
, struct stat
*st
)
4396 int dflt_usr
= 0, dflt_grp
= 0;
4405 if (get_name_and_id (psd
, &st
->st_uid
, st
->st_uname
, UID
))
4407 if (get_name_and_id (psd
, &st
->st_gid
, st
->st_gname
, GID
))
4410 /* Consider files to belong to current user/group, if we cannot get
4411 more accurate information. */
4414 st
->st_uid
= dflt_passwd
.pw_uid
;
4415 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
4419 st
->st_gid
= dflt_passwd
.pw_gid
;
4420 strcpy (st
->st_gname
, dflt_group
.gr_name
);
4424 /* Return non-zero if NAME is a potentially slow filesystem. */
4426 is_slow_fs (const char *name
)
4431 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
4432 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
4433 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
4434 devtype
= GetDriveType (NULL
); /* use root of current drive */
4437 /* GetDriveType needs the root directory of the drive. */
4438 strncpy (drive_root
, name
, 2);
4439 drive_root
[2] = '\\';
4440 drive_root
[3] = '\0';
4441 devtype
= GetDriveType (drive_root
);
4443 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
4446 /* If this is non-zero, the caller wants accurate information about
4447 file's owner and group, which could be expensive to get. dired.c
4448 uses this flag when needed for the job at hand. */
4449 int w32_stat_get_owner_group
;
4451 /* MSVC stat function can't cope with UNC names and has other bugs, so
4452 replace it with our own. This also allows us to calculate consistent
4453 inode values and owner/group without hacks in the main Emacs code,
4454 and support file names encoded in UTF-8. */
4457 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
4459 char *name
, *save_name
, *r
;
4460 WIN32_FIND_DATAW wfd_w
;
4461 WIN32_FIND_DATAA wfd_a
;
4463 unsigned __int64 fake_inode
= 0;
4466 int rootdir
= FALSE
;
4467 PSECURITY_DESCRIPTOR psd
= NULL
;
4468 int is_a_symlink
= 0;
4469 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
4470 DWORD access_rights
= 0;
4471 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
4472 FILETIME ctime
, atime
, wtime
;
4473 wchar_t name_w
[MAX_PATH
];
4474 char name_a
[MAX_PATH
];
4476 if (path
== NULL
|| buf
== NULL
)
4482 save_name
= name
= (char *) map_w32_filename (path
, &path
);
4483 /* Must be valid filename, no wild cards or other invalid
4485 if (strpbrk (name
, "*?|<>\""))
4491 /* Remove trailing directory separator, unless name is the root
4492 directory of a drive or UNC volume in which case ensure there
4493 is a trailing separator. */
4494 len
= strlen (name
);
4495 name
= strcpy (alloca (len
+ 2), name
);
4497 /* Avoid a somewhat costly call to is_symlink if the filesystem
4498 doesn't support symlinks. */
4499 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
4500 is_a_symlink
= is_symlink (name
);
4502 /* Plan A: Open the file and get all the necessary information via
4503 the resulting handle. This solves several issues in one blow:
4505 . retrieves attributes for the target of a symlink, if needed
4506 . gets attributes of root directories and symlinks pointing to
4507 root directories, thus avoiding the need for special-casing
4508 these and detecting them by examining the file-name format
4509 . retrieves more accurate attributes (e.g., non-zero size for
4510 some directories, esp. directories that are junction points)
4511 . correctly resolves "c:/..", "/.." and similar file names
4512 . avoids run-time penalties for 99% of use cases
4514 Plan A is always tried first, unless the user asked not to (but
4515 if the file is a symlink and we need to follow links, we try Plan
4516 A even if the user asked not to).
4518 If Plan A fails, we go to Plan B (below), where various
4519 potentially expensive techniques must be used to handle "special"
4520 files such as UNC volumes etc. */
4521 if (!(NILP (Vw32_get_true_file_attributes
)
4522 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
4523 /* Following symlinks requires getting the info by handle. */
4524 || (is_a_symlink
&& follow_symlinks
))
4526 BY_HANDLE_FILE_INFORMATION info
;
4528 if (is_a_symlink
&& !follow_symlinks
)
4529 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
4530 /* READ_CONTROL access rights are required to get security info
4531 by handle. But if the OS doesn't support security in the
4532 first place, we don't need to try. */
4533 if (is_windows_9x () != TRUE
)
4534 access_rights
|= READ_CONTROL
;
4536 if (w32_unicode_filenames
)
4538 filename_to_utf16 (name
, name_w
);
4539 fh
= CreateFileW (name_w
, access_rights
, 0, NULL
, OPEN_EXISTING
,
4541 /* If CreateFile fails with READ_CONTROL, try again with
4542 zero as access rights. */
4543 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
4544 fh
= CreateFileW (name_w
, 0, 0, NULL
, OPEN_EXISTING
,
4549 filename_to_ansi (name
, name_a
);
4550 fh
= CreateFileA (name_a
, access_rights
, 0, NULL
, OPEN_EXISTING
,
4552 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
4553 fh
= CreateFileA (name_a
, 0, 0, NULL
, OPEN_EXISTING
,
4556 if (fh
== INVALID_HANDLE_VALUE
)
4557 goto no_true_file_attributes
;
4559 /* This is more accurate in terms of getting the correct number
4560 of links, but is quite slow (it is noticeable when Emacs is
4561 making a list of file name completions). */
4562 if (GetFileInformationByHandle (fh
, &info
))
4564 nlinks
= info
.nNumberOfLinks
;
4565 /* Might as well use file index to fake inode values, but this
4566 is not guaranteed to be unique unless we keep a handle open
4567 all the time (even then there are situations where it is
4568 not unique). Reputedly, there are at most 48 bits of info
4569 (on NTFS, presumably less on FAT). */
4570 fake_inode
= info
.nFileIndexHigh
;
4572 fake_inode
+= info
.nFileIndexLow
;
4573 serialnum
= info
.dwVolumeSerialNumber
;
4574 fs_high
= info
.nFileSizeHigh
;
4575 fs_low
= info
.nFileSizeLow
;
4576 ctime
= info
.ftCreationTime
;
4577 atime
= info
.ftLastAccessTime
;
4578 wtime
= info
.ftLastWriteTime
;
4579 fattrs
= info
.dwFileAttributes
;
4583 /* We don't go to Plan B here, because it's not clear that
4584 it's a good idea. The only known use case where
4585 CreateFile succeeds, but GetFileInformationByHandle fails
4586 (with ERROR_INVALID_FUNCTION) is for character devices
4587 such as NUL, PRN, etc. For these, switching to Plan B is
4588 a net loss, because we lose the character device
4589 attribute returned by GetFileType below (FindFirstFile
4590 doesn't set that bit in the attributes), and the other
4591 fields don't make sense for character devices anyway.
4592 Emacs doesn't really care for non-file entities in the
4593 context of l?stat, so neither do we. */
4595 /* w32err is assigned so one could put a breakpoint here and
4596 examine its value, when GetFileInformationByHandle
4598 DWORD w32err
= GetLastError ();
4602 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
4608 /* Test for a symlink before testing for a directory, since
4609 symlinks to directories have the directory bit set, but we
4610 don't want them to appear as directories. */
4611 if (is_a_symlink
&& !follow_symlinks
)
4612 buf
->st_mode
= S_IFLNK
;
4613 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4614 buf
->st_mode
= S_IFDIR
;
4617 DWORD ftype
= GetFileType (fh
);
4621 case FILE_TYPE_DISK
:
4622 buf
->st_mode
= S_IFREG
;
4624 case FILE_TYPE_PIPE
:
4625 buf
->st_mode
= S_IFIFO
;
4627 case FILE_TYPE_CHAR
:
4628 case FILE_TYPE_UNKNOWN
:
4630 buf
->st_mode
= S_IFCHR
;
4633 /* We produce the fallback owner and group data, based on the
4634 current user that runs Emacs, in the following cases:
4636 . caller didn't request owner and group info
4637 . this is Windows 9X
4638 . getting security by handle failed, and we need to produce
4639 information for the target of a symlink (this is better
4640 than producing a potentially misleading info about the
4643 If getting security by handle fails, and we don't need to
4644 resolve symlinks, we try getting security by name. */
4645 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4646 get_file_owner_and_group (NULL
, buf
);
4649 psd
= get_file_security_desc_by_handle (fh
);
4652 get_file_owner_and_group (psd
, buf
);
4655 else if (!(is_a_symlink
&& follow_symlinks
))
4657 psd
= get_file_security_desc_by_name (name
);
4658 get_file_owner_and_group (psd
, buf
);
4662 get_file_owner_and_group (NULL
, buf
);
4668 no_true_file_attributes
:
4669 /* Plan B: Either getting a handle on the file failed, or the
4670 caller explicitly asked us to not bother making this
4671 information more accurate.
4673 Implementation note: In Plan B, we never bother to resolve
4674 symlinks, even if we got here because we tried Plan A and
4675 failed. That's because, even if the caller asked for extra
4676 precision by setting Vw32_get_true_file_attributes to t,
4677 resolving symlinks requires acquiring a file handle to the
4678 symlink, which we already know will fail. And if the user
4679 did not ask for extra precision, resolving symlinks will fly
4680 in the face of that request, since the user then wants the
4681 lightweight version of the code. */
4682 rootdir
= (path
>= save_name
+ len
- 1
4683 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
4685 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4686 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
4687 if (IS_DIRECTORY_SEP (r
[0])
4688 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
4691 /* Note: If NAME is a symlink to the root of a UNC volume
4692 (i.e. "\\SERVER"), we will not detect that here, and we will
4693 return data about the symlink as result of FindFirst below.
4694 This is unfortunate, but that marginal use case does not
4695 justify a call to chase_symlinks which would impose a penalty
4696 on all the other use cases. (We get here for symlinks to
4697 roots of UNC volumes because CreateFile above fails for them,
4698 unlike with symlinks to root directories X:\ of drives.) */
4699 if (is_unc_volume (name
))
4701 fattrs
= unc_volume_file_attributes (name
);
4705 ctime
= atime
= wtime
= utc_base_ft
;
4709 if (!IS_DIRECTORY_SEP (name
[len
-1]))
4710 strcat (name
, "\\");
4711 if (GetDriveType (name
) < 2)
4717 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
4718 ctime
= atime
= wtime
= utc_base_ft
;
4724 if (IS_DIRECTORY_SEP (name
[len
-1]))
4727 /* (This is hacky, but helps when doing file completions on
4728 network drives.) Optimize by using information available from
4729 active readdir if possible. */
4730 len
= strlen (dir_pathname
);
4731 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
4733 if (dir_find_handle
!= INVALID_HANDLE_VALUE
4734 && last_dir_find_data
!= -1
4735 && !(is_a_symlink
&& follow_symlinks
)
4736 /* The 2 file-name comparisons below support only ASCII
4737 characters, and will lose (compare not equal) when
4738 the file names include non-ASCII charcaters that are
4739 the same but for the case. However, doing this
4740 properly involves: (a) converting both file names to
4741 UTF-16, (b) lower-casing both names using CharLowerW,
4742 and (c) comparing the results; this would be quite a
4743 bit slower, whereas Plan B is for users who want
4744 lightweight albeit inaccurate version of 'stat'. */
4745 && c_strncasecmp (save_name
, dir_pathname
, len
) == 0
4746 && IS_DIRECTORY_SEP (name
[len
])
4747 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
4749 have_wfd
= last_dir_find_data
;
4750 /* This was the last entry returned by readdir. */
4751 if (last_dir_find_data
== DIR_FIND_DATA_W
)
4752 wfd_w
= dir_find_data_w
;
4754 wfd_a
= dir_find_data_a
;
4758 logon_network_drive (name
);
4760 if (w32_unicode_filenames
)
4762 filename_to_utf16 (name
, name_w
);
4763 fh
= FindFirstFileW (name_w
, &wfd_w
);
4764 have_wfd
= DIR_FIND_DATA_W
;
4768 filename_to_ansi (name
, name_a
);
4769 /* If NAME includes characters not representable by
4770 the current ANSI codepage, filename_to_ansi
4771 usually replaces them with a '?'. We don't want
4772 to let FindFirstFileA interpret those as widlcards,
4773 and "succeed", returning us data from some random
4774 file in the same directory. */
4775 if (_mbspbrk (name_a
, "?"))
4776 fh
= INVALID_HANDLE_VALUE
;
4778 fh
= FindFirstFileA (name_a
, &wfd_a
);
4779 have_wfd
= DIR_FIND_DATA_A
;
4781 if (fh
== INVALID_HANDLE_VALUE
)
4788 /* Note: if NAME is a symlink, the information we get from
4789 FindFirstFile is for the symlink, not its target. */
4790 if (have_wfd
== DIR_FIND_DATA_W
)
4792 fattrs
= wfd_w
.dwFileAttributes
;
4793 ctime
= wfd_w
.ftCreationTime
;
4794 atime
= wfd_w
.ftLastAccessTime
;
4795 wtime
= wfd_w
.ftLastWriteTime
;
4796 fs_high
= wfd_w
.nFileSizeHigh
;
4797 fs_low
= wfd_w
.nFileSizeLow
;
4801 fattrs
= wfd_a
.dwFileAttributes
;
4802 ctime
= wfd_a
.ftCreationTime
;
4803 atime
= wfd_a
.ftLastAccessTime
;
4804 wtime
= wfd_a
.ftLastWriteTime
;
4805 fs_high
= wfd_a
.nFileSizeHigh
;
4806 fs_low
= wfd_a
.nFileSizeLow
;
4810 serialnum
= volume_info
.serialnum
;
4812 if (is_a_symlink
&& !follow_symlinks
)
4813 buf
->st_mode
= S_IFLNK
;
4814 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4815 buf
->st_mode
= S_IFDIR
;
4817 buf
->st_mode
= S_IFREG
;
4819 get_file_owner_and_group (NULL
, buf
);
4822 buf
->st_ino
= fake_inode
;
4824 buf
->st_dev
= serialnum
;
4825 buf
->st_rdev
= serialnum
;
4827 buf
->st_size
= fs_high
;
4828 buf
->st_size
<<= 32;
4829 buf
->st_size
+= fs_low
;
4830 buf
->st_nlink
= nlinks
;
4832 /* Convert timestamps to Unix format. */
4833 buf
->st_mtime
= convert_time (wtime
);
4834 buf
->st_atime
= convert_time (atime
);
4835 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4836 buf
->st_ctime
= convert_time (ctime
);
4837 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4839 /* determine rwx permissions */
4840 if (is_a_symlink
&& !follow_symlinks
)
4841 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
4844 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
4845 permission
= S_IREAD
;
4847 permission
= S_IREAD
| S_IWRITE
;
4849 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4850 permission
|= S_IEXEC
;
4851 else if (is_exec (name
))
4852 permission
|= S_IEXEC
;
4855 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4861 stat (const char * path
, struct stat
* buf
)
4863 return stat_worker (path
, buf
, 1);
4867 lstat (const char * path
, struct stat
* buf
)
4869 return stat_worker (path
, buf
, 0);
4873 fstatat (int fd
, char const *name
, struct stat
*st
, int flags
)
4875 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4876 This is good enough for the current usage in Emacs, but is fragile.
4878 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4879 Gnulib does this and can serve as a model. */
4880 char fullname
[MAX_UTF8_PATH
];
4884 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
4887 errno
= ENAMETOOLONG
;
4893 return stat_worker (name
, st
, ! (flags
& AT_SYMLINK_NOFOLLOW
));
4896 /* Provide fstat and utime as well as stat for consistent handling of
4899 fstat (int desc
, struct stat
* buf
)
4901 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
4902 BY_HANDLE_FILE_INFORMATION info
;
4903 unsigned __int64 fake_inode
;
4906 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
4908 case FILE_TYPE_DISK
:
4909 buf
->st_mode
= S_IFREG
;
4910 if (!GetFileInformationByHandle (fh
, &info
))
4916 case FILE_TYPE_PIPE
:
4917 buf
->st_mode
= S_IFIFO
;
4919 case FILE_TYPE_CHAR
:
4920 case FILE_TYPE_UNKNOWN
:
4922 buf
->st_mode
= S_IFCHR
;
4924 memset (&info
, 0, sizeof (info
));
4925 info
.dwFileAttributes
= 0;
4926 info
.ftCreationTime
= utc_base_ft
;
4927 info
.ftLastAccessTime
= utc_base_ft
;
4928 info
.ftLastWriteTime
= utc_base_ft
;
4931 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4932 buf
->st_mode
= S_IFDIR
;
4934 buf
->st_nlink
= info
.nNumberOfLinks
;
4935 /* Might as well use file index to fake inode values, but this
4936 is not guaranteed to be unique unless we keep a handle open
4937 all the time (even then there are situations where it is
4938 not unique). Reputedly, there are at most 48 bits of info
4939 (on NTFS, presumably less on FAT). */
4940 fake_inode
= info
.nFileIndexHigh
;
4942 fake_inode
+= info
.nFileIndexLow
;
4944 /* MSVC defines _ino_t to be short; other libc's might not. */
4945 if (sizeof (buf
->st_ino
) == 2)
4946 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
4948 buf
->st_ino
= fake_inode
;
4950 /* If the caller so requested, get the true file owner and group.
4951 Otherwise, consider the file to belong to the current user. */
4952 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4953 get_file_owner_and_group (NULL
, buf
);
4956 PSECURITY_DESCRIPTOR psd
= NULL
;
4958 psd
= get_file_security_desc_by_handle (fh
);
4961 get_file_owner_and_group (psd
, buf
);
4965 get_file_owner_and_group (NULL
, buf
);
4968 buf
->st_dev
= info
.dwVolumeSerialNumber
;
4969 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
4971 buf
->st_size
= info
.nFileSizeHigh
;
4972 buf
->st_size
<<= 32;
4973 buf
->st_size
+= info
.nFileSizeLow
;
4975 /* Convert timestamps to Unix format. */
4976 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
4977 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
4978 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4979 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
4980 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4982 /* determine rwx permissions */
4983 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
4984 permission
= S_IREAD
;
4986 permission
= S_IREAD
| S_IWRITE
;
4988 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4989 permission
|= S_IEXEC
;
4992 #if 0 /* no way of knowing the filename */
4993 char * p
= strrchr (name
, '.');
4995 (xstrcasecmp (p
, ".exe") == 0 ||
4996 xstrcasecmp (p
, ".com") == 0 ||
4997 xstrcasecmp (p
, ".bat") == 0 ||
4998 xstrcasecmp (p
, ".cmd") == 0))
4999 permission
|= S_IEXEC
;
5003 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
5008 /* A version of 'utime' which handles directories as well as
5012 utime (const char *name
, struct utimbuf
*times
)
5014 struct utimbuf deftime
;
5021 deftime
.modtime
= deftime
.actime
= time (NULL
);
5025 if (w32_unicode_filenames
)
5027 wchar_t name_utf16
[MAX_PATH
];
5029 if (filename_to_utf16 (name
, name_utf16
) != 0)
5030 return -1; /* errno set by filename_to_utf16 */
5032 /* Need write access to set times. */
5033 fh
= CreateFileW (name_utf16
, FILE_WRITE_ATTRIBUTES
,
5034 /* If NAME specifies a directory, FILE_SHARE_DELETE
5035 allows other processes to delete files inside it,
5036 while we have the directory open. */
5037 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
5038 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
5042 char name_ansi
[MAX_PATH
];
5044 if (filename_to_ansi (name
, name_ansi
) != 0)
5045 return -1; /* errno set by filename_to_ansi */
5047 fh
= CreateFileA (name_ansi
, FILE_WRITE_ATTRIBUTES
,
5048 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
5049 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
5051 if (fh
!= INVALID_HANDLE_VALUE
)
5053 convert_from_time_t (times
->actime
, &atime
);
5054 convert_from_time_t (times
->modtime
, &mtime
);
5055 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
5065 DWORD err
= GetLastError ();
5069 case ERROR_FILE_NOT_FOUND
:
5070 case ERROR_PATH_NOT_FOUND
:
5071 case ERROR_INVALID_DRIVE
:
5072 case ERROR_BAD_NETPATH
:
5073 case ERROR_DEV_NOT_EXIST
:
5074 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5075 file name includes ?s, i.e. translation to ANSI failed. */
5076 case ERROR_INVALID_NAME
:
5079 case ERROR_TOO_MANY_OPEN_FILES
:
5082 case ERROR_ACCESS_DENIED
:
5083 case ERROR_SHARING_VIOLATION
:
5096 /* Symlink-related functions. */
5097 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5098 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5102 symlink (char const *filename
, char const *linkname
)
5104 char linkfn
[MAX_UTF8_PATH
], *tgtfn
;
5106 int dir_access
, filename_ends_in_slash
;
5108 /* Diagnostics follows Posix as much as possible. */
5109 if (filename
== NULL
|| linkname
== NULL
)
5119 if (strlen (filename
) > MAX_UTF8_PATH
|| strlen (linkname
) > MAX_UTF8_PATH
)
5121 errno
= ENAMETOOLONG
;
5125 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
5126 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
5132 /* Note: since empty FILENAME was already rejected, we can safely
5133 refer to FILENAME[1]. */
5134 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
5136 /* Non-absolute FILENAME is understood as being relative to
5137 LINKNAME's directory. We need to prepend that directory to
5138 FILENAME to get correct results from faccessat below, since
5139 otherwise it will interpret FILENAME relative to the
5140 directory where the Emacs process runs. Note that
5141 make-symbolic-link always makes sure LINKNAME is a fully
5142 expanded file name. */
5143 char tem
[MAX_UTF8_PATH
];
5144 char *p
= linkfn
+ strlen (linkfn
);
5146 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
5149 strncpy (tem
, linkfn
, p
- linkfn
);
5150 tem
[p
- linkfn
] = '\0';
5151 strcat (tem
, filename
);
5152 dir_access
= faccessat (AT_FDCWD
, tem
, D_OK
, AT_EACCESS
);
5155 dir_access
= faccessat (AT_FDCWD
, filename
, D_OK
, AT_EACCESS
);
5157 /* Since Windows distinguishes between symlinks to directories and
5158 to files, we provide a kludgy feature: if FILENAME doesn't
5159 exist, but ends in a slash, we create a symlink to directory. If
5160 FILENAME exists and is a directory, we always create a symlink to
5162 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
5163 if (dir_access
== 0 || filename_ends_in_slash
)
5164 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
5166 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
5167 if (filename_ends_in_slash
)
5168 tgtfn
[strlen (tgtfn
) - 1] = '\0';
5171 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
5173 /* ENOSYS is set by create_symbolic_link, when it detects that
5174 the OS doesn't support the CreateSymbolicLink API. */
5175 if (errno
!= ENOSYS
)
5177 DWORD w32err
= GetLastError ();
5181 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5182 TGTFN point to the same file name, go figure. */
5184 case ERROR_FILE_EXISTS
:
5187 case ERROR_ACCESS_DENIED
:
5190 case ERROR_FILE_NOT_FOUND
:
5191 case ERROR_PATH_NOT_FOUND
:
5192 case ERROR_BAD_NETPATH
:
5193 case ERROR_INVALID_REPARSE_DATA
:
5196 case ERROR_DIRECTORY
:
5199 case ERROR_PRIVILEGE_NOT_HELD
:
5200 case ERROR_NOT_ALL_ASSIGNED
:
5203 case ERROR_DISK_FULL
:
5216 /* A quick inexpensive test of whether FILENAME identifies a file that
5217 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5218 must already be in the normalized form returned by
5221 Note: for repeated operations on many files, it is best to test
5222 whether the underlying volume actually supports symlinks, by
5223 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5224 avoid the call to this function if it doesn't. That's because the
5225 call to GetFileAttributes takes a non-negligible time, especially
5226 on non-local or removable filesystems. See stat_worker for an
5227 example of how to do that. */
5229 is_symlink (const char *filename
)
5232 wchar_t filename_w
[MAX_PATH
];
5233 char filename_a
[MAX_PATH
];
5234 WIN32_FIND_DATAW wfdw
;
5235 WIN32_FIND_DATAA wfda
;
5237 int attrs_mean_symlink
;
5239 if (w32_unicode_filenames
)
5241 filename_to_utf16 (filename
, filename_w
);
5242 attrs
= GetFileAttributesW (filename_w
);
5246 filename_to_ansi (filename
, filename_a
);
5247 attrs
= GetFileAttributesA (filename_a
);
5251 DWORD w32err
= GetLastError ();
5255 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
5257 case ERROR_ACCESS_DENIED
:
5260 case ERROR_FILE_NOT_FOUND
:
5261 case ERROR_PATH_NOT_FOUND
:
5268 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
5270 logon_network_drive (filename
);
5271 if (w32_unicode_filenames
)
5273 fh
= FindFirstFileW (filename_w
, &wfdw
);
5274 attrs_mean_symlink
=
5275 (wfdw
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
5276 && (wfdw
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
5278 else if (_mbspbrk (filename_a
, "?"))
5280 /* filename_to_ansi failed to convert the file name. */
5286 fh
= FindFirstFileA (filename_a
, &wfda
);
5287 attrs_mean_symlink
=
5288 (wfda
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
5289 && (wfda
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
5291 if (fh
== INVALID_HANDLE_VALUE
)
5294 return attrs_mean_symlink
;
5297 /* If NAME identifies a symbolic link, copy into BUF the file name of
5298 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5299 null-terminate the target name, even if it fits. Return the number
5300 of bytes copied, or -1 if NAME is not a symlink or any error was
5301 encountered while resolving it. The file name copied into BUF is
5302 encoded in the current ANSI codepage. */
5304 readlink (const char *name
, char *buf
, size_t buf_size
)
5307 TOKEN_PRIVILEGES privs
;
5308 int restore_privs
= 0;
5311 char resolved
[MAX_UTF8_PATH
];
5324 path
= map_w32_filename (name
, NULL
);
5326 if (strlen (path
) > MAX_UTF8_PATH
)
5328 errno
= ENAMETOOLONG
;
5333 if (is_windows_9x () == TRUE
5334 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
5335 || !is_symlink (path
))
5338 errno
= EINVAL
; /* not a symlink */
5342 /* Done with simple tests, now we're in for some _real_ work. */
5343 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
5345 /* Implementation note: From here and onward, don't return early,
5346 since that will fail to restore the original set of privileges of
5347 the calling thread. */
5349 retval
= -1; /* not too optimistic, are we? */
5351 /* Note: In the next call to CreateFile, we use zero as the 2nd
5352 argument because, when the symlink is a hidden/system file,
5353 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5354 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5355 and directory symlinks. */
5356 if (w32_unicode_filenames
)
5358 wchar_t path_w
[MAX_PATH
];
5360 filename_to_utf16 (path
, path_w
);
5361 sh
= CreateFileW (path_w
, 0, 0, NULL
, OPEN_EXISTING
,
5362 FILE_FLAG_OPEN_REPARSE_POINT
5363 | FILE_FLAG_BACKUP_SEMANTICS
,
5368 char path_a
[MAX_PATH
];
5370 filename_to_ansi (path
, path_a
);
5371 sh
= CreateFileA (path_a
, 0, 0, NULL
, OPEN_EXISTING
,
5372 FILE_FLAG_OPEN_REPARSE_POINT
5373 | FILE_FLAG_BACKUP_SEMANTICS
,
5376 if (sh
!= INVALID_HANDLE_VALUE
)
5378 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
5379 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
5382 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
5383 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
5386 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
5390 /* Copy the link target name, in wide characters, from
5391 reparse_data, then convert it to multibyte encoding in
5392 the current locale's codepage. */
5396 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
5398 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
5399 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
5400 size_t size_to_copy
= buf_size
;
5402 /* According to MSDN, PrintNameLength does not include the
5403 terminating null character. */
5404 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
5405 memcpy (lwname
, lwname_src
, lwname_len
);
5406 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
5407 filename_from_utf16 (lwname
, resolved
);
5408 dostounix_filename (resolved
);
5409 lname_size
= strlen (resolved
) + 1;
5410 if (lname_size
<= buf_size
)
5411 size_to_copy
= lname_size
;
5412 strncpy (buf
, resolved
, size_to_copy
);
5414 retval
= size_to_copy
;
5420 /* CreateFile failed. */
5421 DWORD w32err2
= GetLastError ();
5425 case ERROR_FILE_NOT_FOUND
:
5426 case ERROR_PATH_NOT_FOUND
:
5429 case ERROR_ACCESS_DENIED
:
5430 case ERROR_TOO_MANY_OPEN_FILES
:
5440 restore_privilege (&privs
);
5448 readlinkat (int fd
, char const *name
, char *buffer
,
5451 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5452 as in fstatat. FIXME: Add proper support for readlinkat. */
5453 char fullname
[MAX_UTF8_PATH
];
5457 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
5460 errno
= ENAMETOOLONG
;
5466 return readlink (name
, buffer
, buffer_size
);
5469 /* If FILE is a symlink, return its target (stored in a static
5470 buffer); otherwise return FILE.
5472 This function repeatedly resolves symlinks in the last component of
5473 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5474 until it arrives at a file whose last component is not a symlink,
5475 or some error occurs. It returns the target of the last
5476 successfully resolved symlink in the chain. If it succeeds to
5477 resolve even a single symlink, the value returned is an absolute
5478 file name with backslashes (result of GetFullPathName). By
5479 contrast, if the original FILE is returned, it is unaltered.
5481 Note: This function can set errno even if it succeeds.
5483 Implementation note: we only resolve the last portion ("basename")
5484 of the argument FILE and of each following file in the chain,
5485 disregarding any possible symlinks in its leading directories.
5486 This is because Windows system calls and library functions
5487 transparently resolve symlinks in leading directories and return
5488 correct information, as long as the basename is not a symlink. */
5490 chase_symlinks (const char *file
)
5492 static char target
[MAX_UTF8_PATH
];
5493 char link
[MAX_UTF8_PATH
];
5494 wchar_t target_w
[MAX_PATH
], link_w
[MAX_PATH
];
5495 char target_a
[MAX_PATH
], link_a
[MAX_PATH
];
5496 ssize_t res
, link_len
;
5499 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
5500 return (char *)file
;
5502 if (w32_unicode_filenames
)
5504 wchar_t file_w
[MAX_PATH
];
5506 filename_to_utf16 (file
, file_w
);
5507 if (GetFullPathNameW (file_w
, MAX_PATH
, link_w
, NULL
) == 0)
5508 return (char *)file
;
5509 filename_from_utf16 (link_w
, link
);
5513 char file_a
[MAX_PATH
];
5515 filename_to_ansi (file
, file_a
);
5516 if (GetFullPathNameA (file_a
, MAX_PATH
, link_a
, NULL
) == 0)
5517 return (char *)file
;
5518 filename_from_ansi (link_a
, link
);
5520 link_len
= strlen (link
);
5525 /* Remove trailing slashes, as we want to resolve the last
5526 non-trivial part of the link name. */
5527 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
5528 link
[link_len
--] = '\0';
5530 res
= readlink (link
, target
, MAX_UTF8_PATH
);
5534 if (!(IS_DEVICE_SEP (target
[1])
5535 || (IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1]))))
5537 /* Target is relative. Append it to the directory part of
5538 the symlink, then copy the result back to target. */
5539 char *p
= link
+ link_len
;
5541 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
5544 strcpy (target
, link
);
5546 /* Resolve any "." and ".." to get a fully-qualified file name
5548 if (w32_unicode_filenames
)
5550 filename_to_utf16 (target
, target_w
);
5551 link_len
= GetFullPathNameW (target_w
, MAX_PATH
, link_w
, NULL
);
5553 filename_from_utf16 (link_w
, link
);
5557 filename_to_ansi (target
, target_a
);
5558 link_len
= GetFullPathNameA (target_a
, MAX_PATH
, link_a
, NULL
);
5560 filename_from_ansi (link_a
, link
);
5562 link_len
= strlen (link
);
5564 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
5566 if (loop_count
> 100)
5569 if (target
[0] == '\0') /* not a single call to readlink succeeded */
5570 return (char *)file
;
5575 /* Posix ACL emulation. */
5578 acl_valid (acl_t acl
)
5580 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR
)acl
) ? 0 : -1;
5584 acl_to_text (acl_t acl
, ssize_t
*size
)
5587 SECURITY_INFORMATION flags
=
5588 OWNER_SECURITY_INFORMATION
|
5589 GROUP_SECURITY_INFORMATION
|
5590 DACL_SECURITY_INFORMATION
;
5591 char *retval
= NULL
;
5597 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR
)acl
, SDDL_REVISION_1
, flags
, &str_acl
, &local_size
))
5600 /* We don't want to mix heaps, so we duplicate the string in our
5601 heap and free the one allocated by the API. */
5602 retval
= xstrdup (str_acl
);
5605 LocalFree (str_acl
);
5607 else if (errno
!= ENOTSUP
)
5614 acl_from_text (const char *acl_str
)
5616 PSECURITY_DESCRIPTOR psd
, retval
= NULL
;
5622 if (convert_sddl_to_sd (acl_str
, SDDL_REVISION_1
, &psd
, &sd_size
))
5625 retval
= xmalloc (sd_size
);
5626 memcpy (retval
, psd
, sd_size
);
5629 else if (errno
!= ENOTSUP
)
5636 acl_free (void *ptr
)
5643 acl_get_file (const char *fname
, acl_type_t type
)
5645 PSECURITY_DESCRIPTOR psd
= NULL
;
5646 const char *filename
;
5648 if (type
== ACL_TYPE_ACCESS
)
5651 SECURITY_INFORMATION si
=
5652 OWNER_SECURITY_INFORMATION
|
5653 GROUP_SECURITY_INFORMATION
|
5654 DACL_SECURITY_INFORMATION
;
5657 filename
= map_w32_filename (fname
, NULL
);
5658 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5659 fname
= chase_symlinks (filename
);
5664 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
)
5665 && errno
!= ENOTSUP
)
5667 err
= GetLastError ();
5668 if (err
== ERROR_INSUFFICIENT_BUFFER
)
5670 psd
= xmalloc (sd_len
);
5671 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
5678 else if (err
== ERROR_FILE_NOT_FOUND
5679 || err
== ERROR_PATH_NOT_FOUND
5680 /* ERROR_INVALID_NAME is what we get if
5681 w32-unicode-filenames is nil and the file cannot
5682 be encoded in the current ANSI codepage. */
5683 || err
== ERROR_INVALID_NAME
)
5691 else if (type
!= ACL_TYPE_DEFAULT
)
5698 acl_set_file (const char *fname
, acl_type_t type
, acl_t acl
)
5700 TOKEN_PRIVILEGES old1
, old2
;
5702 int st
= 0, retval
= -1;
5703 SECURITY_INFORMATION flags
= 0;
5709 const char *filename
;
5711 if (acl_valid (acl
) != 0
5712 || (type
!= ACL_TYPE_DEFAULT
&& type
!= ACL_TYPE_ACCESS
))
5718 if (type
== ACL_TYPE_DEFAULT
)
5724 filename
= map_w32_filename (fname
, NULL
);
5725 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5726 fname
= chase_symlinks (filename
);
5730 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5732 flags
|= OWNER_SECURITY_INFORMATION
;
5733 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5735 flags
|= GROUP_SECURITY_INFORMATION
;
5736 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR
)acl
, &dacl_present
,
5739 flags
|= DACL_SECURITY_INFORMATION
;
5743 /* According to KB-245153, setting the owner will succeed if either:
5744 (1) the caller is the user who will be the new owner, and has the
5745 SE_TAKE_OWNERSHIP privilege, or
5746 (2) the caller has the SE_RESTORE privilege, in which case she can
5747 set any valid user or group as the owner
5749 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5750 privileges, and disregard any failures in obtaining them. If
5751 these privileges cannot be obtained, and do not already exist in
5752 the calling thread's security token, this function could fail
5754 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME
, TRUE
, &old1
))
5756 if (enable_privilege (SE_RESTORE_NAME
, TRUE
, &old2
))
5761 if (!set_file_security (fname
, flags
, (PSECURITY_DESCRIPTOR
)acl
))
5763 err
= GetLastError ();
5765 if (errno
== ENOTSUP
)
5767 else if (err
== ERROR_INVALID_OWNER
5768 || err
== ERROR_NOT_ALL_ASSIGNED
5769 || err
== ERROR_ACCESS_DENIED
)
5771 /* Maybe the requested ACL and the one the file already has
5772 are identical, in which case we can silently ignore the
5773 failure. (And no, Windows doesn't.) */
5774 acl_t current_acl
= acl_get_file (fname
, ACL_TYPE_ACCESS
);
5779 char *acl_from
= acl_to_text (current_acl
, NULL
);
5780 char *acl_to
= acl_to_text (acl
, NULL
);
5782 if (acl_from
&& acl_to
&& xstrcasecmp (acl_from
, acl_to
) == 0)
5788 acl_free (acl_from
);
5791 acl_free (current_acl
);
5794 else if (err
== ERROR_FILE_NOT_FOUND
5795 || err
== ERROR_PATH_NOT_FOUND
5796 /* ERROR_INVALID_NAME is what we get if
5797 w32-unicode-filenames is nil and the file cannot be
5798 encoded in the current ANSI codepage. */
5799 || err
== ERROR_INVALID_NAME
)
5813 restore_privilege (&old2
);
5814 restore_privilege (&old1
);
5822 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5823 have a fixed max size for file names, so we don't need the kind of
5824 alloc/malloc/realloc dance the gnulib version does. We also don't
5825 support FD-relative symlinks. */
5827 careadlinkat (int fd
, char const *filename
,
5828 char *buffer
, size_t buffer_size
,
5829 struct allocator
const *alloc
,
5830 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
5832 char linkname
[MAX_UTF8_PATH
];
5835 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
5839 char *retval
= buffer
;
5841 linkname
[link_size
++] = '\0';
5842 if (link_size
> buffer_size
)
5843 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
5845 memcpy (retval
, linkname
, link_size
);
5853 /* Support for browsing other processes and their attributes. See
5854 process.c for the Lisp bindings. */
5856 /* Helper wrapper functions. */
5858 static HANDLE WINAPI
5859 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
5861 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
5863 if (g_b_init_create_toolhelp32_snapshot
== 0)
5865 g_b_init_create_toolhelp32_snapshot
= 1;
5866 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
5867 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5868 "CreateToolhelp32Snapshot");
5870 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
5872 return INVALID_HANDLE_VALUE
;
5874 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
5878 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5880 static Process32First_Proc s_pfn_Process32_First
= NULL
;
5882 if (g_b_init_process32_first
== 0)
5884 g_b_init_process32_first
= 1;
5885 s_pfn_Process32_First
= (Process32First_Proc
)
5886 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5889 if (s_pfn_Process32_First
== NULL
)
5893 return (s_pfn_Process32_First (hSnapshot
, lppe
));
5897 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5899 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
5901 if (g_b_init_process32_next
== 0)
5903 g_b_init_process32_next
= 1;
5904 s_pfn_Process32_Next
= (Process32Next_Proc
)
5905 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5908 if (s_pfn_Process32_Next
== NULL
)
5912 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
5916 open_thread_token (HANDLE ThreadHandle
,
5917 DWORD DesiredAccess
,
5919 PHANDLE TokenHandle
)
5921 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
5922 HMODULE hm_advapi32
= NULL
;
5923 if (is_windows_9x () == TRUE
)
5925 SetLastError (ERROR_NOT_SUPPORTED
);
5928 if (g_b_init_open_thread_token
== 0)
5930 g_b_init_open_thread_token
= 1;
5931 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5932 s_pfn_Open_Thread_Token
=
5933 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
5935 if (s_pfn_Open_Thread_Token
== NULL
)
5937 SetLastError (ERROR_NOT_SUPPORTED
);
5941 s_pfn_Open_Thread_Token (
5950 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
5952 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
5953 HMODULE hm_advapi32
= NULL
;
5954 if (is_windows_9x () == TRUE
)
5958 if (g_b_init_impersonate_self
== 0)
5960 g_b_init_impersonate_self
= 1;
5961 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5962 s_pfn_Impersonate_Self
=
5963 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
5965 if (s_pfn_Impersonate_Self
== NULL
)
5969 return s_pfn_Impersonate_Self (ImpersonationLevel
);
5973 revert_to_self (void)
5975 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
5976 HMODULE hm_advapi32
= NULL
;
5977 if (is_windows_9x () == TRUE
)
5981 if (g_b_init_revert_to_self
== 0)
5983 g_b_init_revert_to_self
= 1;
5984 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5985 s_pfn_Revert_To_Self
=
5986 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
5988 if (s_pfn_Revert_To_Self
== NULL
)
5992 return s_pfn_Revert_To_Self ();
5996 get_process_memory_info (HANDLE h_proc
,
5997 PPROCESS_MEMORY_COUNTERS mem_counters
,
6000 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
6001 HMODULE hm_psapi
= NULL
;
6002 if (is_windows_9x () == TRUE
)
6006 if (g_b_init_get_process_memory_info
== 0)
6008 g_b_init_get_process_memory_info
= 1;
6009 hm_psapi
= LoadLibrary ("Psapi.dll");
6011 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
6012 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
6014 if (s_pfn_Get_Process_Memory_Info
== NULL
)
6018 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
6022 get_process_working_set_size (HANDLE h_proc
,
6026 static GetProcessWorkingSetSize_Proc
6027 s_pfn_Get_Process_Working_Set_Size
= NULL
;
6029 if (is_windows_9x () == TRUE
)
6033 if (g_b_init_get_process_working_set_size
== 0)
6035 g_b_init_get_process_working_set_size
= 1;
6036 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
6037 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6038 "GetProcessWorkingSetSize");
6040 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
6044 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
6048 global_memory_status (MEMORYSTATUS
*buf
)
6050 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
6052 if (is_windows_9x () == TRUE
)
6056 if (g_b_init_global_memory_status
== 0)
6058 g_b_init_global_memory_status
= 1;
6059 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
6060 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6061 "GlobalMemoryStatus");
6063 if (s_pfn_Global_Memory_Status
== NULL
)
6067 return s_pfn_Global_Memory_Status (buf
);
6071 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
6073 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
6075 if (is_windows_9x () == TRUE
)
6079 if (g_b_init_global_memory_status_ex
== 0)
6081 g_b_init_global_memory_status_ex
= 1;
6082 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
6083 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6084 "GlobalMemoryStatusEx");
6086 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
6090 return s_pfn_Global_Memory_Status_Ex (buf
);
6094 list_system_processes (void)
6096 struct gcpro gcpro1
;
6097 Lisp_Object proclist
= Qnil
;
6100 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
6102 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
6104 PROCESSENTRY32 proc_entry
;
6110 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
6111 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
6112 res
= process32_next (h_snapshot
, &proc_entry
))
6114 proc_id
= proc_entry
.th32ProcessID
;
6115 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
6118 CloseHandle (h_snapshot
);
6120 proclist
= Fnreverse (proclist
);
6127 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
6129 TOKEN_PRIVILEGES priv
;
6130 DWORD priv_size
= sizeof (priv
);
6131 DWORD opriv_size
= sizeof (*old_priv
);
6132 HANDLE h_token
= NULL
;
6133 HANDLE h_thread
= GetCurrentThread ();
6137 res
= open_thread_token (h_thread
,
6138 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
6140 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
6142 if (impersonate_self (SecurityImpersonation
))
6143 res
= open_thread_token (h_thread
,
6144 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
6149 priv
.PrivilegeCount
= 1;
6150 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
6151 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
6152 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
6153 old_priv
, &opriv_size
)
6154 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
6158 CloseHandle (h_token
);
6164 restore_privilege (TOKEN_PRIVILEGES
*priv
)
6166 DWORD priv_size
= sizeof (*priv
);
6167 HANDLE h_token
= NULL
;
6170 if (open_thread_token (GetCurrentThread (),
6171 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
6174 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
6175 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
6179 CloseHandle (h_token
);
6185 ltime (ULONGLONG time_100ns
)
6187 ULONGLONG time_sec
= time_100ns
/ 10000000;
6188 int subsec
= time_100ns
% 10000000;
6189 return list4i (time_sec
>> 16, time_sec
& 0xffff,
6190 subsec
/ 10, subsec
% 10 * 100000);
6193 #define U64_TO_LISP_TIME(time) ltime (time)
6196 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
6197 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
6200 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
6201 ULONGLONG tem1
, tem2
, tem3
, tem
;
6204 || !get_process_times_fn
6205 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
6206 &ft_kernel
, &ft_user
))
6209 GetSystemTimeAsFileTime (&ft_current
);
6211 FILETIME_TO_U64 (tem1
, ft_kernel
);
6212 *stime
= U64_TO_LISP_TIME (tem1
);
6214 FILETIME_TO_U64 (tem2
, ft_user
);
6215 *utime
= U64_TO_LISP_TIME (tem2
);
6218 *ttime
= U64_TO_LISP_TIME (tem3
);
6220 FILETIME_TO_U64 (tem
, ft_creation
);
6221 /* Process no 4 (System) returns zero creation time. */
6224 *ctime
= U64_TO_LISP_TIME (tem
);
6228 FILETIME_TO_U64 (tem3
, ft_current
);
6229 tem
= (tem3
- utc_base
) - tem
;
6231 *etime
= U64_TO_LISP_TIME (tem
);
6235 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
6246 system_process_attributes (Lisp_Object pid
)
6248 struct gcpro gcpro1
, gcpro2
, gcpro3
;
6249 Lisp_Object attrs
= Qnil
;
6250 Lisp_Object cmd_str
, decoded_cmd
, tem
;
6251 HANDLE h_snapshot
, h_proc
;
6254 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
6255 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
6256 DWORD glength
= sizeof (gname
);
6257 HANDLE token
= NULL
;
6258 SID_NAME_USE user_type
;
6259 unsigned char *buf
= NULL
;
6261 TOKEN_USER user_token
;
6262 TOKEN_PRIMARY_GROUP group_token
;
6265 PROCESS_MEMORY_COUNTERS mem
;
6266 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
6267 SIZE_T minrss
, maxrss
;
6269 MEMORY_STATUS_EX memstex
;
6270 double totphys
= 0.0;
6271 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
6273 BOOL result
= FALSE
;
6275 CHECK_NUMBER_OR_FLOAT (pid
);
6276 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
6278 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
6280 GCPRO3 (attrs
, decoded_cmd
, tem
);
6282 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
6287 pe
.dwSize
= sizeof (PROCESSENTRY32
);
6288 for (res
= process32_first (h_snapshot
, &pe
); res
;
6289 res
= process32_next (h_snapshot
, &pe
))
6291 if (proc_id
== pe
.th32ProcessID
)
6294 decoded_cmd
= build_string ("Idle");
6297 /* Decode the command name from locale-specific
6299 cmd_str
= build_unibyte_string (pe
.szExeFile
);
6302 code_convert_string_norecord (cmd_str
,
6303 Vlocale_coding_system
, 0);
6305 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
6306 attrs
= Fcons (Fcons (Qppid
,
6307 make_fixnum_or_float (pe
.th32ParentProcessID
)),
6309 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
6311 attrs
= Fcons (Fcons (Qthcount
,
6312 make_fixnum_or_float (pe
.cntThreads
)),
6319 CloseHandle (h_snapshot
);
6328 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
6330 /* If we were denied a handle to the process, try again after
6331 enabling the SeDebugPrivilege in our process. */
6334 TOKEN_PRIVILEGES priv_current
;
6336 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
6338 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
6340 restore_privilege (&priv_current
);
6346 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
6349 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
6350 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
6352 buf
= xmalloc (blen
);
6353 result
= get_token_information (token
, TokenUser
,
6354 (LPVOID
)buf
, blen
, &needed
);
6357 memcpy (&user_token
, buf
, sizeof (user_token
));
6358 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
6360 euid
= get_rid (user_token
.User
.Sid
);
6361 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
6366 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
6369 strcpy (uname
, "unknown");
6373 ulength
= strlen (uname
);
6379 /* Determine a reasonable euid and gid values. */
6380 if (xstrcasecmp ("administrator", uname
) == 0)
6382 euid
= 500; /* well-known Administrator uid */
6383 egid
= 513; /* well-known None gid */
6387 /* Get group id and name. */
6388 result
= get_token_information (token
, TokenPrimaryGroup
,
6389 (LPVOID
)buf
, blen
, &needed
);
6390 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
6392 buf
= xrealloc (buf
, blen
= needed
);
6393 result
= get_token_information (token
, TokenPrimaryGroup
,
6394 (LPVOID
)buf
, blen
, &needed
);
6398 memcpy (&group_token
, buf
, sizeof (group_token
));
6399 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
6401 egid
= get_rid (group_token
.PrimaryGroup
);
6402 dlength
= sizeof (domain
);
6404 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
6405 gname
, &glength
, NULL
, &dlength
,
6408 w32_add_to_cache (group_token
.PrimaryGroup
,
6412 strcpy (gname
, "None");
6416 glength
= strlen (gname
);
6424 if (!is_windows_9x ())
6426 /* We couldn't open the process token, presumably because of
6427 insufficient access rights. Assume this process is run
6429 strcpy (uname
, "SYSTEM");
6430 strcpy (gname
, "None");
6431 euid
= 18; /* SYSTEM */
6432 egid
= 513; /* None */
6433 glength
= strlen (gname
);
6434 ulength
= strlen (uname
);
6436 /* If we are running under Windows 9X, where security calls are
6437 not supported, we assume all processes are run by the current
6439 else if (GetUserName (uname
, &ulength
))
6441 if (xstrcasecmp ("administrator", uname
) == 0)
6446 strcpy (gname
, "None");
6447 glength
= strlen (gname
);
6448 ulength
= strlen (uname
);
6454 strcpy (uname
, "administrator");
6455 ulength
= strlen (uname
);
6456 strcpy (gname
, "None");
6457 glength
= strlen (gname
);
6460 CloseHandle (token
);
6463 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
6464 tem
= make_unibyte_string (uname
, ulength
);
6465 attrs
= Fcons (Fcons (Quser
,
6466 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
6468 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
6469 tem
= make_unibyte_string (gname
, glength
);
6470 attrs
= Fcons (Fcons (Qgroup
,
6471 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
6474 if (global_memory_status_ex (&memstex
))
6475 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6476 totphys
= memstex
.ullTotalPhys
/ 1024.0;
6478 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6479 double, so we need to do this for it... */
6481 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
6482 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
6483 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
6485 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
6487 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6488 else if (global_memory_status (&memst
))
6489 totphys
= memst
.dwTotalPhys
/ 1024.0;
6492 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
6495 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
6497 attrs
= Fcons (Fcons (Qmajflt
,
6498 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
6500 attrs
= Fcons (Fcons (Qvsize
,
6501 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
6503 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
6505 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6508 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
6510 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
6512 attrs
= Fcons (Fcons (Qmajflt
,
6513 make_fixnum_or_float (mem
.PageFaultCount
)),
6515 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
6517 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6520 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
6522 DWORD rss
= maxrss
/ 1024;
6524 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
6526 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6529 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
6531 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
6532 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
6533 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
6534 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
6535 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
6536 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
6539 /* FIXME: Retrieve command line by walking the PEB of the process. */
6542 CloseHandle (h_proc
);
6548 /* Wrappers for winsock functions to map between our file descriptors
6549 and winsock's handles; also set h_errno for convenience.
6551 To allow Emacs to run on systems which don't have winsock support
6552 installed, we dynamically link to winsock on startup if present, and
6553 otherwise provide the minimum necessary functionality
6554 (eg. gethostname). */
6556 /* function pointers for relevant socket functions */
6557 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
6558 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
6559 int (PASCAL
*pfn_WSAGetLastError
) (void);
6560 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
6561 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
6562 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
6563 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
6564 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6565 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6566 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
6567 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
6568 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
6569 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
6570 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
6571 int (PASCAL
*pfn_WSACleanup
) (void);
6573 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
6574 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
6575 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
6576 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
6577 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
6578 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
6579 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
6580 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
6581 const char * optval
, int optlen
);
6582 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
6583 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
6585 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
6586 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
6587 struct sockaddr
* from
, int * fromlen
);
6588 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
6589 const struct sockaddr
* to
, int tolen
);
6591 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6592 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
6593 #ifndef HANDLE_FLAG_INHERIT
6594 #define HANDLE_FLAG_INHERIT 1
6598 static int winsock_inuse
;
6603 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
6605 release_listen_threads ();
6606 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6607 after WSAStartup returns successfully, but it seems reasonable
6608 to allow unloading winsock anyway in that case. */
6609 if (pfn_WSACleanup () == 0 ||
6610 pfn_WSAGetLastError () == WSAENETDOWN
)
6612 if (FreeLibrary (winsock_lib
))
6621 init_winsock (int load_now
)
6623 WSADATA winsockData
;
6625 if (winsock_lib
!= NULL
)
6628 pfn_SetHandleInformation
6629 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6630 "SetHandleInformation");
6632 winsock_lib
= LoadLibrary ("Ws2_32.dll");
6634 if (winsock_lib
!= NULL
)
6636 /* dynamically link to socket functions */
6638 #define LOAD_PROC(fn) \
6639 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6642 LOAD_PROC (WSAStartup
);
6643 LOAD_PROC (WSASetLastError
);
6644 LOAD_PROC (WSAGetLastError
);
6645 LOAD_PROC (WSAEventSelect
);
6646 LOAD_PROC (WSACreateEvent
);
6647 LOAD_PROC (WSACloseEvent
);
6650 LOAD_PROC (connect
);
6651 LOAD_PROC (ioctlsocket
);
6654 LOAD_PROC (closesocket
);
6655 LOAD_PROC (shutdown
);
6658 LOAD_PROC (inet_addr
);
6659 LOAD_PROC (gethostname
);
6660 LOAD_PROC (gethostbyname
);
6661 LOAD_PROC (getservbyname
);
6662 LOAD_PROC (getpeername
);
6663 LOAD_PROC (WSACleanup
);
6664 LOAD_PROC (setsockopt
);
6666 LOAD_PROC (getsockname
);
6668 LOAD_PROC (recvfrom
);
6672 /* specify version 1.1 of winsock */
6673 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
6675 if (winsockData
.wVersion
!= 0x101)
6680 /* Report that winsock exists and is usable, but leave
6681 socket functions disabled. I am assuming that calling
6682 WSAStartup does not require any network interaction,
6683 and in particular does not cause or require a dial-up
6684 connection to be established. */
6687 FreeLibrary (winsock_lib
);
6695 FreeLibrary (winsock_lib
);
6705 /* Function to map winsock error codes to errno codes for those errno
6706 code defined in errno.h (errno values not defined by errno.h are
6707 already in nt/inc/sys/socket.h). */
6714 if (winsock_lib
== NULL
)
6717 wsa_err
= pfn_WSAGetLastError ();
6721 case WSAEACCES
: errno
= EACCES
; break;
6722 case WSAEBADF
: errno
= EBADF
; break;
6723 case WSAEFAULT
: errno
= EFAULT
; break;
6724 case WSAEINTR
: errno
= EINTR
; break;
6725 case WSAEINVAL
: errno
= EINVAL
; break;
6726 case WSAEMFILE
: errno
= EMFILE
; break;
6727 case WSAENAMETOOLONG
: errno
= ENAMETOOLONG
; break;
6728 case WSAENOTEMPTY
: errno
= ENOTEMPTY
; break;
6729 default: errno
= wsa_err
; break;
6737 if (winsock_lib
!= NULL
)
6738 pfn_WSASetLastError (0);
6741 /* Extend strerror to handle the winsock-specific error codes. */
6745 } _wsa_errlist
[] = {
6746 {WSAEINTR
, "Interrupted function call"},
6747 {WSAEBADF
, "Bad file descriptor"},
6748 {WSAEACCES
, "Permission denied"},
6749 {WSAEFAULT
, "Bad address"},
6750 {WSAEINVAL
, "Invalid argument"},
6751 {WSAEMFILE
, "Too many open files"},
6753 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
6754 {WSAEINPROGRESS
, "Operation now in progress"},
6755 {WSAEALREADY
, "Operation already in progress"},
6756 {WSAENOTSOCK
, "Socket operation on non-socket"},
6757 {WSAEDESTADDRREQ
, "Destination address required"},
6758 {WSAEMSGSIZE
, "Message too long"},
6759 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
6760 {WSAENOPROTOOPT
, "Bad protocol option"},
6761 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
6762 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
6763 {WSAEOPNOTSUPP
, "Operation not supported"},
6764 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
6765 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
6766 {WSAEADDRINUSE
, "Address already in use"},
6767 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
6768 {WSAENETDOWN
, "Network is down"},
6769 {WSAENETUNREACH
, "Network is unreachable"},
6770 {WSAENETRESET
, "Network dropped connection on reset"},
6771 {WSAECONNABORTED
, "Software caused connection abort"},
6772 {WSAECONNRESET
, "Connection reset by peer"},
6773 {WSAENOBUFS
, "No buffer space available"},
6774 {WSAEISCONN
, "Socket is already connected"},
6775 {WSAENOTCONN
, "Socket is not connected"},
6776 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
6777 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
6778 {WSAETIMEDOUT
, "Connection timed out"},
6779 {WSAECONNREFUSED
, "Connection refused"},
6780 {WSAELOOP
, "Network loop"}, /* not sure */
6781 {WSAENAMETOOLONG
, "Name is too long"},
6782 {WSAEHOSTDOWN
, "Host is down"},
6783 {WSAEHOSTUNREACH
, "No route to host"},
6784 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
6785 {WSAEPROCLIM
, "Too many processes"},
6786 {WSAEUSERS
, "Too many users"}, /* not sure */
6787 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
6788 {WSAESTALE
, "Data is stale"}, /* not sure */
6789 {WSAEREMOTE
, "Remote error"}, /* not sure */
6791 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
6792 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
6793 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
6794 {WSAEDISCON
, "Graceful shutdown in progress"},
6796 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
6797 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
6798 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
6799 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
6800 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
6801 {WSASYSCALLFAILURE
, "System call failure"},
6802 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
6803 {WSATYPE_NOT_FOUND
, "Class type not found"},
6804 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
6805 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
6806 {WSAEREFUSED
, "Operation refused"}, /* not sure */
6809 {WSAHOST_NOT_FOUND
, "Host not found"},
6810 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
6811 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
6812 {WSANO_DATA
, "Valid name, no data record of requested type"},
6818 sys_strerror (int error_no
)
6821 static char unknown_msg
[40];
6823 if (error_no
>= 0 && error_no
< sys_nerr
)
6824 return sys_errlist
[error_no
];
6826 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
6827 if (_wsa_errlist
[i
].errnum
== error_no
)
6828 return _wsa_errlist
[i
].msg
;
6830 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
6834 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6835 but I believe the method of keeping the socket handle separate (and
6836 insuring it is not inheritable) is the correct one. */
6838 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6840 static int socket_to_fd (SOCKET s
);
6843 sys_socket (int af
, int type
, int protocol
)
6847 if (winsock_lib
== NULL
)
6850 return INVALID_SOCKET
;
6855 /* call the real socket function */
6856 s
= pfn_socket (af
, type
, protocol
);
6858 if (s
!= INVALID_SOCKET
)
6859 return socket_to_fd (s
);
6865 /* Convert a SOCKET to a file descriptor. */
6867 socket_to_fd (SOCKET s
)
6872 /* Although under NT 3.5 _open_osfhandle will accept a socket
6873 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6874 that does not work under NT 3.1. However, we can get the same
6875 effect by using a backdoor function to replace an existing
6876 descriptor handle with the one we want. */
6878 /* allocate a file descriptor (with appropriate flags) */
6879 fd
= _open ("NUL:", _O_RDWR
);
6882 /* Make a non-inheritable copy of the socket handle. Note
6883 that it is possible that sockets aren't actually kernel
6884 handles, which appears to be the case on Windows 9x when
6885 the MS Proxy winsock client is installed. */
6887 /* Apparently there is a bug in NT 3.51 with some service
6888 packs, which prevents using DuplicateHandle to make a
6889 socket handle non-inheritable (causes WSACleanup to
6890 hang). The work-around is to use SetHandleInformation
6891 instead if it is available and implemented. */
6892 if (pfn_SetHandleInformation
)
6894 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
6898 HANDLE parent
= GetCurrentProcess ();
6899 HANDLE new_s
= INVALID_HANDLE_VALUE
;
6901 if (DuplicateHandle (parent
,
6907 DUPLICATE_SAME_ACCESS
))
6909 /* It is possible that DuplicateHandle succeeds even
6910 though the socket wasn't really a kernel handle,
6911 because a real handle has the same value. So
6912 test whether the new handle really is a socket. */
6913 long nonblocking
= 0;
6914 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
6916 pfn_closesocket (s
);
6921 CloseHandle (new_s
);
6926 eassert (fd
< MAXDESC
);
6927 fd_info
[fd
].hnd
= (HANDLE
) s
;
6929 /* set our own internal flags */
6930 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
6936 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6938 /* attach child_process to fd_info */
6939 if (fd_info
[ fd
].cp
!= NULL
)
6941 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
6945 fd_info
[ fd
].cp
= cp
;
6948 winsock_inuse
++; /* count open sockets */
6956 pfn_closesocket (s
);
6962 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
6964 if (winsock_lib
== NULL
)
6967 return SOCKET_ERROR
;
6971 if (fd_info
[s
].flags
& FILE_SOCKET
)
6973 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
6974 if (rc
== SOCKET_ERROR
)
6979 return SOCKET_ERROR
;
6983 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
6985 if (winsock_lib
== NULL
)
6988 return SOCKET_ERROR
;
6992 if (fd_info
[s
].flags
& FILE_SOCKET
)
6994 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
6995 if (rc
== SOCKET_ERROR
)
7000 return SOCKET_ERROR
;
7004 sys_htons (u_short hostshort
)
7006 return (winsock_lib
!= NULL
) ?
7007 pfn_htons (hostshort
) : hostshort
;
7011 sys_ntohs (u_short netshort
)
7013 return (winsock_lib
!= NULL
) ?
7014 pfn_ntohs (netshort
) : netshort
;
7018 sys_inet_addr (const char * cp
)
7020 return (winsock_lib
!= NULL
) ?
7021 pfn_inet_addr (cp
) : INADDR_NONE
;
7025 sys_gethostname (char * name
, int namelen
)
7027 if (winsock_lib
!= NULL
)
7032 retval
= pfn_gethostname (name
, namelen
);
7033 if (retval
== SOCKET_ERROR
)
7038 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
7039 return !GetComputerName (name
, (DWORD
*)&namelen
);
7042 return SOCKET_ERROR
;
7046 sys_gethostbyname (const char * name
)
7048 struct hostent
* host
;
7049 int h_err
= h_errno
;
7051 if (winsock_lib
== NULL
)
7053 h_errno
= NO_RECOVERY
;
7059 host
= pfn_gethostbyname (name
);
7071 sys_getservbyname (const char * name
, const char * proto
)
7073 struct servent
* serv
;
7075 if (winsock_lib
== NULL
)
7082 serv
= pfn_getservbyname (name
, proto
);
7089 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
7091 if (winsock_lib
== NULL
)
7094 return SOCKET_ERROR
;
7098 if (fd_info
[s
].flags
& FILE_SOCKET
)
7100 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
7101 if (rc
== SOCKET_ERROR
)
7106 return SOCKET_ERROR
;
7110 sys_shutdown (int s
, int how
)
7112 if (winsock_lib
== NULL
)
7115 return SOCKET_ERROR
;
7119 if (fd_info
[s
].flags
& FILE_SOCKET
)
7121 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
7122 if (rc
== SOCKET_ERROR
)
7127 return SOCKET_ERROR
;
7131 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
7133 if (winsock_lib
== NULL
)
7136 return SOCKET_ERROR
;
7140 if (fd_info
[s
].flags
& FILE_SOCKET
)
7142 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
7143 (const char *)optval
, optlen
);
7144 if (rc
== SOCKET_ERROR
)
7149 return SOCKET_ERROR
;
7153 sys_listen (int s
, int backlog
)
7155 if (winsock_lib
== NULL
)
7158 return SOCKET_ERROR
;
7162 if (fd_info
[s
].flags
& FILE_SOCKET
)
7164 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
7165 if (rc
== SOCKET_ERROR
)
7168 fd_info
[s
].flags
|= FILE_LISTEN
;
7172 return SOCKET_ERROR
;
7176 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
7178 if (winsock_lib
== NULL
)
7181 return SOCKET_ERROR
;
7185 if (fd_info
[s
].flags
& FILE_SOCKET
)
7187 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
7188 if (rc
== SOCKET_ERROR
)
7193 return SOCKET_ERROR
;
7197 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
7199 if (winsock_lib
== NULL
)
7206 if (fd_info
[s
].flags
& FILE_LISTEN
)
7208 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
7210 if (t
== INVALID_SOCKET
)
7213 fd
= socket_to_fd (t
);
7217 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7218 ResetEvent (fd_info
[s
].cp
->char_avail
);
7227 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
7228 struct sockaddr
* from
, int * fromlen
)
7230 if (winsock_lib
== NULL
)
7233 return SOCKET_ERROR
;
7237 if (fd_info
[s
].flags
& FILE_SOCKET
)
7239 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
7240 if (rc
== SOCKET_ERROR
)
7245 return SOCKET_ERROR
;
7249 sys_sendto (int s
, const char * buf
, int len
, int flags
,
7250 const struct sockaddr
* to
, int tolen
)
7252 if (winsock_lib
== NULL
)
7255 return SOCKET_ERROR
;
7259 if (fd_info
[s
].flags
& FILE_SOCKET
)
7261 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
7262 if (rc
== SOCKET_ERROR
)
7267 return SOCKET_ERROR
;
7270 /* Windows does not have an fcntl function. Provide an implementation
7271 good enough for Emacs. */
7273 fcntl (int s
, int cmd
, int options
)
7275 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
7276 invoked in a context where fd1 is closed and all descriptors less
7277 than fd1 are open, so sys_dup is an adequate implementation. */
7278 if (cmd
== F_DUPFD_CLOEXEC
)
7281 if (winsock_lib
== NULL
)
7288 if (fd_info
[s
].flags
& FILE_SOCKET
)
7290 if (cmd
== F_SETFL
&& options
== O_NONBLOCK
)
7292 unsigned long nblock
= 1;
7293 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
7294 if (rc
== SOCKET_ERROR
)
7296 /* Keep track of the fact that we set this to non-blocking. */
7297 fd_info
[s
].flags
|= FILE_NDELAY
;
7303 return SOCKET_ERROR
;
7307 return SOCKET_ERROR
;
7311 /* Shadow main io functions: we need to handle pipes and sockets more
7312 intelligently, and implement non-blocking mode as well. */
7325 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
7327 child_process
* cp
= fd_info
[fd
].cp
;
7329 fd_info
[fd
].cp
= NULL
;
7331 if (CHILD_ACTIVE (cp
))
7333 /* if last descriptor to active child_process then cleanup */
7335 for (i
= 0; i
< MAXDESC
; i
++)
7339 if (fd_info
[i
].cp
== cp
)
7344 if (fd_info
[fd
].flags
& FILE_SOCKET
)
7346 if (winsock_lib
== NULL
) emacs_abort ();
7348 pfn_shutdown (SOCK_HANDLE (fd
), 2);
7349 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
7351 winsock_inuse
--; /* count open sockets */
7353 /* If the process handle is NULL, it's either a socket
7354 or serial connection, or a subprocess that was
7355 already reaped by reap_subprocess, but whose
7356 resources were not yet freed, because its output was
7357 not fully read yet by the time it was reaped. (This
7358 usually happens with async subprocesses whose output
7359 is being read by Emacs.) Otherwise, this process was
7360 not reaped yet, so we set its FD to a negative value
7361 to make sure sys_select will eventually get to
7362 calling the SIGCHLD handler for it, which will then
7363 invoke waitpid and reap_subprocess. */
7364 if (cp
->procinfo
.hProcess
== NULL
)
7372 if (fd
>= 0 && fd
< MAXDESC
)
7373 fd_info
[fd
].flags
= 0;
7375 /* Note that sockets do not need special treatment here (at least on
7376 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7377 closesocket is equivalent to CloseHandle, which is to be expected
7378 because socket handles are fully fledged kernel handles. */
7390 if (new_fd
>= 0 && new_fd
< MAXDESC
)
7392 /* duplicate our internal info as well */
7393 fd_info
[new_fd
] = fd_info
[fd
];
7399 sys_dup2 (int src
, int dst
)
7403 if (dst
< 0 || dst
>= MAXDESC
)
7409 /* make sure we close the destination first if it's a pipe or socket */
7410 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
7413 rc
= _dup2 (src
, dst
);
7416 /* duplicate our internal info as well */
7417 fd_info
[dst
] = fd_info
[src
];
7423 pipe2 (int * phandles
, int pipe2_flags
)
7428 eassert (pipe2_flags
== O_CLOEXEC
);
7430 /* make pipe handles non-inheritable; when we spawn a child, we
7431 replace the relevant handle with an inheritable one. Also put
7432 pipes into binary mode; we will do text mode translation ourselves
7434 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
7438 /* Protect against overflow, since Windows can open more handles than
7439 our fd_info array has room for. */
7440 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
7442 _close (phandles
[0]);
7443 _close (phandles
[1]);
7449 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
7450 fd_info
[phandles
[0]].flags
= flags
;
7452 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
7453 fd_info
[phandles
[1]].flags
= flags
;
7460 /* Function to do blocking read of one byte, needed to implement
7461 select. It is only allowed on communication ports, sockets, or
7464 _sys_read_ahead (int fd
)
7469 if (fd
< 0 || fd
>= MAXDESC
)
7470 return STATUS_READ_ERROR
;
7472 cp
= fd_info
[fd
].cp
;
7474 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7475 return STATUS_READ_ERROR
;
7477 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
7478 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
7480 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
7484 cp
->status
= STATUS_READ_IN_PROGRESS
;
7486 if (fd_info
[fd
].flags
& FILE_PIPE
)
7488 rc
= _read (fd
, &cp
->chr
, sizeof (char));
7490 /* Give subprocess time to buffer some more output for us before
7491 reporting that input is available; we need this because Windows 95
7492 connects DOS programs to pipes by making the pipe appear to be
7493 the normal console stdout - as a result most DOS programs will
7494 write to stdout without buffering, ie. one character at a
7495 time. Even some W32 programs do this - "dir" in a command
7496 shell on NT is very slow if we don't do this. */
7499 int wait
= w32_pipe_read_delay
;
7505 /* Yield remainder of our time slice, effectively giving a
7506 temporary priority boost to the child process. */
7510 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7512 HANDLE hnd
= fd_info
[fd
].hnd
;
7513 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7516 /* Configure timeouts for blocking read. */
7517 if (!GetCommTimeouts (hnd
, &ct
))
7519 cp
->status
= STATUS_READ_ERROR
;
7520 return STATUS_READ_ERROR
;
7522 ct
.ReadIntervalTimeout
= 0;
7523 ct
.ReadTotalTimeoutMultiplier
= 0;
7524 ct
.ReadTotalTimeoutConstant
= 0;
7525 if (!SetCommTimeouts (hnd
, &ct
))
7527 cp
->status
= STATUS_READ_ERROR
;
7528 return STATUS_READ_ERROR
;
7531 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
7533 if (GetLastError () != ERROR_IO_PENDING
)
7535 cp
->status
= STATUS_READ_ERROR
;
7536 return STATUS_READ_ERROR
;
7538 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7540 cp
->status
= STATUS_READ_ERROR
;
7541 return STATUS_READ_ERROR
;
7545 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
7547 unsigned long nblock
= 0;
7548 /* We always want this to block, so temporarily disable NDELAY. */
7549 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7550 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7552 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
7554 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7557 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7561 if (rc
== sizeof (char))
7562 cp
->status
= STATUS_READ_SUCCEEDED
;
7564 cp
->status
= STATUS_READ_FAILED
;
7570 _sys_wait_accept (int fd
)
7576 if (fd
< 0 || fd
>= MAXDESC
)
7577 return STATUS_READ_ERROR
;
7579 cp
= fd_info
[fd
].cp
;
7581 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7582 return STATUS_READ_ERROR
;
7584 cp
->status
= STATUS_READ_FAILED
;
7586 hEv
= pfn_WSACreateEvent ();
7587 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
7588 if (rc
!= SOCKET_ERROR
)
7591 rc
= WaitForSingleObject (hEv
, 500);
7593 } while (rc
== WAIT_TIMEOUT
7594 && cp
->status
!= STATUS_READ_ERROR
7596 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
7597 if (rc
== WAIT_OBJECT_0
)
7598 cp
->status
= STATUS_READ_SUCCEEDED
;
7600 pfn_WSACloseEvent (hEv
);
7606 sys_read (int fd
, char * buffer
, unsigned int count
)
7611 char * orig_buffer
= buffer
;
7619 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7621 child_process
*cp
= fd_info
[fd
].cp
;
7623 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
7631 /* re-read CR carried over from last read */
7632 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
7634 if (fd_info
[fd
].flags
& FILE_BINARY
) emacs_abort ();
7638 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
7641 /* presence of a child_process structure means we are operating in
7642 non-blocking mode - otherwise we just call _read directly.
7643 Note that the child_process structure might be missing because
7644 reap_subprocess has been called; in this case the pipe is
7645 already broken, so calling _read on it is okay. */
7648 int current_status
= cp
->status
;
7650 switch (current_status
)
7652 case STATUS_READ_FAILED
:
7653 case STATUS_READ_ERROR
:
7654 /* report normal EOF if nothing in buffer */
7656 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7659 case STATUS_READ_READY
:
7660 case STATUS_READ_IN_PROGRESS
:
7661 DebPrint (("sys_read called when read is in progress\n"));
7662 errno
= EWOULDBLOCK
;
7665 case STATUS_READ_SUCCEEDED
:
7666 /* consume read-ahead char */
7667 *buffer
++ = cp
->chr
;
7670 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7671 ResetEvent (cp
->char_avail
);
7673 case STATUS_READ_ACKNOWLEDGED
:
7677 DebPrint (("sys_read: bad status %d\n", current_status
));
7682 if (fd_info
[fd
].flags
& FILE_PIPE
)
7684 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
7685 to_read
= min (waiting
, (DWORD
) count
);
7688 nchars
+= _read (fd
, buffer
, to_read
);
7690 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7692 HANDLE hnd
= fd_info
[fd
].hnd
;
7693 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7699 /* Configure timeouts for non-blocking read. */
7700 if (!GetCommTimeouts (hnd
, &ct
))
7705 ct
.ReadIntervalTimeout
= MAXDWORD
;
7706 ct
.ReadTotalTimeoutMultiplier
= 0;
7707 ct
.ReadTotalTimeoutConstant
= 0;
7708 if (!SetCommTimeouts (hnd
, &ct
))
7714 if (!ResetEvent (ovl
->hEvent
))
7719 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
7721 if (GetLastError () != ERROR_IO_PENDING
)
7726 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7735 else /* FILE_SOCKET */
7737 if (winsock_lib
== NULL
) emacs_abort ();
7739 /* do the equivalent of a non-blocking read */
7740 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
7741 if (waiting
== 0 && nchars
== 0)
7743 errno
= EWOULDBLOCK
;
7749 /* always use binary mode for sockets */
7750 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
7751 if (res
== SOCKET_ERROR
)
7753 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7754 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7764 int nread
= _read (fd
, buffer
, count
);
7767 else if (nchars
== 0)
7772 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7773 /* Perform text mode translation if required. */
7774 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7776 nchars
= crlf_to_lf (nchars
, orig_buffer
);
7777 /* If buffer contains only CR, return that. To be absolutely
7778 sure we should attempt to read the next char, but in
7779 practice a CR to be followed by LF would not appear by
7780 itself in the buffer. */
7781 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
7783 fd_info
[fd
].flags
|= FILE_LAST_CR
;
7789 nchars
= _read (fd
, buffer
, count
);
7794 /* From w32xfns.c */
7795 extern HANDLE interrupt_handle
;
7797 /* For now, don't bother with a non-blocking mode */
7799 sys_write (int fd
, const void * buffer
, unsigned int count
)
7809 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7811 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
7817 /* Perform text mode translation if required. */
7818 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7820 char * tmpbuf
= alloca (count
* 2);
7821 unsigned char * src
= (void *)buffer
;
7822 unsigned char * dst
= tmpbuf
;
7827 unsigned char *next
;
7828 /* copy next line or remaining bytes */
7829 next
= _memccpy (dst
, src
, '\n', nbytes
);
7832 /* copied one line ending with '\n' */
7833 int copied
= next
- dst
;
7836 /* insert '\r' before '\n' */
7843 /* copied remaining partial line -> now finished */
7850 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
7852 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
7853 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
7854 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
7857 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
7859 if (GetLastError () != ERROR_IO_PENDING
)
7864 if (detect_input_pending ())
7865 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
7868 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
7869 if (active
== WAIT_OBJECT_0
)
7870 { /* User pressed C-g, cancel write, then leave. Don't bother
7871 cleaning up as we may only get stuck in buggy drivers. */
7872 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
7877 if (active
== WAIT_OBJECT_0
+ 1
7878 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
7885 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
7887 unsigned long nblock
= 0;
7888 if (winsock_lib
== NULL
) emacs_abort ();
7890 /* TODO: implement select() properly so non-blocking I/O works. */
7891 /* For now, make sure the write blocks. */
7892 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7893 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7895 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
7897 /* Set the socket back to non-blocking if it was before,
7898 for other operations that support it. */
7899 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7902 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7905 if (nchars
== SOCKET_ERROR
)
7907 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7908 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7914 /* Some networked filesystems don't like too large writes, so
7915 break them into smaller chunks. See the Comments section of
7916 the MSDN documentation of WriteFile for details behind the
7917 choice of the value of CHUNK below. See also the thread
7918 http://thread.gmane.org/gmane.comp.version-control.git/145294
7919 in the git mailing list. */
7920 const unsigned char *p
= buffer
;
7921 const unsigned chunk
= 30 * 1024 * 1024;
7926 unsigned this_chunk
= count
< chunk
? count
: chunk
;
7927 int n
= _write (fd
, p
, this_chunk
);
7935 else if (n
< this_chunk
)
7946 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
7948 extern Lisp_Object
conv_sockaddr_to_lisp (struct sockaddr
*, int);
7950 /* Return information about network interface IFNAME, or about all
7951 interfaces (if IFNAME is nil). */
7953 network_interface_get_info (Lisp_Object ifname
)
7955 ULONG ainfo_len
= sizeof (IP_ADAPTER_INFO
);
7956 IP_ADAPTER_INFO
*adapter
, *ainfo
= xmalloc (ainfo_len
);
7957 DWORD retval
= get_adapters_info (ainfo
, &ainfo_len
);
7958 Lisp_Object res
= Qnil
;
7960 if (retval
== ERROR_BUFFER_OVERFLOW
)
7962 ainfo
= xrealloc (ainfo
, ainfo_len
);
7963 retval
= get_adapters_info (ainfo
, &ainfo_len
);
7966 if (retval
== ERROR_SUCCESS
)
7968 int eth_count
= 0, tr_count
= 0, fddi_count
= 0, ppp_count
= 0;
7969 int sl_count
= 0, wlan_count
= 0, lo_count
= 0, ifx_count
= 0;
7971 struct sockaddr_in sa
;
7973 /* For the below, we need some winsock functions, so make sure
7974 the winsock DLL is loaded. If we cannot successfully load
7975 it, they will have no use of the information we provide,
7977 if (!winsock_lib
&& !init_winsock (1))
7980 for (adapter
= ainfo
; adapter
; adapter
= adapter
->Next
)
7982 char namebuf
[MAX_ADAPTER_NAME_LENGTH
+ 4];
7984 /* Present Unix-compatible interface names, instead of the
7985 Windows names, which are really GUIDs not readable by
7987 static const char *ifmt
[] = {
7988 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
8003 switch (adapter
->Type
)
8005 case MIB_IF_TYPE_ETHERNET
:
8006 /* Windows before Vista reports wireless adapters as
8007 Ethernet. Work around by looking at the Description
8009 if (strstr (adapter
->Description
, "Wireless "))
8012 if_num
= wlan_count
++;
8016 ifmt_idx
= ETHERNET
;
8017 if_num
= eth_count
++;
8020 case MIB_IF_TYPE_TOKENRING
:
8021 ifmt_idx
= TOKENRING
;
8022 if_num
= tr_count
++;
8024 case MIB_IF_TYPE_FDDI
:
8026 if_num
= fddi_count
++;
8028 case MIB_IF_TYPE_PPP
:
8030 if_num
= ppp_count
++;
8032 case MIB_IF_TYPE_SLIP
:
8034 if_num
= sl_count
++;
8036 case IF_TYPE_IEEE80211
:
8038 if_num
= wlan_count
++;
8040 case MIB_IF_TYPE_LOOPBACK
:
8043 ifmt_idx
= LOOPBACK
;
8044 if_num
= lo_count
++;
8050 ifmt_idx
= OTHER_IF
;
8051 if_num
= ifx_count
++;
8054 if (ifmt_idx
== NONE
)
8056 sprintf (namebuf
, ifmt
[ifmt_idx
], if_num
);
8058 sa
.sin_family
= AF_INET
;
8059 ip_addr
= sys_inet_addr (adapter
->IpAddressList
.IpAddress
.String
);
8060 if (ip_addr
== INADDR_NONE
)
8062 /* Bogus address, skip this interface. */
8065 sa
.sin_addr
.s_addr
= ip_addr
;
8068 res
= Fcons (Fcons (build_string (namebuf
),
8069 conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8070 sizeof (struct sockaddr
))),
8072 else if (strcmp (namebuf
, SSDATA (ifname
)) == 0)
8074 Lisp_Object hwaddr
= Fmake_vector (make_number (6), Qnil
);
8075 register struct Lisp_Vector
*p
= XVECTOR (hwaddr
);
8076 Lisp_Object flags
= Qnil
;
8080 /* Flags. We guess most of them by type, since the
8081 Windows flags are different and hard to get by. */
8082 flags
= Fcons (intern ("up"), flags
);
8083 if (ifmt_idx
== ETHERNET
|| ifmt_idx
== WLAN
)
8085 flags
= Fcons (intern ("broadcast"), flags
);
8086 flags
= Fcons (intern ("multicast"), flags
);
8088 flags
= Fcons (intern ("running"), flags
);
8089 if (ifmt_idx
== PPP
)
8091 flags
= Fcons (intern ("pointopoint"), flags
);
8092 flags
= Fcons (intern ("noarp"), flags
);
8094 if (adapter
->HaveWins
)
8095 flags
= Fcons (intern ("WINS"), flags
);
8096 if (adapter
->DhcpEnabled
)
8097 flags
= Fcons (intern ("dynamic"), flags
);
8099 res
= Fcons (flags
, res
);
8101 /* Hardware address and its family. */
8102 for (n
= 0; n
< adapter
->AddressLength
; n
++)
8103 p
->contents
[n
] = make_number ((int) adapter
->Address
[n
]);
8104 /* Windows does not support AF_LINK or AF_PACKET family
8105 of addresses. Use an arbitrary family number that is
8106 identical to what GNU/Linux returns. */
8107 res
= Fcons (Fcons (make_number (1), hwaddr
), res
);
8110 sa
.sin_family
= AF_INET
;
8111 net_mask
= sys_inet_addr (adapter
->IpAddressList
.IpMask
.String
);
8112 if (net_mask
!= INADDR_NONE
)
8114 sa
.sin_addr
.s_addr
= net_mask
;
8116 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8117 sizeof (struct sockaddr
)),
8121 res
= Fcons (Qnil
, res
);
8123 sa
.sin_family
= AF_INET
;
8124 if (ip_addr
!= INADDR_NONE
)
8126 /* Broadcast address is only reported by
8127 GetAdaptersAddresses, which is of limited
8128 availability. Generate it on our own. */
8129 u_long bcast_addr
= (ip_addr
& net_mask
) | ~net_mask
;
8131 sa
.sin_addr
.s_addr
= bcast_addr
;
8133 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8134 sizeof (struct sockaddr
)),
8138 sa
.sin_addr
.s_addr
= ip_addr
;
8140 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8141 sizeof (struct sockaddr
)),
8145 res
= Fcons (Qnil
, Fcons (Qnil
, res
));
8148 /* GetAdaptersInfo is documented to not report loopback
8149 interfaces, so we generate one out of thin air. */
8152 sa
.sin_family
= AF_INET
;
8156 sa
.sin_addr
.s_addr
= sys_inet_addr ("127.0.0.1");
8157 res
= Fcons (Fcons (build_string ("lo"),
8158 conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8159 sizeof (struct sockaddr
))),
8162 else if (strcmp (SSDATA (ifname
), "lo") == 0)
8164 res
= Fcons (Fcons (intern ("running"),
8165 Fcons (intern ("loopback"),
8166 Fcons (intern ("up"), Qnil
))), Qnil
);
8167 /* 772 is what 3 different GNU/Linux systems report for
8168 the loopback interface. */
8169 res
= Fcons (Fcons (make_number (772),
8170 Fmake_vector (make_number (6),
8173 sa
.sin_addr
.s_addr
= sys_inet_addr ("255.0.0.0");
8174 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8175 sizeof (struct sockaddr
)),
8177 sa
.sin_addr
.s_addr
= sys_inet_addr ("0.0.0.0");
8178 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8179 sizeof (struct sockaddr
)),
8181 sa
.sin_addr
.s_addr
= sys_inet_addr ("127.0.0.1");
8182 res
= Fcons (conv_sockaddr_to_lisp ((struct sockaddr
*) &sa
,
8183 sizeof (struct sockaddr
)),
8196 network_interface_list (void)
8198 return network_interface_get_info (Qnil
);
8202 network_interface_info (Lisp_Object ifname
)
8204 return network_interface_get_info (ifname
);
8208 /* The Windows CRT functions are "optimized for speed", so they don't
8209 check for timezone and DST changes if they were last called less
8210 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
8211 all Emacs features that repeatedly call time functions (e.g.,
8212 display-time) are in real danger of missing timezone and DST
8213 changes. Calling tzset before each localtime call fixes that. */
8215 sys_localtime (const time_t *t
)
8218 return localtime (t
);
8223 /* Try loading LIBRARY_ID from the file(s) specified in
8224 Vdynamic_library_alist. If the library is loaded successfully,
8225 return the handle of the DLL, and record the filename in the
8226 property :loaded-from of LIBRARY_ID. If the library could not be
8227 found, or when it was already loaded (because the handle is not
8228 recorded anywhere, and so is lost after use), return NULL.
8230 We could also save the handle in :loaded-from, but currently
8231 there's no use case for it. */
8233 w32_delayed_load (Lisp_Object library_id
)
8235 HMODULE dll_handle
= NULL
;
8237 CHECK_SYMBOL (library_id
);
8239 if (CONSP (Vdynamic_library_alist
)
8240 && NILP (Fassq (library_id
, Vlibrary_cache
)))
8242 Lisp_Object found
= Qnil
;
8243 Lisp_Object dlls
= Fassq (library_id
, Vdynamic_library_alist
);
8246 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
8248 Lisp_Object dll
= XCAR (dlls
);
8249 char name
[MAX_UTF8_PATH
];
8253 dll
= ENCODE_FILE (dll
);
8254 if (w32_unicode_filenames
)
8256 wchar_t name_w
[MAX_PATH
];
8258 filename_to_utf16 (SSDATA (dll
), name_w
);
8259 dll_handle
= LoadLibraryW (name_w
);
8262 res
= GetModuleFileNameW (dll_handle
, name_w
,
8265 filename_from_utf16 (name_w
, name
);
8270 char name_a
[MAX_PATH
];
8272 filename_to_ansi (SSDATA (dll
), name_a
);
8273 dll_handle
= LoadLibraryA (name_a
);
8276 res
= GetModuleFileNameA (dll_handle
, name_a
,
8279 filename_from_ansi (name_a
, name
);
8284 ptrdiff_t len
= strlen (name
);
8287 /* Possibly truncated */
8288 ? make_specified_string (name
, -1, len
, 1)
8294 Fput (library_id
, QCloaded_from
, found
);
8302 check_windows_init_file (void)
8304 /* A common indication that Emacs is not installed properly is when
8305 it cannot find the Windows installation file. If this file does
8306 not exist in the expected place, tell the user. */
8308 if (!noninteractive
&& !inhibit_window_system
8309 /* Vload_path is not yet initialized when we are loading
8311 && NILP (Vpurify_flag
))
8313 Lisp_Object init_file
;
8316 /* Implementation note: this function runs early during Emacs
8317 startup, before startup.el is run. So Vload_path is still in
8318 its initial unibyte form, holding ANSI-encoded file names.
8319 That is why we never bother to ENCODE_FILE here, nor use wide
8320 APIs for file names: we will never get UTF-8 encoded file
8322 init_file
= build_string ("term/w32-win");
8323 fd
= openp (Vload_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
8326 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
8327 char *init_file_name
= SDATA (init_file
);
8328 char *load_path
= SDATA (load_path_print
);
8329 char *buffer
= alloca (1024
8330 + strlen (init_file_name
)
8331 + strlen (load_path
));
8334 "The Emacs Windows initialization file \"%s.el\" "
8335 "could not be found in your Emacs installation. "
8336 "Emacs checked the following directories for this file:\n"
8338 "When Emacs cannot find this file, it usually means that it "
8339 "was not installed properly, or its distribution file was "
8340 "not unpacked properly.\nSee the README.W32 file in the "
8341 "top-level Emacs directory for more information.",
8342 init_file_name
, load_path
);
8345 "Emacs Abort Dialog",
8346 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
8347 /* Use the low-level system abort. */
8358 term_ntproc (int ignored
)
8364 /* shutdown the socket interface if necessary */
8371 init_ntproc (int dumping
)
8373 sigset_t initial_mask
= 0;
8375 /* Initialize the socket interface now if available and requested by
8376 the user by defining PRELOAD_WINSOCK; otherwise loading will be
8377 delayed until open-network-stream is called (w32-has-winsock can
8378 also be used to dynamically load or reload winsock).
8380 Conveniently, init_environment is called before us, so
8381 PRELOAD_WINSOCK can be set in the registry. */
8383 /* Always initialize this correctly. */
8386 if (getenv ("PRELOAD_WINSOCK") != NULL
)
8387 init_winsock (TRUE
);
8389 /* Initial preparation for subprocess support: replace our standard
8390 handles with non-inheritable versions. */
8393 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
8394 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
8395 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
8397 parent
= GetCurrentProcess ();
8399 /* ignore errors when duplicating and closing; typically the
8400 handles will be invalid when running as a gui program. */
8401 DuplicateHandle (parent
,
8402 GetStdHandle (STD_INPUT_HANDLE
),
8407 DUPLICATE_SAME_ACCESS
);
8409 DuplicateHandle (parent
,
8410 GetStdHandle (STD_OUTPUT_HANDLE
),
8415 DUPLICATE_SAME_ACCESS
);
8417 DuplicateHandle (parent
,
8418 GetStdHandle (STD_ERROR_HANDLE
),
8423 DUPLICATE_SAME_ACCESS
);
8429 if (stdin_save
!= INVALID_HANDLE_VALUE
)
8430 _open_osfhandle ((intptr_t) stdin_save
, O_TEXT
);
8432 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
8435 if (stdout_save
!= INVALID_HANDLE_VALUE
)
8436 _open_osfhandle ((intptr_t) stdout_save
, O_TEXT
);
8438 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
8441 if (stderr_save
!= INVALID_HANDLE_VALUE
)
8442 _open_osfhandle ((intptr_t) stderr_save
, O_TEXT
);
8444 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
8448 /* unfortunately, atexit depends on implementation of malloc */
8449 /* atexit (term_ntproc); */
8452 /* Make sure we start with all signals unblocked. */
8453 sigprocmask (SIG_SETMASK
, &initial_mask
, NULL
);
8454 signal (SIGABRT
, term_ntproc
);
8458 /* determine which drives are fixed, for GetCachedVolumeInformation */
8460 /* GetDriveType must have trailing backslash. */
8461 char drive
[] = "A:\\";
8463 /* Loop over all possible drive letters */
8464 while (*drive
<= 'Z')
8466 /* Record if this drive letter refers to a fixed drive. */
8467 fixed_drives
[DRIVE_INDEX (*drive
)] =
8468 (GetDriveType (drive
) == DRIVE_FIXED
);
8473 /* Reset the volume info cache. */
8474 volume_cache
= NULL
;
8479 shutdown_handler ensures that buffers' autosave files are
8480 up to date when the user logs off, or the system shuts down.
8483 shutdown_handler (DWORD type
)
8485 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
8486 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
8487 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
8488 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
8490 /* Shut down cleanly, making sure autosave files are up to date. */
8491 shut_down_emacs (0, Qnil
);
8494 /* Allow other handlers to handle this signal. */
8499 globals_of_w32 is used to initialize those global variables that
8500 must always be initialized on startup even when the global variable
8501 initialized is non zero (see the function main in emacs.c).
8504 globals_of_w32 (void)
8506 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
8508 get_process_times_fn
= (GetProcessTimes_Proc
)
8509 GetProcAddress (kernel32
, "GetProcessTimes");
8511 DEFSYM (QCloaded_from
, ":loaded-from");
8513 g_b_init_is_windows_9x
= 0;
8514 g_b_init_open_process_token
= 0;
8515 g_b_init_get_token_information
= 0;
8516 g_b_init_lookup_account_sid
= 0;
8517 g_b_init_get_sid_sub_authority
= 0;
8518 g_b_init_get_sid_sub_authority_count
= 0;
8519 g_b_init_get_security_info
= 0;
8520 g_b_init_get_file_security_w
= 0;
8521 g_b_init_get_file_security_a
= 0;
8522 g_b_init_get_security_descriptor_owner
= 0;
8523 g_b_init_get_security_descriptor_group
= 0;
8524 g_b_init_is_valid_sid
= 0;
8525 g_b_init_create_toolhelp32_snapshot
= 0;
8526 g_b_init_process32_first
= 0;
8527 g_b_init_process32_next
= 0;
8528 g_b_init_open_thread_token
= 0;
8529 g_b_init_impersonate_self
= 0;
8530 g_b_init_revert_to_self
= 0;
8531 g_b_init_get_process_memory_info
= 0;
8532 g_b_init_get_process_working_set_size
= 0;
8533 g_b_init_global_memory_status
= 0;
8534 g_b_init_global_memory_status_ex
= 0;
8535 g_b_init_equal_sid
= 0;
8536 g_b_init_copy_sid
= 0;
8537 g_b_init_get_length_sid
= 0;
8538 g_b_init_get_native_system_info
= 0;
8539 g_b_init_get_system_times
= 0;
8540 g_b_init_create_symbolic_link_w
= 0;
8541 g_b_init_create_symbolic_link_a
= 0;
8542 g_b_init_get_security_descriptor_dacl
= 0;
8543 g_b_init_convert_sd_to_sddl
= 0;
8544 g_b_init_convert_sddl_to_sd
= 0;
8545 g_b_init_is_valid_security_descriptor
= 0;
8546 g_b_init_set_file_security_w
= 0;
8547 g_b_init_set_file_security_a
= 0;
8548 g_b_init_get_adapters_info
= 0;
8549 num_of_processors
= 0;
8550 /* The following sets a handler for shutdown notifications for
8551 console apps. This actually applies to Emacs in both console and
8552 GUI modes, since we had to fool windows into thinking emacs is a
8553 console application to get console mode to work. */
8554 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
8556 /* "None" is the default group name on standalone workstations. */
8557 strcpy (dflt_group_name
, "None");
8559 /* Reset, in case it has some value inherited from dump time. */
8560 w32_stat_get_owner_group
= 0;
8562 /* If w32_unicode_filenames is non-zero, we will be using Unicode
8563 (a.k.a. "wide") APIs to invoke functions that accept file
8565 if (is_windows_9x ())
8566 w32_unicode_filenames
= 0;
8568 w32_unicode_filenames
= 1;
8571 /* For make-serial-process */
8573 serial_open (Lisp_Object port_obj
)
8575 char *port
= SSDATA (port_obj
);
8580 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
8581 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
8582 if (hnd
== INVALID_HANDLE_VALUE
)
8583 error ("Could not open %s", port
);
8584 fd
= (int) _open_osfhandle ((intptr_t) hnd
, 0);
8586 error ("Could not open %s", port
);
8590 error ("Could not create child process");
8592 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
8593 fd_info
[ fd
].hnd
= hnd
;
8594 fd_info
[ fd
].flags
|=
8595 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
8596 if (fd_info
[ fd
].cp
!= NULL
)
8598 error ("fd_info[fd = %d] is already in use", fd
);
8600 fd_info
[ fd
].cp
= cp
;
8601 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
8602 if (cp
->ovl_read
.hEvent
== NULL
)
8603 error ("Could not create read event");
8604 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
8605 if (cp
->ovl_write
.hEvent
== NULL
)
8606 error ("Could not create write event");
8611 /* For serial-process-configure */
8613 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
8615 Lisp_Object childp2
= Qnil
;
8616 Lisp_Object tem
= Qnil
;
8620 char summary
[4] = "???"; /* This usually becomes "8N1". */
8622 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
8623 error ("Not a serial process");
8624 hnd
= fd_info
[ p
->outfd
].hnd
;
8626 childp2
= Fcopy_sequence (p
->childp
);
8628 /* Initialize timeouts for blocking read and blocking write. */
8629 if (!GetCommTimeouts (hnd
, &ct
))
8630 error ("GetCommTimeouts() failed");
8631 ct
.ReadIntervalTimeout
= 0;
8632 ct
.ReadTotalTimeoutMultiplier
= 0;
8633 ct
.ReadTotalTimeoutConstant
= 0;
8634 ct
.WriteTotalTimeoutMultiplier
= 0;
8635 ct
.WriteTotalTimeoutConstant
= 0;
8636 if (!SetCommTimeouts (hnd
, &ct
))
8637 error ("SetCommTimeouts() failed");
8638 /* Read port attributes and prepare default configuration. */
8639 memset (&dcb
, 0, sizeof (dcb
));
8640 dcb
.DCBlength
= sizeof (DCB
);
8641 if (!GetCommState (hnd
, &dcb
))
8642 error ("GetCommState() failed");
8645 dcb
.fAbortOnError
= FALSE
;
8646 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
8651 /* Configure speed. */
8652 if (!NILP (Fplist_member (contact
, QCspeed
)))
8653 tem
= Fplist_get (contact
, QCspeed
);
8655 tem
= Fplist_get (p
->childp
, QCspeed
);
8657 dcb
.BaudRate
= XINT (tem
);
8658 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
8660 /* Configure bytesize. */
8661 if (!NILP (Fplist_member (contact
, QCbytesize
)))
8662 tem
= Fplist_get (contact
, QCbytesize
);
8664 tem
= Fplist_get (p
->childp
, QCbytesize
);
8666 tem
= make_number (8);
8668 if (XINT (tem
) != 7 && XINT (tem
) != 8)
8669 error (":bytesize must be nil (8), 7, or 8");
8670 dcb
.ByteSize
= XINT (tem
);
8671 summary
[0] = XINT (tem
) + '0';
8672 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
8674 /* Configure parity. */
8675 if (!NILP (Fplist_member (contact
, QCparity
)))
8676 tem
= Fplist_get (contact
, QCparity
);
8678 tem
= Fplist_get (p
->childp
, QCparity
);
8679 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
8680 error (":parity must be nil (no parity), `even', or `odd'");
8681 dcb
.fParity
= FALSE
;
8682 dcb
.Parity
= NOPARITY
;
8683 dcb
.fErrorChar
= FALSE
;
8688 else if (EQ (tem
, Qeven
))
8692 dcb
.Parity
= EVENPARITY
;
8693 dcb
.fErrorChar
= TRUE
;
8695 else if (EQ (tem
, Qodd
))
8699 dcb
.Parity
= ODDPARITY
;
8700 dcb
.fErrorChar
= TRUE
;
8702 childp2
= Fplist_put (childp2
, QCparity
, tem
);
8704 /* Configure stopbits. */
8705 if (!NILP (Fplist_member (contact
, QCstopbits
)))
8706 tem
= Fplist_get (contact
, QCstopbits
);
8708 tem
= Fplist_get (p
->childp
, QCstopbits
);
8710 tem
= make_number (1);
8712 if (XINT (tem
) != 1 && XINT (tem
) != 2)
8713 error (":stopbits must be nil (1 stopbit), 1, or 2");
8714 summary
[2] = XINT (tem
) + '0';
8715 if (XINT (tem
) == 1)
8716 dcb
.StopBits
= ONESTOPBIT
;
8717 else if (XINT (tem
) == 2)
8718 dcb
.StopBits
= TWOSTOPBITS
;
8719 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
8721 /* Configure flowcontrol. */
8722 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
8723 tem
= Fplist_get (contact
, QCflowcontrol
);
8725 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
8726 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
8727 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
8728 dcb
.fOutxCtsFlow
= FALSE
;
8729 dcb
.fOutxDsrFlow
= FALSE
;
8730 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
8731 dcb
.fDsrSensitivity
= FALSE
;
8732 dcb
.fTXContinueOnXoff
= FALSE
;
8735 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
8736 dcb
.XonChar
= 17; /* Control-Q */
8737 dcb
.XoffChar
= 19; /* Control-S */
8740 /* Already configured. */
8742 else if (EQ (tem
, Qhw
))
8744 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
8745 dcb
.fOutxCtsFlow
= TRUE
;
8747 else if (EQ (tem
, Qsw
))
8752 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
8754 /* Activate configuration. */
8755 if (!SetCommState (hnd
, &dcb
))
8756 error ("SetCommState() failed");
8758 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
8759 pset_childp (p
, childp2
);
8765 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
8769 struct timespec timeout
;
8770 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
8771 int fd
= process
->infd
;
8773 n
= sys_read (fd
, (char*)buf
, sz
);
8780 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8781 if (err
== EWOULDBLOCK
)
8784 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
8790 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
8792 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
8793 int fd
= process
->outfd
;
8794 ssize_t n
= sys_write (fd
, buf
, sz
);
8796 /* 0 or more bytes written means everything went fine. */
8800 /* Negative bytes written means we got an error in errno.
8801 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8802 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
8803 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
8807 #endif /* HAVE_GNUTLS */