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 EMACS_TIME
*, 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])
2513 if (fd
< 0 && !file
)
2518 ut
.actime
= timespec
[0].tv_sec
;
2519 ut
.modtime
= timespec
[1].tv_sec
;
2521 return _futime (fd
, &ut
);
2523 return _utime (file
, &ut
);
2527 /* ------------------------------------------------------------------------- */
2528 /* IO support and wrapper functions for the Windows API. */
2529 /* ------------------------------------------------------------------------- */
2531 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2532 on network directories, so we handle that case here.
2533 (Ulrich Leodolter, 1/11/95). */
2535 sys_ctime (const time_t *t
)
2537 char *str
= (char *) ctime (t
);
2538 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2541 /* Emulate sleep...we could have done this with a define, but that
2542 would necessitate including windows.h in the files that used it.
2543 This is much easier. */
2545 sys_sleep (int seconds
)
2547 Sleep (seconds
* 1000);
2550 /* Internal MSVC functions for low-level descriptor munging */
2551 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2552 extern int __cdecl
_free_osfhnd (int fd
);
2554 /* parallel array of private info on file handles */
2555 filedesc fd_info
[ MAXDESC
];
2557 typedef struct volume_info_data
{
2558 struct volume_info_data
* next
;
2560 /* time when info was obtained */
2563 /* actual volume info */
2572 /* Global referenced by various functions. */
2573 static volume_info_data volume_info
;
2575 /* Vector to indicate which drives are local and fixed (for which cached
2576 data never expires). */
2577 static BOOL fixed_drives
[26];
2579 /* Consider cached volume information to be stale if older than 10s,
2580 at least for non-local drives. Info for fixed drives is never stale. */
2581 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2582 #define VOLINFO_STILL_VALID( root_dir, info ) \
2583 ( ( isalpha (root_dir[0]) && \
2584 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2585 || GetTickCount () - info->timestamp < 10000 )
2587 /* Cache support functions. */
2589 /* Simple linked list with linear search is sufficient. */
2590 static volume_info_data
*volume_cache
= NULL
;
2592 static volume_info_data
*
2593 lookup_volume_info (char * root_dir
)
2595 volume_info_data
* info
;
2597 for (info
= volume_cache
; info
; info
= info
->next
)
2598 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2604 add_volume_info (char * root_dir
, volume_info_data
* info
)
2606 info
->root_dir
= xstrdup (root_dir
);
2607 info
->next
= volume_cache
;
2608 volume_cache
= info
;
2612 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2613 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2614 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2615 static volume_info_data
*
2616 GetCachedVolumeInformation (char * root_dir
)
2618 volume_info_data
* info
;
2619 char default_root
[ MAX_PATH
];
2621 /* NULL for root_dir means use root from current directory. */
2622 if (root_dir
== NULL
)
2624 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2626 parse_root (default_root
, &root_dir
);
2628 root_dir
= default_root
;
2631 /* Local fixed drives can be cached permanently. Removable drives
2632 cannot be cached permanently, since the volume name and serial
2633 number (if nothing else) can change. Remote drives should be
2634 treated as if they are removable, since there is no sure way to
2635 tell whether they are or not. Also, the UNC association of drive
2636 letters mapped to remote volumes can be changed at any time (even
2637 by other processes) without notice.
2639 As a compromise, so we can benefit from caching info for remote
2640 volumes, we use a simple expiry mechanism to invalidate cache
2641 entries that are more than ten seconds old. */
2644 /* No point doing this, because WNetGetConnection is even slower than
2645 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2646 GetDriveType is about the only call of this type which does not
2647 involve network access, and so is extremely quick). */
2649 /* Map drive letter to UNC if remote. */
2650 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2652 char remote_name
[ 256 ];
2653 char drive
[3] = { root_dir
[0], ':' };
2655 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2657 /* do something */ ;
2661 info
= lookup_volume_info (root_dir
);
2663 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2671 /* Info is not cached, or is stale. */
2672 if (!GetVolumeInformation (root_dir
,
2673 name
, sizeof (name
),
2677 type
, sizeof (type
)))
2680 /* Cache the volume information for future use, overwriting existing
2681 entry if present. */
2684 info
= xmalloc (sizeof (volume_info_data
));
2685 add_volume_info (root_dir
, info
);
2693 info
->name
= xstrdup (name
);
2694 info
->serialnum
= serialnum
;
2695 info
->maxcomp
= maxcomp
;
2696 info
->flags
= flags
;
2697 info
->type
= xstrdup (type
);
2698 info
->timestamp
= GetTickCount ();
2704 /* Get information on the volume where NAME is held; set path pointer to
2705 start of pathname in NAME (past UNC header\volume header if present),
2706 if pPath is non-NULL.
2708 Note: if NAME includes symlinks, the information is for the volume
2709 of the symlink, not of its target. That's because, even though
2710 GetVolumeInformation returns information about the symlink target
2711 of its argument, we only pass the root directory to
2712 GetVolumeInformation, not the full NAME. */
2714 get_volume_info (const char * name
, const char ** pPath
)
2716 char temp
[MAX_PATH
];
2717 char *rootname
= NULL
; /* default to current volume */
2718 volume_info_data
* info
;
2723 /* Find the root name of the volume if given. */
2724 if (isalpha (name
[0]) && name
[1] == ':')
2732 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2736 int dbcs_p
= max_filename_mbslen () > 1;
2741 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2747 const char *p
= name
;
2749 name
= CharNextExA (file_name_codepage
, name
, 0);
2750 memcpy (str
, p
, name
- p
);
2763 info
= GetCachedVolumeInformation (rootname
);
2766 /* Set global referenced by other functions. */
2767 volume_info
= *info
;
2773 /* Determine if volume is FAT format (ie. only supports short 8.3
2774 names); also set path pointer to start of pathname in name, if
2775 pPath is non-NULL. */
2777 is_fat_volume (const char * name
, const char ** pPath
)
2779 if (get_volume_info (name
, pPath
))
2780 return (volume_info
.maxcomp
== 12);
2784 /* Map filename to a valid 8.3 name if necessary.
2785 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2787 map_w32_filename (const char * name
, const char ** pPath
)
2789 static char shortname
[MAX_PATH
];
2790 char * str
= shortname
;
2793 const char * save_name
= name
;
2795 if (strlen (name
) >= MAX_PATH
)
2797 /* Return a filename which will cause callers to fail. */
2798 strcpy (shortname
, "?");
2802 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2804 register int left
= 8; /* maximum number of chars in part */
2805 register int extn
= 0; /* extension added? */
2806 register int dots
= 2; /* maximum number of dots allowed */
2809 *str
++ = *name
++; /* skip past UNC header */
2811 while ((c
= *name
++))
2818 *str
++ = (c
== ':' ? ':' : '\\');
2819 extn
= 0; /* reset extension flags */
2820 dots
= 2; /* max 2 dots */
2821 left
= 8; /* max length 8 for main part */
2826 /* Convert path components of the form .xxx to _xxx,
2827 but leave . and .. as they are. This allows .emacs
2828 to be read as _emacs, for example. */
2832 IS_DIRECTORY_SEP (*name
))
2847 extn
= 1; /* we've got an extension */
2848 left
= 3; /* 3 chars in extension */
2852 /* any embedded dots after the first are converted to _ */
2857 case '#': /* don't lose these, they're important */
2859 str
[-1] = c
; /* replace last character of part */
2864 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2866 dots
= 0; /* started a path component */
2875 strcpy (shortname
, name
);
2876 unixtodos_filename (shortname
);
2880 *pPath
= shortname
+ (path
- save_name
);
2886 is_exec (const char * name
)
2888 char * p
= strrchr (name
, '.');
2891 && (xstrcasecmp (p
, ".exe") == 0 ||
2892 xstrcasecmp (p
, ".com") == 0 ||
2893 xstrcasecmp (p
, ".bat") == 0 ||
2894 xstrcasecmp (p
, ".cmd") == 0));
2897 /* Emulate the Unix directory procedures opendir, closedir,
2898 and readdir. We can't use the procedures supplied in sysdep.c,
2899 so we provide them here. */
2901 struct dirent dir_static
; /* simulated directory contents */
2902 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2903 static int dir_is_fat
;
2904 static char dir_pathname
[MAXPATHLEN
+1];
2905 static WIN32_FIND_DATA dir_find_data
;
2907 /* Support shares on a network resource as subdirectories of a read-only
2909 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2910 static HANDLE
open_unc_volume (const char *);
2911 static char *read_unc_volume (HANDLE
, char *, int);
2912 static void close_unc_volume (HANDLE
);
2915 opendir (const char *filename
)
2919 /* Opening is done by FindFirstFile. However, a read is inherent to
2920 this operation, so we defer the open until read time. */
2922 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2924 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2927 /* Note: We don't support traversal of UNC volumes via symlinks.
2928 Doing so would mean punishing 99.99% of use cases by resolving
2929 all the possible symlinks in FILENAME, recursively. */
2930 if (is_unc_volume (filename
))
2932 wnet_enum_handle
= open_unc_volume (filename
);
2933 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2937 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2944 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2945 dir_pathname
[MAXPATHLEN
] = '\0';
2946 /* Note: We don't support symlinks to file names on FAT volumes.
2947 Doing so would mean punishing 99.99% of use cases by resolving
2948 all the possible symlinks in FILENAME, recursively. */
2949 dir_is_fat
= is_fat_volume (filename
, NULL
);
2955 closedir (DIR *dirp
)
2957 /* If we have a find-handle open, close it. */
2958 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2960 FindClose (dir_find_handle
);
2961 dir_find_handle
= INVALID_HANDLE_VALUE
;
2963 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2965 close_unc_volume (wnet_enum_handle
);
2966 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2968 xfree ((char *) dirp
);
2974 int downcase
= !NILP (Vw32_downcase_file_names
);
2976 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2978 if (!read_unc_volume (wnet_enum_handle
,
2979 dir_find_data
.cFileName
,
2983 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2984 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2986 char filename
[MAXNAMLEN
+ 3];
2988 int dbcs_p
= max_filename_mbslen () > 1;
2990 strcpy (filename
, dir_pathname
);
2991 ln
= strlen (filename
) - 1;
2994 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2995 strcat (filename
, "\\");
2999 char *end
= filename
+ ln
+ 1;
3000 char *last_char
= CharPrevExA (file_name_codepage
, filename
, end
, 0);
3002 if (!IS_DIRECTORY_SEP (*last_char
))
3003 strcat (filename
, "\\");
3005 strcat (filename
, "*");
3007 /* Note: No need to resolve symlinks in FILENAME, because
3008 FindFirst opens the directory that is the target of a
3010 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
3012 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
3017 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
3021 /* Emacs never uses this value, so don't bother making it match
3022 value returned by stat(). */
3023 dir_static
.d_ino
= 1;
3025 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
3027 /* If the file name in cFileName[] includes `?' characters, it means
3028 the original file name used characters that cannot be represented
3029 by the current ANSI codepage. To avoid total lossage, retrieve
3030 the short 8+3 alias of the long file name. */
3031 if (_mbspbrk (dir_static
.d_name
, "?"))
3033 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
3034 downcase
= 1; /* 8+3 aliases are returned in all caps */
3036 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
3037 dir_static
.d_reclen
= sizeof (struct dirent
) - MAXNAMLEN
+ 3 +
3038 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
3040 /* If the file name in cFileName[] includes `?' characters, it means
3041 the original file name used characters that cannot be represented
3042 by the current ANSI codepage. To avoid total lossage, retrieve
3043 the short 8+3 alias of the long file name. */
3044 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
3046 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
3047 /* 8+3 aliases are returned in all caps, which could break
3048 various alists that look at filenames' extensions. */
3052 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
3053 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
3055 _mbslwr (dir_static
.d_name
);
3059 int dbcs_p
= max_filename_mbslen () > 1;
3060 for (p
= dir_static
.d_name
; *p
; )
3062 if (*p
>= 'a' && *p
<= 'z')
3065 p
= CharNextExA (file_name_codepage
, p
, 0);
3070 _mbslwr (dir_static
.d_name
);
3077 open_unc_volume (const char *path
)
3083 nr
.dwScope
= RESOURCE_GLOBALNET
;
3084 nr
.dwType
= RESOURCETYPE_DISK
;
3085 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
3086 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3087 nr
.lpLocalName
= NULL
;
3088 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
3089 nr
.lpComment
= NULL
;
3090 nr
.lpProvider
= NULL
;
3092 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
3093 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
3095 if (result
== NO_ERROR
)
3098 return INVALID_HANDLE_VALUE
;
3102 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
3106 DWORD bufsize
= 512;
3109 int dbcs_p
= max_filename_mbslen () > 1;
3112 buffer
= alloca (bufsize
);
3113 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
3114 if (result
!= NO_ERROR
)
3117 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3118 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
3121 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
3124 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
))
3125 ptr
= CharNextExA (file_name_codepage
, ptr
, 0);
3129 strncpy (readbuf
, ptr
, size
);
3134 close_unc_volume (HANDLE henum
)
3136 if (henum
!= INVALID_HANDLE_VALUE
)
3137 WNetCloseEnum (henum
);
3141 unc_volume_file_attributes (const char *path
)
3146 henum
= open_unc_volume (path
);
3147 if (henum
== INVALID_HANDLE_VALUE
)
3150 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
3152 close_unc_volume (henum
);
3157 /* Ensure a network connection is authenticated. */
3159 logon_network_drive (const char *path
)
3161 NETRESOURCE resource
;
3162 char share
[MAX_PATH
];
3169 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
3170 drvtype
= DRIVE_REMOTE
;
3171 else if (path
[0] == '\0' || path
[1] != ':')
3172 drvtype
= GetDriveType (NULL
);
3179 drvtype
= GetDriveType (drive
);
3182 /* Only logon to networked drives. */
3183 if (drvtype
!= DRIVE_REMOTE
)
3187 strncpy (share
, path
, MAX_PATH
);
3188 /* Truncate to just server and share name. */
3189 dbcs_p
= max_filename_mbslen () > 1;
3190 for (p
= share
+ 2; *p
&& p
< share
+ MAX_PATH
; )
3192 if (IS_DIRECTORY_SEP (*p
) && ++n_slashes
> 3)
3198 p
= CharNextExA (file_name_codepage
, p
, 0);
3203 resource
.dwType
= RESOURCETYPE_DISK
;
3204 resource
.lpLocalName
= NULL
;
3205 resource
.lpRemoteName
= share
;
3206 resource
.lpProvider
= NULL
;
3208 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
3211 /* Emulate faccessat(2). */
3213 faccessat (int dirfd
, const char * path
, int mode
, int flags
)
3217 if (dirfd
!= AT_FDCWD
3218 && !(IS_DIRECTORY_SEP (path
[0])
3219 || IS_DEVICE_SEP (path
[1])))
3225 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3226 newer versions blow up when passed D_OK. */
3227 path
= map_w32_filename (path
, NULL
);
3228 /* If the last element of PATH is a symlink, we need to resolve it
3229 to get the attributes of its target file. Note: any symlinks in
3230 PATH elements other than the last one are transparently resolved
3231 by GetFileAttributes below. */
3232 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0
3233 && (flags
& AT_SYMLINK_NOFOLLOW
) == 0)
3234 path
= chase_symlinks (path
);
3236 if ((attributes
= GetFileAttributes (path
)) == -1)
3238 DWORD w32err
= GetLastError ();
3242 case ERROR_INVALID_NAME
:
3243 case ERROR_BAD_PATHNAME
:
3244 if (is_unc_volume (path
))
3246 attributes
= unc_volume_file_attributes (path
);
3247 if (attributes
== -1)
3255 case ERROR_FILE_NOT_FOUND
:
3256 case ERROR_BAD_NETPATH
:
3265 if ((mode
& X_OK
) != 0
3266 && !(is_exec (path
) || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3271 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3276 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3284 /* Shadow some MSVC runtime functions to map requests for long filenames
3285 to reasonable short names if necessary. This was originally added to
3286 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3290 sys_chdir (const char * path
)
3292 return _chdir (map_w32_filename (path
, NULL
));
3296 sys_chmod (const char * path
, int mode
)
3298 path
= chase_symlinks (map_w32_filename (path
, NULL
));
3299 return _chmod (path
, mode
);
3303 sys_creat (const char * path
, int mode
)
3305 return _creat (map_w32_filename (path
, NULL
), mode
);
3309 sys_fopen (const char * path
, const char * mode
)
3313 const char * mode_save
= mode
;
3315 /* Force all file handles to be non-inheritable. This is necessary to
3316 ensure child processes don't unwittingly inherit handles that might
3317 prevent future file access. */
3321 else if (mode
[0] == 'w' || mode
[0] == 'a')
3322 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
3326 /* Only do simplistic option parsing. */
3330 oflag
&= ~(O_RDONLY
| O_WRONLY
);
3333 else if (mode
[0] == 'b')
3338 else if (mode
[0] == 't')
3345 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
3349 return _fdopen (fd
, mode_save
);
3352 /* This only works on NTFS volumes, but is useful to have. */
3354 sys_link (const char * old
, const char * new)
3358 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
3360 if (old
== NULL
|| new == NULL
)
3366 strcpy (oldname
, map_w32_filename (old
, NULL
));
3367 strcpy (newname
, map_w32_filename (new, NULL
));
3369 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
3370 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
3371 if (fileh
!= INVALID_HANDLE_VALUE
)
3375 /* Confusingly, the "alternate" stream name field does not apply
3376 when restoring a hard link, and instead contains the actual
3377 stream data for the link (ie. the name of the link to create).
3378 The WIN32_STREAM_ID structure before the cStreamName field is
3379 the stream header, which is then immediately followed by the
3383 WIN32_STREAM_ID wid
;
3384 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
3387 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
3388 data
.wid
.cStreamName
, MAX_PATH
);
3391 LPVOID context
= NULL
;
3394 data
.wid
.dwStreamId
= BACKUP_LINK
;
3395 data
.wid
.dwStreamAttributes
= 0;
3396 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
3397 data
.wid
.Size
.HighPart
= 0;
3398 data
.wid
.dwStreamNameSize
= 0;
3400 if (BackupWrite (fileh
, (LPBYTE
)&data
,
3401 offsetof (WIN32_STREAM_ID
, cStreamName
)
3402 + data
.wid
.Size
.LowPart
,
3403 &wbytes
, FALSE
, FALSE
, &context
)
3404 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
3411 /* Should try mapping GetLastError to errno; for now just
3412 indicate a general error (eg. links not supported). */
3413 errno
= EINVAL
; // perhaps EMLINK?
3417 CloseHandle (fileh
);
3426 sys_mkdir (const char * path
)
3428 return _mkdir (map_w32_filename (path
, NULL
));
3432 sys_open (const char * path
, int oflag
, int mode
)
3434 const char* mpath
= map_w32_filename (path
, NULL
);
3437 /* If possible, try to open file without _O_CREAT, to be able to
3438 write to existing hidden and system files. Force all file
3439 handles to be non-inheritable. */
3440 if ((oflag
& (_O_CREAT
| _O_EXCL
)) != (_O_CREAT
| _O_EXCL
))
3441 res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3443 res
= _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
3448 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
3451 Standard algorithm for generating a temporary file name seems to be
3452 use pid or tid with a letter on the front (in place of the 6 X's)
3453 and cycle through the letters to find a unique name. We extend
3454 that to allow any reasonable character as the first of the 6 X's,
3455 so that the number of simultaneously used temporary files will be
3459 mkostemp (char * template, int flags
)
3463 unsigned uid
= GetCurrentThreadId ();
3464 int save_errno
= errno
;
3465 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3468 if (template == NULL
)
3471 p
= template + strlen (template);
3473 /* replace up to the last 5 X's with uid in decimal */
3474 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
3476 p
[0] = '0' + uid
% 10;
3480 if (i
< 0 && p
[0] == 'X')
3485 p
[0] = first_char
[i
];
3486 if ((fd
= sys_open (template,
3487 flags
| _O_CREAT
| _O_EXCL
| _O_RDWR
,
3488 S_IRUSR
| S_IWUSR
)) >= 0
3496 while (++i
< sizeof (first_char
));
3499 /* Template is badly formed or else we can't generate a unique name. */
3504 fchmod (int fd
, mode_t mode
)
3510 sys_rename_replace (const char *oldname
, const char *newname
, BOOL force
)
3513 char temp
[MAX_PATH
];
3517 /* MoveFile on Windows 95 doesn't correctly change the short file name
3518 alias in a number of circumstances (it is not easy to predict when
3519 just by looking at oldname and newname, unfortunately). In these
3520 cases, renaming through a temporary name avoids the problem.
3522 A second problem on Windows 95 is that renaming through a temp name when
3523 newname is uppercase fails (the final long name ends up in
3524 lowercase, although the short alias might be uppercase) UNLESS the
3525 long temp name is not 8.3.
3527 So, on Windows 95 we always rename through a temp name, and we make sure
3528 the temp name has a long extension to ensure correct renaming. */
3530 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3532 /* volume_info is set indirectly by map_w32_filename. */
3533 oldname_dev
= volume_info
.serialnum
;
3535 if (os_subtype
== OS_9X
)
3541 oldname
= map_w32_filename (oldname
, NULL
);
3542 if ((o
= strrchr (oldname
, '\\')))
3545 o
= (char *) oldname
;
3547 if ((p
= strrchr (temp
, '\\')))
3554 /* Force temp name to require a manufactured 8.3 alias - this
3555 seems to make the second rename work properly. */
3556 sprintf (p
, "_.%s.%u", o
, i
);
3558 result
= rename (oldname
, temp
);
3560 /* This loop must surely terminate! */
3561 while (result
< 0 && errno
== EEXIST
);
3566 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3567 (at least if it is a file; don't do this for directories).
3569 Since we mustn't do this if we are just changing the case of the
3570 file name (we would end up deleting the file we are trying to
3571 rename!), we let rename detect if the destination file already
3572 exists - that way we avoid the possible pitfalls of trying to
3573 determine ourselves whether two names really refer to the same
3574 file, which is not always possible in the general case. (Consider
3575 all the permutations of shared or subst'd drives, etc.) */
3577 newname
= map_w32_filename (newname
, NULL
);
3579 /* volume_info is set indirectly by map_w32_filename. */
3580 newname_dev
= volume_info
.serialnum
;
3582 result
= rename (temp
, newname
);
3584 if (result
< 0 && force
)
3586 DWORD w32err
= GetLastError ();
3589 && newname_dev
!= oldname_dev
)
3591 /* The implementation of `rename' on Windows does not return
3592 errno = EXDEV when you are moving a directory to a
3593 different storage device (ex. logical disk). It returns
3594 EACCES instead. So here we handle such situations and
3598 if ((attributes
= GetFileAttributes (temp
)) != -1
3599 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3602 else if (errno
== EEXIST
)
3604 if (_chmod (newname
, 0666) != 0)
3606 if (_unlink (newname
) != 0)
3608 result
= rename (temp
, newname
);
3610 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
3611 && is_symlink (temp
))
3613 /* This is Windows prohibiting the user from creating a
3614 symlink in another place, since that requires
3624 sys_rename (char const *old
, char const *new)
3626 return sys_rename_replace (old
, new, TRUE
);
3630 sys_rmdir (const char * path
)
3632 return _rmdir (map_w32_filename (path
, NULL
));
3636 sys_unlink (const char * path
)
3638 path
= map_w32_filename (path
, NULL
);
3640 /* On Unix, unlink works without write permission. */
3641 _chmod (path
, 0666);
3642 return _unlink (path
);
3645 static FILETIME utc_base_ft
;
3646 static ULONGLONG utc_base
; /* In 100ns units */
3647 static int init
= 0;
3649 #define FILETIME_TO_U64(result, ft) \
3651 ULARGE_INTEGER uiTemp; \
3652 uiTemp.LowPart = (ft).dwLowDateTime; \
3653 uiTemp.HighPart = (ft).dwHighDateTime; \
3654 result = uiTemp.QuadPart; \
3658 initialize_utc_base (void)
3660 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3669 st
.wMilliseconds
= 0;
3671 SystemTimeToFileTime (&st
, &utc_base_ft
);
3672 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3676 convert_time (FILETIME ft
)
3682 initialize_utc_base ();
3686 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3689 FILETIME_TO_U64 (tmp
, ft
);
3690 return (time_t) ((tmp
- utc_base
) / 10000000L);
3694 convert_from_time_t (time_t time
, FILETIME
* pft
)
3700 initialize_utc_base ();
3704 /* time in 100ns units since 1-Jan-1601 */
3705 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3706 pft
->dwHighDateTime
= tmp
.HighPart
;
3707 pft
->dwLowDateTime
= tmp
.LowPart
;
3711 /* No reason to keep this; faking inode values either by hashing or even
3712 using the file index from GetInformationByHandle, is not perfect and
3713 so by default Emacs doesn't use the inode values on Windows.
3714 Instead, we now determine file-truename correctly (except for
3715 possible drive aliasing etc). */
3717 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3719 hashval (const unsigned char * str
)
3724 h
= (h
<< 4) + *str
++;
3730 /* Return the hash value of the canonical pathname, excluding the
3731 drive/UNC header, to get a hopefully unique inode number. */
3733 generate_inode_val (const char * name
)
3735 char fullname
[ MAX_PATH
];
3739 /* Get the truly canonical filename, if it exists. (Note: this
3740 doesn't resolve aliasing due to subst commands, or recognize hard
3742 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3745 parse_root (fullname
, &p
);
3746 /* Normal W32 filesystems are still case insensitive. */
3753 static PSECURITY_DESCRIPTOR
3754 get_file_security_desc_by_handle (HANDLE h
)
3756 PSECURITY_DESCRIPTOR psd
= NULL
;
3758 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3759 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3761 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
3762 NULL
, NULL
, NULL
, NULL
, &psd
);
3763 if (err
!= ERROR_SUCCESS
)
3769 static PSECURITY_DESCRIPTOR
3770 get_file_security_desc_by_name (const char *fname
)
3772 PSECURITY_DESCRIPTOR psd
= NULL
;
3774 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3775 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3777 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3779 err
= GetLastError ();
3780 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3784 psd
= xmalloc (sd_len
);
3785 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3797 unsigned n_subauthorities
;
3799 /* Use the last sub-authority value of the RID, the relative
3800 portion of the SID, as user/group ID. */
3801 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3802 if (n_subauthorities
< 1)
3803 return 0; /* the "World" RID */
3804 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3807 /* Caching SID and account values for faster lokup. */
3811 struct w32_id
*next
;
3813 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3816 static struct w32_id
*w32_idlist
;
3819 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3821 struct w32_id
*tail
, *found
;
3823 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3825 if (equal_sid ((PSID
)tail
->sid
, sid
))
3834 strcpy (name
, found
->name
);
3842 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3845 struct w32_id
*new_entry
;
3847 /* We don't want to leave behind stale cache from when Emacs was
3851 sid_len
= get_length_sid (sid
);
3852 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3855 new_entry
->rid
= id
;
3856 strcpy (new_entry
->name
, name
);
3857 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3858 new_entry
->next
= w32_idlist
;
3859 w32_idlist
= new_entry
;
3868 get_name_and_id (PSECURITY_DESCRIPTOR psd
, unsigned *id
, char *nm
, int what
)
3872 SID_NAME_USE ignore
;
3874 DWORD name_len
= sizeof (name
);
3876 DWORD domain_len
= sizeof (domain
);
3881 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3882 else if (what
== GID
)
3883 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3887 if (!result
|| !is_valid_sid (sid
))
3889 else if (!w32_cached_id (sid
, id
, nm
))
3891 if (!lookup_account_sid (NULL
, sid
, name
, &name_len
,
3892 domain
, &domain_len
, &ignore
)
3893 || name_len
> UNLEN
+1)
3897 *id
= get_rid (sid
);
3899 w32_add_to_cache (sid
, *id
, name
);
3906 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
, struct stat
*st
)
3908 int dflt_usr
= 0, dflt_grp
= 0;
3917 if (get_name_and_id (psd
, &st
->st_uid
, st
->st_uname
, UID
))
3919 if (get_name_and_id (psd
, &st
->st_gid
, st
->st_gname
, GID
))
3922 /* Consider files to belong to current user/group, if we cannot get
3923 more accurate information. */
3926 st
->st_uid
= dflt_passwd
.pw_uid
;
3927 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3931 st
->st_gid
= dflt_passwd
.pw_gid
;
3932 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3936 /* Return non-zero if NAME is a potentially slow filesystem. */
3938 is_slow_fs (const char *name
)
3943 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3944 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3945 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3946 devtype
= GetDriveType (NULL
); /* use root of current drive */
3949 /* GetDriveType needs the root directory of the drive. */
3950 strncpy (drive_root
, name
, 2);
3951 drive_root
[2] = '\\';
3952 drive_root
[3] = '\0';
3953 devtype
= GetDriveType (drive_root
);
3955 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3958 /* If this is non-zero, the caller wants accurate information about
3959 file's owner and group, which could be expensive to get. */
3960 int w32_stat_get_owner_group
;
3962 /* MSVC stat function can't cope with UNC names and has other bugs, so
3963 replace it with our own. This also allows us to calculate consistent
3964 inode values and owner/group without hacks in the main Emacs code. */
3967 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
3969 char *name
, *save_name
, *r
;
3970 WIN32_FIND_DATA wfd
;
3972 unsigned __int64 fake_inode
= 0;
3975 int rootdir
= FALSE
;
3976 PSECURITY_DESCRIPTOR psd
= NULL
;
3977 int is_a_symlink
= 0;
3978 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
3979 DWORD access_rights
= 0;
3980 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
3981 FILETIME ctime
, atime
, wtime
;
3984 if (path
== NULL
|| buf
== NULL
)
3990 save_name
= name
= (char *) map_w32_filename (path
, &path
);
3991 /* Must be valid filename, no wild cards or other invalid
3992 characters. We use _mbspbrk to support multibyte strings that
3993 might look to strpbrk as if they included literal *, ?, and other
3994 characters mentioned below that are disallowed by Windows
3996 if (_mbspbrk (name
, "*?|<>\""))
4002 /* Remove trailing directory separator, unless name is the root
4003 directory of a drive or UNC volume in which case ensure there
4004 is a trailing separator. */
4005 len
= strlen (name
);
4006 name
= strcpy (alloca (len
+ 2), name
);
4008 /* Avoid a somewhat costly call to is_symlink if the filesystem
4009 doesn't support symlinks. */
4010 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
4011 is_a_symlink
= is_symlink (name
);
4013 /* Plan A: Open the file and get all the necessary information via
4014 the resulting handle. This solves several issues in one blow:
4016 . retrieves attributes for the target of a symlink, if needed
4017 . gets attributes of root directories and symlinks pointing to
4018 root directories, thus avoiding the need for special-casing
4019 these and detecting them by examining the file-name format
4020 . retrieves more accurate attributes (e.g., non-zero size for
4021 some directories, esp. directories that are junction points)
4022 . correctly resolves "c:/..", "/.." and similar file names
4023 . avoids run-time penalties for 99% of use cases
4025 Plan A is always tried first, unless the user asked not to (but
4026 if the file is a symlink and we need to follow links, we try Plan
4027 A even if the user asked not to).
4029 If Plan A fails, we go to Plan B (below), where various
4030 potentially expensive techniques must be used to handle "special"
4031 files such as UNC volumes etc. */
4032 if (!(NILP (Vw32_get_true_file_attributes
)
4033 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
4034 /* Following symlinks requires getting the info by handle. */
4035 || (is_a_symlink
&& follow_symlinks
))
4037 BY_HANDLE_FILE_INFORMATION info
;
4039 if (is_a_symlink
&& !follow_symlinks
)
4040 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
4041 /* READ_CONTROL access rights are required to get security info
4042 by handle. But if the OS doesn't support security in the
4043 first place, we don't need to try. */
4044 if (is_windows_9x () != TRUE
)
4045 access_rights
|= READ_CONTROL
;
4047 fh
= CreateFile (name
, access_rights
, 0, NULL
, OPEN_EXISTING
,
4049 /* If CreateFile fails with READ_CONTROL, try again with zero as
4051 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
4052 fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
4054 if (fh
== INVALID_HANDLE_VALUE
)
4055 goto no_true_file_attributes
;
4057 /* This is more accurate in terms of getting the correct number
4058 of links, but is quite slow (it is noticeable when Emacs is
4059 making a list of file name completions). */
4060 if (GetFileInformationByHandle (fh
, &info
))
4062 nlinks
= info
.nNumberOfLinks
;
4063 /* Might as well use file index to fake inode values, but this
4064 is not guaranteed to be unique unless we keep a handle open
4065 all the time (even then there are situations where it is
4066 not unique). Reputedly, there are at most 48 bits of info
4067 (on NTFS, presumably less on FAT). */
4068 fake_inode
= info
.nFileIndexHigh
;
4070 fake_inode
+= info
.nFileIndexLow
;
4071 serialnum
= info
.dwVolumeSerialNumber
;
4072 fs_high
= info
.nFileSizeHigh
;
4073 fs_low
= info
.nFileSizeLow
;
4074 ctime
= info
.ftCreationTime
;
4075 atime
= info
.ftLastAccessTime
;
4076 wtime
= info
.ftLastWriteTime
;
4077 fattrs
= info
.dwFileAttributes
;
4081 /* We don't go to Plan B here, because it's not clear that
4082 it's a good idea. The only known use case where
4083 CreateFile succeeds, but GetFileInformationByHandle fails
4084 (with ERROR_INVALID_FUNCTION) is for character devices
4085 such as NUL, PRN, etc. For these, switching to Plan B is
4086 a net loss, because we lose the character device
4087 attribute returned by GetFileType below (FindFirstFile
4088 doesn't set that bit in the attributes), and the other
4089 fields don't make sense for character devices anyway.
4090 Emacs doesn't really care for non-file entities in the
4091 context of l?stat, so neither do we. */
4093 /* w32err is assigned so one could put a breakpoint here and
4094 examine its value, when GetFileInformationByHandle
4096 DWORD w32err
= GetLastError ();
4100 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
4106 /* Test for a symlink before testing for a directory, since
4107 symlinks to directories have the directory bit set, but we
4108 don't want them to appear as directories. */
4109 if (is_a_symlink
&& !follow_symlinks
)
4110 buf
->st_mode
= S_IFLNK
;
4111 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4112 buf
->st_mode
= S_IFDIR
;
4115 DWORD ftype
= GetFileType (fh
);
4119 case FILE_TYPE_DISK
:
4120 buf
->st_mode
= S_IFREG
;
4122 case FILE_TYPE_PIPE
:
4123 buf
->st_mode
= S_IFIFO
;
4125 case FILE_TYPE_CHAR
:
4126 case FILE_TYPE_UNKNOWN
:
4128 buf
->st_mode
= S_IFCHR
;
4131 /* We produce the fallback owner and group data, based on the
4132 current user that runs Emacs, in the following cases:
4134 . caller didn't request owner and group info
4135 . this is Windows 9X
4136 . getting security by handle failed, and we need to produce
4137 information for the target of a symlink (this is better
4138 than producing a potentially misleading info about the
4141 If getting security by handle fails, and we don't need to
4142 resolve symlinks, we try getting security by name. */
4143 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4144 get_file_owner_and_group (NULL
, buf
);
4147 psd
= get_file_security_desc_by_handle (fh
);
4150 get_file_owner_and_group (psd
, buf
);
4153 else if (!(is_a_symlink
&& follow_symlinks
))
4155 psd
= get_file_security_desc_by_name (name
);
4156 get_file_owner_and_group (psd
, buf
);
4160 get_file_owner_and_group (NULL
, buf
);
4166 no_true_file_attributes
:
4167 /* Plan B: Either getting a handle on the file failed, or the
4168 caller explicitly asked us to not bother making this
4169 information more accurate.
4171 Implementation note: In Plan B, we never bother to resolve
4172 symlinks, even if we got here because we tried Plan A and
4173 failed. That's because, even if the caller asked for extra
4174 precision by setting Vw32_get_true_file_attributes to t,
4175 resolving symlinks requires acquiring a file handle to the
4176 symlink, which we already know will fail. And if the user
4177 did not ask for extra precision, resolving symlinks will fly
4178 in the face of that request, since the user then wants the
4179 lightweight version of the code. */
4180 dbcs_p
= max_filename_mbslen () > 1;
4181 rootdir
= (path
>= save_name
+ len
- 1
4182 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
4184 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4185 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
4186 if (IS_DIRECTORY_SEP (r
[0])
4187 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
4190 /* Note: If NAME is a symlink to the root of a UNC volume
4191 (i.e. "\\SERVER"), we will not detect that here, and we will
4192 return data about the symlink as result of FindFirst below.
4193 This is unfortunate, but that marginal use case does not
4194 justify a call to chase_symlinks which would impose a penalty
4195 on all the other use cases. (We get here for symlinks to
4196 roots of UNC volumes because CreateFile above fails for them,
4197 unlike with symlinks to root directories X:\ of drives.) */
4198 if (is_unc_volume (name
))
4200 fattrs
= unc_volume_file_attributes (name
);
4204 ctime
= atime
= wtime
= utc_base_ft
;
4210 if (!IS_DIRECTORY_SEP (name
[len
-1]))
4211 strcat (name
, "\\");
4215 char *end
= name
+ len
;
4216 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4218 if (!IS_DIRECTORY_SEP (*n
))
4219 strcat (name
, "\\");
4221 if (GetDriveType (name
) < 2)
4227 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
4228 ctime
= atime
= wtime
= utc_base_ft
;
4234 if (IS_DIRECTORY_SEP (name
[len
-1]))
4239 char *end
= name
+ len
;
4240 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4242 if (IS_DIRECTORY_SEP (*n
))
4246 /* (This is hacky, but helps when doing file completions on
4247 network drives.) Optimize by using information available from
4248 active readdir if possible. */
4249 len
= strlen (dir_pathname
);
4252 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
4257 char *end
= dir_pathname
+ len
;
4258 char *n
= CharPrevExA (file_name_codepage
, dir_pathname
, end
, 0);
4260 if (IS_DIRECTORY_SEP (*n
))
4263 if (dir_find_handle
!= INVALID_HANDLE_VALUE
4264 && !(is_a_symlink
&& follow_symlinks
)
4265 && strnicmp (save_name
, dir_pathname
, len
) == 0
4266 && IS_DIRECTORY_SEP (name
[len
])
4267 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
4269 /* This was the last entry returned by readdir. */
4270 wfd
= dir_find_data
;
4274 logon_network_drive (name
);
4276 fh
= FindFirstFile (name
, &wfd
);
4277 if (fh
== INVALID_HANDLE_VALUE
)
4284 /* Note: if NAME is a symlink, the information we get from
4285 FindFirstFile is for the symlink, not its target. */
4286 fattrs
= wfd
.dwFileAttributes
;
4287 ctime
= wfd
.ftCreationTime
;
4288 atime
= wfd
.ftLastAccessTime
;
4289 wtime
= wfd
.ftLastWriteTime
;
4290 fs_high
= wfd
.nFileSizeHigh
;
4291 fs_low
= wfd
.nFileSizeLow
;
4294 serialnum
= volume_info
.serialnum
;
4296 if (is_a_symlink
&& !follow_symlinks
)
4297 buf
->st_mode
= S_IFLNK
;
4298 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4299 buf
->st_mode
= S_IFDIR
;
4301 buf
->st_mode
= S_IFREG
;
4303 get_file_owner_and_group (NULL
, buf
);
4307 /* Not sure if there is any point in this. */
4308 if (!NILP (Vw32_generate_fake_inodes
))
4309 fake_inode
= generate_inode_val (name
);
4310 else if (fake_inode
== 0)
4312 /* For want of something better, try to make everything unique. */
4313 static DWORD gen_num
= 0;
4314 fake_inode
= ++gen_num
;
4318 buf
->st_ino
= fake_inode
;
4320 buf
->st_dev
= serialnum
;
4321 buf
->st_rdev
= serialnum
;
4323 buf
->st_size
= fs_high
;
4324 buf
->st_size
<<= 32;
4325 buf
->st_size
+= fs_low
;
4326 buf
->st_nlink
= nlinks
;
4328 /* Convert timestamps to Unix format. */
4329 buf
->st_mtime
= convert_time (wtime
);
4330 buf
->st_atime
= convert_time (atime
);
4331 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4332 buf
->st_ctime
= convert_time (ctime
);
4333 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4335 /* determine rwx permissions */
4336 if (is_a_symlink
&& !follow_symlinks
)
4337 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
4340 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
4341 permission
= S_IREAD
;
4343 permission
= S_IREAD
| S_IWRITE
;
4345 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4346 permission
|= S_IEXEC
;
4347 else if (is_exec (name
))
4348 permission
|= S_IEXEC
;
4351 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4357 stat (const char * path
, struct stat
* buf
)
4359 return stat_worker (path
, buf
, 1);
4363 lstat (const char * path
, struct stat
* buf
)
4365 return stat_worker (path
, buf
, 0);
4369 fstatat (int fd
, char const *name
, struct stat
*st
, int flags
)
4371 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4372 This is good enough for the current usage in Emacs, but is fragile.
4374 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4375 Gnulib does this and can serve as a model. */
4376 char fullname
[MAX_PATH
];
4380 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
4383 errno
= ENAMETOOLONG
;
4389 return stat_worker (name
, st
, ! (flags
& AT_SYMLINK_NOFOLLOW
));
4392 /* Provide fstat and utime as well as stat for consistent handling of
4395 fstat (int desc
, struct stat
* buf
)
4397 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
4398 BY_HANDLE_FILE_INFORMATION info
;
4399 unsigned __int64 fake_inode
;
4402 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
4404 case FILE_TYPE_DISK
:
4405 buf
->st_mode
= S_IFREG
;
4406 if (!GetFileInformationByHandle (fh
, &info
))
4412 case FILE_TYPE_PIPE
:
4413 buf
->st_mode
= S_IFIFO
;
4415 case FILE_TYPE_CHAR
:
4416 case FILE_TYPE_UNKNOWN
:
4418 buf
->st_mode
= S_IFCHR
;
4420 memset (&info
, 0, sizeof (info
));
4421 info
.dwFileAttributes
= 0;
4422 info
.ftCreationTime
= utc_base_ft
;
4423 info
.ftLastAccessTime
= utc_base_ft
;
4424 info
.ftLastWriteTime
= utc_base_ft
;
4427 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4428 buf
->st_mode
= S_IFDIR
;
4430 buf
->st_nlink
= info
.nNumberOfLinks
;
4431 /* Might as well use file index to fake inode values, but this
4432 is not guaranteed to be unique unless we keep a handle open
4433 all the time (even then there are situations where it is
4434 not unique). Reputedly, there are at most 48 bits of info
4435 (on NTFS, presumably less on FAT). */
4436 fake_inode
= info
.nFileIndexHigh
;
4438 fake_inode
+= info
.nFileIndexLow
;
4440 /* MSVC defines _ino_t to be short; other libc's might not. */
4441 if (sizeof (buf
->st_ino
) == 2)
4442 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
4444 buf
->st_ino
= fake_inode
;
4446 /* If the caller so requested, get the true file owner and group.
4447 Otherwise, consider the file to belong to the current user. */
4448 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4449 get_file_owner_and_group (NULL
, buf
);
4452 PSECURITY_DESCRIPTOR psd
= NULL
;
4454 psd
= get_file_security_desc_by_handle (fh
);
4457 get_file_owner_and_group (psd
, buf
);
4461 get_file_owner_and_group (NULL
, buf
);
4464 buf
->st_dev
= info
.dwVolumeSerialNumber
;
4465 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
4467 buf
->st_size
= info
.nFileSizeHigh
;
4468 buf
->st_size
<<= 32;
4469 buf
->st_size
+= info
.nFileSizeLow
;
4471 /* Convert timestamps to Unix format. */
4472 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
4473 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
4474 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4475 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
4476 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4478 /* determine rwx permissions */
4479 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
4480 permission
= S_IREAD
;
4482 permission
= S_IREAD
| S_IWRITE
;
4484 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4485 permission
|= S_IEXEC
;
4488 #if 0 /* no way of knowing the filename */
4489 char * p
= strrchr (name
, '.');
4491 (xstrcasecmp (p
, ".exe") == 0 ||
4492 xstrcasecmp (p
, ".com") == 0 ||
4493 xstrcasecmp (p
, ".bat") == 0 ||
4494 xstrcasecmp (p
, ".cmd") == 0))
4495 permission
|= S_IEXEC
;
4499 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4505 utime (const char *name
, struct utimbuf
*times
)
4507 struct utimbuf deftime
;
4514 deftime
.modtime
= deftime
.actime
= time (NULL
);
4518 /* Need write access to set times. */
4519 fh
= CreateFile (name
, FILE_WRITE_ATTRIBUTES
,
4520 /* If NAME specifies a directory, FILE_SHARE_DELETE
4521 allows other processes to delete files inside it,
4522 while we have the directory open. */
4523 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
4524 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
4525 if (fh
!= INVALID_HANDLE_VALUE
)
4527 convert_from_time_t (times
->actime
, &atime
);
4528 convert_from_time_t (times
->modtime
, &mtime
);
4529 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
4546 /* Symlink-related functions. */
4547 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4548 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4552 symlink (char const *filename
, char const *linkname
)
4554 char linkfn
[MAX_PATH
], *tgtfn
;
4556 int dir_access
, filename_ends_in_slash
;
4559 /* Diagnostics follows Posix as much as possible. */
4560 if (filename
== NULL
|| linkname
== NULL
)
4570 if (strlen (filename
) > MAX_PATH
|| strlen (linkname
) > MAX_PATH
)
4572 errno
= ENAMETOOLONG
;
4576 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
4577 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
4583 dbcs_p
= max_filename_mbslen () > 1;
4585 /* Note: since empty FILENAME was already rejected, we can safely
4586 refer to FILENAME[1]. */
4587 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
4589 /* Non-absolute FILENAME is understood as being relative to
4590 LINKNAME's directory. We need to prepend that directory to
4591 FILENAME to get correct results from faccessat below, since
4592 otherwise it will interpret FILENAME relative to the
4593 directory where the Emacs process runs. Note that
4594 make-symbolic-link always makes sure LINKNAME is a fully
4595 expanded file name. */
4597 char *p
= linkfn
+ strlen (linkfn
);
4601 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
4606 char *p1
= CharPrevExA (file_name_codepage
, linkfn
, p
, 0);
4608 while (p
> linkfn
&& !IS_ANY_SEP (*p1
))
4611 p1
= CharPrevExA (file_name_codepage
, linkfn
, p1
, 0);
4615 strncpy (tem
, linkfn
, p
- linkfn
);
4616 tem
[p
- linkfn
] = '\0';
4617 strcat (tem
, filename
);
4618 dir_access
= faccessat (AT_FDCWD
, tem
, D_OK
, AT_EACCESS
);
4621 dir_access
= faccessat (AT_FDCWD
, filename
, D_OK
, AT_EACCESS
);
4623 /* Since Windows distinguishes between symlinks to directories and
4624 to files, we provide a kludgy feature: if FILENAME doesn't
4625 exist, but ends in a slash, we create a symlink to directory. If
4626 FILENAME exists and is a directory, we always create a symlink to
4629 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
4632 const char *end
= filename
+ strlen (filename
);
4633 const char *n
= CharPrevExA (file_name_codepage
, filename
, end
, 0);
4635 filename_ends_in_slash
= IS_DIRECTORY_SEP (*n
);
4637 if (dir_access
== 0 || filename_ends_in_slash
)
4638 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
4640 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
4641 if (filename_ends_in_slash
)
4642 tgtfn
[strlen (tgtfn
) - 1] = '\0';
4645 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
4647 /* ENOSYS is set by create_symbolic_link, when it detects that
4648 the OS doesn't support the CreateSymbolicLink API. */
4649 if (errno
!= ENOSYS
)
4651 DWORD w32err
= GetLastError ();
4655 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4656 TGTFN point to the same file name, go figure. */
4658 case ERROR_FILE_EXISTS
:
4661 case ERROR_ACCESS_DENIED
:
4664 case ERROR_FILE_NOT_FOUND
:
4665 case ERROR_PATH_NOT_FOUND
:
4666 case ERROR_BAD_NETPATH
:
4667 case ERROR_INVALID_REPARSE_DATA
:
4670 case ERROR_DIRECTORY
:
4673 case ERROR_PRIVILEGE_NOT_HELD
:
4674 case ERROR_NOT_ALL_ASSIGNED
:
4677 case ERROR_DISK_FULL
:
4690 /* A quick inexpensive test of whether FILENAME identifies a file that
4691 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4692 must already be in the normalized form returned by
4695 Note: for repeated operations on many files, it is best to test
4696 whether the underlying volume actually supports symlinks, by
4697 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4698 avoid the call to this function if it doesn't. That's because the
4699 call to GetFileAttributes takes a non-negligible time, especially
4700 on non-local or removable filesystems. See stat_worker for an
4701 example of how to do that. */
4703 is_symlink (const char *filename
)
4706 WIN32_FIND_DATA wfd
;
4709 attrs
= GetFileAttributes (filename
);
4712 DWORD w32err
= GetLastError ();
4716 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
4718 case ERROR_ACCESS_DENIED
:
4721 case ERROR_FILE_NOT_FOUND
:
4722 case ERROR_PATH_NOT_FOUND
:
4729 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
4731 logon_network_drive (filename
);
4732 fh
= FindFirstFile (filename
, &wfd
);
4733 if (fh
== INVALID_HANDLE_VALUE
)
4736 return (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
4737 && (wfd
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
4740 /* If NAME identifies a symbolic link, copy into BUF the file name of
4741 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4742 null-terminate the target name, even if it fits. Return the number
4743 of bytes copied, or -1 if NAME is not a symlink or any error was
4744 encountered while resolving it. The file name copied into BUF is
4745 encoded in the current ANSI codepage. */
4747 readlink (const char *name
, char *buf
, size_t buf_size
)
4750 TOKEN_PRIVILEGES privs
;
4751 int restore_privs
= 0;
4766 path
= map_w32_filename (name
, NULL
);
4768 if (strlen (path
) > MAX_PATH
)
4770 errno
= ENAMETOOLONG
;
4775 if (is_windows_9x () == TRUE
4776 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
4777 || !is_symlink (path
))
4780 errno
= EINVAL
; /* not a symlink */
4784 /* Done with simple tests, now we're in for some _real_ work. */
4785 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
4787 /* Implementation note: From here and onward, don't return early,
4788 since that will fail to restore the original set of privileges of
4789 the calling thread. */
4791 retval
= -1; /* not too optimistic, are we? */
4793 /* Note: In the next call to CreateFile, we use zero as the 2nd
4794 argument because, when the symlink is a hidden/system file,
4795 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4796 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4797 and directory symlinks. */
4798 sh
= CreateFile (path
, 0, 0, NULL
, OPEN_EXISTING
,
4799 FILE_FLAG_OPEN_REPARSE_POINT
| FILE_FLAG_BACKUP_SEMANTICS
,
4801 if (sh
!= INVALID_HANDLE_VALUE
)
4803 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
4804 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
4807 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
4808 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
4811 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
4815 /* Copy the link target name, in wide characters, from
4816 reparse_data, then convert it to multibyte encoding in
4817 the current locale's codepage. */
4819 BYTE lname
[MAX_PATH
];
4822 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
4824 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
4825 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
4826 /* This updates file_name_codepage which we need below. */
4827 int dbcs_p
= max_filename_mbslen () > 1;
4829 /* According to MSDN, PrintNameLength does not include the
4830 terminating null character. */
4831 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
4832 memcpy (lwname
, lwname_src
, lwname_len
);
4833 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
4835 lname_len
= WideCharToMultiByte (file_name_codepage
, 0, lwname
, -1,
4836 lname
, MAX_PATH
, NULL
, NULL
);
4839 /* WideCharToMultiByte failed. */
4840 DWORD w32err1
= GetLastError ();
4844 case ERROR_INSUFFICIENT_BUFFER
:
4845 errno
= ENAMETOOLONG
;
4847 case ERROR_INVALID_PARAMETER
:
4850 case ERROR_NO_UNICODE_TRANSLATION
:
4860 size_t size_to_copy
= buf_size
;
4861 BYTE
*p
= lname
, *p2
;
4862 BYTE
*pend
= p
+ lname_len
;
4864 /* Normalize like dostounix_filename does, but we don't
4865 want to assume that lname is null-terminated. */
4867 p2
= CharNextExA (file_name_codepage
, p
, 0);
4870 if (*p
&& *p2
== ':' && *p
>= 'A' && *p
<= 'Z')
4881 p
= CharNextExA (file_name_codepage
, p
, 0);
4882 /* CharNextExA doesn't advance at null character. */
4889 /* Testing for null-terminated LNAME is paranoia:
4890 WideCharToMultiByte should always return a
4891 null-terminated string when its 4th argument is -1
4892 and its 3rd argument is null-terminated (which they
4894 if (lname
[lname_len
- 1] == '\0')
4896 if (lname_len
<= buf_size
)
4897 size_to_copy
= lname_len
;
4898 strncpy (buf
, lname
, size_to_copy
);
4900 retval
= size_to_copy
;
4907 /* CreateFile failed. */
4908 DWORD w32err2
= GetLastError ();
4912 case ERROR_FILE_NOT_FOUND
:
4913 case ERROR_PATH_NOT_FOUND
:
4916 case ERROR_ACCESS_DENIED
:
4917 case ERROR_TOO_MANY_OPEN_FILES
:
4927 restore_privilege (&privs
);
4935 readlinkat (int fd
, char const *name
, char *buffer
,
4938 /* Rely on a hack: an open directory is modeled as file descriptor 0,
4939 as in fstatat. FIXME: Add proper support for readlinkat. */
4940 char fullname
[MAX_PATH
];
4944 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
4947 errno
= ENAMETOOLONG
;
4953 return readlink (name
, buffer
, buffer_size
);
4956 /* If FILE is a symlink, return its target (stored in a static
4957 buffer); otherwise return FILE.
4959 This function repeatedly resolves symlinks in the last component of
4960 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4961 until it arrives at a file whose last component is not a symlink,
4962 or some error occurs. It returns the target of the last
4963 successfully resolved symlink in the chain. If it succeeds to
4964 resolve even a single symlink, the value returned is an absolute
4965 file name with backslashes (result of GetFullPathName). By
4966 contrast, if the original FILE is returned, it is unaltered.
4968 Note: This function can set errno even if it succeeds.
4970 Implementation note: we only resolve the last portion ("basename")
4971 of the argument FILE and of each following file in the chain,
4972 disregarding any possible symlinks in its leading directories.
4973 This is because Windows system calls and library functions
4974 transparently resolve symlinks in leading directories and return
4975 correct information, as long as the basename is not a symlink. */
4977 chase_symlinks (const char *file
)
4979 static char target
[MAX_PATH
];
4980 char link
[MAX_PATH
];
4981 ssize_t res
, link_len
;
4985 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
4986 return (char *)file
;
4988 if ((link_len
= GetFullPathName (file
, MAX_PATH
, link
, NULL
)) == 0)
4989 return (char *)file
;
4991 dbcs_p
= max_filename_mbslen () > 1;
4995 /* Remove trailing slashes, as we want to resolve the last
4996 non-trivial part of the link name. */
4999 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
5000 link
[link_len
--] = '\0';
5002 else if (link_len
> 3)
5004 char *n
= CharPrevExA (file_name_codepage
, link
, link
+ link_len
, 0);
5006 while (n
>= link
+ 2 && IS_DIRECTORY_SEP (*n
))
5009 n
= CharPrevExA (file_name_codepage
, link
, n
, 0);
5013 res
= readlink (link
, target
, MAX_PATH
);
5017 if (!(IS_DEVICE_SEP (target
[1])
5018 || (IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1]))))
5020 /* Target is relative. Append it to the directory part of
5021 the symlink, then copy the result back to target. */
5022 char *p
= link
+ link_len
;
5026 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
5031 char *p1
= CharPrevExA (file_name_codepage
, link
, p
, 0);
5033 while (p
> link
&& !IS_ANY_SEP (*p1
))
5036 p1
= CharPrevExA (file_name_codepage
, link
, p1
, 0);
5040 strcpy (target
, link
);
5042 /* Resolve any "." and ".." to get a fully-qualified file name
5044 link_len
= GetFullPathName (target
, MAX_PATH
, link
, NULL
);
5046 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
5048 if (loop_count
> 100)
5051 if (target
[0] == '\0') /* not a single call to readlink succeeded */
5052 return (char *)file
;
5057 /* Posix ACL emulation. */
5060 acl_valid (acl_t acl
)
5062 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR
)acl
) ? 0 : -1;
5066 acl_to_text (acl_t acl
, ssize_t
*size
)
5069 SECURITY_INFORMATION flags
=
5070 OWNER_SECURITY_INFORMATION
|
5071 GROUP_SECURITY_INFORMATION
|
5072 DACL_SECURITY_INFORMATION
;
5073 char *retval
= NULL
;
5079 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR
)acl
, SDDL_REVISION_1
, flags
, &str_acl
, &local_size
))
5082 /* We don't want to mix heaps, so we duplicate the string in our
5083 heap and free the one allocated by the API. */
5084 retval
= xstrdup (str_acl
);
5087 LocalFree (str_acl
);
5089 else if (errno
!= ENOTSUP
)
5096 acl_from_text (const char *acl_str
)
5098 PSECURITY_DESCRIPTOR psd
, retval
= NULL
;
5104 if (convert_sddl_to_sd (acl_str
, SDDL_REVISION_1
, &psd
, &sd_size
))
5107 retval
= xmalloc (sd_size
);
5108 memcpy (retval
, psd
, sd_size
);
5111 else if (errno
!= ENOTSUP
)
5118 acl_free (void *ptr
)
5125 acl_get_file (const char *fname
, acl_type_t type
)
5127 PSECURITY_DESCRIPTOR psd
= NULL
;
5128 const char *filename
;
5130 if (type
== ACL_TYPE_ACCESS
)
5133 SECURITY_INFORMATION si
=
5134 OWNER_SECURITY_INFORMATION
|
5135 GROUP_SECURITY_INFORMATION
|
5136 DACL_SECURITY_INFORMATION
;
5139 filename
= map_w32_filename (fname
, NULL
);
5140 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5141 fname
= chase_symlinks (filename
);
5146 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
)
5147 && errno
!= ENOTSUP
)
5149 err
= GetLastError ();
5150 if (err
== ERROR_INSUFFICIENT_BUFFER
)
5152 psd
= xmalloc (sd_len
);
5153 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
5160 else if (err
== ERROR_FILE_NOT_FOUND
5161 || err
== ERROR_PATH_NOT_FOUND
)
5169 else if (type
!= ACL_TYPE_DEFAULT
)
5176 acl_set_file (const char *fname
, acl_type_t type
, acl_t acl
)
5178 TOKEN_PRIVILEGES old1
, old2
;
5180 int st
= 0, retval
= -1;
5181 SECURITY_INFORMATION flags
= 0;
5187 const char *filename
;
5189 if (acl_valid (acl
) != 0
5190 || (type
!= ACL_TYPE_DEFAULT
&& type
!= ACL_TYPE_ACCESS
))
5196 if (type
== ACL_TYPE_DEFAULT
)
5202 filename
= map_w32_filename (fname
, NULL
);
5203 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5204 fname
= chase_symlinks (filename
);
5208 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5210 flags
|= OWNER_SECURITY_INFORMATION
;
5211 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5213 flags
|= GROUP_SECURITY_INFORMATION
;
5214 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR
)acl
, &dacl_present
,
5217 flags
|= DACL_SECURITY_INFORMATION
;
5221 /* According to KB-245153, setting the owner will succeed if either:
5222 (1) the caller is the user who will be the new owner, and has the
5223 SE_TAKE_OWNERSHIP privilege, or
5224 (2) the caller has the SE_RESTORE privilege, in which case she can
5225 set any valid user or group as the owner
5227 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5228 privileges, and disregard any failures in obtaining them. If
5229 these privileges cannot be obtained, and do not already exist in
5230 the calling thread's security token, this function could fail
5232 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME
, TRUE
, &old1
))
5234 if (enable_privilege (SE_RESTORE_NAME
, TRUE
, &old2
))
5239 if (!set_file_security ((char *)fname
, flags
, (PSECURITY_DESCRIPTOR
)acl
))
5241 err
= GetLastError ();
5243 if (errno
== ENOTSUP
)
5245 else if (err
== ERROR_INVALID_OWNER
5246 || err
== ERROR_NOT_ALL_ASSIGNED
5247 || err
== ERROR_ACCESS_DENIED
)
5249 /* Maybe the requested ACL and the one the file already has
5250 are identical, in which case we can silently ignore the
5251 failure. (And no, Windows doesn't.) */
5252 acl_t current_acl
= acl_get_file (fname
, ACL_TYPE_ACCESS
);
5257 char *acl_from
= acl_to_text (current_acl
, NULL
);
5258 char *acl_to
= acl_to_text (acl
, NULL
);
5260 if (acl_from
&& acl_to
&& xstrcasecmp (acl_from
, acl_to
) == 0)
5266 acl_free (acl_from
);
5269 acl_free (current_acl
);
5272 else if (err
== ERROR_FILE_NOT_FOUND
|| err
== ERROR_PATH_NOT_FOUND
)
5286 restore_privilege (&old2
);
5287 restore_privilege (&old1
);
5295 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5296 have a fixed max size for file names, so we don't need the kind of
5297 alloc/malloc/realloc dance the gnulib version does. We also don't
5298 support FD-relative symlinks. */
5300 careadlinkat (int fd
, char const *filename
,
5301 char *buffer
, size_t buffer_size
,
5302 struct allocator
const *alloc
,
5303 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
5305 char linkname
[MAX_PATH
];
5308 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
5312 char *retval
= buffer
;
5314 linkname
[link_size
++] = '\0';
5315 if (link_size
> buffer_size
)
5316 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
5318 memcpy (retval
, linkname
, link_size
);
5326 /* Support for browsing other processes and their attributes. See
5327 process.c for the Lisp bindings. */
5329 /* Helper wrapper functions. */
5331 static HANDLE WINAPI
5332 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
5334 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
5336 if (g_b_init_create_toolhelp32_snapshot
== 0)
5338 g_b_init_create_toolhelp32_snapshot
= 1;
5339 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
5340 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5341 "CreateToolhelp32Snapshot");
5343 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
5345 return INVALID_HANDLE_VALUE
;
5347 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
5351 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5353 static Process32First_Proc s_pfn_Process32_First
= NULL
;
5355 if (g_b_init_process32_first
== 0)
5357 g_b_init_process32_first
= 1;
5358 s_pfn_Process32_First
= (Process32First_Proc
)
5359 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5362 if (s_pfn_Process32_First
== NULL
)
5366 return (s_pfn_Process32_First (hSnapshot
, lppe
));
5370 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5372 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
5374 if (g_b_init_process32_next
== 0)
5376 g_b_init_process32_next
= 1;
5377 s_pfn_Process32_Next
= (Process32Next_Proc
)
5378 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5381 if (s_pfn_Process32_Next
== NULL
)
5385 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
5389 open_thread_token (HANDLE ThreadHandle
,
5390 DWORD DesiredAccess
,
5392 PHANDLE TokenHandle
)
5394 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
5395 HMODULE hm_advapi32
= NULL
;
5396 if (is_windows_9x () == TRUE
)
5398 SetLastError (ERROR_NOT_SUPPORTED
);
5401 if (g_b_init_open_thread_token
== 0)
5403 g_b_init_open_thread_token
= 1;
5404 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5405 s_pfn_Open_Thread_Token
=
5406 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
5408 if (s_pfn_Open_Thread_Token
== NULL
)
5410 SetLastError (ERROR_NOT_SUPPORTED
);
5414 s_pfn_Open_Thread_Token (
5423 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
5425 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
5426 HMODULE hm_advapi32
= NULL
;
5427 if (is_windows_9x () == TRUE
)
5431 if (g_b_init_impersonate_self
== 0)
5433 g_b_init_impersonate_self
= 1;
5434 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5435 s_pfn_Impersonate_Self
=
5436 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
5438 if (s_pfn_Impersonate_Self
== NULL
)
5442 return s_pfn_Impersonate_Self (ImpersonationLevel
);
5446 revert_to_self (void)
5448 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
5449 HMODULE hm_advapi32
= NULL
;
5450 if (is_windows_9x () == TRUE
)
5454 if (g_b_init_revert_to_self
== 0)
5456 g_b_init_revert_to_self
= 1;
5457 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5458 s_pfn_Revert_To_Self
=
5459 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
5461 if (s_pfn_Revert_To_Self
== NULL
)
5465 return s_pfn_Revert_To_Self ();
5469 get_process_memory_info (HANDLE h_proc
,
5470 PPROCESS_MEMORY_COUNTERS mem_counters
,
5473 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
5474 HMODULE hm_psapi
= NULL
;
5475 if (is_windows_9x () == TRUE
)
5479 if (g_b_init_get_process_memory_info
== 0)
5481 g_b_init_get_process_memory_info
= 1;
5482 hm_psapi
= LoadLibrary ("Psapi.dll");
5484 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
5485 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
5487 if (s_pfn_Get_Process_Memory_Info
== NULL
)
5491 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
5495 get_process_working_set_size (HANDLE h_proc
,
5499 static GetProcessWorkingSetSize_Proc
5500 s_pfn_Get_Process_Working_Set_Size
= NULL
;
5502 if (is_windows_9x () == TRUE
)
5506 if (g_b_init_get_process_working_set_size
== 0)
5508 g_b_init_get_process_working_set_size
= 1;
5509 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
5510 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5511 "GetProcessWorkingSetSize");
5513 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
5517 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
5521 global_memory_status (MEMORYSTATUS
*buf
)
5523 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
5525 if (is_windows_9x () == TRUE
)
5529 if (g_b_init_global_memory_status
== 0)
5531 g_b_init_global_memory_status
= 1;
5532 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
5533 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5534 "GlobalMemoryStatus");
5536 if (s_pfn_Global_Memory_Status
== NULL
)
5540 return s_pfn_Global_Memory_Status (buf
);
5544 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
5546 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
5548 if (is_windows_9x () == TRUE
)
5552 if (g_b_init_global_memory_status_ex
== 0)
5554 g_b_init_global_memory_status_ex
= 1;
5555 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
5556 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5557 "GlobalMemoryStatusEx");
5559 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
5563 return s_pfn_Global_Memory_Status_Ex (buf
);
5567 list_system_processes (void)
5569 struct gcpro gcpro1
;
5570 Lisp_Object proclist
= Qnil
;
5573 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
5575 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
5577 PROCESSENTRY32 proc_entry
;
5583 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
5584 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
5585 res
= process32_next (h_snapshot
, &proc_entry
))
5587 proc_id
= proc_entry
.th32ProcessID
;
5588 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
5591 CloseHandle (h_snapshot
);
5593 proclist
= Fnreverse (proclist
);
5600 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
5602 TOKEN_PRIVILEGES priv
;
5603 DWORD priv_size
= sizeof (priv
);
5604 DWORD opriv_size
= sizeof (*old_priv
);
5605 HANDLE h_token
= NULL
;
5606 HANDLE h_thread
= GetCurrentThread ();
5610 res
= open_thread_token (h_thread
,
5611 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5613 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
5615 if (impersonate_self (SecurityImpersonation
))
5616 res
= open_thread_token (h_thread
,
5617 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5622 priv
.PrivilegeCount
= 1;
5623 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
5624 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
5625 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
5626 old_priv
, &opriv_size
)
5627 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
5631 CloseHandle (h_token
);
5637 restore_privilege (TOKEN_PRIVILEGES
*priv
)
5639 DWORD priv_size
= sizeof (*priv
);
5640 HANDLE h_token
= NULL
;
5643 if (open_thread_token (GetCurrentThread (),
5644 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5647 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
5648 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
5652 CloseHandle (h_token
);
5658 ltime (ULONGLONG time_100ns
)
5660 ULONGLONG time_sec
= time_100ns
/ 10000000;
5661 int subsec
= time_100ns
% 10000000;
5662 return list4i (time_sec
>> 16, time_sec
& 0xffff,
5663 subsec
/ 10, subsec
% 10 * 100000);
5666 #define U64_TO_LISP_TIME(time) ltime (time)
5669 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
5670 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
5673 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
5674 ULONGLONG tem1
, tem2
, tem3
, tem
;
5677 || !get_process_times_fn
5678 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
5679 &ft_kernel
, &ft_user
))
5682 GetSystemTimeAsFileTime (&ft_current
);
5684 FILETIME_TO_U64 (tem1
, ft_kernel
);
5685 *stime
= U64_TO_LISP_TIME (tem1
);
5687 FILETIME_TO_U64 (tem2
, ft_user
);
5688 *utime
= U64_TO_LISP_TIME (tem2
);
5691 *ttime
= U64_TO_LISP_TIME (tem3
);
5693 FILETIME_TO_U64 (tem
, ft_creation
);
5694 /* Process no 4 (System) returns zero creation time. */
5697 *ctime
= U64_TO_LISP_TIME (tem
);
5701 FILETIME_TO_U64 (tem3
, ft_current
);
5702 tem
= (tem3
- utc_base
) - tem
;
5704 *etime
= U64_TO_LISP_TIME (tem
);
5708 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
5719 system_process_attributes (Lisp_Object pid
)
5721 struct gcpro gcpro1
, gcpro2
, gcpro3
;
5722 Lisp_Object attrs
= Qnil
;
5723 Lisp_Object cmd_str
, decoded_cmd
, tem
;
5724 HANDLE h_snapshot
, h_proc
;
5727 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
5728 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
5729 DWORD glength
= sizeof (gname
);
5730 HANDLE token
= NULL
;
5731 SID_NAME_USE user_type
;
5732 unsigned char *buf
= NULL
;
5734 TOKEN_USER user_token
;
5735 TOKEN_PRIMARY_GROUP group_token
;
5738 PROCESS_MEMORY_COUNTERS mem
;
5739 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
5740 SIZE_T minrss
, maxrss
;
5742 MEMORY_STATUS_EX memstex
;
5743 double totphys
= 0.0;
5744 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
5746 BOOL result
= FALSE
;
5748 CHECK_NUMBER_OR_FLOAT (pid
);
5749 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
5751 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
5753 GCPRO3 (attrs
, decoded_cmd
, tem
);
5755 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
5760 pe
.dwSize
= sizeof (PROCESSENTRY32
);
5761 for (res
= process32_first (h_snapshot
, &pe
); res
;
5762 res
= process32_next (h_snapshot
, &pe
))
5764 if (proc_id
== pe
.th32ProcessID
)
5767 decoded_cmd
= build_string ("Idle");
5770 /* Decode the command name from locale-specific
5772 cmd_str
= build_unibyte_string (pe
.szExeFile
);
5775 code_convert_string_norecord (cmd_str
,
5776 Vlocale_coding_system
, 0);
5778 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
5779 attrs
= Fcons (Fcons (Qppid
,
5780 make_fixnum_or_float (pe
.th32ParentProcessID
)),
5782 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
5784 attrs
= Fcons (Fcons (Qthcount
,
5785 make_fixnum_or_float (pe
.cntThreads
)),
5792 CloseHandle (h_snapshot
);
5801 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
5803 /* If we were denied a handle to the process, try again after
5804 enabling the SeDebugPrivilege in our process. */
5807 TOKEN_PRIVILEGES priv_current
;
5809 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
5811 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
5813 restore_privilege (&priv_current
);
5819 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
5822 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
5823 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5825 buf
= xmalloc (blen
);
5826 result
= get_token_information (token
, TokenUser
,
5827 (LPVOID
)buf
, blen
, &needed
);
5830 memcpy (&user_token
, buf
, sizeof (user_token
));
5831 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
5833 euid
= get_rid (user_token
.User
.Sid
);
5834 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
5839 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
5842 strcpy (uname
, "unknown");
5846 ulength
= strlen (uname
);
5852 /* Determine a reasonable euid and gid values. */
5853 if (xstrcasecmp ("administrator", uname
) == 0)
5855 euid
= 500; /* well-known Administrator uid */
5856 egid
= 513; /* well-known None gid */
5860 /* Get group id and name. */
5861 result
= get_token_information (token
, TokenPrimaryGroup
,
5862 (LPVOID
)buf
, blen
, &needed
);
5863 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5865 buf
= xrealloc (buf
, blen
= needed
);
5866 result
= get_token_information (token
, TokenPrimaryGroup
,
5867 (LPVOID
)buf
, blen
, &needed
);
5871 memcpy (&group_token
, buf
, sizeof (group_token
));
5872 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
5874 egid
= get_rid (group_token
.PrimaryGroup
);
5875 dlength
= sizeof (domain
);
5877 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
5878 gname
, &glength
, NULL
, &dlength
,
5881 w32_add_to_cache (group_token
.PrimaryGroup
,
5885 strcpy (gname
, "None");
5889 glength
= strlen (gname
);
5897 if (!is_windows_9x ())
5899 /* We couldn't open the process token, presumably because of
5900 insufficient access rights. Assume this process is run
5902 strcpy (uname
, "SYSTEM");
5903 strcpy (gname
, "None");
5904 euid
= 18; /* SYSTEM */
5905 egid
= 513; /* None */
5906 glength
= strlen (gname
);
5907 ulength
= strlen (uname
);
5909 /* If we are running under Windows 9X, where security calls are
5910 not supported, we assume all processes are run by the current
5912 else if (GetUserName (uname
, &ulength
))
5914 if (xstrcasecmp ("administrator", uname
) == 0)
5919 strcpy (gname
, "None");
5920 glength
= strlen (gname
);
5921 ulength
= strlen (uname
);
5927 strcpy (uname
, "administrator");
5928 ulength
= strlen (uname
);
5929 strcpy (gname
, "None");
5930 glength
= strlen (gname
);
5933 CloseHandle (token
);
5936 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
5937 tem
= make_unibyte_string (uname
, ulength
);
5938 attrs
= Fcons (Fcons (Quser
,
5939 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5941 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
5942 tem
= make_unibyte_string (gname
, glength
);
5943 attrs
= Fcons (Fcons (Qgroup
,
5944 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5947 if (global_memory_status_ex (&memstex
))
5948 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5949 totphys
= memstex
.ullTotalPhys
/ 1024.0;
5951 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5952 double, so we need to do this for it... */
5954 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
5955 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
5956 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
5958 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
5960 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5961 else if (global_memory_status (&memst
))
5962 totphys
= memst
.dwTotalPhys
/ 1024.0;
5965 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
5968 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
5970 attrs
= Fcons (Fcons (Qmajflt
,
5971 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
5973 attrs
= Fcons (Fcons (Qvsize
,
5974 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
5976 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5978 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5981 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
5983 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
5985 attrs
= Fcons (Fcons (Qmajflt
,
5986 make_fixnum_or_float (mem
.PageFaultCount
)),
5988 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5990 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5993 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
5995 DWORD rss
= maxrss
/ 1024;
5997 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
5999 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
6002 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
6004 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
6005 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
6006 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
6007 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
6008 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
6009 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
6012 /* FIXME: Retrieve command line by walking the PEB of the process. */
6015 CloseHandle (h_proc
);
6021 /* Wrappers for winsock functions to map between our file descriptors
6022 and winsock's handles; also set h_errno for convenience.
6024 To allow Emacs to run on systems which don't have winsock support
6025 installed, we dynamically link to winsock on startup if present, and
6026 otherwise provide the minimum necessary functionality
6027 (eg. gethostname). */
6029 /* function pointers for relevant socket functions */
6030 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
6031 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
6032 int (PASCAL
*pfn_WSAGetLastError
) (void);
6033 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
6034 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
6035 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
6036 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
6037 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6038 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
6039 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
6040 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
6041 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
6042 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
6043 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
6044 int (PASCAL
*pfn_WSACleanup
) (void);
6046 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
6047 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
6048 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
6049 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
6050 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
6051 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
6052 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
6053 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
6054 const char * optval
, int optlen
);
6055 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
6056 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
6058 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
6059 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
6060 struct sockaddr
* from
, int * fromlen
);
6061 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
6062 const struct sockaddr
* to
, int tolen
);
6064 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6065 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
6066 #ifndef HANDLE_FLAG_INHERIT
6067 #define HANDLE_FLAG_INHERIT 1
6071 static int winsock_inuse
;
6076 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
6078 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6079 after WSAStartup returns successfully, but it seems reasonable
6080 to allow unloading winsock anyway in that case. */
6081 if (pfn_WSACleanup () == 0 ||
6082 pfn_WSAGetLastError () == WSAENETDOWN
)
6084 if (FreeLibrary (winsock_lib
))
6093 init_winsock (int load_now
)
6095 WSADATA winsockData
;
6097 if (winsock_lib
!= NULL
)
6100 pfn_SetHandleInformation
6101 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6102 "SetHandleInformation");
6104 winsock_lib
= LoadLibrary ("Ws2_32.dll");
6106 if (winsock_lib
!= NULL
)
6108 /* dynamically link to socket functions */
6110 #define LOAD_PROC(fn) \
6111 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6114 LOAD_PROC (WSAStartup
);
6115 LOAD_PROC (WSASetLastError
);
6116 LOAD_PROC (WSAGetLastError
);
6117 LOAD_PROC (WSAEventSelect
);
6118 LOAD_PROC (WSACreateEvent
);
6119 LOAD_PROC (WSACloseEvent
);
6122 LOAD_PROC (connect
);
6123 LOAD_PROC (ioctlsocket
);
6126 LOAD_PROC (closesocket
);
6127 LOAD_PROC (shutdown
);
6130 LOAD_PROC (inet_addr
);
6131 LOAD_PROC (gethostname
);
6132 LOAD_PROC (gethostbyname
);
6133 LOAD_PROC (getservbyname
);
6134 LOAD_PROC (getpeername
);
6135 LOAD_PROC (WSACleanup
);
6136 LOAD_PROC (setsockopt
);
6138 LOAD_PROC (getsockname
);
6140 LOAD_PROC (recvfrom
);
6144 /* specify version 1.1 of winsock */
6145 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
6147 if (winsockData
.wVersion
!= 0x101)
6152 /* Report that winsock exists and is usable, but leave
6153 socket functions disabled. I am assuming that calling
6154 WSAStartup does not require any network interaction,
6155 and in particular does not cause or require a dial-up
6156 connection to be established. */
6159 FreeLibrary (winsock_lib
);
6167 FreeLibrary (winsock_lib
);
6177 /* Function to map winsock error codes to errno codes for those errno
6178 code defined in errno.h (errno values not defined by errno.h are
6179 already in nt/inc/sys/socket.h). */
6186 if (winsock_lib
== NULL
)
6189 wsa_err
= pfn_WSAGetLastError ();
6193 case WSAEACCES
: errno
= EACCES
; break;
6194 case WSAEBADF
: errno
= EBADF
; break;
6195 case WSAEFAULT
: errno
= EFAULT
; break;
6196 case WSAEINTR
: errno
= EINTR
; break;
6197 case WSAEINVAL
: errno
= EINVAL
; break;
6198 case WSAEMFILE
: errno
= EMFILE
; break;
6199 case WSAENAMETOOLONG
: errno
= ENAMETOOLONG
; break;
6200 case WSAENOTEMPTY
: errno
= ENOTEMPTY
; break;
6201 default: errno
= wsa_err
; break;
6209 if (winsock_lib
!= NULL
)
6210 pfn_WSASetLastError (0);
6213 /* Extend strerror to handle the winsock-specific error codes. */
6217 } _wsa_errlist
[] = {
6218 {WSAEINTR
, "Interrupted function call"},
6219 {WSAEBADF
, "Bad file descriptor"},
6220 {WSAEACCES
, "Permission denied"},
6221 {WSAEFAULT
, "Bad address"},
6222 {WSAEINVAL
, "Invalid argument"},
6223 {WSAEMFILE
, "Too many open files"},
6225 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
6226 {WSAEINPROGRESS
, "Operation now in progress"},
6227 {WSAEALREADY
, "Operation already in progress"},
6228 {WSAENOTSOCK
, "Socket operation on non-socket"},
6229 {WSAEDESTADDRREQ
, "Destination address required"},
6230 {WSAEMSGSIZE
, "Message too long"},
6231 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
6232 {WSAENOPROTOOPT
, "Bad protocol option"},
6233 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
6234 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
6235 {WSAEOPNOTSUPP
, "Operation not supported"},
6236 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
6237 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
6238 {WSAEADDRINUSE
, "Address already in use"},
6239 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
6240 {WSAENETDOWN
, "Network is down"},
6241 {WSAENETUNREACH
, "Network is unreachable"},
6242 {WSAENETRESET
, "Network dropped connection on reset"},
6243 {WSAECONNABORTED
, "Software caused connection abort"},
6244 {WSAECONNRESET
, "Connection reset by peer"},
6245 {WSAENOBUFS
, "No buffer space available"},
6246 {WSAEISCONN
, "Socket is already connected"},
6247 {WSAENOTCONN
, "Socket is not connected"},
6248 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
6249 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
6250 {WSAETIMEDOUT
, "Connection timed out"},
6251 {WSAECONNREFUSED
, "Connection refused"},
6252 {WSAELOOP
, "Network loop"}, /* not sure */
6253 {WSAENAMETOOLONG
, "Name is too long"},
6254 {WSAEHOSTDOWN
, "Host is down"},
6255 {WSAEHOSTUNREACH
, "No route to host"},
6256 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
6257 {WSAEPROCLIM
, "Too many processes"},
6258 {WSAEUSERS
, "Too many users"}, /* not sure */
6259 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
6260 {WSAESTALE
, "Data is stale"}, /* not sure */
6261 {WSAEREMOTE
, "Remote error"}, /* not sure */
6263 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
6264 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
6265 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
6266 {WSAEDISCON
, "Graceful shutdown in progress"},
6268 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
6269 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
6270 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
6271 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
6272 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
6273 {WSASYSCALLFAILURE
, "System call failure"},
6274 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
6275 {WSATYPE_NOT_FOUND
, "Class type not found"},
6276 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
6277 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
6278 {WSAEREFUSED
, "Operation refused"}, /* not sure */
6281 {WSAHOST_NOT_FOUND
, "Host not found"},
6282 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
6283 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
6284 {WSANO_DATA
, "Valid name, no data record of requested type"},
6290 sys_strerror (int error_no
)
6293 static char unknown_msg
[40];
6295 if (error_no
>= 0 && error_no
< sys_nerr
)
6296 return sys_errlist
[error_no
];
6298 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
6299 if (_wsa_errlist
[i
].errnum
== error_no
)
6300 return _wsa_errlist
[i
].msg
;
6302 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
6306 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6307 but I believe the method of keeping the socket handle separate (and
6308 insuring it is not inheritable) is the correct one. */
6310 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6312 static int socket_to_fd (SOCKET s
);
6315 sys_socket (int af
, int type
, int protocol
)
6319 if (winsock_lib
== NULL
)
6322 return INVALID_SOCKET
;
6327 /* call the real socket function */
6328 s
= pfn_socket (af
, type
, protocol
);
6330 if (s
!= INVALID_SOCKET
)
6331 return socket_to_fd (s
);
6337 /* Convert a SOCKET to a file descriptor. */
6339 socket_to_fd (SOCKET s
)
6344 /* Although under NT 3.5 _open_osfhandle will accept a socket
6345 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6346 that does not work under NT 3.1. However, we can get the same
6347 effect by using a backdoor function to replace an existing
6348 descriptor handle with the one we want. */
6350 /* allocate a file descriptor (with appropriate flags) */
6351 fd
= _open ("NUL:", _O_RDWR
);
6354 /* Make a non-inheritable copy of the socket handle. Note
6355 that it is possible that sockets aren't actually kernel
6356 handles, which appears to be the case on Windows 9x when
6357 the MS Proxy winsock client is installed. */
6359 /* Apparently there is a bug in NT 3.51 with some service
6360 packs, which prevents using DuplicateHandle to make a
6361 socket handle non-inheritable (causes WSACleanup to
6362 hang). The work-around is to use SetHandleInformation
6363 instead if it is available and implemented. */
6364 if (pfn_SetHandleInformation
)
6366 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
6370 HANDLE parent
= GetCurrentProcess ();
6371 HANDLE new_s
= INVALID_HANDLE_VALUE
;
6373 if (DuplicateHandle (parent
,
6379 DUPLICATE_SAME_ACCESS
))
6381 /* It is possible that DuplicateHandle succeeds even
6382 though the socket wasn't really a kernel handle,
6383 because a real handle has the same value. So
6384 test whether the new handle really is a socket. */
6385 long nonblocking
= 0;
6386 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
6388 pfn_closesocket (s
);
6393 CloseHandle (new_s
);
6398 eassert (fd
< MAXDESC
);
6399 fd_info
[fd
].hnd
= (HANDLE
) s
;
6401 /* set our own internal flags */
6402 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
6408 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6410 /* attach child_process to fd_info */
6411 if (fd_info
[ fd
].cp
!= NULL
)
6413 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
6417 fd_info
[ fd
].cp
= cp
;
6420 winsock_inuse
++; /* count open sockets */
6428 pfn_closesocket (s
);
6434 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
6436 if (winsock_lib
== NULL
)
6439 return SOCKET_ERROR
;
6443 if (fd_info
[s
].flags
& FILE_SOCKET
)
6445 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
6446 if (rc
== SOCKET_ERROR
)
6451 return SOCKET_ERROR
;
6455 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
6457 if (winsock_lib
== NULL
)
6460 return SOCKET_ERROR
;
6464 if (fd_info
[s
].flags
& FILE_SOCKET
)
6466 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
6467 if (rc
== SOCKET_ERROR
)
6472 return SOCKET_ERROR
;
6476 sys_htons (u_short hostshort
)
6478 return (winsock_lib
!= NULL
) ?
6479 pfn_htons (hostshort
) : hostshort
;
6483 sys_ntohs (u_short netshort
)
6485 return (winsock_lib
!= NULL
) ?
6486 pfn_ntohs (netshort
) : netshort
;
6490 sys_inet_addr (const char * cp
)
6492 return (winsock_lib
!= NULL
) ?
6493 pfn_inet_addr (cp
) : INADDR_NONE
;
6497 sys_gethostname (char * name
, int namelen
)
6499 if (winsock_lib
!= NULL
)
6504 retval
= pfn_gethostname (name
, namelen
);
6505 if (retval
== SOCKET_ERROR
)
6510 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
6511 return !GetComputerName (name
, (DWORD
*)&namelen
);
6514 return SOCKET_ERROR
;
6518 sys_gethostbyname (const char * name
)
6520 struct hostent
* host
;
6521 int h_err
= h_errno
;
6523 if (winsock_lib
== NULL
)
6525 h_errno
= NO_RECOVERY
;
6531 host
= pfn_gethostbyname (name
);
6543 sys_getservbyname (const char * name
, const char * proto
)
6545 struct servent
* serv
;
6547 if (winsock_lib
== NULL
)
6554 serv
= pfn_getservbyname (name
, proto
);
6561 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
6563 if (winsock_lib
== NULL
)
6566 return SOCKET_ERROR
;
6570 if (fd_info
[s
].flags
& FILE_SOCKET
)
6572 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
6573 if (rc
== SOCKET_ERROR
)
6578 return SOCKET_ERROR
;
6582 sys_shutdown (int s
, int how
)
6584 if (winsock_lib
== NULL
)
6587 return SOCKET_ERROR
;
6591 if (fd_info
[s
].flags
& FILE_SOCKET
)
6593 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
6594 if (rc
== SOCKET_ERROR
)
6599 return SOCKET_ERROR
;
6603 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
6605 if (winsock_lib
== NULL
)
6608 return SOCKET_ERROR
;
6612 if (fd_info
[s
].flags
& FILE_SOCKET
)
6614 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
6615 (const char *)optval
, optlen
);
6616 if (rc
== SOCKET_ERROR
)
6621 return SOCKET_ERROR
;
6625 sys_listen (int s
, int backlog
)
6627 if (winsock_lib
== NULL
)
6630 return SOCKET_ERROR
;
6634 if (fd_info
[s
].flags
& FILE_SOCKET
)
6636 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
6637 if (rc
== SOCKET_ERROR
)
6640 fd_info
[s
].flags
|= FILE_LISTEN
;
6644 return SOCKET_ERROR
;
6648 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
6650 if (winsock_lib
== NULL
)
6653 return SOCKET_ERROR
;
6657 if (fd_info
[s
].flags
& FILE_SOCKET
)
6659 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
6660 if (rc
== SOCKET_ERROR
)
6665 return SOCKET_ERROR
;
6669 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
6671 if (winsock_lib
== NULL
)
6678 if (fd_info
[s
].flags
& FILE_LISTEN
)
6680 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
6682 if (t
== INVALID_SOCKET
)
6685 fd
= socket_to_fd (t
);
6689 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6690 ResetEvent (fd_info
[s
].cp
->char_avail
);
6699 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
6700 struct sockaddr
* from
, int * fromlen
)
6702 if (winsock_lib
== NULL
)
6705 return SOCKET_ERROR
;
6709 if (fd_info
[s
].flags
& FILE_SOCKET
)
6711 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
6712 if (rc
== SOCKET_ERROR
)
6717 return SOCKET_ERROR
;
6721 sys_sendto (int s
, const char * buf
, int len
, int flags
,
6722 const struct sockaddr
* to
, int tolen
)
6724 if (winsock_lib
== NULL
)
6727 return SOCKET_ERROR
;
6731 if (fd_info
[s
].flags
& FILE_SOCKET
)
6733 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
6734 if (rc
== SOCKET_ERROR
)
6739 return SOCKET_ERROR
;
6742 /* Windows does not have an fcntl function. Provide an implementation
6743 good enough for Emacs. */
6745 fcntl (int s
, int cmd
, int options
)
6747 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
6748 invoked in a context where fd1 is closed and all descriptors less
6749 than fd1 are open, so sys_dup is an adequate implementation. */
6750 if (cmd
== F_DUPFD_CLOEXEC
)
6753 if (winsock_lib
== NULL
)
6760 if (fd_info
[s
].flags
& FILE_SOCKET
)
6762 if (cmd
== F_SETFL
&& options
== O_NONBLOCK
)
6764 unsigned long nblock
= 1;
6765 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
6766 if (rc
== SOCKET_ERROR
)
6768 /* Keep track of the fact that we set this to non-blocking. */
6769 fd_info
[s
].flags
|= FILE_NDELAY
;
6775 return SOCKET_ERROR
;
6779 return SOCKET_ERROR
;
6783 /* Shadow main io functions: we need to handle pipes and sockets more
6784 intelligently, and implement non-blocking mode as well. */
6797 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
6799 child_process
* cp
= fd_info
[fd
].cp
;
6801 fd_info
[fd
].cp
= NULL
;
6803 if (CHILD_ACTIVE (cp
))
6805 /* if last descriptor to active child_process then cleanup */
6807 for (i
= 0; i
< MAXDESC
; i
++)
6811 if (fd_info
[i
].cp
== cp
)
6816 if (fd_info
[fd
].flags
& FILE_SOCKET
)
6818 if (winsock_lib
== NULL
) emacs_abort ();
6820 pfn_shutdown (SOCK_HANDLE (fd
), 2);
6821 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
6823 winsock_inuse
--; /* count open sockets */
6825 /* If the process handle is NULL, it's either a socket
6826 or serial connection, or a subprocess that was
6827 already reaped by reap_subprocess, but whose
6828 resources were not yet freed, because its output was
6829 not fully read yet by the time it was reaped. (This
6830 usually happens with async subprocesses whose output
6831 is being read by Emacs.) Otherwise, this process was
6832 not reaped yet, so we set its FD to a negative value
6833 to make sure sys_select will eventually get to
6834 calling the SIGCHLD handler for it, which will then
6835 invoke waitpid and reap_subprocess. */
6836 if (cp
->procinfo
.hProcess
== NULL
)
6844 if (fd
>= 0 && fd
< MAXDESC
)
6845 fd_info
[fd
].flags
= 0;
6847 /* Note that sockets do not need special treatment here (at least on
6848 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
6849 closesocket is equivalent to CloseHandle, which is to be expected
6850 because socket handles are fully fledged kernel handles. */
6862 if (new_fd
>= 0 && new_fd
< MAXDESC
)
6864 /* duplicate our internal info as well */
6865 fd_info
[new_fd
] = fd_info
[fd
];
6871 sys_dup2 (int src
, int dst
)
6875 if (dst
< 0 || dst
>= MAXDESC
)
6881 /* make sure we close the destination first if it's a pipe or socket */
6882 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
6885 rc
= _dup2 (src
, dst
);
6888 /* duplicate our internal info as well */
6889 fd_info
[dst
] = fd_info
[src
];
6895 pipe2 (int * phandles
, int pipe2_flags
)
6900 eassert (pipe2_flags
== O_CLOEXEC
);
6902 /* make pipe handles non-inheritable; when we spawn a child, we
6903 replace the relevant handle with an inheritable one. Also put
6904 pipes into binary mode; we will do text mode translation ourselves
6906 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
6910 /* Protect against overflow, since Windows can open more handles than
6911 our fd_info array has room for. */
6912 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
6914 _close (phandles
[0]);
6915 _close (phandles
[1]);
6921 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
6922 fd_info
[phandles
[0]].flags
= flags
;
6924 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
6925 fd_info
[phandles
[1]].flags
= flags
;
6932 /* Function to do blocking read of one byte, needed to implement
6933 select. It is only allowed on communication ports, sockets, or
6936 _sys_read_ahead (int fd
)
6941 if (fd
< 0 || fd
>= MAXDESC
)
6942 return STATUS_READ_ERROR
;
6944 cp
= fd_info
[fd
].cp
;
6946 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6947 return STATUS_READ_ERROR
;
6949 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
6950 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
6952 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
6956 cp
->status
= STATUS_READ_IN_PROGRESS
;
6958 if (fd_info
[fd
].flags
& FILE_PIPE
)
6960 rc
= _read (fd
, &cp
->chr
, sizeof (char));
6962 /* Give subprocess time to buffer some more output for us before
6963 reporting that input is available; we need this because Windows 95
6964 connects DOS programs to pipes by making the pipe appear to be
6965 the normal console stdout - as a result most DOS programs will
6966 write to stdout without buffering, ie. one character at a
6967 time. Even some W32 programs do this - "dir" in a command
6968 shell on NT is very slow if we don't do this. */
6971 int wait
= w32_pipe_read_delay
;
6977 /* Yield remainder of our time slice, effectively giving a
6978 temporary priority boost to the child process. */
6982 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
6984 HANDLE hnd
= fd_info
[fd
].hnd
;
6985 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
6988 /* Configure timeouts for blocking read. */
6989 if (!GetCommTimeouts (hnd
, &ct
))
6991 cp
->status
= STATUS_READ_ERROR
;
6992 return STATUS_READ_ERROR
;
6994 ct
.ReadIntervalTimeout
= 0;
6995 ct
.ReadTotalTimeoutMultiplier
= 0;
6996 ct
.ReadTotalTimeoutConstant
= 0;
6997 if (!SetCommTimeouts (hnd
, &ct
))
6999 cp
->status
= STATUS_READ_ERROR
;
7000 return STATUS_READ_ERROR
;
7003 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
7005 if (GetLastError () != ERROR_IO_PENDING
)
7007 cp
->status
= STATUS_READ_ERROR
;
7008 return STATUS_READ_ERROR
;
7010 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7012 cp
->status
= STATUS_READ_ERROR
;
7013 return STATUS_READ_ERROR
;
7017 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
7019 unsigned long nblock
= 0;
7020 /* We always want this to block, so temporarily disable NDELAY. */
7021 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7022 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7024 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
7026 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7029 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7033 if (rc
== sizeof (char))
7034 cp
->status
= STATUS_READ_SUCCEEDED
;
7036 cp
->status
= STATUS_READ_FAILED
;
7042 _sys_wait_accept (int fd
)
7048 if (fd
< 0 || fd
>= MAXDESC
)
7049 return STATUS_READ_ERROR
;
7051 cp
= fd_info
[fd
].cp
;
7053 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
7054 return STATUS_READ_ERROR
;
7056 cp
->status
= STATUS_READ_FAILED
;
7058 hEv
= pfn_WSACreateEvent ();
7059 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
7060 if (rc
!= SOCKET_ERROR
)
7062 rc
= WaitForSingleObject (hEv
, INFINITE
);
7063 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
7064 if (rc
== WAIT_OBJECT_0
)
7065 cp
->status
= STATUS_READ_SUCCEEDED
;
7067 pfn_WSACloseEvent (hEv
);
7073 sys_read (int fd
, char * buffer
, unsigned int count
)
7078 char * orig_buffer
= buffer
;
7086 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7088 child_process
*cp
= fd_info
[fd
].cp
;
7090 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
7098 /* re-read CR carried over from last read */
7099 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
7101 if (fd_info
[fd
].flags
& FILE_BINARY
) emacs_abort ();
7105 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
7108 /* presence of a child_process structure means we are operating in
7109 non-blocking mode - otherwise we just call _read directly.
7110 Note that the child_process structure might be missing because
7111 reap_subprocess has been called; in this case the pipe is
7112 already broken, so calling _read on it is okay. */
7115 int current_status
= cp
->status
;
7117 switch (current_status
)
7119 case STATUS_READ_FAILED
:
7120 case STATUS_READ_ERROR
:
7121 /* report normal EOF if nothing in buffer */
7123 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7126 case STATUS_READ_READY
:
7127 case STATUS_READ_IN_PROGRESS
:
7128 DebPrint (("sys_read called when read is in progress\n"));
7129 errno
= EWOULDBLOCK
;
7132 case STATUS_READ_SUCCEEDED
:
7133 /* consume read-ahead char */
7134 *buffer
++ = cp
->chr
;
7137 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7138 ResetEvent (cp
->char_avail
);
7140 case STATUS_READ_ACKNOWLEDGED
:
7144 DebPrint (("sys_read: bad status %d\n", current_status
));
7149 if (fd_info
[fd
].flags
& FILE_PIPE
)
7151 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
7152 to_read
= min (waiting
, (DWORD
) count
);
7155 nchars
+= _read (fd
, buffer
, to_read
);
7157 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7159 HANDLE hnd
= fd_info
[fd
].hnd
;
7160 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7166 /* Configure timeouts for non-blocking read. */
7167 if (!GetCommTimeouts (hnd
, &ct
))
7172 ct
.ReadIntervalTimeout
= MAXDWORD
;
7173 ct
.ReadTotalTimeoutMultiplier
= 0;
7174 ct
.ReadTotalTimeoutConstant
= 0;
7175 if (!SetCommTimeouts (hnd
, &ct
))
7181 if (!ResetEvent (ovl
->hEvent
))
7186 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
7188 if (GetLastError () != ERROR_IO_PENDING
)
7193 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7202 else /* FILE_SOCKET */
7204 if (winsock_lib
== NULL
) emacs_abort ();
7206 /* do the equivalent of a non-blocking read */
7207 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
7208 if (waiting
== 0 && nchars
== 0)
7210 errno
= EWOULDBLOCK
;
7216 /* always use binary mode for sockets */
7217 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
7218 if (res
== SOCKET_ERROR
)
7220 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7221 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7231 int nread
= _read (fd
, buffer
, count
);
7234 else if (nchars
== 0)
7239 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7240 /* Perform text mode translation if required. */
7241 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7243 nchars
= crlf_to_lf (nchars
, orig_buffer
);
7244 /* If buffer contains only CR, return that. To be absolutely
7245 sure we should attempt to read the next char, but in
7246 practice a CR to be followed by LF would not appear by
7247 itself in the buffer. */
7248 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
7250 fd_info
[fd
].flags
|= FILE_LAST_CR
;
7256 nchars
= _read (fd
, buffer
, count
);
7261 /* From w32xfns.c */
7262 extern HANDLE interrupt_handle
;
7264 /* For now, don't bother with a non-blocking mode */
7266 sys_write (int fd
, const void * buffer
, unsigned int count
)
7276 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7278 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
7284 /* Perform text mode translation if required. */
7285 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7287 char * tmpbuf
= alloca (count
* 2);
7288 unsigned char * src
= (void *)buffer
;
7289 unsigned char * dst
= tmpbuf
;
7294 unsigned char *next
;
7295 /* copy next line or remaining bytes */
7296 next
= _memccpy (dst
, src
, '\n', nbytes
);
7299 /* copied one line ending with '\n' */
7300 int copied
= next
- dst
;
7303 /* insert '\r' before '\n' */
7310 /* copied remaining partial line -> now finished */
7317 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
7319 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
7320 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
7321 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
7324 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
7326 if (GetLastError () != ERROR_IO_PENDING
)
7331 if (detect_input_pending ())
7332 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
7335 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
7336 if (active
== WAIT_OBJECT_0
)
7337 { /* User pressed C-g, cancel write, then leave. Don't bother
7338 cleaning up as we may only get stuck in buggy drivers. */
7339 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
7344 if (active
== WAIT_OBJECT_0
+ 1
7345 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
7352 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
7354 unsigned long nblock
= 0;
7355 if (winsock_lib
== NULL
) emacs_abort ();
7357 /* TODO: implement select() properly so non-blocking I/O works. */
7358 /* For now, make sure the write blocks. */
7359 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7360 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7362 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
7364 /* Set the socket back to non-blocking if it was before,
7365 for other operations that support it. */
7366 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7369 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7372 if (nchars
== SOCKET_ERROR
)
7374 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7375 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7381 /* Some networked filesystems don't like too large writes, so
7382 break them into smaller chunks. See the Comments section of
7383 the MSDN documentation of WriteFile for details behind the
7384 choice of the value of CHUNK below. See also the thread
7385 http://thread.gmane.org/gmane.comp.version-control.git/145294
7386 in the git mailing list. */
7387 const unsigned char *p
= buffer
;
7388 const unsigned chunk
= 30 * 1024 * 1024;
7393 unsigned this_chunk
= count
< chunk
? count
: chunk
;
7394 int n
= _write (fd
, p
, this_chunk
);
7402 else if (n
< this_chunk
)
7412 /* The Windows CRT functions are "optimized for speed", so they don't
7413 check for timezone and DST changes if they were last called less
7414 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
7415 all Emacs features that repeatedly call time functions (e.g.,
7416 display-time) are in real danger of missing timezone and DST
7417 changes. Calling tzset before each localtime call fixes that. */
7419 sys_localtime (const time_t *t
)
7422 return localtime (t
);
7427 /* Try loading LIBRARY_ID from the file(s) specified in
7428 Vdynamic_library_alist. If the library is loaded successfully,
7429 return the handle of the DLL, and record the filename in the
7430 property :loaded-from of LIBRARY_ID. If the library could not be
7431 found, or when it was already loaded (because the handle is not
7432 recorded anywhere, and so is lost after use), return NULL.
7434 We could also save the handle in :loaded-from, but currently
7435 there's no use case for it. */
7437 w32_delayed_load (Lisp_Object library_id
)
7439 HMODULE library_dll
= NULL
;
7441 CHECK_SYMBOL (library_id
);
7443 if (CONSP (Vdynamic_library_alist
)
7444 && NILP (Fassq (library_id
, Vlibrary_cache
)))
7446 Lisp_Object found
= Qnil
;
7447 Lisp_Object dlls
= Fassq (library_id
, Vdynamic_library_alist
);
7450 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
7452 CHECK_STRING_CAR (dlls
);
7453 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
7455 char name
[MAX_PATH
];
7458 len
= GetModuleFileNameA (library_dll
, name
, sizeof (name
));
7459 found
= Fcons (XCAR (dlls
),
7461 /* Possibly truncated */
7462 ? make_specified_string (name
, -1, len
, 1)
7468 Fput (library_id
, QCloaded_from
, found
);
7476 check_windows_init_file (void)
7478 /* A common indication that Emacs is not installed properly is when
7479 it cannot find the Windows installation file. If this file does
7480 not exist in the expected place, tell the user. */
7482 if (!noninteractive
&& !inhibit_window_system
7483 /* Vload_path is not yet initialized when we are loading
7485 && NILP (Vpurify_flag
))
7487 Lisp_Object init_file
;
7490 init_file
= build_string ("term/w32-win");
7491 fd
= openp (Vload_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
7494 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
7495 char *init_file_name
= SDATA (init_file
);
7496 char *load_path
= SDATA (load_path_print
);
7497 char *buffer
= alloca (1024
7498 + strlen (init_file_name
)
7499 + strlen (load_path
));
7502 "The Emacs Windows initialization file \"%s.el\" "
7503 "could not be found in your Emacs installation. "
7504 "Emacs checked the following directories for this file:\n"
7506 "When Emacs cannot find this file, it usually means that it "
7507 "was not installed properly, or its distribution file was "
7508 "not unpacked properly.\nSee the README.W32 file in the "
7509 "top-level Emacs directory for more information.",
7510 init_file_name
, load_path
);
7513 "Emacs Abort Dialog",
7514 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
7515 /* Use the low-level system abort. */
7526 term_ntproc (int ignored
)
7532 /* shutdown the socket interface if necessary */
7539 init_ntproc (int dumping
)
7541 sigset_t initial_mask
= 0;
7543 /* Initialize the socket interface now if available and requested by
7544 the user by defining PRELOAD_WINSOCK; otherwise loading will be
7545 delayed until open-network-stream is called (w32-has-winsock can
7546 also be used to dynamically load or reload winsock).
7548 Conveniently, init_environment is called before us, so
7549 PRELOAD_WINSOCK can be set in the registry. */
7551 /* Always initialize this correctly. */
7554 if (getenv ("PRELOAD_WINSOCK") != NULL
)
7555 init_winsock (TRUE
);
7557 /* Initial preparation for subprocess support: replace our standard
7558 handles with non-inheritable versions. */
7561 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
7562 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
7563 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
7565 parent
= GetCurrentProcess ();
7567 /* ignore errors when duplicating and closing; typically the
7568 handles will be invalid when running as a gui program. */
7569 DuplicateHandle (parent
,
7570 GetStdHandle (STD_INPUT_HANDLE
),
7575 DUPLICATE_SAME_ACCESS
);
7577 DuplicateHandle (parent
,
7578 GetStdHandle (STD_OUTPUT_HANDLE
),
7583 DUPLICATE_SAME_ACCESS
);
7585 DuplicateHandle (parent
,
7586 GetStdHandle (STD_ERROR_HANDLE
),
7591 DUPLICATE_SAME_ACCESS
);
7597 if (stdin_save
!= INVALID_HANDLE_VALUE
)
7598 _open_osfhandle ((intptr_t) stdin_save
, O_TEXT
);
7600 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
7603 if (stdout_save
!= INVALID_HANDLE_VALUE
)
7604 _open_osfhandle ((intptr_t) stdout_save
, O_TEXT
);
7606 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
7609 if (stderr_save
!= INVALID_HANDLE_VALUE
)
7610 _open_osfhandle ((intptr_t) stderr_save
, O_TEXT
);
7612 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
7616 /* unfortunately, atexit depends on implementation of malloc */
7617 /* atexit (term_ntproc); */
7620 /* Make sure we start with all signals unblocked. */
7621 sigprocmask (SIG_SETMASK
, &initial_mask
, NULL
);
7622 signal (SIGABRT
, term_ntproc
);
7626 /* determine which drives are fixed, for GetCachedVolumeInformation */
7628 /* GetDriveType must have trailing backslash. */
7629 char drive
[] = "A:\\";
7631 /* Loop over all possible drive letters */
7632 while (*drive
<= 'Z')
7634 /* Record if this drive letter refers to a fixed drive. */
7635 fixed_drives
[DRIVE_INDEX (*drive
)] =
7636 (GetDriveType (drive
) == DRIVE_FIXED
);
7641 /* Reset the volume info cache. */
7642 volume_cache
= NULL
;
7647 shutdown_handler ensures that buffers' autosave files are
7648 up to date when the user logs off, or the system shuts down.
7651 shutdown_handler (DWORD type
)
7653 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
7654 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
7655 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
7656 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
7658 /* Shut down cleanly, making sure autosave files are up to date. */
7659 shut_down_emacs (0, Qnil
);
7662 /* Allow other handlers to handle this signal. */
7667 globals_of_w32 is used to initialize those global variables that
7668 must always be initialized on startup even when the global variable
7669 initialized is non zero (see the function main in emacs.c).
7672 globals_of_w32 (void)
7674 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
7676 get_process_times_fn
= (GetProcessTimes_Proc
)
7677 GetProcAddress (kernel32
, "GetProcessTimes");
7679 DEFSYM (QCloaded_from
, ":loaded-from");
7681 g_b_init_is_windows_9x
= 0;
7682 g_b_init_open_process_token
= 0;
7683 g_b_init_get_token_information
= 0;
7684 g_b_init_lookup_account_sid
= 0;
7685 g_b_init_get_sid_sub_authority
= 0;
7686 g_b_init_get_sid_sub_authority_count
= 0;
7687 g_b_init_get_security_info
= 0;
7688 g_b_init_get_file_security
= 0;
7689 g_b_init_get_security_descriptor_owner
= 0;
7690 g_b_init_get_security_descriptor_group
= 0;
7691 g_b_init_is_valid_sid
= 0;
7692 g_b_init_create_toolhelp32_snapshot
= 0;
7693 g_b_init_process32_first
= 0;
7694 g_b_init_process32_next
= 0;
7695 g_b_init_open_thread_token
= 0;
7696 g_b_init_impersonate_self
= 0;
7697 g_b_init_revert_to_self
= 0;
7698 g_b_init_get_process_memory_info
= 0;
7699 g_b_init_get_process_working_set_size
= 0;
7700 g_b_init_global_memory_status
= 0;
7701 g_b_init_global_memory_status_ex
= 0;
7702 g_b_init_equal_sid
= 0;
7703 g_b_init_copy_sid
= 0;
7704 g_b_init_get_length_sid
= 0;
7705 g_b_init_get_native_system_info
= 0;
7706 g_b_init_get_system_times
= 0;
7707 g_b_init_create_symbolic_link
= 0;
7708 g_b_init_get_security_descriptor_dacl
= 0;
7709 g_b_init_convert_sd_to_sddl
= 0;
7710 g_b_init_convert_sddl_to_sd
= 0;
7711 g_b_init_is_valid_security_descriptor
= 0;
7712 g_b_init_set_file_security
= 0;
7713 num_of_processors
= 0;
7714 /* The following sets a handler for shutdown notifications for
7715 console apps. This actually applies to Emacs in both console and
7716 GUI modes, since we had to fool windows into thinking emacs is a
7717 console application to get console mode to work. */
7718 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
7720 /* "None" is the default group name on standalone workstations. */
7721 strcpy (dflt_group_name
, "None");
7723 /* Reset, in case it has some value inherited from dump time. */
7724 w32_stat_get_owner_group
= 0;
7727 /* For make-serial-process */
7729 serial_open (Lisp_Object port_obj
)
7731 char *port
= SSDATA (port_obj
);
7736 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
7737 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
7738 if (hnd
== INVALID_HANDLE_VALUE
)
7739 error ("Could not open %s", port
);
7740 fd
= (int) _open_osfhandle ((intptr_t) hnd
, 0);
7742 error ("Could not open %s", port
);
7746 error ("Could not create child process");
7748 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7749 fd_info
[ fd
].hnd
= hnd
;
7750 fd_info
[ fd
].flags
|=
7751 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
7752 if (fd_info
[ fd
].cp
!= NULL
)
7754 error ("fd_info[fd = %d] is already in use", fd
);
7756 fd_info
[ fd
].cp
= cp
;
7757 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
7758 if (cp
->ovl_read
.hEvent
== NULL
)
7759 error ("Could not create read event");
7760 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
7761 if (cp
->ovl_write
.hEvent
== NULL
)
7762 error ("Could not create write event");
7767 /* For serial-process-configure */
7769 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
7771 Lisp_Object childp2
= Qnil
;
7772 Lisp_Object tem
= Qnil
;
7776 char summary
[4] = "???"; /* This usually becomes "8N1". */
7778 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
7779 error ("Not a serial process");
7780 hnd
= fd_info
[ p
->outfd
].hnd
;
7782 childp2
= Fcopy_sequence (p
->childp
);
7784 /* Initialize timeouts for blocking read and blocking write. */
7785 if (!GetCommTimeouts (hnd
, &ct
))
7786 error ("GetCommTimeouts() failed");
7787 ct
.ReadIntervalTimeout
= 0;
7788 ct
.ReadTotalTimeoutMultiplier
= 0;
7789 ct
.ReadTotalTimeoutConstant
= 0;
7790 ct
.WriteTotalTimeoutMultiplier
= 0;
7791 ct
.WriteTotalTimeoutConstant
= 0;
7792 if (!SetCommTimeouts (hnd
, &ct
))
7793 error ("SetCommTimeouts() failed");
7794 /* Read port attributes and prepare default configuration. */
7795 memset (&dcb
, 0, sizeof (dcb
));
7796 dcb
.DCBlength
= sizeof (DCB
);
7797 if (!GetCommState (hnd
, &dcb
))
7798 error ("GetCommState() failed");
7801 dcb
.fAbortOnError
= FALSE
;
7802 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
7807 /* Configure speed. */
7808 if (!NILP (Fplist_member (contact
, QCspeed
)))
7809 tem
= Fplist_get (contact
, QCspeed
);
7811 tem
= Fplist_get (p
->childp
, QCspeed
);
7813 dcb
.BaudRate
= XINT (tem
);
7814 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
7816 /* Configure bytesize. */
7817 if (!NILP (Fplist_member (contact
, QCbytesize
)))
7818 tem
= Fplist_get (contact
, QCbytesize
);
7820 tem
= Fplist_get (p
->childp
, QCbytesize
);
7822 tem
= make_number (8);
7824 if (XINT (tem
) != 7 && XINT (tem
) != 8)
7825 error (":bytesize must be nil (8), 7, or 8");
7826 dcb
.ByteSize
= XINT (tem
);
7827 summary
[0] = XINT (tem
) + '0';
7828 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
7830 /* Configure parity. */
7831 if (!NILP (Fplist_member (contact
, QCparity
)))
7832 tem
= Fplist_get (contact
, QCparity
);
7834 tem
= Fplist_get (p
->childp
, QCparity
);
7835 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
7836 error (":parity must be nil (no parity), `even', or `odd'");
7837 dcb
.fParity
= FALSE
;
7838 dcb
.Parity
= NOPARITY
;
7839 dcb
.fErrorChar
= FALSE
;
7844 else if (EQ (tem
, Qeven
))
7848 dcb
.Parity
= EVENPARITY
;
7849 dcb
.fErrorChar
= TRUE
;
7851 else if (EQ (tem
, Qodd
))
7855 dcb
.Parity
= ODDPARITY
;
7856 dcb
.fErrorChar
= TRUE
;
7858 childp2
= Fplist_put (childp2
, QCparity
, tem
);
7860 /* Configure stopbits. */
7861 if (!NILP (Fplist_member (contact
, QCstopbits
)))
7862 tem
= Fplist_get (contact
, QCstopbits
);
7864 tem
= Fplist_get (p
->childp
, QCstopbits
);
7866 tem
= make_number (1);
7868 if (XINT (tem
) != 1 && XINT (tem
) != 2)
7869 error (":stopbits must be nil (1 stopbit), 1, or 2");
7870 summary
[2] = XINT (tem
) + '0';
7871 if (XINT (tem
) == 1)
7872 dcb
.StopBits
= ONESTOPBIT
;
7873 else if (XINT (tem
) == 2)
7874 dcb
.StopBits
= TWOSTOPBITS
;
7875 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
7877 /* Configure flowcontrol. */
7878 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
7879 tem
= Fplist_get (contact
, QCflowcontrol
);
7881 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
7882 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
7883 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
7884 dcb
.fOutxCtsFlow
= FALSE
;
7885 dcb
.fOutxDsrFlow
= FALSE
;
7886 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
7887 dcb
.fDsrSensitivity
= FALSE
;
7888 dcb
.fTXContinueOnXoff
= FALSE
;
7891 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
7892 dcb
.XonChar
= 17; /* Control-Q */
7893 dcb
.XoffChar
= 19; /* Control-S */
7896 /* Already configured. */
7898 else if (EQ (tem
, Qhw
))
7900 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
7901 dcb
.fOutxCtsFlow
= TRUE
;
7903 else if (EQ (tem
, Qsw
))
7908 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
7910 /* Activate configuration. */
7911 if (!SetCommState (hnd
, &dcb
))
7912 error ("SetCommState() failed");
7914 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
7915 pset_childp (p
, childp2
);
7921 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
7926 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7927 int fd
= process
->infd
;
7929 n
= sys_read (fd
, (char*)buf
, sz
);
7936 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7937 if (err
== EWOULDBLOCK
)
7940 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
7946 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
7948 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7949 int fd
= process
->outfd
;
7950 ssize_t n
= sys_write (fd
, buf
, sz
);
7952 /* 0 or more bytes written means everything went fine. */
7956 /* Negative bytes written means we got an error in errno.
7957 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7958 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
7959 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
7963 #endif /* HAVE_GNUTLS */