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
22 #include <stddef.h> /* for offsetof */
25 #include <float.h> /* for DBL_EPSILON */
32 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
34 #include <sys/utime.h>
37 /* must include CRT headers *before* config.h */
40 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
67 #include "epaths.h" /* for SHELL */
72 /* MinGW64 (_W64) defines these in its _mingw.h. */
73 #if defined(__GNUC__) && !defined(_W64)
74 #define _ANONYMOUS_UNION
75 #define _ANONYMOUS_STRUCT
78 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
79 use a different name to avoid compilation problems. */
80 typedef struct _MEMORY_STATUS_EX
{
83 DWORDLONG ullTotalPhys
;
84 DWORDLONG ullAvailPhys
;
85 DWORDLONG ullTotalPageFile
;
86 DWORDLONG ullAvailPageFile
;
87 DWORDLONG ullTotalVirtual
;
88 DWORDLONG ullAvailVirtual
;
89 DWORDLONG ullAvailExtendedVirtual
;
90 } MEMORY_STATUS_EX
,*LPMEMORY_STATUS_EX
;
92 /* These are here so that GDB would know about these data types. This
93 allows to attach GDB to Emacs when a fatal exception is triggered
94 and Windows pops up the "application needs to be closed" dialog.
95 At that point, _gnu_exception_handler, the top-level exception
96 handler installed by the MinGW startup code, is somewhere on the
97 call-stack of the main thread, so going to that call frame and
98 looking at the argument to _gnu_exception_handler, which is a
99 PEXCEPTION_POINTERS pointer, can reveal the exception code
100 (excptr->ExceptionRecord->ExceptionCode) and the address where the
101 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
102 well as some additional information specific to the exception. */
103 PEXCEPTION_POINTERS excptr
;
104 PEXCEPTION_RECORD excprec
;
110 #include <tlhelp32.h>
115 #if _WIN32_WINNT < 0x0500
116 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
117 /* This either is not in psapi.h or guarded by higher value of
118 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
119 defines it in psapi.h */
120 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
122 DWORD PageFaultCount
;
123 SIZE_T PeakWorkingSetSize
;
124 SIZE_T WorkingSetSize
;
125 SIZE_T QuotaPeakPagedPoolUsage
;
126 SIZE_T QuotaPagedPoolUsage
;
127 SIZE_T QuotaPeakNonPagedPoolUsage
;
128 SIZE_T QuotaNonPagedPoolUsage
;
129 SIZE_T PagefileUsage
;
130 SIZE_T PeakPagefileUsage
;
132 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
136 #include <winioctl.h>
142 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
143 define them by hand if not already defined. */
144 #ifndef SDDL_REVISION_1
145 #define SDDL_REVISION_1 1
146 #endif /* SDDL_REVISION_1 */
148 #if defined(_MSC_VER) || defined(_W64)
149 /* MSVC and MinGW64 don't provide the definition of
150 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
151 which cannot be included because it triggers conflicts with other
152 Windows API headers. So we define it here by hand. */
154 typedef struct _REPARSE_DATA_BUFFER
{
156 USHORT ReparseDataLength
;
160 USHORT SubstituteNameOffset
;
161 USHORT SubstituteNameLength
;
162 USHORT PrintNameOffset
;
163 USHORT PrintNameLength
;
166 } SymbolicLinkReparseBuffer
;
168 USHORT SubstituteNameOffset
;
169 USHORT SubstituteNameLength
;
170 USHORT PrintNameOffset
;
171 USHORT PrintNameLength
;
173 } MountPointReparseBuffer
;
176 } GenericReparseBuffer
;
178 } REPARSE_DATA_BUFFER
, *PREPARSE_DATA_BUFFER
;
180 #ifndef FILE_DEVICE_FILE_SYSTEM
181 #define FILE_DEVICE_FILE_SYSTEM 9
183 #ifndef METHOD_BUFFERED
184 #define METHOD_BUFFERED 0
186 #ifndef FILE_ANY_ACCESS
187 #define FILE_ANY_ACCESS 0x00000000
190 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
192 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
193 #ifndef FSCTL_GET_REPARSE_POINT
194 #define FSCTL_GET_REPARSE_POINT \
195 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
199 /* TCP connection support. */
200 #include <sys/socket.h>
221 #include "w32common.h"
223 #include "w32select.h"
225 #include "dispextern.h" /* for xstrcasecmp */
226 #include "coding.h" /* for Vlocale_coding_system */
228 #include "careadlinkat.h"
229 #include "allocator.h"
231 /* For serial_configure and serial_open. */
234 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
235 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
237 Lisp_Object QCloaded_from
;
239 void globals_of_w32 (void);
240 static DWORD
get_rid (PSID
);
241 static int is_symlink (const char *);
242 static char * chase_symlinks (const char *);
243 static int enable_privilege (LPCTSTR
, BOOL
, TOKEN_PRIVILEGES
*);
244 static int restore_privilege (TOKEN_PRIVILEGES
*);
245 static BOOL WINAPI
revert_to_self (void);
247 extern int sys_access (const char *, int);
248 extern void *e_malloc (size_t);
249 extern int sys_select (int, SELECT_TYPE
*, SELECT_TYPE
*, SELECT_TYPE
*,
250 struct timespec
*, void *);
251 extern int sys_dup (int);
256 /* Initialization states.
258 WARNING: If you add any more such variables for additional APIs,
259 you MUST add initialization for them to globals_of_w32
260 below. This is because these variables might get set
261 to non-NULL values during dumping, but the dumped Emacs
262 cannot reuse those values, because it could be run on a
263 different version of the OS, where API addresses are
265 static BOOL g_b_init_is_windows_9x
;
266 static BOOL g_b_init_open_process_token
;
267 static BOOL g_b_init_get_token_information
;
268 static BOOL g_b_init_lookup_account_sid
;
269 static BOOL g_b_init_get_sid_sub_authority
;
270 static BOOL g_b_init_get_sid_sub_authority_count
;
271 static BOOL g_b_init_get_security_info
;
272 static BOOL g_b_init_get_file_security
;
273 static BOOL g_b_init_get_security_descriptor_owner
;
274 static BOOL g_b_init_get_security_descriptor_group
;
275 static BOOL g_b_init_is_valid_sid
;
276 static BOOL g_b_init_create_toolhelp32_snapshot
;
277 static BOOL g_b_init_process32_first
;
278 static BOOL g_b_init_process32_next
;
279 static BOOL g_b_init_open_thread_token
;
280 static BOOL g_b_init_impersonate_self
;
281 static BOOL g_b_init_revert_to_self
;
282 static BOOL g_b_init_get_process_memory_info
;
283 static BOOL g_b_init_get_process_working_set_size
;
284 static BOOL g_b_init_global_memory_status
;
285 static BOOL g_b_init_global_memory_status_ex
;
286 static BOOL g_b_init_get_length_sid
;
287 static BOOL g_b_init_equal_sid
;
288 static BOOL g_b_init_copy_sid
;
289 static BOOL g_b_init_get_native_system_info
;
290 static BOOL g_b_init_get_system_times
;
291 static BOOL g_b_init_create_symbolic_link
;
292 static BOOL g_b_init_get_security_descriptor_dacl
;
293 static BOOL g_b_init_convert_sd_to_sddl
;
294 static BOOL g_b_init_convert_sddl_to_sd
;
295 static BOOL g_b_init_is_valid_security_descriptor
;
296 static BOOL g_b_init_set_file_security
;
299 BEGIN: Wrapper functions around OpenProcessToken
300 and other functions in advapi32.dll that are only
301 supported in Windows NT / 2k / XP
303 /* ** Function pointer typedefs ** */
304 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
305 HANDLE ProcessHandle
,
307 PHANDLE TokenHandle
);
308 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
310 TOKEN_INFORMATION_CLASS TokenInformationClass
,
311 LPVOID TokenInformation
,
312 DWORD TokenInformationLength
,
313 PDWORD ReturnLength
);
314 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
315 HANDLE process_handle
,
316 LPFILETIME creation_time
,
317 LPFILETIME exit_time
,
318 LPFILETIME kernel_time
,
319 LPFILETIME user_time
);
321 GetProcessTimes_Proc get_process_times_fn
= NULL
;
324 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
325 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
326 const char * const SetFileSecurity_Name
= "SetFileSecurityW";
328 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
329 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
330 const char * const SetFileSecurity_Name
= "SetFileSecurityA";
332 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
333 LPCTSTR lpSystemName
,
338 LPDWORD cbDomainName
,
339 PSID_NAME_USE peUse
);
340 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
343 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
345 typedef DWORD (WINAPI
* GetSecurityInfo_Proc
) (
347 SE_OBJECT_TYPE ObjectType
,
348 SECURITY_INFORMATION SecurityInfo
,
353 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
);
354 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
356 SECURITY_INFORMATION RequestedInformation
,
357 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
359 LPDWORD lpnLengthNeeded
);
360 typedef BOOL (WINAPI
*SetFileSecurity_Proc
) (
362 SECURITY_INFORMATION SecurityInformation
,
363 PSECURITY_DESCRIPTOR pSecurityDescriptor
);
364 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
365 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
367 LPBOOL lpbOwnerDefaulted
);
368 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
369 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
371 LPBOOL lpbGroupDefaulted
);
372 typedef BOOL (WINAPI
*GetSecurityDescriptorDacl_Proc
) (
373 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
374 LPBOOL lpbDaclPresent
,
376 LPBOOL lpbDaclDefaulted
);
377 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
379 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
381 DWORD th32ProcessID
);
382 typedef BOOL (WINAPI
* Process32First_Proc
) (
384 LPPROCESSENTRY32 lppe
);
385 typedef BOOL (WINAPI
* Process32Next_Proc
) (
387 LPPROCESSENTRY32 lppe
);
388 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
392 PHANDLE TokenHandle
);
393 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
394 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
395 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
396 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
398 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
400 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
402 PSIZE_T lpMinimumWorkingSetSize
,
403 PSIZE_T lpMaximumWorkingSetSize
);
404 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
405 LPMEMORYSTATUS lpBuffer
);
406 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
407 LPMEMORY_STATUS_EX lpBuffer
);
408 typedef BOOL (WINAPI
* CopySid_Proc
) (
409 DWORD nDestinationSidLength
,
410 PSID pDestinationSid
,
412 typedef BOOL (WINAPI
* EqualSid_Proc
) (
415 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
417 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
418 LPSYSTEM_INFO lpSystemInfo
);
419 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
420 LPFILETIME lpIdleTime
,
421 LPFILETIME lpKernelTime
,
422 LPFILETIME lpUserTime
);
423 typedef BOOLEAN (WINAPI
*CreateSymbolicLink_Proc
) (
424 LPTSTR lpSymlinkFileName
,
425 LPTSTR lpTargetFileName
,
427 typedef BOOL (WINAPI
*ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
) (
428 LPCTSTR StringSecurityDescriptor
,
429 DWORD StringSDRevision
,
430 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
431 PULONG SecurityDescriptorSize
);
432 typedef BOOL (WINAPI
*ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
) (
433 PSECURITY_DESCRIPTOR SecurityDescriptor
,
434 DWORD RequestedStringSDRevision
,
435 SECURITY_INFORMATION SecurityInformation
,
436 LPTSTR
*StringSecurityDescriptor
,
437 PULONG StringSecurityDescriptorLen
);
438 typedef BOOL (WINAPI
*IsValidSecurityDescriptor_Proc
) (PSECURITY_DESCRIPTOR
);
440 /* ** A utility function ** */
444 static BOOL s_b_ret
= 0;
445 OSVERSIONINFO os_ver
;
446 if (g_b_init_is_windows_9x
== 0)
448 g_b_init_is_windows_9x
= 1;
449 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
450 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
451 if (GetVersionEx (&os_ver
))
453 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
459 static Lisp_Object
ltime (ULONGLONG
);
461 /* Get total user and system times for get-internal-run-time.
462 Returns a list of integers if the times are provided by the OS
463 (NT derivatives), otherwise it returns the result of current-time. */
465 w32_get_internal_run_time (void)
467 if (get_process_times_fn
)
469 FILETIME create
, exit
, kernel
, user
;
470 HANDLE proc
= GetCurrentProcess ();
471 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
473 LARGE_INTEGER user_int
, kernel_int
, total
;
474 user_int
.LowPart
= user
.dwLowDateTime
;
475 user_int
.HighPart
= user
.dwHighDateTime
;
476 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
477 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
478 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
479 return ltime (total
.QuadPart
);
483 return Fcurrent_time ();
486 /* ** The wrapper functions ** */
489 open_process_token (HANDLE ProcessHandle
,
493 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
494 HMODULE hm_advapi32
= NULL
;
495 if (is_windows_9x () == TRUE
)
499 if (g_b_init_open_process_token
== 0)
501 g_b_init_open_process_token
= 1;
502 hm_advapi32
= LoadLibrary ("Advapi32.dll");
503 s_pfn_Open_Process_Token
=
504 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
506 if (s_pfn_Open_Process_Token
== NULL
)
511 s_pfn_Open_Process_Token (
519 get_token_information (HANDLE TokenHandle
,
520 TOKEN_INFORMATION_CLASS TokenInformationClass
,
521 LPVOID TokenInformation
,
522 DWORD TokenInformationLength
,
525 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
526 HMODULE hm_advapi32
= NULL
;
527 if (is_windows_9x () == TRUE
)
531 if (g_b_init_get_token_information
== 0)
533 g_b_init_get_token_information
= 1;
534 hm_advapi32
= LoadLibrary ("Advapi32.dll");
535 s_pfn_Get_Token_Information
=
536 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
538 if (s_pfn_Get_Token_Information
== NULL
)
543 s_pfn_Get_Token_Information (
545 TokenInformationClass
,
547 TokenInformationLength
,
553 lookup_account_sid (LPCTSTR lpSystemName
,
558 LPDWORD cbDomainName
,
561 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
562 HMODULE hm_advapi32
= NULL
;
563 if (is_windows_9x () == TRUE
)
567 if (g_b_init_lookup_account_sid
== 0)
569 g_b_init_lookup_account_sid
= 1;
570 hm_advapi32
= LoadLibrary ("Advapi32.dll");
571 s_pfn_Lookup_Account_Sid
=
572 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
574 if (s_pfn_Lookup_Account_Sid
== NULL
)
579 s_pfn_Lookup_Account_Sid (
591 get_sid_sub_authority (PSID pSid
, DWORD n
)
593 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
594 static DWORD zero
= 0U;
595 HMODULE hm_advapi32
= NULL
;
596 if (is_windows_9x () == TRUE
)
600 if (g_b_init_get_sid_sub_authority
== 0)
602 g_b_init_get_sid_sub_authority
= 1;
603 hm_advapi32
= LoadLibrary ("Advapi32.dll");
604 s_pfn_Get_Sid_Sub_Authority
=
605 (GetSidSubAuthority_Proc
) GetProcAddress (
606 hm_advapi32
, "GetSidSubAuthority");
608 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
612 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
616 get_sid_sub_authority_count (PSID pSid
)
618 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
619 static UCHAR zero
= 0U;
620 HMODULE hm_advapi32
= NULL
;
621 if (is_windows_9x () == TRUE
)
625 if (g_b_init_get_sid_sub_authority_count
== 0)
627 g_b_init_get_sid_sub_authority_count
= 1;
628 hm_advapi32
= LoadLibrary ("Advapi32.dll");
629 s_pfn_Get_Sid_Sub_Authority_Count
=
630 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
631 hm_advapi32
, "GetSidSubAuthorityCount");
633 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
637 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
641 get_security_info (HANDLE handle
,
642 SE_OBJECT_TYPE ObjectType
,
643 SECURITY_INFORMATION SecurityInfo
,
648 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
)
650 static GetSecurityInfo_Proc s_pfn_Get_Security_Info
= NULL
;
651 HMODULE hm_advapi32
= NULL
;
652 if (is_windows_9x () == TRUE
)
656 if (g_b_init_get_security_info
== 0)
658 g_b_init_get_security_info
= 1;
659 hm_advapi32
= LoadLibrary ("Advapi32.dll");
660 s_pfn_Get_Security_Info
=
661 (GetSecurityInfo_Proc
) GetProcAddress (
662 hm_advapi32
, "GetSecurityInfo");
664 if (s_pfn_Get_Security_Info
== NULL
)
668 return (s_pfn_Get_Security_Info (handle
, ObjectType
, SecurityInfo
,
669 ppsidOwner
, ppsidGroup
, ppDacl
, ppSacl
,
670 ppSecurityDescriptor
));
674 get_file_security (LPCTSTR lpFileName
,
675 SECURITY_INFORMATION RequestedInformation
,
676 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
678 LPDWORD lpnLengthNeeded
)
680 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
681 HMODULE hm_advapi32
= NULL
;
682 if (is_windows_9x () == TRUE
)
687 if (g_b_init_get_file_security
== 0)
689 g_b_init_get_file_security
= 1;
690 hm_advapi32
= LoadLibrary ("Advapi32.dll");
691 s_pfn_Get_File_Security
=
692 (GetFileSecurity_Proc
) GetProcAddress (
693 hm_advapi32
, GetFileSecurity_Name
);
695 if (s_pfn_Get_File_Security
== NULL
)
700 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
701 pSecurityDescriptor
, nLength
,
706 set_file_security (LPCTSTR lpFileName
,
707 SECURITY_INFORMATION SecurityInformation
,
708 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
710 static SetFileSecurity_Proc s_pfn_Set_File_Security
= NULL
;
711 HMODULE hm_advapi32
= NULL
;
712 if (is_windows_9x () == TRUE
)
717 if (g_b_init_set_file_security
== 0)
719 g_b_init_set_file_security
= 1;
720 hm_advapi32
= LoadLibrary ("Advapi32.dll");
721 s_pfn_Set_File_Security
=
722 (SetFileSecurity_Proc
) GetProcAddress (
723 hm_advapi32
, SetFileSecurity_Name
);
725 if (s_pfn_Set_File_Security
== NULL
)
730 return (s_pfn_Set_File_Security (lpFileName
, SecurityInformation
,
731 pSecurityDescriptor
));
735 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
737 LPBOOL lpbOwnerDefaulted
)
739 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
740 HMODULE hm_advapi32
= NULL
;
741 if (is_windows_9x () == TRUE
)
746 if (g_b_init_get_security_descriptor_owner
== 0)
748 g_b_init_get_security_descriptor_owner
= 1;
749 hm_advapi32
= LoadLibrary ("Advapi32.dll");
750 s_pfn_Get_Security_Descriptor_Owner
=
751 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
752 hm_advapi32
, "GetSecurityDescriptorOwner");
754 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
759 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
764 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
766 LPBOOL lpbGroupDefaulted
)
768 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
769 HMODULE hm_advapi32
= NULL
;
770 if (is_windows_9x () == TRUE
)
775 if (g_b_init_get_security_descriptor_group
== 0)
777 g_b_init_get_security_descriptor_group
= 1;
778 hm_advapi32
= LoadLibrary ("Advapi32.dll");
779 s_pfn_Get_Security_Descriptor_Group
=
780 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
781 hm_advapi32
, "GetSecurityDescriptorGroup");
783 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
788 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
793 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
794 LPBOOL lpbDaclPresent
,
796 LPBOOL lpbDaclDefaulted
)
798 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl
= NULL
;
799 HMODULE hm_advapi32
= NULL
;
800 if (is_windows_9x () == TRUE
)
805 if (g_b_init_get_security_descriptor_dacl
== 0)
807 g_b_init_get_security_descriptor_dacl
= 1;
808 hm_advapi32
= LoadLibrary ("Advapi32.dll");
809 s_pfn_Get_Security_Descriptor_Dacl
=
810 (GetSecurityDescriptorDacl_Proc
) GetProcAddress (
811 hm_advapi32
, "GetSecurityDescriptorDacl");
813 if (s_pfn_Get_Security_Descriptor_Dacl
== NULL
)
818 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor
,
819 lpbDaclPresent
, pDacl
,
824 is_valid_sid (PSID sid
)
826 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
827 HMODULE hm_advapi32
= NULL
;
828 if (is_windows_9x () == TRUE
)
832 if (g_b_init_is_valid_sid
== 0)
834 g_b_init_is_valid_sid
= 1;
835 hm_advapi32
= LoadLibrary ("Advapi32.dll");
837 (IsValidSid_Proc
) GetProcAddress (
838 hm_advapi32
, "IsValidSid");
840 if (s_pfn_Is_Valid_Sid
== NULL
)
844 return (s_pfn_Is_Valid_Sid (sid
));
848 equal_sid (PSID sid1
, PSID sid2
)
850 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
851 HMODULE hm_advapi32
= NULL
;
852 if (is_windows_9x () == TRUE
)
856 if (g_b_init_equal_sid
== 0)
858 g_b_init_equal_sid
= 1;
859 hm_advapi32
= LoadLibrary ("Advapi32.dll");
861 (EqualSid_Proc
) GetProcAddress (
862 hm_advapi32
, "EqualSid");
864 if (s_pfn_Equal_Sid
== NULL
)
868 return (s_pfn_Equal_Sid (sid1
, sid2
));
872 get_length_sid (PSID sid
)
874 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
875 HMODULE hm_advapi32
= NULL
;
876 if (is_windows_9x () == TRUE
)
880 if (g_b_init_get_length_sid
== 0)
882 g_b_init_get_length_sid
= 1;
883 hm_advapi32
= LoadLibrary ("Advapi32.dll");
884 s_pfn_Get_Length_Sid
=
885 (GetLengthSid_Proc
) GetProcAddress (
886 hm_advapi32
, "GetLengthSid");
888 if (s_pfn_Get_Length_Sid
== NULL
)
892 return (s_pfn_Get_Length_Sid (sid
));
896 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
898 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
899 HMODULE hm_advapi32
= NULL
;
900 if (is_windows_9x () == TRUE
)
904 if (g_b_init_copy_sid
== 0)
906 g_b_init_copy_sid
= 1;
907 hm_advapi32
= LoadLibrary ("Advapi32.dll");
909 (CopySid_Proc
) GetProcAddress (
910 hm_advapi32
, "CopySid");
912 if (s_pfn_Copy_Sid
== NULL
)
916 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
920 END: Wrapper functions around OpenProcessToken
921 and other functions in advapi32.dll that are only
922 supported in Windows NT / 2k / XP
926 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
928 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
929 if (is_windows_9x () != TRUE
)
931 if (g_b_init_get_native_system_info
== 0)
933 g_b_init_get_native_system_info
= 1;
934 s_pfn_Get_Native_System_Info
=
935 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
936 "GetNativeSystemInfo");
938 if (s_pfn_Get_Native_System_Info
!= NULL
)
939 s_pfn_Get_Native_System_Info (lpSystemInfo
);
942 lpSystemInfo
->dwNumberOfProcessors
= -1;
946 get_system_times (LPFILETIME lpIdleTime
,
947 LPFILETIME lpKernelTime
,
948 LPFILETIME lpUserTime
)
950 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
951 if (is_windows_9x () == TRUE
)
955 if (g_b_init_get_system_times
== 0)
957 g_b_init_get_system_times
= 1;
958 s_pfn_Get_System_times
=
959 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
962 if (s_pfn_Get_System_times
== NULL
)
964 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
967 static BOOLEAN WINAPI
968 create_symbolic_link (LPTSTR lpSymlinkFilename
,
969 LPTSTR lpTargetFileName
,
972 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link
= NULL
;
975 if (is_windows_9x () == TRUE
)
980 if (g_b_init_create_symbolic_link
== 0)
982 g_b_init_create_symbolic_link
= 1;
984 s_pfn_Create_Symbolic_Link
=
985 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
986 "CreateSymbolicLinkW");
988 s_pfn_Create_Symbolic_Link
=
989 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
990 "CreateSymbolicLinkA");
993 if (s_pfn_Create_Symbolic_Link
== NULL
)
999 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
1001 /* If we were denied creation of the symlink, try again after
1002 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1005 TOKEN_PRIVILEGES priv_current
;
1007 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME
, TRUE
, &priv_current
))
1009 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
1011 restore_privilege (&priv_current
);
1019 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor
)
1021 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc
= NULL
;
1023 if (is_windows_9x () == TRUE
)
1029 if (g_b_init_is_valid_security_descriptor
== 0)
1031 g_b_init_is_valid_security_descriptor
= 1;
1032 s_pfn_Is_Valid_Security_Descriptor_Proc
=
1033 (IsValidSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1034 "IsValidSecurityDescriptor");
1036 if (s_pfn_Is_Valid_Security_Descriptor_Proc
== NULL
)
1042 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor
);
1046 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor
,
1047 DWORD RequestedStringSDRevision
,
1048 SECURITY_INFORMATION SecurityInformation
,
1049 LPTSTR
*StringSecurityDescriptor
,
1050 PULONG StringSecurityDescriptorLen
)
1052 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL
= NULL
;
1055 if (is_windows_9x () == TRUE
)
1061 if (g_b_init_convert_sd_to_sddl
== 0)
1063 g_b_init_convert_sd_to_sddl
= 1;
1065 s_pfn_Convert_SD_To_SDDL
=
1066 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1067 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1069 s_pfn_Convert_SD_To_SDDL
=
1070 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1071 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1074 if (s_pfn_Convert_SD_To_SDDL
== NULL
)
1080 retval
= s_pfn_Convert_SD_To_SDDL (SecurityDescriptor
,
1081 RequestedStringSDRevision
,
1082 SecurityInformation
,
1083 StringSecurityDescriptor
,
1084 StringSecurityDescriptorLen
);
1090 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor
,
1091 DWORD StringSDRevision
,
1092 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
1093 PULONG SecurityDescriptorSize
)
1095 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD
= NULL
;
1098 if (is_windows_9x () == TRUE
)
1104 if (g_b_init_convert_sddl_to_sd
== 0)
1106 g_b_init_convert_sddl_to_sd
= 1;
1108 s_pfn_Convert_SDDL_To_SD
=
1109 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1110 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1112 s_pfn_Convert_SDDL_To_SD
=
1113 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1114 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1117 if (s_pfn_Convert_SDDL_To_SD
== NULL
)
1123 retval
= s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor
,
1126 SecurityDescriptorSize
);
1133 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1134 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1136 This is called from alloc.c:valid_pointer_p. */
1138 w32_valid_pointer_p (void *p
, int size
)
1141 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
1145 unsigned char *buf
= alloca (size
);
1146 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
1155 static char startup_dir
[MAXPATHLEN
];
1157 /* Get the current working directory. */
1159 getcwd (char *dir
, int dirsize
)
1166 if (dirsize
<= strlen (startup_dir
))
1172 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
1176 /* Emacs doesn't actually change directory itself, it stays in the
1177 same directory where it was started. */
1178 strcpy (dir
, startup_dir
);
1183 /* Emulate getloadavg. */
1185 struct load_sample
{
1192 /* Number of processors on this machine. */
1193 static unsigned num_of_processors
;
1195 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1196 static struct load_sample samples
[16*60];
1197 static int first_idx
= -1, last_idx
= -1;
1198 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
1203 int next_idx
= from
+ 1;
1205 if (next_idx
>= max_idx
)
1214 int prev_idx
= from
- 1;
1217 prev_idx
= max_idx
- 1;
1223 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
1225 SYSTEM_INFO sysinfo
;
1226 FILETIME ft_idle
, ft_user
, ft_kernel
;
1228 /* Initialize the number of processors on this machine. */
1229 if (num_of_processors
<= 0)
1231 get_native_system_info (&sysinfo
);
1232 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1233 if (num_of_processors
<= 0)
1235 GetSystemInfo (&sysinfo
);
1236 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1238 if (num_of_processors
<= 0)
1239 num_of_processors
= 1;
1242 /* TODO: Take into account threads that are ready to run, by
1243 sampling the "\System\Processor Queue Length" performance
1244 counter. The code below accounts only for threads that are
1245 actually running. */
1247 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
1249 ULARGE_INTEGER uidle
, ukernel
, uuser
;
1251 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
1252 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
1253 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
1254 *idle
= uidle
.QuadPart
;
1255 *kernel
= ukernel
.QuadPart
;
1256 *user
= uuser
.QuadPart
;
1266 /* Produce the load average for a given time interval, using the
1267 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1268 1-minute, 5-minute, or 15-minute average, respectively. */
1272 double retval
= -1.0;
1275 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
1276 time_t now
= samples
[last_idx
].sample_time
;
1278 if (first_idx
!= last_idx
)
1280 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
1282 tdiff
= difftime (now
, samples
[idx
].sample_time
);
1283 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
1286 samples
[last_idx
].kernel
+ samples
[last_idx
].user
1287 - (samples
[idx
].kernel
+ samples
[idx
].user
);
1288 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
1290 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
1293 if (idx
== first_idx
)
1302 getloadavg (double loadavg
[], int nelem
)
1305 ULONGLONG idle
, kernel
, user
;
1306 time_t now
= time (NULL
);
1308 /* Store another sample. We ignore samples that are less than 1 sec
1310 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
1312 sample_system_load (&idle
, &kernel
, &user
);
1313 last_idx
= buf_next (last_idx
);
1314 samples
[last_idx
].sample_time
= now
;
1315 samples
[last_idx
].idle
= idle
;
1316 samples
[last_idx
].kernel
= kernel
;
1317 samples
[last_idx
].user
= user
;
1318 /* If the buffer has more that 15 min worth of samples, discard
1320 if (first_idx
== -1)
1321 first_idx
= last_idx
;
1322 while (first_idx
!= last_idx
1323 && (difftime (now
, samples
[first_idx
].sample_time
)
1324 >= 15.0*60 + 2*DBL_EPSILON
*now
))
1325 first_idx
= buf_next (first_idx
);
1328 for (elem
= 0; elem
< nelem
; elem
++)
1330 double avg
= getavg (elem
);
1334 loadavg
[elem
] = avg
;
1340 /* Emulate getpwuid, getpwnam and others. */
1342 #define PASSWD_FIELD_SIZE 256
1344 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1345 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1346 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1347 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
1348 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
1350 static struct passwd dflt_passwd
=
1362 static char dflt_group_name
[GNLEN
+1];
1364 static struct group dflt_group
=
1366 /* When group information is not available, we return this as the
1367 group for all files. */
1375 return dflt_passwd
.pw_uid
;
1381 /* I could imagine arguing for checking to see whether the user is
1382 in the Administrators group and returning a UID of 0 for that
1383 case, but I don't know how wise that would be in the long run. */
1390 return dflt_passwd
.pw_gid
;
1400 getpwuid (unsigned uid
)
1402 if (uid
== dflt_passwd
.pw_uid
)
1403 return &dflt_passwd
;
1408 getgrgid (gid_t gid
)
1414 getpwnam (char *name
)
1418 pw
= getpwuid (getuid ());
1422 if (xstrcasecmp (name
, pw
->pw_name
))
1429 init_user_info (void)
1431 /* Find the user's real name by opening the process token and
1432 looking up the name associated with the user-sid in that token.
1434 Use the relative portion of the identifier authority value from
1435 the user-sid as the user id value (same for group id using the
1436 primary group sid from the process token). */
1438 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1439 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1440 DWORD glength
= sizeof (gname
);
1441 HANDLE token
= NULL
;
1442 SID_NAME_USE user_type
;
1443 unsigned char *buf
= NULL
;
1445 TOKEN_USER user_token
;
1446 TOKEN_PRIMARY_GROUP group_token
;
1449 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1452 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1453 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1455 buf
= xmalloc (blen
);
1456 result
= get_token_information (token
, TokenUser
,
1457 (LPVOID
)buf
, blen
, &needed
);
1460 memcpy (&user_token
, buf
, sizeof (user_token
));
1461 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1463 domain
, &dlength
, &user_type
);
1471 strcpy (dflt_passwd
.pw_name
, uname
);
1472 /* Determine a reasonable uid value. */
1473 if (xstrcasecmp ("administrator", uname
) == 0)
1475 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1476 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1480 /* Use the last sub-authority value of the RID, the relative
1481 portion of the SID, as user/group ID. */
1482 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1484 /* Get group id and name. */
1485 result
= get_token_information (token
, TokenPrimaryGroup
,
1486 (LPVOID
)buf
, blen
, &needed
);
1487 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1489 buf
= xrealloc (buf
, blen
= needed
);
1490 result
= get_token_information (token
, TokenPrimaryGroup
,
1491 (LPVOID
)buf
, blen
, &needed
);
1495 memcpy (&group_token
, buf
, sizeof (group_token
));
1496 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1497 dlength
= sizeof (domain
);
1498 /* If we can get at the real Primary Group name, use that.
1499 Otherwise, the default group name was already set to
1500 "None" in globals_of_w32. */
1501 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1502 gname
, &glength
, NULL
, &dlength
,
1504 strcpy (dflt_group_name
, gname
);
1507 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1510 /* If security calls are not supported (presumably because we
1511 are running under Windows 9X), fallback to this: */
1512 else if (GetUserName (uname
, &ulength
))
1514 strcpy (dflt_passwd
.pw_name
, uname
);
1515 if (xstrcasecmp ("administrator", uname
) == 0)
1516 dflt_passwd
.pw_uid
= 0;
1518 dflt_passwd
.pw_uid
= 123;
1519 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1523 strcpy (dflt_passwd
.pw_name
, "unknown");
1524 dflt_passwd
.pw_uid
= 123;
1525 dflt_passwd
.pw_gid
= 123;
1527 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1529 /* Ensure HOME and SHELL are defined. */
1530 if (getenv ("HOME") == NULL
)
1532 if (getenv ("SHELL") == NULL
)
1535 /* Set dir and shell from environment variables. */
1536 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1537 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1541 CloseHandle (token
);
1547 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1548 return ((rand () << 15) | rand ());
1557 /* Current codepage for encoding file names. */
1558 static int file_name_codepage
;
1560 /* Return the maximum length in bytes of a multibyte character
1561 sequence encoded in the current ANSI codepage. This is required to
1562 correctly walk the encoded file names one character at a time. */
1564 max_filename_mbslen (void)
1566 /* A simple cache to avoid calling GetCPInfo every time we need to
1567 normalize a file name. The file-name encoding is not supposed to
1568 be changed too frequently, if ever. */
1569 static Lisp_Object last_file_name_encoding
;
1570 static int last_max_mbslen
;
1571 Lisp_Object current_encoding
;
1573 current_encoding
= Vfile_name_coding_system
;
1574 if (NILP (current_encoding
))
1575 current_encoding
= Vdefault_file_name_coding_system
;
1577 if (!EQ (last_file_name_encoding
, current_encoding
))
1581 last_file_name_encoding
= current_encoding
;
1582 /* Default to the current ANSI codepage. */
1583 file_name_codepage
= w32_ansi_code_page
;
1584 if (!NILP (current_encoding
))
1586 char *cpname
= SDATA (SYMBOL_NAME (current_encoding
));
1587 char *cp
= NULL
, *end
;
1590 if (strncmp (cpname
, "cp", 2) == 0)
1592 else if (strncmp (cpname
, "windows-", 8) == 0)
1598 cpnum
= strtol (cp
, &end
, 10);
1599 if (cpnum
&& *end
== '\0' && end
- cp
>= 2)
1600 file_name_codepage
= cpnum
;
1604 if (!file_name_codepage
)
1605 file_name_codepage
= CP_ACP
; /* CP_ACP = 0, but let's not assume that */
1607 if (!GetCPInfo (file_name_codepage
, &cp_info
))
1609 file_name_codepage
= CP_ACP
;
1610 if (!GetCPInfo (file_name_codepage
, &cp_info
))
1613 last_max_mbslen
= cp_info
.MaxCharSize
;
1616 return last_max_mbslen
;
1619 /* Normalize filename by converting all path separators to
1620 the specified separator. Also conditionally convert upper
1621 case path name components to lower case. */
1624 normalize_filename (register char *fp
, char path_sep
, int multibyte
)
1628 int dbcs_p
= max_filename_mbslen () > 1;
1630 /* Multibyte file names are in the Emacs internal representation, so
1631 we can traverse them by bytes with no problems. */
1635 /* Always lower-case drive letters a-z, even if the filesystem
1636 preserves case in filenames.
1637 This is so filenames can be compared by string comparison
1638 functions that are case-sensitive. Even case-preserving filesystems
1639 do not distinguish case in drive letters. */
1641 p2
= CharNextExA (file_name_codepage
, fp
, 0);
1645 if (*p2
== ':' && *fp
>= 'A' && *fp
<= 'Z')
1651 if (multibyte
|| NILP (Vw32_downcase_file_names
))
1655 if (*fp
== '/' || *fp
== '\\')
1660 fp
= CharNextExA (file_name_codepage
, fp
, 0);
1665 sep
= path_sep
; /* convert to this path separator */
1666 elem
= fp
; /* start of current path element */
1669 if (*fp
>= 'a' && *fp
<= 'z')
1670 elem
= 0; /* don't convert this element */
1672 if (*fp
== 0 || *fp
== ':')
1674 sep
= *fp
; /* restore current separator (or 0) */
1675 *fp
= '/'; /* after conversion of this element */
1678 if (*fp
== '/' || *fp
== '\\')
1680 if (elem
&& elem
!= fp
)
1682 *fp
= 0; /* temporary end of string */
1683 _mbslwr (elem
); /* while we convert to lower case */
1685 *fp
= sep
; /* convert (or restore) path separator */
1686 elem
= fp
+ 1; /* next element starts after separator */
1694 fp
= CharNextExA (file_name_codepage
, fp
, 0);
1699 /* Destructively turn backslashes into slashes. MULTIBYTE non-zero
1700 means the file name is a multibyte string in Emacs's internal
1703 dostounix_filename (register char *p
, int multibyte
)
1705 normalize_filename (p
, '/', multibyte
);
1708 /* Destructively turn slashes into backslashes. */
1710 unixtodos_filename (register char *p
)
1712 normalize_filename (p
, '\\', 0);
1715 /* Remove all CR's that are followed by a LF.
1716 (From msdos.c...probably should figure out a way to share it,
1717 although this code isn't going to ever change.) */
1719 crlf_to_lf (register int n
, register unsigned char *buf
)
1721 unsigned char *np
= buf
;
1722 unsigned char *startp
= buf
;
1723 unsigned char *endp
= buf
+ n
;
1727 while (buf
< endp
- 1)
1731 if (*(++buf
) != 0x0a)
1742 /* Parse the root part of file name, if present. Return length and
1743 optionally store pointer to char after root. */
1745 parse_root (char * name
, char ** pPath
)
1747 char * start
= name
;
1752 /* find the root name of the volume if given */
1753 if (isalpha (name
[0]) && name
[1] == ':')
1755 /* skip past drive specifier */
1757 if (IS_DIRECTORY_SEP (name
[0]))
1760 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1763 int dbcs_p
= max_filename_mbslen () > 1;
1768 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1771 name
= CharNextExA (file_name_codepage
, name
, 0);
1776 if (IS_DIRECTORY_SEP (name
[0]))
1783 return name
- start
;
1786 /* Get long base name for name; name is assumed to be absolute. */
1788 get_long_basename (char * name
, char * buf
, int size
)
1790 WIN32_FIND_DATA find_data
;
1794 /* must be valid filename, no wild cards or other invalid characters */
1795 if (_mbspbrk (name
, "*?|<>\""))
1798 dir_handle
= FindFirstFile (name
, &find_data
);
1799 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1801 if ((len
= strlen (find_data
.cFileName
)) < size
)
1802 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1805 FindClose (dir_handle
);
1810 /* Get long name for file, if possible (assumed to be absolute). */
1812 w32_get_long_filename (char * name
, char * buf
, int size
)
1817 char full
[ MAX_PATH
];
1820 len
= strlen (name
);
1821 if (len
>= MAX_PATH
)
1824 /* Use local copy for destructive modification. */
1825 memcpy (full
, name
, len
+1);
1826 unixtodos_filename (full
);
1828 /* Copy root part verbatim. */
1829 len
= parse_root (full
, &p
);
1830 memcpy (o
, full
, len
);
1835 while (p
!= NULL
&& *p
)
1838 p
= _mbschr (q
, '\\');
1840 len
= get_long_basename (full
, o
, size
);
1863 is_unc_volume (const char *filename
)
1865 const char *ptr
= filename
;
1867 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1870 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1876 /* Emulate the Posix unsetenv. */
1878 unsetenv (const char *name
)
1884 if (name
== NULL
|| *name
== '\0' || strchr (name
, '=') != NULL
)
1889 name_len
= strlen (name
);
1890 /* MS docs says an environment variable cannot be longer than 32K. */
1891 if (name_len
> 32767)
1896 /* It is safe to use 'alloca' with 32K size, since the stack is at
1897 least 2MB, and we set it to 8MB in the link command line. */
1898 var
= alloca (name_len
+ 2);
1899 strncpy (var
, name
, name_len
);
1900 var
[name_len
++] = '=';
1901 var
[name_len
] = '\0';
1902 return _putenv (var
);
1905 /* MS _putenv doesn't support removing a variable when the argument
1906 does not include the '=' character, so we fix that here. */
1908 sys_putenv (char *str
)
1910 const char *const name_end
= strchr (str
, '=');
1912 if (name_end
== NULL
)
1914 /* Remove the variable from the environment. */
1915 return unsetenv (str
);
1918 return _putenv (str
);
1921 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1924 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1927 HKEY hrootkey
= NULL
;
1930 /* Check both the current user and the local machine to see if
1931 we have any resources. */
1933 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1937 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1938 && (lpvalue
= xmalloc (cbData
)) != NULL
1939 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1941 RegCloseKey (hrootkey
);
1947 RegCloseKey (hrootkey
);
1950 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1954 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1955 && (lpvalue
= xmalloc (cbData
)) != NULL
1956 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1958 RegCloseKey (hrootkey
);
1964 RegCloseKey (hrootkey
);
1970 char *get_emacs_configuration (void);
1973 init_environment (char ** argv
)
1975 static const char * const tempdirs
[] = {
1976 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1981 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1983 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1984 temporary files and assume "/tmp" if $TMPDIR is unset, which
1985 will break on DOS/Windows. Refuse to work if we cannot find
1986 a directory, not even "c:/", usable for that purpose. */
1987 for (i
= 0; i
< imax
; i
++)
1989 const char *tmp
= tempdirs
[i
];
1992 tmp
= getenv (tmp
+ 1);
1993 /* Note that `access' can lie to us if the directory resides on a
1994 read-only filesystem, like CD-ROM or a write-protected floppy.
1995 The only way to be really sure is to actually create a file and
1996 see if it succeeds. But I think that's too much to ask. */
1998 /* MSVCRT's _access crashes with D_OK. */
1999 if (tmp
&& faccessat (AT_FDCWD
, tmp
, D_OK
, AT_EACCESS
) == 0)
2001 char * var
= alloca (strlen (tmp
) + 8);
2002 sprintf (var
, "TMPDIR=%s", tmp
);
2003 _putenv (strdup (var
));
2010 Fcons (build_string ("no usable temporary directories found!!"),
2012 "While setting TMPDIR: ");
2014 /* Check for environment variables and use registry settings if they
2015 don't exist. Fallback on default values where applicable. */
2020 char locale_name
[32];
2021 char default_home
[MAX_PATH
];
2024 static const struct env_entry
2030 /* If the default value is NULL, we will use the value from the
2031 outside environment or the Registry, but will not push the
2032 variable into the Emacs environment if it is defined neither
2033 in the Registry nor in the outside environment. */
2035 {"PRELOAD_WINSOCK", NULL
},
2036 {"emacs_dir", "C:/emacs"},
2037 {"EMACSLOADPATH", NULL
},
2038 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2039 {"EMACSDATA", NULL
},
2040 {"EMACSPATH", NULL
},
2047 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2049 /* We need to copy dflt_envvars[] and work on the copy because we
2050 don't want the dumped Emacs to inherit the values of
2051 environment variables we saw during dumping (which could be on
2052 a different system). The defaults above must be left intact. */
2053 struct env_entry env_vars
[N_ENV_VARS
];
2055 for (i
= 0; i
< N_ENV_VARS
; i
++)
2056 env_vars
[i
] = dflt_envvars
[i
];
2058 /* For backwards compatibility, check if a .emacs file exists in C:/
2059 If not, then we can try to default to the appdata directory under the
2060 user's profile, which is more likely to be writable. */
2061 if (!check_existing ("C:/.emacs"))
2063 HRESULT profile_result
;
2064 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2065 of Windows 95 and NT4 that have not been updated to include
2067 ShGetFolderPath_fn get_folder_path
;
2068 get_folder_path
= (ShGetFolderPath_fn
)
2069 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2071 if (get_folder_path
!= NULL
)
2073 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
2076 /* If we can't get the appdata dir, revert to old behavior. */
2077 if (profile_result
== S_OK
)
2079 env_vars
[0].def_value
= default_home
;
2085 /* Get default locale info and use it for LANG. */
2086 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
2087 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
2088 locale_name
, sizeof (locale_name
)))
2090 for (i
= 0; i
< N_ENV_VARS
; i
++)
2092 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
2094 env_vars
[i
].def_value
= locale_name
;
2100 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2102 /* Treat emacs_dir specially: set it unconditionally based on our
2106 char modname
[MAX_PATH
];
2108 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2110 if ((p
= _mbsrchr (modname
, '\\')) == NULL
)
2114 if ((p
= _mbsrchr (modname
, '\\'))
2115 /* From bin means installed Emacs, from src means uninstalled. */
2116 && (xstrcasecmp (p
, "\\bin") == 0 || xstrcasecmp (p
, "\\src") == 0))
2118 char buf
[SET_ENV_BUF_SIZE
];
2119 int within_build_tree
= xstrcasecmp (p
, "\\src") == 0;
2122 for (p
= modname
; *p
; p
= CharNext (p
))
2123 if (*p
== '\\') *p
= '/';
2125 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
2126 _putenv (strdup (buf
));
2127 /* If we are running from the Posix-like build tree, define
2128 SHELL to point to our own cmdproxy. The loop below will
2129 then disregard PATH_EXEC and the default value. */
2130 if (within_build_tree
)
2132 _snprintf (buf
, sizeof (buf
) - 1,
2133 "SHELL=%s/nt/cmdproxy.exe", modname
);
2134 _putenv (strdup (buf
));
2137 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
2139 /* FIXME: should use substring of get_emacs_configuration ().
2140 But I don't think the Windows build supports alpha, mips etc
2141 anymore, so have taken the easy option for now. */
2142 else if (p
&& (xstrcasecmp (p
, "\\i386") == 0
2143 || xstrcasecmp (p
, "\\AMD64") == 0))
2146 p
= _mbsrchr (modname
, '\\');
2150 p
= _mbsrchr (modname
, '\\');
2151 if (p
&& xstrcasecmp (p
, "\\src") == 0)
2153 char buf
[SET_ENV_BUF_SIZE
];
2156 for (p
= modname
; *p
; p
= CharNext (p
))
2157 if (*p
== '\\') *p
= '/';
2159 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
2160 _putenv (strdup (buf
));
2166 for (i
= 0; i
< N_ENV_VARS
; i
++)
2168 if (!getenv (env_vars
[i
].name
))
2171 char bufc
[SET_ENV_BUF_SIZE
];
2173 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
2174 /* Also ignore empty environment variables. */
2179 if (strcmp (env_vars
[i
].name
, "SHELL") == 0)
2181 /* Look for cmdproxy.exe in every directory in
2182 PATH_EXEC. FIXME: This does not find cmdproxy
2183 in nt/ when we run uninstalled. */
2184 char fname
[MAX_PATH
];
2185 const char *pstart
= PATH_EXEC
, *pend
;
2188 pend
= _mbschr (pstart
, ';');
2190 pend
= pstart
+ strlen (pstart
);
2191 /* Be defensive against series of ;;; characters. */
2194 strncpy (fname
, pstart
, pend
- pstart
);
2195 fname
[pend
- pstart
] = '/';
2196 strcpy (&fname
[pend
- pstart
+ 1], "cmdproxy.exe");
2197 ExpandEnvironmentStrings ((LPSTR
) fname
, bufc
,
2199 if (check_existing (bufc
))
2212 /* If not found in any directory, use the
2213 default as the last resort. */
2214 lpval
= env_vars
[i
].def_value
;
2215 dwType
= REG_EXPAND_SZ
;
2221 lpval
= env_vars
[i
].def_value
;
2222 dwType
= REG_EXPAND_SZ
;
2224 if (strcmp (env_vars
[i
].name
, "HOME") == 0 && !appdata
)
2225 Vdelayed_warnings_list
2226 = Fcons (listn (CONSTYPE_HEAP
, 2,
2227 intern ("initialization"),
2228 build_string ("Setting HOME to C:\\ by default is deprecated")),
2229 Vdelayed_warnings_list
);
2234 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
2236 if (dwType
== REG_EXPAND_SZ
)
2237 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
2238 else if (dwType
== REG_SZ
)
2239 strcpy (buf1
, lpval
);
2240 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
2242 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
2244 _putenv (strdup (buf2
));
2254 /* Rebuild system configuration to reflect invoking system. */
2255 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
2257 /* Another special case: on NT, the PATH variable is actually named
2258 "Path" although cmd.exe (perhaps NT itself) arranges for
2259 environment variable lookup and setting to be case insensitive.
2260 However, Emacs assumes a fully case sensitive environment, so we
2261 need to change "Path" to "PATH" to match the expectations of
2262 various elisp packages. We do this by the sneaky method of
2263 modifying the string in the C runtime environ entry.
2265 The same applies to COMSPEC. */
2269 for (envp
= environ
; *envp
; envp
++)
2270 if (_strnicmp (*envp
, "PATH=", 5) == 0)
2271 memcpy (*envp
, "PATH=", 5);
2272 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
2273 memcpy (*envp
, "COMSPEC=", 8);
2276 /* Remember the initial working directory for getcwd. */
2277 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2278 Does it matter anywhere in Emacs? */
2279 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
2283 static char modname
[MAX_PATH
];
2285 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2290 /* Determine if there is a middle mouse button, to allow parse_button
2291 to decide whether right mouse events should be mouse-2 or
2293 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
2298 /* Called from expand-file-name when default-directory is not a string. */
2301 emacs_root_dir (void)
2303 static char root_dir
[FILENAME_MAX
];
2306 p
= getenv ("emacs_dir");
2309 strcpy (root_dir
, p
);
2310 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
2311 dostounix_filename (root_dir
, 0);
2315 /* We don't have scripts to automatically determine the system configuration
2316 for Emacs before it's compiled, and we don't want to have to make the
2317 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
2321 get_emacs_configuration (void)
2323 char *arch
, *oem
, *os
;
2325 static char configuration_buffer
[32];
2327 /* Determine the processor type. */
2328 switch (get_processor_type ())
2331 #ifdef PROCESSOR_INTEL_386
2332 case PROCESSOR_INTEL_386
:
2333 case PROCESSOR_INTEL_486
:
2334 case PROCESSOR_INTEL_PENTIUM
:
2342 #ifdef PROCESSOR_AMD_X8664
2343 case PROCESSOR_AMD_X8664
:
2348 #ifdef PROCESSOR_MIPS_R2000
2349 case PROCESSOR_MIPS_R2000
:
2350 case PROCESSOR_MIPS_R3000
:
2351 case PROCESSOR_MIPS_R4000
:
2356 #ifdef PROCESSOR_ALPHA_21064
2357 case PROCESSOR_ALPHA_21064
:
2367 /* Use the OEM field to reflect the compiler/library combination. */
2369 #define COMPILER_NAME "msvc"
2372 #define COMPILER_NAME "mingw"
2374 #define COMPILER_NAME "unknown"
2377 oem
= COMPILER_NAME
;
2379 switch (osinfo_cache
.dwPlatformId
) {
2380 case VER_PLATFORM_WIN32_NT
:
2382 build_num
= osinfo_cache
.dwBuildNumber
;
2384 case VER_PLATFORM_WIN32_WINDOWS
:
2385 if (osinfo_cache
.dwMinorVersion
== 0) {
2390 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
2392 case VER_PLATFORM_WIN32s
:
2393 /* Not supported, should not happen. */
2395 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
2403 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
2404 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
2405 get_w32_major_version (), get_w32_minor_version (), build_num
);
2407 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
2410 return configuration_buffer
;
2414 get_emacs_configuration_options (void)
2416 static char *options_buffer
;
2417 char cv
[32]; /* Enough for COMPILER_VERSION. */
2419 cv
, /* To be filled later. */
2423 #ifdef ENABLE_CHECKING
2424 " --enable-checking",
2426 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2427 with a starting space to save work here. */
2429 " --cflags", USER_CFLAGS
,
2432 " --ldflags", USER_LDFLAGS
,
2439 /* Work out the effective configure options for this build. */
2441 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2444 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2446 #define COMPILER_VERSION ""
2450 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
2451 return "Error: not enough space for compiler version";
2452 cv
[sizeof (cv
) - 1] = '\0';
2454 for (i
= 0; options
[i
]; i
++)
2455 size
+= strlen (options
[i
]);
2457 options_buffer
= xmalloc (size
+ 1);
2458 options_buffer
[0] = '\0';
2460 for (i
= 0; options
[i
]; i
++)
2461 strcat (options_buffer
, options
[i
]);
2463 return options_buffer
;
2467 #include <sys/timeb.h>
2469 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2471 gettimeofday (struct timeval
*__restrict tv
, struct timezone
*__restrict tz
)
2476 tv
->tv_sec
= tb
.time
;
2477 tv
->tv_usec
= tb
.millitm
* 1000L;
2478 /* Implementation note: _ftime sometimes doesn't update the dstflag
2479 according to the new timezone when the system timezone is
2480 changed. We could fix that by using GetSystemTime and
2481 GetTimeZoneInformation, but that doesn't seem necessary, since
2482 Emacs always calls gettimeofday with the 2nd argument NULL (see
2483 current_emacs_time). */
2486 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
2487 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
2492 /* Emulate fdutimens. */
2494 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2495 TIMESPEC[0] and TIMESPEC[1], respectively.
2496 FD must be either negative -- in which case it is ignored --
2497 or a file descriptor that is open on FILE.
2498 If FD is nonnegative, then FILE can be NULL, which means
2499 use just futimes instead of utimes.
2500 If TIMESPEC is null, FAIL.
2501 Return 0 on success, -1 (setting errno) on failure. */
2504 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
2511 if (fd
< 0 && !file
)
2516 /* _futime's prototype defines 2nd arg as having the type 'struct
2517 _utimbuf', while utime needs to accept 'struct utimbuf' for
2518 compatibility with Posix. So we need to use 2 different (but
2519 equivalent) types to avoid compiler warnings, sigh. */
2522 struct _utimbuf _ut
;
2524 _ut
.actime
= timespec
[0].tv_sec
;
2525 _ut
.modtime
= timespec
[1].tv_sec
;
2526 return _futime (fd
, &_ut
);
2532 ut
.actime
= timespec
[0].tv_sec
;
2533 ut
.modtime
= timespec
[1].tv_sec
;
2534 /* Call 'utime', which is implemented below, not the MS library
2535 function, which fails on directories. */
2536 return utime (file
, &ut
);
2541 /* ------------------------------------------------------------------------- */
2542 /* IO support and wrapper functions for the Windows API. */
2543 /* ------------------------------------------------------------------------- */
2545 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2546 on network directories, so we handle that case here.
2547 (Ulrich Leodolter, 1/11/95). */
2549 sys_ctime (const time_t *t
)
2551 char *str
= (char *) ctime (t
);
2552 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2555 /* Emulate sleep...we could have done this with a define, but that
2556 would necessitate including windows.h in the files that used it.
2557 This is much easier. */
2559 sys_sleep (int seconds
)
2561 Sleep (seconds
* 1000);
2564 /* Internal MSVC functions for low-level descriptor munging */
2565 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2566 extern int __cdecl
_free_osfhnd (int fd
);
2568 /* parallel array of private info on file handles */
2569 filedesc fd_info
[ MAXDESC
];
2571 typedef struct volume_info_data
{
2572 struct volume_info_data
* next
;
2574 /* time when info was obtained */
2577 /* actual volume info */
2586 /* Global referenced by various functions. */
2587 static volume_info_data volume_info
;
2589 /* Vector to indicate which drives are local and fixed (for which cached
2590 data never expires). */
2591 static BOOL fixed_drives
[26];
2593 /* Consider cached volume information to be stale if older than 10s,
2594 at least for non-local drives. Info for fixed drives is never stale. */
2595 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2596 #define VOLINFO_STILL_VALID( root_dir, info ) \
2597 ( ( isalpha (root_dir[0]) && \
2598 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2599 || GetTickCount () - info->timestamp < 10000 )
2601 /* Cache support functions. */
2603 /* Simple linked list with linear search is sufficient. */
2604 static volume_info_data
*volume_cache
= NULL
;
2606 static volume_info_data
*
2607 lookup_volume_info (char * root_dir
)
2609 volume_info_data
* info
;
2611 for (info
= volume_cache
; info
; info
= info
->next
)
2612 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2618 add_volume_info (char * root_dir
, volume_info_data
* info
)
2620 info
->root_dir
= xstrdup (root_dir
);
2621 info
->next
= volume_cache
;
2622 volume_cache
= info
;
2626 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2627 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2628 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2629 static volume_info_data
*
2630 GetCachedVolumeInformation (char * root_dir
)
2632 volume_info_data
* info
;
2633 char default_root
[ MAX_PATH
];
2635 /* NULL for root_dir means use root from current directory. */
2636 if (root_dir
== NULL
)
2638 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2640 parse_root (default_root
, &root_dir
);
2642 root_dir
= default_root
;
2645 /* Local fixed drives can be cached permanently. Removable drives
2646 cannot be cached permanently, since the volume name and serial
2647 number (if nothing else) can change. Remote drives should be
2648 treated as if they are removable, since there is no sure way to
2649 tell whether they are or not. Also, the UNC association of drive
2650 letters mapped to remote volumes can be changed at any time (even
2651 by other processes) without notice.
2653 As a compromise, so we can benefit from caching info for remote
2654 volumes, we use a simple expiry mechanism to invalidate cache
2655 entries that are more than ten seconds old. */
2658 /* No point doing this, because WNetGetConnection is even slower than
2659 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2660 GetDriveType is about the only call of this type which does not
2661 involve network access, and so is extremely quick). */
2663 /* Map drive letter to UNC if remote. */
2664 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2666 char remote_name
[ 256 ];
2667 char drive
[3] = { root_dir
[0], ':' };
2669 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2671 /* do something */ ;
2675 info
= lookup_volume_info (root_dir
);
2677 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2685 /* Info is not cached, or is stale. */
2686 if (!GetVolumeInformation (root_dir
,
2687 name
, sizeof (name
),
2691 type
, sizeof (type
)))
2694 /* Cache the volume information for future use, overwriting existing
2695 entry if present. */
2698 info
= xmalloc (sizeof (volume_info_data
));
2699 add_volume_info (root_dir
, info
);
2707 info
->name
= xstrdup (name
);
2708 info
->serialnum
= serialnum
;
2709 info
->maxcomp
= maxcomp
;
2710 info
->flags
= flags
;
2711 info
->type
= xstrdup (type
);
2712 info
->timestamp
= GetTickCount ();
2718 /* Get information on the volume where NAME is held; set path pointer to
2719 start of pathname in NAME (past UNC header\volume header if present),
2720 if pPath is non-NULL.
2722 Note: if NAME includes symlinks, the information is for the volume
2723 of the symlink, not of its target. That's because, even though
2724 GetVolumeInformation returns information about the symlink target
2725 of its argument, we only pass the root directory to
2726 GetVolumeInformation, not the full NAME. */
2728 get_volume_info (const char * name
, const char ** pPath
)
2730 char temp
[MAX_PATH
];
2731 char *rootname
= NULL
; /* default to current volume */
2732 volume_info_data
* info
;
2737 /* Find the root name of the volume if given. */
2738 if (isalpha (name
[0]) && name
[1] == ':')
2746 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2750 int dbcs_p
= max_filename_mbslen () > 1;
2755 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2761 const char *p
= name
;
2763 name
= CharNextExA (file_name_codepage
, name
, 0);
2764 memcpy (str
, p
, name
- p
);
2777 info
= GetCachedVolumeInformation (rootname
);
2780 /* Set global referenced by other functions. */
2781 volume_info
= *info
;
2787 /* Determine if volume is FAT format (ie. only supports short 8.3
2788 names); also set path pointer to start of pathname in name, if
2789 pPath is non-NULL. */
2791 is_fat_volume (const char * name
, const char ** pPath
)
2793 if (get_volume_info (name
, pPath
))
2794 return (volume_info
.maxcomp
== 12);
2798 /* Map filename to a valid 8.3 name if necessary.
2799 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2801 map_w32_filename (const char * name
, const char ** pPath
)
2803 static char shortname
[MAX_PATH
];
2804 char * str
= shortname
;
2807 const char * save_name
= name
;
2809 if (strlen (name
) >= MAX_PATH
)
2811 /* Return a filename which will cause callers to fail. */
2812 strcpy (shortname
, "?");
2816 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2818 register int left
= 8; /* maximum number of chars in part */
2819 register int extn
= 0; /* extension added? */
2820 register int dots
= 2; /* maximum number of dots allowed */
2823 *str
++ = *name
++; /* skip past UNC header */
2825 while ((c
= *name
++))
2832 *str
++ = (c
== ':' ? ':' : '\\');
2833 extn
= 0; /* reset extension flags */
2834 dots
= 2; /* max 2 dots */
2835 left
= 8; /* max length 8 for main part */
2840 /* Convert path components of the form .xxx to _xxx,
2841 but leave . and .. as they are. This allows .emacs
2842 to be read as _emacs, for example. */
2846 IS_DIRECTORY_SEP (*name
))
2861 extn
= 1; /* we've got an extension */
2862 left
= 3; /* 3 chars in extension */
2866 /* any embedded dots after the first are converted to _ */
2871 case '#': /* don't lose these, they're important */
2873 str
[-1] = c
; /* replace last character of part */
2878 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2880 dots
= 0; /* started a path component */
2889 strcpy (shortname
, name
);
2890 unixtodos_filename (shortname
);
2894 *pPath
= shortname
+ (path
- save_name
);
2900 is_exec (const char * name
)
2902 char * p
= strrchr (name
, '.');
2905 && (xstrcasecmp (p
, ".exe") == 0 ||
2906 xstrcasecmp (p
, ".com") == 0 ||
2907 xstrcasecmp (p
, ".bat") == 0 ||
2908 xstrcasecmp (p
, ".cmd") == 0));
2911 /* Emulate the Unix directory procedures opendir, closedir,
2912 and readdir. We can't use the procedures supplied in sysdep.c,
2913 so we provide them here. */
2915 struct dirent dir_static
; /* simulated directory contents */
2916 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2917 static int dir_is_fat
;
2918 static char dir_pathname
[MAXPATHLEN
+1];
2919 static WIN32_FIND_DATA dir_find_data
;
2921 /* Support shares on a network resource as subdirectories of a read-only
2923 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2924 static HANDLE
open_unc_volume (const char *);
2925 static char *read_unc_volume (HANDLE
, char *, int);
2926 static void close_unc_volume (HANDLE
);
2929 opendir (const char *filename
)
2933 /* Opening is done by FindFirstFile. However, a read is inherent to
2934 this operation, so we defer the open until read time. */
2936 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2938 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2941 /* Note: We don't support traversal of UNC volumes via symlinks.
2942 Doing so would mean punishing 99.99% of use cases by resolving
2943 all the possible symlinks in FILENAME, recursively. */
2944 if (is_unc_volume (filename
))
2946 wnet_enum_handle
= open_unc_volume (filename
);
2947 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2951 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2958 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2959 dir_pathname
[MAXPATHLEN
] = '\0';
2960 /* Note: We don't support symlinks to file names on FAT volumes.
2961 Doing so would mean punishing 99.99% of use cases by resolving
2962 all the possible symlinks in FILENAME, recursively. */
2963 dir_is_fat
= is_fat_volume (filename
, NULL
);
2969 closedir (DIR *dirp
)
2971 /* If we have a find-handle open, close it. */
2972 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2974 FindClose (dir_find_handle
);
2975 dir_find_handle
= INVALID_HANDLE_VALUE
;
2977 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2979 close_unc_volume (wnet_enum_handle
);
2980 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2982 xfree ((char *) dirp
);
2988 int downcase
= !NILP (Vw32_downcase_file_names
);
2990 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2992 if (!read_unc_volume (wnet_enum_handle
,
2993 dir_find_data
.cFileName
,
2997 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2998 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
3000 char filename
[MAXNAMLEN
+ 3];
3002 int dbcs_p
= max_filename_mbslen () > 1;
3004 strcpy (filename
, dir_pathname
);
3005 ln
= strlen (filename
) - 1;
3008 if (!IS_DIRECTORY_SEP (filename
[ln
]))
3009 strcat (filename
, "\\");
3013 char *end
= filename
+ ln
+ 1;
3014 char *last_char
= CharPrevExA (file_name_codepage
, filename
, end
, 0);
3016 if (!IS_DIRECTORY_SEP (*last_char
))
3017 strcat (filename
, "\\");
3019 strcat (filename
, "*");
3021 /* Note: No need to resolve symlinks in FILENAME, because
3022 FindFirst opens the directory that is the target of a
3024 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
3026 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
3031 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
3035 /* Emacs never uses this value, so don't bother making it match
3036 value returned by stat(). */
3037 dir_static
.d_ino
= 1;
3039 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
3041 /* If the file name in cFileName[] includes `?' characters, it means
3042 the original file name used characters that cannot be represented
3043 by the current ANSI codepage. To avoid total lossage, retrieve
3044 the short 8+3 alias of the long file name. */
3045 if (_mbspbrk (dir_static
.d_name
, "?"))
3047 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
3048 downcase
= 1; /* 8+3 aliases are returned in all caps */
3050 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
3051 dir_static
.d_reclen
= sizeof (struct dirent
) - MAXNAMLEN
+ 3 +
3052 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
3054 /* If the file name in cFileName[] includes `?' characters, it means
3055 the original file name used characters that cannot be represented
3056 by the current ANSI codepage. To avoid total lossage, retrieve
3057 the short 8+3 alias of the long file name. */
3058 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
3060 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
3061 /* 8+3 aliases are returned in all caps, which could break
3062 various alists that look at filenames' extensions. */
3066 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
3067 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
3069 _mbslwr (dir_static
.d_name
);
3073 int dbcs_p
= max_filename_mbslen () > 1;
3074 for (p
= dir_static
.d_name
; *p
; )
3076 if (*p
>= 'a' && *p
<= 'z')
3079 p
= CharNextExA (file_name_codepage
, p
, 0);
3084 _mbslwr (dir_static
.d_name
);
3091 open_unc_volume (const char *path
)
3097 nr
.dwScope
= RESOURCE_GLOBALNET
;
3098 nr
.dwType
= RESOURCETYPE_DISK
;
3099 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
3100 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3101 nr
.lpLocalName
= NULL
;
3102 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
3103 nr
.lpComment
= NULL
;
3104 nr
.lpProvider
= NULL
;
3106 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
3107 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
3109 if (result
== NO_ERROR
)
3112 return INVALID_HANDLE_VALUE
;
3116 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
3120 DWORD bufsize
= 512;
3123 int dbcs_p
= max_filename_mbslen () > 1;
3126 buffer
= alloca (bufsize
);
3127 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
3128 if (result
!= NO_ERROR
)
3131 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3132 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
3135 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
3138 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
))
3139 ptr
= CharNextExA (file_name_codepage
, ptr
, 0);
3143 strncpy (readbuf
, ptr
, size
);
3148 close_unc_volume (HANDLE henum
)
3150 if (henum
!= INVALID_HANDLE_VALUE
)
3151 WNetCloseEnum (henum
);
3155 unc_volume_file_attributes (const char *path
)
3160 henum
= open_unc_volume (path
);
3161 if (henum
== INVALID_HANDLE_VALUE
)
3164 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
3166 close_unc_volume (henum
);
3171 /* Ensure a network connection is authenticated. */
3173 logon_network_drive (const char *path
)
3175 NETRESOURCE resource
;
3176 char share
[MAX_PATH
];
3183 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
3184 drvtype
= DRIVE_REMOTE
;
3185 else if (path
[0] == '\0' || path
[1] != ':')
3186 drvtype
= GetDriveType (NULL
);
3193 drvtype
= GetDriveType (drive
);
3196 /* Only logon to networked drives. */
3197 if (drvtype
!= DRIVE_REMOTE
)
3201 strncpy (share
, path
, MAX_PATH
);
3202 /* Truncate to just server and share name. */
3203 dbcs_p
= max_filename_mbslen () > 1;
3204 for (p
= share
+ 2; *p
&& p
< share
+ MAX_PATH
; )
3206 if (IS_DIRECTORY_SEP (*p
) && ++n_slashes
> 3)
3212 p
= CharNextExA (file_name_codepage
, p
, 0);
3217 resource
.dwType
= RESOURCETYPE_DISK
;
3218 resource
.lpLocalName
= NULL
;
3219 resource
.lpRemoteName
= share
;
3220 resource
.lpProvider
= NULL
;
3222 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
3225 /* Emulate faccessat(2). */
3227 faccessat (int dirfd
, const char * path
, int mode
, int flags
)
3231 if (dirfd
!= AT_FDCWD
3232 && !(IS_DIRECTORY_SEP (path
[0])
3233 || IS_DEVICE_SEP (path
[1])))
3239 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3240 newer versions blow up when passed D_OK. */
3241 path
= map_w32_filename (path
, NULL
);
3242 /* If the last element of PATH is a symlink, we need to resolve it
3243 to get the attributes of its target file. Note: any symlinks in
3244 PATH elements other than the last one are transparently resolved
3245 by GetFileAttributes below. */
3246 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0
3247 && (flags
& AT_SYMLINK_NOFOLLOW
) == 0)
3248 path
= chase_symlinks (path
);
3250 if ((attributes
= GetFileAttributes (path
)) == -1)
3252 DWORD w32err
= GetLastError ();
3256 case ERROR_INVALID_NAME
:
3257 case ERROR_BAD_PATHNAME
:
3258 if (is_unc_volume (path
))
3260 attributes
= unc_volume_file_attributes (path
);
3261 if (attributes
== -1)
3269 case ERROR_FILE_NOT_FOUND
:
3270 case ERROR_BAD_NETPATH
:
3279 if ((mode
& X_OK
) != 0
3280 && !(is_exec (path
) || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3285 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3290 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3298 /* Shadow some MSVC runtime functions to map requests for long filenames
3299 to reasonable short names if necessary. This was originally added to
3300 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3304 sys_chdir (const char * path
)
3306 return _chdir (map_w32_filename (path
, NULL
));
3310 sys_chmod (const char * path
, int mode
)
3312 path
= chase_symlinks (map_w32_filename (path
, NULL
));
3313 return _chmod (path
, mode
);
3317 sys_creat (const char * path
, int mode
)
3319 return _creat (map_w32_filename (path
, NULL
), mode
);
3323 sys_fopen (const char * path
, const char * mode
)
3327 const char * mode_save
= mode
;
3329 /* Force all file handles to be non-inheritable. This is necessary to
3330 ensure child processes don't unwittingly inherit handles that might
3331 prevent future file access. */
3335 else if (mode
[0] == 'w' || mode
[0] == 'a')
3336 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
3340 /* Only do simplistic option parsing. */
3344 oflag
&= ~(O_RDONLY
| O_WRONLY
);
3347 else if (mode
[0] == 'b')
3352 else if (mode
[0] == 't')
3359 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
3363 return _fdopen (fd
, mode_save
);
3366 /* This only works on NTFS volumes, but is useful to have. */
3368 sys_link (const char * old
, const char * new)
3372 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
3374 if (old
== NULL
|| new == NULL
)
3380 strcpy (oldname
, map_w32_filename (old
, NULL
));
3381 strcpy (newname
, map_w32_filename (new, NULL
));
3383 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
3384 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
3385 if (fileh
!= INVALID_HANDLE_VALUE
)
3389 /* Confusingly, the "alternate" stream name field does not apply
3390 when restoring a hard link, and instead contains the actual
3391 stream data for the link (ie. the name of the link to create).
3392 The WIN32_STREAM_ID structure before the cStreamName field is
3393 the stream header, which is then immediately followed by the
3397 WIN32_STREAM_ID wid
;
3398 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
3401 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
3402 data
.wid
.cStreamName
, MAX_PATH
);
3405 LPVOID context
= NULL
;
3408 data
.wid
.dwStreamId
= BACKUP_LINK
;
3409 data
.wid
.dwStreamAttributes
= 0;
3410 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
3411 data
.wid
.Size
.HighPart
= 0;
3412 data
.wid
.dwStreamNameSize
= 0;
3414 if (BackupWrite (fileh
, (LPBYTE
)&data
,
3415 offsetof (WIN32_STREAM_ID
, cStreamName
)
3416 + data
.wid
.Size
.LowPart
,
3417 &wbytes
, FALSE
, FALSE
, &context
)
3418 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
3425 /* Should try mapping GetLastError to errno; for now just
3426 indicate a general error (eg. links not supported). */
3427 errno
= EINVAL
; // perhaps EMLINK?
3431 CloseHandle (fileh
);
3440 sys_mkdir (const char * path
)
3442 return _mkdir (map_w32_filename (path
, NULL
));
3446 sys_open (const char * path
, int oflag
, int mode
)
3448 const char* mpath
= map_w32_filename (path
, NULL
);
3451 /* If possible, try to open file without _O_CREAT, to be able to
3452 write to existing hidden and system files. Force all file
3453 handles to be non-inheritable. */
3454 if ((oflag
& (_O_CREAT
| _O_EXCL
)) != (_O_CREAT
| _O_EXCL
))
3455 res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3457 res
= _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
3462 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
3465 Standard algorithm for generating a temporary file name seems to be
3466 use pid or tid with a letter on the front (in place of the 6 X's)
3467 and cycle through the letters to find a unique name. We extend
3468 that to allow any reasonable character as the first of the 6 X's,
3469 so that the number of simultaneously used temporary files will be
3473 mkostemp (char * template, int flags
)
3477 unsigned uid
= GetCurrentThreadId ();
3478 int save_errno
= errno
;
3479 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3482 if (template == NULL
)
3485 p
= template + strlen (template);
3487 /* replace up to the last 5 X's with uid in decimal */
3488 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
3490 p
[0] = '0' + uid
% 10;
3494 if (i
< 0 && p
[0] == 'X')
3499 p
[0] = first_char
[i
];
3500 if ((fd
= sys_open (template,
3501 flags
| _O_CREAT
| _O_EXCL
| _O_RDWR
,
3502 S_IRUSR
| S_IWUSR
)) >= 0
3510 while (++i
< sizeof (first_char
));
3513 /* Template is badly formed or else we can't generate a unique name. */
3518 fchmod (int fd
, mode_t mode
)
3524 sys_rename_replace (const char *oldname
, const char *newname
, BOOL force
)
3527 char temp
[MAX_PATH
];
3531 /* MoveFile on Windows 95 doesn't correctly change the short file name
3532 alias in a number of circumstances (it is not easy to predict when
3533 just by looking at oldname and newname, unfortunately). In these
3534 cases, renaming through a temporary name avoids the problem.
3536 A second problem on Windows 95 is that renaming through a temp name when
3537 newname is uppercase fails (the final long name ends up in
3538 lowercase, although the short alias might be uppercase) UNLESS the
3539 long temp name is not 8.3.
3541 So, on Windows 95 we always rename through a temp name, and we make sure
3542 the temp name has a long extension to ensure correct renaming. */
3544 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3546 /* volume_info is set indirectly by map_w32_filename. */
3547 oldname_dev
= volume_info
.serialnum
;
3549 if (os_subtype
== OS_9X
)
3555 oldname
= map_w32_filename (oldname
, NULL
);
3556 if ((o
= strrchr (oldname
, '\\')))
3559 o
= (char *) oldname
;
3561 if ((p
= strrchr (temp
, '\\')))
3568 /* Force temp name to require a manufactured 8.3 alias - this
3569 seems to make the second rename work properly. */
3570 sprintf (p
, "_.%s.%u", o
, i
);
3572 result
= rename (oldname
, temp
);
3574 /* This loop must surely terminate! */
3575 while (result
< 0 && errno
== EEXIST
);
3580 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3581 (at least if it is a file; don't do this for directories).
3583 Since we mustn't do this if we are just changing the case of the
3584 file name (we would end up deleting the file we are trying to
3585 rename!), we let rename detect if the destination file already
3586 exists - that way we avoid the possible pitfalls of trying to
3587 determine ourselves whether two names really refer to the same
3588 file, which is not always possible in the general case. (Consider
3589 all the permutations of shared or subst'd drives, etc.) */
3591 newname
= map_w32_filename (newname
, NULL
);
3593 /* volume_info is set indirectly by map_w32_filename. */
3594 newname_dev
= volume_info
.serialnum
;
3596 result
= rename (temp
, newname
);
3598 if (result
< 0 && force
)
3600 DWORD w32err
= GetLastError ();
3603 && newname_dev
!= oldname_dev
)
3605 /* The implementation of `rename' on Windows does not return
3606 errno = EXDEV when you are moving a directory to a
3607 different storage device (ex. logical disk). It returns
3608 EACCES instead. So here we handle such situations and
3612 if ((attributes
= GetFileAttributes (temp
)) != -1
3613 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3616 else if (errno
== EEXIST
)
3618 if (_chmod (newname
, 0666) != 0)
3620 if (_unlink (newname
) != 0)
3622 result
= rename (temp
, newname
);
3624 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
3625 && is_symlink (temp
))
3627 /* This is Windows prohibiting the user from creating a
3628 symlink in another place, since that requires
3638 sys_rename (char const *old
, char const *new)
3640 return sys_rename_replace (old
, new, TRUE
);
3644 sys_rmdir (const char * path
)
3646 return _rmdir (map_w32_filename (path
, NULL
));
3650 sys_unlink (const char * path
)
3652 path
= map_w32_filename (path
, NULL
);
3654 /* On Unix, unlink works without write permission. */
3655 _chmod (path
, 0666);
3656 return _unlink (path
);
3659 static FILETIME utc_base_ft
;
3660 static ULONGLONG utc_base
; /* In 100ns units */
3661 static int init
= 0;
3663 #define FILETIME_TO_U64(result, ft) \
3665 ULARGE_INTEGER uiTemp; \
3666 uiTemp.LowPart = (ft).dwLowDateTime; \
3667 uiTemp.HighPart = (ft).dwHighDateTime; \
3668 result = uiTemp.QuadPart; \
3672 initialize_utc_base (void)
3674 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3683 st
.wMilliseconds
= 0;
3685 SystemTimeToFileTime (&st
, &utc_base_ft
);
3686 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3690 convert_time (FILETIME ft
)
3696 initialize_utc_base ();
3700 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3703 FILETIME_TO_U64 (tmp
, ft
);
3704 return (time_t) ((tmp
- utc_base
) / 10000000L);
3708 convert_from_time_t (time_t time
, FILETIME
* pft
)
3714 initialize_utc_base ();
3718 /* time in 100ns units since 1-Jan-1601 */
3719 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3720 pft
->dwHighDateTime
= tmp
.HighPart
;
3721 pft
->dwLowDateTime
= tmp
.LowPart
;
3725 /* No reason to keep this; faking inode values either by hashing or even
3726 using the file index from GetInformationByHandle, is not perfect and
3727 so by default Emacs doesn't use the inode values on Windows.
3728 Instead, we now determine file-truename correctly (except for
3729 possible drive aliasing etc). */
3731 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3733 hashval (const unsigned char * str
)
3738 h
= (h
<< 4) + *str
++;
3744 /* Return the hash value of the canonical pathname, excluding the
3745 drive/UNC header, to get a hopefully unique inode number. */
3747 generate_inode_val (const char * name
)
3749 char fullname
[ MAX_PATH
];
3753 /* Get the truly canonical filename, if it exists. (Note: this
3754 doesn't resolve aliasing due to subst commands, or recognize hard
3756 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3759 parse_root (fullname
, &p
);
3760 /* Normal W32 filesystems are still case insensitive. */
3767 static PSECURITY_DESCRIPTOR
3768 get_file_security_desc_by_handle (HANDLE h
)
3770 PSECURITY_DESCRIPTOR psd
= NULL
;
3772 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3773 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3775 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
3776 NULL
, NULL
, NULL
, NULL
, &psd
);
3777 if (err
!= ERROR_SUCCESS
)
3783 static PSECURITY_DESCRIPTOR
3784 get_file_security_desc_by_name (const char *fname
)
3786 PSECURITY_DESCRIPTOR psd
= NULL
;
3788 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3789 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3791 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3793 err
= GetLastError ();
3794 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3798 psd
= xmalloc (sd_len
);
3799 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3811 unsigned n_subauthorities
;
3813 /* Use the last sub-authority value of the RID, the relative
3814 portion of the SID, as user/group ID. */
3815 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3816 if (n_subauthorities
< 1)
3817 return 0; /* the "World" RID */
3818 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3821 /* Caching SID and account values for faster lokup. */
3825 struct w32_id
*next
;
3827 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3830 static struct w32_id
*w32_idlist
;
3833 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3835 struct w32_id
*tail
, *found
;
3837 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3839 if (equal_sid ((PSID
)tail
->sid
, sid
))
3848 strcpy (name
, found
->name
);
3856 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3859 struct w32_id
*new_entry
;
3861 /* We don't want to leave behind stale cache from when Emacs was
3865 sid_len
= get_length_sid (sid
);
3866 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3869 new_entry
->rid
= id
;
3870 strcpy (new_entry
->name
, name
);
3871 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3872 new_entry
->next
= w32_idlist
;
3873 w32_idlist
= new_entry
;
3882 get_name_and_id (PSECURITY_DESCRIPTOR psd
, unsigned *id
, char *nm
, int what
)
3886 SID_NAME_USE ignore
;
3888 DWORD name_len
= sizeof (name
);
3890 DWORD domain_len
= sizeof (domain
);
3895 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3896 else if (what
== GID
)
3897 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3901 if (!result
|| !is_valid_sid (sid
))
3903 else if (!w32_cached_id (sid
, id
, nm
))
3905 if (!lookup_account_sid (NULL
, sid
, name
, &name_len
,
3906 domain
, &domain_len
, &ignore
)
3907 || name_len
> UNLEN
+1)
3911 *id
= get_rid (sid
);
3913 w32_add_to_cache (sid
, *id
, name
);
3920 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
, struct stat
*st
)
3922 int dflt_usr
= 0, dflt_grp
= 0;
3931 if (get_name_and_id (psd
, &st
->st_uid
, st
->st_uname
, UID
))
3933 if (get_name_and_id (psd
, &st
->st_gid
, st
->st_gname
, GID
))
3936 /* Consider files to belong to current user/group, if we cannot get
3937 more accurate information. */
3940 st
->st_uid
= dflt_passwd
.pw_uid
;
3941 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3945 st
->st_gid
= dflt_passwd
.pw_gid
;
3946 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3950 /* Return non-zero if NAME is a potentially slow filesystem. */
3952 is_slow_fs (const char *name
)
3957 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3958 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3959 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3960 devtype
= GetDriveType (NULL
); /* use root of current drive */
3963 /* GetDriveType needs the root directory of the drive. */
3964 strncpy (drive_root
, name
, 2);
3965 drive_root
[2] = '\\';
3966 drive_root
[3] = '\0';
3967 devtype
= GetDriveType (drive_root
);
3969 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3972 /* If this is non-zero, the caller wants accurate information about
3973 file's owner and group, which could be expensive to get. */
3974 int w32_stat_get_owner_group
;
3976 /* MSVC stat function can't cope with UNC names and has other bugs, so
3977 replace it with our own. This also allows us to calculate consistent
3978 inode values and owner/group without hacks in the main Emacs code. */
3981 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
3983 char *name
, *save_name
, *r
;
3984 WIN32_FIND_DATA wfd
;
3986 unsigned __int64 fake_inode
= 0;
3989 int rootdir
= FALSE
;
3990 PSECURITY_DESCRIPTOR psd
= NULL
;
3991 int is_a_symlink
= 0;
3992 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
3993 DWORD access_rights
= 0;
3994 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
3995 FILETIME ctime
, atime
, wtime
;
3998 if (path
== NULL
|| buf
== NULL
)
4004 save_name
= name
= (char *) map_w32_filename (path
, &path
);
4005 /* Must be valid filename, no wild cards or other invalid
4006 characters. We use _mbspbrk to support multibyte strings that
4007 might look to strpbrk as if they included literal *, ?, and other
4008 characters mentioned below that are disallowed by Windows
4010 if (_mbspbrk (name
, "*?|<>\""))
4016 /* Remove trailing directory separator, unless name is the root
4017 directory of a drive or UNC volume in which case ensure there
4018 is a trailing separator. */
4019 len
= strlen (name
);
4020 name
= strcpy (alloca (len
+ 2), name
);
4022 /* Avoid a somewhat costly call to is_symlink if the filesystem
4023 doesn't support symlinks. */
4024 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
4025 is_a_symlink
= is_symlink (name
);
4027 /* Plan A: Open the file and get all the necessary information via
4028 the resulting handle. This solves several issues in one blow:
4030 . retrieves attributes for the target of a symlink, if needed
4031 . gets attributes of root directories and symlinks pointing to
4032 root directories, thus avoiding the need for special-casing
4033 these and detecting them by examining the file-name format
4034 . retrieves more accurate attributes (e.g., non-zero size for
4035 some directories, esp. directories that are junction points)
4036 . correctly resolves "c:/..", "/.." and similar file names
4037 . avoids run-time penalties for 99% of use cases
4039 Plan A is always tried first, unless the user asked not to (but
4040 if the file is a symlink and we need to follow links, we try Plan
4041 A even if the user asked not to).
4043 If Plan A fails, we go to Plan B (below), where various
4044 potentially expensive techniques must be used to handle "special"
4045 files such as UNC volumes etc. */
4046 if (!(NILP (Vw32_get_true_file_attributes
)
4047 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
4048 /* Following symlinks requires getting the info by handle. */
4049 || (is_a_symlink
&& follow_symlinks
))
4051 BY_HANDLE_FILE_INFORMATION info
;
4053 if (is_a_symlink
&& !follow_symlinks
)
4054 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
4055 /* READ_CONTROL access rights are required to get security info
4056 by handle. But if the OS doesn't support security in the
4057 first place, we don't need to try. */
4058 if (is_windows_9x () != TRUE
)
4059 access_rights
|= READ_CONTROL
;
4061 fh
= CreateFile (name
, access_rights
, 0, NULL
, OPEN_EXISTING
,
4063 /* If CreateFile fails with READ_CONTROL, try again with zero as
4065 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
4066 fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
4068 if (fh
== INVALID_HANDLE_VALUE
)
4069 goto no_true_file_attributes
;
4071 /* This is more accurate in terms of getting the correct number
4072 of links, but is quite slow (it is noticeable when Emacs is
4073 making a list of file name completions). */
4074 if (GetFileInformationByHandle (fh
, &info
))
4076 nlinks
= info
.nNumberOfLinks
;
4077 /* Might as well use file index to fake inode values, but this
4078 is not guaranteed to be unique unless we keep a handle open
4079 all the time (even then there are situations where it is
4080 not unique). Reputedly, there are at most 48 bits of info
4081 (on NTFS, presumably less on FAT). */
4082 fake_inode
= info
.nFileIndexHigh
;
4084 fake_inode
+= info
.nFileIndexLow
;
4085 serialnum
= info
.dwVolumeSerialNumber
;
4086 fs_high
= info
.nFileSizeHigh
;
4087 fs_low
= info
.nFileSizeLow
;
4088 ctime
= info
.ftCreationTime
;
4089 atime
= info
.ftLastAccessTime
;
4090 wtime
= info
.ftLastWriteTime
;
4091 fattrs
= info
.dwFileAttributes
;
4095 /* We don't go to Plan B here, because it's not clear that
4096 it's a good idea. The only known use case where
4097 CreateFile succeeds, but GetFileInformationByHandle fails
4098 (with ERROR_INVALID_FUNCTION) is for character devices
4099 such as NUL, PRN, etc. For these, switching to Plan B is
4100 a net loss, because we lose the character device
4101 attribute returned by GetFileType below (FindFirstFile
4102 doesn't set that bit in the attributes), and the other
4103 fields don't make sense for character devices anyway.
4104 Emacs doesn't really care for non-file entities in the
4105 context of l?stat, so neither do we. */
4107 /* w32err is assigned so one could put a breakpoint here and
4108 examine its value, when GetFileInformationByHandle
4110 DWORD w32err
= GetLastError ();
4114 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
4120 /* Test for a symlink before testing for a directory, since
4121 symlinks to directories have the directory bit set, but we
4122 don't want them to appear as directories. */
4123 if (is_a_symlink
&& !follow_symlinks
)
4124 buf
->st_mode
= S_IFLNK
;
4125 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4126 buf
->st_mode
= S_IFDIR
;
4129 DWORD ftype
= GetFileType (fh
);
4133 case FILE_TYPE_DISK
:
4134 buf
->st_mode
= S_IFREG
;
4136 case FILE_TYPE_PIPE
:
4137 buf
->st_mode
= S_IFIFO
;
4139 case FILE_TYPE_CHAR
:
4140 case FILE_TYPE_UNKNOWN
:
4142 buf
->st_mode
= S_IFCHR
;
4145 /* We produce the fallback owner and group data, based on the
4146 current user that runs Emacs, in the following cases:
4148 . caller didn't request owner and group info
4149 . this is Windows 9X
4150 . getting security by handle failed, and we need to produce
4151 information for the target of a symlink (this is better
4152 than producing a potentially misleading info about the
4155 If getting security by handle fails, and we don't need to
4156 resolve symlinks, we try getting security by name. */
4157 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4158 get_file_owner_and_group (NULL
, buf
);
4161 psd
= get_file_security_desc_by_handle (fh
);
4164 get_file_owner_and_group (psd
, buf
);
4167 else if (!(is_a_symlink
&& follow_symlinks
))
4169 psd
= get_file_security_desc_by_name (name
);
4170 get_file_owner_and_group (psd
, buf
);
4174 get_file_owner_and_group (NULL
, buf
);
4180 no_true_file_attributes
:
4181 /* Plan B: Either getting a handle on the file failed, or the
4182 caller explicitly asked us to not bother making this
4183 information more accurate.
4185 Implementation note: In Plan B, we never bother to resolve
4186 symlinks, even if we got here because we tried Plan A and
4187 failed. That's because, even if the caller asked for extra
4188 precision by setting Vw32_get_true_file_attributes to t,
4189 resolving symlinks requires acquiring a file handle to the
4190 symlink, which we already know will fail. And if the user
4191 did not ask for extra precision, resolving symlinks will fly
4192 in the face of that request, since the user then wants the
4193 lightweight version of the code. */
4194 dbcs_p
= max_filename_mbslen () > 1;
4195 rootdir
= (path
>= save_name
+ len
- 1
4196 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
4198 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4199 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
4200 if (IS_DIRECTORY_SEP (r
[0])
4201 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
4204 /* Note: If NAME is a symlink to the root of a UNC volume
4205 (i.e. "\\SERVER"), we will not detect that here, and we will
4206 return data about the symlink as result of FindFirst below.
4207 This is unfortunate, but that marginal use case does not
4208 justify a call to chase_symlinks which would impose a penalty
4209 on all the other use cases. (We get here for symlinks to
4210 roots of UNC volumes because CreateFile above fails for them,
4211 unlike with symlinks to root directories X:\ of drives.) */
4212 if (is_unc_volume (name
))
4214 fattrs
= unc_volume_file_attributes (name
);
4218 ctime
= atime
= wtime
= utc_base_ft
;
4224 if (!IS_DIRECTORY_SEP (name
[len
-1]))
4225 strcat (name
, "\\");
4229 char *end
= name
+ len
;
4230 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4232 if (!IS_DIRECTORY_SEP (*n
))
4233 strcat (name
, "\\");
4235 if (GetDriveType (name
) < 2)
4241 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
4242 ctime
= atime
= wtime
= utc_base_ft
;
4248 if (IS_DIRECTORY_SEP (name
[len
-1]))
4253 char *end
= name
+ len
;
4254 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4256 if (IS_DIRECTORY_SEP (*n
))
4260 /* (This is hacky, but helps when doing file completions on
4261 network drives.) Optimize by using information available from
4262 active readdir if possible. */
4263 len
= strlen (dir_pathname
);
4266 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
4271 char *end
= dir_pathname
+ len
;
4272 char *n
= CharPrevExA (file_name_codepage
, dir_pathname
, end
, 0);
4274 if (IS_DIRECTORY_SEP (*n
))
4277 if (dir_find_handle
!= INVALID_HANDLE_VALUE
4278 && !(is_a_symlink
&& follow_symlinks
)
4279 && strnicmp (save_name
, dir_pathname
, len
) == 0
4280 && IS_DIRECTORY_SEP (name
[len
])
4281 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
4283 /* This was the last entry returned by readdir. */
4284 wfd
= dir_find_data
;
4288 logon_network_drive (name
);
4290 fh
= FindFirstFile (name
, &wfd
);
4291 if (fh
== INVALID_HANDLE_VALUE
)
4298 /* Note: if NAME is a symlink, the information we get from
4299 FindFirstFile is for the symlink, not its target. */
4300 fattrs
= wfd
.dwFileAttributes
;
4301 ctime
= wfd
.ftCreationTime
;
4302 atime
= wfd
.ftLastAccessTime
;
4303 wtime
= wfd
.ftLastWriteTime
;
4304 fs_high
= wfd
.nFileSizeHigh
;
4305 fs_low
= wfd
.nFileSizeLow
;
4308 serialnum
= volume_info
.serialnum
;
4310 if (is_a_symlink
&& !follow_symlinks
)
4311 buf
->st_mode
= S_IFLNK
;
4312 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4313 buf
->st_mode
= S_IFDIR
;
4315 buf
->st_mode
= S_IFREG
;
4317 get_file_owner_and_group (NULL
, buf
);
4321 /* Not sure if there is any point in this. */
4322 if (!NILP (Vw32_generate_fake_inodes
))
4323 fake_inode
= generate_inode_val (name
);
4324 else if (fake_inode
== 0)
4326 /* For want of something better, try to make everything unique. */
4327 static DWORD gen_num
= 0;
4328 fake_inode
= ++gen_num
;
4332 buf
->st_ino
= fake_inode
;
4334 buf
->st_dev
= serialnum
;
4335 buf
->st_rdev
= serialnum
;
4337 buf
->st_size
= fs_high
;
4338 buf
->st_size
<<= 32;
4339 buf
->st_size
+= fs_low
;
4340 buf
->st_nlink
= nlinks
;
4342 /* Convert timestamps to Unix format. */
4343 buf
->st_mtime
= convert_time (wtime
);
4344 buf
->st_atime
= convert_time (atime
);
4345 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4346 buf
->st_ctime
= convert_time (ctime
);
4347 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4349 /* determine rwx permissions */
4350 if (is_a_symlink
&& !follow_symlinks
)
4351 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
4354 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
4355 permission
= S_IREAD
;
4357 permission
= S_IREAD
| S_IWRITE
;
4359 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4360 permission
|= S_IEXEC
;
4361 else if (is_exec (name
))
4362 permission
|= S_IEXEC
;
4365 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4371 stat (const char * path
, struct stat
* buf
)
4373 return stat_worker (path
, buf
, 1);
4377 lstat (const char * path
, struct stat
* buf
)
4379 return stat_worker (path
, buf
, 0);
4383 fstatat (int fd
, char const *name
, struct stat
*st
, int flags
)
4385 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4386 This is good enough for the current usage in Emacs, but is fragile.
4388 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4389 Gnulib does this and can serve as a model. */
4390 char fullname
[MAX_PATH
];
4394 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
4397 errno
= ENAMETOOLONG
;
4403 return stat_worker (name
, st
, ! (flags
& AT_SYMLINK_NOFOLLOW
));
4406 /* Provide fstat and utime as well as stat for consistent handling of
4409 fstat (int desc
, struct stat
* buf
)
4411 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
4412 BY_HANDLE_FILE_INFORMATION info
;
4413 unsigned __int64 fake_inode
;
4416 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
4418 case FILE_TYPE_DISK
:
4419 buf
->st_mode
= S_IFREG
;
4420 if (!GetFileInformationByHandle (fh
, &info
))
4426 case FILE_TYPE_PIPE
:
4427 buf
->st_mode
= S_IFIFO
;
4429 case FILE_TYPE_CHAR
:
4430 case FILE_TYPE_UNKNOWN
:
4432 buf
->st_mode
= S_IFCHR
;
4434 memset (&info
, 0, sizeof (info
));
4435 info
.dwFileAttributes
= 0;
4436 info
.ftCreationTime
= utc_base_ft
;
4437 info
.ftLastAccessTime
= utc_base_ft
;
4438 info
.ftLastWriteTime
= utc_base_ft
;
4441 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4442 buf
->st_mode
= S_IFDIR
;
4444 buf
->st_nlink
= info
.nNumberOfLinks
;
4445 /* Might as well use file index to fake inode values, but this
4446 is not guaranteed to be unique unless we keep a handle open
4447 all the time (even then there are situations where it is
4448 not unique). Reputedly, there are at most 48 bits of info
4449 (on NTFS, presumably less on FAT). */
4450 fake_inode
= info
.nFileIndexHigh
;
4452 fake_inode
+= info
.nFileIndexLow
;
4454 /* MSVC defines _ino_t to be short; other libc's might not. */
4455 if (sizeof (buf
->st_ino
) == 2)
4456 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
4458 buf
->st_ino
= fake_inode
;
4460 /* If the caller so requested, get the true file owner and group.
4461 Otherwise, consider the file to belong to the current user. */
4462 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4463 get_file_owner_and_group (NULL
, buf
);
4466 PSECURITY_DESCRIPTOR psd
= NULL
;
4468 psd
= get_file_security_desc_by_handle (fh
);
4471 get_file_owner_and_group (psd
, buf
);
4475 get_file_owner_and_group (NULL
, buf
);
4478 buf
->st_dev
= info
.dwVolumeSerialNumber
;
4479 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
4481 buf
->st_size
= info
.nFileSizeHigh
;
4482 buf
->st_size
<<= 32;
4483 buf
->st_size
+= info
.nFileSizeLow
;
4485 /* Convert timestamps to Unix format. */
4486 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
4487 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
4488 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4489 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
4490 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4492 /* determine rwx permissions */
4493 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
4494 permission
= S_IREAD
;
4496 permission
= S_IREAD
| S_IWRITE
;
4498 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4499 permission
|= S_IEXEC
;
4502 #if 0 /* no way of knowing the filename */
4503 char * p
= strrchr (name
, '.');
4505 (xstrcasecmp (p
, ".exe") == 0 ||
4506 xstrcasecmp (p
, ".com") == 0 ||
4507 xstrcasecmp (p
, ".bat") == 0 ||
4508 xstrcasecmp (p
, ".cmd") == 0))
4509 permission
|= S_IEXEC
;
4513 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4518 /* A version of 'utime' which handles directories as well as
4522 utime (const char *name
, struct utimbuf
*times
)
4524 struct utimbuf deftime
;
4531 deftime
.modtime
= deftime
.actime
= time (NULL
);
4535 /* Need write access to set times. */
4536 fh
= CreateFile (name
, FILE_WRITE_ATTRIBUTES
,
4537 /* If NAME specifies a directory, FILE_SHARE_DELETE
4538 allows other processes to delete files inside it,
4539 while we have the directory open. */
4540 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
4541 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
4542 if (fh
!= INVALID_HANDLE_VALUE
)
4544 convert_from_time_t (times
->actime
, &atime
);
4545 convert_from_time_t (times
->modtime
, &mtime
);
4546 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
4563 /* Symlink-related functions. */
4564 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4565 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4569 symlink (char const *filename
, char const *linkname
)
4571 char linkfn
[MAX_PATH
], *tgtfn
;
4573 int dir_access
, filename_ends_in_slash
;
4576 /* Diagnostics follows Posix as much as possible. */
4577 if (filename
== NULL
|| linkname
== NULL
)
4587 if (strlen (filename
) > MAX_PATH
|| strlen (linkname
) > MAX_PATH
)
4589 errno
= ENAMETOOLONG
;
4593 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
4594 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
4600 dbcs_p
= max_filename_mbslen () > 1;
4602 /* Note: since empty FILENAME was already rejected, we can safely
4603 refer to FILENAME[1]. */
4604 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
4606 /* Non-absolute FILENAME is understood as being relative to
4607 LINKNAME's directory. We need to prepend that directory to
4608 FILENAME to get correct results from faccessat below, since
4609 otherwise it will interpret FILENAME relative to the
4610 directory where the Emacs process runs. Note that
4611 make-symbolic-link always makes sure LINKNAME is a fully
4612 expanded file name. */
4614 char *p
= linkfn
+ strlen (linkfn
);
4618 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
4623 char *p1
= CharPrevExA (file_name_codepage
, linkfn
, p
, 0);
4625 while (p
> linkfn
&& !IS_ANY_SEP (*p1
))
4628 p1
= CharPrevExA (file_name_codepage
, linkfn
, p1
, 0);
4632 strncpy (tem
, linkfn
, p
- linkfn
);
4633 tem
[p
- linkfn
] = '\0';
4634 strcat (tem
, filename
);
4635 dir_access
= faccessat (AT_FDCWD
, tem
, D_OK
, AT_EACCESS
);
4638 dir_access
= faccessat (AT_FDCWD
, filename
, D_OK
, AT_EACCESS
);
4640 /* Since Windows distinguishes between symlinks to directories and
4641 to files, we provide a kludgy feature: if FILENAME doesn't
4642 exist, but ends in a slash, we create a symlink to directory. If
4643 FILENAME exists and is a directory, we always create a symlink to
4646 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
4649 const char *end
= filename
+ strlen (filename
);
4650 const char *n
= CharPrevExA (file_name_codepage
, filename
, end
, 0);
4652 filename_ends_in_slash
= IS_DIRECTORY_SEP (*n
);
4654 if (dir_access
== 0 || filename_ends_in_slash
)
4655 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
4657 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
4658 if (filename_ends_in_slash
)
4659 tgtfn
[strlen (tgtfn
) - 1] = '\0';
4662 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
4664 /* ENOSYS is set by create_symbolic_link, when it detects that
4665 the OS doesn't support the CreateSymbolicLink API. */
4666 if (errno
!= ENOSYS
)
4668 DWORD w32err
= GetLastError ();
4672 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4673 TGTFN point to the same file name, go figure. */
4675 case ERROR_FILE_EXISTS
:
4678 case ERROR_ACCESS_DENIED
:
4681 case ERROR_FILE_NOT_FOUND
:
4682 case ERROR_PATH_NOT_FOUND
:
4683 case ERROR_BAD_NETPATH
:
4684 case ERROR_INVALID_REPARSE_DATA
:
4687 case ERROR_DIRECTORY
:
4690 case ERROR_PRIVILEGE_NOT_HELD
:
4691 case ERROR_NOT_ALL_ASSIGNED
:
4694 case ERROR_DISK_FULL
:
4707 /* A quick inexpensive test of whether FILENAME identifies a file that
4708 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4709 must already be in the normalized form returned by
4712 Note: for repeated operations on many files, it is best to test
4713 whether the underlying volume actually supports symlinks, by
4714 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4715 avoid the call to this function if it doesn't. That's because the
4716 call to GetFileAttributes takes a non-negligible time, especially
4717 on non-local or removable filesystems. See stat_worker for an
4718 example of how to do that. */
4720 is_symlink (const char *filename
)
4723 WIN32_FIND_DATA wfd
;
4726 attrs
= GetFileAttributes (filename
);
4729 DWORD w32err
= GetLastError ();
4733 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
4735 case ERROR_ACCESS_DENIED
:
4738 case ERROR_FILE_NOT_FOUND
:
4739 case ERROR_PATH_NOT_FOUND
:
4746 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
4748 logon_network_drive (filename
);
4749 fh
= FindFirstFile (filename
, &wfd
);
4750 if (fh
== INVALID_HANDLE_VALUE
)
4753 return (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
4754 && (wfd
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
4757 /* If NAME identifies a symbolic link, copy into BUF the file name of
4758 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4759 null-terminate the target name, even if it fits. Return the number
4760 of bytes copied, or -1 if NAME is not a symlink or any error was
4761 encountered while resolving it. The file name copied into BUF is
4762 encoded in the current ANSI codepage. */
4764 readlink (const char *name
, char *buf
, size_t buf_size
)
4767 TOKEN_PRIVILEGES privs
;
4768 int restore_privs
= 0;
4783 path
= map_w32_filename (name
, NULL
);
4785 if (strlen (path
) > MAX_PATH
)
4787 errno
= ENAMETOOLONG
;
4792 if (is_windows_9x () == TRUE
4793 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
4794 || !is_symlink (path
))
4797 errno
= EINVAL
; /* not a symlink */
4801 /* Done with simple tests, now we're in for some _real_ work. */
4802 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
4804 /* Implementation note: From here and onward, don't return early,
4805 since that will fail to restore the original set of privileges of
4806 the calling thread. */
4808 retval
= -1; /* not too optimistic, are we? */
4810 /* Note: In the next call to CreateFile, we use zero as the 2nd
4811 argument because, when the symlink is a hidden/system file,
4812 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4813 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4814 and directory symlinks. */
4815 sh
= CreateFile (path
, 0, 0, NULL
, OPEN_EXISTING
,
4816 FILE_FLAG_OPEN_REPARSE_POINT
| FILE_FLAG_BACKUP_SEMANTICS
,
4818 if (sh
!= INVALID_HANDLE_VALUE
)
4820 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
4821 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
4824 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
4825 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
4828 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
4832 /* Copy the link target name, in wide characters, from
4833 reparse_data, then convert it to multibyte encoding in
4834 the current locale's codepage. */
4836 BYTE lname
[MAX_PATH
];
4839 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
4841 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
4842 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
4843 /* This updates file_name_codepage which we need below. */
4844 int dbcs_p
= max_filename_mbslen () > 1;
4846 /* According to MSDN, PrintNameLength does not include the
4847 terminating null character. */
4848 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
4849 memcpy (lwname
, lwname_src
, lwname_len
);
4850 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
4852 lname_len
= WideCharToMultiByte (file_name_codepage
, 0, lwname
, -1,
4853 lname
, MAX_PATH
, NULL
, NULL
);
4856 /* WideCharToMultiByte failed. */
4857 DWORD w32err1
= GetLastError ();
4861 case ERROR_INSUFFICIENT_BUFFER
:
4862 errno
= ENAMETOOLONG
;
4864 case ERROR_INVALID_PARAMETER
:
4867 case ERROR_NO_UNICODE_TRANSLATION
:
4877 size_t size_to_copy
= buf_size
;
4878 BYTE
*p
= lname
, *p2
;
4879 BYTE
*pend
= p
+ lname_len
;
4881 /* Normalize like dostounix_filename does, but we don't
4882 want to assume that lname is null-terminated. */
4884 p2
= CharNextExA (file_name_codepage
, p
, 0);
4887 if (*p
&& *p2
== ':' && *p
>= 'A' && *p
<= 'Z')
4898 p
= CharNextExA (file_name_codepage
, p
, 0);
4899 /* CharNextExA doesn't advance at null character. */
4906 /* Testing for null-terminated LNAME is paranoia:
4907 WideCharToMultiByte should always return a
4908 null-terminated string when its 4th argument is -1
4909 and its 3rd argument is null-terminated (which they
4911 if (lname
[lname_len
- 1] == '\0')
4913 if (lname_len
<= buf_size
)
4914 size_to_copy
= lname_len
;
4915 strncpy (buf
, lname
, size_to_copy
);
4917 retval
= size_to_copy
;
4924 /* CreateFile failed. */
4925 DWORD w32err2
= GetLastError ();
4929 case ERROR_FILE_NOT_FOUND
:
4930 case ERROR_PATH_NOT_FOUND
:
4933 case ERROR_ACCESS_DENIED
:
4934 case ERROR_TOO_MANY_OPEN_FILES
:
4944 restore_privilege (&privs
);
4952 readlinkat (int fd
, char const *name
, char *buffer
,
4955 /* Rely on a hack: an open directory is modeled as file descriptor 0,
4956 as in fstatat. FIXME: Add proper support for readlinkat. */
4957 char fullname
[MAX_PATH
];
4961 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
4964 errno
= ENAMETOOLONG
;
4970 return readlink (name
, buffer
, buffer_size
);
4973 /* If FILE is a symlink, return its target (stored in a static
4974 buffer); otherwise return FILE.
4976 This function repeatedly resolves symlinks in the last component of
4977 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4978 until it arrives at a file whose last component is not a symlink,
4979 or some error occurs. It returns the target of the last
4980 successfully resolved symlink in the chain. If it succeeds to
4981 resolve even a single symlink, the value returned is an absolute
4982 file name with backslashes (result of GetFullPathName). By
4983 contrast, if the original FILE is returned, it is unaltered.
4985 Note: This function can set errno even if it succeeds.
4987 Implementation note: we only resolve the last portion ("basename")
4988 of the argument FILE and of each following file in the chain,
4989 disregarding any possible symlinks in its leading directories.
4990 This is because Windows system calls and library functions
4991 transparently resolve symlinks in leading directories and return
4992 correct information, as long as the basename is not a symlink. */
4994 chase_symlinks (const char *file
)
4996 static char target
[MAX_PATH
];
4997 char link
[MAX_PATH
];
4998 ssize_t res
, link_len
;
5002 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
5003 return (char *)file
;
5005 if ((link_len
= GetFullPathName (file
, MAX_PATH
, link
, NULL
)) == 0)
5006 return (char *)file
;
5008 dbcs_p
= max_filename_mbslen () > 1;
5012 /* Remove trailing slashes, as we want to resolve the last
5013 non-trivial part of the link name. */
5016 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
5017 link
[link_len
--] = '\0';
5019 else if (link_len
> 3)
5021 char *n
= CharPrevExA (file_name_codepage
, link
, link
+ link_len
, 0);
5023 while (n
>= link
+ 2 && IS_DIRECTORY_SEP (*n
))
5026 n
= CharPrevExA (file_name_codepage
, link
, n
, 0);
5030 res
= readlink (link
, target
, MAX_PATH
);
5034 if (!(IS_DEVICE_SEP (target
[1])
5035 || (IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1]))))
5037 /* Target is relative. Append it to the directory part of
5038 the symlink, then copy the result back to target. */
5039 char *p
= link
+ link_len
;
5043 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
5048 char *p1
= CharPrevExA (file_name_codepage
, link
, p
, 0);
5050 while (p
> link
&& !IS_ANY_SEP (*p1
))
5053 p1
= CharPrevExA (file_name_codepage
, link
, p1
, 0);
5057 strcpy (target
, link
);
5059 /* Resolve any "." and ".." to get a fully-qualified file name
5061 link_len
= GetFullPathName (target
, MAX_PATH
, link
, NULL
);
5063 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
5065 if (loop_count
> 100)
5068 if (target
[0] == '\0') /* not a single call to readlink succeeded */
5069 return (char *)file
;
5074 /* Posix ACL emulation. */
5077 acl_valid (acl_t acl
)
5079 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR
)acl
) ? 0 : -1;
5083 acl_to_text (acl_t acl
, ssize_t
*size
)
5086 SECURITY_INFORMATION flags
=
5087 OWNER_SECURITY_INFORMATION
|
5088 GROUP_SECURITY_INFORMATION
|
5089 DACL_SECURITY_INFORMATION
;
5090 char *retval
= NULL
;
5096 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR
)acl
, SDDL_REVISION_1
, flags
, &str_acl
, &local_size
))
5099 /* We don't want to mix heaps, so we duplicate the string in our
5100 heap and free the one allocated by the API. */
5101 retval
= xstrdup (str_acl
);
5104 LocalFree (str_acl
);
5106 else if (errno
!= ENOTSUP
)
5113 acl_from_text (const char *acl_str
)
5115 PSECURITY_DESCRIPTOR psd
, retval
= NULL
;
5121 if (convert_sddl_to_sd (acl_str
, SDDL_REVISION_1
, &psd
, &sd_size
))
5124 retval
= xmalloc (sd_size
);
5125 memcpy (retval
, psd
, sd_size
);
5128 else if (errno
!= ENOTSUP
)
5135 acl_free (void *ptr
)
5142 acl_get_file (const char *fname
, acl_type_t type
)
5144 PSECURITY_DESCRIPTOR psd
= NULL
;
5145 const char *filename
;
5147 if (type
== ACL_TYPE_ACCESS
)
5150 SECURITY_INFORMATION si
=
5151 OWNER_SECURITY_INFORMATION
|
5152 GROUP_SECURITY_INFORMATION
|
5153 DACL_SECURITY_INFORMATION
;
5156 filename
= map_w32_filename (fname
, NULL
);
5157 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5158 fname
= chase_symlinks (filename
);
5163 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
)
5164 && errno
!= ENOTSUP
)
5166 err
= GetLastError ();
5167 if (err
== ERROR_INSUFFICIENT_BUFFER
)
5169 psd
= xmalloc (sd_len
);
5170 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
5177 else if (err
== ERROR_FILE_NOT_FOUND
5178 || err
== ERROR_PATH_NOT_FOUND
)
5186 else if (type
!= ACL_TYPE_DEFAULT
)
5193 acl_set_file (const char *fname
, acl_type_t type
, acl_t acl
)
5195 TOKEN_PRIVILEGES old1
, old2
;
5197 int st
= 0, retval
= -1;
5198 SECURITY_INFORMATION flags
= 0;
5204 const char *filename
;
5206 if (acl_valid (acl
) != 0
5207 || (type
!= ACL_TYPE_DEFAULT
&& type
!= ACL_TYPE_ACCESS
))
5213 if (type
== ACL_TYPE_DEFAULT
)
5219 filename
= map_w32_filename (fname
, NULL
);
5220 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5221 fname
= chase_symlinks (filename
);
5225 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5227 flags
|= OWNER_SECURITY_INFORMATION
;
5228 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5230 flags
|= GROUP_SECURITY_INFORMATION
;
5231 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR
)acl
, &dacl_present
,
5234 flags
|= DACL_SECURITY_INFORMATION
;
5238 /* According to KB-245153, setting the owner will succeed if either:
5239 (1) the caller is the user who will be the new owner, and has the
5240 SE_TAKE_OWNERSHIP privilege, or
5241 (2) the caller has the SE_RESTORE privilege, in which case she can
5242 set any valid user or group as the owner
5244 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5245 privileges, and disregard any failures in obtaining them. If
5246 these privileges cannot be obtained, and do not already exist in
5247 the calling thread's security token, this function could fail
5249 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME
, TRUE
, &old1
))
5251 if (enable_privilege (SE_RESTORE_NAME
, TRUE
, &old2
))
5256 if (!set_file_security ((char *)fname
, flags
, (PSECURITY_DESCRIPTOR
)acl
))
5258 err
= GetLastError ();
5260 if (errno
== ENOTSUP
)
5262 else if (err
== ERROR_INVALID_OWNER
5263 || err
== ERROR_NOT_ALL_ASSIGNED
5264 || err
== ERROR_ACCESS_DENIED
)
5266 /* Maybe the requested ACL and the one the file already has
5267 are identical, in which case we can silently ignore the
5268 failure. (And no, Windows doesn't.) */
5269 acl_t current_acl
= acl_get_file (fname
, ACL_TYPE_ACCESS
);
5274 char *acl_from
= acl_to_text (current_acl
, NULL
);
5275 char *acl_to
= acl_to_text (acl
, NULL
);
5277 if (acl_from
&& acl_to
&& xstrcasecmp (acl_from
, acl_to
) == 0)
5283 acl_free (acl_from
);
5286 acl_free (current_acl
);
5289 else if (err
== ERROR_FILE_NOT_FOUND
|| err
== ERROR_PATH_NOT_FOUND
)
5303 restore_privilege (&old2
);
5304 restore_privilege (&old1
);
5312 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5313 have a fixed max size for file names, so we don't need the kind of
5314 alloc/malloc/realloc dance the gnulib version does. We also don't
5315 support FD-relative symlinks. */
5317 careadlinkat (int fd
, char const *filename
,
5318 char *buffer
, size_t buffer_size
,
5319 struct allocator
const *alloc
,
5320 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
5322 char linkname
[MAX_PATH
];
5325 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
5329 char *retval
= buffer
;
5331 linkname
[link_size
++] = '\0';
5332 if (link_size
> buffer_size
)
5333 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
5335 memcpy (retval
, linkname
, link_size
);
5343 /* Support for browsing other processes and their attributes. See
5344 process.c for the Lisp bindings. */
5346 /* Helper wrapper functions. */
5348 static HANDLE WINAPI
5349 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
5351 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
5353 if (g_b_init_create_toolhelp32_snapshot
== 0)
5355 g_b_init_create_toolhelp32_snapshot
= 1;
5356 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
5357 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5358 "CreateToolhelp32Snapshot");
5360 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
5362 return INVALID_HANDLE_VALUE
;
5364 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
5368 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5370 static Process32First_Proc s_pfn_Process32_First
= NULL
;
5372 if (g_b_init_process32_first
== 0)
5374 g_b_init_process32_first
= 1;
5375 s_pfn_Process32_First
= (Process32First_Proc
)
5376 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5379 if (s_pfn_Process32_First
== NULL
)
5383 return (s_pfn_Process32_First (hSnapshot
, lppe
));
5387 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5389 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
5391 if (g_b_init_process32_next
== 0)
5393 g_b_init_process32_next
= 1;
5394 s_pfn_Process32_Next
= (Process32Next_Proc
)
5395 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5398 if (s_pfn_Process32_Next
== NULL
)
5402 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
5406 open_thread_token (HANDLE ThreadHandle
,
5407 DWORD DesiredAccess
,
5409 PHANDLE TokenHandle
)
5411 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
5412 HMODULE hm_advapi32
= NULL
;
5413 if (is_windows_9x () == TRUE
)
5415 SetLastError (ERROR_NOT_SUPPORTED
);
5418 if (g_b_init_open_thread_token
== 0)
5420 g_b_init_open_thread_token
= 1;
5421 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5422 s_pfn_Open_Thread_Token
=
5423 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
5425 if (s_pfn_Open_Thread_Token
== NULL
)
5427 SetLastError (ERROR_NOT_SUPPORTED
);
5431 s_pfn_Open_Thread_Token (
5440 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
5442 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
5443 HMODULE hm_advapi32
= NULL
;
5444 if (is_windows_9x () == TRUE
)
5448 if (g_b_init_impersonate_self
== 0)
5450 g_b_init_impersonate_self
= 1;
5451 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5452 s_pfn_Impersonate_Self
=
5453 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
5455 if (s_pfn_Impersonate_Self
== NULL
)
5459 return s_pfn_Impersonate_Self (ImpersonationLevel
);
5463 revert_to_self (void)
5465 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
5466 HMODULE hm_advapi32
= NULL
;
5467 if (is_windows_9x () == TRUE
)
5471 if (g_b_init_revert_to_self
== 0)
5473 g_b_init_revert_to_self
= 1;
5474 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5475 s_pfn_Revert_To_Self
=
5476 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
5478 if (s_pfn_Revert_To_Self
== NULL
)
5482 return s_pfn_Revert_To_Self ();
5486 get_process_memory_info (HANDLE h_proc
,
5487 PPROCESS_MEMORY_COUNTERS mem_counters
,
5490 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
5491 HMODULE hm_psapi
= NULL
;
5492 if (is_windows_9x () == TRUE
)
5496 if (g_b_init_get_process_memory_info
== 0)
5498 g_b_init_get_process_memory_info
= 1;
5499 hm_psapi
= LoadLibrary ("Psapi.dll");
5501 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
5502 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
5504 if (s_pfn_Get_Process_Memory_Info
== NULL
)
5508 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
5512 get_process_working_set_size (HANDLE h_proc
,
5516 static GetProcessWorkingSetSize_Proc
5517 s_pfn_Get_Process_Working_Set_Size
= NULL
;
5519 if (is_windows_9x () == TRUE
)
5523 if (g_b_init_get_process_working_set_size
== 0)
5525 g_b_init_get_process_working_set_size
= 1;
5526 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
5527 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5528 "GetProcessWorkingSetSize");
5530 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
5534 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
5538 global_memory_status (MEMORYSTATUS
*buf
)
5540 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
5542 if (is_windows_9x () == TRUE
)
5546 if (g_b_init_global_memory_status
== 0)
5548 g_b_init_global_memory_status
= 1;
5549 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
5550 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5551 "GlobalMemoryStatus");
5553 if (s_pfn_Global_Memory_Status
== NULL
)
5557 return s_pfn_Global_Memory_Status (buf
);
5561 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
5563 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
5565 if (is_windows_9x () == TRUE
)
5569 if (g_b_init_global_memory_status_ex
== 0)
5571 g_b_init_global_memory_status_ex
= 1;
5572 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
5573 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5574 "GlobalMemoryStatusEx");
5576 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
5580 return s_pfn_Global_Memory_Status_Ex (buf
);
5584 list_system_processes (void)
5586 struct gcpro gcpro1
;
5587 Lisp_Object proclist
= Qnil
;
5590 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
5592 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
5594 PROCESSENTRY32 proc_entry
;
5600 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
5601 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
5602 res
= process32_next (h_snapshot
, &proc_entry
))
5604 proc_id
= proc_entry
.th32ProcessID
;
5605 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
5608 CloseHandle (h_snapshot
);
5610 proclist
= Fnreverse (proclist
);
5617 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
5619 TOKEN_PRIVILEGES priv
;
5620 DWORD priv_size
= sizeof (priv
);
5621 DWORD opriv_size
= sizeof (*old_priv
);
5622 HANDLE h_token
= NULL
;
5623 HANDLE h_thread
= GetCurrentThread ();
5627 res
= open_thread_token (h_thread
,
5628 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5630 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
5632 if (impersonate_self (SecurityImpersonation
))
5633 res
= open_thread_token (h_thread
,
5634 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5639 priv
.PrivilegeCount
= 1;
5640 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
5641 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
5642 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
5643 old_priv
, &opriv_size
)
5644 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
5648 CloseHandle (h_token
);
5654 restore_privilege (TOKEN_PRIVILEGES
*priv
)
5656 DWORD priv_size
= sizeof (*priv
);
5657 HANDLE h_token
= NULL
;
5660 if (open_thread_token (GetCurrentThread (),
5661 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5664 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
5665 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
5669 CloseHandle (h_token
);
5675 ltime (ULONGLONG time_100ns
)
5677 ULONGLONG time_sec
= time_100ns
/ 10000000;
5678 int subsec
= time_100ns
% 10000000;
5679 return list4i (time_sec
>> 16, time_sec
& 0xffff,
5680 subsec
/ 10, subsec
% 10 * 100000);
5683 #define U64_TO_LISP_TIME(time) ltime (time)
5686 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
5687 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
5690 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
5691 ULONGLONG tem1
, tem2
, tem3
, tem
;
5694 || !get_process_times_fn
5695 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
5696 &ft_kernel
, &ft_user
))
5699 GetSystemTimeAsFileTime (&ft_current
);
5701 FILETIME_TO_U64 (tem1
, ft_kernel
);
5702 *stime
= U64_TO_LISP_TIME (tem1
);
5704 FILETIME_TO_U64 (tem2
, ft_user
);
5705 *utime
= U64_TO_LISP_TIME (tem2
);
5708 *ttime
= U64_TO_LISP_TIME (tem3
);
5710 FILETIME_TO_U64 (tem
, ft_creation
);
5711 /* Process no 4 (System) returns zero creation time. */
5714 *ctime
= U64_TO_LISP_TIME (tem
);
5718 FILETIME_TO_U64 (tem3
, ft_current
);
5719 tem
= (tem3
- utc_base
) - tem
;
5721 *etime
= U64_TO_LISP_TIME (tem
);
5725 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
5736 system_process_attributes (Lisp_Object pid
)
5738 struct gcpro gcpro1
, gcpro2
, gcpro3
;
5739 Lisp_Object attrs
= Qnil
;
5740 Lisp_Object cmd_str
, decoded_cmd
, tem
;
5741 HANDLE h_snapshot
, h_proc
;
5744 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
5745 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
5746 DWORD glength
= sizeof (gname
);
5747 HANDLE token
= NULL
;
5748 SID_NAME_USE user_type
;
5749 unsigned char *buf
= NULL
;
5751 TOKEN_USER user_token
;
5752 TOKEN_PRIMARY_GROUP group_token
;
5755 PROCESS_MEMORY_COUNTERS mem
;
5756 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
5757 SIZE_T minrss
, maxrss
;
5759 MEMORY_STATUS_EX memstex
;
5760 double totphys
= 0.0;
5761 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
5763 BOOL result
= FALSE
;
5765 CHECK_NUMBER_OR_FLOAT (pid
);
5766 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
5768 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
5770 GCPRO3 (attrs
, decoded_cmd
, tem
);
5772 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
5777 pe
.dwSize
= sizeof (PROCESSENTRY32
);
5778 for (res
= process32_first (h_snapshot
, &pe
); res
;
5779 res
= process32_next (h_snapshot
, &pe
))
5781 if (proc_id
== pe
.th32ProcessID
)
5784 decoded_cmd
= build_string ("Idle");
5787 /* Decode the command name from locale-specific
5789 cmd_str
= build_unibyte_string (pe
.szExeFile
);
5792 code_convert_string_norecord (cmd_str
,
5793 Vlocale_coding_system
, 0);
5795 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
5796 attrs
= Fcons (Fcons (Qppid
,
5797 make_fixnum_or_float (pe
.th32ParentProcessID
)),
5799 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
5801 attrs
= Fcons (Fcons (Qthcount
,
5802 make_fixnum_or_float (pe
.cntThreads
)),
5809 CloseHandle (h_snapshot
);
5818 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
5820 /* If we were denied a handle to the process, try again after
5821 enabling the SeDebugPrivilege in our process. */
5824 TOKEN_PRIVILEGES priv_current
;
5826 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
5828 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
5830 restore_privilege (&priv_current
);
5836 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
5839 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
5840 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5842 buf
= xmalloc (blen
);
5843 result
= get_token_information (token
, TokenUser
,
5844 (LPVOID
)buf
, blen
, &needed
);
5847 memcpy (&user_token
, buf
, sizeof (user_token
));
5848 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
5850 euid
= get_rid (user_token
.User
.Sid
);
5851 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
5856 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
5859 strcpy (uname
, "unknown");
5863 ulength
= strlen (uname
);
5869 /* Determine a reasonable euid and gid values. */
5870 if (xstrcasecmp ("administrator", uname
) == 0)
5872 euid
= 500; /* well-known Administrator uid */
5873 egid
= 513; /* well-known None gid */
5877 /* Get group id and name. */
5878 result
= get_token_information (token
, TokenPrimaryGroup
,
5879 (LPVOID
)buf
, blen
, &needed
);
5880 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5882 buf
= xrealloc (buf
, blen
= needed
);
5883 result
= get_token_information (token
, TokenPrimaryGroup
,
5884 (LPVOID
)buf
, blen
, &needed
);
5888 memcpy (&group_token
, buf
, sizeof (group_token
));
5889 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
5891 egid
= get_rid (group_token
.PrimaryGroup
);
5892 dlength
= sizeof (domain
);
5894 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
5895 gname
, &glength
, NULL
, &dlength
,
5898 w32_add_to_cache (group_token
.PrimaryGroup
,
5902 strcpy (gname
, "None");
5906 glength
= strlen (gname
);
5914 if (!is_windows_9x ())
5916 /* We couldn't open the process token, presumably because of
5917 insufficient access rights. Assume this process is run
5919 strcpy (uname
, "SYSTEM");
5920 strcpy (gname
, "None");
5921 euid
= 18; /* SYSTEM */
5922 egid
= 513; /* None */
5923 glength
= strlen (gname
);
5924 ulength
= strlen (uname
);
5926 /* If we are running under Windows 9X, where security calls are
5927 not supported, we assume all processes are run by the current
5929 else if (GetUserName (uname
, &ulength
))
5931 if (xstrcasecmp ("administrator", uname
) == 0)
5936 strcpy (gname
, "None");
5937 glength
= strlen (gname
);
5938 ulength
= strlen (uname
);
5944 strcpy (uname
, "administrator");
5945 ulength
= strlen (uname
);
5946 strcpy (gname
, "None");
5947 glength
= strlen (gname
);
5950 CloseHandle (token
);
5953 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
5954 tem
= make_unibyte_string (uname
, ulength
);
5955 attrs
= Fcons (Fcons (Quser
,
5956 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5958 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
5959 tem
= make_unibyte_string (gname
, glength
);
5960 attrs
= Fcons (Fcons (Qgroup
,
5961 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5964 if (global_memory_status_ex (&memstex
))
5965 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5966 totphys
= memstex
.ullTotalPhys
/ 1024.0;
5968 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5969 double, so we need to do this for it... */
5971 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
5972 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
5973 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
5975 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
5977 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5978 else if (global_memory_status (&memst
))
5979 totphys
= memst
.dwTotalPhys
/ 1024.0;
5982 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
5985 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
5987 attrs
= Fcons (Fcons (Qmajflt
,
5988 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
5990 attrs
= Fcons (Fcons (Qvsize
,
5991 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
5993 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5995 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5998 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
6000 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
6002 attrs
= Fcons (Fcons (Qmajflt
,
6003 make_fixnum_or_float (mem
.PageFaultCount
)),
6005 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
6007 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6010 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
6012 DWORD rss
= maxrss
/ 1024;
6014 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
6016 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6019 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
6021 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
6022 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
6023 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
6024 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
6025 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
6026 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
6029 /* FIXME: Retrieve command line by walking the PEB of the process. */
6032 CloseHandle (h_proc
);
6038 /* Wrappers for winsock functions to map between our file descriptors
6039 and winsock's handles; also set h_errno for convenience.
6041 To allow Emacs to run on systems which don't have winsock support
6042 installed, we dynamically link to winsock on startup if present, and
6043 otherwise provide the minimum necessary functionality
6044 (eg. gethostname). */
6046 /* function pointers for relevant socket functions */
6047 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
6048 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
6049 int (PASCAL
*pfn_WSAGetLastError
) (void);
6050 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
6051 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
6052 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
6053 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
6054 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6055 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6056 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
6057 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
6058 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
6059 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
6060 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
6061 int (PASCAL
*pfn_WSACleanup
) (void);
6063 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
6064 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
6065 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
6066 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
6067 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
6068 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
6069 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
6070 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
6071 const char * optval
, int optlen
);
6072 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
6073 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
6075 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
6076 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
6077 struct sockaddr
* from
, int * fromlen
);
6078 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
6079 const struct sockaddr
* to
, int tolen
);
6081 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6082 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
6083 #ifndef HANDLE_FLAG_INHERIT
6084 #define HANDLE_FLAG_INHERIT 1
6088 static int winsock_inuse
;
6093 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
6095 release_listen_threads ();
6096 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6097 after WSAStartup returns successfully, but it seems reasonable
6098 to allow unloading winsock anyway in that case. */
6099 if (pfn_WSACleanup () == 0 ||
6100 pfn_WSAGetLastError () == WSAENETDOWN
)
6102 if (FreeLibrary (winsock_lib
))
6111 init_winsock (int load_now
)
6113 WSADATA winsockData
;
6115 if (winsock_lib
!= NULL
)
6118 pfn_SetHandleInformation
6119 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6120 "SetHandleInformation");
6122 winsock_lib
= LoadLibrary ("Ws2_32.dll");
6124 if (winsock_lib
!= NULL
)
6126 /* dynamically link to socket functions */
6128 #define LOAD_PROC(fn) \
6129 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6132 LOAD_PROC (WSAStartup
);
6133 LOAD_PROC (WSASetLastError
);
6134 LOAD_PROC (WSAGetLastError
);
6135 LOAD_PROC (WSAEventSelect
);
6136 LOAD_PROC (WSACreateEvent
);
6137 LOAD_PROC (WSACloseEvent
);
6140 LOAD_PROC (connect
);
6141 LOAD_PROC (ioctlsocket
);
6144 LOAD_PROC (closesocket
);
6145 LOAD_PROC (shutdown
);
6148 LOAD_PROC (inet_addr
);
6149 LOAD_PROC (gethostname
);
6150 LOAD_PROC (gethostbyname
);
6151 LOAD_PROC (getservbyname
);
6152 LOAD_PROC (getpeername
);
6153 LOAD_PROC (WSACleanup
);
6154 LOAD_PROC (setsockopt
);
6156 LOAD_PROC (getsockname
);
6158 LOAD_PROC (recvfrom
);
6162 /* specify version 1.1 of winsock */
6163 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
6165 if (winsockData
.wVersion
!= 0x101)
6170 /* Report that winsock exists and is usable, but leave
6171 socket functions disabled. I am assuming that calling
6172 WSAStartup does not require any network interaction,
6173 and in particular does not cause or require a dial-up
6174 connection to be established. */
6177 FreeLibrary (winsock_lib
);
6185 FreeLibrary (winsock_lib
);
6195 /* Function to map winsock error codes to errno codes for those errno
6196 code defined in errno.h (errno values not defined by errno.h are
6197 already in nt/inc/sys/socket.h). */
6204 if (winsock_lib
== NULL
)
6207 wsa_err
= pfn_WSAGetLastError ();
6211 case WSAEACCES
: errno
= EACCES
; break;
6212 case WSAEBADF
: errno
= EBADF
; break;
6213 case WSAEFAULT
: errno
= EFAULT
; break;
6214 case WSAEINTR
: errno
= EINTR
; break;
6215 case WSAEINVAL
: errno
= EINVAL
; break;
6216 case WSAEMFILE
: errno
= EMFILE
; break;
6217 case WSAENAMETOOLONG
: errno
= ENAMETOOLONG
; break;
6218 case WSAENOTEMPTY
: errno
= ENOTEMPTY
; break;
6219 default: errno
= wsa_err
; break;
6227 if (winsock_lib
!= NULL
)
6228 pfn_WSASetLastError (0);
6231 /* Extend strerror to handle the winsock-specific error codes. */
6235 } _wsa_errlist
[] = {
6236 {WSAEINTR
, "Interrupted function call"},
6237 {WSAEBADF
, "Bad file descriptor"},
6238 {WSAEACCES
, "Permission denied"},
6239 {WSAEFAULT
, "Bad address"},
6240 {WSAEINVAL
, "Invalid argument"},
6241 {WSAEMFILE
, "Too many open files"},
6243 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
6244 {WSAEINPROGRESS
, "Operation now in progress"},
6245 {WSAEALREADY
, "Operation already in progress"},
6246 {WSAENOTSOCK
, "Socket operation on non-socket"},
6247 {WSAEDESTADDRREQ
, "Destination address required"},
6248 {WSAEMSGSIZE
, "Message too long"},
6249 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
6250 {WSAENOPROTOOPT
, "Bad protocol option"},
6251 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
6252 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
6253 {WSAEOPNOTSUPP
, "Operation not supported"},
6254 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
6255 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
6256 {WSAEADDRINUSE
, "Address already in use"},
6257 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
6258 {WSAENETDOWN
, "Network is down"},
6259 {WSAENETUNREACH
, "Network is unreachable"},
6260 {WSAENETRESET
, "Network dropped connection on reset"},
6261 {WSAECONNABORTED
, "Software caused connection abort"},
6262 {WSAECONNRESET
, "Connection reset by peer"},
6263 {WSAENOBUFS
, "No buffer space available"},
6264 {WSAEISCONN
, "Socket is already connected"},
6265 {WSAENOTCONN
, "Socket is not connected"},
6266 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
6267 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
6268 {WSAETIMEDOUT
, "Connection timed out"},
6269 {WSAECONNREFUSED
, "Connection refused"},
6270 {WSAELOOP
, "Network loop"}, /* not sure */
6271 {WSAENAMETOOLONG
, "Name is too long"},
6272 {WSAEHOSTDOWN
, "Host is down"},
6273 {WSAEHOSTUNREACH
, "No route to host"},
6274 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
6275 {WSAEPROCLIM
, "Too many processes"},
6276 {WSAEUSERS
, "Too many users"}, /* not sure */
6277 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
6278 {WSAESTALE
, "Data is stale"}, /* not sure */
6279 {WSAEREMOTE
, "Remote error"}, /* not sure */
6281 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
6282 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
6283 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
6284 {WSAEDISCON
, "Graceful shutdown in progress"},
6286 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
6287 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
6288 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
6289 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
6290 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
6291 {WSASYSCALLFAILURE
, "System call failure"},
6292 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
6293 {WSATYPE_NOT_FOUND
, "Class type not found"},
6294 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
6295 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
6296 {WSAEREFUSED
, "Operation refused"}, /* not sure */
6299 {WSAHOST_NOT_FOUND
, "Host not found"},
6300 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
6301 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
6302 {WSANO_DATA
, "Valid name, no data record of requested type"},
6308 sys_strerror (int error_no
)
6311 static char unknown_msg
[40];
6313 if (error_no
>= 0 && error_no
< sys_nerr
)
6314 return sys_errlist
[error_no
];
6316 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
6317 if (_wsa_errlist
[i
].errnum
== error_no
)
6318 return _wsa_errlist
[i
].msg
;
6320 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
6324 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6325 but I believe the method of keeping the socket handle separate (and
6326 insuring it is not inheritable) is the correct one. */
6328 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6330 static int socket_to_fd (SOCKET s
);
6333 sys_socket (int af
, int type
, int protocol
)
6337 if (winsock_lib
== NULL
)
6340 return INVALID_SOCKET
;
6345 /* call the real socket function */
6346 s
= pfn_socket (af
, type
, protocol
);
6348 if (s
!= INVALID_SOCKET
)
6349 return socket_to_fd (s
);
6355 /* Convert a SOCKET to a file descriptor. */
6357 socket_to_fd (SOCKET s
)
6362 /* Although under NT 3.5 _open_osfhandle will accept a socket
6363 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6364 that does not work under NT 3.1. However, we can get the same
6365 effect by using a backdoor function to replace an existing
6366 descriptor handle with the one we want. */
6368 /* allocate a file descriptor (with appropriate flags) */
6369 fd
= _open ("NUL:", _O_RDWR
);
6372 /* Make a non-inheritable copy of the socket handle. Note
6373 that it is possible that sockets aren't actually kernel
6374 handles, which appears to be the case on Windows 9x when
6375 the MS Proxy winsock client is installed. */
6377 /* Apparently there is a bug in NT 3.51 with some service
6378 packs, which prevents using DuplicateHandle to make a
6379 socket handle non-inheritable (causes WSACleanup to
6380 hang). The work-around is to use SetHandleInformation
6381 instead if it is available and implemented. */
6382 if (pfn_SetHandleInformation
)
6384 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
6388 HANDLE parent
= GetCurrentProcess ();
6389 HANDLE new_s
= INVALID_HANDLE_VALUE
;
6391 if (DuplicateHandle (parent
,
6397 DUPLICATE_SAME_ACCESS
))
6399 /* It is possible that DuplicateHandle succeeds even
6400 though the socket wasn't really a kernel handle,
6401 because a real handle has the same value. So
6402 test whether the new handle really is a socket. */
6403 long nonblocking
= 0;
6404 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
6406 pfn_closesocket (s
);
6411 CloseHandle (new_s
);
6416 eassert (fd
< MAXDESC
);
6417 fd_info
[fd
].hnd
= (HANDLE
) s
;
6419 /* set our own internal flags */
6420 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
6426 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6428 /* attach child_process to fd_info */
6429 if (fd_info
[ fd
].cp
!= NULL
)
6431 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
6435 fd_info
[ fd
].cp
= cp
;
6438 winsock_inuse
++; /* count open sockets */
6446 pfn_closesocket (s
);
6452 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
6454 if (winsock_lib
== NULL
)
6457 return SOCKET_ERROR
;
6461 if (fd_info
[s
].flags
& FILE_SOCKET
)
6463 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
6464 if (rc
== SOCKET_ERROR
)
6469 return SOCKET_ERROR
;
6473 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
6475 if (winsock_lib
== NULL
)
6478 return SOCKET_ERROR
;
6482 if (fd_info
[s
].flags
& FILE_SOCKET
)
6484 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
6485 if (rc
== SOCKET_ERROR
)
6490 return SOCKET_ERROR
;
6494 sys_htons (u_short hostshort
)
6496 return (winsock_lib
!= NULL
) ?
6497 pfn_htons (hostshort
) : hostshort
;
6501 sys_ntohs (u_short netshort
)
6503 return (winsock_lib
!= NULL
) ?
6504 pfn_ntohs (netshort
) : netshort
;
6508 sys_inet_addr (const char * cp
)
6510 return (winsock_lib
!= NULL
) ?
6511 pfn_inet_addr (cp
) : INADDR_NONE
;
6515 sys_gethostname (char * name
, int namelen
)
6517 if (winsock_lib
!= NULL
)
6522 retval
= pfn_gethostname (name
, namelen
);
6523 if (retval
== SOCKET_ERROR
)
6528 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
6529 return !GetComputerName (name
, (DWORD
*)&namelen
);
6532 return SOCKET_ERROR
;
6536 sys_gethostbyname (const char * name
)
6538 struct hostent
* host
;
6539 int h_err
= h_errno
;
6541 if (winsock_lib
== NULL
)
6543 h_errno
= NO_RECOVERY
;
6549 host
= pfn_gethostbyname (name
);
6561 sys_getservbyname (const char * name
, const char * proto
)
6563 struct servent
* serv
;
6565 if (winsock_lib
== NULL
)
6572 serv
= pfn_getservbyname (name
, proto
);
6579 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
6581 if (winsock_lib
== NULL
)
6584 return SOCKET_ERROR
;
6588 if (fd_info
[s
].flags
& FILE_SOCKET
)
6590 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
6591 if (rc
== SOCKET_ERROR
)
6596 return SOCKET_ERROR
;
6600 sys_shutdown (int s
, int how
)
6602 if (winsock_lib
== NULL
)
6605 return SOCKET_ERROR
;
6609 if (fd_info
[s
].flags
& FILE_SOCKET
)
6611 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
6612 if (rc
== SOCKET_ERROR
)
6617 return SOCKET_ERROR
;
6621 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
6623 if (winsock_lib
== NULL
)
6626 return SOCKET_ERROR
;
6630 if (fd_info
[s
].flags
& FILE_SOCKET
)
6632 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
6633 (const char *)optval
, optlen
);
6634 if (rc
== SOCKET_ERROR
)
6639 return SOCKET_ERROR
;
6643 sys_listen (int s
, int backlog
)
6645 if (winsock_lib
== NULL
)
6648 return SOCKET_ERROR
;
6652 if (fd_info
[s
].flags
& FILE_SOCKET
)
6654 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
6655 if (rc
== SOCKET_ERROR
)
6658 fd_info
[s
].flags
|= FILE_LISTEN
;
6662 return SOCKET_ERROR
;
6666 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
6668 if (winsock_lib
== NULL
)
6671 return SOCKET_ERROR
;
6675 if (fd_info
[s
].flags
& FILE_SOCKET
)
6677 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
6678 if (rc
== SOCKET_ERROR
)
6683 return SOCKET_ERROR
;
6687 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
6689 if (winsock_lib
== NULL
)
6696 if (fd_info
[s
].flags
& FILE_LISTEN
)
6698 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
6700 if (t
== INVALID_SOCKET
)
6703 fd
= socket_to_fd (t
);
6707 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6708 ResetEvent (fd_info
[s
].cp
->char_avail
);
6717 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
6718 struct sockaddr
* from
, int * fromlen
)
6720 if (winsock_lib
== NULL
)
6723 return SOCKET_ERROR
;
6727 if (fd_info
[s
].flags
& FILE_SOCKET
)
6729 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
6730 if (rc
== SOCKET_ERROR
)
6735 return SOCKET_ERROR
;
6739 sys_sendto (int s
, const char * buf
, int len
, int flags
,
6740 const struct sockaddr
* to
, int tolen
)
6742 if (winsock_lib
== NULL
)
6745 return SOCKET_ERROR
;
6749 if (fd_info
[s
].flags
& FILE_SOCKET
)
6751 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
6752 if (rc
== SOCKET_ERROR
)
6757 return SOCKET_ERROR
;
6760 /* Windows does not have an fcntl function. Provide an implementation
6761 good enough for Emacs. */
6763 fcntl (int s
, int cmd
, int options
)
6765 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
6766 invoked in a context where fd1 is closed and all descriptors less
6767 than fd1 are open, so sys_dup is an adequate implementation. */
6768 if (cmd
== F_DUPFD_CLOEXEC
)
6771 if (winsock_lib
== NULL
)
6778 if (fd_info
[s
].flags
& FILE_SOCKET
)
6780 if (cmd
== F_SETFL
&& options
== O_NONBLOCK
)
6782 unsigned long nblock
= 1;
6783 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
6784 if (rc
== SOCKET_ERROR
)
6786 /* Keep track of the fact that we set this to non-blocking. */
6787 fd_info
[s
].flags
|= FILE_NDELAY
;
6793 return SOCKET_ERROR
;
6797 return SOCKET_ERROR
;
6801 /* Shadow main io functions: we need to handle pipes and sockets more
6802 intelligently, and implement non-blocking mode as well. */
6815 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
6817 child_process
* cp
= fd_info
[fd
].cp
;
6819 fd_info
[fd
].cp
= NULL
;
6821 if (CHILD_ACTIVE (cp
))
6823 /* if last descriptor to active child_process then cleanup */
6825 for (i
= 0; i
< MAXDESC
; i
++)
6829 if (fd_info
[i
].cp
== cp
)
6834 if (fd_info
[fd
].flags
& FILE_SOCKET
)
6836 if (winsock_lib
== NULL
) emacs_abort ();
6838 pfn_shutdown (SOCK_HANDLE (fd
), 2);
6839 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
6841 winsock_inuse
--; /* count open sockets */
6843 /* If the process handle is NULL, it's either a socket
6844 or serial connection, or a subprocess that was
6845 already reaped by reap_subprocess, but whose
6846 resources were not yet freed, because its output was
6847 not fully read yet by the time it was reaped. (This
6848 usually happens with async subprocesses whose output
6849 is being read by Emacs.) Otherwise, this process was
6850 not reaped yet, so we set its FD to a negative value
6851 to make sure sys_select will eventually get to
6852 calling the SIGCHLD handler for it, which will then
6853 invoke waitpid and reap_subprocess. */
6854 if (cp
->procinfo
.hProcess
== NULL
)
6862 if (fd
>= 0 && fd
< MAXDESC
)
6863 fd_info
[fd
].flags
= 0;
6865 /* Note that sockets do not need special treatment here (at least on
6866 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
6867 closesocket is equivalent to CloseHandle, which is to be expected
6868 because socket handles are fully fledged kernel handles. */
6880 if (new_fd
>= 0 && new_fd
< MAXDESC
)
6882 /* duplicate our internal info as well */
6883 fd_info
[new_fd
] = fd_info
[fd
];
6889 sys_dup2 (int src
, int dst
)
6893 if (dst
< 0 || dst
>= MAXDESC
)
6899 /* make sure we close the destination first if it's a pipe or socket */
6900 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
6903 rc
= _dup2 (src
, dst
);
6906 /* duplicate our internal info as well */
6907 fd_info
[dst
] = fd_info
[src
];
6913 pipe2 (int * phandles
, int pipe2_flags
)
6918 eassert (pipe2_flags
== O_CLOEXEC
);
6920 /* make pipe handles non-inheritable; when we spawn a child, we
6921 replace the relevant handle with an inheritable one. Also put
6922 pipes into binary mode; we will do text mode translation ourselves
6924 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
6928 /* Protect against overflow, since Windows can open more handles than
6929 our fd_info array has room for. */
6930 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
6932 _close (phandles
[0]);
6933 _close (phandles
[1]);
6939 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
6940 fd_info
[phandles
[0]].flags
= flags
;
6942 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
6943 fd_info
[phandles
[1]].flags
= flags
;
6950 /* Function to do blocking read of one byte, needed to implement
6951 select. It is only allowed on communication ports, sockets, or
6954 _sys_read_ahead (int fd
)
6959 if (fd
< 0 || fd
>= MAXDESC
)
6960 return STATUS_READ_ERROR
;
6962 cp
= fd_info
[fd
].cp
;
6964 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6965 return STATUS_READ_ERROR
;
6967 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
6968 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
6970 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
6974 cp
->status
= STATUS_READ_IN_PROGRESS
;
6976 if (fd_info
[fd
].flags
& FILE_PIPE
)
6978 rc
= _read (fd
, &cp
->chr
, sizeof (char));
6980 /* Give subprocess time to buffer some more output for us before
6981 reporting that input is available; we need this because Windows 95
6982 connects DOS programs to pipes by making the pipe appear to be
6983 the normal console stdout - as a result most DOS programs will
6984 write to stdout without buffering, ie. one character at a
6985 time. Even some W32 programs do this - "dir" in a command
6986 shell on NT is very slow if we don't do this. */
6989 int wait
= w32_pipe_read_delay
;
6995 /* Yield remainder of our time slice, effectively giving a
6996 temporary priority boost to the child process. */
7000 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7002 HANDLE hnd
= fd_info
[fd
].hnd
;
7003 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7006 /* Configure timeouts for blocking read. */
7007 if (!GetCommTimeouts (hnd
, &ct
))
7009 cp
->status
= STATUS_READ_ERROR
;
7010 return STATUS_READ_ERROR
;
7012 ct
.ReadIntervalTimeout
= 0;
7013 ct
.ReadTotalTimeoutMultiplier
= 0;
7014 ct
.ReadTotalTimeoutConstant
= 0;
7015 if (!SetCommTimeouts (hnd
, &ct
))
7017 cp
->status
= STATUS_READ_ERROR
;
7018 return STATUS_READ_ERROR
;
7021 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
7023 if (GetLastError () != ERROR_IO_PENDING
)
7025 cp
->status
= STATUS_READ_ERROR
;
7026 return STATUS_READ_ERROR
;
7028 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7030 cp
->status
= STATUS_READ_ERROR
;
7031 return STATUS_READ_ERROR
;
7035 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
7037 unsigned long nblock
= 0;
7038 /* We always want this to block, so temporarily disable NDELAY. */
7039 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7040 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7042 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
7044 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7047 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7051 if (rc
== sizeof (char))
7052 cp
->status
= STATUS_READ_SUCCEEDED
;
7054 cp
->status
= STATUS_READ_FAILED
;
7060 _sys_wait_accept (int fd
)
7066 if (fd
< 0 || fd
>= MAXDESC
)
7067 return STATUS_READ_ERROR
;
7069 cp
= fd_info
[fd
].cp
;
7071 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7072 return STATUS_READ_ERROR
;
7074 cp
->status
= STATUS_READ_FAILED
;
7076 hEv
= pfn_WSACreateEvent ();
7077 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
7078 if (rc
!= SOCKET_ERROR
)
7081 rc
= WaitForSingleObject (hEv
, 500);
7083 } while (rc
== WAIT_TIMEOUT
7084 && cp
->status
!= STATUS_READ_ERROR
7086 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
7087 if (rc
== WAIT_OBJECT_0
)
7088 cp
->status
= STATUS_READ_SUCCEEDED
;
7090 pfn_WSACloseEvent (hEv
);
7096 sys_read (int fd
, char * buffer
, unsigned int count
)
7101 char * orig_buffer
= buffer
;
7109 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7111 child_process
*cp
= fd_info
[fd
].cp
;
7113 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
7121 /* re-read CR carried over from last read */
7122 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
7124 if (fd_info
[fd
].flags
& FILE_BINARY
) emacs_abort ();
7128 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
7131 /* presence of a child_process structure means we are operating in
7132 non-blocking mode - otherwise we just call _read directly.
7133 Note that the child_process structure might be missing because
7134 reap_subprocess has been called; in this case the pipe is
7135 already broken, so calling _read on it is okay. */
7138 int current_status
= cp
->status
;
7140 switch (current_status
)
7142 case STATUS_READ_FAILED
:
7143 case STATUS_READ_ERROR
:
7144 /* report normal EOF if nothing in buffer */
7146 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7149 case STATUS_READ_READY
:
7150 case STATUS_READ_IN_PROGRESS
:
7151 DebPrint (("sys_read called when read is in progress\n"));
7152 errno
= EWOULDBLOCK
;
7155 case STATUS_READ_SUCCEEDED
:
7156 /* consume read-ahead char */
7157 *buffer
++ = cp
->chr
;
7160 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7161 ResetEvent (cp
->char_avail
);
7163 case STATUS_READ_ACKNOWLEDGED
:
7167 DebPrint (("sys_read: bad status %d\n", current_status
));
7172 if (fd_info
[fd
].flags
& FILE_PIPE
)
7174 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
7175 to_read
= min (waiting
, (DWORD
) count
);
7178 nchars
+= _read (fd
, buffer
, to_read
);
7180 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7182 HANDLE hnd
= fd_info
[fd
].hnd
;
7183 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7189 /* Configure timeouts for non-blocking read. */
7190 if (!GetCommTimeouts (hnd
, &ct
))
7195 ct
.ReadIntervalTimeout
= MAXDWORD
;
7196 ct
.ReadTotalTimeoutMultiplier
= 0;
7197 ct
.ReadTotalTimeoutConstant
= 0;
7198 if (!SetCommTimeouts (hnd
, &ct
))
7204 if (!ResetEvent (ovl
->hEvent
))
7209 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
7211 if (GetLastError () != ERROR_IO_PENDING
)
7216 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7225 else /* FILE_SOCKET */
7227 if (winsock_lib
== NULL
) emacs_abort ();
7229 /* do the equivalent of a non-blocking read */
7230 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
7231 if (waiting
== 0 && nchars
== 0)
7233 errno
= EWOULDBLOCK
;
7239 /* always use binary mode for sockets */
7240 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
7241 if (res
== SOCKET_ERROR
)
7243 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7244 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7254 int nread
= _read (fd
, buffer
, count
);
7257 else if (nchars
== 0)
7262 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7263 /* Perform text mode translation if required. */
7264 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7266 nchars
= crlf_to_lf (nchars
, orig_buffer
);
7267 /* If buffer contains only CR, return that. To be absolutely
7268 sure we should attempt to read the next char, but in
7269 practice a CR to be followed by LF would not appear by
7270 itself in the buffer. */
7271 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
7273 fd_info
[fd
].flags
|= FILE_LAST_CR
;
7279 nchars
= _read (fd
, buffer
, count
);
7284 /* From w32xfns.c */
7285 extern HANDLE interrupt_handle
;
7287 /* For now, don't bother with a non-blocking mode */
7289 sys_write (int fd
, const void * buffer
, unsigned int count
)
7299 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7301 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
7307 /* Perform text mode translation if required. */
7308 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7310 char * tmpbuf
= alloca (count
* 2);
7311 unsigned char * src
= (void *)buffer
;
7312 unsigned char * dst
= tmpbuf
;
7317 unsigned char *next
;
7318 /* copy next line or remaining bytes */
7319 next
= _memccpy (dst
, src
, '\n', nbytes
);
7322 /* copied one line ending with '\n' */
7323 int copied
= next
- dst
;
7326 /* insert '\r' before '\n' */
7333 /* copied remaining partial line -> now finished */
7340 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
7342 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
7343 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
7344 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
7347 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
7349 if (GetLastError () != ERROR_IO_PENDING
)
7354 if (detect_input_pending ())
7355 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
7358 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
7359 if (active
== WAIT_OBJECT_0
)
7360 { /* User pressed C-g, cancel write, then leave. Don't bother
7361 cleaning up as we may only get stuck in buggy drivers. */
7362 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
7367 if (active
== WAIT_OBJECT_0
+ 1
7368 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
7375 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
7377 unsigned long nblock
= 0;
7378 if (winsock_lib
== NULL
) emacs_abort ();
7380 /* TODO: implement select() properly so non-blocking I/O works. */
7381 /* For now, make sure the write blocks. */
7382 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7383 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7385 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
7387 /* Set the socket back to non-blocking if it was before,
7388 for other operations that support it. */
7389 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7392 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7395 if (nchars
== SOCKET_ERROR
)
7397 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7398 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7404 /* Some networked filesystems don't like too large writes, so
7405 break them into smaller chunks. See the Comments section of
7406 the MSDN documentation of WriteFile for details behind the
7407 choice of the value of CHUNK below. See also the thread
7408 http://thread.gmane.org/gmane.comp.version-control.git/145294
7409 in the git mailing list. */
7410 const unsigned char *p
= buffer
;
7411 const unsigned chunk
= 30 * 1024 * 1024;
7416 unsigned this_chunk
= count
< chunk
? count
: chunk
;
7417 int n
= _write (fd
, p
, this_chunk
);
7425 else if (n
< this_chunk
)
7435 /* The Windows CRT functions are "optimized for speed", so they don't
7436 check for timezone and DST changes if they were last called less
7437 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
7438 all Emacs features that repeatedly call time functions (e.g.,
7439 display-time) are in real danger of missing timezone and DST
7440 changes. Calling tzset before each localtime call fixes that. */
7442 sys_localtime (const time_t *t
)
7445 return localtime (t
);
7450 /* Try loading LIBRARY_ID from the file(s) specified in
7451 Vdynamic_library_alist. If the library is loaded successfully,
7452 return the handle of the DLL, and record the filename in the
7453 property :loaded-from of LIBRARY_ID. If the library could not be
7454 found, or when it was already loaded (because the handle is not
7455 recorded anywhere, and so is lost after use), return NULL.
7457 We could also save the handle in :loaded-from, but currently
7458 there's no use case for it. */
7460 w32_delayed_load (Lisp_Object library_id
)
7462 HMODULE library_dll
= NULL
;
7464 CHECK_SYMBOL (library_id
);
7466 if (CONSP (Vdynamic_library_alist
)
7467 && NILP (Fassq (library_id
, Vlibrary_cache
)))
7469 Lisp_Object found
= Qnil
;
7470 Lisp_Object dlls
= Fassq (library_id
, Vdynamic_library_alist
);
7473 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
7475 CHECK_STRING_CAR (dlls
);
7476 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
7478 char name
[MAX_PATH
];
7481 len
= GetModuleFileNameA (library_dll
, name
, sizeof (name
));
7482 found
= Fcons (XCAR (dlls
),
7484 /* Possibly truncated */
7485 ? make_specified_string (name
, -1, len
, 1)
7491 Fput (library_id
, QCloaded_from
, found
);
7499 check_windows_init_file (void)
7501 /* A common indication that Emacs is not installed properly is when
7502 it cannot find the Windows installation file. If this file does
7503 not exist in the expected place, tell the user. */
7505 if (!noninteractive
&& !inhibit_window_system
7506 /* Vload_path is not yet initialized when we are loading
7508 && NILP (Vpurify_flag
))
7510 Lisp_Object init_file
;
7513 init_file
= build_string ("term/w32-win");
7514 fd
= openp (Vload_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
7517 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
7518 char *init_file_name
= SDATA (init_file
);
7519 char *load_path
= SDATA (load_path_print
);
7520 char *buffer
= alloca (1024
7521 + strlen (init_file_name
)
7522 + strlen (load_path
));
7525 "The Emacs Windows initialization file \"%s.el\" "
7526 "could not be found in your Emacs installation. "
7527 "Emacs checked the following directories for this file:\n"
7529 "When Emacs cannot find this file, it usually means that it "
7530 "was not installed properly, or its distribution file was "
7531 "not unpacked properly.\nSee the README.W32 file in the "
7532 "top-level Emacs directory for more information.",
7533 init_file_name
, load_path
);
7536 "Emacs Abort Dialog",
7537 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
7538 /* Use the low-level system abort. */
7549 term_ntproc (int ignored
)
7555 /* shutdown the socket interface if necessary */
7562 init_ntproc (int dumping
)
7564 sigset_t initial_mask
= 0;
7566 /* Initialize the socket interface now if available and requested by
7567 the user by defining PRELOAD_WINSOCK; otherwise loading will be
7568 delayed until open-network-stream is called (w32-has-winsock can
7569 also be used to dynamically load or reload winsock).
7571 Conveniently, init_environment is called before us, so
7572 PRELOAD_WINSOCK can be set in the registry. */
7574 /* Always initialize this correctly. */
7577 if (getenv ("PRELOAD_WINSOCK") != NULL
)
7578 init_winsock (TRUE
);
7580 /* Initial preparation for subprocess support: replace our standard
7581 handles with non-inheritable versions. */
7584 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
7585 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
7586 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
7588 parent
= GetCurrentProcess ();
7590 /* ignore errors when duplicating and closing; typically the
7591 handles will be invalid when running as a gui program. */
7592 DuplicateHandle (parent
,
7593 GetStdHandle (STD_INPUT_HANDLE
),
7598 DUPLICATE_SAME_ACCESS
);
7600 DuplicateHandle (parent
,
7601 GetStdHandle (STD_OUTPUT_HANDLE
),
7606 DUPLICATE_SAME_ACCESS
);
7608 DuplicateHandle (parent
,
7609 GetStdHandle (STD_ERROR_HANDLE
),
7614 DUPLICATE_SAME_ACCESS
);
7620 if (stdin_save
!= INVALID_HANDLE_VALUE
)
7621 _open_osfhandle ((intptr_t) stdin_save
, O_TEXT
);
7623 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
7626 if (stdout_save
!= INVALID_HANDLE_VALUE
)
7627 _open_osfhandle ((intptr_t) stdout_save
, O_TEXT
);
7629 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
7632 if (stderr_save
!= INVALID_HANDLE_VALUE
)
7633 _open_osfhandle ((intptr_t) stderr_save
, O_TEXT
);
7635 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
7639 /* unfortunately, atexit depends on implementation of malloc */
7640 /* atexit (term_ntproc); */
7643 /* Make sure we start with all signals unblocked. */
7644 sigprocmask (SIG_SETMASK
, &initial_mask
, NULL
);
7645 signal (SIGABRT
, term_ntproc
);
7649 /* determine which drives are fixed, for GetCachedVolumeInformation */
7651 /* GetDriveType must have trailing backslash. */
7652 char drive
[] = "A:\\";
7654 /* Loop over all possible drive letters */
7655 while (*drive
<= 'Z')
7657 /* Record if this drive letter refers to a fixed drive. */
7658 fixed_drives
[DRIVE_INDEX (*drive
)] =
7659 (GetDriveType (drive
) == DRIVE_FIXED
);
7664 /* Reset the volume info cache. */
7665 volume_cache
= NULL
;
7670 shutdown_handler ensures that buffers' autosave files are
7671 up to date when the user logs off, or the system shuts down.
7674 shutdown_handler (DWORD type
)
7676 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
7677 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
7678 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
7679 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
7681 /* Shut down cleanly, making sure autosave files are up to date. */
7682 shut_down_emacs (0, Qnil
);
7685 /* Allow other handlers to handle this signal. */
7690 globals_of_w32 is used to initialize those global variables that
7691 must always be initialized on startup even when the global variable
7692 initialized is non zero (see the function main in emacs.c).
7695 globals_of_w32 (void)
7697 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
7699 get_process_times_fn
= (GetProcessTimes_Proc
)
7700 GetProcAddress (kernel32
, "GetProcessTimes");
7702 DEFSYM (QCloaded_from
, ":loaded-from");
7704 g_b_init_is_windows_9x
= 0;
7705 g_b_init_open_process_token
= 0;
7706 g_b_init_get_token_information
= 0;
7707 g_b_init_lookup_account_sid
= 0;
7708 g_b_init_get_sid_sub_authority
= 0;
7709 g_b_init_get_sid_sub_authority_count
= 0;
7710 g_b_init_get_security_info
= 0;
7711 g_b_init_get_file_security
= 0;
7712 g_b_init_get_security_descriptor_owner
= 0;
7713 g_b_init_get_security_descriptor_group
= 0;
7714 g_b_init_is_valid_sid
= 0;
7715 g_b_init_create_toolhelp32_snapshot
= 0;
7716 g_b_init_process32_first
= 0;
7717 g_b_init_process32_next
= 0;
7718 g_b_init_open_thread_token
= 0;
7719 g_b_init_impersonate_self
= 0;
7720 g_b_init_revert_to_self
= 0;
7721 g_b_init_get_process_memory_info
= 0;
7722 g_b_init_get_process_working_set_size
= 0;
7723 g_b_init_global_memory_status
= 0;
7724 g_b_init_global_memory_status_ex
= 0;
7725 g_b_init_equal_sid
= 0;
7726 g_b_init_copy_sid
= 0;
7727 g_b_init_get_length_sid
= 0;
7728 g_b_init_get_native_system_info
= 0;
7729 g_b_init_get_system_times
= 0;
7730 g_b_init_create_symbolic_link
= 0;
7731 g_b_init_get_security_descriptor_dacl
= 0;
7732 g_b_init_convert_sd_to_sddl
= 0;
7733 g_b_init_convert_sddl_to_sd
= 0;
7734 g_b_init_is_valid_security_descriptor
= 0;
7735 g_b_init_set_file_security
= 0;
7736 num_of_processors
= 0;
7737 /* The following sets a handler for shutdown notifications for
7738 console apps. This actually applies to Emacs in both console and
7739 GUI modes, since we had to fool windows into thinking emacs is a
7740 console application to get console mode to work. */
7741 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
7743 /* "None" is the default group name on standalone workstations. */
7744 strcpy (dflt_group_name
, "None");
7746 /* Reset, in case it has some value inherited from dump time. */
7747 w32_stat_get_owner_group
= 0;
7750 /* For make-serial-process */
7752 serial_open (Lisp_Object port_obj
)
7754 char *port
= SSDATA (port_obj
);
7759 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
7760 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
7761 if (hnd
== INVALID_HANDLE_VALUE
)
7762 error ("Could not open %s", port
);
7763 fd
= (int) _open_osfhandle ((intptr_t) hnd
, 0);
7765 error ("Could not open %s", port
);
7769 error ("Could not create child process");
7771 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7772 fd_info
[ fd
].hnd
= hnd
;
7773 fd_info
[ fd
].flags
|=
7774 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
7775 if (fd_info
[ fd
].cp
!= NULL
)
7777 error ("fd_info[fd = %d] is already in use", fd
);
7779 fd_info
[ fd
].cp
= cp
;
7780 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
7781 if (cp
->ovl_read
.hEvent
== NULL
)
7782 error ("Could not create read event");
7783 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
7784 if (cp
->ovl_write
.hEvent
== NULL
)
7785 error ("Could not create write event");
7790 /* For serial-process-configure */
7792 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
7794 Lisp_Object childp2
= Qnil
;
7795 Lisp_Object tem
= Qnil
;
7799 char summary
[4] = "???"; /* This usually becomes "8N1". */
7801 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
7802 error ("Not a serial process");
7803 hnd
= fd_info
[ p
->outfd
].hnd
;
7805 childp2
= Fcopy_sequence (p
->childp
);
7807 /* Initialize timeouts for blocking read and blocking write. */
7808 if (!GetCommTimeouts (hnd
, &ct
))
7809 error ("GetCommTimeouts() failed");
7810 ct
.ReadIntervalTimeout
= 0;
7811 ct
.ReadTotalTimeoutMultiplier
= 0;
7812 ct
.ReadTotalTimeoutConstant
= 0;
7813 ct
.WriteTotalTimeoutMultiplier
= 0;
7814 ct
.WriteTotalTimeoutConstant
= 0;
7815 if (!SetCommTimeouts (hnd
, &ct
))
7816 error ("SetCommTimeouts() failed");
7817 /* Read port attributes and prepare default configuration. */
7818 memset (&dcb
, 0, sizeof (dcb
));
7819 dcb
.DCBlength
= sizeof (DCB
);
7820 if (!GetCommState (hnd
, &dcb
))
7821 error ("GetCommState() failed");
7824 dcb
.fAbortOnError
= FALSE
;
7825 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
7830 /* Configure speed. */
7831 if (!NILP (Fplist_member (contact
, QCspeed
)))
7832 tem
= Fplist_get (contact
, QCspeed
);
7834 tem
= Fplist_get (p
->childp
, QCspeed
);
7836 dcb
.BaudRate
= XINT (tem
);
7837 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
7839 /* Configure bytesize. */
7840 if (!NILP (Fplist_member (contact
, QCbytesize
)))
7841 tem
= Fplist_get (contact
, QCbytesize
);
7843 tem
= Fplist_get (p
->childp
, QCbytesize
);
7845 tem
= make_number (8);
7847 if (XINT (tem
) != 7 && XINT (tem
) != 8)
7848 error (":bytesize must be nil (8), 7, or 8");
7849 dcb
.ByteSize
= XINT (tem
);
7850 summary
[0] = XINT (tem
) + '0';
7851 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
7853 /* Configure parity. */
7854 if (!NILP (Fplist_member (contact
, QCparity
)))
7855 tem
= Fplist_get (contact
, QCparity
);
7857 tem
= Fplist_get (p
->childp
, QCparity
);
7858 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
7859 error (":parity must be nil (no parity), `even', or `odd'");
7860 dcb
.fParity
= FALSE
;
7861 dcb
.Parity
= NOPARITY
;
7862 dcb
.fErrorChar
= FALSE
;
7867 else if (EQ (tem
, Qeven
))
7871 dcb
.Parity
= EVENPARITY
;
7872 dcb
.fErrorChar
= TRUE
;
7874 else if (EQ (tem
, Qodd
))
7878 dcb
.Parity
= ODDPARITY
;
7879 dcb
.fErrorChar
= TRUE
;
7881 childp2
= Fplist_put (childp2
, QCparity
, tem
);
7883 /* Configure stopbits. */
7884 if (!NILP (Fplist_member (contact
, QCstopbits
)))
7885 tem
= Fplist_get (contact
, QCstopbits
);
7887 tem
= Fplist_get (p
->childp
, QCstopbits
);
7889 tem
= make_number (1);
7891 if (XINT (tem
) != 1 && XINT (tem
) != 2)
7892 error (":stopbits must be nil (1 stopbit), 1, or 2");
7893 summary
[2] = XINT (tem
) + '0';
7894 if (XINT (tem
) == 1)
7895 dcb
.StopBits
= ONESTOPBIT
;
7896 else if (XINT (tem
) == 2)
7897 dcb
.StopBits
= TWOSTOPBITS
;
7898 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
7900 /* Configure flowcontrol. */
7901 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
7902 tem
= Fplist_get (contact
, QCflowcontrol
);
7904 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
7905 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
7906 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
7907 dcb
.fOutxCtsFlow
= FALSE
;
7908 dcb
.fOutxDsrFlow
= FALSE
;
7909 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
7910 dcb
.fDsrSensitivity
= FALSE
;
7911 dcb
.fTXContinueOnXoff
= FALSE
;
7914 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
7915 dcb
.XonChar
= 17; /* Control-Q */
7916 dcb
.XoffChar
= 19; /* Control-S */
7919 /* Already configured. */
7921 else if (EQ (tem
, Qhw
))
7923 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
7924 dcb
.fOutxCtsFlow
= TRUE
;
7926 else if (EQ (tem
, Qsw
))
7931 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
7933 /* Activate configuration. */
7934 if (!SetCommState (hnd
, &dcb
))
7935 error ("SetCommState() failed");
7937 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
7938 pset_childp (p
, childp2
);
7944 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
7948 struct timespec timeout
;
7949 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7950 int fd
= process
->infd
;
7952 n
= sys_read (fd
, (char*)buf
, sz
);
7959 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7960 if (err
== EWOULDBLOCK
)
7963 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
7969 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
7971 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7972 int fd
= process
->outfd
;
7973 ssize_t n
= sys_write (fd
, buf
, sz
);
7975 /* 0 or more bytes written means everything went fine. */
7979 /* Negative bytes written means we got an error in errno.
7980 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7981 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
7982 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
7986 #endif /* HAVE_GNUTLS */