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, ... */
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
;
100 #if _WIN32_WINNT < 0x0500
101 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
102 /* This either is not in psapi.h or guarded by higher value of
103 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
104 defines it in psapi.h */
105 typedef struct _PROCESS_MEMORY_COUNTERS_EX
{
107 DWORD PageFaultCount
;
108 SIZE_T PeakWorkingSetSize
;
109 SIZE_T WorkingSetSize
;
110 SIZE_T QuotaPeakPagedPoolUsage
;
111 SIZE_T QuotaPagedPoolUsage
;
112 SIZE_T QuotaPeakNonPagedPoolUsage
;
113 SIZE_T QuotaNonPagedPoolUsage
;
114 SIZE_T PagefileUsage
;
115 SIZE_T PeakPagefileUsage
;
117 } PROCESS_MEMORY_COUNTERS_EX
,*PPROCESS_MEMORY_COUNTERS_EX
;
121 #include <winioctl.h>
127 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
128 define them by hand if not already defined. */
129 #ifndef SDDL_REVISION_1
130 #define SDDL_REVISION_1 1
131 #endif /* SDDL_REVISION_1 */
133 #if defined(_MSC_VER) || defined(_W64)
134 /* MSVC and MinGW64 don't provide the definition of
135 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
136 which cannot be included because it triggers conflicts with other
137 Windows API headers. So we define it here by hand. */
139 typedef struct _REPARSE_DATA_BUFFER
{
141 USHORT ReparseDataLength
;
145 USHORT SubstituteNameOffset
;
146 USHORT SubstituteNameLength
;
147 USHORT PrintNameOffset
;
148 USHORT PrintNameLength
;
151 } SymbolicLinkReparseBuffer
;
153 USHORT SubstituteNameOffset
;
154 USHORT SubstituteNameLength
;
155 USHORT PrintNameOffset
;
156 USHORT PrintNameLength
;
158 } MountPointReparseBuffer
;
161 } GenericReparseBuffer
;
163 } REPARSE_DATA_BUFFER
, *PREPARSE_DATA_BUFFER
;
165 #ifndef FILE_DEVICE_FILE_SYSTEM
166 #define FILE_DEVICE_FILE_SYSTEM 9
168 #ifndef METHOD_BUFFERED
169 #define METHOD_BUFFERED 0
171 #ifndef FILE_ANY_ACCESS
172 #define FILE_ANY_ACCESS 0x00000000
175 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
177 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
178 #ifndef FSCTL_GET_REPARSE_POINT
179 #define FSCTL_GET_REPARSE_POINT \
180 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
184 /* TCP connection support. */
185 #include <sys/socket.h>
206 #include "w32common.h"
208 #include "w32select.h"
210 #include "dispextern.h" /* for xstrcasecmp */
211 #include "coding.h" /* for Vlocale_coding_system */
213 #include "careadlinkat.h"
214 #include "allocator.h"
216 /* For serial_configure and serial_open. */
219 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
220 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
222 Lisp_Object QCloaded_from
;
224 void globals_of_w32 (void);
225 static DWORD
get_rid (PSID
);
226 static int is_symlink (const char *);
227 static char * chase_symlinks (const char *);
228 static int enable_privilege (LPCTSTR
, BOOL
, TOKEN_PRIVILEGES
*);
229 static int restore_privilege (TOKEN_PRIVILEGES
*);
230 static BOOL WINAPI
revert_to_self (void);
232 extern int sys_access (const char *, int);
233 extern void *e_malloc (size_t);
234 extern int sys_select (int, SELECT_TYPE
*, SELECT_TYPE
*, SELECT_TYPE
*,
235 EMACS_TIME
*, void *);
239 /* Initialization states.
241 WARNING: If you add any more such variables for additional APIs,
242 you MUST add initialization for them to globals_of_w32
243 below. This is because these variables might get set
244 to non-NULL values during dumping, but the dumped Emacs
245 cannot reuse those values, because it could be run on a
246 different version of the OS, where API addresses are
248 static BOOL g_b_init_is_windows_9x
;
249 static BOOL g_b_init_open_process_token
;
250 static BOOL g_b_init_get_token_information
;
251 static BOOL g_b_init_lookup_account_sid
;
252 static BOOL g_b_init_get_sid_sub_authority
;
253 static BOOL g_b_init_get_sid_sub_authority_count
;
254 static BOOL g_b_init_get_security_info
;
255 static BOOL g_b_init_get_file_security
;
256 static BOOL g_b_init_get_security_descriptor_owner
;
257 static BOOL g_b_init_get_security_descriptor_group
;
258 static BOOL g_b_init_is_valid_sid
;
259 static BOOL g_b_init_create_toolhelp32_snapshot
;
260 static BOOL g_b_init_process32_first
;
261 static BOOL g_b_init_process32_next
;
262 static BOOL g_b_init_open_thread_token
;
263 static BOOL g_b_init_impersonate_self
;
264 static BOOL g_b_init_revert_to_self
;
265 static BOOL g_b_init_get_process_memory_info
;
266 static BOOL g_b_init_get_process_working_set_size
;
267 static BOOL g_b_init_global_memory_status
;
268 static BOOL g_b_init_global_memory_status_ex
;
269 static BOOL g_b_init_get_length_sid
;
270 static BOOL g_b_init_equal_sid
;
271 static BOOL g_b_init_copy_sid
;
272 static BOOL g_b_init_get_native_system_info
;
273 static BOOL g_b_init_get_system_times
;
274 static BOOL g_b_init_create_symbolic_link
;
275 static BOOL g_b_init_get_security_descriptor_dacl
;
276 static BOOL g_b_init_convert_sd_to_sddl
;
277 static BOOL g_b_init_convert_sddl_to_sd
;
278 static BOOL g_b_init_is_valid_security_descriptor
;
279 static BOOL g_b_init_set_file_security
;
282 BEGIN: Wrapper functions around OpenProcessToken
283 and other functions in advapi32.dll that are only
284 supported in Windows NT / 2k / XP
286 /* ** Function pointer typedefs ** */
287 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
288 HANDLE ProcessHandle
,
290 PHANDLE TokenHandle
);
291 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
293 TOKEN_INFORMATION_CLASS TokenInformationClass
,
294 LPVOID TokenInformation
,
295 DWORD TokenInformationLength
,
296 PDWORD ReturnLength
);
297 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
298 HANDLE process_handle
,
299 LPFILETIME creation_time
,
300 LPFILETIME exit_time
,
301 LPFILETIME kernel_time
,
302 LPFILETIME user_time
);
304 GetProcessTimes_Proc get_process_times_fn
= NULL
;
307 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
308 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
309 const char * const SetFileSecurity_Name
= "SetFileSecurityW";
311 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
312 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
313 const char * const SetFileSecurity_Name
= "SetFileSecurityA";
315 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
316 LPCTSTR lpSystemName
,
321 LPDWORD cbDomainName
,
322 PSID_NAME_USE peUse
);
323 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
326 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
328 typedef DWORD (WINAPI
* GetSecurityInfo_Proc
) (
330 SE_OBJECT_TYPE ObjectType
,
331 SECURITY_INFORMATION SecurityInfo
,
336 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
);
337 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
339 SECURITY_INFORMATION RequestedInformation
,
340 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
342 LPDWORD lpnLengthNeeded
);
343 typedef BOOL (WINAPI
*SetFileSecurity_Proc
) (
345 SECURITY_INFORMATION SecurityInformation
,
346 PSECURITY_DESCRIPTOR pSecurityDescriptor
);
347 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
348 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
350 LPBOOL lpbOwnerDefaulted
);
351 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
352 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
354 LPBOOL lpbGroupDefaulted
);
355 typedef BOOL (WINAPI
*GetSecurityDescriptorDacl_Proc
) (
356 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
357 LPBOOL lpbDaclPresent
,
359 LPBOOL lpbDaclDefaulted
);
360 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
362 typedef HANDLE (WINAPI
* CreateToolhelp32Snapshot_Proc
) (
364 DWORD th32ProcessID
);
365 typedef BOOL (WINAPI
* Process32First_Proc
) (
367 LPPROCESSENTRY32 lppe
);
368 typedef BOOL (WINAPI
* Process32Next_Proc
) (
370 LPPROCESSENTRY32 lppe
);
371 typedef BOOL (WINAPI
* OpenThreadToken_Proc
) (
375 PHANDLE TokenHandle
);
376 typedef BOOL (WINAPI
* ImpersonateSelf_Proc
) (
377 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
);
378 typedef BOOL (WINAPI
* RevertToSelf_Proc
) (void);
379 typedef BOOL (WINAPI
* GetProcessMemoryInfo_Proc
) (
381 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
383 typedef BOOL (WINAPI
* GetProcessWorkingSetSize_Proc
) (
385 PSIZE_T lpMinimumWorkingSetSize
,
386 PSIZE_T lpMaximumWorkingSetSize
);
387 typedef BOOL (WINAPI
* GlobalMemoryStatus_Proc
) (
388 LPMEMORYSTATUS lpBuffer
);
389 typedef BOOL (WINAPI
* GlobalMemoryStatusEx_Proc
) (
390 LPMEMORY_STATUS_EX lpBuffer
);
391 typedef BOOL (WINAPI
* CopySid_Proc
) (
392 DWORD nDestinationSidLength
,
393 PSID pDestinationSid
,
395 typedef BOOL (WINAPI
* EqualSid_Proc
) (
398 typedef DWORD (WINAPI
* GetLengthSid_Proc
) (
400 typedef void (WINAPI
* GetNativeSystemInfo_Proc
) (
401 LPSYSTEM_INFO lpSystemInfo
);
402 typedef BOOL (WINAPI
* GetSystemTimes_Proc
) (
403 LPFILETIME lpIdleTime
,
404 LPFILETIME lpKernelTime
,
405 LPFILETIME lpUserTime
);
406 typedef BOOLEAN (WINAPI
*CreateSymbolicLink_Proc
) (
407 LPTSTR lpSymlinkFileName
,
408 LPTSTR lpTargetFileName
,
410 typedef BOOL (WINAPI
*ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
) (
411 LPCTSTR StringSecurityDescriptor
,
412 DWORD StringSDRevision
,
413 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
414 PULONG SecurityDescriptorSize
);
415 typedef BOOL (WINAPI
*ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
) (
416 PSECURITY_DESCRIPTOR SecurityDescriptor
,
417 DWORD RequestedStringSDRevision
,
418 SECURITY_INFORMATION SecurityInformation
,
419 LPTSTR
*StringSecurityDescriptor
,
420 PULONG StringSecurityDescriptorLen
);
421 typedef BOOL (WINAPI
*IsValidSecurityDescriptor_Proc
) (PSECURITY_DESCRIPTOR
);
423 /* ** A utility function ** */
427 static BOOL s_b_ret
= 0;
428 OSVERSIONINFO os_ver
;
429 if (g_b_init_is_windows_9x
== 0)
431 g_b_init_is_windows_9x
= 1;
432 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
433 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
434 if (GetVersionEx (&os_ver
))
436 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
442 static Lisp_Object
ltime (ULONGLONG
);
444 /* Get total user and system times for get-internal-run-time.
445 Returns a list of integers if the times are provided by the OS
446 (NT derivatives), otherwise it returns the result of current-time. */
448 w32_get_internal_run_time (void)
450 if (get_process_times_fn
)
452 FILETIME create
, exit
, kernel
, user
;
453 HANDLE proc
= GetCurrentProcess ();
454 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
456 LARGE_INTEGER user_int
, kernel_int
, total
;
457 user_int
.LowPart
= user
.dwLowDateTime
;
458 user_int
.HighPart
= user
.dwHighDateTime
;
459 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
460 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
461 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
462 return ltime (total
.QuadPart
);
466 return Fcurrent_time ();
469 /* ** The wrapper functions ** */
472 open_process_token (HANDLE ProcessHandle
,
476 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
477 HMODULE hm_advapi32
= NULL
;
478 if (is_windows_9x () == TRUE
)
482 if (g_b_init_open_process_token
== 0)
484 g_b_init_open_process_token
= 1;
485 hm_advapi32
= LoadLibrary ("Advapi32.dll");
486 s_pfn_Open_Process_Token
=
487 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
489 if (s_pfn_Open_Process_Token
== NULL
)
494 s_pfn_Open_Process_Token (
502 get_token_information (HANDLE TokenHandle
,
503 TOKEN_INFORMATION_CLASS TokenInformationClass
,
504 LPVOID TokenInformation
,
505 DWORD TokenInformationLength
,
508 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
509 HMODULE hm_advapi32
= NULL
;
510 if (is_windows_9x () == TRUE
)
514 if (g_b_init_get_token_information
== 0)
516 g_b_init_get_token_information
= 1;
517 hm_advapi32
= LoadLibrary ("Advapi32.dll");
518 s_pfn_Get_Token_Information
=
519 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
521 if (s_pfn_Get_Token_Information
== NULL
)
526 s_pfn_Get_Token_Information (
528 TokenInformationClass
,
530 TokenInformationLength
,
536 lookup_account_sid (LPCTSTR lpSystemName
,
541 LPDWORD cbDomainName
,
544 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
545 HMODULE hm_advapi32
= NULL
;
546 if (is_windows_9x () == TRUE
)
550 if (g_b_init_lookup_account_sid
== 0)
552 g_b_init_lookup_account_sid
= 1;
553 hm_advapi32
= LoadLibrary ("Advapi32.dll");
554 s_pfn_Lookup_Account_Sid
=
555 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
557 if (s_pfn_Lookup_Account_Sid
== NULL
)
562 s_pfn_Lookup_Account_Sid (
574 get_sid_sub_authority (PSID pSid
, DWORD n
)
576 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
577 static DWORD zero
= 0U;
578 HMODULE hm_advapi32
= NULL
;
579 if (is_windows_9x () == TRUE
)
583 if (g_b_init_get_sid_sub_authority
== 0)
585 g_b_init_get_sid_sub_authority
= 1;
586 hm_advapi32
= LoadLibrary ("Advapi32.dll");
587 s_pfn_Get_Sid_Sub_Authority
=
588 (GetSidSubAuthority_Proc
) GetProcAddress (
589 hm_advapi32
, "GetSidSubAuthority");
591 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
595 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
599 get_sid_sub_authority_count (PSID pSid
)
601 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
602 static UCHAR zero
= 0U;
603 HMODULE hm_advapi32
= NULL
;
604 if (is_windows_9x () == TRUE
)
608 if (g_b_init_get_sid_sub_authority_count
== 0)
610 g_b_init_get_sid_sub_authority_count
= 1;
611 hm_advapi32
= LoadLibrary ("Advapi32.dll");
612 s_pfn_Get_Sid_Sub_Authority_Count
=
613 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
614 hm_advapi32
, "GetSidSubAuthorityCount");
616 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
620 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
624 get_security_info (HANDLE handle
,
625 SE_OBJECT_TYPE ObjectType
,
626 SECURITY_INFORMATION SecurityInfo
,
631 PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
)
633 static GetSecurityInfo_Proc s_pfn_Get_Security_Info
= NULL
;
634 HMODULE hm_advapi32
= NULL
;
635 if (is_windows_9x () == TRUE
)
639 if (g_b_init_get_security_info
== 0)
641 g_b_init_get_security_info
= 1;
642 hm_advapi32
= LoadLibrary ("Advapi32.dll");
643 s_pfn_Get_Security_Info
=
644 (GetSecurityInfo_Proc
) GetProcAddress (
645 hm_advapi32
, "GetSecurityInfo");
647 if (s_pfn_Get_Security_Info
== NULL
)
651 return (s_pfn_Get_Security_Info (handle
, ObjectType
, SecurityInfo
,
652 ppsidOwner
, ppsidGroup
, ppDacl
, ppSacl
,
653 ppSecurityDescriptor
));
657 get_file_security (LPCTSTR lpFileName
,
658 SECURITY_INFORMATION RequestedInformation
,
659 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
661 LPDWORD lpnLengthNeeded
)
663 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
664 HMODULE hm_advapi32
= NULL
;
665 if (is_windows_9x () == TRUE
)
670 if (g_b_init_get_file_security
== 0)
672 g_b_init_get_file_security
= 1;
673 hm_advapi32
= LoadLibrary ("Advapi32.dll");
674 s_pfn_Get_File_Security
=
675 (GetFileSecurity_Proc
) GetProcAddress (
676 hm_advapi32
, GetFileSecurity_Name
);
678 if (s_pfn_Get_File_Security
== NULL
)
683 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
684 pSecurityDescriptor
, nLength
,
689 set_file_security (LPCTSTR lpFileName
,
690 SECURITY_INFORMATION SecurityInformation
,
691 PSECURITY_DESCRIPTOR pSecurityDescriptor
)
693 static SetFileSecurity_Proc s_pfn_Set_File_Security
= NULL
;
694 HMODULE hm_advapi32
= NULL
;
695 if (is_windows_9x () == TRUE
)
700 if (g_b_init_set_file_security
== 0)
702 g_b_init_set_file_security
= 1;
703 hm_advapi32
= LoadLibrary ("Advapi32.dll");
704 s_pfn_Set_File_Security
=
705 (SetFileSecurity_Proc
) GetProcAddress (
706 hm_advapi32
, SetFileSecurity_Name
);
708 if (s_pfn_Set_File_Security
== NULL
)
713 return (s_pfn_Set_File_Security (lpFileName
, SecurityInformation
,
714 pSecurityDescriptor
));
718 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
720 LPBOOL lpbOwnerDefaulted
)
722 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
723 HMODULE hm_advapi32
= NULL
;
724 if (is_windows_9x () == TRUE
)
729 if (g_b_init_get_security_descriptor_owner
== 0)
731 g_b_init_get_security_descriptor_owner
= 1;
732 hm_advapi32
= LoadLibrary ("Advapi32.dll");
733 s_pfn_Get_Security_Descriptor_Owner
=
734 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
735 hm_advapi32
, "GetSecurityDescriptorOwner");
737 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
742 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
747 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
749 LPBOOL lpbGroupDefaulted
)
751 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
752 HMODULE hm_advapi32
= NULL
;
753 if (is_windows_9x () == TRUE
)
758 if (g_b_init_get_security_descriptor_group
== 0)
760 g_b_init_get_security_descriptor_group
= 1;
761 hm_advapi32
= LoadLibrary ("Advapi32.dll");
762 s_pfn_Get_Security_Descriptor_Group
=
763 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
764 hm_advapi32
, "GetSecurityDescriptorGroup");
766 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
771 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
776 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor
,
777 LPBOOL lpbDaclPresent
,
779 LPBOOL lpbDaclDefaulted
)
781 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl
= NULL
;
782 HMODULE hm_advapi32
= NULL
;
783 if (is_windows_9x () == TRUE
)
788 if (g_b_init_get_security_descriptor_dacl
== 0)
790 g_b_init_get_security_descriptor_dacl
= 1;
791 hm_advapi32
= LoadLibrary ("Advapi32.dll");
792 s_pfn_Get_Security_Descriptor_Dacl
=
793 (GetSecurityDescriptorDacl_Proc
) GetProcAddress (
794 hm_advapi32
, "GetSecurityDescriptorDacl");
796 if (s_pfn_Get_Security_Descriptor_Dacl
== NULL
)
801 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor
,
802 lpbDaclPresent
, pDacl
,
807 is_valid_sid (PSID sid
)
809 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
810 HMODULE hm_advapi32
= NULL
;
811 if (is_windows_9x () == TRUE
)
815 if (g_b_init_is_valid_sid
== 0)
817 g_b_init_is_valid_sid
= 1;
818 hm_advapi32
= LoadLibrary ("Advapi32.dll");
820 (IsValidSid_Proc
) GetProcAddress (
821 hm_advapi32
, "IsValidSid");
823 if (s_pfn_Is_Valid_Sid
== NULL
)
827 return (s_pfn_Is_Valid_Sid (sid
));
831 equal_sid (PSID sid1
, PSID sid2
)
833 static EqualSid_Proc s_pfn_Equal_Sid
= NULL
;
834 HMODULE hm_advapi32
= NULL
;
835 if (is_windows_9x () == TRUE
)
839 if (g_b_init_equal_sid
== 0)
841 g_b_init_equal_sid
= 1;
842 hm_advapi32
= LoadLibrary ("Advapi32.dll");
844 (EqualSid_Proc
) GetProcAddress (
845 hm_advapi32
, "EqualSid");
847 if (s_pfn_Equal_Sid
== NULL
)
851 return (s_pfn_Equal_Sid (sid1
, sid2
));
855 get_length_sid (PSID sid
)
857 static GetLengthSid_Proc s_pfn_Get_Length_Sid
= NULL
;
858 HMODULE hm_advapi32
= NULL
;
859 if (is_windows_9x () == TRUE
)
863 if (g_b_init_get_length_sid
== 0)
865 g_b_init_get_length_sid
= 1;
866 hm_advapi32
= LoadLibrary ("Advapi32.dll");
867 s_pfn_Get_Length_Sid
=
868 (GetLengthSid_Proc
) GetProcAddress (
869 hm_advapi32
, "GetLengthSid");
871 if (s_pfn_Get_Length_Sid
== NULL
)
875 return (s_pfn_Get_Length_Sid (sid
));
879 copy_sid (DWORD destlen
, PSID dest
, PSID src
)
881 static CopySid_Proc s_pfn_Copy_Sid
= NULL
;
882 HMODULE hm_advapi32
= NULL
;
883 if (is_windows_9x () == TRUE
)
887 if (g_b_init_copy_sid
== 0)
889 g_b_init_copy_sid
= 1;
890 hm_advapi32
= LoadLibrary ("Advapi32.dll");
892 (CopySid_Proc
) GetProcAddress (
893 hm_advapi32
, "CopySid");
895 if (s_pfn_Copy_Sid
== NULL
)
899 return (s_pfn_Copy_Sid (destlen
, dest
, src
));
903 END: Wrapper functions around OpenProcessToken
904 and other functions in advapi32.dll that are only
905 supported in Windows NT / 2k / XP
909 get_native_system_info (LPSYSTEM_INFO lpSystemInfo
)
911 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info
= NULL
;
912 if (is_windows_9x () != TRUE
)
914 if (g_b_init_get_native_system_info
== 0)
916 g_b_init_get_native_system_info
= 1;
917 s_pfn_Get_Native_System_Info
=
918 (GetNativeSystemInfo_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
919 "GetNativeSystemInfo");
921 if (s_pfn_Get_Native_System_Info
!= NULL
)
922 s_pfn_Get_Native_System_Info (lpSystemInfo
);
925 lpSystemInfo
->dwNumberOfProcessors
= -1;
929 get_system_times (LPFILETIME lpIdleTime
,
930 LPFILETIME lpKernelTime
,
931 LPFILETIME lpUserTime
)
933 static GetSystemTimes_Proc s_pfn_Get_System_times
= NULL
;
934 if (is_windows_9x () == TRUE
)
938 if (g_b_init_get_system_times
== 0)
940 g_b_init_get_system_times
= 1;
941 s_pfn_Get_System_times
=
942 (GetSystemTimes_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
945 if (s_pfn_Get_System_times
== NULL
)
947 return (s_pfn_Get_System_times (lpIdleTime
, lpKernelTime
, lpUserTime
));
950 static BOOLEAN WINAPI
951 create_symbolic_link (LPTSTR lpSymlinkFilename
,
952 LPTSTR lpTargetFileName
,
955 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link
= NULL
;
958 if (is_windows_9x () == TRUE
)
963 if (g_b_init_create_symbolic_link
== 0)
965 g_b_init_create_symbolic_link
= 1;
967 s_pfn_Create_Symbolic_Link
=
968 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
969 "CreateSymbolicLinkW");
971 s_pfn_Create_Symbolic_Link
=
972 (CreateSymbolicLink_Proc
)GetProcAddress (GetModuleHandle ("kernel32.dll"),
973 "CreateSymbolicLinkA");
976 if (s_pfn_Create_Symbolic_Link
== NULL
)
982 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
984 /* If we were denied creation of the symlink, try again after
985 enabling the SeCreateSymbolicLinkPrivilege for our process. */
988 TOKEN_PRIVILEGES priv_current
;
990 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME
, TRUE
, &priv_current
))
992 retval
= s_pfn_Create_Symbolic_Link (lpSymlinkFilename
, lpTargetFileName
,
994 restore_privilege (&priv_current
);
1002 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor
)
1004 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc
= NULL
;
1006 if (is_windows_9x () == TRUE
)
1012 if (g_b_init_is_valid_security_descriptor
== 0)
1014 g_b_init_is_valid_security_descriptor
= 1;
1015 s_pfn_Is_Valid_Security_Descriptor_Proc
=
1016 (IsValidSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1017 "IsValidSecurityDescriptor");
1019 if (s_pfn_Is_Valid_Security_Descriptor_Proc
== NULL
)
1025 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor
);
1029 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor
,
1030 DWORD RequestedStringSDRevision
,
1031 SECURITY_INFORMATION SecurityInformation
,
1032 LPTSTR
*StringSecurityDescriptor
,
1033 PULONG StringSecurityDescriptorLen
)
1035 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL
= NULL
;
1038 if (is_windows_9x () == TRUE
)
1044 if (g_b_init_convert_sd_to_sddl
== 0)
1046 g_b_init_convert_sd_to_sddl
= 1;
1048 s_pfn_Convert_SD_To_SDDL
=
1049 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1050 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1052 s_pfn_Convert_SD_To_SDDL
=
1053 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1054 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1057 if (s_pfn_Convert_SD_To_SDDL
== NULL
)
1063 retval
= s_pfn_Convert_SD_To_SDDL (SecurityDescriptor
,
1064 RequestedStringSDRevision
,
1065 SecurityInformation
,
1066 StringSecurityDescriptor
,
1067 StringSecurityDescriptorLen
);
1073 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor
,
1074 DWORD StringSDRevision
,
1075 PSECURITY_DESCRIPTOR
*SecurityDescriptor
,
1076 PULONG SecurityDescriptorSize
)
1078 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD
= NULL
;
1081 if (is_windows_9x () == TRUE
)
1087 if (g_b_init_convert_sddl_to_sd
== 0)
1089 g_b_init_convert_sddl_to_sd
= 1;
1091 s_pfn_Convert_SDDL_To_SD
=
1092 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1093 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1095 s_pfn_Convert_SDDL_To_SD
=
1096 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc
)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1097 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1100 if (s_pfn_Convert_SDDL_To_SD
== NULL
)
1106 retval
= s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor
,
1109 SecurityDescriptorSize
);
1116 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1117 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1119 This is called from alloc.c:valid_pointer_p. */
1121 w32_valid_pointer_p (void *p
, int size
)
1124 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
1128 unsigned char *buf
= alloca (size
);
1129 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
1138 static char startup_dir
[MAXPATHLEN
];
1140 /* Get the current working directory. */
1142 getcwd (char *dir
, int dirsize
)
1149 if (dirsize
<= strlen (startup_dir
))
1155 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
1159 /* Emacs doesn't actually change directory itself, it stays in the
1160 same directory where it was started. */
1161 strcpy (dir
, startup_dir
);
1166 /* Emulate getloadavg. */
1168 struct load_sample
{
1175 /* Number of processors on this machine. */
1176 static unsigned num_of_processors
;
1178 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1179 static struct load_sample samples
[16*60];
1180 static int first_idx
= -1, last_idx
= -1;
1181 static int max_idx
= sizeof (samples
) / sizeof (samples
[0]);
1186 int next_idx
= from
+ 1;
1188 if (next_idx
>= max_idx
)
1197 int prev_idx
= from
- 1;
1200 prev_idx
= max_idx
- 1;
1206 sample_system_load (ULONGLONG
*idle
, ULONGLONG
*kernel
, ULONGLONG
*user
)
1208 SYSTEM_INFO sysinfo
;
1209 FILETIME ft_idle
, ft_user
, ft_kernel
;
1211 /* Initialize the number of processors on this machine. */
1212 if (num_of_processors
<= 0)
1214 get_native_system_info (&sysinfo
);
1215 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1216 if (num_of_processors
<= 0)
1218 GetSystemInfo (&sysinfo
);
1219 num_of_processors
= sysinfo
.dwNumberOfProcessors
;
1221 if (num_of_processors
<= 0)
1222 num_of_processors
= 1;
1225 /* TODO: Take into account threads that are ready to run, by
1226 sampling the "\System\Processor Queue Length" performance
1227 counter. The code below accounts only for threads that are
1228 actually running. */
1230 if (get_system_times (&ft_idle
, &ft_kernel
, &ft_user
))
1232 ULARGE_INTEGER uidle
, ukernel
, uuser
;
1234 memcpy (&uidle
, &ft_idle
, sizeof (ft_idle
));
1235 memcpy (&ukernel
, &ft_kernel
, sizeof (ft_kernel
));
1236 memcpy (&uuser
, &ft_user
, sizeof (ft_user
));
1237 *idle
= uidle
.QuadPart
;
1238 *kernel
= ukernel
.QuadPart
;
1239 *user
= uuser
.QuadPart
;
1249 /* Produce the load average for a given time interval, using the
1250 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1251 1-minute, 5-minute, or 15-minute average, respectively. */
1255 double retval
= -1.0;
1258 double span
= (which
== 0 ? 1.0 : (which
== 1 ? 5.0 : 15.0)) * 60;
1259 time_t now
= samples
[last_idx
].sample_time
;
1261 if (first_idx
!= last_idx
)
1263 for (idx
= buf_prev (last_idx
); ; idx
= buf_prev (idx
))
1265 tdiff
= difftime (now
, samples
[idx
].sample_time
);
1266 if (tdiff
>= span
- 2*DBL_EPSILON
*now
)
1269 samples
[last_idx
].kernel
+ samples
[last_idx
].user
1270 - (samples
[idx
].kernel
+ samples
[idx
].user
);
1271 long double idl
= samples
[last_idx
].idle
- samples
[idx
].idle
;
1273 retval
= (1.0 - idl
/ sys
) * num_of_processors
;
1276 if (idx
== first_idx
)
1285 getloadavg (double loadavg
[], int nelem
)
1288 ULONGLONG idle
, kernel
, user
;
1289 time_t now
= time (NULL
);
1291 /* Store another sample. We ignore samples that are less than 1 sec
1293 if (difftime (now
, samples
[last_idx
].sample_time
) >= 1.0 - 2*DBL_EPSILON
*now
)
1295 sample_system_load (&idle
, &kernel
, &user
);
1296 last_idx
= buf_next (last_idx
);
1297 samples
[last_idx
].sample_time
= now
;
1298 samples
[last_idx
].idle
= idle
;
1299 samples
[last_idx
].kernel
= kernel
;
1300 samples
[last_idx
].user
= user
;
1301 /* If the buffer has more that 15 min worth of samples, discard
1303 if (first_idx
== -1)
1304 first_idx
= last_idx
;
1305 while (first_idx
!= last_idx
1306 && (difftime (now
, samples
[first_idx
].sample_time
)
1307 >= 15.0*60 + 2*DBL_EPSILON
*now
))
1308 first_idx
= buf_next (first_idx
);
1311 for (elem
= 0; elem
< nelem
; elem
++)
1313 double avg
= getavg (elem
);
1317 loadavg
[elem
] = avg
;
1323 /* Emulate getpwuid, getpwnam and others. */
1325 #define PASSWD_FIELD_SIZE 256
1327 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
1328 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
1329 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
1330 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
1331 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
1333 static struct passwd dflt_passwd
=
1345 static char dflt_group_name
[GNLEN
+1];
1347 static struct group dflt_group
=
1349 /* When group information is not available, we return this as the
1350 group for all files. */
1358 return dflt_passwd
.pw_uid
;
1364 /* I could imagine arguing for checking to see whether the user is
1365 in the Administrators group and returning a UID of 0 for that
1366 case, but I don't know how wise that would be in the long run. */
1373 return dflt_passwd
.pw_gid
;
1383 getpwuid (unsigned uid
)
1385 if (uid
== dflt_passwd
.pw_uid
)
1386 return &dflt_passwd
;
1391 getgrgid (gid_t gid
)
1397 getpwnam (char *name
)
1401 pw
= getpwuid (getuid ());
1405 if (xstrcasecmp (name
, pw
->pw_name
))
1412 init_user_info (void)
1414 /* Find the user's real name by opening the process token and
1415 looking up the name associated with the user-sid in that token.
1417 Use the relative portion of the identifier authority value from
1418 the user-sid as the user id value (same for group id using the
1419 primary group sid from the process token). */
1421 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
1422 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
1423 DWORD glength
= sizeof (gname
);
1424 HANDLE token
= NULL
;
1425 SID_NAME_USE user_type
;
1426 unsigned char *buf
= NULL
;
1428 TOKEN_USER user_token
;
1429 TOKEN_PRIMARY_GROUP group_token
;
1432 result
= open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
);
1435 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
1436 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1438 buf
= xmalloc (blen
);
1439 result
= get_token_information (token
, TokenUser
,
1440 (LPVOID
)buf
, blen
, &needed
);
1443 memcpy (&user_token
, buf
, sizeof (user_token
));
1444 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
1446 domain
, &dlength
, &user_type
);
1454 strcpy (dflt_passwd
.pw_name
, uname
);
1455 /* Determine a reasonable uid value. */
1456 if (xstrcasecmp ("administrator", uname
) == 0)
1458 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
1459 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
1463 /* Use the last sub-authority value of the RID, the relative
1464 portion of the SID, as user/group ID. */
1465 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
1467 /* Get group id and name. */
1468 result
= get_token_information (token
, TokenPrimaryGroup
,
1469 (LPVOID
)buf
, blen
, &needed
);
1470 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
1472 buf
= xrealloc (buf
, blen
= needed
);
1473 result
= get_token_information (token
, TokenPrimaryGroup
,
1474 (LPVOID
)buf
, blen
, &needed
);
1478 memcpy (&group_token
, buf
, sizeof (group_token
));
1479 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
1480 dlength
= sizeof (domain
);
1481 /* If we can get at the real Primary Group name, use that.
1482 Otherwise, the default group name was already set to
1483 "None" in globals_of_w32. */
1484 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
1485 gname
, &glength
, NULL
, &dlength
,
1487 strcpy (dflt_group_name
, gname
);
1490 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1493 /* If security calls are not supported (presumably because we
1494 are running under Windows 9X), fallback to this: */
1495 else if (GetUserName (uname
, &ulength
))
1497 strcpy (dflt_passwd
.pw_name
, uname
);
1498 if (xstrcasecmp ("administrator", uname
) == 0)
1499 dflt_passwd
.pw_uid
= 0;
1501 dflt_passwd
.pw_uid
= 123;
1502 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
1506 strcpy (dflt_passwd
.pw_name
, "unknown");
1507 dflt_passwd
.pw_uid
= 123;
1508 dflt_passwd
.pw_gid
= 123;
1510 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
1512 /* Ensure HOME and SHELL are defined. */
1513 if (getenv ("HOME") == NULL
)
1515 if (getenv ("SHELL") == NULL
)
1518 /* Set dir and shell from environment variables. */
1519 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
1520 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
1524 CloseHandle (token
);
1530 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1531 return ((rand () << 15) | rand ());
1540 /* Current codepage for encoding file names. */
1541 static int file_name_codepage
;
1543 /* Return the maximum length in bytes of a multibyte character
1544 sequence encoded in the current ANSI codepage. This is required to
1545 correctly walk the encoded file names one character at a time. */
1547 max_filename_mbslen (void)
1549 /* A simple cache to avoid calling GetCPInfo every time we need to
1550 normalize a file name. The file-name encoding is not supposed to
1551 be changed too frequently, if ever. */
1552 static Lisp_Object last_file_name_encoding
;
1553 static int last_max_mbslen
;
1554 Lisp_Object current_encoding
;
1556 current_encoding
= Vfile_name_coding_system
;
1557 if (NILP (current_encoding
))
1558 current_encoding
= Vdefault_file_name_coding_system
;
1560 if (!EQ (last_file_name_encoding
, current_encoding
))
1564 last_file_name_encoding
= current_encoding
;
1565 /* Default to the current ANSI codepage. */
1566 file_name_codepage
= w32_ansi_code_page
;
1567 if (!NILP (current_encoding
))
1569 char *cpname
= SDATA (SYMBOL_NAME (current_encoding
));
1570 char *cp
= NULL
, *end
;
1573 if (strncmp (cpname
, "cp", 2) == 0)
1575 else if (strncmp (cpname
, "windows-", 8) == 0)
1581 cpnum
= strtol (cp
, &end
, 10);
1582 if (cpnum
&& *end
== '\0' && end
- cp
>= 2)
1583 file_name_codepage
= cpnum
;
1587 if (!file_name_codepage
)
1588 file_name_codepage
= CP_ACP
; /* CP_ACP = 0, but let's not assume that */
1590 if (!GetCPInfo (file_name_codepage
, &cp_info
))
1592 file_name_codepage
= CP_ACP
;
1593 if (!GetCPInfo (file_name_codepage
, &cp_info
))
1596 last_max_mbslen
= cp_info
.MaxCharSize
;
1599 return last_max_mbslen
;
1602 /* Normalize filename by converting all path separators to
1603 the specified separator. Also conditionally convert upper
1604 case path name components to lower case. */
1607 normalize_filename (register char *fp
, char path_sep
, int multibyte
)
1611 int dbcs_p
= max_filename_mbslen () > 1;
1613 /* Multibyte file names are in the Emacs internal representation, so
1614 we can traverse them by bytes with no problems. */
1618 /* Always lower-case drive letters a-z, even if the filesystem
1619 preserves case in filenames.
1620 This is so filenames can be compared by string comparison
1621 functions that are case-sensitive. Even case-preserving filesystems
1622 do not distinguish case in drive letters. */
1624 p2
= CharNextExA (file_name_codepage
, fp
, 0);
1628 if (*p2
== ':' && *fp
>= 'A' && *fp
<= 'Z')
1634 if (multibyte
|| NILP (Vw32_downcase_file_names
))
1638 if (*fp
== '/' || *fp
== '\\')
1643 fp
= CharNextExA (file_name_codepage
, fp
, 0);
1648 sep
= path_sep
; /* convert to this path separator */
1649 elem
= fp
; /* start of current path element */
1652 if (*fp
>= 'a' && *fp
<= 'z')
1653 elem
= 0; /* don't convert this element */
1655 if (*fp
== 0 || *fp
== ':')
1657 sep
= *fp
; /* restore current separator (or 0) */
1658 *fp
= '/'; /* after conversion of this element */
1661 if (*fp
== '/' || *fp
== '\\')
1663 if (elem
&& elem
!= fp
)
1665 *fp
= 0; /* temporary end of string */
1666 _mbslwr (elem
); /* while we convert to lower case */
1668 *fp
= sep
; /* convert (or restore) path separator */
1669 elem
= fp
+ 1; /* next element starts after separator */
1677 fp
= CharNextExA (file_name_codepage
, fp
, 0);
1682 /* Destructively turn backslashes into slashes. MULTIBYTE non-zero
1683 means the file name is a multibyte string in Emacs's internal
1686 dostounix_filename (register char *p
, int multibyte
)
1688 normalize_filename (p
, '/', multibyte
);
1691 /* Destructively turn slashes into backslashes. */
1693 unixtodos_filename (register char *p
)
1695 normalize_filename (p
, '\\', 0);
1698 /* Remove all CR's that are followed by a LF.
1699 (From msdos.c...probably should figure out a way to share it,
1700 although this code isn't going to ever change.) */
1702 crlf_to_lf (register int n
, register unsigned char *buf
)
1704 unsigned char *np
= buf
;
1705 unsigned char *startp
= buf
;
1706 unsigned char *endp
= buf
+ n
;
1710 while (buf
< endp
- 1)
1714 if (*(++buf
) != 0x0a)
1725 /* Parse the root part of file name, if present. Return length and
1726 optionally store pointer to char after root. */
1728 parse_root (char * name
, char ** pPath
)
1730 char * start
= name
;
1735 /* find the root name of the volume if given */
1736 if (isalpha (name
[0]) && name
[1] == ':')
1738 /* skip past drive specifier */
1740 if (IS_DIRECTORY_SEP (name
[0]))
1743 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1746 int dbcs_p
= max_filename_mbslen () > 1;
1751 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1754 name
= CharNextExA (file_name_codepage
, name
, 0);
1759 if (IS_DIRECTORY_SEP (name
[0]))
1766 return name
- start
;
1769 /* Get long base name for name; name is assumed to be absolute. */
1771 get_long_basename (char * name
, char * buf
, int size
)
1773 WIN32_FIND_DATA find_data
;
1777 /* must be valid filename, no wild cards or other invalid characters */
1778 if (_mbspbrk (name
, "*?|<>\""))
1781 dir_handle
= FindFirstFile (name
, &find_data
);
1782 if (dir_handle
!= INVALID_HANDLE_VALUE
)
1784 if ((len
= strlen (find_data
.cFileName
)) < size
)
1785 memcpy (buf
, find_data
.cFileName
, len
+ 1);
1788 FindClose (dir_handle
);
1793 /* Get long name for file, if possible (assumed to be absolute). */
1795 w32_get_long_filename (char * name
, char * buf
, int size
)
1800 char full
[ MAX_PATH
];
1803 len
= strlen (name
);
1804 if (len
>= MAX_PATH
)
1807 /* Use local copy for destructive modification. */
1808 memcpy (full
, name
, len
+1);
1809 unixtodos_filename (full
);
1811 /* Copy root part verbatim. */
1812 len
= parse_root (full
, &p
);
1813 memcpy (o
, full
, len
);
1818 while (p
!= NULL
&& *p
)
1821 p
= _mbschr (q
, '\\');
1823 len
= get_long_basename (full
, o
, size
);
1846 is_unc_volume (const char *filename
)
1848 const char *ptr
= filename
;
1850 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1853 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1859 /* Emulate the Posix unsetenv. */
1861 unsetenv (const char *name
)
1867 if (name
== NULL
|| *name
== '\0' || strchr (name
, '=') != NULL
)
1872 name_len
= strlen (name
);
1873 /* MS docs says an environment variable cannot be longer than 32K. */
1874 if (name_len
> 32767)
1879 /* It is safe to use 'alloca' with 32K size, since the stack is at
1880 least 2MB, and we set it to 8MB in the link command line. */
1881 var
= alloca (name_len
+ 2);
1882 strncpy (var
, name
, name_len
);
1883 var
[name_len
++] = '=';
1884 var
[name_len
] = '\0';
1885 return _putenv (var
);
1888 /* MS _putenv doesn't support removing a variable when the argument
1889 does not include the '=' character, so we fix that here. */
1891 sys_putenv (char *str
)
1893 const char *const name_end
= strchr (str
, '=');
1895 if (name_end
== NULL
)
1897 /* Remove the variable from the environment. */
1898 return unsetenv (str
);
1901 return _putenv (str
);
1904 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1907 w32_get_resource (char *key
, LPDWORD lpdwtype
)
1910 HKEY hrootkey
= NULL
;
1913 /* Check both the current user and the local machine to see if
1914 we have any resources. */
1916 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1920 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1921 && (lpvalue
= xmalloc (cbData
)) != NULL
1922 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1924 RegCloseKey (hrootkey
);
1930 RegCloseKey (hrootkey
);
1933 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, 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
);
1953 char *get_emacs_configuration (void);
1956 init_environment (char ** argv
)
1958 static const char * const tempdirs
[] = {
1959 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1964 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1966 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1967 temporary files and assume "/tmp" if $TMPDIR is unset, which
1968 will break on DOS/Windows. Refuse to work if we cannot find
1969 a directory, not even "c:/", usable for that purpose. */
1970 for (i
= 0; i
< imax
; i
++)
1972 const char *tmp
= tempdirs
[i
];
1975 tmp
= getenv (tmp
+ 1);
1976 /* Note that `access' can lie to us if the directory resides on a
1977 read-only filesystem, like CD-ROM or a write-protected floppy.
1978 The only way to be really sure is to actually create a file and
1979 see if it succeeds. But I think that's too much to ask. */
1981 /* MSVCRT's _access crashes with D_OK. */
1982 if (tmp
&& faccessat (AT_FDCWD
, tmp
, D_OK
, AT_EACCESS
) == 0)
1984 char * var
= alloca (strlen (tmp
) + 8);
1985 sprintf (var
, "TMPDIR=%s", tmp
);
1986 _putenv (strdup (var
));
1993 Fcons (build_string ("no usable temporary directories found!!"),
1995 "While setting TMPDIR: ");
1997 /* Check for environment variables and use registry settings if they
1998 don't exist. Fallback on default values where applicable. */
2003 char locale_name
[32];
2004 char default_home
[MAX_PATH
];
2007 static const struct env_entry
2013 /* If the default value is NULL, we will use the value from the
2014 outside environment or the Registry, but will not push the
2015 variable into the Emacs environment if it is defined neither
2016 in the Registry nor in the outside environment. */
2018 {"PRELOAD_WINSOCK", NULL
},
2019 {"emacs_dir", "C:/emacs"},
2020 {"EMACSLOADPATH", NULL
},
2021 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
2022 {"EMACSDATA", NULL
},
2023 {"EMACSPATH", NULL
},
2030 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2032 /* We need to copy dflt_envvars[] and work on the copy because we
2033 don't want the dumped Emacs to inherit the values of
2034 environment variables we saw during dumping (which could be on
2035 a different system). The defaults above must be left intact. */
2036 struct env_entry env_vars
[N_ENV_VARS
];
2038 for (i
= 0; i
< N_ENV_VARS
; i
++)
2039 env_vars
[i
] = dflt_envvars
[i
];
2041 /* For backwards compatibility, check if a .emacs file exists in C:/
2042 If not, then we can try to default to the appdata directory under the
2043 user's profile, which is more likely to be writable. */
2044 if (!check_existing ("C:/.emacs"))
2046 HRESULT profile_result
;
2047 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2048 of Windows 95 and NT4 that have not been updated to include
2050 ShGetFolderPath_fn get_folder_path
;
2051 get_folder_path
= (ShGetFolderPath_fn
)
2052 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2054 if (get_folder_path
!= NULL
)
2056 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
2059 /* If we can't get the appdata dir, revert to old behavior. */
2060 if (profile_result
== S_OK
)
2062 env_vars
[0].def_value
= default_home
;
2068 /* Get default locale info and use it for LANG. */
2069 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
2070 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
2071 locale_name
, sizeof (locale_name
)))
2073 for (i
= 0; i
< N_ENV_VARS
; i
++)
2075 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
2077 env_vars
[i
].def_value
= locale_name
;
2083 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2085 /* Treat emacs_dir specially: set it unconditionally based on our
2089 char modname
[MAX_PATH
];
2091 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2093 if ((p
= _mbsrchr (modname
, '\\')) == NULL
)
2097 if ((p
= _mbsrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
2099 char buf
[SET_ENV_BUF_SIZE
];
2102 for (p
= modname
; *p
; p
= CharNext (p
))
2103 if (*p
== '\\') *p
= '/';
2105 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
2106 _putenv (strdup (buf
));
2108 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
2110 /* FIXME: should use substring of get_emacs_configuration ().
2111 But I don't think the Windows build supports alpha, mips etc
2112 anymore, so have taken the easy option for now. */
2113 else if (p
&& (xstrcasecmp (p
, "\\i386") == 0
2114 || xstrcasecmp (p
, "\\AMD64") == 0))
2117 p
= _mbsrchr (modname
, '\\');
2121 p
= _mbsrchr (modname
, '\\');
2122 if (p
&& xstrcasecmp (p
, "\\src") == 0)
2124 char buf
[SET_ENV_BUF_SIZE
];
2127 for (p
= modname
; *p
; p
= CharNext (p
))
2128 if (*p
== '\\') *p
= '/';
2130 _snprintf (buf
, sizeof (buf
)-1, "emacs_dir=%s", modname
);
2131 _putenv (strdup (buf
));
2137 for (i
= 0; i
< N_ENV_VARS
; i
++)
2139 if (!getenv (env_vars
[i
].name
))
2143 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
2144 /* Also ignore empty environment variables. */
2148 lpval
= env_vars
[i
].def_value
;
2149 dwType
= REG_EXPAND_SZ
;
2151 if (!strcmp (env_vars
[i
].name
, "HOME") && !appdata
)
2152 Vdelayed_warnings_list
2153 = Fcons (listn (CONSTYPE_HEAP
, 2,
2154 intern ("initialization"),
2155 build_string ("Setting HOME to C:\\ by default is deprecated")),
2156 Vdelayed_warnings_list
);
2161 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
2163 if (dwType
== REG_EXPAND_SZ
)
2164 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof (buf1
));
2165 else if (dwType
== REG_SZ
)
2166 strcpy (buf1
, lpval
);
2167 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
2169 _snprintf (buf2
, sizeof (buf2
)-1, "%s=%s", env_vars
[i
].name
,
2171 _putenv (strdup (buf2
));
2181 /* Rebuild system configuration to reflect invoking system. */
2182 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
2184 /* Another special case: on NT, the PATH variable is actually named
2185 "Path" although cmd.exe (perhaps NT itself) arranges for
2186 environment variable lookup and setting to be case insensitive.
2187 However, Emacs assumes a fully case sensitive environment, so we
2188 need to change "Path" to "PATH" to match the expectations of
2189 various elisp packages. We do this by the sneaky method of
2190 modifying the string in the C runtime environ entry.
2192 The same applies to COMSPEC. */
2196 for (envp
= environ
; *envp
; envp
++)
2197 if (_strnicmp (*envp
, "PATH=", 5) == 0)
2198 memcpy (*envp
, "PATH=", 5);
2199 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
2200 memcpy (*envp
, "COMSPEC=", 8);
2203 /* Remember the initial working directory for getcwd. */
2204 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2205 Does it matter anywhere in Emacs? */
2206 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
2210 static char modname
[MAX_PATH
];
2212 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
2217 /* Determine if there is a middle mouse button, to allow parse_button
2218 to decide whether right mouse events should be mouse-2 or
2220 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
2225 /* Called from expand-file-name when default-directory is not a string. */
2228 emacs_root_dir (void)
2230 static char root_dir
[FILENAME_MAX
];
2233 p
= getenv ("emacs_dir");
2236 strcpy (root_dir
, p
);
2237 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
2238 dostounix_filename (root_dir
, 0);
2242 /* We don't have scripts to automatically determine the system configuration
2243 for Emacs before it's compiled, and we don't want to have to make the
2244 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
2248 get_emacs_configuration (void)
2250 char *arch
, *oem
, *os
;
2252 static char configuration_buffer
[32];
2254 /* Determine the processor type. */
2255 switch (get_processor_type ())
2258 #ifdef PROCESSOR_INTEL_386
2259 case PROCESSOR_INTEL_386
:
2260 case PROCESSOR_INTEL_486
:
2261 case PROCESSOR_INTEL_PENTIUM
:
2269 #ifdef PROCESSOR_AMD_X8664
2270 case PROCESSOR_AMD_X8664
:
2275 #ifdef PROCESSOR_MIPS_R2000
2276 case PROCESSOR_MIPS_R2000
:
2277 case PROCESSOR_MIPS_R3000
:
2278 case PROCESSOR_MIPS_R4000
:
2283 #ifdef PROCESSOR_ALPHA_21064
2284 case PROCESSOR_ALPHA_21064
:
2294 /* Use the OEM field to reflect the compiler/library combination. */
2296 #define COMPILER_NAME "msvc"
2299 #define COMPILER_NAME "mingw"
2301 #define COMPILER_NAME "unknown"
2304 oem
= COMPILER_NAME
;
2306 switch (osinfo_cache
.dwPlatformId
) {
2307 case VER_PLATFORM_WIN32_NT
:
2309 build_num
= osinfo_cache
.dwBuildNumber
;
2311 case VER_PLATFORM_WIN32_WINDOWS
:
2312 if (osinfo_cache
.dwMinorVersion
== 0) {
2317 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
2319 case VER_PLATFORM_WIN32s
:
2320 /* Not supported, should not happen. */
2322 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
2330 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
2331 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
2332 get_w32_major_version (), get_w32_minor_version (), build_num
);
2334 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
2337 return configuration_buffer
;
2341 get_emacs_configuration_options (void)
2343 static char *options_buffer
;
2344 char cv
[32]; /* Enough for COMPILER_VERSION. */
2346 cv
, /* To be filled later. */
2350 #ifdef ENABLE_CHECKING
2351 " --enable-checking",
2353 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2354 with a starting space to save work here. */
2356 " --cflags", USER_CFLAGS
,
2359 " --ldflags", USER_LDFLAGS
,
2366 /* Work out the effective configure options for this build. */
2368 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2371 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2373 #define COMPILER_VERSION ""
2377 if (_snprintf (cv
, sizeof (cv
) - 1, COMPILER_VERSION
) < 0)
2378 return "Error: not enough space for compiler version";
2379 cv
[sizeof (cv
) - 1] = '\0';
2381 for (i
= 0; options
[i
]; i
++)
2382 size
+= strlen (options
[i
]);
2384 options_buffer
= xmalloc (size
+ 1);
2385 options_buffer
[0] = '\0';
2387 for (i
= 0; options
[i
]; i
++)
2388 strcat (options_buffer
, options
[i
]);
2390 return options_buffer
;
2394 #include <sys/timeb.h>
2396 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2398 gettimeofday (struct timeval
*restrict tv
, struct timezone
*restrict tz
)
2403 tv
->tv_sec
= tb
.time
;
2404 tv
->tv_usec
= tb
.millitm
* 1000L;
2405 /* Implementation note: _ftime sometimes doesn't update the dstflag
2406 according to the new timezone when the system timezone is
2407 changed. We could fix that by using GetSystemTime and
2408 GetTimeZoneInformation, but that doesn't seem necessary, since
2409 Emacs always calls gettimeofday with the 2nd argument NULL (see
2410 current_emacs_time). */
2413 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
2414 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
2419 /* Emulate fdutimens. */
2421 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2422 TIMESPEC[0] and TIMESPEC[1], respectively.
2423 FD must be either negative -- in which case it is ignored --
2424 or a file descriptor that is open on FILE.
2425 If FD is nonnegative, then FILE can be NULL, which means
2426 use just futimes instead of utimes.
2427 If TIMESPEC is null, FAIL.
2428 Return 0 on success, -1 (setting errno) on failure. */
2431 fdutimens (int fd
, char const *file
, struct timespec
const timespec
[2])
2440 if (fd
< 0 && !file
)
2445 ut
.actime
= timespec
[0].tv_sec
;
2446 ut
.modtime
= timespec
[1].tv_sec
;
2448 return _futime (fd
, &ut
);
2450 return _utime (file
, &ut
);
2454 /* ------------------------------------------------------------------------- */
2455 /* IO support and wrapper functions for the Windows API. */
2456 /* ------------------------------------------------------------------------- */
2458 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2459 on network directories, so we handle that case here.
2460 (Ulrich Leodolter, 1/11/95). */
2462 sys_ctime (const time_t *t
)
2464 char *str
= (char *) ctime (t
);
2465 return (str
? str
: "Sun Jan 01 00:00:00 1970");
2468 /* Emulate sleep...we could have done this with a define, but that
2469 would necessitate including windows.h in the files that used it.
2470 This is much easier. */
2472 sys_sleep (int seconds
)
2474 Sleep (seconds
* 1000);
2477 /* Internal MSVC functions for low-level descriptor munging */
2478 extern int __cdecl
_set_osfhnd (int fd
, long h
);
2479 extern int __cdecl
_free_osfhnd (int fd
);
2481 /* parallel array of private info on file handles */
2482 filedesc fd_info
[ MAXDESC
];
2484 typedef struct volume_info_data
{
2485 struct volume_info_data
* next
;
2487 /* time when info was obtained */
2490 /* actual volume info */
2499 /* Global referenced by various functions. */
2500 static volume_info_data volume_info
;
2502 /* Vector to indicate which drives are local and fixed (for which cached
2503 data never expires). */
2504 static BOOL fixed_drives
[26];
2506 /* Consider cached volume information to be stale if older than 10s,
2507 at least for non-local drives. Info for fixed drives is never stale. */
2508 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2509 #define VOLINFO_STILL_VALID( root_dir, info ) \
2510 ( ( isalpha (root_dir[0]) && \
2511 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2512 || GetTickCount () - info->timestamp < 10000 )
2514 /* Cache support functions. */
2516 /* Simple linked list with linear search is sufficient. */
2517 static volume_info_data
*volume_cache
= NULL
;
2519 static volume_info_data
*
2520 lookup_volume_info (char * root_dir
)
2522 volume_info_data
* info
;
2524 for (info
= volume_cache
; info
; info
= info
->next
)
2525 if (xstrcasecmp (info
->root_dir
, root_dir
) == 0)
2531 add_volume_info (char * root_dir
, volume_info_data
* info
)
2533 info
->root_dir
= xstrdup (root_dir
);
2534 info
->next
= volume_cache
;
2535 volume_cache
= info
;
2539 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2540 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2541 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2542 static volume_info_data
*
2543 GetCachedVolumeInformation (char * root_dir
)
2545 volume_info_data
* info
;
2546 char default_root
[ MAX_PATH
];
2548 /* NULL for root_dir means use root from current directory. */
2549 if (root_dir
== NULL
)
2551 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
2553 parse_root (default_root
, &root_dir
);
2555 root_dir
= default_root
;
2558 /* Local fixed drives can be cached permanently. Removable drives
2559 cannot be cached permanently, since the volume name and serial
2560 number (if nothing else) can change. Remote drives should be
2561 treated as if they are removable, since there is no sure way to
2562 tell whether they are or not. Also, the UNC association of drive
2563 letters mapped to remote volumes can be changed at any time (even
2564 by other processes) without notice.
2566 As a compromise, so we can benefit from caching info for remote
2567 volumes, we use a simple expiry mechanism to invalidate cache
2568 entries that are more than ten seconds old. */
2571 /* No point doing this, because WNetGetConnection is even slower than
2572 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2573 GetDriveType is about the only call of this type which does not
2574 involve network access, and so is extremely quick). */
2576 /* Map drive letter to UNC if remote. */
2577 if (isalpha (root_dir
[0]) && !fixed
[DRIVE_INDEX (root_dir
[0])])
2579 char remote_name
[ 256 ];
2580 char drive
[3] = { root_dir
[0], ':' };
2582 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
2584 /* do something */ ;
2588 info
= lookup_volume_info (root_dir
);
2590 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
2598 /* Info is not cached, or is stale. */
2599 if (!GetVolumeInformation (root_dir
,
2600 name
, sizeof (name
),
2604 type
, sizeof (type
)))
2607 /* Cache the volume information for future use, overwriting existing
2608 entry if present. */
2611 info
= xmalloc (sizeof (volume_info_data
));
2612 add_volume_info (root_dir
, info
);
2620 info
->name
= xstrdup (name
);
2621 info
->serialnum
= serialnum
;
2622 info
->maxcomp
= maxcomp
;
2623 info
->flags
= flags
;
2624 info
->type
= xstrdup (type
);
2625 info
->timestamp
= GetTickCount ();
2631 /* Get information on the volume where NAME is held; set path pointer to
2632 start of pathname in NAME (past UNC header\volume header if present),
2633 if pPath is non-NULL.
2635 Note: if NAME includes symlinks, the information is for the volume
2636 of the symlink, not of its target. That's because, even though
2637 GetVolumeInformation returns information about the symlink target
2638 of its argument, we only pass the root directory to
2639 GetVolumeInformation, not the full NAME. */
2641 get_volume_info (const char * name
, const char ** pPath
)
2643 char temp
[MAX_PATH
];
2644 char *rootname
= NULL
; /* default to current volume */
2645 volume_info_data
* info
;
2650 /* Find the root name of the volume if given. */
2651 if (isalpha (name
[0]) && name
[1] == ':')
2659 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
2663 int dbcs_p
= max_filename_mbslen () > 1;
2668 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
2674 const char *p
= name
;
2676 name
= CharNextExA (file_name_codepage
, name
, 0);
2677 memcpy (str
, p
, name
- p
);
2690 info
= GetCachedVolumeInformation (rootname
);
2693 /* Set global referenced by other functions. */
2694 volume_info
= *info
;
2700 /* Determine if volume is FAT format (ie. only supports short 8.3
2701 names); also set path pointer to start of pathname in name, if
2702 pPath is non-NULL. */
2704 is_fat_volume (const char * name
, const char ** pPath
)
2706 if (get_volume_info (name
, pPath
))
2707 return (volume_info
.maxcomp
== 12);
2711 /* Map filename to a valid 8.3 name if necessary.
2712 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2714 map_w32_filename (const char * name
, const char ** pPath
)
2716 static char shortname
[MAX_PATH
];
2717 char * str
= shortname
;
2720 const char * save_name
= name
;
2722 if (strlen (name
) >= MAX_PATH
)
2724 /* Return a filename which will cause callers to fail. */
2725 strcpy (shortname
, "?");
2729 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
2731 register int left
= 8; /* maximum number of chars in part */
2732 register int extn
= 0; /* extension added? */
2733 register int dots
= 2; /* maximum number of dots allowed */
2736 *str
++ = *name
++; /* skip past UNC header */
2738 while ((c
= *name
++))
2745 *str
++ = (c
== ':' ? ':' : '\\');
2746 extn
= 0; /* reset extension flags */
2747 dots
= 2; /* max 2 dots */
2748 left
= 8; /* max length 8 for main part */
2753 /* Convert path components of the form .xxx to _xxx,
2754 but leave . and .. as they are. This allows .emacs
2755 to be read as _emacs, for example. */
2759 IS_DIRECTORY_SEP (*name
))
2774 extn
= 1; /* we've got an extension */
2775 left
= 3; /* 3 chars in extension */
2779 /* any embedded dots after the first are converted to _ */
2784 case '#': /* don't lose these, they're important */
2786 str
[-1] = c
; /* replace last character of part */
2791 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
2793 dots
= 0; /* started a path component */
2802 strcpy (shortname
, name
);
2803 unixtodos_filename (shortname
);
2807 *pPath
= shortname
+ (path
- save_name
);
2813 is_exec (const char * name
)
2815 char * p
= strrchr (name
, '.');
2818 && (xstrcasecmp (p
, ".exe") == 0 ||
2819 xstrcasecmp (p
, ".com") == 0 ||
2820 xstrcasecmp (p
, ".bat") == 0 ||
2821 xstrcasecmp (p
, ".cmd") == 0));
2824 /* Emulate the Unix directory procedures opendir, closedir,
2825 and readdir. We can't use the procedures supplied in sysdep.c,
2826 so we provide them here. */
2828 struct dirent dir_static
; /* simulated directory contents */
2829 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
2830 static int dir_is_fat
;
2831 static char dir_pathname
[MAXPATHLEN
+1];
2832 static WIN32_FIND_DATA dir_find_data
;
2834 /* Support shares on a network resource as subdirectories of a read-only
2836 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2837 static HANDLE
open_unc_volume (const char *);
2838 static char *read_unc_volume (HANDLE
, char *, int);
2839 static void close_unc_volume (HANDLE
);
2842 opendir (const char *filename
)
2846 /* Opening is done by FindFirstFile. However, a read is inherent to
2847 this operation, so we defer the open until read time. */
2849 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2851 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2854 /* Note: We don't support traversal of UNC volumes via symlinks.
2855 Doing so would mean punishing 99.99% of use cases by resolving
2856 all the possible symlinks in FILENAME, recursively. */
2857 if (is_unc_volume (filename
))
2859 wnet_enum_handle
= open_unc_volume (filename
);
2860 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
2864 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
2871 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
2872 dir_pathname
[MAXPATHLEN
] = '\0';
2873 /* Note: We don't support symlinks to file names on FAT volumes.
2874 Doing so would mean punishing 99.99% of use cases by resolving
2875 all the possible symlinks in FILENAME, recursively. */
2876 dir_is_fat
= is_fat_volume (filename
, NULL
);
2882 closedir (DIR *dirp
)
2884 /* If we have a find-handle open, close it. */
2885 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
2887 FindClose (dir_find_handle
);
2888 dir_find_handle
= INVALID_HANDLE_VALUE
;
2890 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2892 close_unc_volume (wnet_enum_handle
);
2893 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2895 xfree ((char *) dirp
);
2901 int downcase
= !NILP (Vw32_downcase_file_names
);
2903 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2905 if (!read_unc_volume (wnet_enum_handle
,
2906 dir_find_data
.cFileName
,
2910 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2911 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2913 char filename
[MAXNAMLEN
+ 3];
2915 int dbcs_p
= max_filename_mbslen () > 1;
2917 strcpy (filename
, dir_pathname
);
2918 ln
= strlen (filename
) - 1;
2921 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2922 strcat (filename
, "\\");
2926 char *end
= filename
+ ln
+ 1;
2927 char *last_char
= CharPrevExA (file_name_codepage
, filename
, end
, 0);
2929 if (!IS_DIRECTORY_SEP (*last_char
))
2930 strcat (filename
, "\\");
2932 strcat (filename
, "*");
2934 /* Note: No need to resolve symlinks in FILENAME, because
2935 FindFirst opens the directory that is the target of a
2937 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2939 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2944 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2948 /* Emacs never uses this value, so don't bother making it match
2949 value returned by stat(). */
2950 dir_static
.d_ino
= 1;
2952 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2954 /* If the file name in cFileName[] includes `?' characters, it means
2955 the original file name used characters that cannot be represented
2956 by the current ANSI codepage. To avoid total lossage, retrieve
2957 the short 8+3 alias of the long file name. */
2958 if (_mbspbrk (dir_static
.d_name
, "?"))
2960 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2961 downcase
= 1; /* 8+3 aliases are returned in all caps */
2963 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2964 dir_static
.d_reclen
= sizeof (struct dirent
) - MAXNAMLEN
+ 3 +
2965 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2967 /* If the file name in cFileName[] includes `?' characters, it means
2968 the original file name used characters that cannot be represented
2969 by the current ANSI codepage. To avoid total lossage, retrieve
2970 the short 8+3 alias of the long file name. */
2971 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2973 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2974 /* 8+3 aliases are returned in all caps, which could break
2975 various alists that look at filenames' extensions. */
2979 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2980 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2982 _mbslwr (dir_static
.d_name
);
2986 int dbcs_p
= max_filename_mbslen () > 1;
2987 for (p
= dir_static
.d_name
; *p
; )
2989 if (*p
>= 'a' && *p
<= 'z')
2992 p
= CharNextExA (file_name_codepage
, p
, 0);
2997 _mbslwr (dir_static
.d_name
);
3004 open_unc_volume (const char *path
)
3010 nr
.dwScope
= RESOURCE_GLOBALNET
;
3011 nr
.dwType
= RESOURCETYPE_DISK
;
3012 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
3013 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
3014 nr
.lpLocalName
= NULL
;
3015 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
3016 nr
.lpComment
= NULL
;
3017 nr
.lpProvider
= NULL
;
3019 result
= WNetOpenEnum (RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
3020 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
3022 if (result
== NO_ERROR
)
3025 return INVALID_HANDLE_VALUE
;
3029 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
3033 DWORD bufsize
= 512;
3036 int dbcs_p
= max_filename_mbslen () > 1;
3039 buffer
= alloca (bufsize
);
3040 result
= WNetEnumResource (henum
, &count
, buffer
, &bufsize
);
3041 if (result
!= NO_ERROR
)
3044 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3045 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
3048 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
3051 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
))
3052 ptr
= CharNextExA (file_name_codepage
, ptr
, 0);
3056 strncpy (readbuf
, ptr
, size
);
3061 close_unc_volume (HANDLE henum
)
3063 if (henum
!= INVALID_HANDLE_VALUE
)
3064 WNetCloseEnum (henum
);
3068 unc_volume_file_attributes (const char *path
)
3073 henum
= open_unc_volume (path
);
3074 if (henum
== INVALID_HANDLE_VALUE
)
3077 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
3079 close_unc_volume (henum
);
3084 /* Ensure a network connection is authenticated. */
3086 logon_network_drive (const char *path
)
3088 NETRESOURCE resource
;
3089 char share
[MAX_PATH
];
3096 if (IS_DIRECTORY_SEP (path
[0]) && IS_DIRECTORY_SEP (path
[1]))
3097 drvtype
= DRIVE_REMOTE
;
3098 else if (path
[0] == '\0' || path
[1] != ':')
3099 drvtype
= GetDriveType (NULL
);
3106 drvtype
= GetDriveType (drive
);
3109 /* Only logon to networked drives. */
3110 if (drvtype
!= DRIVE_REMOTE
)
3114 strncpy (share
, path
, MAX_PATH
);
3115 /* Truncate to just server and share name. */
3116 dbcs_p
= max_filename_mbslen () > 1;
3117 for (p
= share
+ 2; *p
&& p
< share
+ MAX_PATH
; )
3119 if (IS_DIRECTORY_SEP (*p
) && ++n_slashes
> 3)
3125 p
= CharNextExA (file_name_codepage
, p
, 0);
3130 resource
.dwType
= RESOURCETYPE_DISK
;
3131 resource
.lpLocalName
= NULL
;
3132 resource
.lpRemoteName
= share
;
3133 resource
.lpProvider
= NULL
;
3135 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
3138 /* Emulate faccessat(2). */
3140 faccessat (int dirfd
, const char * path
, int mode
, int flags
)
3144 if (dirfd
!= AT_FDCWD
3145 && !(IS_DIRECTORY_SEP (path
[0])
3146 || IS_DEVICE_SEP (path
[1])))
3152 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3153 newer versions blow up when passed D_OK. */
3154 path
= map_w32_filename (path
, NULL
);
3155 /* If the last element of PATH is a symlink, we need to resolve it
3156 to get the attributes of its target file. Note: any symlinks in
3157 PATH elements other than the last one are transparently resolved
3158 by GetFileAttributes below. */
3159 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0
3160 && (flags
& AT_SYMLINK_NOFOLLOW
) == 0)
3161 path
= chase_symlinks (path
);
3163 if ((attributes
= GetFileAttributes (path
)) == -1)
3165 DWORD w32err
= GetLastError ();
3169 case ERROR_INVALID_NAME
:
3170 case ERROR_BAD_PATHNAME
:
3171 if (is_unc_volume (path
))
3173 attributes
= unc_volume_file_attributes (path
);
3174 if (attributes
== -1)
3182 case ERROR_FILE_NOT_FOUND
:
3183 case ERROR_BAD_NETPATH
:
3192 if ((mode
& X_OK
) != 0
3193 && !(is_exec (path
) || (attributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0))
3198 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
3203 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
3211 /* Shadow some MSVC runtime functions to map requests for long filenames
3212 to reasonable short names if necessary. This was originally added to
3213 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3217 sys_chdir (const char * path
)
3219 return _chdir (map_w32_filename (path
, NULL
));
3223 sys_chmod (const char * path
, int mode
)
3225 path
= chase_symlinks (map_w32_filename (path
, NULL
));
3226 return _chmod (path
, mode
);
3230 sys_creat (const char * path
, int mode
)
3232 return _creat (map_w32_filename (path
, NULL
), mode
);
3236 sys_fopen (const char * path
, const char * mode
)
3240 const char * mode_save
= mode
;
3242 /* Force all file handles to be non-inheritable. This is necessary to
3243 ensure child processes don't unwittingly inherit handles that might
3244 prevent future file access. */
3248 else if (mode
[0] == 'w' || mode
[0] == 'a')
3249 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
3253 /* Only do simplistic option parsing. */
3257 oflag
&= ~(O_RDONLY
| O_WRONLY
);
3260 else if (mode
[0] == 'b')
3265 else if (mode
[0] == 't')
3272 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
3276 return _fdopen (fd
, mode_save
);
3279 /* This only works on NTFS volumes, but is useful to have. */
3281 sys_link (const char * old
, const char * new)
3285 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
3287 if (old
== NULL
|| new == NULL
)
3293 strcpy (oldname
, map_w32_filename (old
, NULL
));
3294 strcpy (newname
, map_w32_filename (new, NULL
));
3296 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
3297 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
3298 if (fileh
!= INVALID_HANDLE_VALUE
)
3302 /* Confusingly, the "alternate" stream name field does not apply
3303 when restoring a hard link, and instead contains the actual
3304 stream data for the link (ie. the name of the link to create).
3305 The WIN32_STREAM_ID structure before the cStreamName field is
3306 the stream header, which is then immediately followed by the
3310 WIN32_STREAM_ID wid
;
3311 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
3314 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
3315 data
.wid
.cStreamName
, MAX_PATH
);
3318 LPVOID context
= NULL
;
3321 data
.wid
.dwStreamId
= BACKUP_LINK
;
3322 data
.wid
.dwStreamAttributes
= 0;
3323 data
.wid
.Size
.LowPart
= wlen
* sizeof (WCHAR
);
3324 data
.wid
.Size
.HighPart
= 0;
3325 data
.wid
.dwStreamNameSize
= 0;
3327 if (BackupWrite (fileh
, (LPBYTE
)&data
,
3328 offsetof (WIN32_STREAM_ID
, cStreamName
)
3329 + data
.wid
.Size
.LowPart
,
3330 &wbytes
, FALSE
, FALSE
, &context
)
3331 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
3338 /* Should try mapping GetLastError to errno; for now just
3339 indicate a general error (eg. links not supported). */
3340 errno
= EINVAL
; // perhaps EMLINK?
3344 CloseHandle (fileh
);
3353 sys_mkdir (const char * path
)
3355 return _mkdir (map_w32_filename (path
, NULL
));
3358 /* Because of long name mapping issues, we need to implement this
3359 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
3360 a unique name, instead of setting the input template to an empty
3363 Standard algorithm seems to be use pid or tid with a letter on the
3364 front (in place of the 6 X's) and cycle through the letters to find a
3365 unique name. We extend that to allow any reasonable character as the
3366 first of the 6 X's. */
3368 sys_mktemp (char * template)
3372 unsigned uid
= GetCurrentThreadId ();
3373 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3375 if (template == NULL
)
3377 p
= template + strlen (template);
3379 /* replace up to the last 5 X's with uid in decimal */
3380 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
3382 p
[0] = '0' + uid
% 10;
3386 if (i
< 0 && p
[0] == 'X')
3391 int save_errno
= errno
;
3392 p
[0] = first_char
[i
];
3393 if (faccessat (AT_FDCWD
, template, F_OK
, AT_EACCESS
) < 0)
3399 while (++i
< sizeof (first_char
));
3402 /* Template is badly formed or else we can't generate a unique name,
3403 so return empty string */
3409 sys_open (const char * path
, int oflag
, int mode
)
3411 const char* mpath
= map_w32_filename (path
, NULL
);
3414 /* If possible, try to open file without _O_CREAT, to be able to
3415 write to existing hidden and system files. Force all file
3416 handles to be non-inheritable. */
3417 if ((oflag
& (_O_CREAT
| _O_EXCL
)) != (_O_CREAT
| _O_EXCL
))
3418 res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
3420 res
= _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
3426 fchmod (int fd
, mode_t mode
)
3432 sys_rename_replace (const char *oldname
, const char *newname
, BOOL force
)
3435 char temp
[MAX_PATH
];
3439 /* MoveFile on Windows 95 doesn't correctly change the short file name
3440 alias in a number of circumstances (it is not easy to predict when
3441 just by looking at oldname and newname, unfortunately). In these
3442 cases, renaming through a temporary name avoids the problem.
3444 A second problem on Windows 95 is that renaming through a temp name when
3445 newname is uppercase fails (the final long name ends up in
3446 lowercase, although the short alias might be uppercase) UNLESS the
3447 long temp name is not 8.3.
3449 So, on Windows 95 we always rename through a temp name, and we make sure
3450 the temp name has a long extension to ensure correct renaming. */
3452 strcpy (temp
, map_w32_filename (oldname
, NULL
));
3454 /* volume_info is set indirectly by map_w32_filename. */
3455 oldname_dev
= volume_info
.serialnum
;
3457 if (os_subtype
== OS_9X
)
3463 oldname
= map_w32_filename (oldname
, NULL
);
3464 if ((o
= strrchr (oldname
, '\\')))
3467 o
= (char *) oldname
;
3469 if ((p
= strrchr (temp
, '\\')))
3476 /* Force temp name to require a manufactured 8.3 alias - this
3477 seems to make the second rename work properly. */
3478 sprintf (p
, "_.%s.%u", o
, i
);
3480 result
= rename (oldname
, temp
);
3482 /* This loop must surely terminate! */
3483 while (result
< 0 && errno
== EEXIST
);
3488 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3489 (at least if it is a file; don't do this for directories).
3491 Since we mustn't do this if we are just changing the case of the
3492 file name (we would end up deleting the file we are trying to
3493 rename!), we let rename detect if the destination file already
3494 exists - that way we avoid the possible pitfalls of trying to
3495 determine ourselves whether two names really refer to the same
3496 file, which is not always possible in the general case. (Consider
3497 all the permutations of shared or subst'd drives, etc.) */
3499 newname
= map_w32_filename (newname
, NULL
);
3501 /* volume_info is set indirectly by map_w32_filename. */
3502 newname_dev
= volume_info
.serialnum
;
3504 result
= rename (temp
, newname
);
3506 if (result
< 0 && force
)
3508 DWORD w32err
= GetLastError ();
3511 && newname_dev
!= oldname_dev
)
3513 /* The implementation of `rename' on Windows does not return
3514 errno = EXDEV when you are moving a directory to a
3515 different storage device (ex. logical disk). It returns
3516 EACCES instead. So here we handle such situations and
3520 if ((attributes
= GetFileAttributes (temp
)) != -1
3521 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3524 else if (errno
== EEXIST
)
3526 if (_chmod (newname
, 0666) != 0)
3528 if (_unlink (newname
) != 0)
3530 result
= rename (temp
, newname
);
3532 else if (w32err
== ERROR_PRIVILEGE_NOT_HELD
3533 && is_symlink (temp
))
3535 /* This is Windows prohibiting the user from creating a
3536 symlink in another place, since that requires
3546 sys_rename (char const *old
, char const *new)
3548 return sys_rename_replace (old
, new, TRUE
);
3552 sys_rmdir (const char * path
)
3554 return _rmdir (map_w32_filename (path
, NULL
));
3558 sys_unlink (const char * path
)
3560 path
= map_w32_filename (path
, NULL
);
3562 /* On Unix, unlink works without write permission. */
3563 _chmod (path
, 0666);
3564 return _unlink (path
);
3567 static FILETIME utc_base_ft
;
3568 static ULONGLONG utc_base
; /* In 100ns units */
3569 static int init
= 0;
3571 #define FILETIME_TO_U64(result, ft) \
3573 ULARGE_INTEGER uiTemp; \
3574 uiTemp.LowPart = (ft).dwLowDateTime; \
3575 uiTemp.HighPart = (ft).dwHighDateTime; \
3576 result = uiTemp.QuadPart; \
3580 initialize_utc_base (void)
3582 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3591 st
.wMilliseconds
= 0;
3593 SystemTimeToFileTime (&st
, &utc_base_ft
);
3594 FILETIME_TO_U64 (utc_base
, utc_base_ft
);
3598 convert_time (FILETIME ft
)
3604 initialize_utc_base ();
3608 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
3611 FILETIME_TO_U64 (tmp
, ft
);
3612 return (time_t) ((tmp
- utc_base
) / 10000000L);
3616 convert_from_time_t (time_t time
, FILETIME
* pft
)
3622 initialize_utc_base ();
3626 /* time in 100ns units since 1-Jan-1601 */
3627 tmp
.QuadPart
= (ULONGLONG
) time
* 10000000L + utc_base
;
3628 pft
->dwHighDateTime
= tmp
.HighPart
;
3629 pft
->dwLowDateTime
= tmp
.LowPart
;
3633 /* No reason to keep this; faking inode values either by hashing or even
3634 using the file index from GetInformationByHandle, is not perfect and
3635 so by default Emacs doesn't use the inode values on Windows.
3636 Instead, we now determine file-truename correctly (except for
3637 possible drive aliasing etc). */
3639 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3641 hashval (const unsigned char * str
)
3646 h
= (h
<< 4) + *str
++;
3652 /* Return the hash value of the canonical pathname, excluding the
3653 drive/UNC header, to get a hopefully unique inode number. */
3655 generate_inode_val (const char * name
)
3657 char fullname
[ MAX_PATH
];
3661 /* Get the truly canonical filename, if it exists. (Note: this
3662 doesn't resolve aliasing due to subst commands, or recognize hard
3664 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
3667 parse_root (fullname
, &p
);
3668 /* Normal W32 filesystems are still case insensitive. */
3675 static PSECURITY_DESCRIPTOR
3676 get_file_security_desc_by_handle (HANDLE h
)
3678 PSECURITY_DESCRIPTOR psd
= NULL
;
3680 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3681 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3683 err
= get_security_info (h
, SE_FILE_OBJECT
, si
,
3684 NULL
, NULL
, NULL
, NULL
, &psd
);
3685 if (err
!= ERROR_SUCCESS
)
3691 static PSECURITY_DESCRIPTOR
3692 get_file_security_desc_by_name (const char *fname
)
3694 PSECURITY_DESCRIPTOR psd
= NULL
;
3696 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
3697 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
3699 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
3701 err
= GetLastError ();
3702 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
3706 psd
= xmalloc (sd_len
);
3707 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
3719 unsigned n_subauthorities
;
3721 /* Use the last sub-authority value of the RID, the relative
3722 portion of the SID, as user/group ID. */
3723 n_subauthorities
= *get_sid_sub_authority_count (sid
);
3724 if (n_subauthorities
< 1)
3725 return 0; /* the "World" RID */
3726 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
3729 /* Caching SID and account values for faster lokup. */
3732 # define FLEXIBLE_ARRAY_MEMBER
3734 # define FLEXIBLE_ARRAY_MEMBER 1
3739 struct w32_id
*next
;
3741 unsigned char sid
[FLEXIBLE_ARRAY_MEMBER
];
3744 static struct w32_id
*w32_idlist
;
3747 w32_cached_id (PSID sid
, unsigned *id
, char *name
)
3749 struct w32_id
*tail
, *found
;
3751 for (found
= NULL
, tail
= w32_idlist
; tail
; tail
= tail
->next
)
3753 if (equal_sid ((PSID
)tail
->sid
, sid
))
3762 strcpy (name
, found
->name
);
3770 w32_add_to_cache (PSID sid
, unsigned id
, char *name
)
3773 struct w32_id
*new_entry
;
3775 /* We don't want to leave behind stale cache from when Emacs was
3779 sid_len
= get_length_sid (sid
);
3780 new_entry
= xmalloc (offsetof (struct w32_id
, sid
) + sid_len
);
3783 new_entry
->rid
= id
;
3784 strcpy (new_entry
->name
, name
);
3785 copy_sid (sid_len
, (PSID
)new_entry
->sid
, sid
);
3786 new_entry
->next
= w32_idlist
;
3787 w32_idlist
= new_entry
;
3796 get_name_and_id (PSECURITY_DESCRIPTOR psd
, unsigned *id
, char *nm
, int what
)
3800 SID_NAME_USE ignore
;
3802 DWORD name_len
= sizeof (name
);
3804 DWORD domain_len
= sizeof (domain
);
3809 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
3810 else if (what
== GID
)
3811 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
3815 if (!result
|| !is_valid_sid (sid
))
3817 else if (!w32_cached_id (sid
, id
, nm
))
3819 if (!lookup_account_sid (NULL
, sid
, name
, &name_len
,
3820 domain
, &domain_len
, &ignore
)
3821 || name_len
> UNLEN
+1)
3825 *id
= get_rid (sid
);
3827 w32_add_to_cache (sid
, *id
, name
);
3834 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd
, struct stat
*st
)
3836 int dflt_usr
= 0, dflt_grp
= 0;
3845 if (get_name_and_id (psd
, &st
->st_uid
, st
->st_uname
, UID
))
3847 if (get_name_and_id (psd
, &st
->st_gid
, st
->st_gname
, GID
))
3850 /* Consider files to belong to current user/group, if we cannot get
3851 more accurate information. */
3854 st
->st_uid
= dflt_passwd
.pw_uid
;
3855 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
3859 st
->st_gid
= dflt_passwd
.pw_gid
;
3860 strcpy (st
->st_gname
, dflt_group
.gr_name
);
3864 /* Return non-zero if NAME is a potentially slow filesystem. */
3866 is_slow_fs (const char *name
)
3871 if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
3872 devtype
= DRIVE_REMOTE
; /* assume UNC name is remote */
3873 else if (!(strlen (name
) >= 2 && IS_DEVICE_SEP (name
[1])))
3874 devtype
= GetDriveType (NULL
); /* use root of current drive */
3877 /* GetDriveType needs the root directory of the drive. */
3878 strncpy (drive_root
, name
, 2);
3879 drive_root
[2] = '\\';
3880 drive_root
[3] = '\0';
3881 devtype
= GetDriveType (drive_root
);
3883 return !(devtype
== DRIVE_FIXED
|| devtype
== DRIVE_RAMDISK
);
3886 /* If this is non-zero, the caller wants accurate information about
3887 file's owner and group, which could be expensive to get. */
3888 int w32_stat_get_owner_group
;
3890 /* MSVC stat function can't cope with UNC names and has other bugs, so
3891 replace it with our own. This also allows us to calculate consistent
3892 inode values and owner/group without hacks in the main Emacs code. */
3895 stat_worker (const char * path
, struct stat
* buf
, int follow_symlinks
)
3897 char *name
, *save_name
, *r
;
3898 WIN32_FIND_DATA wfd
;
3900 unsigned __int64 fake_inode
= 0;
3903 int rootdir
= FALSE
;
3904 PSECURITY_DESCRIPTOR psd
= NULL
;
3905 int is_a_symlink
= 0;
3906 DWORD file_flags
= FILE_FLAG_BACKUP_SEMANTICS
;
3907 DWORD access_rights
= 0;
3908 DWORD fattrs
= 0, serialnum
= 0, fs_high
= 0, fs_low
= 0, nlinks
= 1;
3909 FILETIME ctime
, atime
, wtime
;
3912 if (path
== NULL
|| buf
== NULL
)
3918 save_name
= name
= (char *) map_w32_filename (path
, &path
);
3919 /* Must be valid filename, no wild cards or other invalid
3920 characters. We use _mbspbrk to support multibyte strings that
3921 might look to strpbrk as if they included literal *, ?, and other
3922 characters mentioned below that are disallowed by Windows
3924 if (_mbspbrk (name
, "*?|<>\""))
3930 /* Remove trailing directory separator, unless name is the root
3931 directory of a drive or UNC volume in which case ensure there
3932 is a trailing separator. */
3933 len
= strlen (name
);
3934 name
= strcpy (alloca (len
+ 2), name
);
3936 /* Avoid a somewhat costly call to is_symlink if the filesystem
3937 doesn't support symlinks. */
3938 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
3939 is_a_symlink
= is_symlink (name
);
3941 /* Plan A: Open the file and get all the necessary information via
3942 the resulting handle. This solves several issues in one blow:
3944 . retrieves attributes for the target of a symlink, if needed
3945 . gets attributes of root directories and symlinks pointing to
3946 root directories, thus avoiding the need for special-casing
3947 these and detecting them by examining the file-name format
3948 . retrieves more accurate attributes (e.g., non-zero size for
3949 some directories, esp. directories that are junction points)
3950 . correctly resolves "c:/..", "/.." and similar file names
3951 . avoids run-time penalties for 99% of use cases
3953 Plan A is always tried first, unless the user asked not to (but
3954 if the file is a symlink and we need to follow links, we try Plan
3955 A even if the user asked not to).
3957 If Plan A fails, we go to Plan B (below), where various
3958 potentially expensive techniques must be used to handle "special"
3959 files such as UNC volumes etc. */
3960 if (!(NILP (Vw32_get_true_file_attributes
)
3961 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) && is_slow_fs (name
)))
3962 /* Following symlinks requires getting the info by handle. */
3963 || (is_a_symlink
&& follow_symlinks
))
3965 BY_HANDLE_FILE_INFORMATION info
;
3967 if (is_a_symlink
&& !follow_symlinks
)
3968 file_flags
|= FILE_FLAG_OPEN_REPARSE_POINT
;
3969 /* READ_CONTROL access rights are required to get security info
3970 by handle. But if the OS doesn't support security in the
3971 first place, we don't need to try. */
3972 if (is_windows_9x () != TRUE
)
3973 access_rights
|= READ_CONTROL
;
3975 fh
= CreateFile (name
, access_rights
, 0, NULL
, OPEN_EXISTING
,
3977 /* If CreateFile fails with READ_CONTROL, try again with zero as
3979 if (fh
== INVALID_HANDLE_VALUE
&& access_rights
)
3980 fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
3982 if (fh
== INVALID_HANDLE_VALUE
)
3983 goto no_true_file_attributes
;
3985 /* This is more accurate in terms of getting the correct number
3986 of links, but is quite slow (it is noticeable when Emacs is
3987 making a list of file name completions). */
3988 if (GetFileInformationByHandle (fh
, &info
))
3990 nlinks
= info
.nNumberOfLinks
;
3991 /* Might as well use file index to fake inode values, but this
3992 is not guaranteed to be unique unless we keep a handle open
3993 all the time (even then there are situations where it is
3994 not unique). Reputedly, there are at most 48 bits of info
3995 (on NTFS, presumably less on FAT). */
3996 fake_inode
= info
.nFileIndexHigh
;
3998 fake_inode
+= info
.nFileIndexLow
;
3999 serialnum
= info
.dwVolumeSerialNumber
;
4000 fs_high
= info
.nFileSizeHigh
;
4001 fs_low
= info
.nFileSizeLow
;
4002 ctime
= info
.ftCreationTime
;
4003 atime
= info
.ftLastAccessTime
;
4004 wtime
= info
.ftLastWriteTime
;
4005 fattrs
= info
.dwFileAttributes
;
4009 /* We don't go to Plan B here, because it's not clear that
4010 it's a good idea. The only known use case where
4011 CreateFile succeeds, but GetFileInformationByHandle fails
4012 (with ERROR_INVALID_FUNCTION) is for character devices
4013 such as NUL, PRN, etc. For these, switching to Plan B is
4014 a net loss, because we lose the character device
4015 attribute returned by GetFileType below (FindFirstFile
4016 doesn't set that bit in the attributes), and the other
4017 fields don't make sense for character devices anyway.
4018 Emacs doesn't really care for non-file entities in the
4019 context of l?stat, so neither do we. */
4021 /* w32err is assigned so one could put a breakpoint here and
4022 examine its value, when GetFileInformationByHandle
4024 DWORD w32err
= GetLastError ();
4028 case ERROR_FILE_NOT_FOUND
: /* can this ever happen? */
4034 /* Test for a symlink before testing for a directory, since
4035 symlinks to directories have the directory bit set, but we
4036 don't want them to appear as directories. */
4037 if (is_a_symlink
&& !follow_symlinks
)
4038 buf
->st_mode
= S_IFLNK
;
4039 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4040 buf
->st_mode
= S_IFDIR
;
4043 DWORD ftype
= GetFileType (fh
);
4047 case FILE_TYPE_DISK
:
4048 buf
->st_mode
= S_IFREG
;
4050 case FILE_TYPE_PIPE
:
4051 buf
->st_mode
= S_IFIFO
;
4053 case FILE_TYPE_CHAR
:
4054 case FILE_TYPE_UNKNOWN
:
4056 buf
->st_mode
= S_IFCHR
;
4059 /* We produce the fallback owner and group data, based on the
4060 current user that runs Emacs, in the following cases:
4062 . caller didn't request owner and group info
4063 . this is Windows 9X
4064 . getting security by handle failed, and we need to produce
4065 information for the target of a symlink (this is better
4066 than producing a potentially misleading info about the
4069 If getting security by handle fails, and we don't need to
4070 resolve symlinks, we try getting security by name. */
4071 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4072 get_file_owner_and_group (NULL
, buf
);
4075 psd
= get_file_security_desc_by_handle (fh
);
4078 get_file_owner_and_group (psd
, buf
);
4081 else if (!(is_a_symlink
&& follow_symlinks
))
4083 psd
= get_file_security_desc_by_name (name
);
4084 get_file_owner_and_group (psd
, buf
);
4088 get_file_owner_and_group (NULL
, buf
);
4094 no_true_file_attributes
:
4095 /* Plan B: Either getting a handle on the file failed, or the
4096 caller explicitly asked us to not bother making this
4097 information more accurate.
4099 Implementation note: In Plan B, we never bother to resolve
4100 symlinks, even if we got here because we tried Plan A and
4101 failed. That's because, even if the caller asked for extra
4102 precision by setting Vw32_get_true_file_attributes to t,
4103 resolving symlinks requires acquiring a file handle to the
4104 symlink, which we already know will fail. And if the user
4105 did not ask for extra precision, resolving symlinks will fly
4106 in the face of that request, since the user then wants the
4107 lightweight version of the code. */
4108 dbcs_p
= max_filename_mbslen () > 1;
4109 rootdir
= (path
>= save_name
+ len
- 1
4110 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
4112 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4113 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
4114 if (IS_DIRECTORY_SEP (r
[0])
4115 && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
4118 /* Note: If NAME is a symlink to the root of a UNC volume
4119 (i.e. "\\SERVER"), we will not detect that here, and we will
4120 return data about the symlink as result of FindFirst below.
4121 This is unfortunate, but that marginal use case does not
4122 justify a call to chase_symlinks which would impose a penalty
4123 on all the other use cases. (We get here for symlinks to
4124 roots of UNC volumes because CreateFile above fails for them,
4125 unlike with symlinks to root directories X:\ of drives.) */
4126 if (is_unc_volume (name
))
4128 fattrs
= unc_volume_file_attributes (name
);
4132 ctime
= atime
= wtime
= utc_base_ft
;
4138 if (!IS_DIRECTORY_SEP (name
[len
-1]))
4139 strcat (name
, "\\");
4143 char *end
= name
+ len
;
4144 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4146 if (!IS_DIRECTORY_SEP (*n
))
4147 strcat (name
, "\\");
4149 if (GetDriveType (name
) < 2)
4155 fattrs
= FILE_ATTRIBUTE_DIRECTORY
;
4156 ctime
= atime
= wtime
= utc_base_ft
;
4162 if (IS_DIRECTORY_SEP (name
[len
-1]))
4167 char *end
= name
+ len
;
4168 char *n
= CharPrevExA (file_name_codepage
, name
, end
, 0);
4170 if (IS_DIRECTORY_SEP (*n
))
4174 /* (This is hacky, but helps when doing file completions on
4175 network drives.) Optimize by using information available from
4176 active readdir if possible. */
4177 len
= strlen (dir_pathname
);
4180 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
4185 char *end
= dir_pathname
+ len
;
4186 char *n
= CharPrevExA (file_name_codepage
, dir_pathname
, end
, 0);
4188 if (IS_DIRECTORY_SEP (*n
))
4191 if (dir_find_handle
!= INVALID_HANDLE_VALUE
4192 && !(is_a_symlink
&& follow_symlinks
)
4193 && strnicmp (save_name
, dir_pathname
, len
) == 0
4194 && IS_DIRECTORY_SEP (name
[len
])
4195 && xstrcasecmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
4197 /* This was the last entry returned by readdir. */
4198 wfd
= dir_find_data
;
4202 logon_network_drive (name
);
4204 fh
= FindFirstFile (name
, &wfd
);
4205 if (fh
== INVALID_HANDLE_VALUE
)
4212 /* Note: if NAME is a symlink, the information we get from
4213 FindFirstFile is for the symlink, not its target. */
4214 fattrs
= wfd
.dwFileAttributes
;
4215 ctime
= wfd
.ftCreationTime
;
4216 atime
= wfd
.ftLastAccessTime
;
4217 wtime
= wfd
.ftLastWriteTime
;
4218 fs_high
= wfd
.nFileSizeHigh
;
4219 fs_low
= wfd
.nFileSizeLow
;
4222 serialnum
= volume_info
.serialnum
;
4224 if (is_a_symlink
&& !follow_symlinks
)
4225 buf
->st_mode
= S_IFLNK
;
4226 else if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4227 buf
->st_mode
= S_IFDIR
;
4229 buf
->st_mode
= S_IFREG
;
4231 get_file_owner_and_group (NULL
, buf
);
4235 /* Not sure if there is any point in this. */
4236 if (!NILP (Vw32_generate_fake_inodes
))
4237 fake_inode
= generate_inode_val (name
);
4238 else if (fake_inode
== 0)
4240 /* For want of something better, try to make everything unique. */
4241 static DWORD gen_num
= 0;
4242 fake_inode
= ++gen_num
;
4246 buf
->st_ino
= fake_inode
;
4248 buf
->st_dev
= serialnum
;
4249 buf
->st_rdev
= serialnum
;
4251 buf
->st_size
= fs_high
;
4252 buf
->st_size
<<= 32;
4253 buf
->st_size
+= fs_low
;
4254 buf
->st_nlink
= nlinks
;
4256 /* Convert timestamps to Unix format. */
4257 buf
->st_mtime
= convert_time (wtime
);
4258 buf
->st_atime
= convert_time (atime
);
4259 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4260 buf
->st_ctime
= convert_time (ctime
);
4261 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4263 /* determine rwx permissions */
4264 if (is_a_symlink
&& !follow_symlinks
)
4265 permission
= S_IREAD
| S_IWRITE
| S_IEXEC
; /* Posix expectations */
4268 if (fattrs
& FILE_ATTRIBUTE_READONLY
)
4269 permission
= S_IREAD
;
4271 permission
= S_IREAD
| S_IWRITE
;
4273 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
4274 permission
|= S_IEXEC
;
4275 else if (is_exec (name
))
4276 permission
|= S_IEXEC
;
4279 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4285 stat (const char * path
, struct stat
* buf
)
4287 return stat_worker (path
, buf
, 1);
4291 lstat (const char * path
, struct stat
* buf
)
4293 return stat_worker (path
, buf
, 0);
4297 fstatat (int fd
, char const *name
, struct stat
*st
, int flags
)
4299 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4300 This is good enough for the current usage in Emacs, but is fragile.
4302 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4303 Gnulib does this and can serve as a model. */
4304 char fullname
[MAX_PATH
];
4308 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
4311 errno
= ENAMETOOLONG
;
4317 return stat_worker (name
, st
, ! (flags
& AT_SYMLINK_NOFOLLOW
));
4320 /* Provide fstat and utime as well as stat for consistent handling of
4323 fstat (int desc
, struct stat
* buf
)
4325 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
4326 BY_HANDLE_FILE_INFORMATION info
;
4327 unsigned __int64 fake_inode
;
4330 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
4332 case FILE_TYPE_DISK
:
4333 buf
->st_mode
= S_IFREG
;
4334 if (!GetFileInformationByHandle (fh
, &info
))
4340 case FILE_TYPE_PIPE
:
4341 buf
->st_mode
= S_IFIFO
;
4343 case FILE_TYPE_CHAR
:
4344 case FILE_TYPE_UNKNOWN
:
4346 buf
->st_mode
= S_IFCHR
;
4348 memset (&info
, 0, sizeof (info
));
4349 info
.dwFileAttributes
= 0;
4350 info
.ftCreationTime
= utc_base_ft
;
4351 info
.ftLastAccessTime
= utc_base_ft
;
4352 info
.ftLastWriteTime
= utc_base_ft
;
4355 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4356 buf
->st_mode
= S_IFDIR
;
4358 buf
->st_nlink
= info
.nNumberOfLinks
;
4359 /* Might as well use file index to fake inode values, but this
4360 is not guaranteed to be unique unless we keep a handle open
4361 all the time (even then there are situations where it is
4362 not unique). Reputedly, there are at most 48 bits of info
4363 (on NTFS, presumably less on FAT). */
4364 fake_inode
= info
.nFileIndexHigh
;
4366 fake_inode
+= info
.nFileIndexLow
;
4368 /* MSVC defines _ino_t to be short; other libc's might not. */
4369 if (sizeof (buf
->st_ino
) == 2)
4370 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
4372 buf
->st_ino
= fake_inode
;
4374 /* If the caller so requested, get the true file owner and group.
4375 Otherwise, consider the file to belong to the current user. */
4376 if (!w32_stat_get_owner_group
|| is_windows_9x () == TRUE
)
4377 get_file_owner_and_group (NULL
, buf
);
4380 PSECURITY_DESCRIPTOR psd
= NULL
;
4382 psd
= get_file_security_desc_by_handle (fh
);
4385 get_file_owner_and_group (psd
, buf
);
4389 get_file_owner_and_group (NULL
, buf
);
4392 buf
->st_dev
= info
.dwVolumeSerialNumber
;
4393 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
4395 buf
->st_size
= info
.nFileSizeHigh
;
4396 buf
->st_size
<<= 32;
4397 buf
->st_size
+= info
.nFileSizeLow
;
4399 /* Convert timestamps to Unix format. */
4400 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
4401 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
4402 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
4403 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
4404 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
4406 /* determine rwx permissions */
4407 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
4408 permission
= S_IREAD
;
4410 permission
= S_IREAD
| S_IWRITE
;
4412 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
4413 permission
|= S_IEXEC
;
4416 #if 0 /* no way of knowing the filename */
4417 char * p
= strrchr (name
, '.');
4419 (xstrcasecmp (p
, ".exe") == 0 ||
4420 xstrcasecmp (p
, ".com") == 0 ||
4421 xstrcasecmp (p
, ".bat") == 0 ||
4422 xstrcasecmp (p
, ".cmd") == 0))
4423 permission
|= S_IEXEC
;
4427 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
4433 utime (const char *name
, struct _utimbuf
*times
)
4435 struct _utimbuf deftime
;
4442 deftime
.modtime
= deftime
.actime
= time (NULL
);
4446 /* Need write access to set times. */
4447 fh
= CreateFile (name
, FILE_WRITE_ATTRIBUTES
,
4448 /* If NAME specifies a directory, FILE_SHARE_DELETE
4449 allows other processes to delete files inside it,
4450 while we have the directory open. */
4451 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
4452 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
4453 if (fh
!= INVALID_HANDLE_VALUE
)
4455 convert_from_time_t (times
->actime
, &atime
);
4456 convert_from_time_t (times
->modtime
, &mtime
);
4457 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
4474 /* Symlink-related functions. */
4475 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4476 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4480 symlink (char const *filename
, char const *linkname
)
4482 char linkfn
[MAX_PATH
], *tgtfn
;
4484 int dir_access
, filename_ends_in_slash
;
4487 /* Diagnostics follows Posix as much as possible. */
4488 if (filename
== NULL
|| linkname
== NULL
)
4498 if (strlen (filename
) > MAX_PATH
|| strlen (linkname
) > MAX_PATH
)
4500 errno
= ENAMETOOLONG
;
4504 strcpy (linkfn
, map_w32_filename (linkname
, NULL
));
4505 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0)
4511 dbcs_p
= max_filename_mbslen () > 1;
4513 /* Note: since empty FILENAME was already rejected, we can safely
4514 refer to FILENAME[1]. */
4515 if (!(IS_DIRECTORY_SEP (filename
[0]) || IS_DEVICE_SEP (filename
[1])))
4517 /* Non-absolute FILENAME is understood as being relative to
4518 LINKNAME's directory. We need to prepend that directory to
4519 FILENAME to get correct results from faccessat below, since
4520 otherwise it will interpret FILENAME relative to the
4521 directory where the Emacs process runs. Note that
4522 make-symbolic-link always makes sure LINKNAME is a fully
4523 expanded file name. */
4525 char *p
= linkfn
+ strlen (linkfn
);
4529 while (p
> linkfn
&& !IS_ANY_SEP (p
[-1]))
4534 char *p1
= CharPrevExA (file_name_codepage
, linkfn
, p
, 0);
4536 while (p
> linkfn
&& !IS_ANY_SEP (*p1
))
4539 p1
= CharPrevExA (file_name_codepage
, linkfn
, p1
, 0);
4543 strncpy (tem
, linkfn
, p
- linkfn
);
4544 tem
[p
- linkfn
] = '\0';
4545 strcat (tem
, filename
);
4546 dir_access
= faccessat (AT_FDCWD
, tem
, D_OK
, AT_EACCESS
);
4549 dir_access
= faccessat (AT_FDCWD
, filename
, D_OK
, AT_EACCESS
);
4551 /* Since Windows distinguishes between symlinks to directories and
4552 to files, we provide a kludgy feature: if FILENAME doesn't
4553 exist, but ends in a slash, we create a symlink to directory. If
4554 FILENAME exists and is a directory, we always create a symlink to
4557 filename_ends_in_slash
= IS_DIRECTORY_SEP (filename
[strlen (filename
) - 1]);
4560 const char *end
= filename
+ strlen (filename
);
4561 const char *n
= CharPrevExA (file_name_codepage
, filename
, end
, 0);
4563 filename_ends_in_slash
= IS_DIRECTORY_SEP (*n
);
4565 if (dir_access
== 0 || filename_ends_in_slash
)
4566 flags
= SYMBOLIC_LINK_FLAG_DIRECTORY
;
4568 tgtfn
= (char *)map_w32_filename (filename
, NULL
);
4569 if (filename_ends_in_slash
)
4570 tgtfn
[strlen (tgtfn
) - 1] = '\0';
4573 if (!create_symbolic_link (linkfn
, tgtfn
, flags
))
4575 /* ENOSYS is set by create_symbolic_link, when it detects that
4576 the OS doesn't support the CreateSymbolicLink API. */
4577 if (errno
!= ENOSYS
)
4579 DWORD w32err
= GetLastError ();
4583 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4584 TGTFN point to the same file name, go figure. */
4586 case ERROR_FILE_EXISTS
:
4589 case ERROR_ACCESS_DENIED
:
4592 case ERROR_FILE_NOT_FOUND
:
4593 case ERROR_PATH_NOT_FOUND
:
4594 case ERROR_BAD_NETPATH
:
4595 case ERROR_INVALID_REPARSE_DATA
:
4598 case ERROR_DIRECTORY
:
4601 case ERROR_PRIVILEGE_NOT_HELD
:
4602 case ERROR_NOT_ALL_ASSIGNED
:
4605 case ERROR_DISK_FULL
:
4618 /* A quick inexpensive test of whether FILENAME identifies a file that
4619 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4620 must already be in the normalized form returned by
4623 Note: for repeated operations on many files, it is best to test
4624 whether the underlying volume actually supports symlinks, by
4625 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4626 avoid the call to this function if it doesn't. That's because the
4627 call to GetFileAttributes takes a non-negligible time, especially
4628 on non-local or removable filesystems. See stat_worker for an
4629 example of how to do that. */
4631 is_symlink (const char *filename
)
4634 WIN32_FIND_DATA wfd
;
4637 attrs
= GetFileAttributes (filename
);
4640 DWORD w32err
= GetLastError ();
4644 case ERROR_BAD_NETPATH
: /* network share, can't be a symlink */
4646 case ERROR_ACCESS_DENIED
:
4649 case ERROR_FILE_NOT_FOUND
:
4650 case ERROR_PATH_NOT_FOUND
:
4657 if ((attrs
& FILE_ATTRIBUTE_REPARSE_POINT
) == 0)
4659 logon_network_drive (filename
);
4660 fh
= FindFirstFile (filename
, &wfd
);
4661 if (fh
== INVALID_HANDLE_VALUE
)
4664 return (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0
4665 && (wfd
.dwReserved0
& IO_REPARSE_TAG_SYMLINK
) == IO_REPARSE_TAG_SYMLINK
;
4668 /* If NAME identifies a symbolic link, copy into BUF the file name of
4669 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4670 null-terminate the target name, even if it fits. Return the number
4671 of bytes copied, or -1 if NAME is not a symlink or any error was
4672 encountered while resolving it. The file name copied into BUF is
4673 encoded in the current ANSI codepage. */
4675 readlink (const char *name
, char *buf
, size_t buf_size
)
4678 TOKEN_PRIVILEGES privs
;
4679 int restore_privs
= 0;
4694 path
= map_w32_filename (name
, NULL
);
4696 if (strlen (path
) > MAX_PATH
)
4698 errno
= ENAMETOOLONG
;
4703 if (is_windows_9x () == TRUE
4704 || (volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) == 0
4705 || !is_symlink (path
))
4708 errno
= EINVAL
; /* not a symlink */
4712 /* Done with simple tests, now we're in for some _real_ work. */
4713 if (enable_privilege (SE_BACKUP_NAME
, TRUE
, &privs
))
4715 /* Implementation note: From here and onward, don't return early,
4716 since that will fail to restore the original set of privileges of
4717 the calling thread. */
4719 retval
= -1; /* not too optimistic, are we? */
4721 /* Note: In the next call to CreateFile, we use zero as the 2nd
4722 argument because, when the symlink is a hidden/system file,
4723 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4724 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4725 and directory symlinks. */
4726 sh
= CreateFile (path
, 0, 0, NULL
, OPEN_EXISTING
,
4727 FILE_FLAG_OPEN_REPARSE_POINT
| FILE_FLAG_BACKUP_SEMANTICS
,
4729 if (sh
!= INVALID_HANDLE_VALUE
)
4731 BYTE reparse_buf
[MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
4732 REPARSE_DATA_BUFFER
*reparse_data
= (REPARSE_DATA_BUFFER
*)&reparse_buf
[0];
4735 if (!DeviceIoControl (sh
, FSCTL_GET_REPARSE_POINT
, NULL
, 0,
4736 reparse_buf
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
4739 else if (reparse_data
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
4743 /* Copy the link target name, in wide characters, from
4744 reparse_data, then convert it to multibyte encoding in
4745 the current locale's codepage. */
4747 BYTE lname
[MAX_PATH
];
4750 reparse_data
->SymbolicLinkReparseBuffer
.PrintNameLength
;
4752 reparse_data
->SymbolicLinkReparseBuffer
.PathBuffer
4753 + reparse_data
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
);
4754 /* This updates file_name_codepage which we need below. */
4755 int dbcs_p
= max_filename_mbslen () > 1;
4757 /* According to MSDN, PrintNameLength does not include the
4758 terminating null character. */
4759 lwname
= alloca ((lwname_len
+ 1) * sizeof(WCHAR
));
4760 memcpy (lwname
, lwname_src
, lwname_len
);
4761 lwname
[lwname_len
/sizeof(WCHAR
)] = 0; /* null-terminate */
4763 lname_len
= WideCharToMultiByte (file_name_codepage
, 0, lwname
, -1,
4764 lname
, MAX_PATH
, NULL
, NULL
);
4767 /* WideCharToMultiByte failed. */
4768 DWORD w32err1
= GetLastError ();
4772 case ERROR_INSUFFICIENT_BUFFER
:
4773 errno
= ENAMETOOLONG
;
4775 case ERROR_INVALID_PARAMETER
:
4778 case ERROR_NO_UNICODE_TRANSLATION
:
4788 size_t size_to_copy
= buf_size
;
4789 BYTE
*p
= lname
, *p2
;
4790 BYTE
*pend
= p
+ lname_len
;
4792 /* Normalize like dostounix_filename does, but we don't
4793 want to assume that lname is null-terminated. */
4795 p2
= CharNextExA (file_name_codepage
, p
, 0);
4798 if (*p
&& *p2
== ':' && *p
>= 'A' && *p
<= 'Z')
4809 p
= CharNextExA (file_name_codepage
, p
, 0);
4810 /* CharNextExA doesn't advance at null character. */
4817 /* Testing for null-terminated LNAME is paranoia:
4818 WideCharToMultiByte should always return a
4819 null-terminated string when its 4th argument is -1
4820 and its 3rd argument is null-terminated (which they
4822 if (lname
[lname_len
- 1] == '\0')
4824 if (lname_len
<= buf_size
)
4825 size_to_copy
= lname_len
;
4826 strncpy (buf
, lname
, size_to_copy
);
4828 retval
= size_to_copy
;
4835 /* CreateFile failed. */
4836 DWORD w32err2
= GetLastError ();
4840 case ERROR_FILE_NOT_FOUND
:
4841 case ERROR_PATH_NOT_FOUND
:
4844 case ERROR_ACCESS_DENIED
:
4845 case ERROR_TOO_MANY_OPEN_FILES
:
4855 restore_privilege (&privs
);
4863 readlinkat (int fd
, char const *name
, char *buffer
,
4866 /* Rely on a hack: an open directory is modeled as file descriptor 0,
4867 as in fstatat. FIXME: Add proper support for readlinkat. */
4868 char fullname
[MAX_PATH
];
4872 if (_snprintf (fullname
, sizeof fullname
, "%s/%s", dir_pathname
, name
)
4875 errno
= ENAMETOOLONG
;
4881 return readlink (name
, buffer
, buffer_size
);
4884 /* If FILE is a symlink, return its target (stored in a static
4885 buffer); otherwise return FILE.
4887 This function repeatedly resolves symlinks in the last component of
4888 a chain of symlink file names, as in foo -> bar -> baz -> ...,
4889 until it arrives at a file whose last component is not a symlink,
4890 or some error occurs. It returns the target of the last
4891 successfully resolved symlink in the chain. If it succeeds to
4892 resolve even a single symlink, the value returned is an absolute
4893 file name with backslashes (result of GetFullPathName). By
4894 contrast, if the original FILE is returned, it is unaltered.
4896 Note: This function can set errno even if it succeeds.
4898 Implementation note: we only resolve the last portion ("basename")
4899 of the argument FILE and of each following file in the chain,
4900 disregarding any possible symlinks in its leading directories.
4901 This is because Windows system calls and library functions
4902 transparently resolve symlinks in leading directories and return
4903 correct information, as long as the basename is not a symlink. */
4905 chase_symlinks (const char *file
)
4907 static char target
[MAX_PATH
];
4908 char link
[MAX_PATH
];
4909 ssize_t res
, link_len
;
4913 if (is_windows_9x () == TRUE
|| !is_symlink (file
))
4914 return (char *)file
;
4916 if ((link_len
= GetFullPathName (file
, MAX_PATH
, link
, NULL
)) == 0)
4917 return (char *)file
;
4919 dbcs_p
= max_filename_mbslen () > 1;
4923 /* Remove trailing slashes, as we want to resolve the last
4924 non-trivial part of the link name. */
4927 while (link_len
> 3 && IS_DIRECTORY_SEP (link
[link_len
-1]))
4928 link
[link_len
--] = '\0';
4930 else if (link_len
> 3)
4932 char *n
= CharPrevExA (file_name_codepage
, link
, link
+ link_len
, 0);
4934 while (n
>= link
+ 2 && IS_DIRECTORY_SEP (*n
))
4937 n
= CharPrevExA (file_name_codepage
, link
, n
, 0);
4941 res
= readlink (link
, target
, MAX_PATH
);
4945 if (!(IS_DEVICE_SEP (target
[1])
4946 || (IS_DIRECTORY_SEP (target
[0]) && IS_DIRECTORY_SEP (target
[1]))))
4948 /* Target is relative. Append it to the directory part of
4949 the symlink, then copy the result back to target. */
4950 char *p
= link
+ link_len
;
4954 while (p
> link
&& !IS_ANY_SEP (p
[-1]))
4959 char *p1
= CharPrevExA (file_name_codepage
, link
, p
, 0);
4961 while (p
> link
&& !IS_ANY_SEP (*p1
))
4964 p1
= CharPrevExA (file_name_codepage
, link
, p1
, 0);
4968 strcpy (target
, link
);
4970 /* Resolve any "." and ".." to get a fully-qualified file name
4972 link_len
= GetFullPathName (target
, MAX_PATH
, link
, NULL
);
4974 } while (res
> 0 && link_len
> 0 && ++loop_count
<= 100);
4976 if (loop_count
> 100)
4979 if (target
[0] == '\0') /* not a single call to readlink succeeded */
4980 return (char *)file
;
4985 /* Posix ACL emulation. */
4988 acl_valid (acl_t acl
)
4990 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR
)acl
) ? 0 : -1;
4994 acl_to_text (acl_t acl
, ssize_t
*size
)
4997 SECURITY_INFORMATION flags
=
4998 OWNER_SECURITY_INFORMATION
|
4999 GROUP_SECURITY_INFORMATION
|
5000 DACL_SECURITY_INFORMATION
;
5001 char *retval
= NULL
;
5007 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR
)acl
, SDDL_REVISION_1
, flags
, &str_acl
, &local_size
))
5010 /* We don't want to mix heaps, so we duplicate the string in our
5011 heap and free the one allocated by the API. */
5012 retval
= xstrdup (str_acl
);
5015 LocalFree (str_acl
);
5017 else if (errno
!= ENOTSUP
)
5024 acl_from_text (const char *acl_str
)
5026 PSECURITY_DESCRIPTOR psd
, retval
= NULL
;
5032 if (convert_sddl_to_sd (acl_str
, SDDL_REVISION_1
, &psd
, &sd_size
))
5035 retval
= xmalloc (sd_size
);
5036 memcpy (retval
, psd
, sd_size
);
5039 else if (errno
!= ENOTSUP
)
5046 acl_free (void *ptr
)
5053 acl_get_file (const char *fname
, acl_type_t type
)
5055 PSECURITY_DESCRIPTOR psd
= NULL
;
5056 const char *filename
;
5058 if (type
== ACL_TYPE_ACCESS
)
5061 SECURITY_INFORMATION si
=
5062 OWNER_SECURITY_INFORMATION
|
5063 GROUP_SECURITY_INFORMATION
|
5064 DACL_SECURITY_INFORMATION
;
5067 filename
= map_w32_filename (fname
, NULL
);
5068 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5069 fname
= chase_symlinks (filename
);
5074 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
)
5075 && errno
!= ENOTSUP
)
5077 err
= GetLastError ();
5078 if (err
== ERROR_INSUFFICIENT_BUFFER
)
5080 psd
= xmalloc (sd_len
);
5081 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
5088 else if (err
== ERROR_FILE_NOT_FOUND
5089 || err
== ERROR_PATH_NOT_FOUND
)
5097 else if (type
!= ACL_TYPE_DEFAULT
)
5104 acl_set_file (const char *fname
, acl_type_t type
, acl_t acl
)
5106 TOKEN_PRIVILEGES old1
, old2
;
5108 int st
= 0, retval
= -1;
5109 SECURITY_INFORMATION flags
= 0;
5115 const char *filename
;
5117 if (acl_valid (acl
) != 0
5118 || (type
!= ACL_TYPE_DEFAULT
&& type
!= ACL_TYPE_ACCESS
))
5124 if (type
== ACL_TYPE_DEFAULT
)
5130 filename
= map_w32_filename (fname
, NULL
);
5131 if ((volume_info
.flags
& FILE_SUPPORTS_REPARSE_POINTS
) != 0)
5132 fname
= chase_symlinks (filename
);
5136 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5138 flags
|= OWNER_SECURITY_INFORMATION
;
5139 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR
)acl
, &psid
, &dflt
)
5141 flags
|= GROUP_SECURITY_INFORMATION
;
5142 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR
)acl
, &dacl_present
,
5145 flags
|= DACL_SECURITY_INFORMATION
;
5149 /* According to KB-245153, setting the owner will succeed if either:
5150 (1) the caller is the user who will be the new owner, and has the
5151 SE_TAKE_OWNERSHIP privilege, or
5152 (2) the caller has the SE_RESTORE privilege, in which case she can
5153 set any valid user or group as the owner
5155 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5156 privileges, and disregard any failures in obtaining them. If
5157 these privileges cannot be obtained, and do not already exist in
5158 the calling thread's security token, this function could fail
5160 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME
, TRUE
, &old1
))
5162 if (enable_privilege (SE_RESTORE_NAME
, TRUE
, &old2
))
5167 if (!set_file_security ((char *)fname
, flags
, (PSECURITY_DESCRIPTOR
)acl
))
5169 err
= GetLastError ();
5171 if (errno
== ENOTSUP
)
5173 else if (err
== ERROR_INVALID_OWNER
5174 || err
== ERROR_NOT_ALL_ASSIGNED
5175 || err
== ERROR_ACCESS_DENIED
)
5177 /* Maybe the requested ACL and the one the file already has
5178 are identical, in which case we can silently ignore the
5179 failure. (And no, Windows doesn't.) */
5180 acl_t current_acl
= acl_get_file (fname
, ACL_TYPE_ACCESS
);
5185 char *acl_from
= acl_to_text (current_acl
, NULL
);
5186 char *acl_to
= acl_to_text (acl
, NULL
);
5188 if (acl_from
&& acl_to
&& xstrcasecmp (acl_from
, acl_to
) == 0)
5194 acl_free (acl_from
);
5197 acl_free (current_acl
);
5200 else if (err
== ERROR_FILE_NOT_FOUND
|| err
== ERROR_PATH_NOT_FOUND
)
5214 restore_privilege (&old2
);
5215 restore_privilege (&old1
);
5223 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5224 have a fixed max size for file names, so we don't need the kind of
5225 alloc/malloc/realloc dance the gnulib version does. We also don't
5226 support FD-relative symlinks. */
5228 careadlinkat (int fd
, char const *filename
,
5229 char *buffer
, size_t buffer_size
,
5230 struct allocator
const *alloc
,
5231 ssize_t (*preadlinkat
) (int, char const *, char *, size_t))
5233 char linkname
[MAX_PATH
];
5236 link_size
= preadlinkat (fd
, filename
, linkname
, sizeof(linkname
));
5240 char *retval
= buffer
;
5242 linkname
[link_size
++] = '\0';
5243 if (link_size
> buffer_size
)
5244 retval
= (char *)(alloc
? alloc
->allocate
: xmalloc
) (link_size
);
5246 memcpy (retval
, linkname
, link_size
);
5254 /* Support for browsing other processes and their attributes. See
5255 process.c for the Lisp bindings. */
5257 /* Helper wrapper functions. */
5259 static HANDLE WINAPI
5260 create_toolhelp32_snapshot (DWORD Flags
, DWORD Ignored
)
5262 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot
= NULL
;
5264 if (g_b_init_create_toolhelp32_snapshot
== 0)
5266 g_b_init_create_toolhelp32_snapshot
= 1;
5267 s_pfn_Create_Toolhelp32_Snapshot
= (CreateToolhelp32Snapshot_Proc
)
5268 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5269 "CreateToolhelp32Snapshot");
5271 if (s_pfn_Create_Toolhelp32_Snapshot
== NULL
)
5273 return INVALID_HANDLE_VALUE
;
5275 return (s_pfn_Create_Toolhelp32_Snapshot (Flags
, Ignored
));
5279 process32_first (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5281 static Process32First_Proc s_pfn_Process32_First
= NULL
;
5283 if (g_b_init_process32_first
== 0)
5285 g_b_init_process32_first
= 1;
5286 s_pfn_Process32_First
= (Process32First_Proc
)
5287 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5290 if (s_pfn_Process32_First
== NULL
)
5294 return (s_pfn_Process32_First (hSnapshot
, lppe
));
5298 process32_next (HANDLE hSnapshot
, LPPROCESSENTRY32 lppe
)
5300 static Process32Next_Proc s_pfn_Process32_Next
= NULL
;
5302 if (g_b_init_process32_next
== 0)
5304 g_b_init_process32_next
= 1;
5305 s_pfn_Process32_Next
= (Process32Next_Proc
)
5306 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5309 if (s_pfn_Process32_Next
== NULL
)
5313 return (s_pfn_Process32_Next (hSnapshot
, lppe
));
5317 open_thread_token (HANDLE ThreadHandle
,
5318 DWORD DesiredAccess
,
5320 PHANDLE TokenHandle
)
5322 static OpenThreadToken_Proc s_pfn_Open_Thread_Token
= NULL
;
5323 HMODULE hm_advapi32
= NULL
;
5324 if (is_windows_9x () == TRUE
)
5326 SetLastError (ERROR_NOT_SUPPORTED
);
5329 if (g_b_init_open_thread_token
== 0)
5331 g_b_init_open_thread_token
= 1;
5332 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5333 s_pfn_Open_Thread_Token
=
5334 (OpenThreadToken_Proc
) GetProcAddress (hm_advapi32
, "OpenThreadToken");
5336 if (s_pfn_Open_Thread_Token
== NULL
)
5338 SetLastError (ERROR_NOT_SUPPORTED
);
5342 s_pfn_Open_Thread_Token (
5351 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
5353 static ImpersonateSelf_Proc s_pfn_Impersonate_Self
= NULL
;
5354 HMODULE hm_advapi32
= NULL
;
5355 if (is_windows_9x () == TRUE
)
5359 if (g_b_init_impersonate_self
== 0)
5361 g_b_init_impersonate_self
= 1;
5362 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5363 s_pfn_Impersonate_Self
=
5364 (ImpersonateSelf_Proc
) GetProcAddress (hm_advapi32
, "ImpersonateSelf");
5366 if (s_pfn_Impersonate_Self
== NULL
)
5370 return s_pfn_Impersonate_Self (ImpersonationLevel
);
5374 revert_to_self (void)
5376 static RevertToSelf_Proc s_pfn_Revert_To_Self
= NULL
;
5377 HMODULE hm_advapi32
= NULL
;
5378 if (is_windows_9x () == TRUE
)
5382 if (g_b_init_revert_to_self
== 0)
5384 g_b_init_revert_to_self
= 1;
5385 hm_advapi32
= LoadLibrary ("Advapi32.dll");
5386 s_pfn_Revert_To_Self
=
5387 (RevertToSelf_Proc
) GetProcAddress (hm_advapi32
, "RevertToSelf");
5389 if (s_pfn_Revert_To_Self
== NULL
)
5393 return s_pfn_Revert_To_Self ();
5397 get_process_memory_info (HANDLE h_proc
,
5398 PPROCESS_MEMORY_COUNTERS mem_counters
,
5401 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info
= NULL
;
5402 HMODULE hm_psapi
= NULL
;
5403 if (is_windows_9x () == TRUE
)
5407 if (g_b_init_get_process_memory_info
== 0)
5409 g_b_init_get_process_memory_info
= 1;
5410 hm_psapi
= LoadLibrary ("Psapi.dll");
5412 s_pfn_Get_Process_Memory_Info
= (GetProcessMemoryInfo_Proc
)
5413 GetProcAddress (hm_psapi
, "GetProcessMemoryInfo");
5415 if (s_pfn_Get_Process_Memory_Info
== NULL
)
5419 return s_pfn_Get_Process_Memory_Info (h_proc
, mem_counters
, bufsize
);
5423 get_process_working_set_size (HANDLE h_proc
,
5427 static GetProcessWorkingSetSize_Proc
5428 s_pfn_Get_Process_Working_Set_Size
= NULL
;
5430 if (is_windows_9x () == TRUE
)
5434 if (g_b_init_get_process_working_set_size
== 0)
5436 g_b_init_get_process_working_set_size
= 1;
5437 s_pfn_Get_Process_Working_Set_Size
= (GetProcessWorkingSetSize_Proc
)
5438 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5439 "GetProcessWorkingSetSize");
5441 if (s_pfn_Get_Process_Working_Set_Size
== NULL
)
5445 return s_pfn_Get_Process_Working_Set_Size (h_proc
, minrss
, maxrss
);
5449 global_memory_status (MEMORYSTATUS
*buf
)
5451 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status
= NULL
;
5453 if (is_windows_9x () == TRUE
)
5457 if (g_b_init_global_memory_status
== 0)
5459 g_b_init_global_memory_status
= 1;
5460 s_pfn_Global_Memory_Status
= (GlobalMemoryStatus_Proc
)
5461 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5462 "GlobalMemoryStatus");
5464 if (s_pfn_Global_Memory_Status
== NULL
)
5468 return s_pfn_Global_Memory_Status (buf
);
5472 global_memory_status_ex (MEMORY_STATUS_EX
*buf
)
5474 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex
= NULL
;
5476 if (is_windows_9x () == TRUE
)
5480 if (g_b_init_global_memory_status_ex
== 0)
5482 g_b_init_global_memory_status_ex
= 1;
5483 s_pfn_Global_Memory_Status_Ex
= (GlobalMemoryStatusEx_Proc
)
5484 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5485 "GlobalMemoryStatusEx");
5487 if (s_pfn_Global_Memory_Status_Ex
== NULL
)
5491 return s_pfn_Global_Memory_Status_Ex (buf
);
5495 list_system_processes (void)
5497 struct gcpro gcpro1
;
5498 Lisp_Object proclist
= Qnil
;
5501 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
5503 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
5505 PROCESSENTRY32 proc_entry
;
5511 proc_entry
.dwSize
= sizeof (PROCESSENTRY32
);
5512 for (res
= process32_first (h_snapshot
, &proc_entry
); res
;
5513 res
= process32_next (h_snapshot
, &proc_entry
))
5515 proc_id
= proc_entry
.th32ProcessID
;
5516 proclist
= Fcons (make_fixnum_or_float (proc_id
), proclist
);
5519 CloseHandle (h_snapshot
);
5521 proclist
= Fnreverse (proclist
);
5528 enable_privilege (LPCTSTR priv_name
, BOOL enable_p
, TOKEN_PRIVILEGES
*old_priv
)
5530 TOKEN_PRIVILEGES priv
;
5531 DWORD priv_size
= sizeof (priv
);
5532 DWORD opriv_size
= sizeof (*old_priv
);
5533 HANDLE h_token
= NULL
;
5534 HANDLE h_thread
= GetCurrentThread ();
5538 res
= open_thread_token (h_thread
,
5539 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5541 if (!res
&& GetLastError () == ERROR_NO_TOKEN
)
5543 if (impersonate_self (SecurityImpersonation
))
5544 res
= open_thread_token (h_thread
,
5545 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5550 priv
.PrivilegeCount
= 1;
5551 priv
.Privileges
[0].Attributes
= enable_p
? SE_PRIVILEGE_ENABLED
: 0;
5552 LookupPrivilegeValue (NULL
, priv_name
, &priv
.Privileges
[0].Luid
);
5553 if (AdjustTokenPrivileges (h_token
, FALSE
, &priv
, priv_size
,
5554 old_priv
, &opriv_size
)
5555 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
5559 CloseHandle (h_token
);
5565 restore_privilege (TOKEN_PRIVILEGES
*priv
)
5567 DWORD priv_size
= sizeof (*priv
);
5568 HANDLE h_token
= NULL
;
5571 if (open_thread_token (GetCurrentThread (),
5572 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
5575 if (AdjustTokenPrivileges (h_token
, FALSE
, priv
, priv_size
, NULL
, NULL
)
5576 && GetLastError () != ERROR_NOT_ALL_ASSIGNED
)
5580 CloseHandle (h_token
);
5586 ltime (ULONGLONG time_100ns
)
5588 ULONGLONG time_sec
= time_100ns
/ 10000000;
5589 int subsec
= time_100ns
% 10000000;
5590 return list4i (time_sec
>> 16, time_sec
& 0xffff,
5591 subsec
/ 10, subsec
% 10 * 100000);
5594 #define U64_TO_LISP_TIME(time) ltime (time)
5597 process_times (HANDLE h_proc
, Lisp_Object
*ctime
, Lisp_Object
*etime
,
5598 Lisp_Object
*stime
, Lisp_Object
*utime
, Lisp_Object
*ttime
,
5601 FILETIME ft_creation
, ft_exit
, ft_kernel
, ft_user
, ft_current
;
5602 ULONGLONG tem1
, tem2
, tem3
, tem
;
5605 || !get_process_times_fn
5606 || !(*get_process_times_fn
) (h_proc
, &ft_creation
, &ft_exit
,
5607 &ft_kernel
, &ft_user
))
5610 GetSystemTimeAsFileTime (&ft_current
);
5612 FILETIME_TO_U64 (tem1
, ft_kernel
);
5613 *stime
= U64_TO_LISP_TIME (tem1
);
5615 FILETIME_TO_U64 (tem2
, ft_user
);
5616 *utime
= U64_TO_LISP_TIME (tem2
);
5619 *ttime
= U64_TO_LISP_TIME (tem3
);
5621 FILETIME_TO_U64 (tem
, ft_creation
);
5622 /* Process no 4 (System) returns zero creation time. */
5625 *ctime
= U64_TO_LISP_TIME (tem
);
5629 FILETIME_TO_U64 (tem3
, ft_current
);
5630 tem
= (tem3
- utc_base
) - tem
;
5632 *etime
= U64_TO_LISP_TIME (tem
);
5636 *pcpu
= 100.0 * (tem1
+ tem2
) / tem
;
5647 system_process_attributes (Lisp_Object pid
)
5649 struct gcpro gcpro1
, gcpro2
, gcpro3
;
5650 Lisp_Object attrs
= Qnil
;
5651 Lisp_Object cmd_str
, decoded_cmd
, tem
;
5652 HANDLE h_snapshot
, h_proc
;
5655 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
5656 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), needed
;
5657 DWORD glength
= sizeof (gname
);
5658 HANDLE token
= NULL
;
5659 SID_NAME_USE user_type
;
5660 unsigned char *buf
= NULL
;
5662 TOKEN_USER user_token
;
5663 TOKEN_PRIMARY_GROUP group_token
;
5666 PROCESS_MEMORY_COUNTERS mem
;
5667 PROCESS_MEMORY_COUNTERS_EX mem_ex
;
5668 SIZE_T minrss
, maxrss
;
5670 MEMORY_STATUS_EX memstex
;
5671 double totphys
= 0.0;
5672 Lisp_Object ctime
, stime
, utime
, etime
, ttime
;
5674 BOOL result
= FALSE
;
5676 CHECK_NUMBER_OR_FLOAT (pid
);
5677 proc_id
= FLOATP (pid
) ? XFLOAT_DATA (pid
) : XINT (pid
);
5679 h_snapshot
= create_toolhelp32_snapshot (TH32CS_SNAPPROCESS
, 0);
5681 GCPRO3 (attrs
, decoded_cmd
, tem
);
5683 if (h_snapshot
!= INVALID_HANDLE_VALUE
)
5688 pe
.dwSize
= sizeof (PROCESSENTRY32
);
5689 for (res
= process32_first (h_snapshot
, &pe
); res
;
5690 res
= process32_next (h_snapshot
, &pe
))
5692 if (proc_id
== pe
.th32ProcessID
)
5695 decoded_cmd
= build_string ("Idle");
5698 /* Decode the command name from locale-specific
5700 cmd_str
= make_unibyte_string (pe
.szExeFile
,
5701 strlen (pe
.szExeFile
));
5703 code_convert_string_norecord (cmd_str
,
5704 Vlocale_coding_system
, 0);
5706 attrs
= Fcons (Fcons (Qcomm
, decoded_cmd
), attrs
);
5707 attrs
= Fcons (Fcons (Qppid
,
5708 make_fixnum_or_float (pe
.th32ParentProcessID
)),
5710 attrs
= Fcons (Fcons (Qpri
, make_number (pe
.pcPriClassBase
)),
5712 attrs
= Fcons (Fcons (Qthcount
,
5713 make_fixnum_or_float (pe
.cntThreads
)),
5720 CloseHandle (h_snapshot
);
5729 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
5731 /* If we were denied a handle to the process, try again after
5732 enabling the SeDebugPrivilege in our process. */
5735 TOKEN_PRIVILEGES priv_current
;
5737 if (enable_privilege (SE_DEBUG_NAME
, TRUE
, &priv_current
))
5739 h_proc
= OpenProcess (PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
,
5741 restore_privilege (&priv_current
);
5747 result
= open_process_token (h_proc
, TOKEN_QUERY
, &token
);
5750 result
= get_token_information (token
, TokenUser
, NULL
, 0, &blen
);
5751 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5753 buf
= xmalloc (blen
);
5754 result
= get_token_information (token
, TokenUser
,
5755 (LPVOID
)buf
, blen
, &needed
);
5758 memcpy (&user_token
, buf
, sizeof (user_token
));
5759 if (!w32_cached_id (user_token
.User
.Sid
, &euid
, uname
))
5761 euid
= get_rid (user_token
.User
.Sid
);
5762 result
= lookup_account_sid (NULL
, user_token
.User
.Sid
,
5767 w32_add_to_cache (user_token
.User
.Sid
, euid
, uname
);
5770 strcpy (uname
, "unknown");
5774 ulength
= strlen (uname
);
5780 /* Determine a reasonable euid and gid values. */
5781 if (xstrcasecmp ("administrator", uname
) == 0)
5783 euid
= 500; /* well-known Administrator uid */
5784 egid
= 513; /* well-known None gid */
5788 /* Get group id and name. */
5789 result
= get_token_information (token
, TokenPrimaryGroup
,
5790 (LPVOID
)buf
, blen
, &needed
);
5791 if (!result
&& GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
5793 buf
= xrealloc (buf
, blen
= needed
);
5794 result
= get_token_information (token
, TokenPrimaryGroup
,
5795 (LPVOID
)buf
, blen
, &needed
);
5799 memcpy (&group_token
, buf
, sizeof (group_token
));
5800 if (!w32_cached_id (group_token
.PrimaryGroup
, &egid
, gname
))
5802 egid
= get_rid (group_token
.PrimaryGroup
);
5803 dlength
= sizeof (domain
);
5805 lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
5806 gname
, &glength
, NULL
, &dlength
,
5809 w32_add_to_cache (group_token
.PrimaryGroup
,
5813 strcpy (gname
, "None");
5817 glength
= strlen (gname
);
5825 if (!is_windows_9x ())
5827 /* We couldn't open the process token, presumably because of
5828 insufficient access rights. Assume this process is run
5830 strcpy (uname
, "SYSTEM");
5831 strcpy (gname
, "None");
5832 euid
= 18; /* SYSTEM */
5833 egid
= 513; /* None */
5834 glength
= strlen (gname
);
5835 ulength
= strlen (uname
);
5837 /* If we are running under Windows 9X, where security calls are
5838 not supported, we assume all processes are run by the current
5840 else if (GetUserName (uname
, &ulength
))
5842 if (xstrcasecmp ("administrator", uname
) == 0)
5847 strcpy (gname
, "None");
5848 glength
= strlen (gname
);
5849 ulength
= strlen (uname
);
5855 strcpy (uname
, "administrator");
5856 ulength
= strlen (uname
);
5857 strcpy (gname
, "None");
5858 glength
= strlen (gname
);
5861 CloseHandle (token
);
5864 attrs
= Fcons (Fcons (Qeuid
, make_fixnum_or_float (euid
)), attrs
);
5865 tem
= make_unibyte_string (uname
, ulength
);
5866 attrs
= Fcons (Fcons (Quser
,
5867 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5869 attrs
= Fcons (Fcons (Qegid
, make_fixnum_or_float (egid
)), attrs
);
5870 tem
= make_unibyte_string (gname
, glength
);
5871 attrs
= Fcons (Fcons (Qgroup
,
5872 code_convert_string_norecord (tem
, Vlocale_coding_system
, 0)),
5875 if (global_memory_status_ex (&memstex
))
5876 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
5877 totphys
= memstex
.ullTotalPhys
/ 1024.0;
5879 /* Visual Studio 6 cannot convert an unsigned __int64 type to
5880 double, so we need to do this for it... */
5882 DWORD tot_hi
= memstex
.ullTotalPhys
>> 32;
5883 DWORD tot_md
= (memstex
.ullTotalPhys
& 0x00000000ffffffff) >> 10;
5884 DWORD tot_lo
= memstex
.ullTotalPhys
% 1024;
5886 totphys
= tot_hi
* 4194304.0 + tot_md
+ tot_lo
/ 1024.0;
5888 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5889 else if (global_memory_status (&memst
))
5890 totphys
= memst
.dwTotalPhys
/ 1024.0;
5893 && get_process_memory_info (h_proc
, (PROCESS_MEMORY_COUNTERS
*)&mem_ex
,
5896 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
5898 attrs
= Fcons (Fcons (Qmajflt
,
5899 make_fixnum_or_float (mem_ex
.PageFaultCount
)),
5901 attrs
= Fcons (Fcons (Qvsize
,
5902 make_fixnum_or_float (mem_ex
.PrivateUsage
/ 1024)),
5904 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5906 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5909 && get_process_memory_info (h_proc
, &mem
, sizeof (mem
)))
5911 SIZE_T rss
= mem_ex
.WorkingSetSize
/ 1024;
5913 attrs
= Fcons (Fcons (Qmajflt
,
5914 make_fixnum_or_float (mem
.PageFaultCount
)),
5916 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (rss
)), attrs
);
5918 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5921 && get_process_working_set_size (h_proc
, &minrss
, &maxrss
))
5923 DWORD rss
= maxrss
/ 1024;
5925 attrs
= Fcons (Fcons (Qrss
, make_fixnum_or_float (maxrss
/ 1024)), attrs
);
5927 attrs
= Fcons (Fcons (Qpmem
, make_float (100. * rss
/ totphys
)), attrs
);
5930 if (process_times (h_proc
, &ctime
, &etime
, &stime
, &utime
, &ttime
, &pcpu
))
5932 attrs
= Fcons (Fcons (Qutime
, utime
), attrs
);
5933 attrs
= Fcons (Fcons (Qstime
, stime
), attrs
);
5934 attrs
= Fcons (Fcons (Qtime
, ttime
), attrs
);
5935 attrs
= Fcons (Fcons (Qstart
, ctime
), attrs
);
5936 attrs
= Fcons (Fcons (Qetime
, etime
), attrs
);
5937 attrs
= Fcons (Fcons (Qpcpu
, make_float (pcpu
)), attrs
);
5940 /* FIXME: Retrieve command line by walking the PEB of the process. */
5943 CloseHandle (h_proc
);
5949 /* Wrappers for winsock functions to map between our file descriptors
5950 and winsock's handles; also set h_errno for convenience.
5952 To allow Emacs to run on systems which don't have winsock support
5953 installed, we dynamically link to winsock on startup if present, and
5954 otherwise provide the minimum necessary functionality
5955 (eg. gethostname). */
5957 /* function pointers for relevant socket functions */
5958 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
5959 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
5960 int (PASCAL
*pfn_WSAGetLastError
) (void);
5961 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
5962 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
5963 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
5964 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
5965 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
5966 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
5967 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
5968 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
5969 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
5970 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
5971 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
5972 int (PASCAL
*pfn_WSACleanup
) (void);
5974 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
5975 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
5976 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
5977 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
5978 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
5979 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
5980 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
5981 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
5982 const char * optval
, int optlen
);
5983 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
5984 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
5986 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
5987 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
5988 struct sockaddr
* from
, int * fromlen
);
5989 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
5990 const struct sockaddr
* to
, int tolen
);
5992 /* SetHandleInformation is only needed to make sockets non-inheritable. */
5993 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
5994 #ifndef HANDLE_FLAG_INHERIT
5995 #define HANDLE_FLAG_INHERIT 1
5999 static int winsock_inuse
;
6004 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
6006 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6007 after WSAStartup returns successfully, but it seems reasonable
6008 to allow unloading winsock anyway in that case. */
6009 if (pfn_WSACleanup () == 0 ||
6010 pfn_WSAGetLastError () == WSAENETDOWN
)
6012 if (FreeLibrary (winsock_lib
))
6021 init_winsock (int load_now
)
6023 WSADATA winsockData
;
6025 if (winsock_lib
!= NULL
)
6028 pfn_SetHandleInformation
6029 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6030 "SetHandleInformation");
6032 winsock_lib
= LoadLibrary ("Ws2_32.dll");
6034 if (winsock_lib
!= NULL
)
6036 /* dynamically link to socket functions */
6038 #define LOAD_PROC(fn) \
6039 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6042 LOAD_PROC (WSAStartup
);
6043 LOAD_PROC (WSASetLastError
);
6044 LOAD_PROC (WSAGetLastError
);
6045 LOAD_PROC (WSAEventSelect
);
6046 LOAD_PROC (WSACreateEvent
);
6047 LOAD_PROC (WSACloseEvent
);
6050 LOAD_PROC (connect
);
6051 LOAD_PROC (ioctlsocket
);
6054 LOAD_PROC (closesocket
);
6055 LOAD_PROC (shutdown
);
6058 LOAD_PROC (inet_addr
);
6059 LOAD_PROC (gethostname
);
6060 LOAD_PROC (gethostbyname
);
6061 LOAD_PROC (getservbyname
);
6062 LOAD_PROC (getpeername
);
6063 LOAD_PROC (WSACleanup
);
6064 LOAD_PROC (setsockopt
);
6066 LOAD_PROC (getsockname
);
6068 LOAD_PROC (recvfrom
);
6072 /* specify version 1.1 of winsock */
6073 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
6075 if (winsockData
.wVersion
!= 0x101)
6080 /* Report that winsock exists and is usable, but leave
6081 socket functions disabled. I am assuming that calling
6082 WSAStartup does not require any network interaction,
6083 and in particular does not cause or require a dial-up
6084 connection to be established. */
6087 FreeLibrary (winsock_lib
);
6095 FreeLibrary (winsock_lib
);
6105 /* Function to map winsock error codes to errno codes for those errno
6106 code defined in errno.h (errno values not defined by errno.h are
6107 already in nt/inc/sys/socket.h). */
6114 if (winsock_lib
== NULL
)
6117 wsa_err
= pfn_WSAGetLastError ();
6121 case WSAEACCES
: errno
= EACCES
; break;
6122 case WSAEBADF
: errno
= EBADF
; break;
6123 case WSAEFAULT
: errno
= EFAULT
; break;
6124 case WSAEINTR
: errno
= EINTR
; break;
6125 case WSAEINVAL
: errno
= EINVAL
; break;
6126 case WSAEMFILE
: errno
= EMFILE
; break;
6127 case WSAENAMETOOLONG
: errno
= ENAMETOOLONG
; break;
6128 case WSAENOTEMPTY
: errno
= ENOTEMPTY
; break;
6129 default: errno
= wsa_err
; break;
6137 if (winsock_lib
!= NULL
)
6138 pfn_WSASetLastError (0);
6141 /* Extend strerror to handle the winsock-specific error codes. */
6145 } _wsa_errlist
[] = {
6146 {WSAEINTR
, "Interrupted function call"},
6147 {WSAEBADF
, "Bad file descriptor"},
6148 {WSAEACCES
, "Permission denied"},
6149 {WSAEFAULT
, "Bad address"},
6150 {WSAEINVAL
, "Invalid argument"},
6151 {WSAEMFILE
, "Too many open files"},
6153 {WSAEWOULDBLOCK
, "Resource temporarily unavailable"},
6154 {WSAEINPROGRESS
, "Operation now in progress"},
6155 {WSAEALREADY
, "Operation already in progress"},
6156 {WSAENOTSOCK
, "Socket operation on non-socket"},
6157 {WSAEDESTADDRREQ
, "Destination address required"},
6158 {WSAEMSGSIZE
, "Message too long"},
6159 {WSAEPROTOTYPE
, "Protocol wrong type for socket"},
6160 {WSAENOPROTOOPT
, "Bad protocol option"},
6161 {WSAEPROTONOSUPPORT
, "Protocol not supported"},
6162 {WSAESOCKTNOSUPPORT
, "Socket type not supported"},
6163 {WSAEOPNOTSUPP
, "Operation not supported"},
6164 {WSAEPFNOSUPPORT
, "Protocol family not supported"},
6165 {WSAEAFNOSUPPORT
, "Address family not supported by protocol family"},
6166 {WSAEADDRINUSE
, "Address already in use"},
6167 {WSAEADDRNOTAVAIL
, "Cannot assign requested address"},
6168 {WSAENETDOWN
, "Network is down"},
6169 {WSAENETUNREACH
, "Network is unreachable"},
6170 {WSAENETRESET
, "Network dropped connection on reset"},
6171 {WSAECONNABORTED
, "Software caused connection abort"},
6172 {WSAECONNRESET
, "Connection reset by peer"},
6173 {WSAENOBUFS
, "No buffer space available"},
6174 {WSAEISCONN
, "Socket is already connected"},
6175 {WSAENOTCONN
, "Socket is not connected"},
6176 {WSAESHUTDOWN
, "Cannot send after socket shutdown"},
6177 {WSAETOOMANYREFS
, "Too many references"}, /* not sure */
6178 {WSAETIMEDOUT
, "Connection timed out"},
6179 {WSAECONNREFUSED
, "Connection refused"},
6180 {WSAELOOP
, "Network loop"}, /* not sure */
6181 {WSAENAMETOOLONG
, "Name is too long"},
6182 {WSAEHOSTDOWN
, "Host is down"},
6183 {WSAEHOSTUNREACH
, "No route to host"},
6184 {WSAENOTEMPTY
, "Buffer not empty"}, /* not sure */
6185 {WSAEPROCLIM
, "Too many processes"},
6186 {WSAEUSERS
, "Too many users"}, /* not sure */
6187 {WSAEDQUOT
, "Double quote in host name"}, /* really not sure */
6188 {WSAESTALE
, "Data is stale"}, /* not sure */
6189 {WSAEREMOTE
, "Remote error"}, /* not sure */
6191 {WSASYSNOTREADY
, "Network subsystem is unavailable"},
6192 {WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range"},
6193 {WSANOTINITIALISED
, "Winsock not initialized successfully"},
6194 {WSAEDISCON
, "Graceful shutdown in progress"},
6196 {WSAENOMORE
, "No more operations allowed"}, /* not sure */
6197 {WSAECANCELLED
, "Operation cancelled"}, /* not sure */
6198 {WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider"},
6199 {WSAEINVALIDPROVIDER
, "Invalid service provider version number"},
6200 {WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider"},
6201 {WSASYSCALLFAILURE
, "System call failure"},
6202 {WSASERVICE_NOT_FOUND
, "Service not found"}, /* not sure */
6203 {WSATYPE_NOT_FOUND
, "Class type not found"},
6204 {WSA_E_NO_MORE
, "No more resources available"}, /* really not sure */
6205 {WSA_E_CANCELLED
, "Operation already cancelled"}, /* really not sure */
6206 {WSAEREFUSED
, "Operation refused"}, /* not sure */
6209 {WSAHOST_NOT_FOUND
, "Host not found"},
6210 {WSATRY_AGAIN
, "Authoritative host not found during name lookup"},
6211 {WSANO_RECOVERY
, "Non-recoverable error during name lookup"},
6212 {WSANO_DATA
, "Valid name, no data record of requested type"},
6218 sys_strerror (int error_no
)
6221 static char unknown_msg
[40];
6223 if (error_no
>= 0 && error_no
< sys_nerr
)
6224 return sys_errlist
[error_no
];
6226 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
6227 if (_wsa_errlist
[i
].errnum
== error_no
)
6228 return _wsa_errlist
[i
].msg
;
6230 sprintf (unknown_msg
, "Unidentified error: %d", error_no
);
6234 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6235 but I believe the method of keeping the socket handle separate (and
6236 insuring it is not inheritable) is the correct one. */
6238 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6240 static int socket_to_fd (SOCKET s
);
6243 sys_socket (int af
, int type
, int protocol
)
6247 if (winsock_lib
== NULL
)
6250 return INVALID_SOCKET
;
6255 /* call the real socket function */
6256 s
= pfn_socket (af
, type
, protocol
);
6258 if (s
!= INVALID_SOCKET
)
6259 return socket_to_fd (s
);
6265 /* Convert a SOCKET to a file descriptor. */
6267 socket_to_fd (SOCKET s
)
6272 /* Although under NT 3.5 _open_osfhandle will accept a socket
6273 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6274 that does not work under NT 3.1. However, we can get the same
6275 effect by using a backdoor function to replace an existing
6276 descriptor handle with the one we want. */
6278 /* allocate a file descriptor (with appropriate flags) */
6279 fd
= _open ("NUL:", _O_RDWR
);
6282 /* Make a non-inheritable copy of the socket handle. Note
6283 that it is possible that sockets aren't actually kernel
6284 handles, which appears to be the case on Windows 9x when
6285 the MS Proxy winsock client is installed. */
6287 /* Apparently there is a bug in NT 3.51 with some service
6288 packs, which prevents using DuplicateHandle to make a
6289 socket handle non-inheritable (causes WSACleanup to
6290 hang). The work-around is to use SetHandleInformation
6291 instead if it is available and implemented. */
6292 if (pfn_SetHandleInformation
)
6294 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
6298 HANDLE parent
= GetCurrentProcess ();
6299 HANDLE new_s
= INVALID_HANDLE_VALUE
;
6301 if (DuplicateHandle (parent
,
6307 DUPLICATE_SAME_ACCESS
))
6309 /* It is possible that DuplicateHandle succeeds even
6310 though the socket wasn't really a kernel handle,
6311 because a real handle has the same value. So
6312 test whether the new handle really is a socket. */
6313 long nonblocking
= 0;
6314 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
6316 pfn_closesocket (s
);
6321 CloseHandle (new_s
);
6326 eassert (fd
< MAXDESC
);
6327 fd_info
[fd
].hnd
= (HANDLE
) s
;
6329 /* set our own internal flags */
6330 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
6336 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6338 /* attach child_process to fd_info */
6339 if (fd_info
[ fd
].cp
!= NULL
)
6341 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
6345 fd_info
[ fd
].cp
= cp
;
6348 winsock_inuse
++; /* count open sockets */
6356 pfn_closesocket (s
);
6362 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
6364 if (winsock_lib
== NULL
)
6367 return SOCKET_ERROR
;
6371 if (fd_info
[s
].flags
& FILE_SOCKET
)
6373 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
6374 if (rc
== SOCKET_ERROR
)
6379 return SOCKET_ERROR
;
6383 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
6385 if (winsock_lib
== NULL
)
6388 return SOCKET_ERROR
;
6392 if (fd_info
[s
].flags
& FILE_SOCKET
)
6394 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
6395 if (rc
== SOCKET_ERROR
)
6400 return SOCKET_ERROR
;
6404 sys_htons (u_short hostshort
)
6406 return (winsock_lib
!= NULL
) ?
6407 pfn_htons (hostshort
) : hostshort
;
6411 sys_ntohs (u_short netshort
)
6413 return (winsock_lib
!= NULL
) ?
6414 pfn_ntohs (netshort
) : netshort
;
6418 sys_inet_addr (const char * cp
)
6420 return (winsock_lib
!= NULL
) ?
6421 pfn_inet_addr (cp
) : INADDR_NONE
;
6425 sys_gethostname (char * name
, int namelen
)
6427 if (winsock_lib
!= NULL
)
6432 retval
= pfn_gethostname (name
, namelen
);
6433 if (retval
== SOCKET_ERROR
)
6438 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
6439 return !GetComputerName (name
, (DWORD
*)&namelen
);
6442 return SOCKET_ERROR
;
6446 sys_gethostbyname (const char * name
)
6448 struct hostent
* host
;
6449 int h_err
= h_errno
;
6451 if (winsock_lib
== NULL
)
6453 h_errno
= NO_RECOVERY
;
6459 host
= pfn_gethostbyname (name
);
6471 sys_getservbyname (const char * name
, const char * proto
)
6473 struct servent
* serv
;
6475 if (winsock_lib
== NULL
)
6482 serv
= pfn_getservbyname (name
, proto
);
6489 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
6491 if (winsock_lib
== NULL
)
6494 return SOCKET_ERROR
;
6498 if (fd_info
[s
].flags
& FILE_SOCKET
)
6500 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
6501 if (rc
== SOCKET_ERROR
)
6506 return SOCKET_ERROR
;
6510 sys_shutdown (int s
, int how
)
6512 if (winsock_lib
== NULL
)
6515 return SOCKET_ERROR
;
6519 if (fd_info
[s
].flags
& FILE_SOCKET
)
6521 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
6522 if (rc
== SOCKET_ERROR
)
6527 return SOCKET_ERROR
;
6531 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
6533 if (winsock_lib
== NULL
)
6536 return SOCKET_ERROR
;
6540 if (fd_info
[s
].flags
& FILE_SOCKET
)
6542 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
6543 (const char *)optval
, optlen
);
6544 if (rc
== SOCKET_ERROR
)
6549 return SOCKET_ERROR
;
6553 sys_listen (int s
, int backlog
)
6555 if (winsock_lib
== NULL
)
6558 return SOCKET_ERROR
;
6562 if (fd_info
[s
].flags
& FILE_SOCKET
)
6564 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
6565 if (rc
== SOCKET_ERROR
)
6568 fd_info
[s
].flags
|= FILE_LISTEN
;
6572 return SOCKET_ERROR
;
6576 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
6578 if (winsock_lib
== NULL
)
6581 return SOCKET_ERROR
;
6585 if (fd_info
[s
].flags
& FILE_SOCKET
)
6587 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
6588 if (rc
== SOCKET_ERROR
)
6593 return SOCKET_ERROR
;
6597 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
6599 if (winsock_lib
== NULL
)
6606 if (fd_info
[s
].flags
& FILE_LISTEN
)
6608 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
6610 if (t
== INVALID_SOCKET
)
6613 fd
= socket_to_fd (t
);
6617 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
6618 ResetEvent (fd_info
[s
].cp
->char_avail
);
6627 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
6628 struct sockaddr
* from
, int * fromlen
)
6630 if (winsock_lib
== NULL
)
6633 return SOCKET_ERROR
;
6637 if (fd_info
[s
].flags
& FILE_SOCKET
)
6639 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
6640 if (rc
== SOCKET_ERROR
)
6645 return SOCKET_ERROR
;
6649 sys_sendto (int s
, const char * buf
, int len
, int flags
,
6650 const struct sockaddr
* to
, int tolen
)
6652 if (winsock_lib
== NULL
)
6655 return SOCKET_ERROR
;
6659 if (fd_info
[s
].flags
& FILE_SOCKET
)
6661 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
6662 if (rc
== SOCKET_ERROR
)
6667 return SOCKET_ERROR
;
6670 /* Windows does not have an fcntl function. Provide an implementation
6671 solely for making sockets non-blocking. */
6673 fcntl (int s
, int cmd
, int options
)
6675 if (winsock_lib
== NULL
)
6682 if (fd_info
[s
].flags
& FILE_SOCKET
)
6684 if (cmd
== F_SETFL
&& options
== O_NONBLOCK
)
6686 unsigned long nblock
= 1;
6687 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
6688 if (rc
== SOCKET_ERROR
)
6690 /* Keep track of the fact that we set this to non-blocking. */
6691 fd_info
[s
].flags
|= FILE_NDELAY
;
6697 return SOCKET_ERROR
;
6701 return SOCKET_ERROR
;
6705 /* Shadow main io functions: we need to handle pipes and sockets more
6706 intelligently, and implement non-blocking mode as well. */
6719 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
6721 child_process
* cp
= fd_info
[fd
].cp
;
6723 fd_info
[fd
].cp
= NULL
;
6725 if (CHILD_ACTIVE (cp
))
6727 /* if last descriptor to active child_process then cleanup */
6729 for (i
= 0; i
< MAXDESC
; i
++)
6733 if (fd_info
[i
].cp
== cp
)
6738 if (fd_info
[fd
].flags
& FILE_SOCKET
)
6740 if (winsock_lib
== NULL
) emacs_abort ();
6742 pfn_shutdown (SOCK_HANDLE (fd
), 2);
6743 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
6745 winsock_inuse
--; /* count open sockets */
6747 /* If the process handle is NULL, it's either a socket
6748 or serial connection, or a subprocess that was
6749 already reaped by reap_subprocess, but whose
6750 resources were not yet freed, because its output was
6751 not fully read yet by the time it was reaped. (This
6752 usually happens with async subprocesses whose output
6753 is being read by Emacs.) Otherwise, this process was
6754 not reaped yet, so we set its FD to a negative value
6755 to make sure sys_select will eventually get to
6756 calling the SIGCHLD handler for it, which will then
6757 invoke waitpid and reap_subprocess. */
6758 if (cp
->procinfo
.hProcess
== NULL
)
6766 if (fd
>= 0 && fd
< MAXDESC
)
6767 fd_info
[fd
].flags
= 0;
6769 /* Note that sockets do not need special treatment here (at least on
6770 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
6771 closesocket is equivalent to CloseHandle, which is to be expected
6772 because socket handles are fully fledged kernel handles. */
6784 if (new_fd
>= 0 && new_fd
< MAXDESC
)
6786 /* duplicate our internal info as well */
6787 fd_info
[new_fd
] = fd_info
[fd
];
6793 sys_dup2 (int src
, int dst
)
6797 if (dst
< 0 || dst
>= MAXDESC
)
6803 /* make sure we close the destination first if it's a pipe or socket */
6804 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
6807 rc
= _dup2 (src
, dst
);
6810 /* duplicate our internal info as well */
6811 fd_info
[dst
] = fd_info
[src
];
6816 /* Unix pipe() has only one arg */
6818 sys_pipe (int * phandles
)
6823 /* make pipe handles non-inheritable; when we spawn a child, we
6824 replace the relevant handle with an inheritable one. Also put
6825 pipes into binary mode; we will do text mode translation ourselves
6827 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
6831 /* Protect against overflow, since Windows can open more handles than
6832 our fd_info array has room for. */
6833 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
6835 _close (phandles
[0]);
6836 _close (phandles
[1]);
6842 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
6843 fd_info
[phandles
[0]].flags
= flags
;
6845 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
6846 fd_info
[phandles
[1]].flags
= flags
;
6853 /* Function to do blocking read of one byte, needed to implement
6854 select. It is only allowed on communication ports, sockets, or
6857 _sys_read_ahead (int fd
)
6862 if (fd
< 0 || fd
>= MAXDESC
)
6863 return STATUS_READ_ERROR
;
6865 cp
= fd_info
[fd
].cp
;
6867 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6868 return STATUS_READ_ERROR
;
6870 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SERIAL
| FILE_SOCKET
)) == 0
6871 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
6873 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd
));
6877 cp
->status
= STATUS_READ_IN_PROGRESS
;
6879 if (fd_info
[fd
].flags
& FILE_PIPE
)
6881 rc
= _read (fd
, &cp
->chr
, sizeof (char));
6883 /* Give subprocess time to buffer some more output for us before
6884 reporting that input is available; we need this because Windows 95
6885 connects DOS programs to pipes by making the pipe appear to be
6886 the normal console stdout - as a result most DOS programs will
6887 write to stdout without buffering, ie. one character at a
6888 time. Even some W32 programs do this - "dir" in a command
6889 shell on NT is very slow if we don't do this. */
6892 int wait
= w32_pipe_read_delay
;
6898 /* Yield remainder of our time slice, effectively giving a
6899 temporary priority boost to the child process. */
6903 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
6905 HANDLE hnd
= fd_info
[fd
].hnd
;
6906 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
6909 /* Configure timeouts for blocking read. */
6910 if (!GetCommTimeouts (hnd
, &ct
))
6912 cp
->status
= STATUS_READ_ERROR
;
6913 return STATUS_READ_ERROR
;
6915 ct
.ReadIntervalTimeout
= 0;
6916 ct
.ReadTotalTimeoutMultiplier
= 0;
6917 ct
.ReadTotalTimeoutConstant
= 0;
6918 if (!SetCommTimeouts (hnd
, &ct
))
6920 cp
->status
= STATUS_READ_ERROR
;
6921 return STATUS_READ_ERROR
;
6924 if (!ReadFile (hnd
, &cp
->chr
, sizeof (char), (DWORD
*) &rc
, ovl
))
6926 if (GetLastError () != ERROR_IO_PENDING
)
6928 cp
->status
= STATUS_READ_ERROR
;
6929 return STATUS_READ_ERROR
;
6931 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
6933 cp
->status
= STATUS_READ_ERROR
;
6934 return STATUS_READ_ERROR
;
6938 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
6940 unsigned long nblock
= 0;
6941 /* We always want this to block, so temporarily disable NDELAY. */
6942 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6943 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6945 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
6947 if (fd_info
[fd
].flags
& FILE_NDELAY
)
6950 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
6954 if (rc
== sizeof (char))
6955 cp
->status
= STATUS_READ_SUCCEEDED
;
6957 cp
->status
= STATUS_READ_FAILED
;
6963 _sys_wait_accept (int fd
)
6969 if (fd
< 0 || fd
>= MAXDESC
)
6970 return STATUS_READ_ERROR
;
6972 cp
= fd_info
[fd
].cp
;
6974 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
6975 return STATUS_READ_ERROR
;
6977 cp
->status
= STATUS_READ_FAILED
;
6979 hEv
= pfn_WSACreateEvent ();
6980 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
6981 if (rc
!= SOCKET_ERROR
)
6983 rc
= WaitForSingleObject (hEv
, INFINITE
);
6984 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
6985 if (rc
== WAIT_OBJECT_0
)
6986 cp
->status
= STATUS_READ_SUCCEEDED
;
6988 pfn_WSACloseEvent (hEv
);
6994 sys_read (int fd
, char * buffer
, unsigned int count
)
6999 char * orig_buffer
= buffer
;
7007 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7009 child_process
*cp
= fd_info
[fd
].cp
;
7011 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
7019 /* re-read CR carried over from last read */
7020 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
7022 if (fd_info
[fd
].flags
& FILE_BINARY
) emacs_abort ();
7026 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
7029 /* presence of a child_process structure means we are operating in
7030 non-blocking mode - otherwise we just call _read directly.
7031 Note that the child_process structure might be missing because
7032 reap_subprocess has been called; in this case the pipe is
7033 already broken, so calling _read on it is okay. */
7036 int current_status
= cp
->status
;
7038 switch (current_status
)
7040 case STATUS_READ_FAILED
:
7041 case STATUS_READ_ERROR
:
7042 /* report normal EOF if nothing in buffer */
7044 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7047 case STATUS_READ_READY
:
7048 case STATUS_READ_IN_PROGRESS
:
7049 DebPrint (("sys_read called when read is in progress\n"));
7050 errno
= EWOULDBLOCK
;
7053 case STATUS_READ_SUCCEEDED
:
7054 /* consume read-ahead char */
7055 *buffer
++ = cp
->chr
;
7058 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7059 ResetEvent (cp
->char_avail
);
7061 case STATUS_READ_ACKNOWLEDGED
:
7065 DebPrint (("sys_read: bad status %d\n", current_status
));
7070 if (fd_info
[fd
].flags
& FILE_PIPE
)
7072 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
7073 to_read
= min (waiting
, (DWORD
) count
);
7076 nchars
+= _read (fd
, buffer
, to_read
);
7078 else if (fd_info
[fd
].flags
& FILE_SERIAL
)
7080 HANDLE hnd
= fd_info
[fd
].hnd
;
7081 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_read
;
7087 /* Configure timeouts for non-blocking read. */
7088 if (!GetCommTimeouts (hnd
, &ct
))
7093 ct
.ReadIntervalTimeout
= MAXDWORD
;
7094 ct
.ReadTotalTimeoutMultiplier
= 0;
7095 ct
.ReadTotalTimeoutConstant
= 0;
7096 if (!SetCommTimeouts (hnd
, &ct
))
7102 if (!ResetEvent (ovl
->hEvent
))
7107 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
7109 if (GetLastError () != ERROR_IO_PENDING
)
7114 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
7123 else /* FILE_SOCKET */
7125 if (winsock_lib
== NULL
) emacs_abort ();
7127 /* do the equivalent of a non-blocking read */
7128 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
7129 if (waiting
== 0 && nchars
== 0)
7131 errno
= EWOULDBLOCK
;
7137 /* always use binary mode for sockets */
7138 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
7139 if (res
== SOCKET_ERROR
)
7141 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7142 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7152 int nread
= _read (fd
, buffer
, count
);
7155 else if (nchars
== 0)
7160 fd_info
[fd
].flags
|= FILE_AT_EOF
;
7161 /* Perform text mode translation if required. */
7162 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7164 nchars
= crlf_to_lf (nchars
, orig_buffer
);
7165 /* If buffer contains only CR, return that. To be absolutely
7166 sure we should attempt to read the next char, but in
7167 practice a CR to be followed by LF would not appear by
7168 itself in the buffer. */
7169 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
7171 fd_info
[fd
].flags
|= FILE_LAST_CR
;
7177 nchars
= _read (fd
, buffer
, count
);
7182 /* From w32xfns.c */
7183 extern HANDLE interrupt_handle
;
7185 /* For now, don't bother with a non-blocking mode */
7187 sys_write (int fd
, const void * buffer
, unsigned int count
)
7197 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
7199 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
7205 /* Perform text mode translation if required. */
7206 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
7208 char * tmpbuf
= alloca (count
* 2);
7209 unsigned char * src
= (void *)buffer
;
7210 unsigned char * dst
= tmpbuf
;
7215 unsigned char *next
;
7216 /* copy next line or remaining bytes */
7217 next
= _memccpy (dst
, src
, '\n', nbytes
);
7220 /* copied one line ending with '\n' */
7221 int copied
= next
- dst
;
7224 /* insert '\r' before '\n' */
7231 /* copied remaining partial line -> now finished */
7238 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SERIAL
)
7240 HANDLE hnd
= (HANDLE
) _get_osfhandle (fd
);
7241 OVERLAPPED
*ovl
= &fd_info
[fd
].cp
->ovl_write
;
7242 HANDLE wait_hnd
[2] = { interrupt_handle
, ovl
->hEvent
};
7245 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
7247 if (GetLastError () != ERROR_IO_PENDING
)
7252 if (detect_input_pending ())
7253 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
7256 active
= WaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
);
7257 if (active
== WAIT_OBJECT_0
)
7258 { /* User pressed C-g, cancel write, then leave. Don't bother
7259 cleaning up as we may only get stuck in buggy drivers. */
7260 PurgeComm (hnd
, PURGE_TXABORT
| PURGE_TXCLEAR
);
7265 if (active
== WAIT_OBJECT_0
+ 1
7266 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
7273 else if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
7275 unsigned long nblock
= 0;
7276 if (winsock_lib
== NULL
) emacs_abort ();
7278 /* TODO: implement select() properly so non-blocking I/O works. */
7279 /* For now, make sure the write blocks. */
7280 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7281 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7283 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
7285 /* Set the socket back to non-blocking if it was before,
7286 for other operations that support it. */
7287 if (fd_info
[fd
].flags
& FILE_NDELAY
)
7290 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
7293 if (nchars
== SOCKET_ERROR
)
7295 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7296 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
7302 /* Some networked filesystems don't like too large writes, so
7303 break them into smaller chunks. See the Comments section of
7304 the MSDN documentation of WriteFile for details behind the
7305 choice of the value of CHUNK below. See also the thread
7306 http://thread.gmane.org/gmane.comp.version-control.git/145294
7307 in the git mailing list. */
7308 const unsigned char *p
= buffer
;
7309 const unsigned chunk
= 30 * 1024 * 1024;
7314 unsigned this_chunk
= count
< chunk
? count
: chunk
;
7315 int n
= _write (fd
, p
, this_chunk
);
7323 else if (n
< this_chunk
)
7333 /* The Windows CRT functions are "optimized for speed", so they don't
7334 check for timezone and DST changes if they were last called less
7335 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
7336 all Emacs features that repeatedly call time functions (e.g.,
7337 display-time) are in real danger of missing timezone and DST
7338 changes. Calling tzset before each localtime call fixes that. */
7340 sys_localtime (const time_t *t
)
7343 return localtime (t
);
7348 /* Try loading LIBRARY_ID from the file(s) specified in
7349 Vdynamic_library_alist. If the library is loaded successfully,
7350 return the handle of the DLL, and record the filename in the
7351 property :loaded-from of LIBRARY_ID. If the library could not be
7352 found, or when it was already loaded (because the handle is not
7353 recorded anywhere, and so is lost after use), return NULL.
7355 We could also save the handle in :loaded-from, but currently
7356 there's no use case for it. */
7358 w32_delayed_load (Lisp_Object library_id
)
7360 HMODULE library_dll
= NULL
;
7362 CHECK_SYMBOL (library_id
);
7364 if (CONSP (Vdynamic_library_alist
)
7365 && NILP (Fassq (library_id
, Vlibrary_cache
)))
7367 Lisp_Object found
= Qnil
;
7368 Lisp_Object dlls
= Fassq (library_id
, Vdynamic_library_alist
);
7371 for (dlls
= XCDR (dlls
); CONSP (dlls
); dlls
= XCDR (dlls
))
7373 CHECK_STRING_CAR (dlls
);
7374 if ((library_dll
= LoadLibrary (SDATA (XCAR (dlls
)))))
7376 char name
[MAX_PATH
];
7379 len
= GetModuleFileNameA (library_dll
, name
, sizeof (name
));
7380 found
= Fcons (XCAR (dlls
),
7382 /* Possibly truncated */
7383 ? make_specified_string (name
, -1, len
, 1)
7389 Fput (library_id
, QCloaded_from
, found
);
7397 check_windows_init_file (void)
7399 /* A common indication that Emacs is not installed properly is when
7400 it cannot find the Windows installation file. If this file does
7401 not exist in the expected place, tell the user. */
7403 if (!noninteractive
&& !inhibit_window_system
7404 /* Vload_path is not yet initialized when we are loading
7406 && NILP (Vpurify_flag
))
7408 Lisp_Object init_file
;
7411 init_file
= build_string ("term/w32-win");
7412 fd
= openp (Vload_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
7415 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
7416 char *init_file_name
= SDATA (init_file
);
7417 char *load_path
= SDATA (load_path_print
);
7418 char *buffer
= alloca (1024
7419 + strlen (init_file_name
)
7420 + strlen (load_path
));
7423 "The Emacs Windows initialization file \"%s.el\" "
7424 "could not be found in your Emacs installation. "
7425 "Emacs checked the following directories for this file:\n"
7427 "When Emacs cannot find this file, it usually means that it "
7428 "was not installed properly, or its distribution file was "
7429 "not unpacked properly.\nSee the README.W32 file in the "
7430 "top-level Emacs directory for more information.",
7431 init_file_name
, load_path
);
7434 "Emacs Abort Dialog",
7435 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
7436 /* Use the low-level system abort. */
7447 term_ntproc (int ignored
)
7453 /* shutdown the socket interface if necessary */
7460 init_ntproc (int dumping
)
7462 sigset_t initial_mask
= 0;
7464 /* Initialize the socket interface now if available and requested by
7465 the user by defining PRELOAD_WINSOCK; otherwise loading will be
7466 delayed until open-network-stream is called (w32-has-winsock can
7467 also be used to dynamically load or reload winsock).
7469 Conveniently, init_environment is called before us, so
7470 PRELOAD_WINSOCK can be set in the registry. */
7472 /* Always initialize this correctly. */
7475 if (getenv ("PRELOAD_WINSOCK") != NULL
)
7476 init_winsock (TRUE
);
7478 /* Initial preparation for subprocess support: replace our standard
7479 handles with non-inheritable versions. */
7482 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
7483 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
7484 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
7486 parent
= GetCurrentProcess ();
7488 /* ignore errors when duplicating and closing; typically the
7489 handles will be invalid when running as a gui program. */
7490 DuplicateHandle (parent
,
7491 GetStdHandle (STD_INPUT_HANDLE
),
7496 DUPLICATE_SAME_ACCESS
);
7498 DuplicateHandle (parent
,
7499 GetStdHandle (STD_OUTPUT_HANDLE
),
7504 DUPLICATE_SAME_ACCESS
);
7506 DuplicateHandle (parent
,
7507 GetStdHandle (STD_ERROR_HANDLE
),
7512 DUPLICATE_SAME_ACCESS
);
7518 if (stdin_save
!= INVALID_HANDLE_VALUE
)
7519 _open_osfhandle ((intptr_t) stdin_save
, O_TEXT
);
7521 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
7524 if (stdout_save
!= INVALID_HANDLE_VALUE
)
7525 _open_osfhandle ((intptr_t) stdout_save
, O_TEXT
);
7527 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
7530 if (stderr_save
!= INVALID_HANDLE_VALUE
)
7531 _open_osfhandle ((intptr_t) stderr_save
, O_TEXT
);
7533 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
7537 /* unfortunately, atexit depends on implementation of malloc */
7538 /* atexit (term_ntproc); */
7541 /* Make sure we start with all signals unblocked. */
7542 sigprocmask (SIG_SETMASK
, &initial_mask
, NULL
);
7543 signal (SIGABRT
, term_ntproc
);
7547 /* determine which drives are fixed, for GetCachedVolumeInformation */
7549 /* GetDriveType must have trailing backslash. */
7550 char drive
[] = "A:\\";
7552 /* Loop over all possible drive letters */
7553 while (*drive
<= 'Z')
7555 /* Record if this drive letter refers to a fixed drive. */
7556 fixed_drives
[DRIVE_INDEX (*drive
)] =
7557 (GetDriveType (drive
) == DRIVE_FIXED
);
7562 /* Reset the volume info cache. */
7563 volume_cache
= NULL
;
7568 shutdown_handler ensures that buffers' autosave files are
7569 up to date when the user logs off, or the system shuts down.
7572 shutdown_handler (DWORD type
)
7574 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
7575 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
7576 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
7577 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
7579 /* Shut down cleanly, making sure autosave files are up to date. */
7580 shut_down_emacs (0, Qnil
);
7583 /* Allow other handlers to handle this signal. */
7588 globals_of_w32 is used to initialize those global variables that
7589 must always be initialized on startup even when the global variable
7590 initialized is non zero (see the function main in emacs.c).
7593 globals_of_w32 (void)
7595 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
7597 get_process_times_fn
= (GetProcessTimes_Proc
)
7598 GetProcAddress (kernel32
, "GetProcessTimes");
7600 DEFSYM (QCloaded_from
, ":loaded-from");
7602 g_b_init_is_windows_9x
= 0;
7603 g_b_init_open_process_token
= 0;
7604 g_b_init_get_token_information
= 0;
7605 g_b_init_lookup_account_sid
= 0;
7606 g_b_init_get_sid_sub_authority
= 0;
7607 g_b_init_get_sid_sub_authority_count
= 0;
7608 g_b_init_get_security_info
= 0;
7609 g_b_init_get_file_security
= 0;
7610 g_b_init_get_security_descriptor_owner
= 0;
7611 g_b_init_get_security_descriptor_group
= 0;
7612 g_b_init_is_valid_sid
= 0;
7613 g_b_init_create_toolhelp32_snapshot
= 0;
7614 g_b_init_process32_first
= 0;
7615 g_b_init_process32_next
= 0;
7616 g_b_init_open_thread_token
= 0;
7617 g_b_init_impersonate_self
= 0;
7618 g_b_init_revert_to_self
= 0;
7619 g_b_init_get_process_memory_info
= 0;
7620 g_b_init_get_process_working_set_size
= 0;
7621 g_b_init_global_memory_status
= 0;
7622 g_b_init_global_memory_status_ex
= 0;
7623 g_b_init_equal_sid
= 0;
7624 g_b_init_copy_sid
= 0;
7625 g_b_init_get_length_sid
= 0;
7626 g_b_init_get_native_system_info
= 0;
7627 g_b_init_get_system_times
= 0;
7628 g_b_init_create_symbolic_link
= 0;
7629 g_b_init_get_security_descriptor_dacl
= 0;
7630 g_b_init_convert_sd_to_sddl
= 0;
7631 g_b_init_convert_sddl_to_sd
= 0;
7632 g_b_init_is_valid_security_descriptor
= 0;
7633 g_b_init_set_file_security
= 0;
7634 num_of_processors
= 0;
7635 /* The following sets a handler for shutdown notifications for
7636 console apps. This actually applies to Emacs in both console and
7637 GUI modes, since we had to fool windows into thinking emacs is a
7638 console application to get console mode to work. */
7639 SetConsoleCtrlHandler (shutdown_handler
, TRUE
);
7641 /* "None" is the default group name on standalone workstations. */
7642 strcpy (dflt_group_name
, "None");
7644 /* Reset, in case it has some value inherited from dump time. */
7645 w32_stat_get_owner_group
= 0;
7648 /* For make-serial-process */
7650 serial_open (char *port
)
7656 hnd
= CreateFile (port
, GENERIC_READ
| GENERIC_WRITE
, 0, 0,
7657 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
7658 if (hnd
== INVALID_HANDLE_VALUE
)
7659 error ("Could not open %s", port
);
7660 fd
= (int) _open_osfhandle ((intptr_t) hnd
, 0);
7662 error ("Could not open %s", port
);
7666 error ("Could not create child process");
7668 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
7669 fd_info
[ fd
].hnd
= hnd
;
7670 fd_info
[ fd
].flags
|=
7671 FILE_READ
| FILE_WRITE
| FILE_BINARY
| FILE_SERIAL
;
7672 if (fd_info
[ fd
].cp
!= NULL
)
7674 error ("fd_info[fd = %d] is already in use", fd
);
7676 fd_info
[ fd
].cp
= cp
;
7677 cp
->ovl_read
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
7678 if (cp
->ovl_read
.hEvent
== NULL
)
7679 error ("Could not create read event");
7680 cp
->ovl_write
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
7681 if (cp
->ovl_write
.hEvent
== NULL
)
7682 error ("Could not create write event");
7687 /* For serial-process-configure */
7689 serial_configure (struct Lisp_Process
*p
, Lisp_Object contact
)
7691 Lisp_Object childp2
= Qnil
;
7692 Lisp_Object tem
= Qnil
;
7696 char summary
[4] = "???"; /* This usually becomes "8N1". */
7698 if ((fd_info
[ p
->outfd
].flags
& FILE_SERIAL
) == 0)
7699 error ("Not a serial process");
7700 hnd
= fd_info
[ p
->outfd
].hnd
;
7702 childp2
= Fcopy_sequence (p
->childp
);
7704 /* Initialize timeouts for blocking read and blocking write. */
7705 if (!GetCommTimeouts (hnd
, &ct
))
7706 error ("GetCommTimeouts() failed");
7707 ct
.ReadIntervalTimeout
= 0;
7708 ct
.ReadTotalTimeoutMultiplier
= 0;
7709 ct
.ReadTotalTimeoutConstant
= 0;
7710 ct
.WriteTotalTimeoutMultiplier
= 0;
7711 ct
.WriteTotalTimeoutConstant
= 0;
7712 if (!SetCommTimeouts (hnd
, &ct
))
7713 error ("SetCommTimeouts() failed");
7714 /* Read port attributes and prepare default configuration. */
7715 memset (&dcb
, 0, sizeof (dcb
));
7716 dcb
.DCBlength
= sizeof (DCB
);
7717 if (!GetCommState (hnd
, &dcb
))
7718 error ("GetCommState() failed");
7721 dcb
.fAbortOnError
= FALSE
;
7722 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
7727 /* Configure speed. */
7728 if (!NILP (Fplist_member (contact
, QCspeed
)))
7729 tem
= Fplist_get (contact
, QCspeed
);
7731 tem
= Fplist_get (p
->childp
, QCspeed
);
7733 dcb
.BaudRate
= XINT (tem
);
7734 childp2
= Fplist_put (childp2
, QCspeed
, tem
);
7736 /* Configure bytesize. */
7737 if (!NILP (Fplist_member (contact
, QCbytesize
)))
7738 tem
= Fplist_get (contact
, QCbytesize
);
7740 tem
= Fplist_get (p
->childp
, QCbytesize
);
7742 tem
= make_number (8);
7744 if (XINT (tem
) != 7 && XINT (tem
) != 8)
7745 error (":bytesize must be nil (8), 7, or 8");
7746 dcb
.ByteSize
= XINT (tem
);
7747 summary
[0] = XINT (tem
) + '0';
7748 childp2
= Fplist_put (childp2
, QCbytesize
, tem
);
7750 /* Configure parity. */
7751 if (!NILP (Fplist_member (contact
, QCparity
)))
7752 tem
= Fplist_get (contact
, QCparity
);
7754 tem
= Fplist_get (p
->childp
, QCparity
);
7755 if (!NILP (tem
) && !EQ (tem
, Qeven
) && !EQ (tem
, Qodd
))
7756 error (":parity must be nil (no parity), `even', or `odd'");
7757 dcb
.fParity
= FALSE
;
7758 dcb
.Parity
= NOPARITY
;
7759 dcb
.fErrorChar
= FALSE
;
7764 else if (EQ (tem
, Qeven
))
7768 dcb
.Parity
= EVENPARITY
;
7769 dcb
.fErrorChar
= TRUE
;
7771 else if (EQ (tem
, Qodd
))
7775 dcb
.Parity
= ODDPARITY
;
7776 dcb
.fErrorChar
= TRUE
;
7778 childp2
= Fplist_put (childp2
, QCparity
, tem
);
7780 /* Configure stopbits. */
7781 if (!NILP (Fplist_member (contact
, QCstopbits
)))
7782 tem
= Fplist_get (contact
, QCstopbits
);
7784 tem
= Fplist_get (p
->childp
, QCstopbits
);
7786 tem
= make_number (1);
7788 if (XINT (tem
) != 1 && XINT (tem
) != 2)
7789 error (":stopbits must be nil (1 stopbit), 1, or 2");
7790 summary
[2] = XINT (tem
) + '0';
7791 if (XINT (tem
) == 1)
7792 dcb
.StopBits
= ONESTOPBIT
;
7793 else if (XINT (tem
) == 2)
7794 dcb
.StopBits
= TWOSTOPBITS
;
7795 childp2
= Fplist_put (childp2
, QCstopbits
, tem
);
7797 /* Configure flowcontrol. */
7798 if (!NILP (Fplist_member (contact
, QCflowcontrol
)))
7799 tem
= Fplist_get (contact
, QCflowcontrol
);
7801 tem
= Fplist_get (p
->childp
, QCflowcontrol
);
7802 if (!NILP (tem
) && !EQ (tem
, Qhw
) && !EQ (tem
, Qsw
))
7803 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
7804 dcb
.fOutxCtsFlow
= FALSE
;
7805 dcb
.fOutxDsrFlow
= FALSE
;
7806 dcb
.fDtrControl
= DTR_CONTROL_DISABLE
;
7807 dcb
.fDsrSensitivity
= FALSE
;
7808 dcb
.fTXContinueOnXoff
= FALSE
;
7811 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
7812 dcb
.XonChar
= 17; /* Control-Q */
7813 dcb
.XoffChar
= 19; /* Control-S */
7816 /* Already configured. */
7818 else if (EQ (tem
, Qhw
))
7820 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
7821 dcb
.fOutxCtsFlow
= TRUE
;
7823 else if (EQ (tem
, Qsw
))
7828 childp2
= Fplist_put (childp2
, QCflowcontrol
, tem
);
7830 /* Activate configuration. */
7831 if (!SetCommState (hnd
, &dcb
))
7832 error ("SetCommState() failed");
7834 childp2
= Fplist_put (childp2
, QCsummary
, build_string (summary
));
7835 pset_childp (p
, childp2
);
7841 emacs_gnutls_pull (gnutls_transport_ptr_t p
, void* buf
, size_t sz
)
7846 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7847 int fd
= process
->infd
;
7849 n
= sys_read (fd
, (char*)buf
, sz
);
7856 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7857 if (err
== EWOULDBLOCK
)
7860 emacs_gnutls_transport_set_errno (process
->gnutls_state
, err
);
7866 emacs_gnutls_push (gnutls_transport_ptr_t p
, const void* buf
, size_t sz
)
7868 struct Lisp_Process
*process
= (struct Lisp_Process
*)p
;
7869 int fd
= process
->outfd
;
7870 ssize_t n
= sys_write (fd
, buf
, sz
);
7872 /* 0 or more bytes written means everything went fine. */
7876 /* Negative bytes written means we got an error in errno.
7877 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
7878 emacs_gnutls_transport_set_errno (process
->gnutls_state
,
7879 errno
== EWOULDBLOCK
? EAGAIN
: errno
);
7883 #endif /* HAVE_GNUTLS */